@kokimoki/app 2.1.1 → 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.
- package/README.md +72 -0
- package/dist/core/kokimoki-client.d.ts +75 -15
- package/dist/core/kokimoki-client.js +137 -22
- package/dist/index.d.ts +6 -1
- package/dist/index.js +4 -0
- package/dist/kokimoki.min.d.ts +320 -2
- package/dist/kokimoki.min.js +1916 -115
- package/dist/kokimoki.min.js.map +1 -1
- package/dist/protocol/ws-message/reader.d.ts +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/kokimoki-ai.d.ts +185 -124
- package/dist/services/kokimoki-ai.js +201 -111
- package/dist/services/kokimoki-i18n.d.ts +259 -0
- package/dist/services/kokimoki-i18n.js +325 -0
- package/dist/stores/kokimoki-local-store.d.ts +1 -1
- package/dist/types/common.d.ts +9 -0
- package/dist/types/env.d.ts +36 -0
- package/dist/types/env.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/kokimoki-client.d.ts +31 -0
- package/dist/utils/kokimoki-client.js +38 -0
- package/dist/utils/kokimoki-dev.d.ts +30 -0
- package/dist/utils/kokimoki-dev.js +75 -0
- package/dist/utils/kokimoki-env.d.ts +20 -0
- package/dist/utils/kokimoki-env.js +30 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/kokimoki-ai.instructions.md +316 -0
- package/docs/kokimoki-dynamic-stores.instructions.md +439 -0
- package/docs/kokimoki-i18n.instructions.md +285 -0
- package/docs/kokimoki-leaderboard.instructions.md +189 -0
- package/docs/kokimoki-sdk.instructions.md +221 -0
- package/docs/kokimoki-storage.instructions.md +162 -0
- package/llms.txt +43 -0
- package/package.json +9 -13
package/dist/kokimoki.min.js
CHANGED
|
@@ -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
|
|
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 {
|
|
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
|
-
* @
|
|
1581
|
-
* @
|
|
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
|
-
* @
|
|
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
|
-
* @
|
|
1617
|
-
* @
|
|
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
|
-
*
|
|
2165
|
+
* @typedef {{ [EqualityTraitSymbol]:(other:EqualityTrait)=>boolean }} EqualityTrait
|
|
2166
|
+
*/
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
*
|
|
2170
|
+
* Utility function to compare any two objects.
|
|
2075
2171
|
*
|
|
2076
|
-
*
|
|
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]
|
|
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,94 +2494,1308 @@ 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 &&
|
|
2304
2501
|
isOneOf(process.env.FORCE_COLOR, ['true', '1', '2']);
|
|
2305
2502
|
|
|
2306
|
-
/* c8 ignore start */
|
|
2503
|
+
/* c8 ignore start */
|
|
2504
|
+
/**
|
|
2505
|
+
* Color is enabled by default if the terminal supports it.
|
|
2506
|
+
*
|
|
2507
|
+
* Explicitly enable color using `--color` parameter
|
|
2508
|
+
* Disable color using `--no-color` parameter or using `NO_COLOR=1` environment variable.
|
|
2509
|
+
* `FORCE_COLOR=1` enables color and takes precedence over all.
|
|
2510
|
+
*/
|
|
2511
|
+
const supportsColor = forceColor || (
|
|
2512
|
+
!hasParam('--no-colors') && // @todo deprecate --no-colors
|
|
2513
|
+
!hasConf('no-color') &&
|
|
2514
|
+
(!isNode || process.stdout.isTTY) && (
|
|
2515
|
+
!isNode ||
|
|
2516
|
+
hasParam('--color') ||
|
|
2517
|
+
getVariable('COLORTERM') !== null ||
|
|
2518
|
+
(getVariable('TERM') || '').includes('color')
|
|
2519
|
+
)
|
|
2520
|
+
);
|
|
2521
|
+
/* c8 ignore stop */
|
|
2522
|
+
|
|
2523
|
+
/**
|
|
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.
|
|
3595
|
+
*
|
|
3596
|
+
* @type {<T>(o:any,schema:Schema<T>) => asserts o is T}
|
|
3597
|
+
*/
|
|
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 */
|
|
3607
|
+
|
|
3608
|
+
/**
|
|
3609
|
+
* @template In
|
|
3610
|
+
* @template Out
|
|
3611
|
+
* @typedef {{ if: Schema<In>, h: (o:In,state?:any)=>Out }} Pattern
|
|
3612
|
+
*/
|
|
3613
|
+
|
|
3614
|
+
/**
|
|
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
|
|
3618
|
+
*/
|
|
3619
|
+
|
|
3620
|
+
/**
|
|
3621
|
+
* @todo move this to separate library
|
|
3622
|
+
* @template {any} [State=undefined]
|
|
3623
|
+
* @template {Pattern<any,any>} [Patterns=never]
|
|
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
|
+
}
|
|
3636
|
+
|
|
3637
|
+
/**
|
|
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>>}
|
|
3643
|
+
*/
|
|
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
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
|
|
2307
3679
|
/**
|
|
2308
|
-
*
|
|
2309
|
-
*
|
|
2310
|
-
*
|
|
2311
|
-
* Disable color using `--no-color` parameter or using `NO_COLOR=1` environment variable.
|
|
2312
|
-
* `FORCE_COLOR=1` enables color and takes precedence over all.
|
|
3680
|
+
* @template [State=undefined]
|
|
3681
|
+
* @param {State} [state]
|
|
3682
|
+
* @return {PatternMatcher<State extends undefined ? undefined : Unwrap<ReadSchema<State>>>}
|
|
2313
3683
|
*/
|
|
2314
|
-
const
|
|
2315
|
-
!hasParam('--no-colors') && // @todo deprecate --no-colors
|
|
2316
|
-
!hasConf('no-color') &&
|
|
2317
|
-
(!isNode || process.stdout.isTTY) && (
|
|
2318
|
-
!isNode ||
|
|
2319
|
-
hasParam('--color') ||
|
|
2320
|
-
getVariable('COLORTERM') !== null ||
|
|
2321
|
-
(getVariable('TERM') || '').includes('color')
|
|
2322
|
-
)
|
|
2323
|
-
);
|
|
2324
|
-
/* c8 ignore stop */
|
|
3684
|
+
const match = state => new PatternMatcher(/** @type {any} */ (state));
|
|
2325
3685
|
|
|
2326
3686
|
/**
|
|
2327
|
-
*
|
|
3687
|
+
* Helper function to generate a (non-exhaustive) sample set from a gives schema.
|
|
2328
3688
|
*
|
|
2329
|
-
* @
|
|
3689
|
+
* @type {<T>(o:T,gen:prng.PRNG)=>T}
|
|
2330
3690
|
*/
|
|
2331
|
-
|
|
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());
|
|
2332
3749
|
|
|
2333
3750
|
/**
|
|
2334
|
-
* @
|
|
3751
|
+
* @template S
|
|
3752
|
+
* @param {prng.PRNG} gen
|
|
3753
|
+
* @param {S} schema
|
|
3754
|
+
* @return {Unwrap<ReadSchema<S>>}
|
|
2335
3755
|
*/
|
|
2336
|
-
const
|
|
3756
|
+
const random = (gen, schema) => /** @type {any} */ (_random($(schema), gen));
|
|
3757
|
+
|
|
3758
|
+
/* eslint-env browser */
|
|
3759
|
+
|
|
2337
3760
|
|
|
3761
|
+
/* c8 ignore start */
|
|
2338
3762
|
/**
|
|
2339
|
-
*
|
|
2340
|
-
*
|
|
2341
|
-
* @param {Uint8Array} uint8Array
|
|
2342
|
-
* @return {Uint8Array}
|
|
3763
|
+
* @type {Document}
|
|
2343
3764
|
*/
|
|
2344
|
-
const
|
|
2345
|
-
const newBuf = createUint8ArrayFromLen(uint8Array.byteLength);
|
|
2346
|
-
newBuf.set(uint8Array);
|
|
2347
|
-
return newBuf
|
|
2348
|
-
};
|
|
3765
|
+
const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {});
|
|
2349
3766
|
|
|
2350
3767
|
/**
|
|
2351
|
-
*
|
|
2352
|
-
*
|
|
2353
|
-
* @module pair
|
|
3768
|
+
* @type {$.Schema<DocumentFragment>}
|
|
2354
3769
|
*/
|
|
3770
|
+
$custom(el => el.nodeType === DOCUMENT_FRAGMENT_NODE);
|
|
3771
|
+
|
|
3772
|
+
/** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null);
|
|
2355
3773
|
|
|
2356
3774
|
/**
|
|
2357
|
-
* @
|
|
3775
|
+
* @type {$.Schema<Element>}
|
|
2358
3776
|
*/
|
|
2359
|
-
|
|
2360
|
-
/**
|
|
2361
|
-
* @param {L} left
|
|
2362
|
-
* @param {R} right
|
|
2363
|
-
*/
|
|
2364
|
-
constructor (left, right) {
|
|
2365
|
-
this.left = left;
|
|
2366
|
-
this.right = right;
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
3777
|
+
$custom(el => el.nodeType === ELEMENT_NODE);
|
|
2369
3778
|
|
|
2370
3779
|
/**
|
|
2371
|
-
* @
|
|
2372
|
-
* @param {L} left
|
|
2373
|
-
* @param {R} right
|
|
2374
|
-
* @return {Pair<L,R>}
|
|
3780
|
+
* @type {$.Schema<Text>}
|
|
2375
3781
|
*/
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
/* eslint-env browser */
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
/** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null);
|
|
3782
|
+
$custom(el => el.nodeType === TEXT_NODE);
|
|
2382
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
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
10458
|
+
el.insert(0, this.toArray().map(v => v instanceof AbstractType ? v.clone() : v));
|
|
9046
10459
|
return el
|
|
9047
10460
|
}
|
|
9048
10461
|
|
|
@@ -11436,6 +12849,330 @@ class KokimokiAiService {
|
|
|
11436
12849
|
}
|
|
11437
12850
|
}
|
|
11438
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
|
+
|
|
11439
13176
|
/**
|
|
11440
13177
|
* Kokimoki Leaderboard Service
|
|
11441
13178
|
*
|
|
@@ -12128,16 +13865,16 @@ var functionApply = Function.prototype.apply;
|
|
|
12128
13865
|
/** @type {import('./reflectApply')} */
|
|
12129
13866
|
var reflectApply$1 = typeof Reflect !== 'undefined' && Reflect && Reflect.apply;
|
|
12130
13867
|
|
|
12131
|
-
var bind$
|
|
13868
|
+
var bind$5 = functionBind;
|
|
12132
13869
|
|
|
12133
13870
|
var $apply$2 = functionApply;
|
|
12134
13871
|
var $call$2 = functionCall;
|
|
12135
13872
|
var $reflectApply = reflectApply$1;
|
|
12136
13873
|
|
|
12137
13874
|
/** @type {import('./actualApply')} */
|
|
12138
|
-
var actualApply$1 = $reflectApply || bind$
|
|
13875
|
+
var actualApply$1 = $reflectApply || bind$5.call($call$2, $apply$2);
|
|
12139
13876
|
|
|
12140
|
-
var bind$
|
|
13877
|
+
var bind$4 = functionBind;
|
|
12141
13878
|
var $TypeError$4 = requireType();
|
|
12142
13879
|
|
|
12143
13880
|
var $call$1 = functionCall;
|
|
@@ -12148,7 +13885,7 @@ var callBindApplyHelpers = function callBindBasic(args) {
|
|
|
12148
13885
|
if (args.length < 1 || typeof args[0] !== 'function') {
|
|
12149
13886
|
throw new $TypeError$4('a function is required');
|
|
12150
13887
|
}
|
|
12151
|
-
return $actualApply(bind$
|
|
13888
|
+
return $actualApply(bind$4, $call$1, args);
|
|
12152
13889
|
};
|
|
12153
13890
|
|
|
12154
13891
|
var callBind$2 = callBindApplyHelpers;
|
|
@@ -12206,21 +13943,12 @@ var getProto$4 = reflectGetProto
|
|
|
12206
13943
|
}
|
|
12207
13944
|
: null;
|
|
12208
13945
|
|
|
12209
|
-
var
|
|
12210
|
-
var
|
|
12211
|
-
|
|
12212
|
-
function requireHasown () {
|
|
12213
|
-
if (hasRequiredHasown) return hasown;
|
|
12214
|
-
hasRequiredHasown = 1;
|
|
12215
|
-
|
|
12216
|
-
var call = Function.prototype.call;
|
|
12217
|
-
var $hasOwn = Object.prototype.hasOwnProperty;
|
|
12218
|
-
var bind = functionBind;
|
|
13946
|
+
var call = Function.prototype.call;
|
|
13947
|
+
var $hasOwn = Object.prototype.hasOwnProperty;
|
|
13948
|
+
var bind$3 = functionBind;
|
|
12219
13949
|
|
|
12220
|
-
|
|
12221
|
-
|
|
12222
|
-
return hasown;
|
|
12223
|
-
}
|
|
13950
|
+
/** @type {import('.')} */
|
|
13951
|
+
var hasown = bind$3.call(call, $hasOwn);
|
|
12224
13952
|
|
|
12225
13953
|
var undefined$1;
|
|
12226
13954
|
|
|
@@ -12463,7 +14191,7 @@ var LEGACY_ALIASES = {
|
|
|
12463
14191
|
};
|
|
12464
14192
|
|
|
12465
14193
|
var bind$2 = functionBind;
|
|
12466
|
-
var hasOwn$1 =
|
|
14194
|
+
var hasOwn$1 = hasown;
|
|
12467
14195
|
var $concat = bind$2.call($call, Array.prototype.concat);
|
|
12468
14196
|
var $spliceApply = bind$2.call($apply$1, Array.prototype.splice);
|
|
12469
14197
|
var $replace = bind$2.call($call, String.prototype.replace);
|
|
@@ -12662,7 +14390,7 @@ var isArguments = supportsStandardArguments ? isStandardArguments : isLegacyArgu
|
|
|
12662
14390
|
|
|
12663
14391
|
var callBound$3 = callBound$5;
|
|
12664
14392
|
var hasToStringTag$3 = shams();
|
|
12665
|
-
var hasOwn =
|
|
14393
|
+
var hasOwn = hasown;
|
|
12666
14394
|
var gOPD$2 = gopd$1;
|
|
12667
14395
|
|
|
12668
14396
|
/** @type {import('.')} */
|
|
@@ -15056,7 +16784,7 @@ const createHandlerDefault = (isInitializing, addPropListener, removePropListene
|
|
|
15056
16784
|
removePropListener(prop);
|
|
15057
16785
|
const deleted = Reflect.deleteProperty(target, prop);
|
|
15058
16786
|
if (deleted) {
|
|
15059
|
-
notifyUpdate(
|
|
16787
|
+
notifyUpdate(createOp == null ? void 0 : createOp("delete", prop, prevValue));
|
|
15060
16788
|
}
|
|
15061
16789
|
return deleted;
|
|
15062
16790
|
},
|
|
@@ -15073,10 +16801,11 @@ const createHandlerDefault = (isInitializing, addPropListener, removePropListene
|
|
|
15073
16801
|
const nextValue = !proxyStateMap.has(value) && canProxy(value) ? proxy(value) : value;
|
|
15074
16802
|
addPropListener(prop, nextValue);
|
|
15075
16803
|
Reflect.set(target, prop, nextValue, receiver);
|
|
15076
|
-
notifyUpdate(
|
|
16804
|
+
notifyUpdate(createOp == null ? void 0 : createOp("set", prop, value, prevValue));
|
|
15077
16805
|
return true;
|
|
15078
16806
|
}
|
|
15079
16807
|
});
|
|
16808
|
+
const createOpDefault = (type, prop, ...args) => [type, [prop], ...args];
|
|
15080
16809
|
const proxyStateMap = /* @__PURE__ */ new WeakMap();
|
|
15081
16810
|
const refSet = /* @__PURE__ */ new WeakSet();
|
|
15082
16811
|
const snapCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -15087,6 +16816,7 @@ let newProxy = (target, handler) => new Proxy(target, handler);
|
|
|
15087
16816
|
let canProxy = canProxyDefault;
|
|
15088
16817
|
let createSnapshot = createSnapshotDefault;
|
|
15089
16818
|
let createHandler = createHandlerDefault;
|
|
16819
|
+
let createOp;
|
|
15090
16820
|
function proxy(baseObject = {}) {
|
|
15091
16821
|
if (!isObject(baseObject)) {
|
|
15092
16822
|
throw new Error("object required");
|
|
@@ -15117,8 +16847,11 @@ function proxy(baseObject = {}) {
|
|
|
15117
16847
|
return version;
|
|
15118
16848
|
};
|
|
15119
16849
|
const createPropListener = (prop) => (op, nextVersion) => {
|
|
15120
|
-
|
|
15121
|
-
|
|
16850
|
+
let newOp;
|
|
16851
|
+
if (op) {
|
|
16852
|
+
newOp = [...op];
|
|
16853
|
+
newOp[1] = [prop, ...newOp[1]];
|
|
16854
|
+
}
|
|
15122
16855
|
notifyUpdate(newOp, nextVersion);
|
|
15123
16856
|
};
|
|
15124
16857
|
const propProxyStates = /* @__PURE__ */ new Map();
|
|
@@ -15205,7 +16938,9 @@ function subscribe(proxyObject, callback, notifyInSync) {
|
|
|
15205
16938
|
const addListener = proxyState[2];
|
|
15206
16939
|
let isListenerActive = false;
|
|
15207
16940
|
const listener = (op) => {
|
|
15208
|
-
|
|
16941
|
+
if (op) {
|
|
16942
|
+
ops.push(op);
|
|
16943
|
+
}
|
|
15209
16944
|
if (notifyInSync) {
|
|
15210
16945
|
callback(ops.splice(0));
|
|
15211
16946
|
return;
|
|
@@ -15238,6 +16973,15 @@ function ref(obj) {
|
|
|
15238
16973
|
refSet.add(obj);
|
|
15239
16974
|
return obj;
|
|
15240
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
|
+
}
|
|
15241
16985
|
|
|
15242
16986
|
const parseProxyOps = (ops) => {
|
|
15243
16987
|
const indexed = new Set();
|
|
@@ -16211,6 +17955,7 @@ class KokimokiClient extends EventEmitter$1 {
|
|
|
16211
17955
|
_clientTokenKey = "KM_TOKEN";
|
|
16212
17956
|
_editorContext;
|
|
16213
17957
|
_ai;
|
|
17958
|
+
_i18n;
|
|
16214
17959
|
_storage;
|
|
16215
17960
|
_leaderboard;
|
|
16216
17961
|
constructor(host, appId, code = "") {
|
|
@@ -16224,6 +17969,7 @@ class KokimokiClient extends EventEmitter$1 {
|
|
|
16224
17969
|
this._apiUrl = `http${secure ? "s" : ""}://${this.host}`;
|
|
16225
17970
|
// Initialize modules
|
|
16226
17971
|
this._ai = new KokimokiAiService(this);
|
|
17972
|
+
this._i18n = new KokimokiI18nService(this);
|
|
16227
17973
|
this._storage = new KokimokiStorageService(this);
|
|
16228
17974
|
this._leaderboard = new KokimokiLeaderboardService(this);
|
|
16229
17975
|
// Set up ping interval
|
|
@@ -16733,6 +18479,44 @@ class KokimokiClient extends EventEmitter$1 {
|
|
|
16733
18479
|
clearInterval(this._pingInterval);
|
|
16734
18480
|
}
|
|
16735
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
|
+
}
|
|
16736
18520
|
/**
|
|
16737
18521
|
* Gets the internal room hash identifier for a store.
|
|
16738
18522
|
*
|
|
@@ -16824,6 +18608,15 @@ class KokimokiClient extends EventEmitter$1 {
|
|
|
16824
18608
|
}
|
|
16825
18609
|
return this._ai;
|
|
16826
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
|
+
}
|
|
16827
18620
|
/**
|
|
16828
18621
|
* Access file upload and management for media files, images, and user-generated content.
|
|
16829
18622
|
*/
|
|
@@ -17154,7 +18947,14 @@ function subscribeKey(proxyObject, key, callback, notifyInSync) {
|
|
|
17154
18947
|
}
|
|
17155
18948
|
|
|
17156
18949
|
let currentCleanups;
|
|
18950
|
+
let didWarnDeprecation = false;
|
|
17157
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
|
+
}
|
|
17158
18958
|
let alive = true;
|
|
17159
18959
|
const cleanups = /* @__PURE__ */ new Set();
|
|
17160
18960
|
const subscriptions = /* @__PURE__ */ new Map();
|
|
@@ -17210,7 +19010,7 @@ function watch(callback, options) {
|
|
|
17210
19010
|
return cleanup;
|
|
17211
19011
|
}
|
|
17212
19012
|
|
|
17213
|
-
const DEVTOOLS = Symbol();
|
|
19013
|
+
const DEVTOOLS = /* @__PURE__ */ Symbol();
|
|
17214
19014
|
function devtools(proxyObject, options) {
|
|
17215
19015
|
const { enabled, name = "", ...rest } = options || {};
|
|
17216
19016
|
let extension;
|
|
@@ -17224,10 +19024,11 @@ function devtools(proxyObject, options) {
|
|
|
17224
19024
|
}
|
|
17225
19025
|
return;
|
|
17226
19026
|
}
|
|
19027
|
+
unstable_enableOp();
|
|
17227
19028
|
let isTimeTraveling = false;
|
|
17228
19029
|
const devtools2 = extension.connect({ name, ...rest });
|
|
17229
|
-
const unsub1 = subscribe(proxyObject, (
|
|
17230
|
-
const action =
|
|
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(", ");
|
|
17231
19032
|
if (!action) {
|
|
17232
19033
|
return;
|
|
17233
19034
|
}
|
|
@@ -17288,7 +19089,7 @@ function devtools(proxyObject, options) {
|
|
|
17288
19089
|
};
|
|
17289
19090
|
}
|
|
17290
19091
|
|
|
17291
|
-
const DUMMY_SYMBOL = Symbol();
|
|
19092
|
+
const DUMMY_SYMBOL = /* @__PURE__ */ Symbol();
|
|
17292
19093
|
function useProxy(proxy, options) {
|
|
17293
19094
|
const snapshot = useSnapshot(proxy, options);
|
|
17294
19095
|
snapshot[DUMMY_SYMBOL];
|
|
@@ -17303,5 +19104,5 @@ function useProxy(proxy, options) {
|
|
|
17303
19104
|
});
|
|
17304
19105
|
}
|
|
17305
19106
|
|
|
17306
|
-
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 };
|
|
17307
19108
|
//# sourceMappingURL=kokimoki.min.js.map
|