@character-foundry/character-foundry 0.1.5 → 0.1.6
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/app-framework.cjs +143 -26
- package/dist/app-framework.cjs.map +1 -1
- package/dist/app-framework.d.cts +16 -1
- package/dist/app-framework.d.ts +16 -1
- package/dist/app-framework.js +151 -34
- package/dist/app-framework.js.map +1 -1
- package/dist/charx.cjs +70 -8
- package/dist/charx.cjs.map +1 -1
- package/dist/charx.js +70 -8
- package/dist/charx.js.map +1 -1
- package/dist/core.cjs +93 -6
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +42 -1
- package/dist/core.d.ts +42 -1
- package/dist/core.js +93 -6
- package/dist/core.js.map +1 -1
- package/dist/exporter.cjs +88 -8
- package/dist/exporter.cjs.map +1 -1
- package/dist/exporter.js +89 -9
- package/dist/exporter.js.map +1 -1
- package/dist/federation.cjs +1 -0
- package/dist/federation.cjs.map +1 -1
- package/dist/federation.js +1 -0
- package/dist/federation.js.map +1 -1
- package/dist/index.cjs +122 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +123 -19
- package/dist/index.js.map +1 -1
- package/dist/loader.cjs +42 -14
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.js +43 -15
- package/dist/loader.js.map +1 -1
- package/dist/lorebook.cjs +1 -0
- package/dist/lorebook.cjs.map +1 -1
- package/dist/lorebook.js +1 -0
- package/dist/lorebook.js.map +1 -1
- package/dist/media.cjs +1 -0
- package/dist/media.cjs.map +1 -1
- package/dist/media.js +1 -0
- package/dist/media.js.map +1 -1
- package/dist/normalizer.cjs +1 -0
- package/dist/normalizer.cjs.map +1 -1
- package/dist/normalizer.d.cts +1 -0
- package/dist/normalizer.d.ts +1 -0
- package/dist/normalizer.js +1 -0
- package/dist/normalizer.js.map +1 -1
- package/dist/png.cjs +19 -0
- package/dist/png.cjs.map +1 -1
- package/dist/png.js +19 -0
- package/dist/png.js.map +1 -1
- package/dist/schemas.cjs +80 -0
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +30 -0
- package/dist/schemas.d.ts +30 -0
- package/dist/schemas.js +80 -0
- package/dist/schemas.js.map +1 -1
- package/dist/voxta.cjs +14 -102
- package/dist/voxta.cjs.map +1 -1
- package/dist/voxta.js +15 -103
- package/dist/voxta.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -226,10 +226,14 @@ function alloc(size) {
|
|
|
226
226
|
return new Uint8Array(size);
|
|
227
227
|
}
|
|
228
228
|
var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
229
|
+
var LARGE_BUFFER_THRESHOLD = 1024 * 1024;
|
|
229
230
|
function encode(data) {
|
|
230
231
|
if (isNode) {
|
|
231
232
|
return Buffer.from(data).toString("base64");
|
|
232
233
|
}
|
|
234
|
+
if (data.length > LARGE_BUFFER_THRESHOLD) {
|
|
235
|
+
return encodeChunked(data);
|
|
236
|
+
}
|
|
233
237
|
let binary = "";
|
|
234
238
|
for (let i = 0; i < data.length; i++) {
|
|
235
239
|
binary += String.fromCharCode(data[i]);
|
|
@@ -248,6 +252,21 @@ function decode(base64) {
|
|
|
248
252
|
return result;
|
|
249
253
|
}
|
|
250
254
|
var ENCODE_CHUNK_SIZE = 64 * 1024;
|
|
255
|
+
function encodeChunked(data) {
|
|
256
|
+
if (isNode) {
|
|
257
|
+
return Buffer.from(data).toString("base64");
|
|
258
|
+
}
|
|
259
|
+
const chunks = [];
|
|
260
|
+
for (let i = 0; i < data.length; i += ENCODE_CHUNK_SIZE) {
|
|
261
|
+
const chunk = data.subarray(i, Math.min(i + ENCODE_CHUNK_SIZE, data.length));
|
|
262
|
+
let binary = "";
|
|
263
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
264
|
+
binary += String.fromCharCode(chunk[j]);
|
|
265
|
+
}
|
|
266
|
+
chunks.push(binary);
|
|
267
|
+
}
|
|
268
|
+
return btoa(chunks.join(""));
|
|
269
|
+
}
|
|
251
270
|
var FOUNDRY_ERROR_MARKER = /* @__PURE__ */ Symbol.for("@character-foundry/core:FoundryError");
|
|
252
271
|
var FoundryError = class extends Error {
|
|
253
272
|
constructor(message, code) {
|
|
@@ -1287,12 +1306,69 @@ function matchAssetsToDescriptors(extractedAssets, descriptors) {
|
|
|
1287
1306
|
}
|
|
1288
1307
|
return matched;
|
|
1289
1308
|
}
|
|
1309
|
+
var SAFE_ASSET_TYPES = /* @__PURE__ */ new Set([
|
|
1310
|
+
"icon",
|
|
1311
|
+
"user_icon",
|
|
1312
|
+
"emotion",
|
|
1313
|
+
"background",
|
|
1314
|
+
"sound",
|
|
1315
|
+
"video",
|
|
1316
|
+
"custom",
|
|
1317
|
+
"x-risu-asset",
|
|
1318
|
+
"data",
|
|
1319
|
+
"unknown"
|
|
1320
|
+
]);
|
|
1321
|
+
var SAFE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1322
|
+
// Images
|
|
1323
|
+
"png",
|
|
1324
|
+
"jpg",
|
|
1325
|
+
"jpeg",
|
|
1326
|
+
"webp",
|
|
1327
|
+
"gif",
|
|
1328
|
+
"avif",
|
|
1329
|
+
"svg",
|
|
1330
|
+
"bmp",
|
|
1331
|
+
"ico",
|
|
1332
|
+
// Audio
|
|
1333
|
+
"mp3",
|
|
1334
|
+
"wav",
|
|
1335
|
+
"ogg",
|
|
1336
|
+
"flac",
|
|
1337
|
+
"m4a",
|
|
1338
|
+
"aac",
|
|
1339
|
+
"opus",
|
|
1340
|
+
// Video
|
|
1341
|
+
"mp4",
|
|
1342
|
+
"webm",
|
|
1343
|
+
"avi",
|
|
1344
|
+
"mov",
|
|
1345
|
+
"mkv",
|
|
1346
|
+
// Data
|
|
1347
|
+
"json",
|
|
1348
|
+
"txt",
|
|
1349
|
+
"bin"
|
|
1350
|
+
]);
|
|
1290
1351
|
function getCharxCategory(mimetype) {
|
|
1291
1352
|
if (mimetype.startsWith("image/")) return "images";
|
|
1292
1353
|
if (mimetype.startsWith("audio/")) return "audio";
|
|
1293
1354
|
if (mimetype.startsWith("video/")) return "video";
|
|
1294
1355
|
return "other";
|
|
1295
1356
|
}
|
|
1357
|
+
function sanitizeAssetType(type) {
|
|
1358
|
+
const normalized = type.toLowerCase().replace(/[^a-z0-9-_]/g, "-");
|
|
1359
|
+
if (SAFE_ASSET_TYPES.has(normalized)) {
|
|
1360
|
+
return normalized;
|
|
1361
|
+
}
|
|
1362
|
+
const sanitized = normalized.replace(/[^a-z0-9]/g, "");
|
|
1363
|
+
return sanitized || "custom";
|
|
1364
|
+
}
|
|
1365
|
+
function sanitizeExtension(ext) {
|
|
1366
|
+
const normalized = ext.replace(/^\./, "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1367
|
+
if (SAFE_EXTENSIONS.has(normalized)) {
|
|
1368
|
+
return normalized;
|
|
1369
|
+
}
|
|
1370
|
+
return "bin";
|
|
1371
|
+
}
|
|
1296
1372
|
function sanitizeName(name, ext) {
|
|
1297
1373
|
let safeName = name;
|
|
1298
1374
|
if (safeName.toLowerCase().endsWith(`.${ext.toLowerCase()}`)) {
|
|
@@ -1326,10 +1402,12 @@ Import this file into SillyTavern, RisuAI, or other compatible applications.
|
|
|
1326
1402
|
let assetCount = 0;
|
|
1327
1403
|
for (let i = 0; i < assets.length; i++) {
|
|
1328
1404
|
const asset = assets[i];
|
|
1329
|
-
const
|
|
1405
|
+
const safeType = sanitizeAssetType(asset.type);
|
|
1406
|
+
const safeExt = sanitizeExtension(asset.ext);
|
|
1407
|
+
const mimetype = getMimeTypeFromExt(safeExt);
|
|
1330
1408
|
const category = getCharxCategory(mimetype);
|
|
1331
|
-
const safeName = sanitizeName(asset.name,
|
|
1332
|
-
const assetPath = `assets/${
|
|
1409
|
+
const safeName = sanitizeName(asset.name, safeExt);
|
|
1410
|
+
const assetPath = `assets/${safeType}/${category}/${safeName}.${safeExt}`;
|
|
1333
1411
|
zipEntries[assetPath] = [asset.data, { level: compressionLevel }];
|
|
1334
1412
|
assetCount++;
|
|
1335
1413
|
if (emitXMeta && mimetype.startsWith("image/")) {
|
|
@@ -1350,16 +1428,18 @@ Import this file into SillyTavern, RisuAI, or other compatible applications.
|
|
|
1350
1428
|
};
|
|
1351
1429
|
}
|
|
1352
1430
|
function transformAssetUris(card, assets) {
|
|
1353
|
-
const transformed = JSON.parse(JSON.stringify(card));
|
|
1431
|
+
const transformed = typeof structuredClone === "function" ? structuredClone(card) : JSON.parse(JSON.stringify(card));
|
|
1354
1432
|
transformed.data.assets = assets.map((asset) => {
|
|
1355
|
-
const
|
|
1433
|
+
const safeType = sanitizeAssetType(asset.type);
|
|
1434
|
+
const safeExt = sanitizeExtension(asset.ext);
|
|
1435
|
+
const mimetype = getMimeTypeFromExt(safeExt);
|
|
1356
1436
|
const category = getCharxCategory(mimetype);
|
|
1357
|
-
const safeName = sanitizeName(asset.name,
|
|
1437
|
+
const safeName = sanitizeName(asset.name, safeExt);
|
|
1358
1438
|
return {
|
|
1359
1439
|
type: asset.type,
|
|
1360
|
-
uri: `embeded://assets/${
|
|
1440
|
+
uri: `embeded://assets/${safeType}/${category}/${safeName}.${safeExt}`,
|
|
1361
1441
|
name: safeName,
|
|
1362
|
-
ext:
|
|
1442
|
+
ext: safeExt
|
|
1363
1443
|
};
|
|
1364
1444
|
});
|
|
1365
1445
|
return transformed;
|
|
@@ -7686,7 +7766,7 @@ function getExtension(format) {
|
|
|
7686
7766
|
}
|
|
7687
7767
|
|
|
7688
7768
|
// ../voxta/dist/index.js
|
|
7689
|
-
import {
|
|
7769
|
+
import { zipSync as zipSync22 } from "fflate";
|
|
7690
7770
|
var DEFAULT_OPTIONS2 = {
|
|
7691
7771
|
maxFileSize: 50 * 1024 * 1024,
|
|
7692
7772
|
// 50MB
|
|
@@ -8450,8 +8530,16 @@ function detectExtension(buffer) {
|
|
|
8450
8530
|
if (buffer[0] === 73 && buffer[1] === 68 && buffer[2] === 51) {
|
|
8451
8531
|
return "mp3";
|
|
8452
8532
|
}
|
|
8453
|
-
if (buffer.length
|
|
8454
|
-
|
|
8533
|
+
if (buffer.length >= 4 && buffer[0] === 255 && (buffer[1] & 224) === 224) {
|
|
8534
|
+
const byte2 = buffer[1];
|
|
8535
|
+
const byte3 = buffer[2];
|
|
8536
|
+
const version = byte2 >> 3 & 3;
|
|
8537
|
+
const layer = byte2 >> 1 & 3;
|
|
8538
|
+
const bitrateIndex = byte3 >> 4 & 15;
|
|
8539
|
+
const sampleRate = byte3 >> 2 & 3;
|
|
8540
|
+
if (version !== 1 && layer !== 0 && bitrateIndex !== 15 && sampleRate !== 3) {
|
|
8541
|
+
return "mp3";
|
|
8542
|
+
}
|
|
8455
8543
|
}
|
|
8456
8544
|
if (buffer.length >= 12 && buffer[0] === 82 && buffer[1] === 73 && buffer[2] === 70 && buffer[3] === 70 && buffer[8] === 87 && buffer[9] === 65 && buffer[10] === 86 && buffer[11] === 69) {
|
|
8457
8545
|
return "wav";
|
|
@@ -8485,6 +8573,17 @@ function parsePng(data, options) {
|
|
|
8485
8573
|
}];
|
|
8486
8574
|
if (extracted.extraChunks && options.extractAssets && card.data.assets) {
|
|
8487
8575
|
const usedChunks = /* @__PURE__ */ new Set();
|
|
8576
|
+
const chunkMap = /* @__PURE__ */ new Map();
|
|
8577
|
+
for (const chunk of extracted.extraChunks) {
|
|
8578
|
+
chunkMap.set(chunk.keyword, chunk);
|
|
8579
|
+
if (chunk.keyword.startsWith("chara-ext-asset_")) {
|
|
8580
|
+
const suffix = chunk.keyword.replace("chara-ext-asset_", "");
|
|
8581
|
+
chunkMap.set(suffix, chunk);
|
|
8582
|
+
if (suffix.startsWith(":")) {
|
|
8583
|
+
chunkMap.set(suffix.substring(1), chunk);
|
|
8584
|
+
}
|
|
8585
|
+
}
|
|
8586
|
+
}
|
|
8488
8587
|
for (const descriptor of card.data.assets) {
|
|
8489
8588
|
if (!descriptor.uri) continue;
|
|
8490
8589
|
if (descriptor.uri.startsWith("__asset:") || descriptor.uri.startsWith("asset:") || descriptor.uri.startsWith("pngchunk:") || !descriptor.uri.includes(":")) {
|
|
@@ -8508,13 +8607,11 @@ function parsePng(data, options) {
|
|
|
8508
8607
|
`chara-ext-asset_:${assetId}`
|
|
8509
8608
|
// "chara-ext-asset_:0"
|
|
8510
8609
|
];
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
return false;
|
|
8517
|
-
});
|
|
8610
|
+
let chunk;
|
|
8611
|
+
for (const candidate of candidates) {
|
|
8612
|
+
chunk = chunkMap.get(candidate);
|
|
8613
|
+
if (chunk) break;
|
|
8614
|
+
}
|
|
8518
8615
|
if (chunk) {
|
|
8519
8616
|
try {
|
|
8520
8617
|
const estimatedSize = estimateBase64DecodedSize(chunk.text.length);
|
|
@@ -8716,6 +8813,9 @@ function parseVoxta(data, options) {
|
|
|
8716
8813
|
};
|
|
8717
8814
|
}
|
|
8718
8815
|
function parseJson(data, options) {
|
|
8816
|
+
if (data.length > options.maxFileSize) {
|
|
8817
|
+
throw new SizeLimitError(data.length, options.maxFileSize, "JSON file");
|
|
8818
|
+
}
|
|
8719
8819
|
let jsonStr;
|
|
8720
8820
|
try {
|
|
8721
8821
|
jsonStr = toString(data);
|
|
@@ -8734,6 +8834,9 @@ function parseJson(data, options) {
|
|
|
8734
8834
|
"json"
|
|
8735
8835
|
);
|
|
8736
8836
|
}
|
|
8837
|
+
return parseJsonFromParsed(parsed, jsonStr, data, options);
|
|
8838
|
+
}
|
|
8839
|
+
function parseJsonFromParsed(parsed, jsonStr, rawBuffer, options) {
|
|
8737
8840
|
const spec = detectSpec(parsed);
|
|
8738
8841
|
let card;
|
|
8739
8842
|
let sourceFormat;
|
|
@@ -8758,7 +8861,7 @@ function parseJson(data, options) {
|
|
|
8758
8861
|
sourceFormat,
|
|
8759
8862
|
originalShape: parsed,
|
|
8760
8863
|
rawJson: jsonStr,
|
|
8761
|
-
rawBuffer
|
|
8864
|
+
rawBuffer
|
|
8762
8865
|
};
|
|
8763
8866
|
}
|
|
8764
8867
|
function parseCard(data, options = {}) {
|
|
@@ -8784,6 +8887,7 @@ function parseCard(data, options = {}) {
|
|
|
8784
8887
|
async function parseCardAsync(data, options = {}) {
|
|
8785
8888
|
return parseCard(data, options);
|
|
8786
8889
|
}
|
|
8890
|
+
var DEFAULT_MAX_LOREBOOK_SIZE = 10 * 1024 * 1024;
|
|
8787
8891
|
|
|
8788
8892
|
// ../exporter/dist/index.js
|
|
8789
8893
|
function checkPngLoss(card, assets) {
|