@novely/core 0.47.2 → 0.48.0

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
@@ -2,7 +2,7 @@
2
2
  import { dequal } from "dequal/lite";
3
3
  import { throttle } from "es-toolkit/function";
4
4
  import { merge as deepmerge } from "es-toolkit/object";
5
- import { DEV as DEV3 } from "esm-env";
5
+ import { DEV as DEV4 } from "esm-env";
6
6
 
7
7
  // ../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/full/index.mjs
8
8
  function set(obj, key, val) {
@@ -148,7 +148,7 @@ var isAsset = (suspect) => {
148
148
  // src/utilities/match-action.ts
149
149
  var matchAction = (callbacks, values) => {
150
150
  const { getContext, onBeforeActionCall, push, forward } = callbacks;
151
- return (action, props, { ctx, data }) => {
151
+ const match = (action, props, { ctx, data }) => {
152
152
  const context = typeof ctx === "string" ? getContext(ctx) : ctx;
153
153
  onBeforeActionCall({
154
154
  action,
@@ -171,6 +171,10 @@ var matchAction = (callbacks, values) => {
171
171
  props
172
172
  );
173
173
  };
174
+ return {
175
+ match,
176
+ nativeActions: Object.keys(values)
177
+ };
174
178
  };
175
179
 
176
180
  // src/utilities/ungrupped.ts
@@ -503,17 +507,16 @@ var createQueueProcessor = (queue, options) => {
503
507
  if (action === "custom") {
504
508
  const fn = params[0];
505
509
  if ("callOnlyLatest" in fn && fn.callOnlyLatest) {
506
- const notLatest = next(i).some(([, func]) => {
507
- if (!isFunction(func)) return false;
508
- const c0 = func;
509
- const c1 = fn;
510
- const isIdenticalID = Boolean(c0.id && c1.id && c0.id === c1.id);
511
- const isIdenticalByReference = c0 === c1;
512
- return isIdenticalID || isIdenticalByReference || String(c0) === String(c1);
510
+ const notLatest = next(i).some(([name, func]) => {
511
+ if (name !== "custom") return;
512
+ const isIdenticalId = Boolean(func.id && fn.id && func.id === fn.id);
513
+ const isIdenticalByReference = func === fn;
514
+ const isIdenticalByCode = String(func) === String(fn);
515
+ return isIdenticalId || isIdenticalByReference || isIdenticalByCode;
513
516
  });
514
517
  if (notLatest) continue;
515
518
  } else if ("skipOnRestore" in fn && fn.skipOnRestore) {
516
- if (fn.skipOnRestore(() => next(i))) {
519
+ if (fn.skipOnRestore(next(i))) {
517
520
  continue;
518
521
  }
519
522
  }
@@ -562,7 +565,8 @@ var createQueueProcessor = (queue, options) => {
562
565
  const next2 = array.slice(j);
563
566
  const characterWillAnimate = next2.some(([__action, __character]) => action === __action);
564
567
  const hasBlockingActions = next2.some((item2) => options.skip.has(item2));
565
- return characterWillAnimate && hasBlockingActions;
568
+ const differentCharacterWillAnimate = !hasBlockingActions && next2.some(([__action, __character]) => __action === action && __character !== params[0]);
569
+ return characterWillAnimate && hasBlockingActions || differentCharacterWillAnimate;
566
570
  });
567
571
  if (skip) continue;
568
572
  processedQueue.push(item);
@@ -1026,6 +1030,70 @@ var replace = (input, data, pluralization, actions, pr) => {
1026
1030
  });
1027
1031
  };
1028
1032
 
1033
+ // src/utilities/actions.ts
1034
+ import { DEV as DEV3 } from "esm-env";
1035
+ var VIRTUAL_ACTIONS = ["say"];
1036
+ var buildActionObject = ({
1037
+ rendererActions,
1038
+ nativeActions,
1039
+ characters,
1040
+ preloadAssets,
1041
+ storageData
1042
+ }) => {
1043
+ const allActions = [...nativeActions, ...VIRTUAL_ACTIONS];
1044
+ const object = { ...rendererActions };
1045
+ for (let action of allActions) {
1046
+ object[action] = (...props) => {
1047
+ if (action === "say") {
1048
+ action = "dialog";
1049
+ const [character] = props;
1050
+ if (DEV3 && !characters[character]) {
1051
+ throw new Error(`Attempt to call Say action with unknown character "${character}"`);
1052
+ }
1053
+ } else if (action === "choice") {
1054
+ if (props.slice(1).every((choice) => !Array.isArray(choice))) {
1055
+ for (let i = 1; i < props.length; i++) {
1056
+ const choice = props[i];
1057
+ props[i] = [
1058
+ choice.title,
1059
+ flatActions(choice.children),
1060
+ choice.active,
1061
+ choice.visible,
1062
+ choice.onSelect,
1063
+ choice.image
1064
+ ];
1065
+ }
1066
+ } else {
1067
+ for (let i = 1; i < props.length; i++) {
1068
+ const choice = props[i];
1069
+ if (Array.isArray(choice)) {
1070
+ choice[1] = flatActions(choice[1]);
1071
+ }
1072
+ }
1073
+ }
1074
+ } else if (action === "condition") {
1075
+ const actions = props[1];
1076
+ for (const key in actions) {
1077
+ actions[key] = flatActions(actions[key]);
1078
+ }
1079
+ }
1080
+ if (preloadAssets === "blocking") {
1081
+ huntAssets({
1082
+ action,
1083
+ props,
1084
+ mode: preloadAssets,
1085
+ characters,
1086
+ lang: getLanguageFromStore(storageData),
1087
+ volume: getVolumeFromStore(storageData),
1088
+ handle: enqueueAssetForPreloading
1089
+ });
1090
+ }
1091
+ return [action, ...props];
1092
+ };
1093
+ }
1094
+ return object;
1095
+ };
1096
+
1029
1097
  // src/novely.ts
1030
1098
  var novely = ({
1031
1099
  characters,
@@ -1049,7 +1117,8 @@ var novely = ({
1049
1117
  fetch: request = fetch,
1050
1118
  cloneFunction: clone = klona,
1051
1119
  saveOnUnload = true,
1052
- startKey = "start"
1120
+ startKey = "start",
1121
+ defaultTypewriterSpeed = DEFAULT_TYPEWRITER_SPEED
1053
1122
  }) => {
1054
1123
  const languages = Object.keys(translation);
1055
1124
  const limitScript = pLimit(1);
@@ -1094,61 +1163,6 @@ var novely = ({
1094
1163
  const script = (part) => {
1095
1164
  return limitScript(() => scriptBase(part));
1096
1165
  };
1097
- const action = new Proxy({}, {
1098
- get(_, action2) {
1099
- if (action2 in renderer.actions) {
1100
- return renderer.actions[action2];
1101
- }
1102
- return (...props) => {
1103
- if (action2 === "say") {
1104
- action2 = "dialog";
1105
- const [character] = props;
1106
- if (DEV3 && !characters[character]) {
1107
- throw new Error(`Attempt to call Say action with unknown character "${character}"`);
1108
- }
1109
- } else if (action2 === "choice") {
1110
- const actions = props.slice(1);
1111
- if (actions.every((choice) => !Array.isArray(choice))) {
1112
- for (let i = 1; i < props.length; i++) {
1113
- const choice = props[i];
1114
- props[i] = [
1115
- choice.title,
1116
- flatActions(choice.children),
1117
- choice.active,
1118
- choice.visible,
1119
- choice.onSelect,
1120
- choice.image
1121
- ];
1122
- }
1123
- } else {
1124
- for (let i = 1; i < props.length; i++) {
1125
- const choice = props[i];
1126
- if (Array.isArray(choice)) {
1127
- choice[1] = flatActions(choice[1]);
1128
- }
1129
- }
1130
- }
1131
- } else if (action2 === "condition") {
1132
- const actions = props[1];
1133
- for (const key in actions) {
1134
- actions[key] = flatActions(actions[key]);
1135
- }
1136
- }
1137
- if (preloadAssets === "blocking") {
1138
- huntAssets({
1139
- action: action2,
1140
- props,
1141
- mode: preloadAssets,
1142
- characters,
1143
- lang: getLanguageFromStore(storageData),
1144
- volume: getVolumeFromStore(storageData),
1145
- handle: enqueueAssetForPreloading
1146
- });
1147
- }
1148
- return [action2, ...props];
1149
- };
1150
- }
1151
- });
1152
1166
  const getDefaultSave = (state) => {
1153
1167
  return [
1154
1168
  [
@@ -1165,7 +1179,7 @@ var novely = ({
1165
1179
  if (languages.includes(language)) {
1166
1180
  return language;
1167
1181
  }
1168
- if (DEV3) {
1182
+ if (DEV4) {
1169
1183
  throw new Error(
1170
1184
  `Attempt to use unsupported language "${language}". Supported languages: ${languages.join(", ")}.`
1171
1185
  );
@@ -1202,7 +1216,7 @@ var novely = ({
1202
1216
  };
1203
1217
  const throttledOnStorageDataChange = throttle(onStorageDataChange, throttleTimeout);
1204
1218
  const throttledEmergencyOnStorageDataChange = throttle(() => {
1205
- if (saveOnUnload === true || saveOnUnload === "prod" && !DEV3) {
1219
+ if (saveOnUnload === true || saveOnUnload === "prod" && !DEV4) {
1206
1220
  onStorageDataChange(storageData.get());
1207
1221
  }
1208
1222
  }, 10);
@@ -1211,14 +1225,14 @@ var novely = ({
1211
1225
  let stored = await storage.get();
1212
1226
  for (const migration of migrations) {
1213
1227
  stored = migration(stored);
1214
- if (DEV3 && !stored) {
1228
+ if (DEV4 && !stored) {
1215
1229
  throw new Error("Migrations should return a value.");
1216
1230
  }
1217
1231
  }
1218
1232
  if (overrideLanguage || !stored.meta[0]) {
1219
1233
  stored.meta[0] = getLanguageWithoutParameters();
1220
1234
  }
1221
- stored.meta[1] ||= DEFAULT_TYPEWRITER_SPEED;
1235
+ stored.meta[1] ||= defaultTypewriterSpeed;
1222
1236
  stored.meta[2] ??= 1;
1223
1237
  stored.meta[3] ??= 1;
1224
1238
  stored.meta[4] ??= 1;
@@ -1289,7 +1303,7 @@ var novely = ({
1289
1303
  let interacted = 0;
1290
1304
  const restore = async (save2) => {
1291
1305
  if (isEmpty(story)) {
1292
- if (DEV3) {
1306
+ if (DEV4) {
1293
1307
  throw new Error(
1294
1308
  "Story is empty. You should call an `enine.script` function [https://novely.pages.dev/guide/story.html]"
1295
1309
  );
@@ -1462,7 +1476,7 @@ var novely = ({
1462
1476
  };
1463
1477
  const getLanguageDisplayName = (lang) => {
1464
1478
  const language = translation[lang];
1465
- if (DEV3 && !language) {
1479
+ if (DEV4 && !language) {
1466
1480
  throw new Error(
1467
1481
  `Attempt to use unsupported language "${language}". Supported languages: ${languages.join(", ")}.`
1468
1482
  );
@@ -1626,7 +1640,7 @@ var novely = ({
1626
1640
  }
1627
1641
  }
1628
1642
  };
1629
- const match = matchAction(matchActionOptions, {
1643
+ const { match, nativeActions } = matchAction(matchActionOptions, {
1630
1644
  wait({ ctx, data: data2, push }, [time]) {
1631
1645
  if (ctx.meta.restoring) return;
1632
1646
  setTimeout(push, isFunction(time) ? time(data2) : time);
@@ -1683,11 +1697,11 @@ var novely = ({
1683
1697
  },
1684
1698
  showCharacter({ ctx, push }, [character, emotion, className, style]) {
1685
1699
  emotion ??= defaultEmotions[character];
1686
- if (DEV3 && !emotion) {
1700
+ if (DEV4 && !emotion) {
1687
1701
  throw new Error(`Attemp to show character "${character}" without emotion provided.`);
1688
1702
  }
1689
1703
  if (!emotion) return;
1690
- if (DEV3 && !characters[character].emotions[emotion]) {
1704
+ if (DEV4 && !characters[character].emotions[emotion]) {
1691
1705
  throw new Error(`Attempt to show character "${character}" with unknown emotion "${emotion}"`);
1692
1706
  }
1693
1707
  const handle = ctx.character(character);
@@ -1754,7 +1768,7 @@ var novely = ({
1754
1768
  const imageValue = image ? handleImageAsset(image) : "";
1755
1769
  return [templateReplace(content, data2), active$, visible$, onSelectWrapped, imageValue];
1756
1770
  });
1757
- if (DEV3 && transformedChoices.length === 0) {
1771
+ if (DEV4 && transformedChoices.length === 0) {
1758
1772
  throw new Error(
1759
1773
  `Running choice without variants to choose from, look at how to use Choice action properly [https://novely.pages.dev/guide/actions/choice#usage]`
1760
1774
  );
@@ -1766,7 +1780,7 @@ var novely = ({
1766
1780
  }
1767
1781
  const stack = useStack(ctx);
1768
1782
  const offset = isWithoutQuestion ? 0 : 1;
1769
- if (DEV3 && !transformedChoices[selected]) {
1783
+ if (DEV4 && !transformedChoices[selected]) {
1770
1784
  throw new Error("Choice children is empty, either add content there or make item not selectable");
1771
1785
  }
1772
1786
  stack.value[0].push(["choice", selected + offset], [null, 0]);
@@ -1775,10 +1789,10 @@ var novely = ({
1775
1789
  });
1776
1790
  },
1777
1791
  jump({ ctx, data: data2 }, [scene]) {
1778
- if (DEV3 && !story[scene]) {
1792
+ if (DEV4 && !story[scene]) {
1779
1793
  throw new Error(`Attempt to jump to unknown scene "${scene}"`);
1780
1794
  }
1781
- if (DEV3 && story[scene].length === 0) {
1795
+ if (DEV4 && story[scene].length === 0) {
1782
1796
  throw new Error(`Attempt to jump to empty scene "${scene}"`);
1783
1797
  }
1784
1798
  const stack = useStack(ctx);
@@ -1802,15 +1816,15 @@ var novely = ({
1802
1816
  );
1803
1817
  },
1804
1818
  condition({ ctx, data: data2 }, [condition, variants]) {
1805
- if (DEV3 && Object.values(variants).length === 0) {
1819
+ if (DEV4 && Object.values(variants).length === 0) {
1806
1820
  throw new Error(`Attempt to use Condition action with empty variants object`);
1807
1821
  }
1808
1822
  if (!ctx.meta.restoring) {
1809
1823
  const val = String(condition(data2));
1810
- if (DEV3 && !variants[val]) {
1824
+ if (DEV4 && !variants[val]) {
1811
1825
  throw new Error(`Attempt to go to unknown variant "${val}"`);
1812
1826
  }
1813
- if (DEV3 && variants[val].length === 0) {
1827
+ if (DEV4 && variants[val].length === 0) {
1814
1828
  throw new Error(`Attempt to go to empty variant "${val}"`);
1815
1829
  }
1816
1830
  const stack = useStack(ctx);
@@ -1864,7 +1878,7 @@ var novely = ({
1864
1878
  },
1865
1879
  animateCharacter({ ctx, push }, [character, className]) {
1866
1880
  const classes = className.split(" ");
1867
- if (DEV3 && classes.length === 0) {
1881
+ if (DEV4 && classes.length === 0) {
1868
1882
  throw new Error(
1869
1883
  "Attempt to use AnimateCharacter without classes. Classes should be provided [https://novely.pages.dev/guide/actions/animateCharacter.html]"
1870
1884
  );
@@ -1875,7 +1889,7 @@ var novely = ({
1875
1889
  },
1876
1890
  text({ ctx, data: data2, forward }, text) {
1877
1891
  const string = text.map((content) => templateReplace(content, data2)).join(" ");
1878
- if (DEV3 && string.length === 0) {
1892
+ if (DEV4 && string.length === 0) {
1879
1893
  throw new Error(`Action Text was called with empty string or array`);
1880
1894
  }
1881
1895
  ctx.clearBlockingActions("text");
@@ -1900,7 +1914,7 @@ var novely = ({
1900
1914
  render(ctx);
1901
1915
  },
1902
1916
  preload({ ctx, push }, [source]) {
1903
- if (DEV3 && preloadAssets !== "lazy") {
1917
+ if (DEV4 && preloadAssets !== "lazy") {
1904
1918
  console.error(
1905
1919
  `You do not need a preload action becase "preloadAssets" strategy was set to "${preloadAssets}"`
1906
1920
  );
@@ -1911,10 +1925,10 @@ var novely = ({
1911
1925
  push();
1912
1926
  },
1913
1927
  block({ ctx }, [scene]) {
1914
- if (DEV3 && !story[scene]) {
1928
+ if (DEV4 && !story[scene]) {
1915
1929
  throw new Error(`Attempt to call Block action with unknown scene "${scene}"`);
1916
1930
  }
1917
- if (DEV3 && story[scene].length === 0) {
1931
+ if (DEV4 && story[scene].length === 0) {
1918
1932
  throw new Error(`Attempt to call Block action with empty scene "${scene}"`);
1919
1933
  }
1920
1934
  if (!ctx.meta.restoring) {
@@ -1924,6 +1938,13 @@ var novely = ({
1924
1938
  }
1925
1939
  }
1926
1940
  });
1941
+ const action = buildActionObject({
1942
+ rendererActions: renderer.actions,
1943
+ nativeActions,
1944
+ characters,
1945
+ preloadAssets,
1946
+ storageData
1947
+ });
1927
1948
  const render = (ctx) => {
1928
1949
  const stack = useStack(ctx);
1929
1950
  const [path, state] = stack.value;
@@ -1981,7 +2002,7 @@ var novely = ({
1981
2002
  };
1982
2003
  const setStorageData = (data2) => {
1983
2004
  if (destroyed) {
1984
- if (DEV3) {
2005
+ if (DEV4) {
1985
2006
  throw new Error(
1986
2007
  `function \`setStorageData\` was called after novely instance was destroyed. Data is not updater nor synced after destroy.`
1987
2008
  );
@@ -2018,7 +2039,8 @@ var novely = ({
2018
2039
  */
2019
2040
  action,
2020
2041
  /**
2021
- * @deprecated Will be removed BUT replaced with state passed into actions as a parameter
2042
+ * State bound to `$MAIN` game context
2043
+ * @deprecated Use `state` function provided from action arguments
2022
2044
  */
2023
2045
  state: getStateFunction(MAIN_CONTEXT_KEY),
2024
2046
  /**
@@ -2113,11 +2135,10 @@ var novely = ({
2113
2135
 
2114
2136
  // src/extend-actions.ts
2115
2137
  var extendAction = (base, extension) => {
2116
- return new Proxy({}, {
2117
- get(_, key, receiver) {
2118
- return Reflect.get(key in extension ? extension : base, key, receiver);
2119
- }
2120
- });
2138
+ return {
2139
+ ...extension,
2140
+ ...base
2141
+ };
2121
2142
  };
2122
2143
 
2123
2144
  // src/translations.ts
@@ -2276,7 +2297,7 @@ var JP = {
2276
2297
 
2277
2298
  // src/asset.ts
2278
2299
  import { memoize as memoize4, once } from "es-toolkit/function";
2279
- import { DEV as DEV4 } from "esm-env";
2300
+ import { DEV as DEV5 } from "esm-env";
2280
2301
 
2281
2302
  // src/audio-codecs.ts
2282
2303
  var cut = (str) => str.replace(/^no$/, "");
@@ -2359,7 +2380,7 @@ var SUPPORT_MAPS = {
2359
2380
  };
2360
2381
  var assetPrivate = memoize4(
2361
2382
  (variants) => {
2362
- if (DEV4 && variants.length === 0) {
2383
+ if (DEV5 && variants.length === 0) {
2363
2384
  throw new Error(`Attempt to use "asset" function without arguments`);
2364
2385
  }
2365
2386
  const map = {};
@@ -2381,7 +2402,7 @@ var assetPrivate = memoize4(
2381
2402
  return map[extension];
2382
2403
  }
2383
2404
  }
2384
- if (DEV4) {
2405
+ if (DEV5) {
2385
2406
  throw new Error(`No matching asset was found for ${variants.map((v) => `"${v}"`).join(", ")}`);
2386
2407
  }
2387
2408
  return "";