@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/voxta.cjs CHANGED
@@ -6613,6 +6613,58 @@ var import_zod = require("zod");
6613
6613
  var import_zod2 = require("zod");
6614
6614
  var import_zod3 = require("zod");
6615
6615
  var import_zod4 = require("zod");
6616
+ function preprocessTimestamp(val) {
6617
+ if (val === null || val === void 0) return void 0;
6618
+ let num;
6619
+ if (typeof val === "number") {
6620
+ num = val;
6621
+ } else if (typeof val === "string") {
6622
+ const trimmed = val.trim();
6623
+ if (!trimmed) return void 0;
6624
+ const parsed = Number(trimmed);
6625
+ if (!isNaN(parsed)) {
6626
+ num = parsed;
6627
+ } else {
6628
+ const date = new Date(trimmed);
6629
+ if (isNaN(date.getTime())) return void 0;
6630
+ num = Math.floor(date.getTime() / 1e3);
6631
+ }
6632
+ } else {
6633
+ return void 0;
6634
+ }
6635
+ if (num > 1e10) {
6636
+ num = Math.floor(num / 1e3);
6637
+ }
6638
+ if (num < 0) return void 0;
6639
+ return num;
6640
+ }
6641
+ function preprocessNumeric(val) {
6642
+ if (val === null || val === void 0) return void 0;
6643
+ if (typeof val === "number") {
6644
+ return isNaN(val) ? void 0 : val;
6645
+ }
6646
+ if (typeof val === "string") {
6647
+ const trimmed = val.trim();
6648
+ if (!trimmed) return void 0;
6649
+ const parsed = Number(trimmed);
6650
+ return isNaN(parsed) ? void 0 : parsed;
6651
+ }
6652
+ return void 0;
6653
+ }
6654
+ var KNOWN_ASSET_TYPES = /* @__PURE__ */ new Set([
6655
+ "icon",
6656
+ "background",
6657
+ "emotion",
6658
+ "user_icon",
6659
+ "sound",
6660
+ "video",
6661
+ "custom",
6662
+ "x-risu-asset"
6663
+ ]);
6664
+ function preprocessAssetType(val) {
6665
+ if (typeof val !== "string") return "custom";
6666
+ return KNOWN_ASSET_TYPES.has(val) ? val : "custom";
6667
+ }
6616
6668
  var ISO8601Schema = import_zod.z.string().datetime();
6617
6669
  var UUIDSchema = import_zod.z.string().uuid();
6618
6670
  var SpecSchema = import_zod.z.enum(["v2", "v3"]);
@@ -6635,16 +6687,19 @@ var SourceFormatSchema = import_zod.z.enum([
6635
6687
  // VoxPkg format
6636
6688
  ]);
6637
6689
  var OriginalShapeSchema = import_zod.z.enum(["wrapped", "unwrapped", "legacy"]);
6638
- var AssetTypeSchema = import_zod.z.enum([
6639
- "icon",
6640
- "background",
6641
- "emotion",
6642
- "user_icon",
6643
- "sound",
6644
- "video",
6645
- "custom",
6646
- "x-risu-asset"
6647
- ]);
6690
+ var AssetTypeSchema = import_zod.z.preprocess(
6691
+ preprocessAssetType,
6692
+ import_zod.z.enum([
6693
+ "icon",
6694
+ "background",
6695
+ "emotion",
6696
+ "user_icon",
6697
+ "sound",
6698
+ "video",
6699
+ "custom",
6700
+ "x-risu-asset"
6701
+ ])
6702
+ );
6648
6703
  var AssetDescriptorSchema = import_zod.z.object({
6649
6704
  type: AssetTypeSchema,
6650
6705
  uri: import_zod.z.string(),
@@ -6673,13 +6728,13 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
6673
6728
  selective: import_zod2.z.boolean().nullable().optional(),
6674
6729
  secondary_keys: import_zod2.z.array(import_zod2.z.string()).nullable().optional(),
6675
6730
  constant: import_zod2.z.boolean().nullable().optional(),
6676
- position: import_zod2.z.union([import_zod2.z.enum(["before_char", "after_char"]), import_zod2.z.number().int(), import_zod2.z.literal("")]).nullable().optional()
6731
+ 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()
6677
6732
  }).passthrough();
