@novely/core 0.45.1 → 0.46.0-next.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.
@@ -31,63 +31,96 @@ var Novely = (() => {
31
31
  novely: () => novely
32
32
  });
33
33
 
34
- // src/constants.ts
35
- var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
36
- var BLOCK_EXIT_STATEMENTS = /* @__PURE__ */ new Set(["choice:exit", "condition:exit", "block:exit"]);
37
- var BLOCK_STATEMENTS = /* @__PURE__ */ new Set(["choice", "condition", "block"]);
38
- var AUDIO_ACTIONS = /* @__PURE__ */ new Set([
39
- "playMusic",
40
- "stopMusic",
41
- "playSound",
42
- "stopSound",
43
- "voice",
44
- "stopVoice"
45
- ]);
46
- var EMPTY_SET = /* @__PURE__ */ new Set();
47
- var DEFAULT_TYPEWRITER_SPEED = "Medium";
48
- var HOWLER_SUPPORTED_FILE_FORMATS = /* @__PURE__ */ new Set([
49
- "mp3",
50
- "mpeg",
51
- "opus",
52
- "ogg",
53
- "oga",
54
- "wav",
55
- "aac",
56
- "caf",
57
- "m4a",
58
- "m4b",
59
- "mp4",
60
- "weba",
61
- "webm",
62
- "dolby",
63
- "flac"
64
- ]);
65
- var SUPPORTED_IMAGE_FILE_FORMATS = /* @__PURE__ */ new Set([
66
- "apng",
67
- "avif",
68
- "gif",
69
- "jpg",
70
- "jpeg",
71
- "jfif",
72
- "pjpeg",
73
- "pjp",
74
- "png",
75
- "svg",
76
- "webp",
77
- "bmp"
78
- ]);
79
- var MAIN_CONTEXT_KEY = "$MAIN";
80
-
81
- // src/shared.ts
82
- var STACK_MAP = /* @__PURE__ */ new Map();
83
- var CUSTOM_ACTION_MAP = /* @__PURE__ */ new Map();
84
- var PRELOADED_ASSETS = /* @__PURE__ */ new Set();
85
- var ASSETS_TO_PRELOAD = /* @__PURE__ */ new Set();
34
+ // ../../node_modules/.pnpm/dequal@2.0.3/node_modules/dequal/lite/index.mjs
35
+ var has = Object.prototype.hasOwnProperty;
36
+ function dequal(foo, bar) {
37
+ var ctor, len;
38
+ if (foo === bar) return true;
39
+ if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
40
+ if (ctor === Date) return foo.getTime() === bar.getTime();
41
+ if (ctor === RegExp) return foo.toString() === bar.toString();
42
+ if (ctor === Array) {
43
+ if ((len = foo.length) === bar.length) {
44
+ while (len-- && dequal(foo[len], bar[len])) ;
45
+ }
46
+ return len === -1;
47
+ }
48
+ if (!ctor || typeof foo === "object") {
49
+ len = 0;
50
+ for (ctor in foo) {
51
+ if (has.call(foo, ctor) && ++len && !has.call(bar, ctor)) return false;
52
+ if (!(ctor in bar) || !dequal(foo[ctor], bar[ctor])) return false;
53
+ }
54
+ return Object.keys(bar).length === len;
55
+ }
56
+ }
57
+ return foo !== foo && bar !== bar;
58
+ }
86
59
 
87
- // ../../node_modules/.pnpm/esm-env@1.0.0/node_modules/esm-env/prod-ssr.js
88
- var DEV = false;
60
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/debounce.mjs
61
+ function debounce(func, debounceMs, { signal, edges } = {}) {
62
+ let pendingThis = void 0;
63
+ let pendingArgs = null;
64
+ const leading = edges != null && edges.includes("leading");
65
+ const trailing = edges == null || edges.includes("trailing");
66
+ const invoke = () => {
67
+ if (pendingArgs !== null) {
68
+ func.apply(pendingThis, pendingArgs);
69
+ pendingThis = void 0;
70
+ pendingArgs = null;
71
+ }
72
+ };
73
+ const onTimerEnd = () => {
74
+ if (trailing) {
75
+ invoke();
76
+ }
77
+ cancel();
78
+ };
79
+ let timeoutId = null;
80
+ const schedule = () => {
81
+ if (timeoutId != null) {
82
+ clearTimeout(timeoutId);
83
+ }
84
+ timeoutId = setTimeout(() => {
85
+ timeoutId = null;
86
+ onTimerEnd();
87
+ }, debounceMs);
88
+ };
89
+ const cancelTimer = () => {
90
+ if (timeoutId !== null) {
91
+ clearTimeout(timeoutId);
92
+ timeoutId = null;
93
+ }
94
+ };
95
+ const cancel = () => {
96
+ cancelTimer();
97
+ pendingThis = void 0;
98
+ pendingArgs = null;
99
+ };
100
+ const flush = () => {
101
+ cancelTimer();
102
+ invoke();
103
+ };
104
+ const debounced = function(...args) {
105
+ if (signal?.aborted) {
106
+ return;
107
+ }
108
+ pendingThis = this;
109
+ pendingArgs = args;
110
+ const isFirstCall = timeoutId == null;
111
+ schedule();
112
+ if (leading && isFirstCall) {
113
+ invoke();
114
+ }
115
+ };
116
+ debounced.schedule = schedule;
117
+ debounced.cancel = cancel;
118
+ debounced.flush = flush;
119
+ signal?.addEventListener("abort", cancel, { once: true });
120
+ return debounced;
121
+ }
89
122
 
