@character-foundry/character-foundry 0.4.2 → 0.4.3-dev.1766103111

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 (57) hide show
  1. package/dist/charx.cjs +87 -54
  2. package/dist/charx.cjs.map +1 -1
  3. package/dist/charx.d.cts +40 -31
  4. package/dist/charx.d.ts +40 -31
  5. package/dist/charx.js +87 -54
  6. package/dist/charx.js.map +1 -1
  7. package/dist/exporter.cjs +106 -56
  8. package/dist/exporter.cjs.map +1 -1
  9. package/dist/exporter.d.cts +37 -28
  10. package/dist/exporter.d.ts +37 -28
  11. package/dist/exporter.js +106 -56
  12. package/dist/exporter.js.map +1 -1
  13. package/dist/federation.cjs +104 -36
  14. package/dist/federation.cjs.map +1 -1
  15. package/dist/federation.d.cts +72 -28
  16. package/dist/federation.d.ts +72 -28
  17. package/dist/federation.js +104 -36
  18. package/dist/federation.js.map +1 -1
  19. package/dist/index.cjs +106 -56
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +71 -50
  22. package/dist/index.d.ts +71 -50
  23. package/dist/index.js +106 -56
  24. package/dist/index.js.map +1 -1
  25. package/dist/loader.cjs +173 -33
  26. package/dist/loader.cjs.map +1 -1
  27. package/dist/loader.d.cts +65 -37
  28. package/dist/loader.d.ts +65 -37
  29. package/dist/loader.js +173 -33
  30. package/dist/loader.js.map +1 -1
  31. package/dist/lorebook.d.cts +57 -40
  32. package/dist/lorebook.d.ts +57 -40
  33. package/dist/normalizer.cjs +74 -20
  34. package/dist/normalizer.cjs.map +1 -1
  35. package/dist/normalizer.d.cts +97 -67
  36. package/dist/normalizer.d.ts +97 -67
  37. package/dist/normalizer.js +74 -20
  38. package/dist/normalizer.js.map +1 -1
  39. package/dist/png.cjs +74 -20
  40. package/dist/png.cjs.map +1 -1
  41. package/dist/png.d.cts +57 -41
  42. package/dist/png.d.ts +57 -41
  43. package/dist/png.js +74 -20
  44. package/dist/png.js.map +1 -1
  45. package/dist/schemas.cjs +82 -25
  46. package/dist/schemas.cjs.map +1 -1
  47. package/dist/schemas.d.cts +181 -115
  48. package/dist/schemas.d.ts +181 -115
  49. package/dist/schemas.js +82 -25
  50. package/dist/schemas.js.map +1 -1
  51. package/dist/voxta.cjs +93 -22
  52. package/dist/voxta.cjs.map +1 -1
  53. package/dist/voxta.d.cts +51 -37
  54. package/dist/voxta.d.ts +51 -37
  55. package/dist/voxta.js +93 -22
  56. package/dist/voxta.js.map +1 -1
  57. package/package.json +5 -5
package/dist/charx.cjs CHANGED
@@ -440,6 +440,58 @@ var import_zod = require("zod");
440
440
  var import_zod2 = require("zod");
441
441
  var import_zod3 = require("zod");
442
442
  var import_zod4 = require("zod");