6678
6733
  var CCv2CharacterBookSchema = import_zod2.z.object({
6679
6734
  name: import_zod2.z.string().optional(),
6680
6735
  description: import_zod2.z.string().optional(),
6681
- scan_depth: import_zod2.z.number().int().nonnegative().optional(),
6682
- token_budget: import_zod2.z.number().int().nonnegative().optional(),
6736
+ scan_depth: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
6737
+ token_budget: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
6683
6738
  recursive_scanning: import_zod2.z.boolean().optional(),
6684
6739
  extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
6685
6740
  entries: import_zod2.z.array(CCv2LorebookEntrySchema)
@@ -6726,7 +6781,7 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
6726
6781
  selective: import_zod3.z.boolean().nullable().optional(),
6727
6782
  secondary_keys: import_zod3.z.array(import_zod3.z.string()).nullable().optional(),
6728
6783
  constant: import_zod3.z.boolean().nullable().optional(),
6729
- position: import_zod3.z.union([import_zod3.z.enum(["before_char", "after_char"]), import_zod3.z.number().int(), import_zod3.z.literal("")]).nullable().optional(),
6784
+ 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(),
6730
6785
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
6731
6786
  // v3 specific - also lenient with types since SillyTavern uses numbers for enums
6732
6787
  automation_id: import_zod3.z.string().optional(),
@@ -6742,8 +6797,8 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
6742
6797
  var CCv3CharacterBookSchema = import_zod3.z.object({
6743
6798
  name: import_zod3.z.string().optional(),
6744
6799
  description: import_zod3.z.string().optional(),
6745
- scan_depth: import_zod3.z.number().int().nonnegative().optional(),
6746
- token_budget: import_zod3.z.number().int().nonnegative().optional(),
6800
+ scan_depth: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
6801
+ token_budget: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
6747
6802
  recursive_scanning: import_zod3.z.boolean().optional(),
6748
6803
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
6749
6804
  entries: import_zod3.z.array(CCv3LorebookEntrySchema)
@@ -6775,10 +6830,9 @@ var CCv3DataInnerSchema = import_zod3.z.object({
6775
6830
  nickname: import_zod3.z.string().optional(),
6776
6831
  creator_notes_multilingual: import_zod3.z.record(import_zod3.z.string()).optional(),
6777
6832
  source: import_zod3.z.array(import_zod3.z.string()).optional(),
6778
- creation_date: import_zod3.z.number().int().nonnegative().optional(),
6779
- // Unix timestamp in seconds
6780
- modification_date: import_zod3.z.number().int().nonnegative().optional()
6781
- // Unix timestamp in seconds
6833
+ // Unix timestamps - preprocess to handle ISO strings, numeric strings, milliseconds
6834
+ creation_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional()),
6835
+ modification_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional())
6782
6836
  });
6783
6837
  var CCv3DataSchema = import_zod3.z.object({
6784
6838
  spec: import_zod3.z.literal("chara_card_v3"),
@@ -7252,6 +7306,22 @@ function sanitizeName(name, ext) {
7252
7306
  if (!safeName) safeName = "asset";
7253
7307
  return safeName;
7254
7308
  }
7309
+ function sanitizeExtension(ext) {
7310
+ const normalized = ext.trim().replace(/^\./, "").toLowerCase();
7311
+ if (!normalized) {
7312
+ throw new Error("Invalid asset extension: empty extension");
7313
+ }
7314
+ if (normalized.length > 64) {
7315
+ throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
7316
+ }
7317
+ if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
7318
+ throw new Error("Invalid asset extension: path separators are not allowed");
7319
+ }
7320
+ if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
7321
+ throw new Error(`Invalid asset extension: "${ext}"`);
7322
+ }
7323
+ return normalized;
7324
+ }
7255
7325
  function writeVoxta(card, assets, options = {}) {
7256
7326
  const { compressionLevel = 6, includePackageJson = false } = options;
7257
7327
  const cardData = card.data;
@@ -7340,8 +7410,9 @@ function writeVoxta(card, assets, options = {}) {
7340
7410
  let assetCount = 0;
7341
7411
  let mainThumbnail;
7342
7412
  for (const asset of assets) {
7343
- const safeName = sanitizeName(asset.name, asset.ext);
7344
- const finalFilename = `${safeName}.${asset.ext}`;
7413
+ const safeExt = sanitizeExtension(asset.ext);
7414
+ const safeName = sanitizeName(asset.name, safeExt);
7415
+ const finalFilename = `${safeName}.${safeExt}`;
7345
7416
  let voxtaPath = "";
7346
7417
  const tags = asset.tags || [];
7347
7418
  const isMainIcon = asset.type === "icon" && (tags.includes("portrait-override") || asset.name === "main" || asset.isMain);