@character-foundry/character-foundry 0.4.3-dev.1766019473 → 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.
package/dist/index.js CHANGED
@@ -1339,6 +1339,36 @@ var SAFE_ASSET_TYPES = /* @__PURE__ */ new Set([
1339
1339
  "data",
1340
1340
  "unknown"
1341
1341
  ]);
1342
+ var SAFE_EXTENSIONS = /* @__PURE__ */ new Set([
1343
+ // Images
1344
+ "png",
1345
+ "jpg",
1346
+ "jpeg",
1347
+ "webp",
1348
+ "gif",
1349
+ "avif",
1350
+ "svg",
1351
+ "bmp",
1352
+ "ico",
1353
+ // Audio
1354
+ "mp3",
1355
+ "wav",
1356
+ "ogg",
1357
+ "flac",
1358
+ "m4a",
1359
+ "aac",
1360
+ "opus",
1361
+ // Video
1362
+ "mp4",
1363
+ "webm",
1364
+ "avi",
1365
+ "mov",
1366
+ "mkv",
1367
+ // Data
1368
+ "json",
1369
+ "txt",
1370
+ "bin"
1371
+ ]);
1342
1372
  function getCharxCategory(mimetype) {
1343
1373
  if (mimetype.startsWith("image/")) return "images";
1344
1374
  if (mimetype.startsWith("audio/")) return "audio";
@@ -1354,20 +1384,11 @@ function sanitizeAssetType(type) {
1354
1384
  return sanitized || "custom";
1355
1385
  }
1356
1386
  function sanitizeExtension(ext) {
1357
- const normalized = ext.trim().replace(/^\./, "").toLowerCase();
1358
- if (!normalized) {
1359
- throw new Error("Invalid asset extension: empty extension");
1360
- }
1361
- if (normalized.length > 64) {
1362
- throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
1363
- }
1364
- if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
1365
- throw new Error("Invalid asset extension: path separators are not allowed");
1366
- }
1367
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
1368
- throw new Error(`Invalid asset extension: "${ext}"`);
1387
+ const normalized = ext.replace(/^\./, "").toLowerCase().replace(/[^a-z0-9]/g, "");
1388
+ if (SAFE_EXTENSIONS.has(normalized)) {
1389
+ return normalized;
1369
1390
  }
1370
- return normalized;
1391
+ return "bin";
1371
1392
  }
1372
1393
  function sanitizeName(name, ext) {
1373
1394
  let safeName = name;
@@ -8149,22 +8170,6 @@ function sanitizeName2(name, ext) {
8149
8170
  if (!safeName) safeName = "asset";
8150
8171
  return safeName;
8151
8172
  }
8152
- function sanitizeExtension2(ext) {
8153
- const normalized = ext.trim().replace(/^\./, "").toLowerCase();
8154
- if (!normalized) {
8155
- throw new Error("Invalid asset extension: empty extension");
8156
- }
8157
- if (normalized.length > 64) {
8158
- throw new Error(`Invalid asset extension: too long (${normalized.length} chars)`);
8159
- }
8160
- if (normalized.includes("/") || normalized.includes("\\") || normalized.includes("\0")) {
8161
- throw new Error("Invalid asset extension: path separators are not allowed");
8162
- }
8163
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
8164
- throw new Error(`Invalid asset extension: "${ext}"`);
8165
- }
8166
- return normalized;
8167
- }
8168
8173
  function writeVoxta(card, assets, options = {}) {
8169
8174
  const { compressionLevel = 6, includePackageJson = false } = options;
8170
8175
  const cardData = card.data;
@@ -8253,9 +8258,8 @@ function writeVoxta(card, assets, options = {}) {
8253
8258
  let assetCount = 0;
8254
8259
  let mainThumbnail;
8255
8260
  for (const asset of assets) {
8256
- const safeExt = sanitizeExtension2(asset.ext);
8257
- const safeName = sanitizeName2(asset.name, safeExt);
8258
- const finalFilename = `${safeName}.${safeExt}`;
8261
+ const safeName = sanitizeName2(asset.name, asset.ext);
8262
+ const finalFilename = `${safeName}.${asset.ext}`;
8259
8263
  let voxtaPath = "";
8260
8264
  const tags = asset.tags || [];
8261
8265
  const isMainIcon = asset.type === "icon" && (tags.includes("portrait-override") || asset.name === "main" || asset.isMain);