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

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 +52 -85
  2. package/dist/charx.cjs.map +1 -1
  3. package/dist/charx.d.cts +22 -22
  4. package/dist/charx.d.ts +22 -22
  5. package/dist/charx.js +52 -85
  6. package/dist/charx.js.map +1 -1
  7. package/dist/exporter.cjs +54 -104
  8. package/dist/exporter.cjs.map +1 -1
  9. package/dist/exporter.d.cts +19 -19
  10. package/dist/exporter.d.ts +19 -19
  11. package/dist/exporter.js +54 -104
  12. package/dist/exporter.js.map +1 -1
  13. package/dist/federation.cjs +36 -104
  14. package/dist/federation.cjs.map +1 -1
  15. package/dist/federation.d.cts +19 -54
  16. package/dist/federation.d.ts +19 -54
  17. package/dist/federation.js +36 -104
  18. package/dist/federation.js.map +1 -1
  19. package/dist/index.cjs +54 -104
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +29 -29
  22. package/dist/index.d.ts +29 -29
  23. package/dist/index.js +54 -104
  24. package/dist/index.js.map +1 -1
  25. package/dist/loader.cjs +31 -171
  26. package/dist/loader.cjs.map +1 -1
  27. package/dist/loader.d.cts +23 -37
  28. package/dist/loader.d.ts +23 -37
  29. package/dist/loader.js +31 -171
  30. package/dist/loader.js.map +1 -1
  31. package/dist/lorebook.d.cts +23 -23
  32. package/dist/lorebook.d.ts +23 -23
  33. package/dist/normalizer.cjs +18 -72
  34. package/dist/normalizer.cjs.map +1 -1
  35. package/dist/normalizer.d.cts +37 -37
  36. package/dist/normalizer.d.ts +37 -37
  37. package/dist/normalizer.js +18 -72
  38. package/dist/normalizer.js.map +1 -1
  39. package/dist/png.cjs +18 -72
  40. package/dist/png.cjs.map +1 -1
  41. package/dist/png.d.cts +25 -25
  42. package/dist/png.d.ts +25 -25
  43. package/dist/png.js +18 -72
  44. package/dist/png.js.map +1 -1
  45. package/dist/schemas.cjs +23 -80
  46. package/dist/schemas.cjs.map +1 -1
  47. package/dist/schemas.d.cts +67 -85
  48. package/dist/schemas.d.ts +67 -85
  49. package/dist/schemas.js +23 -80
  50. package/dist/schemas.js.map +1 -1
  51. package/dist/voxta.cjs +20 -91
  52. package/dist/voxta.cjs.map +1 -1
  53. package/dist/voxta.d.cts +23 -23
  54. package/dist/voxta.d.ts +23 -23
  55. package/dist/voxta.js +20 -91
  56. package/dist/voxta.js.map +1 -1
  57. package/package.json +5 -5
package/dist/index.cjs CHANGED
@@ -560,58 +560,6 @@ var import_zod = require("zod");
560
560
  var import_zod2 = require("zod");
561
561
  var import_zod3 = require("zod");
562
562
  var import_zod4 = require("zod");
563
- function preprocessTimestamp(val) {
564
- if (val === null || val === void 0) return void 0;
565
- let num;
566
- if (typeof val === "number") {
567
- num = val;
568
- } else if (typeof val === "string") {
569
- const trimmed = val.trim();
570
- if (!trimmed) return void 0;
571
- const parsed = Number(trimmed);
572
- if (!isNaN(parsed)) {
573
- num = parsed;
574
- } else {
575
- const date = new Date(trimmed);
576
- if (isNaN(date.getTime())) return void 0;
577
- num = Math.floor(date.getTime() / 1e3);
578
- }
579
- } else {
580
- return void 0;
581
- }
582
- if (num > 1e10) {
583
- num = Math.floor(num / 1e3);
584
- }
585
- if (num < 0) return void 0;
586
- return num;
587
- }
588
- function preprocessNumeric(val) {
589
- if (val === null || val === void 0) return void 0;
590
- if (typeof val === "number") {
591
- return isNaN(val) ? void 0 : val;
592
- }
593
- if (typeof val === "string") {
594
- const trimmed = val.trim();
595
- if (!trimmed) return void 0;
596
- const parsed = Number(trimmed);
597
- return isNaN(parsed) ? void 0 : parsed;
598
- }
599
- return void 0;
600
- }
601
- var KNOWN_ASSET_TYPES = /* @__PURE__ */ new Set([
602
- "icon",
603
- "background",
604
- "emotion",
605
- "user_icon",
606
- "sound",
607
- "video",
608
- "custom",
609
- "x-risu-asset"
610
- ]);
611
- function preprocessAssetType(val) {
612
- if (typeof val !== "string") return "custom";
613
- return KNOWN_ASSET_TYPES.has(val) ? val : "custom";
614
- }
615
563
  var ISO8601Schema = import_zod.z.string().datetime();
