@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/exporter.cjs CHANGED
@@ -216,58 +216,6 @@ var import_zod = require("zod");
216
216
  var import_zod2 = require("zod");
217
217
  var import_zod3 = require("zod");
218
218
  var import_zod4 = require("zod");
219
- function preprocessTimestamp(val) {
220
- if (val === null || val === void 0) return void 0;
221
- let num;
222
- if (typeof val === "number") {
223
- num = val;
224
- } else if (typeof val === "string") {
225
- const trimmed = val.trim();
226
- if (!trimmed) return void 0;
227
- const parsed = Number(trimmed);
228
- if (!isNaN(parsed)) {
229
- num = parsed;
230
- } else {
231
- const date = new Date(trimmed);
232
- if (isNaN(date.getTime())) return void 0;
233
- num = Math.floor(date.getTime() / 1e3);
234
- }
235
- } else {
236
- return void 0;
237
- }
238
- if (num > 1e10) {
239
- num = Math.floor(num / 1e3);
240
- }
241
- if (num < 0) return void 0;
242
- return num;
243
- }
244
- function preprocessNumeric(val) {
245
- if (val === null || val === void 0) return void 0;
246
- if (typeof val === "number") {
247
- return isNaN(val) ? void 0 : val;
248
- }
249
- if (typeof val === "string") {
250
- const trimmed = val.trim();
251
- if (!trimmed) return void 0;
252
- const parsed = Number(trimmed);
253
- return isNaN(parsed) ? void 0 : parsed;
254
- }
255
- return void 0;
256
- }
257
- var KNOWN_ASSET_TYPES = /* @__PURE__ */ new Set([
258
- "icon",
259
- "background",
260
- "emotion",
261
- "user_icon",
262
- "sound",
263
- "video",
264
- "custom",
265
- "x-risu-asset"
266
- ]);
267
- function preprocessAssetType(val) {
268
- if (typeof val !== "string") return "custom";
269
- return KNOWN_ASSET_TYPES.has(val) ? val : "custom";
270
- }
271
219
  var ISO8601Schema = import_zod.z.string().datetime();
272
220
  var UUIDSchema = import_zod.z.string().uuid();
273
221
  var SpecSchema = import_zod.z.enum(["v2", "v3"]);
@@ -290,19 +238,16 @@ var SourceFormatSchema = import_zod.z.enum([
290
238
  // VoxPkg format
291
239
  ]);
292
240
  var OriginalShapeSchema = import_zod.z.enum(["wrapped", "unwrapped", "legacy"]);
