@visualautomate/plugin-sdk 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/dist/index.mjs ADDED
@@ -0,0 +1,1511 @@
1
+ // src/simulate.ts
2
+ function toBytes(data) {
3
+ return typeof data === "string" ? new TextEncoder().encode(data) : data;
4
+ }
5
+ function createLocalStorage(seed = {}) {
6
+ const files = /* @__PURE__ */ new Map();
7
+ for (const [path, data] of Object.entries(seed)) {
8
+ files.set(path, {
9
+ bytes: toBytes(data),
10
+ contentType: "application/octet-stream",
11
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
12
+ });
13
+ }
14
+ const result = (path, file) => ({
15
+ url: `memory://${path}`,
16
+ size: file.bytes.length,
17
+ contentType: file.contentType,
18
+ uploadedAt: file.uploadedAt,
19
+ // The real one expires; this one does not, and says so rather than
20
+ // inventing a date a test might come to rely on.
21
+ expiresAt: "never (local simulation)"
22
+ });
23
+ const storage = {
24
+ async put(path, data, contentType = "application/octet-stream") {
25
+ const file = {
26
+ bytes: toBytes(data),
27
+ contentType,
28
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
29
+ };
30
+ files.set(path, file);
31
+ return result(path, file);
32
+ },
33
+ async get(path) {
34
+ return files.get(path)?.bytes ?? null;
35
+ },
36
+ async delete(path) {
37
+ files.delete(path);
38
+ },
39
+ async list(prefix) {
40
+ const listed = [];
41
+ let totalSize = 0;
42
+ for (const [path, file] of files) {
43
+ if (prefix && !path.startsWith(prefix)) continue;
44
+ listed.push({
45
+ url: `memory://${path}`,
46
+ pathname: path,
47
+ size: file.bytes.length,
48
+ uploadedAt: file.uploadedAt
49
+ });
50
+ totalSize += file.bytes.length;
51
+ }
52
+ return { files: listed, totalSize };
53
+ },
54
+ async head(path) {
55
+ const file = files.get(path);
56
+ return file ? { size: file.bytes.length, contentType: file.contentType } : null;
57
+ },
58
+ async signedUrl(path) {
59
+ return files.has(path) ? `memory://${path}` : null;
60
+ },
61
+ /**
62
+ * Really fetches, because that is the only way to find out whether the
63
+ * URL a plugin builds is the URL it meant. The bytes land in the same
64
+ * in-memory store the rest of these read from.
65
+ */
66
+ async download(url, path, contentType) {
67
+ const res = await fetch(url);
68
+ if (!res.ok) throw new Error(`Downloading ${url} failed with status ${res.status}`);
69
+ const file = {
70
+ bytes: new Uint8Array(await res.arrayBuffer()),
71
+ contentType: contentType ?? res.headers.get("content-type") ?? "application/octet-stream",
72
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
73
+ };
74
+ files.set(path, file);
75
+ return result(path, file);
76
+ }
77
+ };
78
+ return { storage, files };
79
+ }
80
+ function createLocalState(seed = {}) {
81
+ const values = new Map(Object.entries(seed));
82
+ const state = {
83
+ async get(key) {
84
+ return values.has(key) ? values.get(key) : null;
85
+ },
86
+ async set(key, value) {
87
+ values.set(key, value);
88
+ },
89
+ async delete(key) {
90
+ values.delete(key);
91
+ },
92
+ async list(prefix) {
93
+ const keys = [...values.keys()].filter((k) => !prefix || k.startsWith(prefix));
94
+ return { keys };
95
+ }
96
+ };
97
+ return { state, values };
98
+ }
99
+ function absent(name, what) {
100
+ throw new Error(
101
+ `context.${name} is not available locally. ${what} Pass a stub to simulate({ ${name}: \u2026 }) to test the code around it, or run the step on a canvas to exercise the real thing.`
102
+ );
103
+ }
104
+ async function simulate(plugin, options = {}) {
105
+ const startTime = Date.now();
106
+ const execute = typeof plugin === "function" ? plugin : plugin?.execute;
107
+ const { storage, files } = createLocalStorage(options.storage);
108
+ const { state, values } = createLocalState(options.state);
109
+ if (typeof execute !== "function") {
110
+ return {
111
+ status: "error",
112
+ output: null,
113
+ error: "This module exports no execute function. A plugin is `export default { execute }`, `module.exports.execute = \u2026`, or a default export that is the function itself.",
114
+ durationMs: Date.now() - startTime,
115
+ files,
116
+ state: values
117
+ };
118
+ }
119
+ const context = {
120
+ workflowId: options.workflowId ?? "local-workflow",
121
+ nodeId: options.nodeId ?? "local-node",
122
+ userId: options.userId ?? "local-user",
123
+ executionId: options.executionId ?? `local-${Date.now()}`,
124
+ startedAt: new Date(startTime).toISOString(),
125
+ secrets: options.secrets ?? {},
126
+ storage,
127
+ state,
128
+ connections: options.connections ?? {
129
+ get: async () => absent("connections", "It reaches an account somebody connected on the platform.")
130
+ },
131
+ media: options.media ?? {
132
+ run: async () => absent("media", "It runs ffmpeg in a container of its own.")
133
+ }
134
+ };
135
+ const timeoutMs = options.timeoutMs ?? 3e4;
136
+ let timer;
137
+ const timeout = new Promise((_, reject) => {
138
+ timer = setTimeout(
139
+ () => reject(new Error(`Plugin execution timed out after ${timeoutMs}ms`)),
140
+ timeoutMs
141
+ );
142
+ });
143
+ try {
144
+ const raw = await Promise.race([
145
+ Promise.resolve(execute(options.input ?? {}, options.config ?? {}, context)),
146
+ timeout
147
+ ]);
148
+ const durationMs = Date.now() - startTime;
149
+ if (!raw || typeof raw !== "object") {
150
+ return {
151
+ status: "error",
152
+ output: null,
153
+ error: `A plugin must return an object like { output: "success", data: {} }. This one returned ${raw === void 0 ? "undefined" : JSON.stringify(raw)}.`,
154
+ durationMs,
155
+ files,
156
+ state: values
157
+ };
158
+ }
159
+ const output = raw;
160
+ if (typeof output.output !== "string") {
161
+ return {
162
+ status: "error",
163
+ output: null,
164
+ error: 'The returned object has no `output`. That field names which port the run leaves by \u2014 usually "success" or "error" \u2014 and it has to be one of the `outputs` in your manifest.',
165
+ durationMs,
166
+ files,
167
+ state: values
168
+ };
169
+ }
170
+ return {
171
+ status: "success",
172
+ output: { ...output, data: output.data ?? {} },
173
+ durationMs,
174
+ outputPort: output.output,
175
+ logs: output.metadata?.logs,
176
+ files,
177
+ state: values
178
+ };
179
+ } catch (error) {
180
+ const durationMs = Date.now() - startTime;
181
+ const message = error instanceof Error ? error.message : String(error);
182
+ return {
183
+ status: message.includes("timed out") ? "timeout" : "error",
184
+ output: null,
185
+ error: message,
186
+ durationMs,
187
+ files,
188
+ state: values
189
+ };
190
+ } finally {
191
+ if (timer) clearTimeout(timer);
192
+ }
193
+ }
194
+
195
+ // src/platform-rules.ts
196
+ var ALLOWED_PACKAGES = [
197
+ {
198
+ "name": "nodemailer",
199
+ "version": "^6.10.0"
200
+ },
201
+ {
202
+ "name": "lodash",
203
+ "version": "^4.17.21"
204
+ },
205
+ {
206
+ "name": "ramda",
207
+ "version": "^0.30.1"
208
+ },
209
+ {
210
+ "name": "underscore",
211
+ "version": "^1.13.8"
212
+ },
213
+ {
214
+ "name": "immer",
215
+ "version": "^11.1.18"
216
+ },
217
+ {
218
+ "name": "immutable",
219
+ "version": "^5.1.9"
220
+ },
221
+ {
222
+ "name": "deepmerge",
223
+ "version": "^4.3.1"
224
+ },
225
+ {
226
+ "name": "defu",
227
+ "version": "^6.1.7"
228
+ },
229
+ {
230
+ "name": "rfdc",
231
+ "version": "^1.4.1"
232
+ },
233
+ {
234
+ "name": "klona",
235
+ "version": "^2.0.6"
236
+ },
237
+ {
238
+ "name": "fast-copy",
239
+ "version": "^4.1.1"
240
+ },
241
+ {
242
+ "name": "fast-deep-equal",
243
+ "version": "^3.1.3"
244
+ },
245
+ {
246
+ "name": "dequal",
247
+ "version": "^2.0.3"
248
+ },
249
+ {
250
+ "name": "object-hash",
251
+ "version": "^3.0.0"
252
+ },
253
+ {
254
+ "name": "hash-sum",
255
+ "version": "^2.0.0"
256
+ },
257
+ {
258
+ "name": "flat",
259
+ "version": "^6.0.1"
260
+ },
261
+ {
262
+ "name": "dot-prop",
263
+ "version": "^10.2.0"
264
+ },
265
+ {
266
+ "name": "object-path",
267
+ "version": "^0.11.8"
268
+ },
269
+ {
270
+ "name": "sort-array",
271
+ "version": "^5.1.1"
272
+ },
273
+ {
274
+ "name": "natural-orderby",
275
+ "version": "^5.0.0"
276
+ },
277
+ {
278
+ "name": "deep-object-diff",
279
+ "version": "^1.1.9"
280
+ },
281
+ {
282
+ "name": "microdiff",
283
+ "version": "^1.6.0"
284
+ },
285
+ {
286
+ "name": "fast-json-patch",
287
+ "version": "^3.1.1"
288
+ },
289
+ {
290
+ "name": "rfc6902",
291
+ "version": "^5.3.0"
292
+ },
293
+ {
294
+ "name": "just-clone",
295
+ "version": "^6.2.0"
296
+ },
297
+ {
298
+ "name": "just-diff",
299
+ "version": "^6.0.2"
300
+ },
301
+ {
302
+ "name": "just-diff-apply",
303
+ "version": "^5.5.0"
304
+ },
305
+ {
306
+ "name": "just-omit",
307
+ "version": "^2.2.0"
308
+ },
309
+ {
310
+ "name": "just-pick",
311
+ "version": "^4.2.0"
312
+ },
313
+ {
314
+ "name": "just-group-by",
315
+ "version": "^2.2.0"
316
+ },
317
+ {
318
+ "name": "just-order-by",
319
+ "version": "^1.0.0"
320
+ },
321
+ {
322
+ "name": "just-unique",
323
+ "version": "^4.2.0"
324
+ },
325
+ {
326
+ "name": "just-flatten-it",
327
+ "version": "^5.2.0"
328
+ },
329
+ {
330
+ "name": "just-safe-get",
331
+ "version": "^4.2.0"
332
+ },
333
+ {
334
+ "name": "just-safe-set",
335
+ "version": "^4.2.1"
336
+ },
337
+ {
338
+ "name": "just-typeof",
339
+ "version": "^3.2.0"
340
+ },
341
+ {
342
+ "name": "just-range",
343
+ "version": "^4.2.0"
344
+ },
345
+ {
346
+ "name": "just-zip-it",
347
+ "version": "^3.2.0"
348
+ },
349
+ {
350
+ "name": "just-compare",
351
+ "version": "^2.3.0"
352
+ },
353
+ {
354
+ "name": "just-intersect",
355
+ "version": "^4.3.0"
356
+ },
357
+ {
358
+ "name": "just-split",
359
+ "version": "^3.2.0"
360
+ },
361
+ {
362
+ "name": "just-truncate",
363
+ "version": "^2.2.0"
364
+ },
365
+ {
366
+ "name": "semver",
367
+ "version": "^7.6.3"
368
+ },
369
+ {
370
+ "name": "compare-versions",
371
+ "version": "^6.1.1"
372
+ },
373
+ {
374
+ "name": "tiny-invariant",
375
+ "version": "^1.3.3"
376
+ },
377
+ {
378
+ "name": "json-stringify-safe",
379
+ "version": "^5.0.1"
380
+ },
381
+ {
382
+ "name": "fast-safe-stringify",
383
+ "version": "^2.1.1"
384
+ },
385
+ {
386
+ "name": "flatted",
387
+ "version": "^3.4.4"
388
+ },
389
+ {
390
+ "name": "superjson",
391
+ "version": "^2.2.6"
392
+ },
393
+ {
394
+ "name": "devalue",
395
+ "version": "^5.9.2"
396
+ },
397
+ {
398
+ "name": "lru-cache",
399
+ "version": "^11.5.2"
400
+ },
401
+ {
402
+ "name": "quick-lru",
403
+ "version": "^7.3.0"
404
+ },
405
+ {
406
+ "name": "memoize-one",
407
+ "version": "^6.0.0"
408
+ },
409
+ {
410
+ "name": "fast-memoize",
411
+ "version": "^2.5.2"
412
+ },
413
+ {
414
+ "name": "uuid",
415
+ "version": "^11.0.5"
416
+ },
417
+ {
418
+ "name": "nanoid",
419
+ "version": "^5.0.9"
420
+ },
421
+ {
422
+ "name": "ulid",
423
+ "version": "^3.0.2"
424
+ },
425
+ {
426
+ "name": "@paralleldrive/cuid2",
427
+ "version": "^3.3.0"
428
+ },
429
+ {
430
+ "name": "slugify",
431
+ "version": "^1.6.6"
432
+ },
433
+ {
434
+ "name": "slug",
435
+ "version": "^12.0.1"
436
+ },
437
+ {
438
+ "name": "sanitize-filename",
439
+ "version": "^1.6.4"
440
+ },
441
+ {
442
+ "name": "filenamify",
443
+ "version": "^7.0.3"
444
+ },
445
+ {
446
+ "name": "seedrandom",
447
+ "version": "^3.0.5"
448
+ },
449
+ {
450
+ "name": "random-js",
451
+ "version": "^2.1.0"
452
+ },
453
+ {
454
+ "name": "chance",
455
+ "version": "^1.1.13"
456
+ },
457
+ {
458
+ "name": "@faker-js/faker",
459
+ "version": "^10.6.0"
460
+ },
461
+ {
462
+ "name": "lorem-ipsum",
463
+ "version": "^3.0.0"
464
+ },
465
+ {
466
+ "name": "randomcolor",
467
+ "version": "^0.6.2"
468
+ },
469
+ {
470
+ "name": "date-fns",
471
+ "version": "^4.1.0"
472
+ },
473
+ {
474
+ "name": "date-fns-tz",
475
+ "version": "^3.2.0"
476
+ },
477
+ {
478
+ "name": "dayjs",
479
+ "version": "^1.11.13"
480
+ },
481
+ {
482
+ "name": "luxon",
483
+ "version": "^3.5.0"
484
+ },
485
+ {
486
+ "name": "moment",
487
+ "version": "^2.30.1"
488
+ },
489
+ {
490
+ "name": "moment-timezone",
491
+ "version": "^0.6.3"
492
+ },
493
+ {
494
+ "name": "ms",
495
+ "version": "^2.1.3"
496
+ },
497
+ {
498
+ "name": "pretty-ms",
499
+ "version": "^9.3.1"
500
+ },
501
+ {
502
+ "name": "parse-duration",
503
+ "version": "^2.1.8"
504
+ },
505
+ {
506
+ "name": "humanize-duration",
507
+ "version": "^3.34.1"
508
+ },
509
+ {
510
+ "name": "timeago.js",
511
+ "version": "^4.0.2"
512
+ },
513
+ {
514
+ "name": "chrono-node",
515
+ "version": "^2.7.7"
516
+ },
517
+ {
518
+ "name": "rrule",
519
+ "version": "^2.8.1"
520
+ },
521
+ {
522
+ "name": "cron-parser",
523
+ "version": "^5.10.0"
524
+ },
525
+ {
526
+ "name": "cronstrue",
527
+ "version": "^3.26.0"
528
+ },
529
+ {
530
+ "name": "date-and-time",
531
+ "version": "^4.5.2"
532
+ },
533
+ {
534
+ "name": "fecha",
535
+ "version": "^4.2.3"
536
+ },
537
+ {
538
+ "name": "dateformat",
539
+ "version": "^5.0.3"
540
+ },
541
+ {
542
+ "name": "iso8601-duration",
543
+ "version": "^2.1.4"
544
+ },
545
+ {
546
+ "name": "ics",
547
+ "version": "^3.12.0"
548
+ },
549
+ {
550
+ "name": "zod",
551
+ "version": "^3.24.1"
552
+ },
553
+ {
554
+ "name": "yup",
555
+ "version": "^1.6.1"
556
+ },
557
+ {
558
+ "name": "joi",
559
+ "version": "^18.2.8"
560
+ },
561
+ {
562
+ "name": "ajv",
563
+ "version": "^8.17.1"
564
+ },
565
+ {
566
+ "name": "ajv-formats",
567
+ "version": "^3.0.1"
568
+ },
569
+ {
570
+ "name": "ajv-errors",
571
+ "version": "^3.0.0"
572
+ },
573
+ {
574
+ "name": "superstruct",
575
+ "version": "^2.0.2"
576
+ },
577
+ {
578
+ "name": "valibot",
579
+ "version": "^1.5.0"
580
+ },
581
+ {
582
+ "name": "jsonschema",
583
+ "version": "^1.5.0"
584
+ },
585
+ {
586
+ "name": "@sinclair/typebox",
587
+ "version": "^0.34.52"
588
+ },
589
+ {
590
+ "name": "validator",
591
+ "version": "^13.12.0"
592
+ },
593
+ {
594
+ "name": "email-validator",
595
+ "version": "^2.0.4"
596
+ },
597
+ {
598
+ "name": "libphonenumber-js",
599
+ "version": "^1.11.17"
600
+ },
601
+ {
602
+ "name": "iban",
603
+ "version": "^0.0.14"
604
+ },
605
+ {
606
+ "name": "credit-card-type",
607
+ "version": "^10.3.0"
608
+ },
609
+ {
610
+ "name": "card-validator",
611
+ "version": "^10.0.4"
612
+ },
613
+ {
614
+ "name": "psl",
615
+ "version": "^1.15.0"
616
+ },
617
+ {
618
+ "name": "tldts",
619
+ "version": "^7.4.12"
620
+ },
621
+ {
622
+ "name": "normalize-url",
623
+ "version": "^9.0.1"
624
+ },
625
+ {
626
+ "name": "valid-url",
627
+ "version": "^1.0.9"
628
+ },
629
+ {
630
+ "name": "is-ip",
631
+ "version": "^5.0.1"
632
+ },
633
+ {
634
+ "name": "ipaddr.js",
635
+ "version": "^2.5.0"
636
+ },
637
+ {
638
+ "name": "ip-address",
639
+ "version": "^10.7.0"
640
+ },
641
+ {
642
+ "name": "netmask",
643
+ "version": "^2.1.1"
644
+ },
645
+ {
646
+ "name": "ua-parser-js",
647
+ "version": "^2.0.10"
648
+ },
649
+ {
650
+ "name": "bowser",
651
+ "version": "^2.14.1"
652
+ },
653
+ {
654
+ "name": "papaparse",
655
+ "version": "^5.4.1"
656
+ },
657
+ {
658
+ "name": "csv-parse",
659
+ "version": "^7.0.2"
660
+ },
661
+ {
662
+ "name": "csv-stringify",
663
+ "version": "^6.8.3"
664
+ },
665
+ {
666
+ "name": "json-2-csv",
667
+ "version": "^5.6.0"
668
+ },
669
+ {
670
+ "name": "js-yaml",
671
+ "version": "^4.1.0"
672
+ },
673
+ {
674
+ "name": "yaml",
675
+ "version": "^2.9.0"
676
+ },
677
+ {
678
+ "name": "json5",
679
+ "version": "^2.2.3"
680
+ },
681
+ {
682
+ "name": "jsonc-parser",
683
+ "version": "^3.3.1"
684
+ },
685
+ {
686
+ "name": "hjson",
687
+ "version": "^3.2.2"
688
+ },
689
+ {
690
+ "name": "toml",
691
+ "version": "^5.0.0"
692
+ },
693
+ {
694
+ "name": "@iarna/toml",
695
+ "version": "^2.2.5"
696
+ },
697
+ {
698
+ "name": "ini",
699
+ "version": "^7.0.0"
700
+ },
701
+ {
702
+ "name": "fast-xml-parser",
703
+ "version": "^4.5.1"
704
+ },
705
+ {
706
+ "name": "xml2js",
707
+ "version": "^0.6.2"
708
+ },
709
+ {
710
+ "name": "xml-js",
711
+ "version": "^1.6.11"
712
+ },
713
+ {
714
+ "name": "xmlbuilder2",
715
+ "version": "^4.0.3"
716
+ },
717
+ {
718
+ "name": "@xmldom/xmldom",
719
+ "version": "^0.9.12"
720
+ },
721
+ {
722
+ "name": "xpath",
723
+ "version": "^0.0.34"
724
+ },
725
+ {
726
+ "name": "cheerio",
727
+ "version": "^1.0.0"
728
+ },
729
+ {
730
+ "name": "htmlparser2",
731
+ "version": "^12.0.0"
732
+ },
733
+ {
734
+ "name": "node-html-parser",
735
+ "version": "^9.0.4"
736
+ },
737
+ {
738
+ "name": "parse5",
739
+ "version": "^8.0.1"
740
+ },
741
+ {
742
+ "name": "sanitize-html",
743
+ "version": "^2.17.7"
744
+ },
745
+ {
746
+ "name": "marked",
747
+ "version": "^15.0.6"
748
+ },
749
+ {
750
+ "name": "markdown-it",
751
+ "version": "^15.0.1"
752
+ },
753
+ {
754
+ "name": "showdown",
755
+ "version": "^2.1.0"
756
+ },
757
+ {
758
+ "name": "turndown",
759
+ "version": "^7.2.0"
760
+ },
761
+ {
762
+ "name": "html-to-text",
763
+ "version": "^9.0.5"
764
+ },
765
+ {
766
+ "name": "he",
767
+ "version": "^1.2.0"
768
+ },
769
+ {
770
+ "name": "entities",
771
+ "version": "^8.1.0"
772
+ },
773
+ {
774
+ "name": "striptags",
775
+ "version": "^3.2.0"
776
+ },
777
+ {
778
+ "name": "front-matter",
779
+ "version": "^4.0.2"
780
+ },
781
+ {
782
+ "name": "qs",
783
+ "version": "^6.13.1"
784
+ },
785
+ {
786
+ "name": "query-string",
787
+ "version": "^9.5.1"
788
+ },
789
+ {
790
+ "name": "url-parse",
791
+ "version": "^1.5.10"
792
+ },
793
+ {
794
+ "name": "mime-types",
795
+ "version": "^2.1.35"
796
+ },
797
+ {
798
+ "name": "mime",
799
+ "version": "^4.1.0"
800
+ },
801
+ {
802
+ "name": "content-type",
803
+ "version": "^3.0.0"
804
+ },
805
+ {
806
+ "name": "cookie",
807
+ "version": "^2.0.1"
808
+ },
809
+ {
810
+ "name": "set-cookie-parser",
811
+ "version": "^3.1.2"
812
+ },
813
+ {
814
+ "name": "jsonpath-plus",
815
+ "version": "^10.2.0"
816
+ },
817
+ {
818
+ "name": "jmespath",
819
+ "version": "^0.16.0"
820
+ },
821
+ {
822
+ "name": "jsonata",
823
+ "version": "^2.2.2"
824
+ },
825
+ {
826
+ "name": "exceljs",
827
+ "version": "^4.4.0"
828
+ },
829
+ {
830
+ "name": "change-case",
831
+ "version": "^5.4.4"
832
+ },
833
+ {
834
+ "name": "camelcase",
835
+ "version": "^9.0.0"
836
+ },
837
+ {
838
+ "name": "decamelize",
839
+ "version": "^6.0.1"
840
+ },
841
+ {
842
+ "name": "title-case",
843
+ "version": "^4.3.2"
844
+ },
845
+ {
846
+ "name": "pluralize",
847
+ "version": "^8.0.0"
848
+ },
849
+ {
850
+ "name": "inflection",
851
+ "version": "^3.0.2"
852
+ },
853
+ {
854
+ "name": "voca",
855
+ "version": "^1.4.1"
856
+ },
857
+ {
858
+ "name": "underscore.string",
859
+ "version": "^3.3.6"
860
+ },
861
+ {
862
+ "name": "string-similarity",
863
+ "version": "^4.0.4"
864
+ },
865
+ {
866
+ "name": "fastest-levenshtein",
867
+ "version": "^1.0.16"
868
+ },
869
+ {
870
+ "name": "leven",
871
+ "version": "^4.1.0"
872
+ },
873
+ {
874
+ "name": "diff",
875
+ "version": "^7.0.0"
876
+ },
877
+ {
878
+ "name": "diff-match-patch",
879
+ "version": "^1.0.5"
880
+ },
881
+ {
882
+ "name": "remove-accents",
883
+ "version": "^0.5.0"
884
+ },
885
+ {
886
+ "name": "transliteration",
887
+ "version": "^2.6.1"
888
+ },
889
+ {
890
+ "name": "latinize",
891
+ "version": "^2.0.0"
892
+ },
893
+ {
894
+ "name": "franc",
895
+ "version": "^6.2.0"
896
+ },
897
+ {
898
+ "name": "stopword",
899
+ "version": "^3.1.5"
900
+ },
901
+ {
902
+ "name": "emoji-regex",
903
+ "version": "^10.6.0"
904
+ },
905
+ {
906
+ "name": "node-emoji",
907
+ "version": "^2.2.0"
908
+ },
909
+ {
910
+ "name": "string-width",
911
+ "version": "^8.2.2"
912
+ },
913
+ {
914
+ "name": "word-wrap",
915
+ "version": "^1.2.5"
916
+ },
917
+ {
918
+ "name": "wrap-ansi",
919
+ "version": "^10.0.1"
920
+ },
921
+ {
922
+ "name": "linkify-it",
923
+ "version": "^6.1.0"
924
+ },
925
+ {
926
+ "name": "linkifyjs",
927
+ "version": "^4.3.3"
928
+ },
929
+ {
930
+ "name": "fuse.js",
931
+ "version": "^7.5.0"
932
+ },
933
+ {
934
+ "name": "minisearch",
935
+ "version": "^7.2.0"
936
+ },
937
+ {
938
+ "name": "lunr",
939
+ "version": "^2.3.9"
940
+ },
941
+ {
942
+ "name": "flexsearch",
943
+ "version": "^0.8.212"
944
+ },
945
+ {
946
+ "name": "mustache",
947
+ "version": "^4.2.0"
948
+ },
949
+ {
950
+ "name": "liquidjs",
951
+ "version": "^10.20.1"
952
+ },
953
+ {
954
+ "name": "intl-messageformat",
955
+ "version": "^11.2.14"
956
+ },
957
+ {
958
+ "name": "gpt-tokenizer",
959
+ "version": "^4.0.0"
960
+ },
961
+ {
962
+ "name": "js-tiktoken",
963
+ "version": "^1.0.21"
964
+ },
965
+ {
966
+ "name": "decimal.js",
967
+ "version": "^10.4.3"
968
+ },
969
+ {
970
+ "name": "big.js",
971
+ "version": "^6.2.2"
972
+ },
973
+ {
974
+ "name": "bignumber.js",
975
+ "version": "^11.1.5"
976
+ },
977
+ {
978
+ "name": "currency.js",
979
+ "version": "^2.0.4"
980
+ },
981
+ {
982
+ "name": "dinero.js",
983
+ "version": "^2.0.2"
984
+ },
985
+ {
986
+ "name": "numeral",
987
+ "version": "^2.0.6"
988
+ },
989
+ {
990
+ "name": "accounting",
991
+ "version": "^0.4.1"
992
+ },
993
+ {
994
+ "name": "fraction.js",
995
+ "version": "^5.3.4"
996
+ },
997
+ {
998
+ "name": "convert-units",
999
+ "version": "^2.3.4"
1000
+ },
1001
+ {
1002
+ "name": "js-quantities",
1003
+ "version": "^1.8.0"
1004
+ },
1005
+ {
1006
+ "name": "mathjs",
1007
+ "version": "^15.2.0"
1008
+ },
1009
+ {
1010
+ "name": "simple-statistics",
1011
+ "version": "^7.12.0"
1012
+ },
1013
+ {
1014
+ "name": "ml-matrix",
1015
+ "version": "^6.15.0"
1016
+ },
1017
+ {
1018
+ "name": "d3-array",
1019
+ "version": "^3.2.4"
1020
+ },
1021
+ {
1022
+ "name": "d3-format",
1023
+ "version": "^3.1.2"
1024
+ },
1025
+ {
1026
+ "name": "d3-time-format",
1027
+ "version": "^4.1.0"
1028
+ },
1029
+ {
1030
+ "name": "geolib",
1031
+ "version": "^3.3.14"
1032
+ },
1033
+ {
1034
+ "name": "haversine-distance",
1035
+ "version": "^1.2.4"
1036
+ },
1037
+ {
1038
+ "name": "filesize",
1039
+ "version": "^11.0.23"
1040
+ },
1041
+ {
1042
+ "name": "bytes",
1043
+ "version": "^3.1.2"
1044
+ },
1045
+ {
1046
+ "name": "human-format",
1047
+ "version": "^1.2.1"
1048
+ },
1049
+ {
1050
+ "name": "jsonwebtoken",
1051
+ "version": "^9.0.2"
1052
+ },
1053
+ {
1054
+ "name": "jose",
1055
+ "version": "^5.9.6"
1056
+ },
1057
+ {
1058
+ "name": "jws",
1059
+ "version": "^4.0.1"
1060
+ },
1061
+ {
1062
+ "name": "jwt-decode",
1063
+ "version": "^4.0.0"
1064
+ },
1065
+ {
1066
+ "name": "crypto-js",
1067
+ "version": "^4.2.0"
1068
+ },
1069
+ {
1070
+ "name": "bcryptjs",
1071
+ "version": "^2.4.3"
1072
+ },
1073
+ {
1074
+ "name": "otplib",
1075
+ "version": "^13.5.0"
1076
+ },
1077
+ {
1078
+ "name": "otpauth",
1079
+ "version": "^9.5.2"
1080
+ },
1081
+ {
1082
+ "name": "tweetnacl",
1083
+ "version": "^1.0.3"
1084
+ },
1085
+ {
1086
+ "name": "tweetnacl-util",
1087
+ "version": "^0.15.1"
1088
+ },
1089
+ {
1090
+ "name": "node-forge",
1091
+ "version": "^1.4.0"
1092
+ },
1093
+ {
1094
+ "name": "elliptic",
1095
+ "version": "^6.6.1"
1096
+ },
1097
+ {
1098
+ "name": "bn.js",
1099
+ "version": "^5.2.5"
1100
+ },
1101
+ {
1102
+ "name": "js-base64",
1103
+ "version": "^3.7.7"
1104
+ },
1105
+ {
1106
+ "name": "base64-js",
1107
+ "version": "^1.5.1"
1108
+ },
1109
+ {
1110
+ "name": "base-64",
1111
+ "version": "^1.0.0"
1112
+ },
1113
+ {
1114
+ "name": "hi-base32",
1115
+ "version": "^0.5.1"
1116
+ },
1117
+ {
1118
+ "name": "thirty-two",
1119
+ "version": "^1.0.2"
1120
+ },
1121
+ {
1122
+ "name": "js-sha256",
1123
+ "version": "^1.0.0"
1124
+ },
1125
+ {
1126
+ "name": "js-sha512",
1127
+ "version": "^0.9.0"
1128
+ },
1129
+ {
1130
+ "name": "js-sha1",
1131
+ "version": "^0.7.0"
1132
+ },
1133
+ {
1134
+ "name": "js-md5",
1135
+ "version": "^0.9.2"
1136
+ },
1137
+ {
1138
+ "name": "hash.js",
1139
+ "version": "^1.1.7"
1140
+ },
1141
+ {
1142
+ "name": "spark-md5",
1143
+ "version": "^3.0.2"
1144
+ },
1145
+ {
1146
+ "name": "blueimp-md5",
1147
+ "version": "^2.19.0"
1148
+ },
1149
+ {
1150
+ "name": "crc-32",
1151
+ "version": "^1.2.2"
1152
+ },
1153
+ {
1154
+ "name": "crc",
1155
+ "version": "^4.3.2"
1156
+ },
1157
+ {
1158
+ "name": "utf8",
1159
+ "version": "^3.0.0"
1160
+ },
1161
+ {
1162
+ "name": "iconv-lite",
1163
+ "version": "^0.7.3"
1164
+ },
1165
+ {
1166
+ "name": "punycode",
1167
+ "version": "^2.3.1"
1168
+ },
1169
+ {
1170
+ "name": "pako",
1171
+ "version": "^3.0.1"
1172
+ },
1173
+ {
1174
+ "name": "fflate",
1175
+ "version": "^0.8.3"
1176
+ },
1177
+ {
1178
+ "name": "lz-string",
1179
+ "version": "^1.5.0"
1180
+ },
1181
+ {
1182
+ "name": "color",
1183
+ "version": "^5.0.3"
1184
+ },
1185
+ {
1186
+ "name": "tinycolor2",
1187
+ "version": "^1.6.0"
1188
+ },
1189
+ {
1190
+ "name": "chroma-js",
1191
+ "version": "^3.2.0"
1192
+ },
1193
+ {
1194
+ "name": "color-convert",
1195
+ "version": "^3.1.3"
1196
+ },
1197
+ {
1198
+ "name": "colord",
1199
+ "version": "^2.10.0"
1200
+ },
1201
+ {
1202
+ "name": "i18n-iso-countries",
1203
+ "version": "^7.14.0"
1204
+ },
1205
+ {
1206
+ "name": "iso-3166-1",
1207
+ "version": "^2.1.1"
1208
+ },
1209
+ {
1210
+ "name": "iso-639-1",
1211
+ "version": "^3.1.6"
1212
+ },
1213
+ {
1214
+ "name": "currency-codes",
1215
+ "version": "^2.2.0"
1216
+ },
1217
+ {
1218
+ "name": "qrcode-generator",
1219
+ "version": "^2.0.4"
1220
+ },
1221
+ {
1222
+ "name": "p-limit",
1223
+ "version": "^6.2.0"
1224
+ },
1225
+ {
1226
+ "name": "p-retry",
1227
+ "version": "^6.2.1"
1228
+ },
1229
+ {
1230
+ "name": "p-map",
1231
+ "version": "^7.0.3"
1232
+ },
1233
+ {
1234
+ "name": "p-queue",
1235
+ "version": "^9.3.3"
1236
+ },
1237
+ {
1238
+ "name": "p-timeout",
1239
+ "version": "^7.0.1"
1240
+ },
1241
+ {
1242
+ "name": "p-all",
1243
+ "version": "^5.0.1"
1244
+ },
1245
+ {
1246
+ "name": "p-props",
1247
+ "version": "^6.1.0"
1248
+ },
1249
+ {
1250
+ "name": "p-settle",
1251
+ "version": "^5.2.1"
1252
+ },
1253
+ {
1254
+ "name": "p-throttle",
1255
+ "version": "^8.1.0"
1256
+ },
1257
+ {
1258
+ "name": "p-debounce",
1259
+ "version": "^5.1.0"
1260
+ },
1261
+ {
1262
+ "name": "async",
1263
+ "version": "^3.2.6"
1264
+ },
1265
+ {
1266
+ "name": "bluebird",
1267
+ "version": "^3.7.2"
1268
+ },
1269
+ {
1270
+ "name": "promise-retry",
1271
+ "version": "^2.0.1"
1272
+ },
1273
+ {
1274
+ "name": "retry",
1275
+ "version": "^0.13.1"
1276
+ },
1277
+ {
1278
+ "name": "exponential-backoff",
1279
+ "version": "^3.1.3"
1280
+ },
1281
+ {
1282
+ "name": "bottleneck",
1283
+ "version": "^2.19.5"
1284
+ },
1285
+ {
1286
+ "name": "throttle-debounce",
1287
+ "version": "^5.0.2"
1288
+ },
1289
+ {
1290
+ "name": "delay",
1291
+ "version": "^7.0.0"
1292
+ },
1293
+ {
1294
+ "name": "graphlib",
1295
+ "version": "^2.1.8"
1296
+ }
1297
+ ];
1298
+ var RESTRICTED_PATTERNS = [
1299
+ /\bprocess\s*\.\s*exit/,
1300
+ /\bprocess\s*\.\s*env/,
1301
+ /\bprocess\s*\.\s*binding/,
1302
+ /\bprocess\s*\.\s*mainModule/,
1303
+ /\bprocess\s*\[/,
1304
+ /\bprocess\s*\(/,
1305
+ /\beval\s*\(/,
1306
+ /\bFunction\s*\(/,
1307
+ /\bnew\s+Function\b/,
1308
+ /\bAsyncFunction\b/,
1309
+ /\bGeneratorFunction\b/,
1310
+ /\bglobalThis\b/,
1311
+ /\bself\s*\[/,
1312
+ /\bimport\s+/,
1313
+ /\bimport\s*\(/,
1314
+ /\bReflect\b/,
1315
+ /\bProxy\b/,
1316
+ /\b__proto__\b/,
1317
+ /\bprototype\s*\[/,
1318
+ /\bprototype\s*\.\s*constructor\b/,
1319
+ /\bconstructor\b/,
1320
+ /\bthis\s*\.\s*constructor\b/,
1321
+ /\barguments\s*\.\s*callee\b/,
1322
+ /\bObject\s*\.\s*defineProperty\b/,
1323
+ /\b__defineGetter__\b/,
1324
+ /\b__defineSetter__\b/,
1325
+ /\b__lookupGetter__\b/,
1326
+ /\b__lookupSetter__\b/,
1327
+ /\bmodule\s*\.\s*(?:constructor|extensions|_compile|_path|_sourceMaps)\b/,
1328
+ /\brequire\s*\.\s*cache\b/,
1329
+ /\brequire\s*\.\s*resolve\b/,
1330
+ /\bError\s*\.\s*captureStackTrace\b/,
1331
+ /\bWebAssembly\b/
1332
+ ];
1333
+
1334
+ // src/validate.ts
1335
+ var ALLOWED_PACKAGE_NAMES = new Set(ALLOWED_PACKAGES.map((p) => p.name));
1336
+ function validatePluginCode(code) {
1337
+ const hasExecute = code.includes("module.exports") || code.includes("exports.execute") || code.includes("export");
1338
+ if (!hasExecute) {
1339
+ return {
1340
+ valid: false,
1341
+ error: "Plugin code must export an execute function. Example: module.exports = { execute: async (input, config, context) => { ... } }"
1342
+ };
1343
+ }
1344
+ for (const pattern of RESTRICTED_PATTERNS) {
1345
+ if (pattern.test(code)) {
1346
+ return {
1347
+ valid: false,
1348
+ error: `Plugin code contains restricted patterns. Plugins cannot access the filesystem, spawn processes, use eval, import modules, or escape the sandbox. (matched ${pattern})`
1349
+ };
1350
+ }
1351
+ }
1352
+ const packages = [];
1353
+ const requireCall = /\brequire\s*\(\s*(['"])([^'"]+)\1\s*\)/g;
1354
+ let match;
1355
+ while ((match = requireCall.exec(code)) !== null) {
1356
+ const name = match[2];
1357
+ if (!ALLOWED_PACKAGE_NAMES.has(name)) {
1358
+ return {
1359
+ valid: false,
1360
+ error: `Plugin code requires "${name}" which is not an allowed package. See ALLOWED_PACKAGES for the list.`
1361
+ };
1362
+ }
1363
+ if (!packages.includes(name)) packages.push(name);
1364
+ }
1365
+ if (/\brequire\s*\(\s*(?!['"][^'"]+['"]\s*\))/.test(code)) {
1366
+ return {
1367
+ valid: false,
1368
+ error: "Plugin code contains a dynamic require() call. Only require() with string literals of allowed packages is permitted."
1369
+ };
1370
+ }
1371
+ return { valid: true, packages };
1372
+ }
1373
+ function sandboxRequire(load) {
1374
+ return (name) => {
1375
+ const allowed = ALLOWED_PACKAGES.find((p) => p.name === name);
1376
+ if (!allowed) throw new Error(`Cannot require "${name}"`);
1377
+ try {
1378
+ return load(name);
1379
+ } catch {
1380
+ throw new Error(
1381
+ `"${name}" is available in the sandbox but not installed here. To run this locally: npm install --save-dev ${name}@${allowed.version}`
1382
+ );
1383
+ }
1384
+ };
1385
+ }
1386
+ function loadPluginCode(code, require2) {
1387
+ const module = { exports: {} };
1388
+ const body = new Function("module", "exports", "require", `"use strict"; ${code}`);
1389
+ body(module, module.exports, require2);
1390
+ return module.exports;
1391
+ }
1392
+
1393
+ // src/context-api.ts
1394
+ var CONTEXT_API = [
1395
+ { path: "input", kind: "variable", info: "What the steps before this one produced, keyed by step name." },
1396
+ { path: "config", kind: "variable", info: "The fields somebody filled in on the canvas." },
1397
+ { path: "context", kind: "variable", info: "Everything about the run: ids, storage, state, media, connections." },
1398
+ { path: "context.workflowId", kind: "property", info: "The workflow this run belongs to." },
1399
+ { path: "context.nodeId", kind: "property", info: "This step's id on the canvas." },
1400
+ { path: "context.userId", kind: "property", info: "Whose run it is." },
1401
+ { path: "context.executionId", kind: "property", info: "This run, distinct from every other run of the workflow." },
1402
+ { path: "context.startedAt", kind: "property", info: "When the run started, as an ISO string." },
1403
+ { path: "context.secrets", kind: "property", info: "Values the plugin was published with. Never the user's credentials." },
1404
+ {
1405
+ path: "context.storage.put",
1406
+ kind: "method",
1407
+ signature: "(path, data, contentType?) => Promise<StorageResult>",
1408
+ info: "Write a file to the account's storage. Data may be a string or bytes."
1409
+ },
1410
+ {
1411
+ path: "context.storage.get",
1412
+ kind: "method",
1413
+ signature: "(path) => Promise<Uint8Array | null>",
1414
+ info: "Read a file back. null when it is not there."
1415
+ },
1416
+ { path: "context.storage.delete", kind: "method", signature: "(path) => Promise<void>", info: "Remove a file." },
1417
+ {
1418
+ path: "context.storage.list",
1419
+ kind: "method",
1420
+ signature: "(prefix?) => Promise<{ files, totalSize }>",
1421
+ info: "Everything under a prefix, or everything."
1422
+ },
1423
+ {
1424
+ path: "context.storage.head",
1425
+ kind: "method",
1426
+ signature: "(path) => Promise<{ size, contentType } | null>",
1427
+ info: "Size and content type without moving the bytes."
1428
+ },
1429
+ {
1430
+ path: "context.storage.signedUrl",
1431
+ kind: "method",
1432
+ signature: "(path, expiresInSeconds?) => Promise<string | null>",
1433
+ info: "A link somebody else can fetch the file from, for a few minutes. For APIs that pull rather than take bytes."
1434
+ },
1435
+ {
1436
+ path: "context.storage.download",
1437
+ kind: "method",
1438
+ signature: "(url, path, contentType?) => Promise<StorageResult>",
1439
+ info: "Pull a URL straight into storage. The bytes never cross this step, so a large file costs the run nothing.",
1440
+ conditional: "Only when the download Worker is configured on the server."
1441
+ },
1442
+ {
1443
+ path: "context.state.get",
1444
+ kind: "method",
1445
+ signature: "(key) => Promise<unknown>",
1446
+ info: "A value this workflow stored on an earlier run. null when never set."
1447
+ },
1448
+ {
1449
+ path: "context.state.set",
1450
+ kind: "method",
1451
+ signature: "(key, value, { ttlSeconds }?) => Promise<void>",
1452
+ info: "Remember something between runs \u2014 a cursor, a last-seen id, a counter."
1453
+ },
1454
+ { path: "context.state.delete", kind: "method", signature: "(key) => Promise<void>", info: "Forget one key." },
1455
+ {
1456
+ path: "context.state.list",
1457
+ kind: "method",
1458
+ signature: "(prefix?) => Promise<{ keys }>",
1459
+ info: "Which keys this workflow has stored."
1460
+ },
1461
+ {
1462
+ path: "context.media.run",
1463
+ kind: "method",
1464
+ signature: "(operation, params) => Promise<Record<string, unknown>>",
1465
+ info: "ffmpeg, by operation name. A plugin never builds a command line \u2014 the server does, one operation at a time.",
1466
+ conditional: "Only when the sandbox and storage are both configured."
1467
+ },
1468
+ {
1469
+ path: "context.connections.get",
1470
+ kind: "method",
1471
+ signature: "(propertyName) => Promise<{ id, request }>",
1472
+ info: "One of the accounts this step was configured with. Takes your property name, not a connection id.",
1473
+ conditional: "Only when the step declares a `connection` property and an account was chosen."
1474
+ },
1475
+ {
1476
+ path: "context.connections.get(...).request",
1477
+ kind: "method",
1478
+ signature: "({ path, method?, query?, headers?, body? }) => Promise<{ ok, status, body }>",
1479
+ info: "A request to the provider, with the credential attached on the way past. Relative paths only \u2014 never a host, and there is no getToken()."
1480
+ },
1481
+ { path: "module.exports.execute", kind: "method", signature: "(input, config, context) => ({ output, data })", info: "The entry point. Return which port to leave by and what to hand on." },
1482
+ { path: "console.log", kind: "method", info: "Appears in the run's log panel. Not on stdout \u2014 the platform reads that." },
1483
+ { path: "console.error", kind: "method", info: "Appears in the run's log panel, marked as an error." }
1484
+ ];
1485
+ var BLOCKED_GLOBALS = [
1486
+ { name: "process", instead: "Ids and secrets are on `context`." },
1487
+ { name: "fs", instead: "Use context.storage." },
1488
+ { name: "child_process", instead: "Not available. For ffmpeg, use context.media.run." },
1489
+ { name: "os", instead: "Not available." },
1490
+ { name: "net", instead: "Use fetch." },
1491
+ { name: "http", instead: "Use fetch." },
1492
+ { name: "https", instead: "Use fetch." },
1493
+ { name: "eval", instead: "Not available." },
1494
+ { name: "Function", instead: "Not available as a constructor." },
1495
+ { name: "Buffer", instead: "Use Uint8Array and TextEncoder/TextDecoder." },
1496
+ { name: "__dirname", instead: "There is no meaningful filesystem." }
1497
+ ];
1498
+ export {
1499
+ ALLOWED_PACKAGES,
1500
+ ALLOWED_PACKAGE_NAMES,
1501
+ BLOCKED_GLOBALS,
1502
+ CONTEXT_API,
1503
+ RESTRICTED_PATTERNS,
1504
+ createLocalState,
1505
+ createLocalStorage,
1506
+ loadPluginCode,
1507
+ sandboxRequire,
1508
+ simulate,
1509
+ validatePluginCode
1510
+ };
1511
+ //# sourceMappingURL=index.mjs.map