616
564
  var UUIDSchema = import_zod.z.string().uuid();
617
565
  var SpecSchema = import_zod.z.enum(["v2", "v3"]);
@@ -634,19 +582,16 @@ var SourceFormatSchema = import_zod.z.enum([
634
582
  // VoxPkg format
635
583
  ]);
636
584
  var OriginalShapeSchema = import_zod.z.enum(["wrapped", "unwrapped", "legacy"]);
637
- var AssetTypeSchema = import_zod.z.preprocess(
638
- preprocessAssetType,
639
- import_zod.z.enum([
640
- "icon",
641
- "background",
642
- "emotion",
643
- "user_icon",
644
- "sound",
645
- "video",
646
- "custom",
647
- "x-risu-asset"
648
- ])
649
- );
585
+ var AssetTypeSchema = import_zod.z.enum([
586
+ "icon",
587
+ "background",
588
+ "emotion",
589
+ "user_icon",
590
+ "sound",
591
+ "video",
592
+ "custom",
593
+ "x-risu-asset"
594
+ ]);
650
595
  var AssetDescriptorSchema = import_zod.z.object({
651
596
  type: AssetTypeSchema,
652
597
  uri: import_zod.z.string(),
@@ -680,8 +625,8 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
680
625
  var CCv2CharacterBookSchema = import_zod2.z.object({
681
626
  name: import_zod2.z.string().optional(),
682
627
  description: import_zod2.z.string().optional(),
683
- scan_depth: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
684
- token_budget: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
628
+ scan_depth: import_zod2.z.number().int().nonnegative().optional(),
629
+ token_budget: import_zod2.z.number().int().nonnegative().optional(),
685
630
  recursive_scanning: import_zod2.z.boolean().optional(),
686
631
  extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
687
632
  entries: import_zod2.z.array(CCv2LorebookEntrySchema)
@@ -755,8 +700,8 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
755
700
  var CCv3CharacterBookSchema = import_zod3.z.object({
756
701
  name: import_zod3.z.string().optional(),
757
702
  description: import_zod3.z.string().optional(),
758
- scan_depth: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
759
- token_budget: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
703
+ scan_depth: import_zod3.z.number().int().nonnegative().optional(),
704
+ token_budget: import_zod3.z.number().int().nonnegative().optional(),
760
705
  recursive_scanning: import_zod3.z.boolean().optional(),
761
706
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
762
707
  entries: import_zod3.z.array(CCv3LorebookEntrySchema)
@@ -788,9 +733,10 @@ var CCv3DataInnerSchema = import_zod3.z.object({
788
733
  nickname: import_zod3.z.string().optional(),
789
734
  creator_notes_multilingual: import_zod3.z.record(import_zod3.z.string()).optional(),
790
735
  source: import_zod3.z.array(import_zod3.z.string()).optional(),
791
- // Unix timestamps - preprocess to handle ISO strings, numeric strings, milliseconds
792
- creation_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional()),
793
- modification_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional())
736
+ creation_date: import_zod3.z.number().int().nonnegative().optional(),
737
+ // Unix timestamp in seconds
738
+ modification_date: import_zod3.z.number().int().nonnegative().optional()
739
+ // Unix timestamp in seconds
794
740
  });
795
741
  var CCv3DataSchema = import_zod3.z.object({
796
742
  spec: import_zod3.z.literal("chara_card_v3"),
@@ -1417,6 +1363,36 @@ var SAFE_ASSET_TYPES = /* @__PURE__ */ new Set([
1417
1363
  "data",
1418
1364
  "unknown"
1419
1365
  ]);
1366
+ var SAFE_EXTENSIONS = /* @__PURE__ */ new Set([
1367
+ // Images
1368
+ "png",
1369
+ "jpg",
1370
+ "jpeg",
1371
+ "webp",
1372
+ "gif",
1373
+ "avif",
1374
+ "svg",
1375
+ "bmp",
1376
+ "ico",
1377
+ // Audio
1378
+ "mp3",
1379
+ "wav",
1380
+ "ogg",
1381
+ "flac",
1382
+ "m4a",
1383
+ "aac",
1384
+ "opus",
1385
+ // Video
1386
+ "mp4",
1387
+ "webm",
1388
+ "avi",
1389
+ "mov",
1390
+ "mkv",
1391
+ // Data
1392
+ "json",
1393
+ "txt",
1394
+ "bin"
1395
+ ]);
1420
1396
  function getCharxCategory(mimetype) {
1421
1397
  if (mimetype.startsWith("image/")) return "images";
1422
1398
  if (mimetype.startsWith("audio/")) return "audio";
@@ -1432,20 +1408,11 @@ function sanitizeAssetType(type) {
1432
1408
  return sanitized || "custom";
1433
1409
  }
1434
1410
  function sanitizeExtension(ext) {
1435
- const normalized = ext.trim().replace(/^\./, "").toLowerCase();
1436
- if (!normalized) {
1437
- throw new Error("Invalid asset extension: empty extension");
1438
- }
1439
- if (normalized.length > 64) {
1440
- throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
1441
- }
1442
- if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
1443
- throw new Error("Invalid asset extension: path separators are not allowed");
1444
- }
1445
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
1446
- throw new Error(`Invalid asset extension: "${ext}"`);
1411
+ const normalized = ext.replace(/^\./, "").toLowerCase().replace(/[^a-z0-9]/g, "");
1412
+ if (SAFE_EXTENSIONS.has(normalized)) {
1413
+ return normalized;
1447
1414
  }
1448
- return normalized;
1415
+ return "bin";
1449
1416
  }
1450
1417
  function sanitizeName(name, ext) {
1451
1418
  let safeName = name;
@@ -8227,22 +8194,6 @@ function sanitizeName2(name, ext) {
8227
8194
  if (!safeName) safeName = "asset";
8228
8195
  return safeName;
8229
8196
  }
8230
- function sanitizeExtension2(ext) {
8231
- const normalized = ext.trim().replace(/^\./, "").toLowerCase();
8232
- if (!normalized) {
8233
- throw new Error("Invalid asset extension: empty extension");
8234
- }
8235
- if (normalized.length > 64) {
8236
- throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
8237
- }
8238
- if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
8239
- throw new Error("Invalid asset extension: path separators are not allowed");
8240
- }
8241
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
8242
- throw new Error(`Invalid asset extension: "${ext}"`);
8243
- }
8244
- return normalized;
8245
- }
8246
8197
  function writeVoxta(card, assets, options = {}) {
8247
8198
  const { compressionLevel = 6, includePackageJson = false } = options;
8248
8199
  const cardData = card.data;
@@ -8331,9 +8282,8 @@ function writeVoxta(card, assets, options = {}) {
8331
8282
  let assetCount = 0;
8332
8283
  let mainThumbnail;
8333
8284
  for (const asset of assets) {
8334
- const safeExt = sanitizeExtension2(asset.ext);
8335
- const safeName = sanitizeName2(asset.name, safeExt);
8336
- const finalFilename = `${safeName}.${safeExt}`;
8285
+ const safeName = sanitizeName2(asset.name, asset.ext);
8286
+ const finalFilename = `${safeName}.${asset.ext}`;
8337
8287
  let voxtaPath = "";
8338
8288
  const tags = asset.tags || [];
8339
8289
  const isMainIcon = asset.type === "icon" && (tags.includes("portrait-override") || asset.name === "main" || asset.isMain);