443
+ function preprocessTimestamp(val) {
444
+ if (val === null || val === void 0) return void 0;
445
+ let num;
446
+ if (typeof val === "number") {
447
+ num = val;
448
+ } else if (typeof val === "string") {
449
+ const trimmed = val.trim();
450
+ if (!trimmed) return void 0;
451
+ const parsed = Number(trimmed);
452
+ if (!isNaN(parsed)) {
453
+ num = parsed;
454
+ } else {
455
+ const date = new Date(trimmed);
456
+ if (isNaN(date.getTime())) return void 0;
457
+ num = Math.floor(date.getTime() / 1e3);
458
+ }
459
+ } else {
460
+ return void 0;
461
+ }
462
+ if (num > 1e10) {
463
+ num = Math.floor(num / 1e3);
464
+ }
465
+ if (num < 0) return void 0;
466
+ return num;
467
+ }
468
+ function preprocessNumeric(val) {
469
+ if (val === null || val === void 0) return void 0;
470
+ if (typeof val === "number") {
471
+ return isNaN(val) ? void 0 : val;
472
+ }
473
+ if (typeof val === "string") {
474
+ const trimmed = val.trim();
475
+ if (!trimmed) return void 0;
476
+ const parsed = Number(trimmed);
477
+ return isNaN(parsed) ? void 0 : parsed;
478
+ }
479
+ return void 0;
480
+ }
481
+ var KNOWN_ASSET_TYPES = /* @__PURE__ */ new Set([
482
+ "icon",
483
+ "background",
484
+ "emotion",
485
+ "user_icon",
486
+ "sound",
487
+ "video",
488
+ "custom",
489
+ "x-risu-asset"
490
+ ]);
491
+ function preprocessAssetType(val) {
492
+ if (typeof val !== "string") return "custom";
493
+ return KNOWN_ASSET_TYPES.has(val) ? val : "custom";
494
+ }
443
495
  var ISO8601Schema = import_zod.z.string().datetime();
444
496
  var UUIDSchema = import_zod.z.string().uuid();
445
497
  var SpecSchema = import_zod.z.enum(["v2", "v3"]);
@@ -462,16 +514,19 @@ var SourceFormatSchema = import_zod.z.enum([
462
514
  // VoxPkg format
463
515
  ]);
464
516
  var OriginalShapeSchema = import_zod.z.enum(["wrapped", "unwrapped", "legacy"]);
465
- var AssetTypeSchema = import_zod.z.enum([
466
- "icon",
467
- "background",
468
- "emotion",
469
- "user_icon",
470
- "sound",
471
- "video",
472
- "custom",
473
- "x-risu-asset"
474
- ]);
517
+ var AssetTypeSchema = import_zod.z.preprocess(
518
+ preprocessAssetType,
519
+ import_zod.z.enum([
520
+ "icon",
521
+ "background",
522
+ "emotion",
523
+ "user_icon",
524
+ "sound",
525
+ "video",
526
+ "custom",
527
+ "x-risu-asset"
528
+ ])
529
+ );
475
530
  var AssetDescriptorSchema = import_zod.z.object({
476
531
  type: AssetTypeSchema,
477
532
  uri: import_zod.z.string(),
@@ -500,13 +555,13 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
500
555
  selective: import_zod2.z.boolean().nullable().optional(),
501
556
  secondary_keys: import_zod2.z.array(import_zod2.z.string()).nullable().optional(),
502
557
  constant: import_zod2.z.boolean().nullable().optional(),
503
- position: import_zod2.z.union([import_zod2.z.enum(["before_char", "after_char"]), import_zod2.z.number().int(), import_zod2.z.literal("")]).nullable().optional()
558
+ position: import_zod2.z.union([import_zod2.z.enum(["before_char", "after_char", "in_chat"]), import_zod2.z.number().int(), import_zod2.z.literal("")]).nullable().optional()
504
559
  }).passthrough();
