@kokimoki/app 2.1.0 → 3.0.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.
Files changed (38) hide show
  1. package/README.md +72 -0
  2. package/dist/core/kokimoki-client.d.ts +75 -15
  3. package/dist/core/kokimoki-client.js +137 -22
  4. package/dist/index.d.ts +6 -1
  5. package/dist/index.js +4 -0
  6. package/dist/kokimoki.min.d.ts +322 -2
  7. package/dist/kokimoki.min.js +1884 -72
  8. package/dist/kokimoki.min.js.map +1 -1
  9. package/dist/llms.txt +6 -0
  10. package/dist/protocol/ws-message/reader.d.ts +1 -1
  11. package/dist/services/index.d.ts +1 -0
  12. package/dist/services/index.js +1 -0
  13. package/dist/services/kokimoki-ai.d.ts +185 -122
  14. package/dist/services/kokimoki-ai.js +201 -109
  15. package/dist/services/kokimoki-i18n.d.ts +259 -0
  16. package/dist/services/kokimoki-i18n.js +325 -0
  17. package/dist/stores/kokimoki-local-store.d.ts +1 -1
  18. package/dist/types/common.d.ts +9 -0
  19. package/dist/types/env.d.ts +36 -0
  20. package/dist/types/env.js +1 -0
  21. package/dist/types/index.d.ts +1 -0
  22. package/dist/types/index.js +1 -0
  23. package/dist/utils/kokimoki-client.d.ts +31 -0
  24. package/dist/utils/kokimoki-client.js +38 -0
  25. package/dist/utils/kokimoki-dev.d.ts +30 -0
  26. package/dist/utils/kokimoki-dev.js +75 -0
  27. package/dist/utils/kokimoki-env.d.ts +20 -0
  28. package/dist/utils/kokimoki-env.js +30 -0
  29. package/dist/version.d.ts +1 -1
  30. package/dist/version.js +1 -1
  31. package/docs/kokimoki-ai.instructions.md +316 -0
  32. package/docs/kokimoki-dynamic-stores.instructions.md +439 -0
  33. package/docs/kokimoki-i18n.instructions.md +285 -0
  34. package/docs/kokimoki-leaderboard.instructions.md +189 -0
  35. package/docs/kokimoki-sdk.instructions.md +221 -0
  36. package/docs/kokimoki-storage.instructions.md +162 -0
  37. package/llms.txt +43 -0
  38. package/package.json +9 -13
@@ -1,3 +1,5 @@
1
+ import i18next from 'i18next';
2
+ import HttpBackend from 'i18next-http-backend';
1
3
  import require$$1 from 'path';
2
4
  import require$$2 from 'fs';
3
5
  import { useMemo, useRef, useSyncExternalStore, useCallback, useLayoutEffect, useEffect, useDebugValue } from 'react';
@@ -493,6 +495,12 @@ var EventEmitter$1 = /*@__PURE__*/getDefaultExportFromCjs(eventsExports);
493
495
  * @module map
494
496
  */
495
497
 
498
+ /**
499
+ * @template K
500
+ * @template V
501
+ * @typedef {Map<K,V>} GlobalMap
502
+ */
503
+
496
504
  /**
497
505
  * Creates a new Map instance.
498
506
  *
@@ -628,6 +636,58 @@ const appendTo = (dest, src) => {
628
636
  */
629
637
  const from = Array.from;
630
638
 
639
+ /**
640
+ * True iff condition holds on every element in the Array.
641
+ *
642
+ * @function
643
+ * @template {ArrayLike<any>} ARR
644
+ *
645
+ * @param {ARR} arr
646
+ * @param {ARR extends ArrayLike<infer S> ? ((value:S, index:number, arr:ARR) => boolean) : any} f
647
+ * @return {boolean}
648
+ */
649
+ const every$1 = (arr, f) => {
650
+ for (let i = 0; i < arr.length; i++) {
651
+ if (!f(arr[i], i, arr)) {
652
+ return false
653
+ }
654
+ }
655
+ return true
656
+ };
657
+
658
+ /**
659
+ * True iff condition holds on some element in the Array.
660
+ *
661
+ * @function
662
+ * @template {ArrayLike<any>} ARR
663
+ *
664
+ * @param {ARR} arr
665
+ * @param {ARR extends ArrayLike<infer S> ? ((value:S, index:number, arr:ARR) => boolean) : never} f
666
+ * @return {boolean}
667
+ */
668
+ const some = (arr, f) => {
669
+ for (let i = 0; i < arr.length; i++) {
670
+ if (f(arr[i], i, arr)) {
671
+ return true
672
+ }
673
+ }
674
+ return false
675
+ };
676
+
677
+ /**
678
+ * @template T
679
+ * @param {number} len
680
+ * @param {function(number, Array<T>):T} f
681
+ * @return {Array<T>}
682
+ */
683
+ const unfold = (len, f) => {
684
+ const array = new Array(len);
685
+ for (let i = 0; i < len; i++) {
686
+ array[i] = f(i, array);
687
+ }
688
+ return array
689
+ };
690
+
631
691
  const isArray$1 = Array.isArray;
632
692
 
633
693
  /**
@@ -743,8 +803,10 @@ const min$2 = (a, b) => a < b ? a : b;
743
803
  const max$3 = (a, b) => a > b ? a : b;
744
804
 
745
805
  /**
806
+ * Check whether n is negative, while considering the -0 edge case. While `-0 < 0` is false, this
807
+ * function returns true for -0,-1,,.. and returns false for 0,1,2,...
746
808
  * @param {number} n
747
- * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0
809
+ * @return {boolean} Wether n is negative. This function also distinguishes between -0 and +0
748
810
  */
749
811
  const isNegativeZero = n => n !== 0 ? n < 0 : 1 / n < 0;
750
812
 
@@ -784,10 +846,19 @@ const BITS31 = 0x7FFFFFFF;
784
846
 
785
847
 
786
848
  const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
849
+ const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER;
787
850
 
788
851
  /* c8 ignore next */
789
852
  const isInteger = Number.isInteger || (num => typeof num === 'number' && isFinite(num) && floor$2(num) === num);
790
853
 
854
+ /**
855
+ * Utility module to work with strings.
856
+ *
857
+ * @module string
858
+ */
859
+
860
+ const fromCharCode = String.fromCharCode;
861
+
791
862
  /**
792
863
  * @param {string} s
793
864
  * @return {string}
@@ -813,7 +884,7 @@ const fromCamelCase = (s, separator) => trimLeft(s.replace(fromCamelCaseRegex, m
813
884
 
814
885
  /**
815
886
  * @param {string} str
816
- * @return {Uint8Array}
887
+ * @return {Uint8Array<ArrayBuffer>}
817
888
  */