293
- var AssetTypeSchema = import_zod.z.preprocess(
294
- preprocessAssetType,
295
- import_zod.z.enum([
296
- "icon",
297
- "background",
298
- "emotion",
299
- "user_icon",
300
- "sound",
301
- "video",
302
- "custom",
303
- "x-risu-asset"
304
- ])
305
- );
241
+ var AssetTypeSchema = import_zod.z.enum([
242
+ "icon",
243
+ "background",
244
+ "emotion",
245
+ "user_icon",
246
+ "sound",
247
+ "video",
248
+ "custom",
249
+ "x-risu-asset"
250
+ ]);
306
251
  var AssetDescriptorSchema = import_zod.z.object({
307
252
  type: AssetTypeSchema,
308
253
  uri: import_zod.z.string(),
@@ -336,8 +281,8 @@ var CCv2LorebookEntrySchema = import_zod2.z.object({
336
281
  var CCv2CharacterBookSchema = import_zod2.z.object({
337
282
  name: import_zod2.z.string().optional(),
338
283
  description: import_zod2.z.string().optional(),
339
- scan_depth: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
340
- token_budget: import_zod2.z.preprocess(preprocessNumeric, import_zod2.z.number().int().nonnegative().optional()),
284
+ scan_depth: import_zod2.z.number().int().nonnegative().optional(),
285
+ token_budget: import_zod2.z.number().int().nonnegative().optional(),
341
286
  recursive_scanning: import_zod2.z.boolean().optional(),
342
287
  extensions: import_zod2.z.record(import_zod2.z.unknown()).optional(),
343
288
  entries: import_zod2.z.array(CCv2LorebookEntrySchema)
@@ -400,8 +345,8 @@ var CCv3LorebookEntrySchema = import_zod3.z.object({
400
345
  var CCv3CharacterBookSchema = import_zod3.z.object({
401
346
  name: import_zod3.z.string().optional(),
402
347
  description: import_zod3.z.string().optional(),
403
- scan_depth: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
404
- token_budget: import_zod3.z.preprocess(preprocessNumeric, import_zod3.z.number().int().nonnegative().optional()),
348
+ scan_depth: import_zod3.z.number().int().nonnegative().optional(),
349
+ token_budget: import_zod3.z.number().int().nonnegative().optional(),
405
350
  recursive_scanning: import_zod3.z.boolean().optional(),
406
351
  extensions: import_zod3.z.record(import_zod3.z.unknown()).optional(),
407
352
  entries: import_zod3.z.array(CCv3LorebookEntrySchema)
@@ -433,9 +378,10 @@ var CCv3DataInnerSchema = import_zod3.z.object({
433
378
  nickname: import_zod3.z.string().optional(),
434
379
  creator_notes_multilingual: import_zod3.z.record(import_zod3.z.string()).optional(),
435
380
  source: import_zod3.z.array(import_zod3.z.string()).optional(),
436
- // Unix timestamps - preprocess to handle ISO strings, numeric strings, milliseconds
437
- creation_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional()),
438
- modification_date: import_zod3.z.preprocess(preprocessTimestamp, import_zod3.z.number().int().nonnegative().optional())
381
+ creation_date: import_zod3.z.number().int().nonnegative().optional(),
382
+ // Unix timestamp in seconds
383
+ modification_date: import_zod3.z.number().int().nonnegative().optional()
384
+ // Unix timestamp in seconds
439
385
  });
440
386
  var CCv3DataSchema = import_zod3.z.object({
441
387
  spec: import_zod3.z.literal("chara_card_v3"),
@@ -600,6 +546,36 @@ var SAFE_ASSET_TYPES = /* @__PURE__ */ new Set([
600
546
  "data",
601
547
  "unknown"
602
548
  ]);
549
+ var SAFE_EXTENSIONS = /* @__PURE__ */ new Set([
550
+ // Images
551
+ "png",
552
+ "jpg",
553
+ "jpeg",
554
+ "webp",
555
+ "gif",
556
+ "avif",
557
+ "svg",
558
+ "bmp",
559
+ "ico",
560
+ // Audio
561
+ "mp3",
562
+ "wav",
563
+ "ogg",
564
+ "flac",
565
+ "m4a",
566
+ "aac",
567
+ "opus",
568
+ // Video
569
+ "mp4",
570
+ "webm",
571
+ "avi",
572
+ "mov",
573
+ "mkv",
574
+ // Data
575
+ "json",
576
+ "txt",
577
+ "bin"
578
+ ]);
603
579
  function getCharxCategory(mimetype) {
604
580
  if (mimetype.startsWith("image/")) return "images";
605
581
  if (mimetype.startsWith("audio/")) return "audio";
@@ -615,20 +591,11 @@ function sanitizeAssetType(type) {
615
591
  return sanitized || "custom";
616
592
  }
617
593
  function sanitizeExtension(ext) {
618
- const normalized = ext.trim().replace(/^\./, "").toLowerCase();
619
- if (!normalized) {
620
- throw new Error("Invalid asset extension: empty extension");
621
- }
622
- if (normalized.length > 64) {
623
- throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
624
- }
625
- if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
626
- throw new Error("Invalid asset extension: path separators are not allowed");
627
- }
628
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
629
- throw new Error(`Invalid asset extension: "${ext}"`);
594
+ const normalized = ext.replace(/^\./, "").toLowerCase().replace(/[^a-z0-9]/g, "");
595
+ if (SAFE_EXTENSIONS.has(normalized)) {
596
+ return normalized;
630
597
  }
631
- return normalized;
598
+ return "bin";
632
599
  }
633
600
  function sanitizeName(name, ext) {
634
601
  let safeName = name;
@@ -7079,22 +7046,6 @@ function sanitizeName2(name, ext) {
7079
7046
  if (!safeName) safeName = "asset";
7080
7047
  return safeName;
7081
7048
  }
7082
- function sanitizeExtension2(ext) {
7083
- const normalized = ext.trim().replace(/^\./, "").toLowerCase();
7084
- if (!normalized) {
7085
- throw new Error("Invalid asset extension: empty extension");
7086
- }
7087
- if (normalized.length > 64) {
7088
- throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
7089
- }
7090
- if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
7091
- throw new Error("Invalid asset extension: path separators are not allowed");
7092
- }
7093
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
7094
- throw new Error(`Invalid asset extension: "${ext}"`);
7095
- }
7096
- return normalized;
7097
- }
7098
7049
  function writeVoxta(card, assets, options = {}) {
7099
7050
  const { compressionLevel = 6, includePackageJson = false } = options;
7100
7051
  const cardData = card.data;
@@ -7183,9 +7134,8 @@ function writeVoxta(card, assets, options = {}) {
7183
7134
  let assetCount = 0;
7184
7135
  let mainThumbnail;
7185
7136
  for (const asset of assets) {
7186
- const safeExt = sanitizeExtension2(asset.ext);
7187
- const safeName = sanitizeName2(asset.name, safeExt);
7188
- const finalFilename = `${safeName}.${safeExt}`;
7137
+ const safeName = sanitizeName2(asset.name, asset.ext);
7138
+ const finalFilename = `${safeName}.${asset.ext}`;
7189
7139
  let voxtaPath = "";
7190
7140
  const tags = asset.tags || [];
7191
7141
  const isMainIcon = asset.type === "icon" && (tags.includes("portrait-override") || asset.name === "main" || asset.isMain);