@promptbook/pdf 0.112.0-73 → 0.112.0-79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +9 -9
  2. package/esm/index.es.js +313 -210
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  5. package/esm/src/avatars/visuals/octopus3d2AvatarVisual.d.ts +7 -0
  6. package/esm/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +37 -0
  7. package/esm/src/book-components/Chat/save/_common/chatExportRendering.d.ts +47 -0
  8. package/esm/src/book-components/Chat/save/html/htmlSaveFormatDefinition.d.ts +12 -0
  9. package/esm/src/book-components/Chat/save/index.d.ts +2 -2
  10. package/esm/src/book-components/Chat/save/markdown/mdSaveFormatDefinition.d.ts +5 -3
  11. package/esm/src/book-components/Chat/save/pdf/buildChatPdf.d.ts +3 -3
  12. package/esm/src/book-components/Chat/save/pdf/pdfSaveFormatDefinition.d.ts +1 -1
  13. package/esm/src/cli/cli-commands/agent/agentProjectPaths.d.ts +8 -8
  14. package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -1
  15. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +56 -0
  16. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.test.d.ts +1 -0
  17. package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +7 -0
  18. package/esm/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +7 -0
  19. package/esm/src/cli/cli-commands/agents-server/init.d.ts +9 -0
  20. package/esm/src/cli/cli-commands/agents-server/init.test.d.ts +1 -0
  21. package/esm/src/cli/cli-commands/agents-server/initializeAgentsServerProjectConfiguration.d.ts +17 -0
  22. package/esm/src/cli/cli-commands/agents-server/printAgentsServerInitializationSummary.d.ts +7 -0
  23. package/esm/src/cli/cli-commands/agents-server/run.d.ts +14 -0
  24. package/esm/src/cli/cli-commands/agents-server/run.test.d.ts +1 -0
  25. package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +23 -0
  26. package/esm/src/cli/cli-commands/agents-server.d.ts +8 -0
  27. package/esm/src/cli/cli-commands/common/projectInitialization.d.ts +65 -0
  28. package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +44 -0
  29. package/esm/src/cli/common/$deprecateCliCommand.d.ts +8 -0
  30. package/esm/src/cli/common/$deprecateCliCommand.test.d.ts +1 -0
  31. package/esm/src/utils/color/Color.d.ts +4 -44
  32. package/esm/src/utils/color/ColorValue.d.ts +55 -0
  33. package/esm/src/utils/color/isHexColorString.d.ts +10 -0
  34. package/esm/src/utils/color/parseColorString.d.ts +11 -0
  35. package/esm/src/version.d.ts +1 -1
  36. package/package.json +2 -2
  37. package/umd/index.umd.js +313 -210
  38. package/umd/index.umd.js.map +1 -1
  39. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  40. package/umd/src/avatars/visuals/octopus3d2AvatarVisual.d.ts +7 -0
  41. package/umd/src/avatars/visuals/octopus3dAvatarVisualShared.d.ts +37 -0
  42. package/umd/src/book-components/Chat/save/_common/chatExportRendering.d.ts +47 -0
  43. package/umd/src/book-components/Chat/save/html/htmlSaveFormatDefinition.d.ts +12 -0
  44. package/umd/src/book-components/Chat/save/index.d.ts +2 -2
  45. package/umd/src/book-components/Chat/save/markdown/mdSaveFormatDefinition.d.ts +5 -3
  46. package/umd/src/book-components/Chat/save/pdf/buildChatPdf.d.ts +3 -3
  47. package/umd/src/book-components/Chat/save/pdf/pdfSaveFormatDefinition.d.ts +1 -1
  48. package/umd/src/cli/cli-commands/agent/agentProjectPaths.d.ts +8 -8
  49. package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -1
  50. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +56 -0
  51. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.test.d.ts +1 -0
  52. package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.d.ts +7 -0
  53. package/umd/src/cli/cli-commands/agents-server/ensureAgentsServerGitignoreFile.d.ts +7 -0
  54. package/umd/src/cli/cli-commands/agents-server/init.d.ts +9 -0
  55. package/umd/src/cli/cli-commands/agents-server/init.test.d.ts +1 -0
  56. package/umd/src/cli/cli-commands/agents-server/initializeAgentsServerProjectConfiguration.d.ts +17 -0
  57. package/umd/src/cli/cli-commands/agents-server/printAgentsServerInitializationSummary.d.ts +7 -0
  58. package/umd/src/cli/cli-commands/agents-server/run.d.ts +14 -0
  59. package/umd/src/cli/cli-commands/agents-server/run.test.d.ts +1 -0
  60. package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +23 -0
  61. package/umd/src/cli/cli-commands/agents-server.d.ts +8 -0
  62. package/umd/src/cli/cli-commands/common/projectInitialization.d.ts +65 -0
  63. package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +44 -0
  64. package/umd/src/cli/common/$deprecateCliCommand.d.ts +8 -0
  65. package/umd/src/cli/common/$deprecateCliCommand.test.d.ts +1 -0
  66. package/umd/src/utils/color/Color.d.ts +4 -44
  67. package/umd/src/utils/color/ColorValue.d.ts +55 -0
  68. package/umd/src/utils/color/isHexColorString.d.ts +10 -0
  69. package/umd/src/utils/color/parseColorString.d.ts +11 -0
  70. package/umd/src/version.d.ts +1 -1
  71. package/esm/src/cli/cli-commands/coder/appendBlock.d.ts +0 -6
  72. package/esm/src/cli/cli-commands/coder/readTextFileIfExists.d.ts +0 -6
  73. package/umd/src/cli/cli-commands/coder/appendBlock.d.ts +0 -6
  74. package/umd/src/cli/cli-commands/coder/readTextFileIfExists.d.ts +0 -6
