@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.js CHANGED
@@ -6573,6 +6573,58 @@ import { z } from "zod";
6573
6573
  import { z as z2 } from "zod";
6574
6574
  import { z as z3 } from "zod";
6575
6575
  import "zod";
6576
+ function preprocessTimestamp(val) {
6577
+ if (val === null || val === void 0) return void 0;
6578
+ let num;
6579
+ if (typeof val === "number") {
6580
+ num = val;
6581
+ } else if (typeof val === "string") {
6582
+ const trimmed = val.trim();
6583
+ if (!trimmed) return void 0;
6584
+ const parsed = Number(trimmed);
6585
+ if (!isNaN(parsed)) {
6586
+ num = parsed;
6587
+ } else {
6588
+ const date = new Date(trimmed);
6589
+ if (isNaN(date.getTime())) return void 0;
6590
+ num = Math.floor(date.getTime() / 1e3);
6591
+ }
6592
+ } else {
6593
+ return void 0;
6594
+ }
6595
+ if (num > 1e10) {
6596
+ num = Math.floor(num / 1e3);
6597
+ }
6598
+ if (num < 0) return void 0;
6599
+ return num;
6600
+ }
6601
+ function preprocessNumeric(val) {
6602
+ if (val === null || val === void 0) return void 0;
6603
+ if (typeof val === "number") {
6604
+ return isNaN(val) ? void 0 : val;
6605
+ }
6606
+ if (typeof val === "string") {
6607
+ const trimmed = val.trim();
6608
+ if (!trimmed) return void 0;
6609
+ const parsed = Number(trimmed);
6610
+ return isNaN(parsed) ? void 0 : parsed;
6611
+ }
6612
+ return void 0;
6613
+ }
6614
+ var KNOWN_ASSET_TYPES = /* @__PURE__ */ new Set([
6615
+ "icon",
6616
+ "background",
6617
+ "emotion",
6618
+ "user_icon",
6619
+ "sound",
6620
+ "video",
6621
+ "custom",
6622
+ "x-risu-asset"
6623
+ ]);
6624
+ function preprocessAssetType(val) {
6625
+ if (typeof val !== "string") return "custom";
6626
+ return KNOWN_ASSET_TYPES.has(val) ? val : "custom";
6627
+ }
6576
6628
  var ISO8601Schema = z.string().datetime();
6577
6629
  var UUIDSchema = z.string().uuid();
6578
6630
  var SpecSchema = z.enum(["v2", "v3"]);
@@ -6595,16 +6647,19 @@ var SourceFormatSchema = z.enum([
6595
6647
  // VoxPkg format
6596
6648
  ]);
6597
6649
  var OriginalShapeSchema = z.enum(["wrapped", "unwrapped", "legacy"]);
