@character-foundry/character-foundry 0.1.5 → 0.1.7
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/image-utils.cjs +249 -0
- package/dist/image-utils.cjs.map +1 -0
- package/dist/image-utils.d.cts +136 -0
- package/dist/image-utils.d.ts +136 -0
- package/dist/image-utils.js +226 -0
- package/dist/image-utils.js.map +1 -0
- 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 +16 -5
package/dist/app-framework.cjs
CHANGED
|
@@ -408,13 +408,23 @@ function analyzeField(name, zodType) {
|
|
|
408
408
|
constraints: extractConstraints(currentType)
|
|
409
409
|
};
|
|
410
410
|
}
|
|
411
|
+
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
412
|
+
function isSafeKey(key) {
|
|
413
|
+
return !DANGEROUS_KEYS.has(key);
|
|
414
|
+
}
|
|
411
415
|
function getValueAtPath(obj, path) {
|
|
412
416
|
const parts = path.split(".");
|
|
413
417
|
let current = obj;
|
|
414
418
|
for (const part of parts) {
|
|
419
|
+
if (!isSafeKey(part)) {
|
|
420
|
+
return void 0;
|
|
421
|
+
}
|
|
415
422
|
if (current == null || typeof current !== "object") {
|
|
416
423
|
return void 0;
|
|
417
424
|
}
|
|
425
|
+
if (!Object.hasOwn(current, part)) {
|
|
426
|
+
return void 0;
|
|
427
|
+
}
|
|
418
428
|
current = current[part];
|
|
419
429
|
}
|
|
420
430
|
return current;
|
|
@@ -424,12 +434,16 @@ function setValueAtPath(obj, path, value) {
|
|
|
424
434
|
if (parts.length === 0 || parts[0] === void 0) {
|
|
425
435
|
return obj;
|
|
426
436
|
}
|
|
437
|
+
const first = parts[0];
|
|
438
|
+
if (!isSafeKey(first)) {
|
|
439
|
+
console.warn(`Rejected dangerous property key in path: ${first}`);
|
|
440
|
+
return obj;
|
|
441
|
+
}
|
|
427
442
|
if (parts.length === 1) {
|
|
428
|
-
return { ...obj, [
|
|
443
|
+
return { ...obj, [first]: value };
|
|
429
444
|
}
|
|
430
|
-
const first = parts[0];
|
|
431
445
|
const rest = parts.slice(1);
|
|
432
|
-
const nested = obj[first] ?? {};
|
|
446
|
+
const nested = (Object.hasOwn(obj, first) ? obj[first] : {}) ?? {};
|
|
433
447
|
return {
|
|
434
448
|
...obj,
|
|
435
449
|
[first]: setValueAtPath(nested, rest.join("."), value)
|
|
@@ -821,11 +835,31 @@ function SearchableSelect({
|
|
|
821
835
|
const [isOpen, setIsOpen] = (0, import_react3.useState)(false);
|
|
822
836
|
const [searchTerm, setSearchTerm] = (0, import_react3.useState)("");
|
|
823
837
|
const [highlightedIndex, setHighlightedIndex] = (0, import_react3.useState)(-1);
|
|
824
|
-
const
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
838
|
+
const rawOptions = hint?.options ?? [];
|
|
839
|
+
const indexedOptions = (0, import_react3.useMemo)(() => {
|
|
840
|
+
return rawOptions.map((opt) => ({
|
|
841
|
+
option: opt,
|
|
842
|
+
labelLower: opt.label.toLowerCase(),
|
|
843
|
+
valueLower: opt.value.toLowerCase()
|
|
844
|
+
}));
|
|
845
|
+
}, [rawOptions]);
|
|
846
|
+
const optionsByValue = (0, import_react3.useMemo)(() => {
|
|
847
|
+
const map = /* @__PURE__ */ new Map();
|
|
848
|
+
for (const opt of rawOptions) {
|
|
849
|
+
map.set(opt.value, opt);
|
|
850
|
+
}
|
|
851
|
+
return map;
|
|
852
|
+
}, [rawOptions]);
|
|
853
|
+
const filteredOptions = (0, import_react3.useMemo)(() => {
|
|
854
|
+
if (!searchTerm) {
|
|
855
|
+
return rawOptions;
|
|
856
|
+
}
|
|
857
|
+
const searchLower = searchTerm.toLowerCase();
|
|
858
|
+
return indexedOptions.filter(
|
|
859
|
+
(indexed) => indexed.labelLower.includes(searchLower) || indexed.valueLower.includes(searchLower)
|
|
860
|
+
).map((indexed) => indexed.option);
|
|
861
|
+
}, [searchTerm, indexedOptions, rawOptions]);
|
|
862
|
+
const selectedOption = optionsByValue.get(value ?? "");
|
|
829
863
|
const displayValue = selectedOption?.label ?? value ?? "";
|
|
830
864
|
(0, import_react3.useEffect)(() => {
|
|
831
865
|
function handleClickOutside(e) {
|
|
@@ -1466,33 +1500,84 @@ function AutoForm({
|
|
|
1466
1500
|
extractDefaults(fieldInfoMap);
|
|
1467
1501
|
return defaults;
|
|
1468
1502
|
}, [fieldInfoMap]);
|
|
1503
|
+
const mergedDefaults = (0, import_react.useMemo)(() => {
|
|
1504
|
+
return deepMerge(
|
|
1505
|
+
deepMerge(schemaDefaults, defaultValues ?? {}),
|
|
1506
|
+
values ?? {}
|
|
1507
|
+
);
|
|
1508
|
+
}, [schemaDefaults, defaultValues, values]);
|
|
1469
1509
|
const methods = (0, import_react_hook_form.useForm)({
|
|
1470
1510
|
resolver: (0, import_zod2.zodResolver)(schema),
|
|
1471
|
-
defaultValues:
|
|
1472
|
-
...schemaDefaults,
|
|
1473
|
-
...defaultValues,
|
|
1474
|
-
...values
|
|
1475
|
-
},
|
|
1511
|
+
defaultValues: mergedDefaults,
|
|
1476
1512
|
mode: "onChange",
|
|
1477
1513
|
shouldUnregister: true
|
|
1478
1514
|
});
|
|
1479
|
-
const { control, handleSubmit, watch, formState, reset } = methods;
|
|
1480
|
-
const watchedValues = watch();
|
|
1515
|
+
const { control, handleSubmit, watch, formState, reset, getValues } = methods;
|
|
1481
1516
|
const prevValuesRef = (0, import_react.useRef)(values);
|
|
1517
|
+
const conditionFields = (0, import_react.useMemo)(() => {
|
|
1518
|
+
const fields = /* @__PURE__ */ new Set();
|
|
1519
|
+
const extractConditionFields = (hints, prefix = "") => {
|
|
1520
|
+
for (const [key, value] of Object.entries(hints)) {
|
|
1521
|
+
if (!value || typeof value !== "object") continue;
|
|
1522
|
+
const hint = value;
|
|
1523
|
+
if (hint.condition && typeof hint.condition === "object") {
|
|
1524
|
+
const condition = hint.condition;
|
|
1525
|
+
if (condition.field) {
|
|
1526
|
+
fields.add(condition.field);
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
if (!("widget" in hint) && !("label" in hint) && !("condition" in hint)) {
|
|
1530
|
+
extractConditionFields(hint, prefix ? `${prefix}.${key}` : key);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
extractConditionFields(uiHints);
|
|
1535
|
+
return Array.from(fields);
|
|
1536
|
+
}, [uiHints]);
|
|
1537
|
+
const [conditionValues, setConditionValues] = (0, import_react.useState)({});
|
|
1538
|
+
(0, import_react.useEffect)(() => {
|
|
1539
|
+
if (conditionFields.length === 0) return;
|
|
1540
|
+
const initial = {};
|
|
1541
|
+
const currentValues = getValues();
|
|
1542
|
+
for (const field of conditionFields) {
|
|
1543
|
+
initial[field] = getValueAtPath(currentValues, field);
|
|
1544
|
+
}
|
|
1545
|
+
setConditionValues(initial);
|
|
1546
|
+
const subscription = watch((formValues, { name }) => {
|
|
1547
|
+
if (name && conditionFields.includes(name)) {
|
|
1548
|
+
setConditionValues((prev) => ({
|
|
1549
|
+
...prev,
|
|
1550
|
+
[name]: getValueAtPath(formValues, name)
|
|
1551
|
+
}));
|
|
1552
|
+
}
|
|
1553
|
+
});
|
|
1554
|
+
return () => subscription.unsubscribe();
|
|
1555
|
+
}, [conditionFields, watch, getValues]);
|
|
1482
1556
|
(0, import_react.useEffect)(() => {
|
|
1483
1557
|
if (values && !shallowEqual(values, prevValuesRef.current)) {
|
|
1484
1558
|
prevValuesRef.current = values;
|
|
1485
|
-
|
|
1559
|
+
const resetValues = deepMerge(
|
|
1560
|
+
deepMerge(schemaDefaults, defaultValues ?? {}),
|
|
1561
|
+
values ?? {}
|
|
1562
|
+
);
|
|
1563
|
+
reset(resetValues);
|
|
1486
1564
|
}
|
|
1487
1565
|
}, [values, reset, schemaDefaults, defaultValues]);
|
|
1566
|
+
const onChangeRef = (0, import_react.useRef)(onChange);
|
|
1567
|
+
onChangeRef.current = onChange;
|
|
1568
|
+
const schemaRef = (0, import_react.useRef)(schema);
|
|
1569
|
+
schemaRef.current = schema;
|
|
1488
1570
|
(0, import_react.useEffect)(() => {
|
|
1489
|
-
if (
|
|
1490
|
-
|
|
1491
|
-
if (
|
|
1492
|
-
|
|
1571
|
+
if (!onChangeRef.current) return;
|
|
1572
|
+
const subscription = watch((formValues, { type }) => {
|
|
1573
|
+
if (type !== "change") return;
|
|
1574
|
+
const result = schemaRef.current.safeParse(formValues);
|
|
1575
|
+
if (result.success && onChangeRef.current) {
|
|
1576
|
+
onChangeRef.current(result.data);
|
|
1493
1577
|
}
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1578
|
+
});
|
|
1579
|
+
return () => subscription.unsubscribe();
|
|
1580
|
+
}, [watch]);
|
|
1496
1581
|
const HINT_KEYS = /* @__PURE__ */ new Set([
|
|
1497
1582
|
"widget",
|
|
1498
1583
|
"label",
|
|
@@ -1538,9 +1623,9 @@ function AutoForm({
|
|
|
1538
1623
|
const isConditionMet = (0, import_react.useCallback)(
|
|
1539
1624
|
(condition) => {
|
|
1540
1625
|
if (!condition) return true;
|
|
1541
|
-
const fieldValue = getValueAtPath(
|
|
1626
|
+
const fieldValue = conditionFields.length > 0 ? conditionValues[condition.field] : getValueAtPath(getValues(), condition.field);
|
|
1542
1627
|
if (condition.when) {
|
|
1543
|
-
return condition.when(fieldValue,
|
|
1628
|
+
return condition.when(fieldValue, getValues());
|
|
1544
1629
|
}
|
|
1545
1630
|
if ("equals" in condition && condition.equals !== void 0) {
|
|
1546
1631
|
return fieldValue === condition.equals;
|
|
@@ -1556,7 +1641,7 @@ function AutoForm({
|
|
|
1556
1641
|
}
|
|
1557
1642
|
return true;
|
|
1558
1643
|
},
|
|
1559
|
-
[
|
|
1644
|
+
[conditionFields, conditionValues, getValues]
|
|
1560
1645
|
);
|
|
1561
1646
|
const orderedFields = (0, import_react.useMemo)(() => {
|
|
1562
1647
|
if (fieldOrder) {
|
|
@@ -1650,19 +1735,51 @@ function AutoForm({
|
|
|
1650
1735
|
}
|
|
1651
1736
|
return formContent;
|
|
1652
1737
|
}
|
|
1738
|
+
function deepMerge(base, override) {
|
|
1739
|
+
const result = { ...base };
|
|
1740
|
+
for (const key of Object.keys(override)) {
|
|
1741
|
+
if (!isSafeKey2(key)) continue;
|
|
1742
|
+
const baseVal = base[key];
|
|
1743
|
+
const overrideVal = override[key];
|
|
1744
|
+
if (isPlainObject(baseVal) && isPlainObject(overrideVal)) {
|
|
1745
|
+
result[key] = deepMerge(
|
|
1746
|
+
baseVal,
|
|
1747
|
+
overrideVal
|
|
1748
|
+
);
|
|
1749
|
+
} else if (overrideVal !== void 0) {
|
|
1750
|
+
result[key] = overrideVal;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
return result;
|
|
1754
|
+
}
|
|
1755
|
+
function isPlainObject(val) {
|
|
1756
|
+
return val !== null && typeof val === "object" && !Array.isArray(val) && Object.getPrototypeOf(val) === Object.prototype;
|
|
1757
|
+
}
|
|
1758
|
+
var DANGEROUS_KEYS2 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1759
|
+
function isSafeKey2(key) {
|
|
1760
|
+
return !DANGEROUS_KEYS2.has(key);
|
|
1761
|
+
}
|
|
1653
1762
|
function setNestedValue(obj, path, value) {
|
|
1654
1763
|
const parts = path.split(".");
|
|
1655
1764
|
let current = obj;
|
|
1656
1765
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
1657
1766
|
const part = parts[i];
|
|
1658
1767
|
if (part === void 0) continue;
|
|
1659
|
-
if (!(part
|
|
1768
|
+
if (!isSafeKey2(part)) {
|
|
1769
|
+
console.warn(`Rejected dangerous property key in path: ${part}`);
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
if (!Object.hasOwn(current, part) || typeof current[part] !== "object") {
|
|
1660
1773
|
current[part] = {};
|
|
1661
1774
|
}
|
|
1662
1775
|
current = current[part];
|
|
1663
1776
|
}
|
|
1664
1777
|
const lastPart = parts[parts.length - 1];
|
|
1665
1778
|
if (lastPart !== void 0) {
|
|
1779
|
+
if (!isSafeKey2(lastPart)) {
|
|
1780
|
+
console.warn(`Rejected dangerous property key in path: ${lastPart}`);
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1666
1783
|
current[lastPart] = value;
|
|
1667
1784
|
}
|
|
1668
1785
|
}
|