package/umd/index.umd.js CHANGED
@@ -23,7 +23,7 @@
23
23
  * @generated
24
24
  * @see https://github.com/webgptorg/promptbook
25
25
  */
26
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-73';
26
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-79';
27
27
  /**
28
28
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
29
29
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -305,6 +305,111 @@
305
305
  }
306
306
  }
307
307
 
308
+ /**
309
+ * Shared immutable channel storage and serialization helpers for `Color`.
310
+ *
311
+ * @private base class of Color
312
+ */
313
+ class ColorValue {
314
+ constructor(red, green, blue, alpha = 255) {
315
+ this.red = red;
316
+ this.green = green;
317
+ this.blue = blue;
318
+ this.alpha = alpha;
319
+ checkChannelValue('Red', red);
320
+ checkChannelValue('Green', green);
321
+ checkChannelValue('Blue', blue);
322
+ checkChannelValue('Alpha', alpha);
323
+ }
324
+ /**
325
+ * Shortcut for `red` property
326
+ * Number from 0 to 255
327
+ * @alias red
328
+ */
329
+ get r() {
330
+ return this.red;
331
+ }
332
+ /**
333
+ * Shortcut for `green` property
334
+ * Number from 0 to 255
335
+ * @alias green
336
+ */
337
+ get g() {
338
+ return this.green;
339
+ }
340
+ /**
341
+ * Shortcut for `blue` property
342
+ * Number from 0 to 255
343
+ * @alias blue
344
+ */
345
+ get b() {
346
+ return this.blue;
347
+ }
348
+ /**
349
+ * Shortcut for `alpha` property
350
+ * Number from 0 (transparent) to 255 (opaque)
351
+ * @alias alpha
352
+ */
353
+ get a() {
354
+ return this.alpha;
355
+ }
356
+ /**
357
+ * Shortcut for `alpha` property
358
+ * Number from 0 (transparent) to 255 (opaque)
359
+ * @alias alpha
360
+ */
361
+ get opacity() {
362
+ return this.alpha;
363
+ }
364
+ /**
365
+ * Shortcut for 1-`alpha` property
366
+ */
367
+ get transparency() {
368
+ return 255 - this.alpha;
369
+ }
370
+ clone() {
371
+ return take(this.createColor(this.red, this.green, this.blue, this.alpha));
372
+ }
373
+ toString() {
374
+ return this.toHex();
375
+ }
376
+ toHex() {
377
+ if (this.alpha === 255) {
378
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
379
+ .toString(16)
380
+ .padStart(2, '0')}`;
381
+ }
382
+ else {
383
+ return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
384
+ .toString(16)
385
+ .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
386
+ }
387
+ }
388
+ toRgb() {
389
+ if (this.alpha === 255) {
390
+ return `rgb(${this.red}, ${this.green}, ${this.blue})`;
391
+ }
392
+ else {
393
+ return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
394
+ }
395
+ }
396
+ toHsl() {
397
+ throw new Error(`Getting HSL is not implemented`);
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Checks if the given value is a valid hex color string
403
+ *
404
+ * @param value - value to check
405
+ * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
406
+ *
407
+ * @private function of Color
408
+ */
409
+ function isHexColorString(value) {
410
+ return (typeof value === 'string' && /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
411
+ }
412
+
308
413
  /**
309
414
  * Constant for short hex lengths.
310
415
  */
@@ -516,16 +621,53 @@
516
621
 
517
622
  /**
518
623
  * Pattern matching hsl regex.
624
+ *
625
+ * @private function of Color
519
626
  */
520
627
  const HSL_REGEX_PATTERN = /^hsl\(\s*([0-9.]+)\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/;
521
628
  /**
522
629
  * Pattern matching RGB regex.
630
+ *
631
+ * @private function of Color
523
632
  */
524
633
  const RGB_REGEX_PATTERN = /^rgb\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
525
634
  /**
526
635
  * Pattern matching rgba regex.
636
+ *
637
+ * @private function of Color
527
638
  */
528
639
  const RGBA_REGEX_PATTERN = /^rgba\(\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*,\s*([0-9.%-]+)\s*\)$/;
640
+ /**
641
+ * Parses a supported color string into RGBA channels.
642
+ *
643
+ * @param color as a string for example `#009edd`, `rgb(0,158,221)`, `rgb(0%,62%,86.7%)`, `hsl(197.1,100%,43.3%)`, `red`, `darkgrey`,...
644
+ * @returns RGBA channel values.
645
+ *
646
+ * @private function of Color
647
+ */
648
+ function parseColorString(color) {
649
+ const trimmed = color.trim();
650
+ const cssColor = CSS_COLORS[trimmed];
651
+ if (cssColor) {
652
+ return parseColorString(cssColor);
653
+ }
654
+ else if (isHexColorString(trimmed)) {
655
+ return parseHexColor(trimmed);
656
+ }
657
+ if (HSL_REGEX_PATTERN.test(trimmed)) {
658
+ return parseHslColor(trimmed);
659
+ }
660
+ else if (RGB_REGEX_PATTERN.test(trimmed)) {
661
+ return parseRgbColor(trimmed);
662
+ }
663
+ else if (RGBA_REGEX_PATTERN.test(trimmed)) {
664
+ return parseRgbaColor(trimmed);
665
+ }
666
+ else {
667
+ throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
668
+ }
669
+ }
670
+
529
671
  /**
530
672
  * Color object represents an RGB color with alpha channel
531
673
  *
@@ -533,7 +675,7 @@
533
675
  *
534
676
  * @public exported from `@promptbook/color`
535
677
  */
536
- class Color {
678
+ class Color extends ColorValue {
537
679
  /**
538
680
  * Creates a new Color instance from miscellaneous formats
539
681
  * - It can receive Color instance and just return the same instance
@@ -606,25 +748,7 @@
606
748
  * @returns Color object
607
749
  */
608
750
  static fromString(color) {
609
- const trimmed = color.trim();
610
- if (CSS_COLORS[trimmed]) {
611
- return Color.fromString(CSS_COLORS[trimmed]);
612
- }
613
- else if (Color.isHexColorString(trimmed)) {
614
- return Color.fromHex(trimmed);
615
- }
616
- if (HSL_REGEX_PATTERN.test(trimmed)) {
617
- return Color.fromHsl(trimmed);
618
- }
619
- else if (RGB_REGEX_PATTERN.test(trimmed)) {
620
- return Color.fromRgbString(trimmed);
621
- }
622
- else if (RGBA_REGEX_PATTERN.test(trimmed)) {
623
- return Color.fromRgbaString(trimmed);
624
- }
625
- else {
626
- throw new Error(`Can not create a new Color instance from string "${trimmed}".`);
627
- }
751
+ return Color.fromColorChannels(parseColorString(color));
628
752
  }
629
753
  /**
630
754
  * Gets common color
@@ -654,8 +778,7 @@
654
778
  * @returns Color object
655
779
  */
656
780
  static fromHex(hex) {
657
- const { red, green, blue, alpha } = parseHexColor(hex);
658
- return take(new Color(red, green, blue, alpha));
781
+ return Color.fromColorChannels(parseHexColor(hex));
659
782
  }
660
783
  /**
661
784
  * Creates a new Color instance from color in hsl format
@@ -664,8 +787,7 @@
664
787
  * @returns Color object
665
788
  */
666
789
  static fromHsl(hsl) {
667
- const { red, green, blue, alpha } = parseHslColor(hsl);
668
- return take(new Color(red, green, blue, alpha));
790
+ return Color.fromColorChannels(parseHslColor(hsl));
669
791
  }
670
792
  /**
671
793
  * Creates a new Color instance from color in rgb format
@@ -674,8 +796,7 @@
674
796
  * @returns Color object
675
797
  */
676
798
  static fromRgbString(rgb) {
677
- const { red, green, blue, alpha } = parseRgbColor(rgb);
678
- return take(new Color(red, green, blue, alpha));
799
+ return Color.fromColorChannels(parseRgbColor(rgb));
679
800
  }
680
801
  /**
681
802
  * Creates a new Color instance from color in rbga format
@@ -684,8 +805,7 @@
684
805
  * @returns Color object
685
806
  */
686
807
  static fromRgbaString(rgba) {
687
- const { red, green, blue, alpha } = parseRgbaColor(rgba);
688
- return take(new Color(red, green, blue, alpha));
808
+ return Color.fromColorChannels(parseRgbaColor(rgba));
689
809
  }
690
810
  /**
691
811
  * Creates a new Color for color channels values
@@ -697,7 +817,7 @@
697
817
  * @returns Color object
698
818
  */
699
819
  static fromValues(red, green, blue, alpha = 255) {
700
- return take(new Color(red, green, blue, alpha));
820
+ return Color.fromColorChannels({ red, green, blue, alpha });
701
821
  }
702
822
  /**
703
823
  * Checks if the given value is a valid Color object.
@@ -730,8 +850,7 @@
730
850
  * @returns true if the value is a valid hex color string (e.g., `#009edd`, `#fff`, etc.)
731
851
  */
732
852
  static isHexColorString(value) {
733
- return (typeof value === 'string' &&
734
- /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value));
853
+ return isHexColorString(value);
735
854
  }
736
855
  /**
737
856
  * Creates new Color object
@@ -744,89 +863,13 @@
744
863
  * @param alpha number from 0 (transparent) to 255 (opaque)
745
864
  */
746
865
  constructor(red, green, blue, alpha = 255) {
747
- this.red = red;
748
- this.green = green;
749
- this.blue = blue;
750
- this.alpha = alpha;
751
- checkChannelValue('Red', red);
752
- checkChannelValue('Green', green);
753
- checkChannelValue('Blue', blue);
754
- checkChannelValue('Alpha', alpha);
866
+ super(red, green, blue, alpha);
755
867
  }
756
- /**
757
- * Shortcut for `red` property
758
- * Number from 0 to 255
759
- * @alias red
760
- */
761
- get r() {
762
- return this.red;
868
+ createColor(red, green, blue, alpha) {
869
+ return new Color(red, green, blue, alpha);
763
870
  }
764
- /**
765
- * Shortcut for `green` property
766
- * Number from 0 to 255
767
- * @alias green
768
- */
769
- get g() {
770
- return this.green;
771
- }
772
- /**
773
- * Shortcut for `blue` property
774
- * Number from 0 to 255
775
- * @alias blue
776
- */
777
- get b() {
778
- return this.blue;
779
- }
780
- /**
781
- * Shortcut for `alpha` property
782
- * Number from 0 (transparent) to 255 (opaque)
783
- * @alias alpha
784
- */
785
- get a() {
786
- return this.alpha;
787
- }
788
- /**
789
- * Shortcut for `alpha` property
790
- * Number from 0 (transparent) to 255 (opaque)
791
- * @alias alpha
792
- */
793
- get opacity() {
794
- return this.alpha;
795
- }
796
- /**
797
- * Shortcut for 1-`alpha` property
798
- */
799
- get transparency() {
800
- return 255 - this.alpha;
801
- }
802
- clone() {
803
- return take(new Color(this.red, this.green, this.blue, this.alpha));
804
- }
805
- toString() {
806
- return this.toHex();
807
- }
808
- toHex() {
809
- if (this.alpha === 255) {
810
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
811
- .toString(16)
812
- .padStart(2, '0')}`;
813
- }
814
- else {
815
- return `#${this.red.toString(16).padStart(2, '0')}${this.green.toString(16).padStart(2, '0')}${this.blue
816
- .toString(16)
817
- .padStart(2, '0')}${this.alpha.toString(16).padStart(2, '0')}`;
818
- }
819
- }
820
- toRgb() {
821
- if (this.alpha === 255) {
822
- return `rgb(${this.red}, ${this.green}, ${this.blue})`;
823
- }
824
- else {
825
- return `rgba(${this.red}, ${this.green}, ${this.blue}, ${Math.round((this.alpha / 255) * 100)}%)`;
826
- }
827
- }
828
- toHsl() {
829
- throw new Error(`Getting HSL is not implemented`);
871
+ static fromColorChannels({ red, green, blue, alpha }) {
872
+ return take(new Color(red, green, blue, alpha));
830
873
  }
831
874
  }
832
875
 
@@ -2235,7 +2278,7 @@
2235
2278
  */
2236
2279
  function createPostprocessingCommands(task) {
2237
2280
  var _a;
2238
- return ((_a = task.postprocessingFunctionNames) === null || _a === void 0 ? void 0 : _a.map((postprocessingFunctionName) => `POSTPROCESSING \`${postprocessingFunctionName}\``)) || [];
2281
+ return (((_a = task.postprocessingFunctionNames) === null || _a === void 0 ? void 0 : _a.map((postprocessingFunctionName) => `POSTPROCESSING \`${postprocessingFunctionName}\``)) || []);
2239
2282
  }
2240
2283
  /**
2241
2284
  * Collects expectation commands.
@@ -2400,120 +2443,183 @@
2400
2443
  * @public exported from `@promptbook/utils`
2401
2444
  */
2402
2445
  function checkSerializableAsJson(options) {
2403
- const { value, name, message } = options;
2446
+ checkSerializableValue(options);
2447
+ }
2448
+ // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
2449
+ // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
2450
+ // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
2451
+ /**
2452
+ * Checks one value and dispatches to the appropriate specialized validator.
2453
+ *
2454
+ * @private function of `checkSerializableAsJson`
2455
+ */
2456
+ function checkSerializableValue(options) {
2457
+ const { value } = options;
2458
+ if (isSerializablePrimitive(value)) {
2459
+ return;
2460
+ }
2404
2461
  if (value === undefined) {
2405
- throw new UnexpectedError(`${name} is undefined`);
2462
+ throw new UnexpectedError(`${options.name} is undefined`);
2406
2463
  }
2407
- else if (value === null) {
2408
- return;
2464
+ if (typeof value === 'symbol') {
2465
+ throw new UnexpectedError(`${options.name} is symbol`);
2409
2466
  }
2410
- else if (typeof value === 'boolean') {
2411
- return;
2467
+ if (typeof value === 'function') {
2468
+ throw new UnexpectedError(`${options.name} is function`);
2412
2469
  }
2413
- else if (typeof value === 'number' && !isNaN(value)) {
2470
+ if (Array.isArray(value)) {
2471
+ checkSerializableArray(options, value);
2414
2472
  return;
2415
2473
  }
2416
- else if (typeof value === 'string') {
2474
+ if (value !== null && typeof value === 'object') {
2475
+ checkSerializableObject(options, value);
2417
2476
  return;
2418
2477
  }
2419
- else if (typeof value === 'symbol') {
2420
- throw new UnexpectedError(`${name} is symbol`);
2421
- }
2422
- else if (typeof value === 'function') {
2423
- throw new UnexpectedError(`${name} is function`);
2424
- }
2425
- else if (typeof value === 'object' && Array.isArray(value)) {
2426
- for (let i = 0; i < value.length; i++) {
2427
- checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
2428
- }
2478
+ throwUnknownTypeError(options);
2479
+ }
2480
+ /**
2481
+ * Checks the primitive values that are directly JSON serializable.
2482
+ *
2483
+ * @private function of `checkSerializableAsJson`
2484
+ */
2485
+ function isSerializablePrimitive(value) {
2486
+ return (value === null ||
2487
+ typeof value === 'boolean' ||
2488
+ (typeof value === 'number' && !isNaN(value)) ||
2489
+ typeof value === 'string');
2490
+ }
2491
+ /**
2492
+ * Recursively checks JSON array items.
2493
+ *
2494
+ * @private function of `checkSerializableAsJson`
2495
+ */
2496
+ function checkSerializableArray(context, arrayValue) {
2497
+ for (let index = 0; index < arrayValue.length; index++) {
2498
+ checkSerializableAsJson({
2499
+ ...context,
2500
+ name: `${context.name}[${index}]`,
2501
+ value: arrayValue[index],
2502
+ });
2429
2503
  }
2430
- else if (typeof value === 'object') {
2431
- if (value instanceof Date) {
2432
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2433
- \`${name}\` is Date
2504
+ }
2505
+ /**
2506
+ * Checks object-like values and dispatches special unsupported built-ins.
2507
+ *
2508
+ * @private function of `checkSerializableAsJson`
2509
+ */
2510
+ function checkSerializableObject(context, objectValue) {
2511
+ checkUnsupportedObjectType(context, objectValue);
2512
+ checkSerializableObjectEntries(context, objectValue);
2513
+ assertJsonStringificationSucceeds(context, objectValue);
2514
+ }
2515
+ /**
2516
+ * Rejects built-in objects that must be converted before JSON serialization.
2517
+ *
2518
+ * @private function of `checkSerializableAsJson`
2519
+ */
2520
+ function checkUnsupportedObjectType(context, objectValue) {
2521
+ if (objectValue instanceof Date) {
2522
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2523
+ \`${context.name}\` is Date
2434
2524
 
2435
- Use \`string_date_iso8601\` instead
2525
+ Use \`string_date_iso8601\` instead
2436
2526
 
2437
- Additional message for \`${name}\`:
2438
- ${block(message || '(nothing)')}
2439
- `));
2440
- }
2441
- else if (value instanceof Map) {
2442
- throw new UnexpectedError(`${name} is Map`);
2443
- }
2444
- else if (value instanceof Set) {
2445
- throw new UnexpectedError(`${name} is Set`);
2446
- }
2447
- else if (value instanceof RegExp) {
2448
- throw new UnexpectedError(`${name} is RegExp`);
2449
- }
2450
- else if (value instanceof Error) {
2451
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2452
- \`${name}\` is unserialized Error
2527
+ Additional message for \`${context.name}\`:
2528
+ ${block(context.message || '(nothing)')}
2529
+ `));
2530
+ }
2531
+ if (objectValue instanceof Map) {
2532
+ throw new UnexpectedError(`${context.name} is Map`);
2533
+ }
2534
+ if (objectValue instanceof Set) {
2535
+ throw new UnexpectedError(`${context.name} is Set`);
2536
+ }
2537
+ if (objectValue instanceof RegExp) {
2538
+ throw new UnexpectedError(`${context.name} is RegExp`);
2539
+ }
2540
+ if (objectValue instanceof Error) {
2541
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2542
+ \`${context.name}\` is unserialized Error
2453
2543
 
2454
- Use function \`serializeError\`
2544
+ Use function \`serializeError\`
2455
2545
 
2456
- Additional message for \`${name}\`:
2457
- ${block(message || '(nothing)')}
2546
+ Additional message for \`${context.name}\`:
2547
+ ${block(context.message || '(nothing)')}
2458
2548
 
2459
- `));
2549
+ `));
2550
+ }
2551
+ }
2552
+ /**
2553
+ * Recursively checks object properties while preserving omitted `undefined` keys.
2554
+ *
2555
+ * @private function of `checkSerializableAsJson`
2556
+ */
2557
+ function checkSerializableObjectEntries(context, objectValue) {
2558
+ for (const [subName, subValue] of Object.entries(objectValue)) {
2559
+ if (subValue === undefined) {
2560
+ // Note: undefined in object is serializable - it is just omitted
2561
+ continue;
2460
2562
  }
2461
- else {
2462
- for (const [subName, subValue] of Object.entries(value)) {
2463
- if (subValue === undefined) {
2464
- // Note: undefined in object is serializable - it is just omitted
2465
- continue;
2466
- }
2467
- checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
2468
- }
2469
- try {
2470
- JSON.stringify(value); // <- TODO: [0]
2471
- }
2472
- catch (error) {
2473
- assertsError(error);
2474
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2475
- \`${name}\` is not serializable
2563
+ checkSerializableAsJson({
2564
+ ...context,
2565
+ name: `${context.name}.${subName}`,
2566
+ value: subValue,
2567
+ });
2568
+ }
2569
+ }
2570
+ /**
2571
+ * Uses `JSON.stringify` as the final guard for cases like circular references.
2572
+ *
2573
+ * @private function of `checkSerializableAsJson`
2574
+ */
2575
+ function assertJsonStringificationSucceeds(context, objectValue) {
2576
+ try {
2577
+ JSON.stringify(objectValue); // <- TODO: [0]
2578
+ }
2579
+ catch (error) {
2580
+ assertsError(error);
2581
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2582
+ \`${context.name}\` is not serializable
2476
2583
 
2477
- ${block(error.stack || error.message)}
2584
+ ${block(error.stack || error.message)}
2478
2585
 
2479
- Additional message for \`${name}\`:
2480
- ${block(message || '(nothing)')}
2481
- `));
2586
+ Additional message for \`${context.name}\`:
2587
+ ${block(context.message || '(nothing)')}
2588
+ `));
2589
+ }
2590
+ /*
2591
+ TODO: [0] Is there some more elegant way to check circular references?
2592
+ const seen = new Set();
2593
+ const stack = [{ value }];
2594
+ while (stack.length > 0) {
2595
+ const { value } = stack.pop()!;
2596
+ if (typeof value === 'object' && value !== null) {
2597
+ if (seen.has(value)) {
2598
+ throw new UnexpectedError(`${name} has circular reference`);
2482
2599
  }
2483
- /*
2484
- TODO: [0] Is there some more elegant way to check circular references?
2485
- const seen = new Set();
2486
- const stack = [{ value }];
2487
- while (stack.length > 0) {
2488
- const { value } = stack.pop()!;
2489
- if (typeof value === 'object' && value !== null) {
2490
- if (seen.has(value)) {
2491
- throw new UnexpectedError(`${name} has circular reference`);
2492
- }
2493
- seen.add(value);
2494
- if (Array.isArray(value)) {
2495
- stack.push(...value.map((value) => ({ value })));
2496
- } else {
2497
- stack.push(...Object.values(value).map((value) => ({ value })));
2498
- }
2499
- }
2600
+ seen.add(value);
2601
+ if (Array.isArray(value)) {
2602
+ stack.push(...value.map((value) => ({ value })));
2603
+ } else {
2604
+ stack.push(...Object.values(value).map((value) => ({ value })));
2500
2605
  }
2501
- */
2502
- return;
2503
2606
  }