818
889
  const _encodeUtf8Polyfill = str => {
819
890
  const encodedString = unescape(encodeURIComponent(str));
@@ -830,7 +901,7 @@ const utf8TextEncoder = /** @type {TextEncoder} */ (typeof TextEncoder !== 'unde
830
901
 
831
902
  /**
832
903
  * @param {string} str
833
- * @return {Uint8Array}
904
+ * @return {Uint8Array<ArrayBuffer>}
834
905
  */
835
906
  const _encodeUtf8Native = str => utf8TextEncoder.encode(str);
836
907
 
@@ -855,6 +926,12 @@ if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) {
855
926
  utf8TextDecoder = null;
856
927
  }
857
928
 
929
+ /**
930
+ * @param {string} source
931
+ * @param {number} n
932
+ */
933
+ const repeat = (source, n) => unfold(n, () => source).join('');
934
+
858
935
  /**
859
936
  * Efficient schema-less binary encoding with support for variable length encoding.
860
937
  *
@@ -924,7 +1001,7 @@ const length = encoder => {
924
1001
  *
925
1002
  * @function
926
1003
  * @param {Encoder} encoder
927
- * @return {Uint8Array} The created ArrayBuffer.
1004
+ * @return {Uint8Array<ArrayBuffer>} The created ArrayBuffer.
928
1005
  */
929
1006
  const toUint8Array = encoder => {
930
1007
  const uint8arr = new Uint8Array(length(encoder));
@@ -1165,6 +1242,14 @@ const isFloat32 = num => {
1165
1242
  return floatTestBed.getFloat32(0) === num
1166
1243
  };
1167
1244
 
1245
+ /**
1246
+ * @typedef {Array<AnyEncodable>} AnyEncodableArray
1247
+ */
1248
+
1249
+ /**
1250
+ * @typedef {undefined|null|number|bigint|boolean|string|{[k:string]:AnyEncodable}|AnyEncodableArray|Uint8Array} AnyEncodable
1251
+ */
1252
+
1168
1253
  /**
1169
1254
  * Encode data with efficient binary format.
1170
1255
  *
@@ -1200,7 +1285,7 @@ const isFloat32 = num => {
1200
1285
  * lib0/encoding.js
1201
1286
  *
1202
1287
  * @param {Encoder} encoder
1203
- * @param {undefined|null|number|bigint|boolean|string|Object<string,any>|Array<any>|Uint8Array} data
1288
+ * @param {AnyEncodable} data
1204
1289
  */
1205
1290
  const writeAny = (encoder, data) => {
1206
1291
  switch (typeof data) {
@@ -1554,16 +1639,17 @@ const errorIntegerOutOfRange = create$3('Integer out of Range');
1554
1639
 
1555
1640
  /**
1556
1641
  * A Decoder handles the decoding of an Uint8Array.
1642
+ * @template {ArrayBufferLike} [Buf=ArrayBufferLike]
1557
1643
  */
1558
1644
  class Decoder {
1559
1645
  /**
1560
- * @param {Uint8Array} uint8Array Binary data to decode
1646
+ * @param {Uint8Array<Buf>} uint8Array Binary data to decode
1561
1647
  */
1562
1648
  constructor (uint8Array) {
1563
1649
  /**
1564
1650
  * Decoding target.
1565
1651
  *
1566
- * @type {Uint8Array}
1652
+ * @type {Uint8Array<Buf>}
1567
1653
  */
1568
1654
  this.arr = uint8Array;
1569
1655
  /**
@@ -1577,8 +1663,9 @@ class Decoder {
1577
1663
 
1578
1664
  /**
1579
1665
  * @function
1580
- * @param {Uint8Array} uint8Array
1581
- * @return {Decoder}
1666
+ * @template {ArrayBufferLike} Buf
1667
+ * @param {Uint8Array<Buf>} uint8Array
1668
+ * @return {Decoder<Buf>}
1582
1669
  */
1583
1670
  const createDecoder = uint8Array => new Decoder(uint8Array);
1584
1671
 
@@ -1596,9 +1683,10 @@ const hasContent = decoder => decoder.pos !== decoder.arr.length;
1596
1683
  * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
1597
1684
  *
1598
1685
  * @function
1599
- * @param {Decoder} decoder The decoder instance
1686
+ * @template {ArrayBufferLike} Buf
1687
+ * @param {Decoder<Buf>} decoder The decoder instance
1600
1688
  * @param {number} len The length of bytes to read
1601
- * @return {Uint8Array}
1689
+ * @return {Uint8Array<Buf>}
1602
1690
  */
1603
1691
  const readUint8Array = (decoder, len) => {
1604
1692
  const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
@@ -1613,8 +1701,9 @@ const readUint8Array = (decoder, len) => {
1613
1701
  * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
1614
1702
  *
1615
1703
  * @function
1616
- * @param {Decoder} decoder
1617
- * @return {Uint8Array}
1704
+ * @template {ArrayBufferLike} Buf
1705
+ * @param {Decoder<Buf>} decoder
1706
+ * @return {Uint8Array<Buf>}
1618
1707
  */
1619
1708
  const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder));
1620
1709
 
@@ -2070,12 +2159,38 @@ try {
2070
2159
  /* c8 ignore next */
2071
2160
  const varStorage = _localStorage;
2072
2161
 
2162
+ const EqualityTraitSymbol = Symbol('Equality');
2163
+
2073
2164
  /**
2074
- * Utility functions for working with EcmaScript objects.
2165
+ * @typedef {{ [EqualityTraitSymbol]:(other:EqualityTrait)=>boolean }} EqualityTrait
2166
+ */
2167
+
2168
+ /**
2169
+ *
2170
+ * Utility function to compare any two objects.
2075
2171
  *
2076
- * @module object
2172
+ * Note that it is expected that the first parameter is more specific than the latter one.
2173
+ *
2174
+ * @example js
2175
+ * class X { [traits.EqualityTraitSymbol] (other) { return other === this } }
2176
+ * class X2 { [traits.EqualityTraitSymbol] (other) { return other === this }, x2 () { return 2 } }
2177
+ * // this is fine
2178
+ * traits.equals(new X2(), new X())
2179
+ * // this is not, because the left type is less specific than the right one
2180
+ * traits.equals(new X(), new X2())
2181
+ *
2182
+ * @template {EqualityTrait} T
2183
+ * @param {NoInfer<T>} a
2184
+ * @param {T} b
2185
+ * @return {boolean}
2077
2186
  */
2187
+ const equals = (a, b) => a === b || !!a?.[EqualityTraitSymbol]?.(b) || false;
2078
2188
 
2189
+ /**
2190
+ * @param {any} o
2191
+ * @return {o is { [k:string]:any }}
2192
+ */
2193
+ const isObject$2 = o => typeof o === 'object';
2079
2194
 
2080
2195
  /**
2081
2196
  * Object.assign
@@ -2144,7 +2259,7 @@ const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
2144
2259
  * @param {Object<string,any>} b
2145
2260
  * @return {boolean}
2146
2261
  */
2147
- const equalFlat = (a, b) => a === b || (size(a) === size(b) && every(a, (val, key) => (val !== undefined || hasProperty(b, key)) && b[key] === val));
2262
+ const equalFlat = (a, b) => a === b || (size(a) === size(b) && every(a, (val, key) => (val !== undefined || hasProperty(b, key)) && equals(b[key], val)));
2148
2263
 
2149
2264
  /**
2150
2265
  * Make an object immutable. This hurts performance and is usually not needed if you perform good
@@ -2203,6 +2318,88 @@ const callAll = (fs, args, i = 0) => {
2203
2318
  */
2204
2319
  const id = a => a;
2205
2320
 
2321
+ /* c8 ignore start */
2322
+
2323
+ /**
2324
+ * @param {any} a
2325
+ * @param {any} b
2326
+ * @return {boolean}
2327
+ */
2328
+ const equalityDeep = (a, b) => {
2329
+ if (a === b) {
2330
+ return true
2331
+ }
2332
+ if (a == null || b == null || (a.constructor !== b.constructor && (a.constructor || Object) !== (b.constructor || Object))) {
2333
+ return false
2334
+ }
2335
+ if (a[EqualityTraitSymbol] != null) {
2336
+ return a[EqualityTraitSymbol](b)
2337
+ }
2338
+ switch (a.constructor) {
2339
+ case ArrayBuffer:
2340
+ a = new Uint8Array(a);
2341
+ b = new Uint8Array(b);
2342
+ // eslint-disable-next-line no-fallthrough
2343
+ case Uint8Array: {
2344
+ if (a.byteLength !== b.byteLength) {
2345
+ return false
2346
+ }
2347
+ for (let i = 0; i < a.length; i++) {
2348
+ if (a[i] !== b[i]) {
2349
+ return false
2350
+ }
2351
+ }
2352
+ break
2353
+ }
2354
+ case Set: {
2355
+ if (a.size !== b.size) {
2356
+ return false
2357
+ }
2358
+ for (const value of a) {
2359
+ if (!b.has(value)) {
2360
+ return false
2361
+ }
2362
+ }
2363
+ break
2364
+ }
2365
+ case Map: {
2366
+ if (a.size !== b.size) {
2367
+ return false
2368
+ }
2369
+ for (const key of a.keys()) {
2370
+ if (!b.has(key) || !equalityDeep(a.get(key), b.get(key))) {
2371
+ return false
2372
+ }
2373
+ }
2374
+ break
2375
+ }
2376
+ case undefined:
2377
+ case Object:
2378
+ if (size(a) !== size(b)) {
2379
+ return false
2380
+ }
2381
+ for (const key in a) {
2382
+ if (!hasProperty(a, key) || !equalityDeep(a[key], b[key])) {
2383
+ return false
2384
+ }
2385
+ }
2386
+ break
2387
+ case Array:
2388
+ if (a.length !== b.length) {
2389
+ return false
2390
+ }
2391
+ for (let i = 0; i < a.length; i++) {
2392
+ if (!equalityDeep(a[i], b[i])) {
2393
+ return false
2394
+ }
2395
+ }
2396
+ break
2397
+ default:
2398
+ return false
2399
+ }
2400
+ return true
2401
+ };
2402
+
2206
2403
  /**
2207
2404
  * @template V
2208
2405
  * @template {V} OPTS
@@ -2297,7 +2494,7 @@ const hasConf = (name) =>
2297
2494
  hasParam('--' + name) || getVariable(name) !== null;
2298
2495
 
2299
2496
  /* c8 ignore next */
2300
- hasConf('production');
2497
+ const production = hasConf('production');
2301
2498
 
2302
2499
  /* c8 ignore next 2 */
2303
2500
  const forceColor = isNode &&
@@ -2324,67 +2521,1281 @@ const supportsColor = forceColor || (
2324
2521
  /* c8 ignore stop */
2325
2522
 
2326
2523
  /**
2327
- * Utility functions to work with buffers (Uint8Array).
2524
+ * Utility functions to work with buffers (Uint8Array).
2525
+ *
2526
+ * @module buffer
2527
+ */
2528
+
2529
+
2530
+ /**
2531
+ * @param {number} len
2532
+ */
2533
+ const createUint8ArrayFromLen = len => new Uint8Array(len);
2534
+
2535
+ /**
2536
+ * Copy the content of an Uint8Array view to a new ArrayBuffer.
2537
+ *
2538
+ * @param {Uint8Array} uint8Array
2539
+ * @return {Uint8Array}
2540
+ */
2541
+ const copyUint8Array = uint8Array => {
2542
+ const newBuf = createUint8ArrayFromLen(uint8Array.byteLength);
2543
+ newBuf.set(uint8Array);
2544
+ return newBuf
2545
+ };
2546
+
2547
+ /**
2548
+ * Working with value pairs.
2549
+ *
2550
+ * @module pair
2551
+ */
2552
+
2553
+ /**
2554
+ * @template L,R
2555
+ */
2556
+ class Pair {
2557
+ /**
2558
+ * @param {L} left
2559
+ * @param {R} right
2560
+ */
2561
+ constructor (left, right) {
2562
+ this.left = left;
2563
+ this.right = right;
2564
+ }
2565
+ }
2566
+
2567
+ /**
2568
+ * @template L,R
2569
+ * @param {L} left
2570
+ * @param {R} right
2571
+ * @return {Pair<L,R>}
2572
+ */
2573
+ const create$1 = (left, right) => new Pair(left, right);
2574
+
2575
+ /**
2576
+ * Fast Pseudo Random Number Generators.
2577
+ *
2578
+ * Given a seed a PRNG generates a sequence of numbers that cannot be reasonably predicted.
2579
+ * Two PRNGs must generate the same random sequence of numbers if given the same seed.
2580
+ *
2581
+ * @module prng
2582
+ */
2583
+
2584
+
2585
+ /**
2586
+ * Generates a single random bool.
2587
+ *
2588
+ * @param {PRNG} gen A random number generator.
2589
+ * @return {Boolean} A random boolean
2590
+ */
2591
+ const bool = gen => (gen.next() >= 0.5);
2592
+
2593
+ /**
2594
+ * Generates a random integer with 53 bit resolution.
2595
+ *
2596
+ * @param {PRNG} gen A random number generator.
2597
+ * @param {Number} min The lower bound of the allowed return values (inclusive).
2598
+ * @param {Number} max The upper bound of the allowed return values (inclusive).
2599
+ * @return {Number} A random integer on [min, max]
2600
+ */
2601
+ const int53 = (gen, min, max) => floor$2(gen.next() * (max + 1 - min) + min);
2602
+
2603
+ /**
2604
+ * Generates a random integer with 32 bit resolution.
2605
+ *
2606
+ * @param {PRNG} gen A random number generator.
2607
+ * @param {Number} min The lower bound of the allowed return values (inclusive).
2608
+ * @param {Number} max The upper bound of the allowed return values (inclusive).
2609
+ * @return {Number} A random integer on [min, max]
2610
+ */
2611
+ const int32 = (gen, min, max) => floor$2(gen.next() * (max + 1 - min) + min);
2612
+
2613
+ /**
2614
+ * @deprecated
2615
+ * Optimized version of prng.int32. It has the same precision as prng.int32, but should be preferred when
2616
+ * openaring on smaller ranges.
2617
+ *
2618
+ * @param {PRNG} gen A random number generator.
2619
+ * @param {Number} min The lower bound of the allowed return values (inclusive).
2620
+ * @param {Number} max The upper bound of the allowed return values (inclusive). The max inclusive number is `binary.BITS31-1`
2621
+ * @return {Number} A random integer on [min, max]
2622
+ */
2623
+ const int31 = (gen, min, max) => int32(gen, min, max);
2624
+
2625
+ /**
2626
+ * @param {PRNG} gen
2627
+ * @return {string} A single letter (a-z)
2628
+ */
2629
+ const letter = gen => fromCharCode(int31(gen, 97, 122));
2630
+
2631
+ /**
2632
+ * @param {PRNG} gen
2633
+ * @param {number} [minLen=0]
2634
+ * @param {number} [maxLen=20]
2635
+ * @return {string} A random word (0-20 characters) without spaces consisting of letters (a-z)
2636
+ */
2637
+ const word = (gen, minLen = 0, maxLen = 20) => {
2638
+ const len = int31(gen, minLen, maxLen);
2639
+ let str = '';
2640
+ for (let i = 0; i < len; i++) {
2641
+ str += letter(gen);
2642
+ }
2643
+ return str
2644
+ };
2645
+
2646
+ /**
2647
+ * Returns one element of a given array.
2648
+ *
2649
+ * @param {PRNG} gen A random number generator.
2650
+ * @param {Array<T>} array Non empty Array of possible values.
2651
+ * @return {T} One of the values of the supplied Array.
2652
+ * @template T
2653
+ */
2654
+ const oneOf = (gen, array) => array[int31(gen, 0, array.length - 1)];
2655
+ /* c8 ignore stop */
2656
+
2657
+ /**
2658
+ * @experimental WIP
2659
+ *
2660
+ * Simple & efficient schemas for your data.
2661
+ */
2662
+
2663
+
2664
+ /**
2665
+ * @typedef {string|number|bigint|boolean|null|undefined|symbol} Primitive
2666
+ */
2667
+
2668
+ /**
2669
+ * @typedef {{ [k:string|number|symbol]: any }} AnyObject
2670
+ */
2671
+
2672
+ /**
2673
+ * @template T
2674
+ * @typedef {T extends Schema<infer X> ? X : T} Unwrap
2675
+ */
2676
+
2677
+ /**
2678
+ * @template T
2679
+ * @typedef {T extends Schema<infer X> ? X : T} TypeOf
2680
+ */
2681
+
2682
+ /**
2683
+ * @template {readonly unknown[]} T
2684
+ * @typedef {T extends readonly [Schema<infer First>, ...infer Rest] ? [First, ...UnwrapArray<Rest>] : [] } UnwrapArray
2685
+ */
2686
+
2687
+ /**
2688
+ * @template T
2689
+ * @typedef {T extends Schema<infer S> ? Schema<S> : never} CastToSchema
2690
+ */
2691
+
2692
+ /**
2693
+ * @template {unknown[]} Arr
2694
+ * @typedef {Arr extends [...unknown[], infer L] ? L : never} TupleLast
2695
+ */
2696
+
2697
+ /**
2698
+ * @template {unknown[]} Arr
2699
+ * @typedef {Arr extends [...infer Fs, unknown] ? Fs : never} TuplePop
2700
+ */
2701
+
2702
+ /**
2703
+ * @template {readonly unknown[]} T
2704
+ * @typedef {T extends []
2705
+ * ? {}
2706
+ * : T extends [infer First]
2707
+ * ? First
2708
+ * : T extends [infer First, ...infer Rest]
2709
+ * ? First & Intersect<Rest>
2710
+ * : never
2711
+ * } Intersect
2712
+ */
2713
+
2714
+ const schemaSymbol = Symbol('0schema');
2715
+
2716
+ class ValidationError {
2717
+ constructor () {
2718
+ /**
2719
+ * Reverse errors
2720
+ * @type {Array<{ path: string?, expected: string, has: string, message: string? }>}
2721
+ */
2722
+ this._rerrs = [];
2723
+ }
2724
+
2725
+ /**
2726
+ * @param {string?} path
2727
+ * @param {string} expected
2728
+ * @param {string} has
2729
+ * @param {string?} message
2730
+ */
2731
+ extend (path, expected, has, message = null) {
2732
+ this._rerrs.push({ path, expected, has, message });
2733
+ }
2734
+
2735
+ toString () {
2736
+ const s = [];
2737
+ for (let i = this._rerrs.length - 1; i > 0; i--) {
2738
+ const r = this._rerrs[i];
2739
+ /* c8 ignore next */
2740
+ s.push(repeat(' ', (this._rerrs.length - i) * 2) + `${r.path != null ? `[${r.path}] ` : ''}${r.has} doesn't match ${r.expected}. ${r.message}`);
2741
+ }
2742
+ return s.join('\n')
2743
+ }
2744
+ }
2745
+
2746
+ /**
2747
+ * @param {any} a
2748
+ * @param {any} b
2749
+ * @return {boolean}
2750
+ */
2751
+ const shapeExtends = (a, b) => {
2752
+ if (a === b) return true
2753
+ if (a == null || b == null || a.constructor !== b.constructor) return false
2754
+ if (a[EqualityTraitSymbol]) return equals(a, b) // last resort: check equality (do this before array and obj check which don't implement the equality trait)
2755
+ if (isArray$1(a)) {
2756
+ return every$1(a, aitem =>
2757
+ some(b, bitem => shapeExtends(aitem, bitem))
2758
+ )
2759
+ } else if (isObject$2(a)) {
2760
+ return every(a, (aitem, akey) =>
2761
+ shapeExtends(aitem, b[akey])
2762
+ )
2763
+ }
2764
+ /* c8 ignore next */
2765
+ return false
2766
+ };
2767
+
2768
+ /**
2769
+ * @template T
2770
+ * @implements {equalityTraits.EqualityTrait}
2771
+ */
2772
+ class Schema {
2773
+ // this.shape must not be defined on Schema. Otherwise typecheck on metatypes (e.g. $$object) won't work as expected anymore
2774
+ /**
2775
+ * If true, the more things are added to the shape the more objects this schema will accept (e.g.
2776
+ * union). By default, the more objects are added, the the fewer objects this schema will accept.
2777
+ * @protected
2778
+ */
2779
+ static _dilutes = false
2780
+
2781
+ /**
2782
+ * @param {Schema<any>} other
2783
+ */
2784
+ extends (other) {
2785
+ let [a, b] = [/** @type {any} */(this).shape, /** @type {any} */ (other).shape];
2786
+ if (/** @type {typeof Schema<any>} */ (this.constructor)._dilutes) [b, a] = [a, b];
2787
+ return shapeExtends(a, b)
2788
+ }
2789
+
2790
+ /**
2791
+ * Overwrite this when necessary. By default, we only check the `shape` property which every shape
2792
+ * should have.
2793
+ * @param {Schema<any>} other
2794
+ */
2795
+ equals (other) {
2796
+ // @ts-ignore
2797
+ return this.constructor === other.constructor && equalityDeep(this.shape, other.shape)
2798
+ }
2799
+
2800
+ [schemaSymbol] () { return true }
2801
+
2802
+ /**
2803
+ * @param {object} other
2804
+ */
2805
+ [EqualityTraitSymbol] (other) {
2806
+ return this.equals(/** @type {any} */ (other))
2807
+ }
2808
+
2809
+ /**
2810
+ * Use `schema.validate(obj)` with a typed parameter that is already of typed to be an instance of
2811
+ * Schema. Validate will check the structure of the parameter and return true iff the instance
2812
+ * really is an instance of Schema.
2813
+ *
2814
+ * @param {T} o
2815
+ * @return {boolean}
2816
+ */
2817
+ validate (o) {
2818
+ return this.check(o)
2819
+ }
2820
+
2821
+ /* c8 ignore start */
2822
+ /**
2823
+ * Similar to validate, but this method accepts untyped parameters.
2824
+ *
2825
+ * @param {any} _o
2826
+ * @param {ValidationError} [_err]
2827
+ * @return {_o is T}
2828
+ */
2829
+ check (_o, _err) {
2830
+ methodUnimplemented();
2831
+ }
2832
+ /* c8 ignore stop */
2833
+
2834
+ /**
2835
+ * @type {Schema<T?>}
2836
+ */
2837
+ get nullable () {
2838
+ // @ts-ignore
2839
+ return $union(this, $null)
2840
+ }
2841
+
2842
+ /**
2843
+ * @type {$Optional<Schema<T>>}
2844
+ */
2845
+ get optional () {
2846
+ return new $Optional(/** @type {Schema<T>} */ (this))
2847
+ }
2848
+
2849
+ /**
2850
+ * Cast a variable to a specific type. Returns the casted value, or throws an exception otherwise.
2851
+ * Use this if you know that the type is of a specific type and you just want to convince the type
2852
+ * system.
2853
+ *
2854
+ * **Do not rely on these error messages!**
2855
+ * Performs an assertion check only if not in a production environment.
2856
+ *
2857
+ * @template OO
2858
+ * @param {OO} o
2859
+ * @return {Extract<OO, T> extends never ? T : (OO extends Array<never> ? T : Extract<OO,T>)}
2860
+ */
2861
+ cast (o) {
2862
+ assert(o, this);
2863
+ return /** @type {any} */ (o)
2864
+ }
2865
+
2866
+ /**
2867
+ * EXPECTO PATRONUM!! 🪄
2868
+ * This function protects against type errors. Though it may not work in the real world.
2869
+ *
2870
+ * "After all this time?"
2871
+ * "Always." - Snape, talking about type safety
2872
+ *
2873
+ * Ensures that a variable is a a specific type. Returns the value, or throws an exception if the assertion check failed.
2874
+ * Use this if you know that the type is of a specific type and you just want to convince the type
2875
+ * system.
2876
+ *
2877
+ * Can be useful when defining lambdas: `s.lambda(s.$number, s.$void).expect((n) => n + 1)`
2878
+ *
2879
+ * **Do not rely on these error messages!**
2880
+ * Performs an assertion check if not in a production environment.
2881
+ *
2882
+ * @param {T} o
2883
+ * @return {o extends T ? T : never}
2884
+ */
2885
+ expect (o) {
2886
+ assert(o, this);
2887
+ return o
2888
+ }
2889
+ }
2890
+
2891
+ /**
2892
+ * @template {(new (...args:any[]) => any) | ((...args:any[]) => any)} Constr
2893
+ * @typedef {Constr extends ((...args:any[]) => infer T) ? T : (Constr extends (new (...args:any[]) => any) ? InstanceType<Constr> : never)} Instance
2894
+ */
2895
+
2896
+ /**
2897
+ * @template {(new (...args:any[]) => any) | ((...args:any[]) => any)} C
2898
+ * @extends {Schema<Instance<C>>}
2899
+ */
2900
+ class $ConstructedBy extends Schema {
2901
+ /**
2902
+ * @param {C} c
2903
+ * @param {((o:Instance<C>)=>boolean)|null} check
2904
+ */
2905
+ constructor (c, check) {
2906
+ super();
2907
+ this.shape = c;
2908
+ this._c = check;
2909
+ }
2910
+
2911
+ /**
2912
+ * @param {any} o
2913
+ * @param {ValidationError} [err]
2914
+ * @return {o is C extends ((...args:any[]) => infer T) ? T : (C extends (new (...args:any[]) => any) ? InstanceType<C> : never)} o
2915
+ */
2916
+ check (o, err = undefined) {
2917
+ const c = o?.constructor === this.shape && (this._c == null || this._c(o));
2918
+ /* c8 ignore next */
2919
+ !c && err?.extend(null, this.shape.name, o?.constructor.name, o?.constructor !== this.shape ? 'Constructor match failed' : 'Check failed');
2920
+ return c
2921
+ }
2922
+ }
2923
+
2924
+ /**
2925
+ * @template {(new (...args:any[]) => any) | ((...args:any[]) => any)} C
2926
+ * @param {C} c
2927
+ * @param {((o:Instance<C>) => boolean)|null} check
2928
+ * @return {CastToSchema<$ConstructedBy<C>>}
2929
+ */
2930
+ const $constructedBy = (c, check = null) => new $ConstructedBy(c, check);
2931
+ $constructedBy($ConstructedBy);
2932
+
2933
+ /**
2934
+ * Check custom properties on any object. You may want to overwrite the generated Schema<any>.
2935
+ *
2936
+ * @extends {Schema<any>}
2937
+ */
2938
+ class $Custom extends Schema {
2939
+ /**
2940
+ * @param {(o:any) => boolean} check
2941
+ */
2942
+ constructor (check) {
2943
+ super();
2944
+ /**
2945
+ * @type {(o:any) => boolean}
2946
+ */
2947
+ this.shape = check;
2948
+ }
2949
+
2950
+ /**
2951
+ * @param {any} o
2952
+ * @param {ValidationError} err
2953
+ * @return {o is any}
2954
+ */
2955
+ check (o, err) {
2956
+ const c = this.shape(o);
2957
+ /* c8 ignore next */
2958
+ !c && err?.extend(null, 'custom prop', o?.constructor.name, 'failed to check custom prop');
2959
+ return c
2960
+ }
2961
+ }
2962
+
2963
+ /**
2964
+ * @param {(o:any) => boolean} check
2965
+ * @return {Schema<any>}
2966
+ */
2967
+ const $custom = (check) => new $Custom(check);
2968
+ $constructedBy($Custom);
2969
+
2970
+ /**
2971
+ * @template {Primitive} T
2972
+ * @extends {Schema<T>}
2973
+ */
2974
+ class $Literal extends Schema {
2975
+ /**
2976
+ * @param {Array<T>} literals
2977
+ */
2978
+ constructor (literals) {
2979
+ super();
2980
+ this.shape = literals;
2981
+ }
2982
+
2983
+ /**
2984
+ *
2985
+ * @param {any} o
2986
+ * @param {ValidationError} [err]
2987
+ * @return {o is T}
2988
+ */
2989
+ check (o, err) {
2990
+ const c = this.shape.some(a => a === o);
2991
+ /* c8 ignore next */
2992
+ !c && err?.extend(null, this.shape.join(' | '), o.toString());
2993
+ return c
2994
+ }
2995
+ }
2996
+
2997
+ /**
2998
+ * @template {Primitive[]} T
2999
+ * @param {T} literals
3000
+ * @return {CastToSchema<$Literal<T[number]>>}
3001
+ */
3002
+ const $literal = (...literals) => new $Literal(literals);
3003
+ const $$literal = $constructedBy($Literal);
3004
+
3005
+ /**
3006
+ * @template {Array<string|Schema<string|number>>} Ts
3007
+ * @typedef {Ts extends [] ? `` : (Ts extends [infer T] ? (Unwrap<T> extends (string|number) ? Unwrap<T> : never) : (Ts extends [infer T1, ...infer Rest] ? `${Unwrap<T1> extends (string|number) ? Unwrap<T1> : never}${Rest extends Array<string|Schema<string|number>> ? CastStringTemplateArgsToTemplate<Rest> : never}` : never))} CastStringTemplateArgsToTemplate
3008
+ */
3009
+
3010
+ /**
3011
+ * @param {string} str
3012
+ * @return {string}
3013
+ */
3014
+ const _regexEscape = /** @type {any} */ (RegExp).escape || /** @type {(str:string) => string} */ (str =>
3015
+ str.replace(/[().|&,$^[\]]/g, s => '\\' + s)
3016
+ );
3017
+
3018
+ /**
3019
+ * @param {string|Schema<any>} s
3020
+ * @return {string[]}
3021
+ */
3022
+ const _schemaStringTemplateToRegex = s => {
3023
+ if ($string.check(s)) {
3024
+ return [_regexEscape(s)]
3025
+ }
3026
+ if ($$literal.check(s)) {
3027
+ return /** @type {Array<string|number>} */ (s.shape).map(v => v + '')
3028
+ }
3029
+ if ($$number.check(s)) {
3030
+ return ['[+-]?\\d+.?\\d*']
3031
+ }
3032
+ if ($$string.check(s)) {
3033
+ return ['.*']
3034
+ }
3035
+ if ($$union.check(s)) {
3036
+ return s.shape.map(_schemaStringTemplateToRegex).flat(1)
3037
+ }
3038
+ /* c8 ignore next 2 */
3039
+ // unexpected schema structure (only supports unions and string in literal types)
3040
+ unexpectedCase();
3041
+ };
3042
+
3043
+ /**
3044
+ * @template {Array<string|Schema<string|number>>} T
3045
+ * @extends {Schema<CastStringTemplateArgsToTemplate<T>>}
3046
+ */
3047
+ class $StringTemplate extends Schema {
3048
+ /**
3049
+ * @param {T} shape
3050
+ */
3051
+ constructor (shape) {
3052
+ super();
3053
+ this.shape = shape;
3054
+ this._r = new RegExp('^' + shape.map(_schemaStringTemplateToRegex).map(opts => `(${opts.join('|')})`).join('') + '$');
3055
+ }
3056
+
3057
+ /**
3058
+ * @param {any} o
3059
+ * @param {ValidationError} [err]
3060
+ * @return {o is CastStringTemplateArgsToTemplate<T>}
3061
+ */
3062
+ check (o, err) {
3063
+ const c = this._r.exec(o) != null;
3064
+ /* c8 ignore next */
3065
+ !c && err?.extend(null, this._r.toString(), o.toString(), 'String doesn\'t match string template.');
3066
+ return c
3067
+ }
3068
+ }
3069
+ $constructedBy($StringTemplate);
3070
+
3071
+ const isOptionalSymbol = Symbol('optional');
3072
+ /**
3073
+ * @template {Schema<any>} S
3074
+ * @extends Schema<Unwrap<S>|undefined>
3075
+ */
3076
+ class $Optional extends Schema {
3077
+ /**
3078
+ * @param {S} shape
3079
+ */
3080
+ constructor (shape) {
3081
+ super();
3082
+ this.shape = shape;
3083
+ }
3084
+
3085
+ /**
3086
+ * @param {any} o
3087
+ * @param {ValidationError} [err]
3088
+ * @return {o is (Unwrap<S>|undefined)}
3089
+ */
3090
+ check (o, err) {
3091
+ const c = o === undefined || this.shape.check(o);
3092
+ /* c8 ignore next */
3093
+ !c && err?.extend(null, 'undefined (optional)', '()');
3094
+ return c
3095
+ }
3096
+
3097
+ get [isOptionalSymbol] () { return true }
3098
+ }
3099
+ const $$optional = $constructedBy($Optional);
3100
+
3101
+ /**
3102
+ * @extends Schema<never>
3103
+ */
3104
+ class $Never extends Schema {
3105
+ /**
3106
+ * @param {any} _o
3107
+ * @param {ValidationError} [err]
3108
+ * @return {_o is never}
3109
+ */
3110
+ check (_o, err) {
3111
+ /* c8 ignore next */
3112
+ err?.extend(null, 'never', typeof _o);
3113
+ return false
3114
+ }
3115
+ }
3116
+ $constructedBy($Never);
3117
+
3118
+ /**
3119
+ * @template {{ [key: string|symbol|number]: Schema<any> }} S
3120
+ * @typedef {{ [Key in keyof S as S[Key] extends $Optional<Schema<any>> ? Key : never]?: S[Key] extends $Optional<Schema<infer Type>> ? Type : never } & { [Key in keyof S as S[Key] extends $Optional<Schema<any>> ? never : Key]: S[Key] extends Schema<infer Type> ? Type : never }} $ObjectToType
3121
+ */
3122
+
3123
+ /**
3124
+ * @template {{[key:string|symbol|number]: Schema<any>}} S
3125
+ * @extends {Schema<$ObjectToType<S>>}
3126
+ */
3127
+ let $Object$3 = class $Object extends Schema {
3128
+ /**
3129
+ * @param {S} shape
3130
+ * @param {boolean} partial
3131
+ */
3132
+ constructor (shape, partial = false) {
3133
+ super();
3134
+ /**
3135
+ * @type {S}
3136
+ */
3137
+ this.shape = shape;
3138
+ this._isPartial = partial;
3139
+ }
3140
+
3141
+ static _dilutes = true
3142
+
3143
+ /**
3144
+ * @type {Schema<Partial<$ObjectToType<S>>>}
3145
+ */
3146
+ get partial () {
3147
+ return new $Object(this.shape, true)
3148
+ }
3149
+
3150
+ /**
3151
+ * @param {any} o
3152
+ * @param {ValidationError} err
3153
+ * @return {o is $ObjectToType<S>}
3154
+ */
3155
+ check (o, err) {
3156
+ if (o == null) {
3157
+ /* c8 ignore next */
3158
+ err?.extend(null, 'object', 'null');
3159
+ return false
3160
+ }
3161
+ return every(this.shape, (vv, vk) => {
3162
+ const c = (this._isPartial && !hasProperty(o, vk)) || vv.check(o[vk], err);
3163
+ !c && err?.extend(vk.toString(), vv.toString(), typeof o[vk], 'Object property does not match');
3164
+ return c
3165
+ })
3166
+ }
3167
+ };
3168
+
3169
+ /**
3170
+ * @template S
3171
+ * @typedef {Schema<{ [Key in keyof S as S[Key] extends $Optional<Schema<any>> ? Key : never]?: S[Key] extends $Optional<Schema<infer Type>> ? Type : never } & { [Key in keyof S as S[Key] extends $Optional<Schema<any>> ? never : Key]: S[Key] extends Schema<infer Type> ? Type : never }>} _ObjectDefToSchema
3172
+ */
3173
+
3174
+ // I used an explicit type annotation instead of $ObjectToType, so that the user doesn't see the
3175
+ // weird type definitions when inspecting type definions.
3176
+ /**
3177
+ * @template {{ [key:string|symbol|number]: Schema<any> }} S
3178
+ * @param {S} def
3179
+ * @return {_ObjectDefToSchema<S> extends Schema<infer S> ? Schema<{ [K in keyof S]: S[K] }> : never}
3180
+ */
3181
+ const $object = def => /** @type {any} */ (new $Object$3(def));
3182
+ const $$object = $constructedBy($Object$3);
3183
+ /**
3184
+ * @type {Schema<{[key:string]: any}>}
3185
+ */
3186
+ const $objectAny = $custom(o => o != null && (o.constructor === Object || o.constructor == null));
3187
+
3188
+ /**
3189
+ * @template {Schema<string|number|symbol>} Keys
3190
+ * @template {Schema<any>} Values
3191
+ * @extends {Schema<{ [key in Unwrap<Keys>]: Unwrap<Values> }>}
3192
+ */
3193
+ class $Record extends Schema {
3194
+ /**
3195
+ * @param {Keys} keys
3196
+ * @param {Values} values
3197
+ */
3198
+ constructor (keys, values) {
3199
+ super();
3200
+ this.shape = {
3201
+ keys, values
3202
+ };
3203
+ }
3204
+
3205
+ /**
3206
+ * @param {any} o
3207
+ * @param {ValidationError} err
3208
+ * @return {o is { [key in Unwrap<Keys>]: Unwrap<Values> }}
3209
+ */
3210
+ check (o, err) {
3211
+ return o != null && every(o, (vv, vk) => {
3212
+ const ck = this.shape.keys.check(vk, err);
3213
+ /* c8 ignore next */
3214
+ !ck && err?.extend(vk + '', 'Record', typeof o, ck ? 'Key doesn\'t match schema' : 'Value doesn\'t match value');
3215
+ return ck && this.shape.values.check(vv, err)
3216
+ })
3217
+ }
3218
+ }
3219
+
3220
+ /**
3221
+ * @template {Schema<string|number|symbol>} Keys
3222
+ * @template {Schema<any>} Values
3223
+ * @param {Keys} keys
3224
+ * @param {Values} values
3225
+ * @return {CastToSchema<$Record<Keys,Values>>}
3226
+ */
3227
+ const $record = (keys, values) => new $Record(keys, values);
3228
+ const $$record = $constructedBy($Record);
3229
+
3230
+ /**
3231
+ * @template {Schema<any>[]} S
3232
+ * @extends {Schema<{ [Key in keyof S]: S[Key] extends Schema<infer Type> ? Type : never }>}
3233
+ */
3234
+ class $Tuple extends Schema {
3235
+ /**
3236
+ * @param {S} shape
3237
+ */
3238
+ constructor (shape) {
3239
+ super();
3240
+ this.shape = shape;
3241
+ }
3242
+
3243
+ /**
3244
+ * @param {any} o
3245
+ * @param {ValidationError} err
3246
+ * @return {o is { [K in keyof S]: S[K] extends Schema<infer Type> ? Type : never }}
3247
+ */
3248
+ check (o, err) {
3249
+ return o != null && every(this.shape, (vv, vk) => {
3250
+ const c = /** @type {Schema<any>} */ (vv).check(o[vk], err);
3251
+ /* c8 ignore next */
3252
+ !c && err?.extend(vk.toString(), 'Tuple', typeof vv);
3253
+ return c
3254
+ })
3255
+ }
3256
+ }
3257
+
3258
+ /**
3259
+ * @template {Array<Schema<any>>} T
3260
+ * @param {T} def
3261
+ * @return {CastToSchema<$Tuple<T>>}
3262
+ */
3263
+ const $tuple = (...def) => new $Tuple(def);
3264
+ $constructedBy($Tuple);
3265
+
3266
+ /**
3267
+ * @template {Schema<any>} S
3268
+ * @extends {Schema<Array<S extends Schema<infer T> ? T : never>>}
3269
+ */
3270
+ class $Array extends Schema {
3271
+ /**
3272
+ * @param {Array<S>} v
3273
+ */
3274
+ constructor (v) {
3275
+ super();
3276
+ /**
3277
+ * @type {Schema<S extends Schema<infer T> ? T : never>}
3278
+ */
3279
+ this.shape = v.length === 1 ? v[0] : new $Union(v);
3280
+ }
3281
+
3282
+ /**
3283
+ * @param {any} o
3284
+ * @param {ValidationError} [err]
3285
+ * @return {o is Array<S extends Schema<infer T> ? T : never>} o
3286
+ */
3287
+ check (o, err) {
3288
+ const c = isArray$1(o) && every$1(o, oi => this.shape.check(oi));
3289
+ /* c8 ignore next */
3290
+ !c && err?.extend(null, 'Array', '');
3291
+ return c
3292
+ }
3293
+ }
3294
+
3295
+ /**
3296
+ * @template {Array<Schema<any>>} T
3297
+ * @param {T} def
3298
+ * @return {Schema<Array<T extends Array<Schema<infer S>> ? S : never>>}
3299
+ */
3300
+ const $array = (...def) => new $Array(def);
3301
+ const $$array = $constructedBy($Array);
3302
+ /**
3303
+ * @type {Schema<Array<any>>}
3304
+ */
3305
+ const $arrayAny = $custom(o => isArray$1(o));
3306
+
3307
+ /**
3308
+ * @template T
3309
+ * @extends {Schema<T>}
3310
+ */
3311
+ class $InstanceOf extends Schema {
3312
+ /**
3313
+ * @param {new (...args:any) => T} constructor
3314
+ * @param {((o:T) => boolean)|null} check
3315
+ */
3316
+ constructor (constructor, check) {
3317
+ super();
3318
+ this.shape = constructor;
3319
+ this._c = check;
3320
+ }
3321
+
3322
+ /**
3323
+ * @param {any} o
3324
+ * @param {ValidationError} err
3325
+ * @return {o is T}
3326
+ */
3327
+ check (o, err) {
3328
+ const c = o instanceof this.shape && (this._c == null || this._c(o));
3329
+ /* c8 ignore next */
3330
+ !c && err?.extend(null, this.shape.name, o?.constructor.name);
3331
+ return c
3332
+ }
3333
+ }
3334
+
3335
+ /**
3336
+ * @template T
3337
+ * @param {new (...args:any) => T} c
3338
+ * @param {((o:T) => boolean)|null} check
3339
+ * @return {Schema<T>}
3340
+ */
3341
+ const $instanceOf = (c, check = null) => new $InstanceOf(c, check);
3342
+ $constructedBy($InstanceOf);
3343
+
3344
+ const $$schema = $instanceOf(Schema);
3345
+
3346
+ /**
3347
+ * @template {Schema<any>[]} Args
3348
+ * @typedef {(...args:UnwrapArray<TuplePop<Args>>)=>Unwrap<TupleLast<Args>>} _LArgsToLambdaDef
3349
+ */
3350
+
3351
+ /**
3352
+ * @template {Array<Schema<any>>} Args
3353
+ * @extends {Schema<_LArgsToLambdaDef<Args>>}
3354
+ */
3355
+ class $Lambda extends Schema {
3356
+ /**
3357
+ * @param {Args} args
3358
+ */
3359
+ constructor (args) {
3360
+ super();
3361
+ this.len = args.length - 1;
3362
+ this.args = $tuple(...args.slice(-1));
3363
+ this.res = args[this.len];
3364
+ }
3365
+
3366
+ /**
3367
+ * @param {any} f
3368
+ * @param {ValidationError} err
3369
+ * @return {f is _LArgsToLambdaDef<Args>}
3370
+ */
3371
+ check (f, err) {
3372
+ const c = f.constructor === Function && f.length <= this.len;
3373
+ /* c8 ignore next */
3374
+ !c && err?.extend(null, 'function', typeof f);
3375
+ return c
3376
+ }
3377
+ }
3378
+ const $$lambda = $constructedBy($Lambda);
3379
+
3380
+ /**
3381
+ * @type {Schema<Function>}
3382
+ */
3383
+ const $function = $custom(o => typeof o === 'function');
3384
+
3385
+ /**
3386
+ * @template {Array<Schema<any>>} T
3387
+ * @extends {Schema<Intersect<UnwrapArray<T>>>}
3388
+ */
3389
+ class $Intersection extends Schema {
3390
+ /**
3391
+ * @param {T} v
3392
+ */
3393
+ constructor (v) {
3394
+ super();
3395
+ /**
3396
+ * @type {T}
3397
+ */
3398
+ this.shape = v;
3399
+ }
3400
+
3401
+ /**
3402
+ * @param {any} o
3403
+ * @param {ValidationError} [err]
3404
+ * @return {o is Intersect<UnwrapArray<T>>}
3405
+ */
3406
+ check (o, err) {
3407
+ // @ts-ignore
3408
+ const c = every$1(this.shape, check => check.check(o, err));
3409
+ /* c8 ignore next */
3410
+ !c && err?.extend(null, 'Intersectinon', typeof o);
3411
+ return c
3412
+ }
3413
+ }
3414
+ $constructedBy($Intersection, o => o.shape.length > 0); // Intersection with length=0 is considered "any"
3415
+
3416
+ /**
3417
+ * @template S
3418
+ * @extends {Schema<S>}
3419
+ */
3420
+ class $Union extends Schema {
3421
+ static _dilutes = true
3422
+
3423
+ /**
3424
+ * @param {Array<Schema<S>>} v
3425
+ */
3426
+ constructor (v) {
3427
+ super();
3428
+ this.shape = v;
3429
+ }
3430
+
3431
+ /**
3432
+ * @param {any} o
3433
+ * @param {ValidationError} [err]
3434
+ * @return {o is S}
3435
+ */
3436
+ check (o, err) {
3437
+ const c = some(this.shape, (vv) => vv.check(o, err));
3438
+ err?.extend(null, 'Union', typeof o);
3439
+ return c
3440
+ }
3441
+ }
3442
+
3443
+ /**
3444
+ * @template {Array<any>} T
3445
+ * @param {T} schemas
3446
+ * @return {CastToSchema<$Union<Unwrap<ReadSchema<T>>>>}
3447
+ */
3448
+ const $union = (...schemas) => schemas.findIndex($s => $$union.check($s)) >= 0
3449
+ ? $union(...schemas.map($s => $($s)).map($s => $$union.check($s) ? $s.shape : [$s]).flat(1))
3450
+ : (schemas.length === 1
3451
+ ? schemas[0]
3452
+ : new $Union(schemas));
3453
+ const $$union = /** @type {Schema<$Union<any>>} */ ($constructedBy($Union));
3454
+
3455
+ const _t = () => true;
3456
+ /**
3457
+ * @type {Schema<any>}
3458
+ */
3459
+ const $any = $custom(_t);
3460
+ const $$any = /** @type {Schema<Schema<any>>} */ ($constructedBy($Custom, o => o.shape === _t));
3461
+
3462
+ /**
3463
+ * @type {Schema<bigint>}
3464
+ */
3465
+ const $bigint = $custom(o => typeof o === 'bigint');
3466
+ const $$bigint = /** @type {Schema<Schema<BigInt>>} */ ($custom(o => o === $bigint));
3467
+
3468
+ /**
3469
+ * @type {Schema<symbol>}
3470
+ */
3471
+ const $symbol = $custom(o => typeof o === 'symbol');
3472
+ /** @type {Schema<Schema<Symbol>>} */ ($custom(o => o === $symbol));
3473
+
3474
+ /**
3475
+ * @type {Schema<number>}
3476
+ */
3477
+ const $number = $custom(o => typeof o === 'number');
3478
+ const $$number = /** @type {Schema<Schema<number>>} */ ($custom(o => o === $number));
3479
+
3480
+ /**
3481
+ * @type {Schema<string>}
3482
+ */
3483
+ const $string = $custom(o => typeof o === 'string');
3484
+ const $$string = /** @type {Schema<Schema<string>>} */ ($custom(o => o === $string));
3485
+
3486
+ /**
3487
+ * @type {Schema<boolean>}
3488
+ */
3489
+ const $boolean = $custom(o => typeof o === 'boolean');
3490
+ const $$boolean = /** @type {Schema<Schema<Boolean>>} */ ($custom(o => o === $boolean));
3491
+
3492
+ /**
3493
+ * @type {Schema<undefined>}
3494
+ */
3495
+ const $undefined = $literal(undefined);
3496
+ /** @type {Schema<Schema<undefined>>} */ ($constructedBy($Literal, o => o.shape.length === 1 && o.shape[0] === undefined));
3497
+
3498
+ /**
3499
+ * @type {Schema<void>}
3500
+ */
3501
+ $literal(undefined);
3502
+
3503
+ const $null = $literal(null);
3504
+ const $$null = /** @type {Schema<Schema<null>>} */ ($constructedBy($Literal, o => o.shape.length === 1 && o.shape[0] === null));
3505
+
3506
+ $constructedBy(Uint8Array);
3507
+ /** @type {Schema<Schema<Uint8Array>>} */ ($constructedBy($ConstructedBy, o => o.shape === Uint8Array));
3508
+
3509
+ /**
3510
+ * @type {Schema<Primitive>}
3511
+ */
3512
+ const $primitive = $union($number, $string, $null, $undefined, $bigint, $boolean, $symbol);
3513
+
3514
+ /**
3515
+ * @typedef {JSON[]} JSONArray
3516
+ */
3517
+ /**
3518
+ * @typedef {Primitive|JSONArray|{ [key:string]:JSON }} JSON
3519
+ */
3520
+ /**
3521
+ * @type {Schema<null|number|string|boolean|JSON[]|{[key:string]:JSON}>}
3522
+ */
3523
+ (() => {
3524
+ const $jsonArr = /** @type {$Array<$any>} */ ($array($any));
3525
+ const $jsonRecord = /** @type {$Record<$string,$any>} */ ($record($string, $any));
3526
+ const $json = $union($number, $string, $null, $boolean, $jsonArr, $jsonRecord);
3527
+ $jsonArr.shape = $json;
3528
+ $jsonRecord.shape.values = $json;
3529
+ return $json
3530
+ })();
3531
+
3532
+ /**
3533
+ * @template {any} IN
3534
+ * @typedef {IN extends Schema<any> ? IN
3535
+ * : (IN extends string|number|boolean|null ? Schema<IN>
3536
+ * : (IN extends new (...args:any[])=>any ? Schema<InstanceType<IN>>
3537
+ * : (IN extends any[] ? Schema<{ [K in keyof IN]: Unwrap<ReadSchema<IN[K]>> }[number]>
3538
+ * : (IN extends object ? (_ObjectDefToSchema<{[K in keyof IN]:ReadSchema<IN[K]>}> extends Schema<infer S> ? Schema<{ [K in keyof S]: S[K] }> : never)
3539
+ * : never)
3540
+ * )
3541
+ * )
3542
+ * )
3543
+ * } ReadSchemaOld
3544
+ */
3545
+
3546
+ /**
3547
+ * @template {any} IN
3548
+ * @typedef {[Extract<IN,Schema<any>>,Extract<IN,string|number|boolean|null>,Extract<IN,new (...args:any[])=>any>,Extract<IN,any[]>,Extract<Exclude<IN,Schema<any>|string|number|boolean|null|(new (...args:any[])=>any)|any[]>,object>] extends [infer Schemas, infer Primitives, infer Constructors, infer Arrs, infer Obj]
3549
+ * ? Schema<
3550
+ * (Schemas extends Schema<infer S> ? S : never)
3551
+ * | Primitives
3552
+ * | (Constructors extends new (...args:any[])=>any ? InstanceType<Constructors> : never)
3553
+ * | (Arrs extends any[] ? { [K in keyof Arrs]: Unwrap<ReadSchema<Arrs[K]>> }[number] : never)
3554
+ * | (Obj extends object ? Unwrap<(_ObjectDefToSchema<{[K in keyof Obj]:ReadSchema<Obj[K]>}> extends Schema<infer S> ? Schema<{ [K in keyof S]: S[K] }> : never)> : never)>
3555
+ * : never
3556
+ * } ReadSchema
3557
+ */
3558
+
3559
+ /**
3560
+ * @typedef {ReadSchema<{x:42}|{y:99}|Schema<string>|[1,2,{}]>} Q
3561
+ */
3562
+
3563
+ /**
3564
+ * @template IN
3565
+ * @param {IN} o
3566
+ * @return {ReadSchema<IN>}
3567
+ */
3568
+ const $ = o => {
3569
+ if ($$schema.check(o)) {
3570
+ return /** @type {any} */ (o)
3571
+ } else if ($objectAny.check(o)) {
3572
+ /**
3573
+ * @type {any}
3574
+ */
3575
+ const o2 = {};
3576
+ for (const k in o) {
3577
+ o2[k] = $(o[k]);
3578
+ }
3579
+ return /** @type {any} */ ($object(o2))
3580
+ } else if ($arrayAny.check(o)) {
3581
+ return /** @type {any} */ ($union(...o.map($)))
3582
+ } else if ($primitive.check(o)) {
3583
+ return /** @type {any} */ ($literal(o))
3584
+ } else if ($function.check(o)) {
3585
+ return /** @type {any} */ ($constructedBy(/** @type {any} */ (o)))
3586
+ }
3587
+ /* c8 ignore next */
3588
+ unexpectedCase();
3589
+ };
3590
+
3591
+ /* c8 ignore start */
3592
+ /**
3593
+ * Assert that a variable is of this specific type.
3594
+ * The assertion check is only performed in non-production environments.
2328
3595
  *
2329
- * @module buffer
3596
+ * @type {<T>(o:any,schema:Schema<T>) => asserts o is T}
2330
3597
  */
2331
-
3598
+ const assert = production
3599
+ ? () => {}
3600
+ : (o, schema) => {
3601
+ const err = new ValidationError();
3602
+ if (!schema.check(o, err)) {
3603
+ throw create$3(`Expected value to be of type ${schema.constructor.name}.\n${err.toString()}`)
3604
+ }
3605
+ };
3606
+ /* c8 ignore end */
2332
3607
 
2333
3608
  /**
2334
- * @param {number} len
3609
+ * @template In
3610
+ * @template Out
3611
+ * @typedef {{ if: Schema<In>, h: (o:In,state?:any)=>Out }} Pattern
2335
3612
  */
2336
- const createUint8ArrayFromLen = len => new Uint8Array(len);
2337
3613
 
2338
3614
  /**
2339
- * Copy the content of an Uint8Array view to a new ArrayBuffer.
2340
- *
2341
- * @param {Uint8Array} uint8Array
2342
- * @return {Uint8Array}
3615
+ * @template {Pattern<any,any>} P
3616
+ * @template In
3617
+ * @typedef {ReturnType<Extract<P,Pattern<In extends number ? number : (In extends string ? string : In),any>>['h']>} PatternMatchResult
2343
3618
  */
2344
- const copyUint8Array = uint8Array => {
2345
- const newBuf = createUint8ArrayFromLen(uint8Array.byteLength);
2346
- newBuf.set(uint8Array);
2347
- return newBuf
2348
- };
2349
3619
 
2350
3620
  /**
2351
- * Working with value pairs.
2352
- *
2353
- * @module pair
3621
+ * @todo move this to separate library
3622
+ * @template {any} [State=undefined]
3623
+ * @template {Pattern<any,any>} [Patterns=never]
2354
3624
  */
3625
+ class PatternMatcher {
3626
+ /**
3627
+ * @param {Schema<State>} [$state]
3628
+ */
3629
+ constructor ($state) {
3630
+ /**
3631
+ * @type {Array<Patterns>}
3632
+ */
3633
+ this.patterns = [];
3634
+ this.$state = $state;
3635
+ }
2355
3636
 
2356
- /**
2357
- * @template L,R
2358
- */
2359
- class Pair {
2360
3637
  /**
2361
- * @param {L} left
2362
- * @param {R} right
3638
+ * @template P
3639
+ * @template R
3640
+ * @param {P} pattern
3641
+ * @param {(o:NoInfer<Unwrap<ReadSchema<P>>>,s:State)=>R} handler
3642
+ * @return {PatternMatcher<State,Patterns|Pattern<Unwrap<ReadSchema<P>>,R>>}
2363
3643
  */
2364
- constructor (left, right) {
2365
- this.left = left;
2366
- this.right = right;
3644
+ if (pattern, handler) {
3645
+ // @ts-ignore
3646
+ this.patterns.push({ if: $(pattern), h: handler });
3647
+ // @ts-ignore
3648
+ return this
3649
+ }
3650
+
3651
+ /**
3652
+ * @template R
3653
+ * @param {(o:any,s:State)=>R} h
3654
+ */
3655
+ else (h) {
3656
+ return this.if($any, h)
3657
+ }
3658
+
3659
+ /**
3660
+ * @return {State extends undefined
3661
+ * ? <In extends Unwrap<Patterns['if']>>(o:In,state?:undefined)=>PatternMatchResult<Patterns,In>
3662
+ * : <In extends Unwrap<Patterns['if']>>(o:In,state:State)=>PatternMatchResult<Patterns,In>}
3663
+ */
3664
+ done () {
3665
+ // @ts-ignore
3666
+ return /** @type {any} */ (o, s) => {
3667
+ for (let i = 0; i < this.patterns.length; i++) {
3668
+ const p = this.patterns[i];
3669
+ if (p.if.check(o)) {
3670
+ // @ts-ignore
3671
+ return p.h(o, s)
3672
+ }
3673
+ }
3674
+ throw create$3('Unhandled pattern')
3675
+ }
2367
3676
  }
2368
3677
  }
2369
3678
 
2370
3679
  /**
2371
- * @template L,R
2372
- * @param {L} left
2373
- * @param {R} right
2374
- * @return {Pair<L,R>}
3680
+ * @template [State=undefined]
3681
+ * @param {State} [state]
3682
+ * @return {PatternMatcher<State extends undefined ? undefined : Unwrap<ReadSchema<State>>>}
2375
3683
  */
2376
- const create$1 = (left, right) => new Pair(left, right);
3684
+ const match = state => new PatternMatcher(/** @type {any} */ (state));
3685
+
3686
+ /**
3687
+ * Helper function to generate a (non-exhaustive) sample set from a gives schema.
3688
+ *
3689
+ * @type {<T>(o:T,gen:prng.PRNG)=>T}
3690
+ */
3691
+ const _random = /** @type {any} */ (match(/** @type {Schema<prng.PRNG>} */ ($any))
3692
+ .if($$number, (_o, gen) => int53(gen, MIN_SAFE_INTEGER, MAX_SAFE_INTEGER))
3693
+ .if($$string, (_o, gen) => word(gen))
3694
+ .if($$boolean, (_o, gen) => bool(gen))
3695
+ .if($$bigint, (_o, gen) => BigInt(int53(gen, MIN_SAFE_INTEGER, MAX_SAFE_INTEGER)))
3696
+ .if($$union, (o, gen) => random(gen, oneOf(gen, o.shape)))
3697
+ .if($$object, (o, gen) => {
3698
+ /**
3699
+ * @type {any}
3700
+ */
3701
+ const res = {};
3702
+ for (const k in o.shape) {
3703
+ let prop = o.shape[k];
3704
+ if ($$optional.check(prop)) {
3705
+ if (bool(gen)) { continue }
3706
+ prop = prop.shape;
3707
+ }
3708
+ res[k] = _random(prop, gen);
3709
+ }
3710
+ return res
3711
+ })
3712
+ .if($$array, (o, gen) => {
3713
+ const arr = [];
3714
+ const n = int32(gen, 0, 42);
3715
+ for (let i = 0; i < n; i++) {
3716
+ arr.push(random(gen, o.shape));
3717
+ }
3718
+ return arr
3719
+ })
3720
+ .if($$literal, (o, gen) => {
3721
+ return oneOf(gen, o.shape)
3722
+ })
3723
+ .if($$null, (o, gen) => {
3724
+ return null
3725
+ })
3726
+ .if($$lambda, (o, gen) => {
3727
+ const res = random(gen, o.res);
3728
+ return () => res
3729
+ })
3730
+ .if($$any, (o, gen) => random(gen, oneOf(gen, [
3731
+ $number, $string, $null, $undefined, $bigint, $boolean,
3732
+ $array($number),
3733
+ $record($union('a', 'b', 'c'), $number)
3734
+ ])))
3735
+ .if($$record, (o, gen) => {
3736
+ /**
3737
+ * @type {any}
3738
+ */
3739
+ const res = {};
3740
+ const keysN = int53(gen, 0, 3);
3741
+ for (let i = 0; i < keysN; i++) {
3742
+ const key = random(gen, o.shape.keys);
3743
+ const val = random(gen, o.shape.values);
3744
+ res[key] = val;
3745
+ }
3746
+ return res
3747
+ })
3748
+ .done());
3749
+
3750
+ /**
3751
+ * @template S
3752
+ * @param {prng.PRNG} gen
3753
+ * @param {S} schema
3754
+ * @return {Unwrap<ReadSchema<S>>}
3755
+ */
3756
+ const random = (gen, schema) => /** @type {any} */ (_random($(schema), gen));
2377
3757
 
2378
3758
  /* eslint-env browser */
2379
3759
 
2380
3760
 
3761
+ /* c8 ignore start */
3762
+ /**
3763
+ * @type {Document}
3764
+ */
3765
+ const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {});
3766
+
3767
+ /**
3768
+ * @type {$.Schema<DocumentFragment>}
3769
+ */
3770
+ $custom(el => el.nodeType === DOCUMENT_FRAGMENT_NODE);
3771
+
2381
3772
  /** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null);
2382
3773
 
3774
+ /**
3775
+ * @type {$.Schema<Element>}
3776
+ */
3777
+ $custom(el => el.nodeType === ELEMENT_NODE);
3778
+
3779
+ /**
3780
+ * @type {$.Schema<Text>}
3781
+ */
3782
+ $custom(el => el.nodeType === TEXT_NODE);
3783
+
2383
3784
  /**
2384
3785
  * @param {Map<string,string>} m
2385
3786
  * @return {string}
2386
3787
  */
2387
3788
  const mapToStyleString = m => map(m, (value, key) => `${key}:${value};`).join('');
3789
+
3790
+ const ELEMENT_NODE = doc.ELEMENT_NODE;
3791
+ const TEXT_NODE = doc.TEXT_NODE;
3792
+ const DOCUMENT_NODE = doc.DOCUMENT_NODE;
3793
+ const DOCUMENT_FRAGMENT_NODE = doc.DOCUMENT_FRAGMENT_NODE;
3794
+
3795
+ /**
3796
+ * @type {$.Schema<Node>}
3797
+ */
3798
+ $custom(el => el.nodeType === DOCUMENT_NODE);
2388
3799
  /* c8 ignore stop */
2389
3800
 
2390
3801
  /**
@@ -5047,17 +6458,21 @@ const cleanupTransactions = (transactionCleanups, i) => {
5047
6458
  // sort events by path length so that top-level events are fired first.
5048
6459
  events
5049
6460
  .sort((event1, event2) => event1.path.length - event2.path.length);
5050
- // We don't need to check for events.length
5051
- // because we know it has at least one element
5052
- callEventHandlerListeners(type._dEH, events, transaction);
6461
+ fs.push(() => {
6462
+ // We don't need to check for events.length
6463
+ // because we know it has at least one element
6464
+ callEventHandlerListeners(type._dEH, events, transaction);
6465
+ });
6466
+ }
6467
+ });
6468
+ fs.push(() => doc.emit('afterTransaction', [transaction, doc]));
6469
+ fs.push(() => {
6470
+ if (transaction._needFormattingCleanup) {
6471
+ cleanupYTextAfterTransaction(transaction);
5053
6472
  }
5054
6473
  });
5055
6474
  });
5056
- fs.push(() => doc.emit('afterTransaction', [transaction, doc]));
5057
6475
  callAll(fs, []);
5058
- if (transaction._needFormattingCleanup) {
5059
- cleanupYTextAfterTransaction(transaction);
5060
- }
5061
6476
  } finally {
5062
6477
  // Replace deleted items with ItemDeleted / GC.
5063
6478
  // This is where content is actually remove from the Yjs Doc.
@@ -5619,7 +7034,7 @@ class YEvent {
5619
7034
  */
5620
7035
  this._changes = null;
5621
7036
  /**
5622
- * @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
7037
+ * @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any }>}
5623
7038
  */
5624
7039
  this._keys = null;
5625
7040
  /**
@@ -5662,7 +7077,7 @@ class YEvent {
5662
7077
  }
5663
7078
 
5664
7079
  /**
5665
- * @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
7080
+ * @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any }>}
5666
7081
  */
5667
7082
  get keys () {
5668
7083
  if (this._keys === null) {
@@ -9037,12 +10452,10 @@ class YXmlElement extends YXmlFragment {
9037
10452
  const el = new YXmlElement(this.nodeName);
9038
10453
  const attrs = this.getAttributes();
9039
10454
  forEach$2(attrs, (value, key) => {
9040
- if (typeof value === 'string') {
9041
- el.setAttribute(key, value);
9042
- }
10455
+ el.setAttribute(key, /** @type {any} */ (value));
9043
10456
  });
9044
10457
  // @ts-ignore
9045
- el.insert(0, this.toArray().map(item => item instanceof AbstractType ? item.clone() : item));
10458
+ el.insert(0, this.toArray().map(v => v instanceof AbstractType ? v.clone() : v));
9046
10459
  return el
9047
10460
  }
9048
10461
 
@@ -11340,6 +12753,8 @@ class KokimokiAiService {
11340
12753
  * higher values make it more creative and varied.
11341
12754
  * @param req.maxTokens Optional. The maximum number of tokens to generate in the response.
11342
12755
  * Controls the length of the AI's output.
12756
+ * @param req.imageUrls Optional. Image URLs to include with the user prompt (Gemini models only).
12757
+ * Allows the AI to analyze and respond based on the provided images.
11343
12758
  *
11344
12759
  * @returns A promise that resolves to an object containing the AI-generated response.
11345
12760
  * @returns {string} content The text content of the AI's response.
@@ -11434,6 +12849,330 @@ class KokimokiAiService {
11434
12849
  }
11435
12850
  }
11436
12851
 
12852
+ let _kmEnv;
12853
+ /**
12854
+ * Parses and returns the Kokimoki environment configuration.
12855
+ *
12856
+ * The environment is injected into the HTML by @kokimoki/kit as a JSON script tag
12857
+ * with id `kokimoki-env`. In production, placeholder values are replaced by the server.
12858
+ *
12859
+ * @returns The parsed KokimokiEnv object
12860
+ * @throws Error if the kokimoki-env element is not found
12861
+ *
12862
+ * @example
12863
+ * ```typescript
12864
+ * import { getKmEnv } from '@kokimoki/app';
12865
+ *
12866
+ * const env = getKmEnv();
12867
+ * console.log(env.dev); // true in development
12868
+ * console.log(env.assets); // CDN URL in production
12869
+ *
12870
+ * // Cast i18n to your app's type if needed
12871
+ * const i18n = env.i18n as typeof i18nResources;
12872
+ * ```
12873
+ */
12874
+ function getKmEnv() {
12875
+ if (_kmEnv) {
12876
+ return _kmEnv;
12877
+ }
12878
+ const element = document.getElementById("kokimoki-env");
12879
+ if (!element) {
12880
+ throw new Error("kokimoki-env element not found. Ensure the app is built with @kokimoki/kit.");
12881
+ }
12882
+ _kmEnv = JSON.parse(element.textContent);
12883
+ return _kmEnv;
12884
+ }
12885
+
12886
+ /**
12887
+ * Kokimoki i18n Service
12888
+ *
12889
+ * Provides translation loading via HTTP backend. Both development and production
12890
+ * use HTTP to load translations consistently.
12891
+ *
12892
+ * In development, translations are served by @kokimoki/kit's dev server middleware.
12893
+ * In production, translations are served from the assets CDN.
12894
+ *
12895
+ * **Key Features:**
12896
+ * - Pre-configured i18next instance creation
12897
+ * - Consistent HTTP-based loading in dev and prod
12898
+ * - URL resolution for translation namespaces
12899
+ * - AI-powered translation requests
12900
+ *
12901
+ * Access via `kmClient.i18n`
12902
+ *
12903
+ * @example
12904
+ * ```typescript
12905
+ * // Setup with React
12906
+ * import { initReactI18next } from 'react-i18next';
12907
+ *
12908
+ * export const i18n = kmClient.i18n.createI18n({
12909
+ * use: [initReactI18next]
12910
+ * });
12911
+ *
12912
+ * // Initialize with primary language
12913
+ * await kmClient.i18n.init('en');
12914
+ *
12915
+ * // Request AI translation for another language
12916
+ * const result = await kmClient.i18n.requestTranslation('de');
12917
+ * // Then poll getTranslationStatus('de') until available
12918
+ * ```
12919
+ */
12920
+ class KokimokiI18nService {
12921
+ client;
12922
+ initPromise = null;
12923
+ instance = null;
12924
+ options = {};
12925
+ constructor(client) {
12926
+ this.client = client;
12927
+ }
12928
+ /**
12929
+ * Create and configure an i18next instance.
12930
+ *
12931
+ * This sets up the instance with plugins but does NOT initialize it.
12932
+ * Call `init(lng)` to initialize with a specific language.
12933
+ *
12934
+ * @param options - Configuration options (plugins, fallback, defaultNS)
12935
+ * @returns Configured i18next instance (not yet initialized)
12936
+ *
12937
+ * @example
12938
+ * ```typescript
12939
+ * // With React
12940
+ * import { initReactI18next } from 'react-i18next';
12941
+ *
12942
+ * export const i18n = kmClient.i18n.createI18n({
12943
+ * use: [initReactI18next]
12944
+ * });
12945
+ *
12946
+ * // Later, when you know the language:
12947
+ * await kmClient.i18n.init('en');
12948
+ *
12949
+ * // Then in components:
12950
+ * const { t } = useTranslation('game');
12951
+ * ```
12952
+ */
12953
+ createI18n(options) {
12954
+ const env = getKmEnv();
12955
+ const namespaces = env.i18nNamespaces ?? [];
12956
+ if (namespaces.length === 0) {
12957
+ console.warn("[KokimokiI18n] No i18n namespaces found. Make sure i18n is configured in @kokimoki/kit plugin.");
12958
+ }
12959
+ this.options = options ?? {};
12960
+ this.instance = i18next.createInstance();
12961
+ // Apply plugins
12962
+ if (options?.use) {
12963
+ for (const plugin of options.use) {
12964
+ this.instance.use(plugin);
12965
+ }
12966
+ }
12967
+ // Add HTTP backend
12968
+ this.instance.use(HttpBackend);
12969
+ return this.instance;
12970
+ }
12971
+ /**
12972
+ * Initialize the i18next instance with a specific language.
12973
+ *
12974
+ * Must call `createI18n()` first to set up the instance.
12975
+ *
12976
+ * @param lng - The language code to initialize with (e.g., 'en', 'de')
12977
+ * @returns Promise that resolves when i18n is ready
12978
+ *
12979
+ * @example
12980
+ * ```typescript
12981
+ * // Create instance first
12982
+ * const i18n = kmClient.i18n.createI18n({ use: [initReactI18next] });
12983
+ *
12984
+ * // Then initialize when you know the language
12985
+ * await kmClient.i18n.init('en');
12986
+ * ```
12987
+ */
12988
+ async init(lng) {
12989
+ if (!this.instance) {
12990
+ throw new Error("Call createI18n() before init()");
12991
+ }
12992
+ if (this.initPromise) {
12993
+ return this.initPromise;
12994
+ }
12995
+ const env = getKmEnv();
12996
+ const namespaces = env.i18nNamespaces ?? [];
12997
+ const fallbackLng = this.options.fallbackLng ?? lng;
12998
+ const defaultNS = this.options.defaultNS;
12999
+ this.initPromise = this.instance.init({
13000
+ lng,
13001
+ fallbackLng,
13002
+ ns: namespaces,
13003
+ defaultNS,
13004
+ backend: {
13005
+ loadPath: (lng, ns) => this.getNamespaceUrl(lng, ns),
13006
+ },
13007
+ interpolation: {
13008
+ escapeValue: false,
13009
+ },
13010
+ });
13011
+ return this.initPromise;
13012
+ }
13013
+ /**
13014
+ * Get the URL for a translation namespace.
13015
+ *
13016
+ * Returns the appropriate URL based on environment:
13017
+ * - Development: `/__kokimoki/i18n/{lng}/{ns}.json`
13018
+ * - Production: `{assets}/km-i18n/{lng}/{ns}.json`
13019
+ *
13020
+ * @param lng - Language code (e.g., 'en', 'et', 'de')
13021
+ * @param ns - Namespace (e.g., 'ui', 'game', 'setup')
13022
+ * @returns Full URL to the translation JSON file
13023
+ *
13024
+ * @example
13025
+ * ```typescript
13026
+ * const url = kmClient.i18n.getNamespaceUrl('en', 'game');
13027
+ * // Dev: "/__kokimoki/i18n/en/game.json"
13028
+ * // Prod: "https://cdn.kokimoki.com/build-123/km-i18n/en/game.json"
13029
+ * ```
13030
+ */
13031
+ getNamespaceUrl(lng, ns) {
13032
+ const env = getKmEnv();
13033
+ if (env.dev) {
13034
+ // Development: use kit plugin's middleware
13035
+ return `/__kokimoki/i18n/${lng}/${ns}.json`;
13036
+ }
13037
+ // Production: use assets CDN with configured i18n path
13038
+ const i18nPath = env.i18nPath ?? 'km-i18n';
13039
+ return `${env.assets}/${i18nPath}/${lng}/${ns}.json`;
13040
+ }
13041
+ /**
13042
+ * Get the list of available namespaces.
13043
+ *
13044
+ * @returns Array of namespace names configured in @kokimoki/kit
13045
+ */
13046
+ getNamespaces() {
13047
+ return getKmEnv().i18nNamespaces ?? [];
13048
+ }
13049
+ /**
13050
+ * Get the list of available languages.
13051
+ *
13052
+ * @returns Array of language codes configured in @kokimoki/kit
13053
+ */
13054
+ getLanguages() {
13055
+ return getKmEnv().i18nLanguages ?? [];
13056
+ }
13057
+ /**
13058
+ * Get the status of all languages that have been requested for AI translation.
13059
+ *
13060
+ * Only available in production. In development, returns an empty array.
13061
+ *
13062
+ * @returns Promise with array of language statuses
13063
+ *
13064
+ * @example
13065
+ * ```typescript
13066
+ * const { languages } = await kmClient.i18n.getAllLanguagesStatus();
13067
+ * // [{ lng: 'de', status: 'available' }, { lng: 'fr', status: 'processing' }]
13068
+ * ```
13069
+ */
13070
+ async getAllLanguagesStatus() {
13071
+ const env = getKmEnv();
13072
+ if (env.dev) {
13073
+ return { languages: [] };
13074
+ }
13075
+ const res = await fetch(`${this.client.apiUrl}/i18n`, {
13076
+ method: "GET",
13077
+ headers: this.client.apiHeaders,
13078
+ });
13079
+ return await res.json();
13080
+ }
13081
+ /**
13082
+ * Get the translation status for a specific language.
13083
+ *
13084
+ * Returns the overall status and per-namespace status for the given language.
13085
+ * In development, returns 'available' for local languages and 'not_available' for others.
13086
+ * In production, queries the API for the actual status.
13087
+ *
13088
+ * @param lng - Target language code (e.g., 'de', 'fr', 'es')
13089
+ * @returns Promise with translation status
13090
+ *
13091
+ * @example
13092
+ * ```typescript
13093
+ * const status = await kmClient.i18n.getTranslationStatus('de');
13094
+ * if (status.status === 'available') {
13095
+ * // All translations ready, can switch language
13096
+ * i18next.changeLanguage('de');
13097
+ * } else if (status.status === 'processing') {
13098
+ * // Show loading indicator
13099
+ * } else {
13100
+ * // Request translation
13101
+ * await kmClient.i18n.requestTranslation('de');
13102
+ * }
13103
+ * ```
13104
+ */
13105
+ async getTranslationStatus(lng) {
13106
+ const env = getKmEnv();
13107
+ if (env.dev) {
13108
+ // In dev, only local languages are available
13109
+ const localLanguages = this.getLanguages();
13110
+ const namespaces = this.getNamespaces();
13111
+ const isLocal = localLanguages.includes(lng);
13112
+ const status = isLocal ? "available" : "not_available";
13113
+ return {
13114
+ status,
13115
+ namespaces: Object.fromEntries(namespaces.map((ns) => [ns, status])),
13116
+ };
13117
+ }
13118
+ const res = await fetch(`${this.client.apiUrl}/i18n/${encodeURIComponent(lng)}/status`, {
13119
+ method: "GET",
13120
+ headers: this.client.apiHeaders,
13121
+ });
13122
+ return await res.json();
13123
+ }
13124
+ /**
13125
+ * Request AI translation for a target language.
13126
+ *
13127
+ * Triggers background AI translation jobs for all namespaces that are not yet available.
13128
+ * Uses the build's configured primary language as the source.
13129
+ *
13130
+ * In development, returns 'already_available' for local languages and throws an error for others.
13131
+ * In production, triggers the API to start translation.
13132
+ *
13133
+ * @param lng - Target language code (e.g., 'de', 'fr', 'es')
13134
+ * @returns Promise with the result of the request
13135
+ *
13136
+ * @example
13137
+ * ```typescript
13138
+ * const result = await kmClient.i18n.requestTranslation('de');
13139
+ *
13140
+ * if (result.status === 'started') {
13141
+ * // Translation started, poll for status
13142
+ * const checkStatus = async () => {
13143
+ * const status = await kmClient.i18n.getTranslationStatus('de');
13144
+ * if (status.status === 'available') {
13145
+ * i18next.changeLanguage('de');
13146
+ * } else if (status.status === 'processing') {
13147
+ * setTimeout(checkStatus, 2000);
13148
+ * }
13149
+ * };
13150
+ * checkStatus();
13151
+ * } else if (result.status === 'already_available') {
13152
+ * // Already translated, switch immediately
13153
+ * i18next.changeLanguage('de');
13154
+ * }
13155
+ * ```
13156
+ */
13157
+ async requestTranslation(lng) {
13158
+ const env = getKmEnv();
13159
+ if (env.dev) {
13160
+ // In dev, only local languages are available
13161
+ const localLanguages = this.getLanguages();
13162
+ if (localLanguages.includes(lng)) {
13163
+ return { status: "already_available" };
13164
+ }
13165
+ // AI translation not available in dev mode
13166
+ throw new Error(`AI translation not available in dev mode. Add local translations for '${lng}' in src/i18n/${lng}/`);
13167
+ }
13168
+ const res = await fetch(`${this.client.apiUrl}/i18n/${encodeURIComponent(lng)}/translate`, {
13169
+ method: "POST",
13170
+ headers: this.client.apiHeaders,
13171
+ });
13172
+ return await res.json();
13173
+ }
13174
+ }
13175
+
11437
13176
  /**
11438
13177
  * Kokimoki Leaderboard Service
11439
13178
  *
@@ -15045,7 +16784,7 @@ const createHandlerDefault = (isInitializing, addPropListener, removePropListene
15045
16784
  removePropListener(prop);
15046
16785
  const deleted = Reflect.deleteProperty(target, prop);
15047
16786
  if (deleted) {
15048
- notifyUpdate(["delete", [prop], prevValue]);
16787
+ notifyUpdate(createOp == null ? void 0 : createOp("delete", prop, prevValue));
15049
16788
  }
15050
16789
  return deleted;
15051
16790
  },
@@ -15062,10 +16801,11 @@ const createHandlerDefault = (isInitializing, addPropListener, removePropListene
15062
16801
  const nextValue = !proxyStateMap.has(value) && canProxy(value) ? proxy(value) : value;
15063
16802
  addPropListener(prop, nextValue);
15064
16803
  Reflect.set(target, prop, nextValue, receiver);
15065
- notifyUpdate(["set", [prop], value, prevValue]);
16804
+ notifyUpdate(createOp == null ? void 0 : createOp("set", prop, value, prevValue));
15066
16805
  return true;
15067
16806
  }
15068
16807
  });
16808
+ const createOpDefault = (type, prop, ...args) => [type, [prop], ...args];
15069
16809
  const proxyStateMap = /* @__PURE__ */ new WeakMap();
15070
16810
  const refSet = /* @__PURE__ */ new WeakSet();
15071
16811
  const snapCache = /* @__PURE__ */ new WeakMap();
@@ -15076,6 +16816,7 @@ let newProxy = (target, handler) => new Proxy(target, handler);
15076
16816
  let canProxy = canProxyDefault;
15077
16817
  let createSnapshot = createSnapshotDefault;
15078
16818
  let createHandler = createHandlerDefault;
16819
+ let createOp;
15079
16820
  function proxy(baseObject = {}) {
15080
16821
  if (!isObject(baseObject)) {
15081
16822
  throw new Error("object required");
@@ -15106,8 +16847,11 @@ function proxy(baseObject = {}) {
15106
16847
  return version;
15107
16848
  };
15108
16849
  const createPropListener = (prop) => (op, nextVersion) => {
15109
- const newOp = [...op];
15110
- newOp[1] = [prop, ...newOp[1]];
16850
+ let newOp;
16851
+ if (op) {
16852
+ newOp = [...op];
16853
+ newOp[1] = [prop, ...newOp[1]];
16854
+ }
15111
16855
  notifyUpdate(newOp, nextVersion);
15112
16856
  };
15113
16857
  const propProxyStates = /* @__PURE__ */ new Map();
@@ -15194,7 +16938,9 @@ function subscribe(proxyObject, callback, notifyInSync) {
15194
16938
  const addListener = proxyState[2];
15195
16939
  let isListenerActive = false;
15196
16940
  const listener = (op) => {
15197
- ops.push(op);
16941
+ if (op) {
16942
+ ops.push(op);
16943
+ }
15198
16944
  if (notifyInSync) {
15199
16945
  callback(ops.splice(0));
15200
16946
  return;
@@ -15227,6 +16973,15 @@ function ref(obj) {
15227
16973
  refSet.add(obj);
15228
16974
  return obj;
15229
16975
  }
16976
+ function unstable_enableOp(enabled = true) {
16977
+ if (enabled === true) {
16978
+ createOp = createOpDefault;
16979
+ } else if (enabled === false) {
16980
+ createOp = void 0;
16981
+ } else {
16982
+ createOp = enabled;
16983
+ }
16984
+ }
15230
16985
 
15231
16986
  const parseProxyOps = (ops) => {
15232
16987
  const indexed = new Set();
@@ -15959,7 +17714,7 @@ class KokimokiTransaction {
15959
17714
  }
15960
17715
 
15961
17716
  // Auto-generated file. Do not edit manually.
15962
- const KOKIMOKI_APP_VERSION = '2.1.0';
17717
+ const KOKIMOKI_APP_VERSION = '2.1.1';
15963
17718
 
15964
17719
  var RoomSubscriptionMode;
15965
17720
  (function (RoomSubscriptionMode) {
@@ -16200,6 +17955,7 @@ class KokimokiClient extends EventEmitter$1 {
16200
17955
  _clientTokenKey = "KM_TOKEN";
16201
17956
  _editorContext;
16202
17957
  _ai;
17958
+ _i18n;
16203
17959
  _storage;
16204
17960
  _leaderboard;
16205
17961
  constructor(host, appId, code = "") {
@@ -16213,6 +17969,7 @@ class KokimokiClient extends EventEmitter$1 {
16213
17969
  this._apiUrl = `http${secure ? "s" : ""}://${this.host}`;
16214
17970
  // Initialize modules
16215
17971
  this._ai = new KokimokiAiService(this);
17972
+ this._i18n = new KokimokiI18nService(this);
16216
17973
  this._storage = new KokimokiStorageService(this);
16217
17974
  this._leaderboard = new KokimokiLeaderboardService(this);
16218
17975
  // Set up ping interval
@@ -16722,6 +18479,44 @@ class KokimokiClient extends EventEmitter$1 {
16722
18479
  clearInterval(this._pingInterval);
16723
18480
  }
16724
18481
  }
18482
+ /**
18483
+ * Waits for all subscriptions to be fully joined.
18484
+ *
18485
+ * This is useful when you need to ensure all stores have completed their initial
18486
+ * synchronization before proceeding (e.g., before running tests or taking snapshots).
18487
+ *
18488
+ * @param timeout - Maximum time to wait in milliseconds (default: 5000ms).
18489
+ * @returns A promise that resolves when all subscriptions are joined, or when timeout is reached.
18490
+ *
18491
+ * @example
18492
+ * ```ts
18493
+ * // Wait for all stores to sync before starting game
18494
+ * await client.waitForSubscriptions();
18495
+ *
18496
+ * // Wait with custom timeout
18497
+ * await client.waitForSubscriptions(10000);
18498
+ * ```
18499
+ */
18500
+ async waitForSubscriptions(timeout = 5000) {
18501
+ const checkInterval = 10;
18502
+ const maxChecks = Math.ceil(timeout / checkInterval);
18503
+ return new Promise((resolve) => {
18504
+ let checks = 0;
18505
+ const intervalId = setInterval(() => {
18506
+ let allJoined = true;
18507
+ for (const subscription of this._subscriptionsByName.values()) {
18508
+ if (!subscription.joined) {
18509
+ allJoined = false;
18510
+ break;
18511
+ }
18512
+ }
18513
+ if (allJoined || ++checks >= maxChecks) {
18514
+ clearInterval(intervalId);
18515
+ resolve();
18516
+ }
18517
+ }, checkInterval);
18518
+ });
18519
+ }
16725
18520
  /**
16726
18521
  * Gets the internal room hash identifier for a store.
16727
18522
  *
@@ -16813,6 +18608,15 @@ class KokimokiClient extends EventEmitter$1 {
16813
18608
  }
16814
18609
  return this._ai;
16815
18610
  }
18611
+ /**
18612
+ * Access i18n URL resolution and translation loading utilities.
18613
+ */
18614
+ get i18n() {
18615
+ if (!this._i18n) {
18616
+ throw new Error("I18n client not initialized");
18617
+ }
18618
+ return this._i18n;
18619
+ }
16816
18620
  /**
16817
18621
  * Access file upload and management for media files, images, and user-generated content.
16818
18622
  */
@@ -17143,7 +18947,14 @@ function subscribeKey(proxyObject, key, callback, notifyInSync) {
17143
18947
  }
17144
18948
 
17145
18949
  let currentCleanups;
18950
+ let didWarnDeprecation = false;
17146
18951
  function watch(callback, options) {
18952
+ if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !didWarnDeprecation) {
18953
+ console.warn(
18954
+ "[DEPRECATED] The `watch` util is no longer maintained. Please migrate to [valtio-reactive](https://github.com/valtiojs/valtio-reactive)."
18955
+ );
18956
+ didWarnDeprecation = true;
18957
+ }
17147
18958
  let alive = true;
17148
18959
  const cleanups = /* @__PURE__ */ new Set();
17149
18960
  const subscriptions = /* @__PURE__ */ new Map();
@@ -17199,7 +19010,7 @@ function watch(callback, options) {
17199
19010
  return cleanup;
17200
19011
  }
17201
19012
 
17202
- const DEVTOOLS = Symbol();
19013
+ const DEVTOOLS = /* @__PURE__ */ Symbol();
17203
19014
  function devtools(proxyObject, options) {
17204
19015
  const { enabled, name = "", ...rest } = options || {};
17205
19016
  let extension;
@@ -17213,10 +19024,11 @@ function devtools(proxyObject, options) {
17213
19024
  }
17214
19025
  return;
17215
19026
  }
19027
+ unstable_enableOp();
17216
19028
  let isTimeTraveling = false;
17217
19029
  const devtools2 = extension.connect({ name, ...rest });
17218
- const unsub1 = subscribe(proxyObject, (ops) => {
17219
- const action = ops.filter(([_, path]) => path[0] !== DEVTOOLS).map(([op, path]) => `${op}:${path.map(String).join(".")}`).join(", ");
19030
+ const unsub1 = subscribe(proxyObject, (unstable_ops) => {
19031
+ const action = unstable_ops.filter(([_, path]) => path[0] !== DEVTOOLS).map(([op, path]) => `${op}:${path.map(String).join(".")}`).join(", ");
17220
19032
  if (!action) {
17221
19033
  return;
17222
19034
  }
@@ -17277,7 +19089,7 @@ function devtools(proxyObject, options) {
17277
19089
  };
17278
19090
  }
17279
19091
 
17280
- const DUMMY_SYMBOL = Symbol();
19092
+ const DUMMY_SYMBOL = /* @__PURE__ */ Symbol();
17281
19093
  function useProxy(proxy, options) {
17282
19094
  const snapshot = useSnapshot(proxy, options);
17283
19095
  snapshot[DUMMY_SYMBOL];
@@ -17292,5 +19104,5 @@ function useProxy(proxy, options) {
17292
19104
  });
17293
19105
  }
17294
19106
 
17295
- export { KokimokiClient, KokimokiStore, derive, devtools, proxy, ref, snapshot, subscribe, subscribeKey, underive, useProxy, useSnapshot, watch };
19107
+ export { KokimokiClient, KokimokiStore, derive, devtools, getKmEnv, proxy, ref, snapshot, subscribe, subscribeKey, underive, useProxy, useSnapshot, watch };
17296
19108
  //# sourceMappingURL=kokimoki.min.js.map