@character-foundry/character-foundry 0.4.1 → 0.4.2-dev.1765997746

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 +17 -38
  2. package/dist/charx.cjs.map +1 -1
  3. package/dist/charx.d.cts +27 -18
  4. package/dist/charx.d.ts +27 -18
  5. package/dist/charx.js +17 -38
  6. package/dist/charx.js.map +1 -1
  7. package/dist/exporter.cjs +36 -40
  8. package/dist/exporter.cjs.map +1 -1
  9. package/dist/exporter.d.cts +27 -18
  10. package/dist/exporter.d.ts +27 -18
  11. package/dist/exporter.js +36 -40
  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 +62 -18
  16. package/dist/federation.d.ts +62 -18
  17. package/dist/federation.js +104 -36
  18. package/dist/federation.js.map +1 -1
  19. package/dist/index.cjs +36 -40
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +63 -42
  22. package/dist/index.d.ts +63 -42
  23. package/dist/index.js +36 -40
  24. package/dist/index.js.map +1 -1
  25. package/dist/loader.cjs +103 -17
  26. package/dist/loader.cjs.map +1 -1
  27. package/dist/loader.d.cts +56 -28
  28. package/dist/loader.d.ts +56 -28
  29. package/dist/loader.js +103 -17
  30. package/dist/loader.js.map +1 -1
  31. package/dist/lorebook.d.cts +51 -34
  32. package/dist/lorebook.d.ts +51 -34
  33. package/dist/normalizer.cjs +4 -4
  34. package/dist/normalizer.cjs.map +1 -1
  35. package/dist/normalizer.d.cts +90 -60
  36. package/dist/normalizer.d.ts +90 -60
  37. package/dist/normalizer.js +4 -4
  38. package/dist/normalizer.js.map +1 -1
  39. package/dist/png.cjs +4 -4
  40. package/dist/png.cjs.map +1 -1
  41. package/dist/png.d.cts +48 -32
  42. package/dist/png.d.ts +48 -32
  43. package/dist/png.js +4 -4
  44. package/dist/png.js.map +1 -1
  45. package/dist/schemas.cjs +9 -9
  46. package/dist/schemas.cjs.map +1 -1
  47. package/dist/schemas.d.cts +144 -96
  48. package/dist/schemas.d.ts +144 -96
  49. package/dist/schemas.js +9 -9
  50. package/dist/schemas.js.map +1 -1
  51. package/dist/voxta.cjs +23 -6
  52. package/dist/voxta.cjs.map +1 -1
  53. package/dist/voxta.d.cts +42 -28
  54. package/dist/voxta.d.ts +42 -28
  55. package/dist/voxta.js +23 -6
  56. package/dist/voxta.js.map +1 -1
  57. package/package.json +6 -6
package/dist/index.cjs CHANGED
@@ -609,7 +609,7 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
609
609
  content: import_zod2.z.string(),
610
610
  enabled: import_zod2.z.boolean().default(true),
611
611
  // Default to enabled if missing
612
- insertion_order: import_zod2.z.number().int().nullable().default(0),
612
+ insertion_order: import_zod2.z.preprocess((v) => v ?? 0, import_zod2.z.number().int()),
613
613
  // Optional fields - be lenient with nulls since wild data has them
614
614
  extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
615
615
  case_sensitive: import_zod2.z.boolean().nullable().optional(),
@@ -620,7 +620,7 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
620
620
  selective: import_zod2.z.boolean().nullable().optional(),
621
621
  secondary_keys: import_zod2.z.array(import_zod2.z.string()).nullable().optional(),
622
622
  constant: import_zod2.z.boolean().nullable().optional(),
623
- position: import_zod2.z.union([import_zod2.z.enum(["before_char", "after_char"]), import_zod2.z.number().int(), import_zod2.z.literal("")]).nullable().optional()
623
+ 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()
624
624
  }).passthrough();