2504
2607
  }
2505
- else {
2506
- throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2507
- \`${name}\` is unknown type
2608
+ */
2609
+ }
2610
+ /**
2611
+ * Throws the fallback error for unsupported value types like `bigint` and `NaN`.
2612
+ *
2613
+ * @private function of `checkSerializableAsJson`
2614
+ */
2615
+ function throwUnknownTypeError(context) {
2616
+ throw new UnexpectedError(spacetrim.spaceTrim((block) => `
2617
+ \`${context.name}\` is unknown type
2508
2618
 
2509
- Additional message for \`${name}\`:
2510
- ${block(message || '(nothing)')}
2511
- `));
2512
- }
2619
+ Additional message for \`${context.name}\`:
2620
+ ${block(context.message || '(nothing)')}
2621
+ `));
2513
2622
  }
2514
- // TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
2515
- // TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
2516
- // Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
2517
2623
 
2518
2624
  /**
2519
2625
  * Creates a deep clone of the given object
@@ -3077,8 +3183,7 @@
3077
3183
  * @private internal utility of `validatePipeline`
3078
3184
  */
3079
3185
  function validateTaskSupportsJokers(task, pipelineIdentification) {
3080
- if (task.format ||
3081
- task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
3186
+ if (task.format || task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
3082
3187
  return;
3083
3188
  }
3084
3189
  throw new PipelineLogicError(spacetrim.spaceTrim((block) => `
@@ -7146,9 +7251,7 @@
7146
7251
  ${block(quoteMultilineText(((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message) || ''))}
7147
7252
 
7148
7253
  Result:
7149
- ${block(failure.result === null
7150
- ? 'null'
7151
- : quoteMultilineText(spacetrim.spaceTrim(failure.result)))}
7254
+ ${block(failure.result === null ? 'null' : quoteMultilineText(spacetrim.spaceTrim(failure.result)))}
7152
7255
  `;
7153
7256
  }))
7154
7257
  .join('\n\n---\n\n');