505
560
  var CCv2CharacterBookSchema = import_zod2.z.object({
506
561
  name: import_zod2.z.string().optional(),
507
562
  description: import_zod2.z.string().optional(),
508
- scan_depth: import_zod2.z.number().int().nonnegative().optional(),
509
- token_budget: import_zod2.z.number().int().nonnegative().optional(),
563
+ scan_depth: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
564
+ token_budget: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
510
565
  recursive_scanning: import_zod2.z.boolean().optional(),
511
566
  extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
512
567
  entries: import_zod2.z.array(CCv2LorebookEntrySchema)
@@ -553,7 +608,7 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
553
608
  selective: import_zod3.z.boolean().nullable().optional(),
554
609
  secondary_keys: import_zod3.z.array(import_zod3.z.string()).nullable().optional(),
555
610
  constant: import_zod3.z.boolean().nullable().optional(),
556
- position: import_zod3.z.union([import_zod3.z.enum(["before_char", "after_char"]), import_zod3.z.number().int(), import_zod3.z.literal("")]).nullable().optional(),
611
+ position: import_zod3.z.union([import_zod3.z.enum(["before_char", "after_char", "in_chat"]), import_zod3.z.number().int(), import_zod3.z.literal("")]).nullable().optional(),
557
612
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
558
613
  // v3 specific - also lenient with types since SillyTavern uses numbers for enums
559
614
  automation_id: import_zod3.z.string().optional(),
@@ -569,8 +624,8 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
569
624
  var CCv3CharacterBookSchema = import_zod3.z.object({
570
625
  name: import_zod3.z.string().optional(),
571
626
  description: import_zod3.z.string().optional(),
572
- scan_depth: import_zod3.z.number().int().nonnegative().optional(),
573
- token_budget: import_zod3.z.number().int().nonnegative().optional(),
627
+ scan_depth: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
628
+ token_budget: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
574
629
  recursive_scanning: import_zod3.z.boolean().optional(),
575
630
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
576
631
  entries: import_zod3.z.array(CCv3LorebookEntrySchema)
@@ -602,10 +657,9 @@ var CCv3DataInnerSchema = import_zod3.z.object({
602
657
  nickname: import_zod3.z.string().optional(),
603
658
  creator_notes_multilingual: import_zod3.z.record(import_zod3.z.string()).optional(),
604
659
  source: import_zod3.z.array(import_zod3.z.string()).optional(),
605
- creation_date: import_zod3.z.number().int().nonnegative().optional(),
606
- // Unix timestamp in seconds
607
- modification_date: import_zod3.z.number().int().nonnegative().optional()
608
- // Unix timestamp in seconds
660
+ // Unix timestamps - preprocess to handle ISO strings, numeric strings, milliseconds
661
+ creation_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional()),
662
+ modification_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional())
609
663
  });
610
664
  var CCv3DataSchema = import_zod3.z.object({
611
665
  spec: import_zod3.z.literal("chara_card_v3"),
@@ -868,36 +922,6 @@ var SAFE_ASSET_TYPES = /* @__PURE__ */ new Set([
868
922
  "data",
869
923
  "unknown"
870
924
  ]);
871
- var SAFE_EXTENSIONS = /* @__PURE__ */ new Set([
872
- // Images
873
- "png",
874
- "jpg",
875
- "jpeg",
876
- "webp",
877
- "gif",
878
- "avif",
879
- "svg",
880
- "bmp",
881
- "ico",
882
- // Audio
883
- "mp3",
884
- "wav",
885
- "ogg",
886
- "flac",
887
- "m4a",
888
- "aac",
889
- "opus",
890
- // Video
891
- "mp4",
892
- "webm",
893
- "avi",
894
- "mov",
895
- "mkv",
896
- // Data
897
- "json",
898
- "txt",
899
- "bin"
900
- ]);
901
925
  function getCharxCategory(mimetype) {
902
926
  if (mimetype.startsWith("image/")) return "images";
903
927
  if (mimetype.startsWith("audio/")) return "audio";
@@ -913,11 +937,20 @@ function sanitizeAssetType(type) {
913
937
  return sanitized || "custom";
914
938
  }
915
939
  function sanitizeExtension(ext) {
916
- const normalized = ext.replace(/^\./, "").toLowerCase().replace(/[^a-z0-9]/g, "");
917
- if (SAFE_EXTENSIONS.has(normalized)) {
918
- return normalized;
940
+ const normalized = ext.trim().replace(/^\./, "").toLowerCase();
941
+ if (!normalized) {
942
+ throw new Error("Invalid asset extension: empty extension");
943
+ }
944
+ if (normalized.length > 64) {
945
+ throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
946
+ }
947
+ if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
948
+ throw new Error("Invalid asset extension: path separators are not allowed");
949
+ }
950
+ if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
951
+ throw new Error(`Invalid asset extension: "${ext}"`);
919
952
  }
920
- return "bin";
953
+ return normalized;
921
954
  }
922
955
  function sanitizeName(name, ext) {
923
956
  let safeName = name;