90
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/once.mjs
123
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/once.mjs
91
124
  function once(func) {
92
125
  let called = false;
93
126
  let cache;
@@ -102,20 +135,28 @@ var Novely = (() => {
102
135
  };
103
136
  }
104
137
 
105
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/throttle.mjs
106
- function throttle(func, throttleMs) {
107
- let lastCallTime;
108
- const throttledFunction = function(...args) {
109
- const now = Date.now();
110
- if (lastCallTime == null || now - lastCallTime >= throttleMs) {
111
- lastCallTime = now;
112
- func(...args);
138
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/throttle.mjs
139
+ function throttle(func, throttleMs, { signal, edges = ["leading", "trailing"] } = {}) {
140
+ let pendingAt = null;
141
+ const debounced = debounce(func, throttleMs, { signal, edges });
142
+ const throttled = function(...args) {
143
+ if (pendingAt == null) {
144
+ pendingAt = Date.now();
145
+ } else {
146
+ if (Date.now() - pendingAt >= throttleMs) {
147
+ pendingAt = Date.now();
148
+ debounced.cancel();
149
+ debounced(...args);
150
+ }
113
151
  }
152
+ debounced(...args);
114
153
  };
115
- return throttledFunction;
154
+ throttled.cancel = debounced.cancel;
155
+ throttled.flush = debounced.flush;
156
+ return throttled;
116
157
  }
117
158
 
118
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/function/memoize.mjs
159
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/function/memoize.mjs
119
160
  function memoize(fn, options = {}) {
120
161
  const { cache = /* @__PURE__ */ new Map(), getCacheKey } = options;
121
162
  const memoizedFn = function(arg) {
@@ -131,156 +172,275 @@ var Novely = (() => {
131
172
  return memoizedFn;
132
173
  }
133
174
 
134
- // src/audio-codecs.ts
135
- var cut = (str2) => str2.replace(/^no$/, "");
136
- var audio = new Audio();
137
- var canPlay = (type) => !!cut(audio.canPlayType(type));
138
- var canPlayMultiple = (...types) => types.some((type) => canPlay(type));
139
- var supportsMap = {
140
- mp3: canPlayMultiple("audio/mpeg;", "audio/mp3;"),
141
- mpeg: canPlay("audio/mpeg;"),
142
- opus: canPlay('audio/ogg; codecs="opus"'),
143
- ogg: canPlay('audio/ogg; codecs="vorbis"'),
144
- oga: canPlay('audio/ogg; codecs="vorbis"'),
145
- wav: canPlayMultiple('audio/wav; codecs="1"', "audio/wav;"),
146
- aac: canPlay("audio/aac;"),
147
- caf: canPlay("audio/x-caf;"),
148
- m4a: canPlayMultiple("audio/x-m4a;", "audio/m4a;", "audio/aac;"),
149
- m4b: canPlayMultiple("audio/x-m4b;", "audio/m4b;", "audio/aac;"),
150
- mp4: canPlayMultiple("audio/x-mp4;", "audio/mp4;", "audio/aac;"),
151
- weba: canPlay('audio/webm; codecs="vorbis"'),
152
- webm: canPlay('audio/webm; codecs="vorbis"'),
153
- dolby: canPlay('audio/mp4; codecs="ec-3"'),
154
- flac: canPlayMultiple("audio/x-flac;", "audio/flac;")
155
- };
175
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/predicate/isPlainObject.mjs
176
+ function isPlainObject(value) {
177
+ if (typeof value !== "object") {
178
+ return false;
179
+ }
180
+ if (value == null) {
181
+ return false;
182
+ }
183
+ if (Object.getPrototypeOf(value) === null) {
184
+ return true;
185
+ }
186
+ if (value.toString() !== "[object Object]") {
187
+ return false;
188
+ }
189
+ let proto = value;
190
+ while (Object.getPrototypeOf(proto) !== null) {
191
+ proto = Object.getPrototypeOf(proto);
192
+ }
193
+ return Object.getPrototypeOf(value) === proto;
194
+ }
156
195
 
157
- // src/image-formats.ts
158
- var avif = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
159
- var jxl = "data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgAAFSqjjBu8nOv58kOHxbSN6wxttW1hSaLIODZJJ3BIEkkaoCUzGM6qJAE=";
160
- var webp = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
161
- var supportsFormat = (source) => {
162
- const { promise, resolve } = Promise.withResolvers();
163
- const img = Object.assign(document.createElement("img"), {
164
- src: source
165
- });
166
- img.onload = img.onerror = () => {
167
- resolve(img.height === 2);
168
- };
169
- return promise;
170
- };
171
- var supportsMap2 = {
172
- avif: false,
173
- jxl: false,
174
- webp: false
175
- };
176
- var formatsMap = {
177
- avif,
178
- jxl,
179
- webp
180
- };
181
- var loadImageFormatsSupport = async () => {
182
- const promises = [];
183
- for (const [format, source] of Object.entries(formatsMap)) {
184
- const promise = supportsFormat(source).then((supported) => {
185
- supportsMap2[format] = supported;
186
- });
187
- promises.push(promise);
196
+ // ../../node_modules/.pnpm/es-toolkit@1.23.0/node_modules/es-toolkit/dist/object/merge.mjs
197
+ function merge(target, source) {
198
+ const sourceKeys = Object.keys(source);
199
+ for (let i = 0; i < sourceKeys.length; i++) {
200
+ const key = sourceKeys[i];
201
+ const sourceValue = source[key];
202
+ const targetValue = target[key];
203
+ if (Array.isArray(sourceValue)) {
204
+ if (Array.isArray(targetValue)) {
205
+ target[key] = merge(targetValue, sourceValue);
206
+ } else {
207
+ target[key] = merge([], sourceValue);
208
+ }
209
+ } else if (isPlainObject(sourceValue)) {
210
+ if (isPlainObject(targetValue)) {
211
+ target[key] = merge(targetValue, sourceValue);
212
+ } else {
213
+ target[key] = merge({}, sourceValue);
214
+ }
215
+ } else if (targetValue === void 0 || sourceValue !== void 0) {
216
+ target[key] = sourceValue;
217
+ }
188
218
  }
189
- await Promise.all(promises);
190
- };
191
- loadImageFormatsSupport();
219
+ return target;
220
+ }
192
221
 
193
- // src/asset.ts
194
- var getType = memoize(
195
- (extensions) => {
196
- if (extensions.every((extension) => HOWLER_SUPPORTED_FILE_FORMATS.has(extension))) {
197
- return "audio";
222
+ // ../../node_modules/.pnpm/esm-env@1.0.0/node_modules/esm-env/prod-ssr.js
223
+ var DEV = false;
224
+
225
+ // ../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/full/index.mjs
226
+ function set(obj, key, val) {
227
+ if (typeof val.value === "object") val.value = klona(val.value);
228
+ if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === "__proto__") {
229
+ Object.defineProperty(obj, key, val);
230
+ } else obj[key] = val.value;
231
+ }
232
+ function klona(x) {
233
+ if (typeof x !== "object") return x;
234
+ var i = 0, k, list, tmp, str = Object.prototype.toString.call(x);
235
+ if (str === "[object Object]") {
236
+ tmp = Object.create(x.__proto__ || null);
237
+ } else if (str === "[object Array]") {
238
+ tmp = Array(x.length);
239
+ } else if (str === "[object Set]") {
240
+ tmp = /* @__PURE__ */ new Set();
241
+ x.forEach(function(val) {
242
+ tmp.add(klona(val));
243
+ });
244
+ } else if (str === "[object Map]") {
245
+ tmp = /* @__PURE__ */ new Map();
246
+ x.forEach(function(val, key) {
247
+ tmp.set(klona(key), klona(val));
248
+ });
249
+ } else if (str === "[object Date]") {
250
+ tmp = /* @__PURE__ */ new Date(+x);
251
+ } else if (str === "[object RegExp]") {
252
+ tmp = new RegExp(x.source, x.flags);
253
+ } else if (str === "[object DataView]") {
254
+ tmp = new x.constructor(klona(x.buffer));
255
+ } else if (str === "[object ArrayBuffer]") {
256
+ tmp = x.slice(0);
257
+ } else if (str.slice(-6) === "Array]") {
258
+ tmp = new x.constructor(x);
259
+ }
260
+ if (tmp) {
261
+ for (list = Object.getOwnPropertySymbols(x); i < list.length; i++) {
262
+ set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
198
263
  }
199
- if (extensions.every((extension) => SUPPORTED_IMAGE_FILE_FORMATS.has(extension))) {
200
- return "image";
264
+ for (i = 0, list = Object.getOwnPropertyNames(x); i < list.length; i++) {
265
+ if (Object.hasOwnProperty.call(tmp, k = list[i]) && tmp[k] === x[k]) continue;
266
+ set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
201
267
  }
202
- throw extensions;
203
- },
204
- {
205
- getCacheKey: (extensions) => extensions.join("~")
206
268
  }
207
- );
208
- var SUPPORT_MAPS = {
209
- "image": supportsMap2,
210
- "audio": supportsMap
269
+ return tmp || x;
270
+ }
271
+
272
+ // ../../node_modules/.pnpm/yocto-queue@1.1.1/node_modules/yocto-queue/index.js
273
+ var Node = class {
274
+ value;
275
+ next;
276
+ constructor(value) {
277
+ this.value = value;
278
+ }
211
279
  };
212
- var assetPrivate = memoize(
213
- (variants) => {
214
- if (DEV && variants.length === 0) {
215
- throw new Error(`Attempt to use "asset" function without arguments`);
280
+ var Queue = class {
281
+ #head;
282
+ #tail;
283
+ #size;
284
+ constructor() {
285
+ this.clear();
286
+ }
287
+ enqueue(value) {
288
+ const node = new Node(value);
289
+ if (this.#head) {
290
+ this.#tail.next = node;
291
+ this.#tail = node;
292
+ } else {
293
+ this.#head = node;
294
+ this.#tail = node;
216
295
  }
217
- const map = {};
218
- const extensions = [];
219
- for (const v of variants) {
220
- const e = getUrlFileExtension(v);
221
- map[e] = v;
222
- extensions.push(e);
296
+ this.#size++;
297
+ }
298
+ dequeue() {
299
+ const current = this.#head;
300
+ if (!current) {
301
+ return;
302
+ }
303
+ this.#head = this.#head.next;
304
+ this.#size--;
305
+ return current.value;
306
+ }
307
+ peek() {
308
+ if (!this.#head) {
309
+ return;
310
+ }
311
+ return this.#head.value;
312
+ }
313
+ clear() {
314
+ this.#head = void 0;
315
+ this.#tail = void 0;
316
+ this.#size = 0;
317
+ }
318
+ get size() {
319
+ return this.#size;
320
+ }
321
+ *[Symbol.iterator]() {
322
+ let current = this.#head;
323
+ while (current) {
324
+ yield current.value;
325
+ current = current.next;
223
326
  }
224
- const type = getType(extensions);
225
- const getSource = once(() => {
226
- const support = SUPPORT_MAPS[type];
227
- for (const extension of extensions) {
228
- if (extension in support) {
229
- if (support[extension]) {
230
- return map[extension];
231
- }
232
- } else {
233
- return map[extension];
234
- }
235
- }
236
- if (DEV) {
237
- throw new Error(`No matching asset was found for ${variants.map((v) => `"${v}"`).join(", ")}`);
238
- }
239
- return "";
240
- });
241
- return {
242
- get source() {
243
- return getSource();
244
- },
245
- get type() {
246
- return type;
247
- }
248
- };
249
- },
250
- {
251
- getCacheKey: (variants) => variants.join("~")
252
327
  }
253
- );
254
- var asset = (...variants) => {
255
- return assetPrivate(variants);
256
- };
257
- var isAsset = (suspect) => {
258
- return suspect !== null && typeof suspect === "object" && "source" in suspect && "type" in suspect;
259
328
  };
260
329
 
261
- // src/utils.ts
262
- var matchAction = ({ getContext, onBeforeActionCall, push, forward }, values) => {
263
- return (action, props, { ctx, data }) => {
264
- const context = typeof ctx === "string" ? getContext(ctx) : ctx;
265
- onBeforeActionCall({
266
- action,
267
- props,
268
- ctx: context
269
- });
270
- return values[action]({
271
- ctx: context,
272
- data,
273
- push() {
274
- if (context.meta.preview) return;
275
- push(context);
276
- },
277
- forward() {
278
- if (context.meta.preview) return;
279
- forward(context);
330
+ // ../../node_modules/.pnpm/p-limit@6.1.0/node_modules/p-limit/index.js
331
+ function pLimit(concurrency) {
332
+ validateConcurrency(concurrency);
333
+ const queue = new Queue();
334
+ let activeCount = 0;
335
+ const resumeNext = () => {
336
+ if (activeCount < concurrency && queue.size > 0) {
337
+ queue.dequeue()();
338
+ activeCount++;
339
+ }
340
+ };
341
+ const next = () => {
342
+ activeCount--;
343
+ resumeNext();
344
+ };
345
+ const run = async (function_, resolve, arguments_) => {
346
+ const result = (async () => function_(...arguments_))();
347
+ resolve(result);
348
+ try {
349
+ await result;
350
+ } catch {
351
+ }
352
+ next();
353
+ };
354
+ const enqueue = (function_, resolve, arguments_) => {
355
+ new Promise((internalResolve) => {
356
+ queue.enqueue(internalResolve);
357
+ }).then(
358
+ run.bind(void 0, function_, resolve, arguments_)
359
+ );
360
+ (async () => {
361
+ await Promise.resolve();
362
+ if (activeCount < concurrency) {
363
+ resumeNext();
280
364
  }
281
- }, props);
365
+ })();
282
366
  };
283
- };
367
+ const generator = (function_, ...arguments_) => new Promise((resolve) => {
368
+ enqueue(function_, resolve, arguments_);
369
+ });
370
+ Object.defineProperties(generator, {
371
+ activeCount: {
372
+ get: () => activeCount
373
+ },
374
+ pendingCount: {
375
+ get: () => queue.size
376
+ },
377
+ clearQueue: {
378
+ value() {
379
+ queue.clear();
380
+ }
381
+ },
382
+ concurrency: {
383
+ get: () => concurrency,
384
+ set(newConcurrency) {
385
+ validateConcurrency(newConcurrency);
386
+ concurrency = newConcurrency;
387
+ queueMicrotask(() => {
388
+ while (activeCount < concurrency && queue.size > 0) {
389
+ resumeNext();
390
+ }
391
+ });
392
+ }
393
+ }
394
+ });
395
+ return generator;
396
+ }
397
+ function validateConcurrency(concurrency) {
398
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
399
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
400
+ }
401
+ }
402
+
403
+ // src/constants.ts
404
+ var SKIPPED_DURING_RESTORE = /* @__PURE__ */ new Set(["dialog", "choice", "input", "vibrate", "text"]);
405
+ var BLOCK_EXIT_STATEMENTS = /* @__PURE__ */ new Set(["choice:exit", "condition:exit", "block:exit"]);
406
+ var BLOCK_STATEMENTS = /* @__PURE__ */ new Set(["choice", "condition", "block"]);
407
+ var AUDIO_ACTIONS = /* @__PURE__ */ new Set(["playMusic", "stopMusic", "playSound", "stopSound", "voice", "stopVoice"]);
408
+ var EMPTY_SET = /* @__PURE__ */ new Set();
409
+ var DEFAULT_TYPEWRITER_SPEED = "Medium";
410
+ var HOWLER_SUPPORTED_FILE_FORMATS = /* @__PURE__ */ new Set([
411
+ "mp3",
412
+ "mpeg",
413
+ "opus",
414
+ "ogg",
415
+ "oga",
416
+ "wav",
417
+ "aac",
418
+ "caf",
419
+ "m4a",
420
+ "m4b",
421
+ "mp4",
422
+ "weba",
423
+ "webm",
424
+ "dolby",
425
+ "flac"
426
+ ]);
427
+ var SUPPORTED_IMAGE_FILE_FORMATS = /* @__PURE__ */ new Set([
428
+ "apng",
429
+ "avif",
430
+ "gif",
431
+ "jpg",
432
+ "jpeg",
433
+ "jfif",
434
+ "pjpeg",
435
+ "pjp",
436
+ "png",
437
+ "svg",
438
+ "webp",
439
+ "bmp"
440
+ ]);
441
+ var MAIN_CONTEXT_KEY = "$MAIN";
442
+
443
+ // src/utilities/assertions.ts
284
444
  var isNumber = (val) => {
285
445
  return typeof val === "number";
286
446
  };
@@ -299,54 +459,13 @@ var Novely = (() => {
299
459
  var isEmpty = (val) => {
300
460
  return typeof val === "object" && !isNull(val) && Object.keys(val).length === 0;
301
461
  };
302
- var isCSSImage = (str2) => {
303
- const startsWith = String.prototype.startsWith.bind(str2);
462
+ var isCSSImageURL = (url) => {
463
+ const startsWith = String.prototype.startsWith.bind(url);
304
464
  return startsWith("http") || startsWith("/") || startsWith(".") || startsWith("data");
305
465
  };
306
- var str = String;
307
466
  var isUserRequiredAction = ([action, ...meta]) => {
308
467
  return Boolean(action === "custom" && meta[0] && meta[0].requireUserAction);
309
468
  };
310
- var getLanguage = (languages) => {
311
- let { language } = navigator;
312
- if (languages.includes(language)) {
313
- return language;
314
- } else if (languages.includes(language = language.slice(0, 2))) {
315
- return language;
316
- } else if (language = languages.find((value) => navigator.languages.includes(value))) {
317
- return language;
318
- }
319
- return languages[0];
320
- };
321
- var createControlledPromise = () => {
322
- const object = {
323
- resolve: null,
324
- reject: null,
325
- promise: null,
326
- cancel: null
327
- };
328
- const init = () => {
329
- const promise = new Promise((resolve, reject) => {
330
- object.reject = reject;
331
- object.resolve = (value) => {
332
- resolve({ cancelled: false, value });
333
- };
334
- object.cancel = () => {
335
- resolve({ cancelled: true, value: null });
336
- init();
337
- };
338
- });
339
- object.promise = promise;
340
- };
341
- return init(), object;
342
- };
343
- var findLastPathItemBeforeItemOfType = (path, name) => {
344
- const item = path.findLast(([_name, _value], i, array) => {
345
- const next = array[i + 1];
346
- return isNull(_name) && isNumber(_value) && next != null && next[0] === name;
347
- });
348
- return item;
349
- };
350
469
  var isBlockStatement = (statement) => {
351
470
  return BLOCK_STATEMENTS.has(statement);
352
471
  };
@@ -359,49 +478,290 @@ var Novely = (() => {
359
478
  var isAudioAction = (action) => {
360
479
  return AUDIO_ACTIONS.has(action);
361
480
  };
362
- var noop = () => {
363
- };
364
481
  var isAction = (element) => {
365
482
  return Array.isArray(element) && isString(element[0]);
366
483
  };
367
- var flatActions = (item) => {
368
- return item.flatMap((data) => {
369
- const type = data[0];
370
- if (Array.isArray(type)) return flatActions(data);
371
- return [data];
372
- });
484
+ var isImageAsset = (asset2) => {
485
+ return isString(asset2) && isCSSImageURL(asset2);
373
486
  };
374
- var flattenStory = (story) => {
375
- const entries = Object.entries(story).map(([name, items]) => {
376
- return [name, flatActions(items)];
377
- });
378
- return Object.fromEntries(entries);
487
+ var isBlockingAction = (action) => {
488
+ return isUserRequiredAction(action) || isSkippedDuringRestore(action[0]) && action[0] !== "vibrate";
379
489
  };
380
- var isExitImpossible = (path) => {
381
- const blockStatements = path.filter(([item]) => isBlockStatement(item));
382
- const blockExitStatements = path.filter(([item]) => isBlockExitStatement(item));
383
- if (blockStatements.length === 0 && blockExitStatements.length === 0) {
384
- return true;
385
- }
386
- if (blockStatements.length > blockExitStatements.length) {
387
- return false;
388
- }
389
- return !blockExitStatements.every(([name], i) => name && name.startsWith(blockStatements[i][0]));
490
+ var isAsset = (suspect) => {
491
+ return suspect !== null && typeof suspect === "object" && "source" in suspect && "type" in suspect;
390
492
  };
391
- var getOppositeAction = (action) => {
392
- const MAP = {
393
- "showCharacter": "hideCharacter",
394
- "playSound": "stopSound",
395
- "playMusic": "stopMusic",
396
- "voice": "stopVoice"
493
+
494
+ // src/utilities/match-action.ts
495
+ var matchAction = (callbacks, values) => {
496
+ const { getContext, onBeforeActionCall, push, forward } = callbacks;
497
+ return (action, props, { ctx, data }) => {
498
+ const context = typeof ctx === "string" ? getContext(ctx) : ctx;
499
+ onBeforeActionCall({
500
+ action,
501
+ props,
502
+ ctx: context
503
+ });
504
+ return values[action](
505
+ {
506
+ ctx: context,
507
+ data,
508
+ push() {
509
+ if (context.meta.preview) return;
510
+ push(context);
511
+ },
512
+ forward() {
513
+ if (context.meta.preview) return;
514
+ forward(context);
515
+ }
516
+ },
517
+ props
518
+ );
397
519
  };
398
- return MAP[action];
399
520
  };
400
- var getActionsFromPath = (story, path, filter) => {
401
- let current = story;
402
- let precurrent;
403
- let ignoreNestedBefore = null;
404
- let index = 0;
521
+
522
+ // src/utilities/ungrupped.ts
523
+ var getLanguage = (languages) => {
524
+ let { language } = navigator;
525
+ if (languages.includes(language)) {
526
+ return language;
527
+ } else if (languages.includes(language = language.slice(0, 2))) {
528
+ return language;
529
+ } else if (language = languages.find((value) => navigator.languages.includes(value))) {
530
+ return language;
531
+ }
532
+ return languages[0];
533
+ };
534
+ var noop = () => {
535
+ };
536
+ var mapSet = (set2, fn) => {
537
+ return [...set2].map(fn);
538
+ };
539
+ var capitalize = (str) => {
540
+ return str[0].toUpperCase() + str.slice(1);
541
+ };
542
+ var getIntlLanguageDisplayName = memoize((lang) => {
543
+ try {
544
+ const intl = new Intl.DisplayNames([lang], {
545
+ type: "language"
546
+ });
547
+ return intl.of(lang) || lang;
548
+ } catch {
549
+ return lang;
550
+ }
551
+ });
552
+ var unwrapAsset = (asset2) => {
553
+ return isAsset(asset2) ? asset2.source : asset2;
554
+ };
555
+ var handleAudioAsset = (asset2) => {
556
+ if (DEV && isAsset(asset2) && asset2.type !== "audio") {
557
+ throw new Error("Attempt to use non-audio asset in audio action", { cause: asset2 });
558
+ }
559
+ return unwrapAsset(asset2);
560
+ };
561
+ var handleImageAsset = (asset2) => {
562
+ if (DEV && isAsset(asset2) && asset2.type !== "image") {
563
+ throw new Error("Attempt to use non-image asset in action that requires image assets", { cause: asset2 });
564
+ }
565
+ return unwrapAsset(asset2);
566
+ };
567
+ var getCharactersData = (characters) => {
568
+ const entries = Object.entries(characters);
569
+ const mapped = entries.map(([key, value]) => [key, { name: value.name, emotions: Object.keys(value.emotions) }]);
570
+ return Object.fromEntries(mapped);
571
+ };
572
+ var toArray = (target) => {
573
+ return Array.isArray(target) ? target : [target];
574
+ };
575
+ var getLanguageFromStore = (store2) => {
576
+ return store2.get().meta[0];
577
+ };
578
+ var getVolumeFromStore = (store2) => {
579
+ const { meta } = store2.get();
580
+ return {
581
+ music: meta[2],
582
+ sound: meta[3],
583
+ voice: meta[4]
584
+ };
585
+ };
586
+
587
+ // src/utilities/actions-processing.ts
588
+ var isExitImpossible = (path) => {
589
+ const blockStatements = path.filter(([item]) => isBlockStatement(item));
590
+ const blockExitStatements = path.filter(([item]) => isBlockExitStatement(item));
591
+ if (blockStatements.length === 0 && blockExitStatements.length === 0) {
592
+ return true;
593
+ }
594
+ if (blockStatements.length > blockExitStatements.length) {
595
+ return false;
596
+ }
597
+ return !blockExitStatements.every(([name], i) => name && name.startsWith(blockStatements[i][0]));
598
+ };
599
+ var createReferFunction = (story) => {
600
+ const refer = (path) => {
601
+ let current = story;
602
+ let precurrent = story;
603
+ const blocks = [];
604
+ for (const [type, val] of path) {
605
+ if (type === "jump") {
606
+ precurrent = story;
607
+ current = current[val];
608
+ } else if (type === null) {
609
+ precurrent = current;
610
+ current = current[val];
611
+ } else if (type === "choice") {
612
+ blocks.push(precurrent);
613
+ current = current[val + 1][1];
614
+ } else if (type === "condition") {
615
+ blocks.push(precurrent);
616
+ current = current[2][val];
617
+ } else if (type === "block") {
618
+ blocks.push(precurrent);
619
+ current = story[val];
620
+ } else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
621
+ current = blocks.pop();
622
+ }
623
+ }
624
+ return current;
625
+ };
626
+ return refer;
627
+ };
628
+ var exitPath = ({ path, refer, onExitImpossible }) => {
629
+ const last = path.at(-1);
630
+ const ignore = [];
631
+ let wasExitImpossible = false;
632
+ if (!isAction(refer(path))) {
633
+ if (last && isNull(last[0]) && isNumber(last[1])) {
634
+ last[1]--;
635
+ } else {
636
+ path.pop();
637
+ }
638
+ }
639
+ if (isExitImpossible(path)) {
640
+ const referred = refer(path);
641
+ if (isAction(referred) && isSkippedDuringRestore(referred[0])) {
642
+ onExitImpossible?.();
643
+ }
644
+ wasExitImpossible = true;
645
+ return {
646
+ exitImpossible: wasExitImpossible
647
+ };
648
+ }
649
+ for (let i = path.length - 1; i > 0; i--) {
650
+ const [name] = path[i];
651
+ if (isBlockExitStatement(name)) {
652
+ ignore.push(name);
653
+ }
654
+ if (!isBlockStatement(name)) continue;
655
+ if (ignore.at(-1)?.startsWith(name)) {
656
+ ignore.pop();
657
+ continue;
658
+ }
659
+ path.push([`${name}:exit`]);
660
+ const prev = findLastPathItemBeforeItemOfType(path.slice(0, i + 1), name);
661
+ if (prev) path.push([null, prev[1] + 1]);
662
+ if (!isAction(refer(path))) {
663
+ path.pop();
664
+ continue;
665
+ }
666
+ break;
667
+ }
668
+ return {
669
+ exitImpossible: wasExitImpossible
670
+ };
671
+ };
672
+ var nextPath = (path) => {
673
+ const last = path.at(-1);
674
+ if (last && (isNull(last[0]) || last[0] === "jump") && isNumber(last[1])) {
675
+ last[1]++;
676
+ } else {
677
+ path.push([null, 0]);
678
+ }
679
+ return path;
680
+ };
681
+ var collectActionsBeforeBlockingAction = ({ path, refer, clone }) => {
682
+ const collection = [];
683
+ let action = refer(path);
684
+ while (true) {
685
+ if (action == void 0) {
686
+ const { exitImpossible } = exitPath({
687
+ path,
688
+ refer
689
+ });
690
+ if (exitImpossible) {
691
+ break;
692
+ }
693
+ }
694
+ if (!action) {
695
+ break;
696
+ }
697
+ if (isBlockingAction(action)) {
698
+ const [name, ...props] = action;
699
+ if (name === "choice") {
700
+ const choiceProps = props;
701
+ for (let i = 0; i < choiceProps.length; i++) {
702
+ const branchContent = choiceProps[i];
703
+ if (!Array.isArray(branchContent)) continue;
704
+ const virtualPath = clone(path);
705
+ virtualPath.push(["choice", i], [null, 0]);
706
+ const innerActions = collectActionsBeforeBlockingAction({
707
+ path: virtualPath,
708
+ refer,
709
+ clone
710
+ });
711
+ collection.push(...innerActions);
712
+ }
713
+ } else if (name === "condition") {
714
+ const conditionProps = props;
715
+ const conditions = Object.keys(conditionProps[1]);
716
+ for (const condition of conditions) {
717
+ const virtualPath = clone(path);
718
+ virtualPath.push(["condition", condition], [null, 0]);
719
+ const innerActions = collectActionsBeforeBlockingAction({
720
+ path: virtualPath,
721
+ refer,
722
+ clone
723
+ });
724
+ collection.push(...innerActions);
725
+ }
726
+ }
727
+ break;
728
+ }
729
+ collection.push(action);
730
+ if (action[0] === "jump") {
731
+ path = [
732
+ ["jump", action[1]],
733
+ [null, 0]
734
+ ];
735
+ } else if (action[0] == "block") {
736
+ path.push(["block", action[1]], [null, 0]);
737
+ } else {
738
+ nextPath(path);
739
+ }
740
+ action = refer(path);
741
+ }
742
+ return collection;
743
+ };
744
+ var findLastPathItemBeforeItemOfType = (path, name) => {
745
+ const item = path.findLast(([_name, _value], i, array) => {
746
+ const next = array[i + 1];
747
+ return isNull(_name) && isNumber(_value) && next != null && next[0] === name;
748
+ });
749
+ return item;
750
+ };
751
+ var getOppositeAction = (action) => {
752
+ const MAP = {
753
+ showCharacter: "hideCharacter",
754
+ playSound: "stopSound",
755
+ playMusic: "stopMusic",
756
+ voice: "stopVoice"
757
+ };
758
+ return MAP[action];
759
+ };
760
+ var getActionsFromPath = (story, path, filter) => {
761
+ let current = story;
762
+ let precurrent;
763
+ let ignoreNestedBefore = null;
764
+ let index = 0;
405
765
  let skipPreserve = void 0;
406
766
  const skip = /* @__PURE__ */ new Set();
407
767
  const max = path.reduce((acc, [type, val]) => {
@@ -493,7 +853,7 @@ var Novely = (() => {
493
853
  const c1 = fn;
494
854
  const isIdenticalID = Boolean(c0.id && c1.id && c0.id === c1.id);
495
855
  const isIdenticalByReference = c0 === c1;
496
- return isIdenticalID || isIdenticalByReference || str(c0) === str(c1);
856
+ return isIdenticalID || isIdenticalByReference || String(c0) === String(c1);
497
857
  });
498
858
  if (notLatest) continue;
499
859
  } else if ("skipOnRestore" in fn && fn.skipOnRestore) {
@@ -560,53 +920,32 @@ var Novely = (() => {
560
920
  }
561
921
  };
562
922
  };
563
- var getStack = memoize(
564
- (_) => {
565
- return [];
566
- },
567
- {
568
- cache: STACK_MAP,
569
- getCacheKey: (ctx) => ctx.id
570
- }
571
- );
572
- var createUseStackFunction = (renderer) => {
573
- const useStack = (context) => {
574
- const ctx = typeof context === "string" ? renderer.getContext(context) : context;
575
- const stack = getStack(ctx);
576
- return {
577
- get previous() {
578
- return stack.previous;
579
- },
580
- get value() {
581
- return stack.at(-1);
582
- },
583
- set value(value) {
584
- stack[stack.length - 1] = value;
585
- },
586
- back() {
587
- if (stack.length > 1) {
588
- stack.previous = stack.pop();
589
- ctx.meta.goingBack = true;
590
- }
591
- },
592
- push(value) {
593
- stack.push(value);
594
- },
595
- clear() {
596
- stack.previous = void 0;
597
- stack.length = 0;
598
- stack.length = 1;
599
- }
600
- };
923
+
924
+ // src/utilities/controlled-promise.ts
925
+ var createControlledPromise = () => {
926
+ const object = {
927
+ resolve: null,
928
+ reject: null,
929
+ promise: null,
930
+ cancel: null
601
931
  };
602
- return useStack;
603
- };
604
- var mapSet = (set2, fn) => {
605
- return [...set2].map(fn);
606
- };
607
- var isImageAsset = (asset2) => {
608
- return isString(asset2) && isCSSImage(asset2);
932
+ const init = () => {
933
+ const promise = new Promise((resolve, reject) => {
934
+ object.reject = reject;
935
+ object.resolve = (value) => {
936
+ resolve({ cancelled: false, value });
937
+ };
938
+ object.cancel = () => {
939
+ resolve({ cancelled: true, value: null });
940
+ init();
941
+ };
942
+ });
943
+ object.promise = promise;
944
+ };
945
+ return init(), object;
609
946
  };
947
+
948
+ // src/utilities/resources.ts
610
949
  var getUrlFileExtension = (address) => {
611
950
  try {
612
951
  const { pathname } = new URL(address, location.href);
@@ -633,7 +972,7 @@ var Novely = (() => {
633
972
  };
634
973
  var getResourseType = memoize(
635
974
  async ({ url, request }) => {
636
- if (!isCSSImage(url)) {
975
+ if (!isCSSImageURL(url)) {
637
976
  return "other";
638
977
  }
639
978
  const extension = getUrlFileExtension(url);
@@ -656,357 +995,85 @@ var Novely = (() => {
656
995
  getCacheKey: ({ url }) => url
657
996
  }
658
997
  );
659
- var capitalize = (str2) => {
660
- return str2[0].toUpperCase() + str2.slice(1);
661
- };
662
- var getIntlLanguageDisplayName = memoize((lang) => {
663
- try {
664
- const intl = new Intl.DisplayNames([lang], {
665
- type: "language"
666
- });
667
- return intl.of(lang) || lang;
668
- } catch {
669
- return lang;
670
- }
671
- });
672
- var createReferFunction = (story) => {
673
- const refer = (path) => {
674
- let current = story;
675
- let precurrent = story;
676
- const blocks = [];
677
- for (const [type, val] of path) {
678
- if (type === "jump") {
679
- precurrent = story;
680
- current = current[val];
681
- } else if (type === null) {
682
- precurrent = current;
683
- current = current[val];
684
- } else if (type === "choice") {
685
- blocks.push(precurrent);
686
- current = current[val + 1][1];
687
- } else if (type === "condition") {
688
- blocks.push(precurrent);
689
- current = current[2][val];
690
- } else if (type === "block") {
691
- blocks.push(precurrent);
692
- current = story[val];
693
- } else if (type === "block:exit" || type === "choice:exit" || type === "condition:exit") {
694
- current = blocks.pop();
695
- }
696
- }
697
- return current;
698
- };
699
- return refer;
700
- };
701
- var exitPath = ({ path, refer, onExitImpossible }) => {
702
- const last = path.at(-1);
703
- const ignore = [];
704
- let wasExitImpossible = false;
705
- if (!isAction(refer(path))) {
706
- if (last && isNull(last[0]) && isNumber(last[1])) {
707
- last[1]--;
708
- } else {
709
- path.pop();
710
- }
711
- }
712
- if (isExitImpossible(path)) {
713
- const referred = refer(path);
714
- if (isAction(referred) && isSkippedDuringRestore(referred[0])) {
715
- onExitImpossible?.();
716
- }
717
- wasExitImpossible = true;
718
- return {
719
- exitImpossible: wasExitImpossible
720
- };
721
- }
722
- for (let i = path.length - 1; i > 0; i--) {
723
- const [name] = path[i];
724
- if (isBlockExitStatement(name)) {
725
- ignore.push(name);
726
- }
727
- if (!isBlockStatement(name)) continue;
728
- if (ignore.at(-1)?.startsWith(name)) {
729
- ignore.pop();
730
- continue;
731
- }
732
- path.push([`${name}:exit`]);
733
- const prev = findLastPathItemBeforeItemOfType(path.slice(0, i + 1), name);
734
- if (prev) path.push([null, prev[1] + 1]);
735
- if (!isAction(refer(path))) {
736
- path.pop();
737
- continue;
738
- }
739
- break;
740
- }
741
- return {
742
- exitImpossible: wasExitImpossible
743
- };
744
- };
745
- var nextPath = (path) => {
746
- const last = path.at(-1);
747
- if (last && (isNull(last[0]) || last[0] === "jump") && isNumber(last[1])) {
748
- last[1]++;
749
- } else {
750
- path.push([null, 0]);
751
- }
752
- return path;
753
- };
754
- var isBlockingAction = (action) => {
755
- return isUserRequiredAction(action) || isSkippedDuringRestore(action[0]) && action[0] !== "vibrate";
756
- };
757
- var collectActionsBeforeBlockingAction = ({ path, refer, clone }) => {
758
- const collection = [];
759
- let action = refer(path);
760
- while (true) {
761
- if (action == void 0) {
762
- const { exitImpossible } = exitPath({
763
- path,
764
- refer
765
- });
766
- if (exitImpossible) {
767
- break;
768
- }
769
- }
770
- if (!action) {
771
- break;
772
- }
773
- if (isBlockingAction(action)) {
774
- const [name, ...props] = action;
775
- if (name === "choice") {
776
- const choiceProps = props;
777
- for (let i = 0; i < choiceProps.length; i++) {
778
- const branchContent = choiceProps[i];
779
- if (!Array.isArray(branchContent)) continue;
780
- const virtualPath = clone(path);
781
- virtualPath.push(["choice", i], [null, 0]);
782
- const innerActions = collectActionsBeforeBlockingAction({
783
- path: virtualPath,
784
- refer,
785
- clone
786
- });
787
- collection.push(...innerActions);
788
- }
789
- } else if (name === "condition") {
790
- const conditionProps = props;
791
- const conditions = Object.keys(conditionProps[1]);
792
- for (const condition of conditions) {
793
- const virtualPath = clone(path);
794
- virtualPath.push(["condition", condition], [null, 0]);
795
- const innerActions = collectActionsBeforeBlockingAction({
796
- path: virtualPath,
797
- refer,
798
- clone
799
- });
800
- collection.push(...innerActions);
801
- }
802
- }
803
- break;
804
- }
805
- collection.push(action);
806
- if (action[0] === "jump") {
807
- path = [["jump", action[1]], [null, 0]];
808
- } else if (action[0] == "block") {
809
- path.push(["block", action[1]], [null, 0]);
810
- } else {
811
- nextPath(path);
812
- }
813
- action = refer(path);
814
- }
815
- return collection;
816
- };
817
- var unwrapAsset = (asset2) => {
818
- return isAsset(asset2) ? asset2.source : asset2;
819
- };
820
- var handleAudioAsset = (asset2) => {
821
- if (DEV && isAsset(asset2) && asset2.type !== "audio") {
822
- throw new Error("Attempt to use non-audio asset in audio action", { cause: asset2 });
823
- }
824
- return unwrapAsset(asset2);
825
- };
826
- var handleImageAsset = (asset2) => {
827
- if (DEV && isAsset(asset2) && asset2.type !== "image") {
828
- throw new Error("Attempt to use non-image asset in action that requires image assets", { cause: asset2 });
829
- }
830
- return unwrapAsset(asset2);
831
- };
832
- var getCharactersData = (characters) => {
833
- const entries = Object.entries(characters);
834
- const mapped = entries.map(([key, value]) => [key, { name: value.name, emotions: Object.keys(value.emotions) }]);
835
- return Object.fromEntries(mapped);
836
- };
837
- var toArray = (target) => {
838
- return Array.isArray(target) ? target : [target];
839
- };
840
- var getLanguageFromStore = (store2) => {
841
- return store2.get().meta[0];
842
- };
843
- var getVolumeFromStore = (store2) => {
844
- const { meta } = store2.get();
845
- return {
846
- music: meta[2],
847
- sound: meta[3],
848
- voice: meta[4]
849
- };
850
- };
851
-
852
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/compat/predicate/isObjectLike.mjs
853
- function isObjectLike(value) {
854
- return typeof value === "object" && value !== null;
855
- }
856
-
857
- // ../../node_modules/.pnpm/es-toolkit@1.16.0/node_modules/es-toolkit/dist/object/merge.mjs
858
- function merge(target, source) {
859
- const sourceKeys = Object.keys(source);
860
- for (let i = 0; i < sourceKeys.length; i++) {
861
- const key = sourceKeys[i];
862
- const sourceValue = source[key];
863
- const targetValue = target[key];
864
- if (Array.isArray(sourceValue)) {
865
- target[key] = merge(targetValue ?? [], sourceValue);
866
- } else if (isObjectLike(targetValue) && isObjectLike(sourceValue)) {
867
- target[key] = merge(targetValue ?? {}, sourceValue);
868
- } else if (targetValue === void 0 || sourceValue !== void 0) {
869
- target[key] = sourceValue;
870
- }
871
- }
872
- return target;
873
- }
874
998
 
875
- // ../../node_modules/.pnpm/dequal@2.0.3/node_modules/dequal/lite/index.mjs
876
- var has = Object.prototype.hasOwnProperty;
877
- function dequal(foo, bar) {
878
- var ctor, len;
879
- if (foo === bar) return true;
880
- if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
881
- if (ctor === Date) return foo.getTime() === bar.getTime();
882
- if (ctor === RegExp) return foo.toString() === bar.toString();
883
- if (ctor === Array) {
884
- if ((len = foo.length) === bar.length) {
885
- while (len-- && dequal(foo[len], bar[len])) ;
886
- }
887
- return len === -1;
888
- }
889
- if (!ctor || typeof foo === "object") {
890
- len = 0;
891
- for (ctor in foo) {
892
- if (has.call(foo, ctor) && ++len && !has.call(bar, ctor)) return false;
893
- if (!(ctor in bar) || !dequal(foo[ctor], bar[ctor])) return false;
894
- }
895
- return Object.keys(bar).length === len;
896
- }
897
- }
898
- return foo !== foo && bar !== bar;
899
- }
900
-
901
- // src/store.ts
902
- var store = (current, subscribers = /* @__PURE__ */ new Set()) => {
903
- const subscribe = (cb) => {
904
- subscribers.add(cb), cb(current);
905
- return () => {
906
- subscribers.delete(cb);
907
- };
908
- };
909
- const push = (value) => {
910
- for (const cb of subscribers) cb(value);
911
- };
912
- const update = (fn) => {
913
- push(current = fn(current));
914
- };
915
- const set2 = (val) => {
916
- update(() => val);
917
- };
918
- const get = () => {
919
- return current;
920
- };
921
- return { subscribe, update, set: set2, get };
922
- };
999
+ // src/shared.ts
1000
+ var STACK_MAP = /* @__PURE__ */ new Map();
1001
+ var CUSTOM_ACTION_MAP = /* @__PURE__ */ new Map();
1002
+ var PRELOADED_ASSETS = /* @__PURE__ */ new Set();
1003
+ var ASSETS_TO_PRELOAD = /* @__PURE__ */ new Set();
923
1004
 
924
- // ../../node_modules/.pnpm/klona@2.0.6/node_modules/klona/full/index.mjs
925
- function set(obj, key, val) {
926
- if (typeof val.value === "object") val.value = klona(val.value);
927
- if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === "__proto__") {
928
- Object.defineProperty(obj, key, val);
929
- } else obj[key] = val.value;
930
- }
931
- function klona(x) {
932
- if (typeof x !== "object") return x;
933
- var i = 0, k, list, tmp, str2 = Object.prototype.toString.call(x);
934
- if (str2 === "[object Object]") {
935
- tmp = Object.create(x.__proto__ || null);
936
- } else if (str2 === "[object Array]") {
937
- tmp = Array(x.length);
938
- } else if (str2 === "[object Set]") {
939
- tmp = /* @__PURE__ */ new Set();
940
- x.forEach(function(val) {
941
- tmp.add(klona(val));
942
- });
943
- } else if (str2 === "[object Map]") {
944
- tmp = /* @__PURE__ */ new Map();
945
- x.forEach(function(val, key) {
946
- tmp.set(klona(key), klona(val));
947
- });
948
- } else if (str2 === "[object Date]") {
949
- tmp = /* @__PURE__ */ new Date(+x);
950
- } else if (str2 === "[object RegExp]") {
951
- tmp = new RegExp(x.source, x.flags);
952
- } else if (str2 === "[object DataView]") {
953
- tmp = new x.constructor(klona(x.buffer));
954
- } else if (str2 === "[object ArrayBuffer]") {
955
- tmp = x.slice(0);
956
- } else if (str2.slice(-6) === "Array]") {
957
- tmp = new x.constructor(x);
958
- }
959
- if (tmp) {
960
- for (list = Object.getOwnPropertySymbols(x); i < list.length; i++) {
961
- set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
962
- }
963
- for (i = 0, list = Object.getOwnPropertyNames(x); i < list.length; i++) {
964
- if (Object.hasOwnProperty.call(tmp, k = list[i]) && tmp[k] === x[k]) continue;
965
- set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
966
- }
1005
+ // src/utilities/stack.ts
1006
+ var getStack = memoize(
1007
+ (_) => {
1008
+ return [];
1009
+ },
1010
+ {
1011
+ cache: STACK_MAP,
1012
+ getCacheKey: (ctx) => ctx.id
967
1013
  }
968
- return tmp || x;
969
- }
1014
+ );
1015
+ var createUseStackFunction = (renderer) => {
1016
+ const useStack = (context) => {
1017
+ const ctx = typeof context === "string" ? renderer.getContext(context) : context;
1018
+ const stack = getStack(ctx);
1019
+ return {
1020
+ get previous() {
1021
+ return stack.previous;
1022
+ },
1023
+ get value() {
1024
+ return stack.at(-1);
1025
+ },
1026
+ set value(value) {
1027
+ stack[stack.length - 1] = value;
1028
+ },
1029
+ back() {
1030
+ if (stack.length > 1) {
1031
+ stack.previous = stack.pop();
1032
+ ctx.meta.goingBack = true;
1033
+ }
1034
+ },
1035
+ push(value) {
1036
+ stack.push(value);
1037
+ },
1038
+ clear() {
1039
+ stack.previous = void 0;
1040
+ stack.length = 0;
1041
+ stack.length = 1;
1042
+ }
1043
+ };
1044
+ };
1045
+ return useStack;
1046
+ };
970
1047
 
971
- // src/translation.ts
972
- var RGX = /{{(.*?)}}/g;
973
- var split = (input, delimeters) => {
974
- const output = [];
975
- for (const delimeter of delimeters) {
976
- if (!input) break;
977
- const [start, end] = input.split(delimeter, 2);
978
- output.push(start);
979
- input = end;
980
- }
981
- output.push(input);
982
- return output;
1048
+ // src/utilities/story.ts
1049
+ var flatActions = (item) => {
1050
+ return item.flatMap((data) => {
1051
+ const type = data[0];
1052
+ if (Array.isArray(type)) return flatActions(data);
1053
+ return [data];
1054
+ });
983
1055
  };
984
- var flattenAllowedContent = (c, state) => {
985
- if (Array.isArray(c)) {
986
- return c.map((item) => flattenAllowedContent(item, state)).join("<br>");
987
- }
988
- if (typeof c === "function") {
989
- return flattenAllowedContent(c(state), state);
990
- }
991
- return c;
1056
+ var flatStory = (story) => {
1057
+ const entries = Object.entries(story).map(([name, items]) => {
1058
+ return [name, flatActions(items)];
1059
+ });
1060
+ return Object.fromEntries(entries);
992
1061
  };
993
- var replace = (input, data, pluralization, actions, pr) => {
994
- return input.replaceAll(RGX, (x, key, y) => {
995
- x = 0;
996
- y = data;
997
- const [pathstr, plural, action] = split(key.trim(), ["@", "%"]);
998
- if (!pathstr) {
999
- return "";
1000
- }
1001
- const path = pathstr.split(".");
1002
- while (y && x < path.length) y = y[path[x++]];
1003
- if (plural && pluralization && y && pr) {
1004
- y = pluralization[plural][pr.select(y)];
1062
+
1063
+ // src/browser.ts
1064
+ var setupBrowserVisibilityChangeListeners = ({ onChange }) => {
1065
+ if (typeof document === "undefined") return noop;
1066
+ const onVisibilityChange = () => {
1067
+ if (document.visibilityState === "hidden") {
1068
+ onChange();
1005
1069
  }
1006
- const actionHandler = actions && action ? actions[action] : void 0;
1007
- if (actionHandler) y = actionHandler(y);
1008
- return y == null ? "" : y;
1009
- });
1070
+ };
1071
+ addEventListener("visibilitychange", onVisibilityChange);
1072
+ addEventListener("beforeunload", onChange);
1073
+ return () => {
1074
+ removeEventListener("visibilitychange", onVisibilityChange);
1075
+ removeEventListener("beforeunload", onChange);
1076
+ };
1010
1077
  };
1011
1078
 
1012
1079
  // src/custom-action.ts
@@ -1049,13 +1116,15 @@ var Novely = (() => {
1049
1116
  };
1050
1117
  };
1051
1118
  const clear = (func) => {
1052
- setClear(holder.cleanup = () => {
1053
- func();
1054
- holder.node = null;
1055
- holder.cleanup = noop;
1056
- setMountElement(null);
1057
- setClear(noop);
1058
- });
1119
+ setClear(
1120
+ holder.cleanup = () => {
1121
+ func();
1122
+ holder.node = null;
1123
+ holder.cleanup = noop;
1124
+ setMountElement(null);
1125
+ setClear(noop);
1126
+ }
1127
+ );
1059
1128
  };
1060
1129
  const data = (updatedData) => {
1061
1130
  if (updatedData) {
@@ -1074,197 +1143,34 @@ var Novely = (() => {
1074
1143
  return fn({
1075
1144
  flags,
1076
1145
  lang,
1077
- state,
1078
- data,
1079
- clear,
1080
- remove,
1081
- rendererContext: ctx,
1082
- getDomNodes,
1083
- getPath,
1084
- contextKey: ctx.id
1085
- });
1086
- };
1087
-
1088
- // src/storage.ts
1089
- var localStorageStorage = (options) => {
1090
- return {
1091
- async get() {
1092
- const fallback = { saves: [], data: {}, meta: [] };
1093
- try {
1094
- const value = localStorage.getItem(options.key);
1095
- return value ? JSON.parse(value) : fallback;
1096
- } catch {
1097
- return fallback;
1098
- }
1099
- },
1100
- async set(data) {
1101
- try {
1102
- localStorage.setItem(options.key, JSON.stringify(data));
1103
- } catch {
1104
- }
1105
- }
1106
- };
1107
- };
1108
-
1109
- // src/browser.ts
1110
- var setupBrowserVisibilityChangeListeners = ({ onChange }) => {
1111
- if (typeof document === "undefined") return noop;
1112
- const onVisibilityChange = () => {
1113
- if (document.visibilityState === "hidden") {
1114
- onChange();
1115
- }
1116
- };
1117
- addEventListener("visibilitychange", onVisibilityChange);
1118
- addEventListener("beforeunload", onChange);
1119
- return () => {
1120
- removeEventListener("visibilitychange", onVisibilityChange);
1121
- removeEventListener("beforeunload", onChange);
1122
- };
1123
- };
1124
-
1125
- // ../../node_modules/.pnpm/yocto-queue@1.1.1/node_modules/yocto-queue/index.js
1126
- var Node = class {
1127
- value;
1128
- next;
1129
- constructor(value) {
1130
- this.value = value;
1131
- }
1132
- };
1133
- var Queue = class {
1134
- #head;
1135
- #tail;
1136
- #size;
1137
- constructor() {
1138
- this.clear();
1139
- }
1140
- enqueue(value) {
1141
- const node = new Node(value);
1142
- if (this.#head) {
1143
- this.#tail.next = node;
1144
- this.#tail = node;
1145
- } else {
1146
- this.#head = node;
1147
- this.#tail = node;
1148
- }
1149
- this.#size++;
1150
- }
1151
- dequeue() {
1152
- const current = this.#head;
1153
- if (!current) {
1154
- return;
1155
- }
1156
- this.#head = this.#head.next;
1157
- this.#size--;
1158
- return current.value;
1159
- }
1160
- peek() {
1161
- if (!this.#head) {
1162
- return;
1163
- }
1164
- return this.#head.value;
1165
- }
1166
- clear() {
1167
- this.#head = void 0;
1168
- this.#tail = void 0;
1169
- this.#size = 0;
1170
- }
1171
- get size() {
1172
- return this.#size;
1173
- }
1174
- *[Symbol.iterator]() {
1175
- let current = this.#head;
1176
- while (current) {
1177
- yield current.value;
1178
- current = current.next;
1179
- }
1180
- }
1181
- };
1182
-
1183
- // ../../node_modules/.pnpm/p-limit@6.1.0/node_modules/p-limit/index.js
1184
- function pLimit(concurrency) {
1185
- validateConcurrency(concurrency);
1186
- const queue = new Queue();
1187
- let activeCount = 0;
1188
- const resumeNext = () => {
1189
- if (activeCount < concurrency && queue.size > 0) {
1190
- queue.dequeue()();
1191
- activeCount++;
1192
- }
1193
- };
1194
- const next = () => {
1195
- activeCount--;
1196
- resumeNext();
1197
- };
1198
- const run = async (function_, resolve, arguments_) => {
1199
- const result = (async () => function_(...arguments_))();
1200
- resolve(result);
1201
- try {
1202
- await result;
1203
- } catch {
1204
- }
1205
- next();
1206
- };
1207
- const enqueue = (function_, resolve, arguments_) => {
1208
- new Promise((internalResolve) => {
1209
- queue.enqueue(internalResolve);
1210
- }).then(
1211
- run.bind(void 0, function_, resolve, arguments_)
1212
- );
1213
- (async () => {
1214
- await Promise.resolve();
1215
- if (activeCount < concurrency) {
1216
- resumeNext();
1217
- }
1218
- })();
1219
- };
1220
- const generator = (function_, ...arguments_) => new Promise((resolve) => {
1221
- enqueue(function_, resolve, arguments_);
1222
- });
1223
- Object.defineProperties(generator, {
1224
- activeCount: {
1225
- get: () => activeCount
1226
- },
1227
- pendingCount: {
1228
- get: () => queue.size
1229
- },
1230
- clearQueue: {
1231
- value() {
1232
- queue.clear();
1233
- }
1234
- },
1235
- concurrency: {
1236
- get: () => concurrency,
1237
- set(newConcurrency) {
1238
- validateConcurrency(newConcurrency);
1239
- concurrency = newConcurrency;
1240
- queueMicrotask(() => {
1241
- while (activeCount < concurrency && queue.size > 0) {
1242
- resumeNext();
1243
- }
1244
- });
1245
- }
1246
- }
1146
+ state,
1147
+ data,
1148
+ clear,
1149
+ remove,
1150
+ rendererContext: ctx,
1151
+ getDomNodes,
1152
+ getPath,
1153
+ contextKey: ctx.id
1247
1154
  });
1248
- return generator;
1249
- }
1250
- function validateConcurrency(concurrency) {
1251
- if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
1252
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
1253
- }
1254
- }
1155
+ };
1255
1156
 
1256
1157
  // src/preloading.ts
1257
1158
  var ACTION_NAME_TO_VOLUME_MAP = {
1258
- "playMusic": "music",
1259
- "playSound": "sound",
1260
- "voice": "voice"
1159
+ playMusic: "music",
1160
+ playSound: "sound",
1161
+ voice: "voice"
1261
1162
  };
1262
1163
  var enqueueAssetForPreloading = (asset2) => {
1263
1164
  if (!PRELOADED_ASSETS.has(asset2)) {
1264
1165
  ASSETS_TO_PRELOAD.add(asset2);
1265
1166
  }
1266
1167
  };
1267
- var handleAssetsPreloading = async ({ request, limiter, preloadAudioBlocking, preloadImageBlocking }) => {
1168
+ var handleAssetsPreloading = async ({
1169
+ request,
1170
+ limiter,
1171
+ preloadAudioBlocking,
1172
+ preloadImageBlocking
1173
+ }) => {
1268
1174
  const list = mapSet(ASSETS_TO_PRELOAD, (asset2) => {
1269
1175
  return limiter(async () => {
1270
1176
  const type = await getResourseType({
@@ -1339,9 +1245,9 @@ var Novely = (() => {
1339
1245
  }
1340
1246
  return;
1341
1247
  }
1342
- if (action === "custom" && props[0].assets && props[0].assets.length > 0) {
1248
+ if (action === "custom" && props[0].assets) {
1343
1249
  for (const asset2 of props[0].assets) {
1344
- handle(asset2);
1250
+ isAsset(asset2) ? handle(asset2.source) : handle(asset2);
1345
1251
  }
1346
1252
  return;
1347
1253
  }
@@ -1349,10 +1255,95 @@ var Novely = (() => {
1349
1255
  for (let i = 1; i < props.length; i++) {
1350
1256
  const data = props[i];
1351
1257
  if (Array.isArray(data)) {
1352
- handle(handleImageAsset(data[4]));
1258
+ handle(handleImageAsset(data[5]));
1259
+ }
1260
+ }
1261
+ }
1262
+ };
1263
+
1264
+ // src/storage.ts
1265
+ var localStorageStorage = (options) => {
1266
+ return {
1267
+ async get() {
1268
+ const fallback = { saves: [], data: {}, meta: [] };
1269
+ try {
1270
+ const value = localStorage.getItem(options.key);
1271
+ return value ? JSON.parse(value) : fallback;
1272
+ } catch {
1273
+ return fallback;
1274
+ }
1275
+ },
1276
+ async set(data) {
1277
+ try {
1278
+ localStorage.setItem(options.key, JSON.stringify(data));
1279
+ } catch {
1353
1280
  }
1354
1281
  }
1282
+ };
1283
+ };
1284
+
1285
+ // src/store.ts
1286
+ var store = (current, subscribers = /* @__PURE__ */ new Set()) => {
1287
+ const subscribe = (cb) => {
1288
+ subscribers.add(cb), cb(current);
1289
+ return () => {
1290
+ subscribers.delete(cb);
1291
+ };
1292
+ };
1293
+ const push = (value) => {
1294
+ for (const cb of subscribers) cb(value);
1295
+ };
1296
+ const update = (fn) => {
1297
+ push(current = fn(current));
1298
+ };
1299
+ const set2 = (val) => {
1300
+ update(() => val);
1301
+ };
1302
+ const get = () => {
1303
+ return current;
1304
+ };
1305
+ return { subscribe, update, set: set2, get };
1306
+ };
1307
+
1308
+ // src/translation.ts
1309
+ var RGX = /{{(.*?)}}/g;
1310
+ var split = (input, delimeters) => {
1311
+ const output = [];
1312
+ for (const delimeter of delimeters) {
1313
+ if (!input) break;
1314
+ const [start, end] = input.split(delimeter, 2);
1315
+ output.push(start);
1316
+ input = end;
1317
+ }
1318
+ output.push(input);
1319
+ return output;
1320
+ };
1321
+ var flattenAllowedContent = (c, state) => {
1322
+ if (Array.isArray(c)) {
1323
+ return c.map((item) => flattenAllowedContent(item, state)).join("<br>");
1355
1324
  }
1325
+ if (typeof c === "function") {
1326
+ return flattenAllowedContent(c(state), state);
1327
+ }
1328
+ return c;
1329
+ };
1330
+ var replace = (input, data, pluralization, actions, pr) => {
1331
+ return input.replaceAll(RGX, (x, key, y) => {
1332
+ x = 0;
1333
+ y = data;
1334
+ const [pathstr, plural, action] = split(key.trim(), ["@", "%"]);
1335
+ if (!pathstr) {
1336
+ return "";
1337
+ }
1338
+ const path = pathstr.split(".");
1339
+ while (y && x < path.length) y = y[path[x++]];
1340
+ if (plural && pluralization && y && pr) {
1341
+ y = pluralization[plural][pr.select(y)];
1342
+ }
1343
+ const actionHandler = actions && action ? actions[action] : void 0;
1344
+ if (actionHandler) y = actionHandler(y);
1345
+ return y == null ? "" : y;
1346
+ });
1356
1347
  };
1357
1348
 
1358
1349
  // src/novely.ts
@@ -1393,7 +1384,7 @@ var Novely = (() => {
1393
1384
  };
1394
1385
  const scriptBase = async (part) => {
1395
1386
  if (destroyed) return;
1396
- Object.assign(story, flattenStory(part));
1387
+ Object.assign(story, flatStory(part));
1397
1388
  let loadingIsShown = false;
1398
1389
  if (!initialScreenWasShown) {
1399
1390
  renderer.ui.showLoading();
@@ -1472,7 +1463,8 @@ var Novely = (() => {
1472
1463
  [null, 0]
1473
1464
  ],
1474
1465
  state,
1475
- [intime(Date.now()), "auto"]
1466
+ [intime(Date.now()), "auto"],
1467
+ []
1476
1468
  ];
1477
1469
  };
1478
1470
  const getLanguageWithoutParameters = () => {
@@ -1481,7 +1473,9 @@ var Novely = (() => {
1481
1473
  return language;
1482
1474
  }
1483
1475
  if (DEV) {
1484
- throw new Error(`Attempt to use unsupported language "${language}". Supported languages: ${languages.join(", ")}.`);
1476
+ throw new Error(
1477
+ `Attempt to use unsupported language "${language}". Supported languages: ${languages.join(", ")}.`
1478
+ );
1485
1479
  }
1486
1480
  throw 0;
1487
1481
  };
@@ -1597,7 +1591,9 @@ var Novely = (() => {
1597
1591
  const restore = async (save2) => {
1598
1592
  if (isEmpty(story)) {
1599
1593
  if (DEV) {
1600
- throw new Error("Story is empty. You should call an `enine.script` function [https://novely.pages.dev/guide/story.html]");
1594
+ throw new Error(
1595
+ "Story is empty. You should call an `enine.script` function [https://novely.pages.dev/guide/story.html]"
1596
+ );
1601
1597
  }
1602
1598
  return;
1603
1599
  }
@@ -1617,7 +1613,10 @@ var Novely = (() => {
1617
1613
  const [path] = stack.value = latest;
1618
1614
  renderer.ui.showScreen("game");
1619
1615
  const { queue, skip, skipPreserve } = getActionsFromPath(story, path, false);
1620
- const { run, keep: { keep, characters: characters2, audio: audio2 } } = createQueueProcessor(queue, {
1616
+ const {
1617
+ run,
1618
+ keep: { keep, characters: characters2, audio: audio2 }
1619
+ } = createQueueProcessor(queue, {
1621
1620
  skip,
1622
1621
  skipPreserve
1623
1622
  });
@@ -1667,7 +1666,9 @@ var Novely = (() => {
1667
1666
  const isSaved = () => {
1668
1667
  const { saves } = storageData.get();
1669
1668
  const [currentPath, currentData] = stack.value;
1670
- return saves.some(([path, data2, [date, type2]]) => type2 === "manual" && times.has(date) && dequal(path, currentPath) && dequal(data2, currentData));
1669
+ return saves.some(
1670
+ ([path, data2, [date, type2]]) => type2 === "manual" && times.has(date) && dequal(path, currentPath) && dequal(data2, currentData)
1671
+ );
1671
1672
  };
1672
1673
  if (interacted > 1 && !force && askBeforeExit && !isSaved()) {
1673
1674
  renderer.ui.showExitPrompt();
@@ -1763,7 +1764,9 @@ var Novely = (() => {
1763
1764
  const getLanguageDisplayName = (lang) => {
1764
1765
  const language = translation[lang];
1765
1766
  if (DEV && !language) {
1766
- throw new Error(`Attempt to use unsupported language "${language}". Supported languages: ${languages.join(", ")}.`);
1767
+ throw new Error(
1768
+ `Attempt to use unsupported language "${language}". Supported languages: ${languages.join(", ")}.`
1769
+ );
1767
1770
  }
1768
1771
  return capitalize(language.nameOverride || getIntlLanguageDisplayName(lang));
1769
1772
  };
@@ -1782,6 +1785,61 @@ var Novely = (() => {
1782
1785
  const getCharacterAssets = (character, emotion) => {
1783
1786
  return toArray(characters[character].emotions[emotion]).map(handleImageAsset);
1784
1787
  };
1788
+ const getCharacterName = (character) => {
1789
+ const c = character;
1790
+ const cs = characters;
1791
+ const [lang] = storageData.get().meta;
1792
+ if (c && c in cs) {
1793
+ const block = cs[c].name;
1794
+ if (typeof block === "string") {
1795
+ return block;
1796
+ }
1797
+ if (lang in block) {
1798
+ return block[lang];
1799
+ }
1800
+ }
1801
+ return String(c) || "";
1802
+ };
1803
+ const getDialogOverview = () => {
1804
+ const { value: save2 } = useStack(MAIN_CONTEXT_KEY);
1805
+ const stateSnapshots = save2[3];
1806
+ const { queue } = getActionsFromPath(story, save2[0], false);
1807
+ const [lang] = storageData.get().meta;
1808
+ const dialogItem = [];
1809
+ for (let p = 0, i = 0; i < queue.length; i++) {
1810
+ const action2 = queue[i];
1811
+ if (action2[0] === "dialog") {
1812
+ const [_, name, text] = action2;
1813
+ let voice = void 0;
1814
+ for (let j = i - 1; j > p; j--) {
1815
+ const action3 = queue[j];
1816
+ if (isUserRequiredAction(action3) || isSkippedDuringRestore(action3[0])) break;
1817
+ if (action3[0] === "stopVoice") break;
1818
+ if (action3[0] === "voice") {
1819
+ voice = action3[1];
1820
+ break;
1821
+ }
1822
+ }
1823
+ dialogItem.push({
1824
+ name,
1825
+ text,
1826
+ voice
1827
+ });
1828
+ p = i;
1829
+ }
1830
+ }
1831
+ const entries = dialogItem.map(({ name, text, voice }, i) => {
1832
+ const state = stateSnapshots[i];
1833
+ const audioSource = isString(voice) ? voice : isAsset(voice) ? voice : voice == void 0 ? voice : voice[lang];
1834
+ name = name ? getCharacterName(name) : "";
1835
+ return {
1836
+ name: templateReplace(name, state),
1837
+ text: templateReplace(text, state),
1838
+ voice: audioSource ? handleAudioAsset(audioSource) : ""
1839
+ };
1840
+ });
1841
+ return entries;
1842
+ };
1785
1843
  const renderer = createRenderer({
1786
1844
  mainContextKey: MAIN_CONTEXT_KEY,
1787
1845
  characters: getCharactersData(characters),
@@ -1803,6 +1861,7 @@ var Novely = (() => {
1803
1861
  getLanguageDisplayName,
1804
1862
  getCharacterColor,
1805
1863
  getCharacterAssets,
1864
+ getDialogOverview,
1806
1865
  getResourseType: getResourseTypeForRenderer
1807
1866
  });
1808
1867
  const useStack = createUseStackFunction(renderer);
@@ -1865,17 +1924,19 @@ var Novely = (() => {
1865
1924
  }
1866
1925
  };
1867
1926
  const match = matchAction(matchActionOptions, {
1868
- wait({ ctx, push }, [time]) {
1927
+ wait({ ctx, data: data2, push }, [time]) {
1869
1928
  if (ctx.meta.restoring) return;
1870
- setTimeout(push, isFunction(time) ? time(getStateAtCtx(ctx)) : time);
1929
+ setTimeout(push, isFunction(time) ? time(data2) : time);
1871
1930
  },
1872
1931
  showBackground({ ctx, push }, [background]) {
1873
1932
  if (isString(background) || isAsset(background)) {
1874
1933
  ctx.background({
1875
- "all": handleImageAsset(background)
1934
+ all: handleImageAsset(background)
1876
1935
  });
1877
1936
  } else {
1878
- ctx.background(Object.fromEntries(Object.entries(background).map(([media, asset2]) => [media, handleImageAsset(asset2)])));
1937
+ ctx.background(
1938
+ Object.fromEntries(Object.entries(background).map(([media, asset2]) => [media, handleImageAsset(asset2)]))
1939
+ );
1879
1940
  }
1880
1941
  push();
1881
1942
  },
@@ -1935,29 +1996,13 @@ var Novely = (() => {
1935
1996
  ctx.character(character).remove(className, style, duration, ctx.meta.restoring).then(push);
1936
1997
  },
1937
1998
  dialog({ ctx, data: data2, forward }, [character, content, emotion]) {
1938
- const name = (() => {
1939
- const c = character;
1940
- const cs = characters;
1941
- const [lang] = storageData.get().meta;
1942
- if (c && c in cs) {
1943
- const block = cs[c].name;
1944
- if (typeof block === "string") {
1945
- return block;
1946
- }
1947
- if (lang in block) {
1948
- return block[lang];
1949
- }
1950
- }
1951
- return c || "";
1952
- })();
1999
+ const name = getCharacterName(character);
2000
+ const stack = useStack(ctx);
2001
+ if (!ctx.meta.restoring && !ctx.meta.goingBack) {
2002
+ stack.value[3].push(clone(data2));
2003
+ }
1953
2004
  ctx.clearBlockingActions("dialog");
1954
- ctx.dialog(
1955
- templateReplace(content, data2),
1956
- templateReplace(name, data2),
1957
- character,
1958
- emotion,
1959
- forward
1960
- );
2005
+ ctx.dialog(templateReplace(content, data2), templateReplace(name, data2), character, emotion, forward);
1961
2006
  },
1962
2007
  function({ ctx, push }, [fn]) {
1963
2008
  const { restoring, goingBack, preview: preview2 } = ctx.meta;
@@ -1982,19 +2027,19 @@ var Novely = (() => {
1982
2027
  const transformedChoices = choices.map(([content, _children, active, visible, onSelect, image]) => {
1983
2028
  const active$ = store(false);
1984
2029
  const visible$ = store(false);
1985
- const update = () => {
1986
- const lang = getLanguageFromStore(storageData);
1987
- const state = getStateAtCtx(ctx);
1988
- const activeValue = !active || active({
1989
- lang,
1990
- state
1991
- });
1992
- const visibleValue = !visible || visible({
2030
+ const lang = getLanguageFromStore(storageData);
2031
+ const getCheckValue = (fn) => {
2032
+ if (!fn) {
2033
+ return true;
2034
+ }
2035
+ return fn({
1993
2036
  lang,
1994
- state
2037
+ state: getStateAtCtx(ctx)
1995
2038
  });
1996
- active$.set(activeValue);
1997
- visible$.set(visibleValue);
2039
+ };
2040
+ const update = () => {
2041
+ active$.set(getCheckValue(active));
2042
+ visible$.set(getCheckValue(visible));
1998
2043
  };
1999
2044
  update();
2000
2045
  const onSelectGuarded = onSelect || noop;
@@ -2007,7 +2052,9 @@ var Novely = (() => {
2007
2052
  return [templateReplace(content, data2), active$, visible$, onSelectWrapped, imageValue];
2008
2053
  });
2009
2054
  if (DEV && transformedChoices.length === 0) {
2010
- throw new Error(`Running choice without variants to choose from, look at how to use Choice action properly [https://novely.pages.dev/guide/actions/choice#usage]`);
2055
+ throw new Error(
2056
+ `Running choice without variants to choose from, look at how to use Choice action properly [https://novely.pages.dev/guide/actions/choice#usage]`
2057
+ );
2011
2058
  }
2012
2059
  ctx.clearBlockingActions("choice");
2013
2060
  ctx.choices(templateReplace(question, data2), transformedChoices, (selected) => {
@@ -2036,6 +2083,7 @@ var Novely = (() => {
2036
2083
  ["jump", scene],
2037
2084
  [null, -1]
2038
2085
  ];
2086
+ stack.value[3] = [];
2039
2087
  match("clear", [], {
2040
2088
  ctx,
2041
2089
  data: data2
@@ -2050,19 +2098,19 @@ var Novely = (() => {
2050
2098
  push
2051
2099
  );
2052
2100
  },
2053
- condition({ ctx }, [condition, variants]) {
2101
+ condition({ ctx, data: data2 }, [condition, variants]) {
2054
2102
  if (DEV && Object.values(variants).length === 0) {
2055
2103
  throw new Error(`Attempt to use Condition action with empty variants object`);
2056
2104
  }
2057
2105
  if (!ctx.meta.restoring) {
2058
- const val = String(condition(getStateAtCtx(ctx)));
2106
+ const val = String(condition(data2));
2059
2107
  if (DEV && !variants[val]) {
2060
2108
  throw new Error(`Attempt to go to unknown variant "${val}"`);
2061
2109
  }
2062
2110
  if (DEV && variants[val].length === 0) {
2063
2111
  throw new Error(`Attempt to go to empty variant "${val}"`);
2064
2112
  }
2065
- const stack = useStack(MAIN_CONTEXT_KEY);
2113
+ const stack = useStack(ctx);
2066
2114
  stack.value[0].push(["condition", val], [null, 0]);
2067
2115
  render(ctx);
2068
2116
  }
@@ -2073,12 +2121,7 @@ var Novely = (() => {
2073
2121
  },
2074
2122
  input({ ctx, data: data2, forward }, [question, onInput, setup]) {
2075
2123
  ctx.clearBlockingActions("input");
2076
- ctx.input(
2077
- templateReplace(question, data2),
2078
- onInput,
2079
- setup || noop,
2080
- forward
2081
- );
2124
+ ctx.input(templateReplace(question, data2), onInput, setup || noop, forward);
2082
2125
  },
2083
2126
  custom({ ctx, push }, [fn]) {
2084
2127
  if (fn.requireUserAction) {
@@ -2118,7 +2161,9 @@ var Novely = (() => {
2118
2161
  animateCharacter({ ctx, push }, [character, className]) {
2119
2162
  const classes = className.split(" ");
2120
2163
  if (DEV && classes.length === 0) {
2121
- throw new Error("Attempt to use AnimateCharacter without classes. Classes should be provided [https://novely.pages.dev/guide/actions/animateCharacter.html]");
2164
+ throw new Error(
2165
+ "Attempt to use AnimateCharacter without classes. Classes should be provided [https://novely.pages.dev/guide/actions/animateCharacter.html]"
2166
+ );
2122
2167
  }
2123
2168
  if (ctx.meta.preview) return;
2124
2169
  ctx.character(character).animate(classes);
@@ -2152,7 +2197,9 @@ var Novely = (() => {
2152
2197
  },
2153
2198
  preload({ ctx, push }, [source]) {
2154
2199
  if (DEV && preloadAssets !== "lazy") {
2155
- console.error(`You do not need a preload action becase "preloadAssets" strategy was set to "${preloadAssets}"`);
2200
+ console.error(
2201
+ `You do not need a preload action becase "preloadAssets" strategy was set to "${preloadAssets}"`
2202
+ );
2156
2203
  }
2157
2204
  if (!ctx.meta.goingBack && !ctx.meta.restoring && !PRELOADED_ASSETS.has(source)) {
2158
2205
  PRELOADED_ASSETS.add(renderer.misc.preloadImage(source));
@@ -2175,22 +2222,23 @@ var Novely = (() => {
2175
2222
  });
2176
2223
  const render = (ctx) => {
2177
2224
  const stack = useStack(ctx);
2178
- const referred = refer(stack.value[0]);
2225
+ const [path, state] = stack.value;
2226
+ const referred = refer(path);
2179
2227
  if (isAction(referred)) {
2180
2228
  const [action2, ...props] = referred;
2181
2229
  match(action2, props, {
2182
2230
  ctx,
2183
- data: stack.value[1]
2231
+ data: state
2184
2232
  });
2185
2233
  } else if (Object.values(story).some((branch) => branch === referred)) {
2186
2234
  match("end", [], {
2187
2235
  ctx,
2188
- data: stack.value[1]
2236
+ data: state
2189
2237
  });
2190
2238
  } else {
2191
2239
  match("exit", [], {
2192
2240
  ctx,
2193
- data: stack.value[1]
2241
+ data: state
2194
2242
  });
2195
2243
  }
2196
2244
  };
@@ -2198,21 +2246,15 @@ var Novely = (() => {
2198
2246
  interacted = value ? interacted + 1 : 0;
2199
2247
  };
2200
2248
  const templateReplace = (content, values) => {
2201
- const { data: data2, meta: [lang] } = storageData.get();
2249
+ const {
2250
+ data: data2,
2251
+ meta: [lang]
2252
+ } = storageData.get();
2202
2253
  const obj = values || data2;
2203
- const str2 = flattenAllowedContent(
2204
- !isFunction(content) && !isString(content) ? content[lang] : content,
2205
- obj
2206
- );
2254
+ const str = flattenAllowedContent(!isFunction(content) && !isString(content) ? content[lang] : content, obj);
2207
2255
  const t2 = translation[lang];
2208
2256
  const pluralRules = (t2.plural || t2.actions) && new Intl.PluralRules(t2.tag || lang);
2209
- return replace(
2210
- str2,
2211
- obj,
2212
- t2.plural,
2213
- t2.actions,
2214
- pluralRules
2215
- );
2257
+ return replace(str, obj, t2.plural, t2.actions, pluralRules);
2216
2258
  };
2217
2259
  const data = (value) => {
2218
2260
  const _data = storageData.get().data;
@@ -2236,7 +2278,9 @@ var Novely = (() => {
2236
2278
  const setStorageData = (data2) => {
2237
2279
  if (destroyed) {
2238
2280
  if (DEV) {
2239
- throw new Error(`function \`setStorageData\` was called after novely instance was destroyed. Data is not updater nor synced after destroy.`);
2281
+ throw new Error(
2282
+ `function \`setStorageData\` was called after novely instance was destroyed. Data is not updater nor synced after destroy.`
2283
+ );
2240
2284
  }
2241
2285
  return;
2242
2286
  }
@@ -2296,7 +2340,7 @@ var Novely = (() => {
2296
2340
  * @example
2297
2341
  * ```ts
2298
2342
  * import type { ConditionParams, StateFunction } from '@novely/core';
2299
- *
2343
+ *
2300
2344
  * const conditionCheck = (state: StateFunction<ConditionParams<typeof engine.typeEssintials>>) => {
2301
2345
  * return state.age >= 18;
2302
2346
  * }
@@ -2407,7 +2451,9 @@ var Novely = (() => {
2407
2451
  CloseMenu: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u043C\u0435\u043D\u044E",
2408
2452
  MusicVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u043C\u0443\u0437\u044B\u043A\u0438",
2409
2453
  SoundVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0437\u0432\u0443\u043A\u043E\u0432",
2410
- VoiceVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0440\u0435\u0447\u0438"
2454
+ VoiceVolume: "\u0413\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0440\u0435\u0447\u0438",
2455
+ Close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C",
2456
+ DialogOverview: "\u041E\u0431\u0437\u043E\u0440 \u0434\u0438\u0430\u043B\u043E\u0433\u0430"
2411
2457
  };
2412
2458
  var EN = {
2413
2459
  NewGame: "New Game",
@@ -2443,7 +2489,9 @@ var Novely = (() => {
2443
2489
  CloseMenu: "Close menu",
2444
2490
  MusicVolume: "Music volume",
2445
2491
  SoundVolume: "Sound volume",
2446
- VoiceVolume: "Voice volume"
2492
+ VoiceVolume: "Voice volume",
2493
+ Close: "Close",
2494
+ DialogOverview: "Dialog Overview"
2447
2495
  };
2448
2496
  var KK = {
2449
2497
  NewGame: "\u0416\u0430\u04A3\u0430 \u043E\u0439\u044B\u043D",
@@ -2479,7 +2527,9 @@ var Novely = (() => {
2479
2527
  CloseMenu: "\u041C\u04D9\u0437\u0456\u0440\u0434\u0456 \u0436\u0430\u0431\u0443",
2480
2528
  MusicVolume: "\u041C\u0443\u0437\u044B\u043A\u0430\u043D\u044B\u04A3 \u043A\u04E9\u043B\u0435\u043C\u0456",
2481
2529
  SoundVolume: "\u0414\u044B\u0431\u044B\u0441\u0442\u0430\u0440\u0434\u044B\u04A3 \u043A\u04E9\u043B\u0435\u043C\u0456",
2482
- VoiceVolume: "\u0421\u04E9\u0439\u043B\u0435\u0443 \u043A\u04E9\u043B\u0435\u043C\u0456"
2530
+ VoiceVolume: "\u0421\u04E9\u0439\u043B\u0435\u0443 \u043A\u04E9\u043B\u0435\u043C\u0456",
2531
+ Close: "\u0416\u0430\u0431\u0443",
2532
+ DialogOverview: "\u0414\u0438\u0430\u043B\u043E\u0433\u049B\u0430 \u0428\u043E\u043B\u0443"
2483
2533
  };
2484
2534
  var JP = {
2485
2535
  NewGame: "\u300C\u65B0\u3057\u3044\u30B2\u30FC\u30E0\u300D",
@@ -2515,7 +2565,133 @@ var Novely = (() => {
2515
2565
  CloseMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B",
2516
2566
  MusicVolume: "\u97F3\u697D\u306E\u30DC\u30EA\u30E5\u30FC\u30E0",
2517
2567
  SoundVolume: "\u97F3\u91CF",
2518
- VoiceVolume: "\u30B9\u30D4\u30FC\u30C1\u306E\u91CF"
2568
+ VoiceVolume: "\u30B9\u30D4\u30FC\u30C1\u306E\u91CF",
2569
+ Close: "\u9589\u3058\u308B",
2570
+ DialogOverview: "\u30C0\u30A4\u30A2\u30ED\u30B0\u306E\u6982\u8981"
2571
+ };
2572
+
2573
+ // src/audio-codecs.ts
2574
+ var cut = (str) => str.replace(/^no$/, "");
2575
+ var audio = new Audio();
2576
+ var canPlay = (type) => !!cut(audio.canPlayType(type));
2577
+ var canPlayMultiple = (...types) => types.some((type) => canPlay(type));
2578
+ var supportsMap = {
2579
+ mp3: canPlayMultiple("audio/mpeg;", "audio/mp3;"),
2580
+ mpeg: canPlay("audio/mpeg;"),
2581
+ opus: canPlay('audio/ogg; codecs="opus"'),
2582
+ ogg: canPlay('audio/ogg; codecs="vorbis"'),
2583
+ oga: canPlay('audio/ogg; codecs="vorbis"'),
2584
+ wav: canPlayMultiple('audio/wav; codecs="1"', "audio/wav;"),
2585
+ aac: canPlay("audio/aac;"),
2586
+ caf: canPlay("audio/x-caf;"),
2587
+ m4a: canPlayMultiple("audio/x-m4a;", "audio/m4a;", "audio/aac;"),
2588
+ m4b: canPlayMultiple("audio/x-m4b;", "audio/m4b;", "audio/aac;"),
2589
+ mp4: canPlayMultiple("audio/x-mp4;", "audio/mp4;", "audio/aac;"),
2590
+ weba: canPlay('audio/webm; codecs="vorbis"'),
2591
+ webm: canPlay('audio/webm; codecs="vorbis"'),
2592
+ dolby: canPlay('audio/mp4; codecs="ec-3"'),
2593
+ flac: canPlayMultiple("audio/x-flac;", "audio/flac;")
2594
+ };
2595
+
2596
+ // src/image-formats.ts
2597
+ var avif = "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=";
2598
+ var jxl = "data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgAAFSqjjBu8nOv58kOHxbSN6wxttW1hSaLIODZJJ3BIEkkaoCUzGM6qJAE=";
2599
+ var webp = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
2600
+ var supportsFormat = (source) => {
2601
+ const { promise, resolve } = Promise.withResolvers();
2602
+ const img = Object.assign(document.createElement("img"), {
2603
+ src: source
2604
+ });
2605
+ img.onload = img.onerror = () => {
2606
+ resolve(img.height === 2);
2607
+ };
2608
+ return promise;
2609
+ };
2610
+ var supportsMap2 = {
2611
+ avif: false,
2612
+ jxl: false,
2613
+ webp: false
2614
+ };
2615
+ var formatsMap = {
2616
+ avif,
2617
+ jxl,
2618
+ webp
2619
+ };
2620
+ var loadImageFormatsSupport = async () => {
2621
+ const promises = [];
2622
+ for (const [format, source] of Object.entries(formatsMap)) {
2623
+ const promise = supportsFormat(source).then((supported) => {
2624
+ supportsMap2[format] = supported;
2625
+ });
2626
+ promises.push(promise);
2627
+ }
2628
+ await Promise.all(promises);
2629
+ };
2630
+ loadImageFormatsSupport();
2631
+
2632
+ // src/asset.ts
2633
+ var getType = memoize(
2634
+ (extensions) => {
2635
+ if (extensions.every((extension) => HOWLER_SUPPORTED_FILE_FORMATS.has(extension))) {
2636
+ return "audio";
2637
+ }
2638
+ if (extensions.every((extension) => SUPPORTED_IMAGE_FILE_FORMATS.has(extension))) {
2639
+ return "image";
2640
+ }
2641
+ throw extensions;
2642
+ },
2643
+ {
2644
+ getCacheKey: (extensions) => extensions.join("~")
2645
+ }
2646
+ );
2647
+ var SUPPORT_MAPS = {
2648
+ image: supportsMap2,
2649
+ audio: supportsMap
2650
+ };
2651
+ var assetPrivate = memoize(
2652
+ (variants) => {
2653
+ if (DEV && variants.length === 0) {
2654
+ throw new Error(`Attempt to use "asset" function without arguments`);
2655
+ }
2656
+ const map = {};
2657
+ const extensions = [];
2658
+ for (const v of variants) {
2659
+ const e = getUrlFileExtension(v);
2660
+ map[e] = v;
2661
+ extensions.push(e);
2662
+ }
2663
+ const type = getType(extensions);
2664
+ const getSource = once(() => {
2665
+ const support = SUPPORT_MAPS[type];
2666
+ for (const extension of extensions) {
2667
+ if (extension in support) {
2668
+ if (support[extension]) {
2669
+ return map[extension];
2670
+ }
2671
+ } else {
2672
+ return map[extension];
2673
+ }
2674
+ }
2675
+ if (DEV) {
2676
+ throw new Error(`No matching asset was found for ${variants.map((v) => `"${v}"`).join(", ")}`);
2677
+ }
2678
+ return "";
2679
+ });
2680
+ return {
2681
+ get source() {
2682
+ return getSource();
2683
+ },
2684
+ get type() {
2685
+ return type;
2686
+ }
2687
+ };
2688
+ },
2689
+ {
2690
+ getCacheKey: (variants) => variants.join("~")
2691
+ }
2692
+ );
2693
+ var asset = (...variants) => {
2694
+ return assetPrivate(variants);
2519
2695
  };
2520
2696
  return __toCommonJS(src_exports);
2521
2697
  })();