6598
- var AssetTypeSchema = z.enum([
6599
- "icon",
6600
- "background",
6601
- "emotion",
6602
- "user_icon",
6603
- "sound",
6604
- "video",
6605
- "custom",
6606
- "x-risu-asset"
6607
- ]);
6650
+ var AssetTypeSchema = z.preprocess(
6651
+ preprocessAssetType,
6652
+ z.enum([
6653
+ "icon",
6654
+ "background",
6655
+ "emotion",
6656
+ "user_icon",
6657
+ "sound",
6658
+ "video",
6659
+ "custom",
6660
+ "x-risu-asset"
6661
+ ])
6662
+ );
6608
6663
  var AssetDescriptorSchema = z.object({
6609
6664
  type: AssetTypeSchema,
6610
6665
  uri: z.string(),
@@ -6633,13 +6688,13 @@ var CCv2LorebookEntrySchema = z2.object({
6633
6688
  selective: z2.boolean().nullable().optional(),
6634
6689
  secondary_keys: z2.array(z2.string()).nullable().optional(),
6635
6690
  constant: z2.boolean().nullable().optional(),
6636
- position: z2.union([z2.enum(["before_char", "after_char"]), z2.number().int(), z2.literal("")]).nullable().optional()
6691
+ position: z2.union([z2.enum(["before_char", "after_char", "in_chat"]), z2.number().int(), z2.literal("")]).nullable().optional()
6637
6692
  }).passthrough();
6638
6693
  var CCv2CharacterBookSchema = z2.object({
6639
6694
  name: z2.string().optional(),
6640
6695
  description: z2.string().optional(),
6641
- scan_depth: z2.number().int().nonnegative().optional(),
6642
- token_budget: z2.number().int().nonnegative().optional(),
6696
+ scan_depth: z2.preprocess(preprocessNumeric, z2.number().int().nonnegative().optional()),
6697
+ token_budget: z2.preprocess(preprocessNumeric, z2.number().int().nonnegative().optional()),
6643
6698
  recursive_scanning: z2.boolean().optional(),
6644
6699
  extensions: z2.record(z2.unknown()).optional(),
6645
6700
  entries: z2.array(CCv2LorebookEntrySchema)
@@ -6686,7 +6741,7 @@ var CCv3LorebookEntrySchema = z3.object({
6686
6741
  selective: z3.boolean().nullable().optional(),
6687
6742
  secondary_keys: z3.array(z3.string()).nullable().optional(),
6688
6743
  constant: z3.boolean().nullable().optional(),
6689
- position: z3.union([z3.enum(["before_char", "after_char"]), z3.number().int(), z3.literal("")]).nullable().optional(),
6744
+ position: z3.union([z3.enum(["before_char", "after_char", "in_chat"]), z3.number().int(), z3.literal("")]).nullable().optional(),
6690
6745
  extensions: z3.record(z3.unknown()).optional(),
6691
6746
  // v3 specific - also lenient with types since SillyTavern uses numbers for enums
6692
6747
  automation_id: z3.string().optional(),
@@ -6702,8 +6757,8 @@ var CCv3LorebookEntrySchema = z3.object({
6702
6757
  var CCv3CharacterBookSchema = z3.object({
6703
6758
  name: z3.string().optional(),
6704
6759
  description: z3.string().optional(),
6705
- scan_depth: z3.number().int().nonnegative().optional(),
6706
- token_budget: z3.number().int().nonnegative().optional(),
6760
+ scan_depth: z3.preprocess(preprocessNumeric, z3.number().int().nonnegative().optional()),
6761
+ token_budget: z3.preprocess(preprocessNumeric, z3.number().int().nonnegative().optional()),
6707
6762
  recursive_scanning: z3.boolean().optional(),
6708
6763
  extensions: z3.record(z3.unknown()).optional(),
6709
6764
  entries: z3.array(CCv3LorebookEntrySchema)
@@ -6735,10 +6790,9 @@ var CCv3DataInnerSchema = z3.object({
6735
6790
  nickname: z3.string().optional(),
6736
6791
  creator_notes_multilingual: z3.record(z3.string()).optional(),
6737
6792
  source: z3.array(z3.string()).optional(),
6738
- creation_date: z3.number().int().nonnegative().optional(),
6739
- // Unix timestamp in seconds
6740
- modification_date: z3.number().int().nonnegative().optional()
6741
- // Unix timestamp in seconds
6793
+ // Unix timestamps - preprocess to handle ISO strings, numeric strings, milliseconds
6794
+ creation_date: z3.preprocess(preprocessTimestamp, z3.number().int().nonnegative().optional()),
6795
+ modification_date: z3.preprocess(preprocessTimestamp, z3.number().int().nonnegative().optional())
6742
6796
  });
6743
6797
  var CCv3DataSchema = z3.object({
6744
6798
  spec: z3.literal("chara_card_v3"),
@@ -7212,6 +7266,22 @@ function sanitizeName(name, ext) {
7212
7266
  if (!safeName) safeName = "asset";
7213
7267
  return safeName;
7214
7268
  }
7269
+ function sanitizeExtension(ext) {
7270
+ const normalized = ext.trim().replace(/^\./, "").toLowerCase();
7271
+ if (!normalized) {
7272
+ throw new Error("Invalid asset extension: empty extension");
7273
+ }
7274
+ if (normalized.length > 64) {
7275
+ throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
7276
+ }
7277
+ if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
7278
+ throw new Error("Invalid asset extension: path separators are not allowed");
7279
+ }
7280
+ if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
7281
+ throw new Error(`Invalid asset extension: "${ext}"`);
7282
+ }
7283
+ return normalized;
7284
+ }
7215
7285
  function writeVoxta(card, assets, options = {}) {
7216
7286
  const { compressionLevel = 6, includePackageJson = false } = options;
7217
7287
  const cardData = card.data;
@@ -7300,8 +7370,9 @@ function writeVoxta(card, assets, options = {}) {
7300
7370
  let assetCount = 0;
7301
7371
  let mainThumbnail;
7302
7372
  for (const asset of assets) {
7303
- const safeName = sanitizeName(asset.name, asset.ext);
7304
- const finalFilename = `${safeName}.${asset.ext}`;
7373
+ const safeExt = sanitizeExtension(asset.ext);
7374
+ const safeName = sanitizeName(asset.name, safeExt);
7375
+ const finalFilename = `${safeName}.${safeExt}`;
7305
7376
  let voxtaPath = "";
7306
7377
  const tags = asset.tags || [];
7307
7378
  const isMainIcon = asset.type === "icon" && (tags.includes("portrait-override") || asset.name === "main" || asset.isMain);