625
625
  var CCv2CharacterBookSchema = import_zod2.z.object({
626
626
  name: import_zod2.z.string().optional(),
@@ -674,7 +674,7 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
674
674
  content: import_zod3.z.string(),
675
675
  enabled: import_zod3.z.boolean().default(true),
676
676
  // Default to enabled if missing
677
- insertion_order: import_zod3.z.number().int().nullable().default(0),
677
+ insertion_order: import_zod3.z.preprocess((v) => v ?? 0, import_zod3.z.number().int()),
678
678
  // Optional fields - be lenient with nulls since wild data has them
679
679
  case_sensitive: import_zod3.z.boolean().nullable().optional(),
680
680
  name: import_zod3.z.string().optional(),
@@ -684,7 +684,7 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
684
684
  selective: import_zod3.z.boolean().nullable().optional(),
685
685
  secondary_keys: import_zod3.z.array(import_zod3.z.string()).nullable().optional(),
686
686
  constant: import_zod3.z.boolean().nullable().optional(),
687
- position: import_zod3.z.union([import_zod3.z.enum(["before_char", "after_char"]), import_zod3.z.number().int(), import_zod3.z.literal("")]).nullable().optional(),
687
+ 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(),
688
688
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
689
689
  // v3 specific - also lenient with types since SillyTavern uses numbers for enums
690
690
  automation_id: import_zod3.z.string().optional(),
@@ -1363,36 +1363,6 @@ var SAFE_ASSET_TYPES = /* @__PURE__ */ new Set([
1363
1363
  "data",
1364
1364
  "unknown"
1365
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
- ]);
1396
1366
  function getCharxCategory(mimetype) {
1397
1367
  if (mimetype.startsWith("image/")) return "images";
1398
1368
  if (mimetype.startsWith("audio/")) return "audio";
@@ -1408,11 +1378,20 @@ function sanitizeAssetType(type) {
1408
1378
  return sanitized || "custom";
1409
1379
  }
1410
1380
  function sanitizeExtension(ext) {
1411
- const normalized = ext.replace(/^\./, "").toLowerCase().replace(/[^a-z0-9]/g, "");
1412
- if (SAFE_EXTENSIONS.has(normalized)) {
1413
- return normalized;
1381
+ const normalized = ext.trim().replace(/^\./, "").toLowerCase();
1382
+ if (!normalized) {
1383
+ throw new Error("Invalid asset extension: empty extension");
1384
+ }
1385
+ if (normalized.length > 64) {
1386
+ throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
1387
+ }
1388
+ if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
1389
+ throw new Error("Invalid asset extension: path separators are not allowed");
1390
+ }
1391
+ if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
1392
+ throw new Error(`Invalid asset extension: "${ext}"`);
1414
1393
  }
1415
- return "bin";
1394
+ return normalized;
1416
1395
  }
1417
1396
  function sanitizeName(name, ext) {
1418
1397
  let safeName = name;
@@ -8194,6 +8173,22 @@ function sanitizeName2(name, ext) {
8194
8173
  if (!safeName) safeName = "asset";
8195
8174
  return safeName;
8196
8175
  }
8176
+ function sanitizeExtension2(ext) {
8177
+ const normalized = ext.trim().replace(/^\./, "").toLowerCase();
8178
+ if (!normalized) {
8179
+ throw new Error("Invalid asset extension: empty extension");
8180
+ }
8181
+ if (normalized.length > 64) {
8182
+ throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
8183
+ }
8184
+ if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
8185
+ throw new Error("Invalid asset extension: path separators are not allowed");
8186
+ }
8187
+ if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
8188
+ throw new Error(`Invalid asset extension: "${ext}"`);
8189
+ }
8190
+ return normalized;
8191
+ }
8197
8192
  function writeVoxta(card, assets, options = {}) {
8198
8193
  const { compressionLevel = 6, includePackageJson = false } = options;
8199
8194
  const cardData = card.data;
@@ -8282,8 +8277,9 @@ function writeVoxta(card, assets, options = {}) {
8282
8277
  let assetCount = 0;
8283
8278
  let mainThumbnail;
8284
8279
  for (const asset of assets) {
8285
- const safeName = sanitizeName2(asset.name, asset.ext);
8286
- const finalFilename = `${safeName}.${asset.ext}`;
8280
+ const safeExt = sanitizeExtension2(asset.ext);
8281
+ const safeName = sanitizeName2(asset.name, safeExt);
8282
+ const finalFilename = `${safeName}.${safeExt}`;
8287
8283
  let voxtaPath = "";
8288
8284
  const tags = asset.tags || [];
8289
8285
  const isMainIcon = asset.type === "icon" && (tags.includes("portrait-override") || asset.name === "main" || asset.isMain);