@voidhash/mimic 0.0.1 → 0.0.3
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/.turbo/turbo-build.log +257 -42
- package/dist/Document.cjs +152 -0
- package/dist/Document.d.cts +67 -0
- package/dist/Document.d.cts.map +1 -0
- package/dist/Document.d.mts +68 -0
- package/dist/Document.d.mts.map +1 -0
- package/dist/Document.mjs +147 -0
- package/dist/Document.mjs.map +1 -0
- package/dist/EffectSchema.cjs +180 -0
- package/dist/EffectSchema.d.cts +84 -0
- package/dist/EffectSchema.d.cts.map +1 -0
- package/dist/EffectSchema.d.mts +84 -0
- package/dist/EffectSchema.d.mts.map +1 -0
- package/dist/EffectSchema.mjs +176 -0
- package/dist/EffectSchema.mjs.map +1 -0
- package/dist/FractionalIndex.cjs +365 -0
- package/dist/FractionalIndex.mjs +364 -0
- package/dist/FractionalIndex.mjs.map +1 -0
- package/dist/Operation.cjs +53 -0
- package/dist/Operation.d.cts +39 -0
- package/dist/Operation.d.cts.map +1 -0
- package/dist/Operation.d.mts +39 -0
- package/dist/Operation.d.mts.map +1 -0
- package/dist/Operation.mjs +46 -0
- package/dist/Operation.mjs.map +1 -0
- package/dist/OperationDefinition.cjs +13 -0
- package/dist/OperationDefinition.d.cts +12 -0
- package/dist/OperationDefinition.d.cts.map +1 -0
- package/dist/OperationDefinition.d.mts +12 -0
- package/dist/OperationDefinition.d.mts.map +1 -0
- package/dist/OperationDefinition.mjs +13 -0
- package/dist/OperationDefinition.mjs.map +1 -0
- package/dist/OperationPath.cjs +148 -0
- package/dist/OperationPath.d.cts +60 -0
- package/dist/OperationPath.d.cts.map +1 -0
- package/dist/OperationPath.d.mts +60 -0
- package/dist/OperationPath.d.mts.map +1 -0
- package/dist/OperationPath.mjs +138 -0
- package/dist/OperationPath.mjs.map +1 -0
- package/dist/{Presence-gWrmGBeu.cjs → Presence.cjs} +4 -39
- package/dist/{Presence-N8u7Eppr.d.mts → Presence.d.cts} +2 -2
- package/dist/Presence.d.cts.map +1 -0
- package/dist/{Presence-DKKP4v5X.d.cts → Presence.d.mts} +2 -2
- package/dist/Presence.d.mts.map +1 -0
- package/dist/{Presence-DdMVKcOv.mjs → Presence.mjs} +3 -28
- package/dist/Presence.mjs.map +1 -0
- package/dist/Primitive.cjs +52 -0
- package/dist/Primitive.d.cts +20 -0
- package/dist/Primitive.d.cts.map +1 -0
- package/dist/Primitive.d.mts +20 -0
- package/dist/Primitive.d.mts.map +1 -0
- package/dist/Primitive.mjs +48 -0
- package/dist/Primitive.mjs.map +1 -0
- package/dist/ProxyEnvironment.cjs +34 -0
- package/dist/ProxyEnvironment.d.cts +31 -0
- package/dist/ProxyEnvironment.d.cts.map +1 -0
- package/dist/ProxyEnvironment.d.mts +31 -0
- package/dist/ProxyEnvironment.d.mts.map +1 -0
- package/dist/ProxyEnvironment.mjs +29 -0
- package/dist/ProxyEnvironment.mjs.map +1 -0
- package/dist/Transaction.cjs +66 -0
- package/dist/Transaction.d.cts +56 -0
- package/dist/Transaction.d.cts.map +1 -0
- package/dist/Transaction.d.mts +56 -0
- package/dist/Transaction.d.mts.map +1 -0
- package/dist/Transaction.mjs +58 -0
- package/dist/Transaction.mjs.map +1 -0
- package/dist/Transform.cjs +11 -0
- package/dist/Transform.d.cts +21 -0
- package/dist/Transform.d.cts.map +1 -0
- package/dist/Transform.d.mts +21 -0
- package/dist/Transform.d.mts.map +1 -0
- package/dist/Transform.mjs +6 -0
- package/dist/Transform.mjs.map +1 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.cjs +14 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.mjs +14 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs +27 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.mjs +27 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.cjs +16 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.mjs +16 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.mjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.cjs +18 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.mjs +12 -0
- package/dist/_virtual/rolldown_runtime.cjs +43 -0
- package/dist/{chunk-CLMFDpHK.mjs → _virtual/rolldown_runtime.mjs} +1 -1
- package/dist/client/ClientDocument.cjs +590 -0
- package/dist/client/ClientDocument.d.cts +161 -0
- package/dist/client/ClientDocument.d.cts.map +1 -0
- package/dist/client/ClientDocument.d.mts +162 -0
- package/dist/client/ClientDocument.d.mts.map +1 -0
- package/dist/client/ClientDocument.mjs +586 -0
- package/dist/client/ClientDocument.mjs.map +1 -0
- package/dist/client/Rebase.cjs +204 -0
- package/dist/client/Rebase.d.cts +87 -0
- package/dist/client/Rebase.d.cts.map +1 -0
- package/dist/client/Rebase.d.mts +88 -0
- package/dist/client/Rebase.d.mts.map +1 -0
- package/dist/client/Rebase.mjs +198 -0
- package/dist/client/Rebase.mjs.map +1 -0
- package/dist/client/StateMonitor.cjs +133 -0
- package/dist/client/StateMonitor.d.cts +122 -0
- package/dist/client/StateMonitor.d.cts.map +1 -0
- package/dist/client/StateMonitor.d.mts +122 -0
- package/dist/client/StateMonitor.d.mts.map +1 -0
- package/dist/client/StateMonitor.mjs +129 -0
- package/dist/client/StateMonitor.mjs.map +1 -0
- package/dist/client/Transport.cjs +11 -0
- package/dist/client/Transport.d.cts +237 -0
- package/dist/client/Transport.d.cts.map +1 -0
- package/dist/client/Transport.d.mts +237 -0
- package/dist/client/Transport.d.mts.map +1 -0
- package/dist/client/Transport.mjs +6 -0
- package/dist/client/Transport.mjs.map +1 -0
- package/dist/client/WebSocketTransport.cjs +396 -0
- package/dist/client/WebSocketTransport.d.cts +29 -0
- package/dist/client/WebSocketTransport.d.cts.map +1 -0
- package/dist/client/WebSocketTransport.d.mts +29 -0
- package/dist/client/WebSocketTransport.d.mts.map +1 -0
- package/dist/client/WebSocketTransport.mjs +392 -0
- package/dist/client/WebSocketTransport.mjs.map +1 -0
- package/dist/client/errors.cjs +135 -0
- package/dist/client/errors.d.cts +87 -0
- package/dist/client/errors.d.cts.map +1 -0
- package/dist/client/errors.d.mts +87 -0
- package/dist/client/errors.d.mts.map +1 -0
- package/dist/client/errors.mjs +127 -0
- package/dist/client/errors.mjs.map +1 -0
- package/dist/client/index.cjs +22 -1424
- package/dist/client/index.d.cts +8 -692
- package/dist/client/index.d.mts +8 -692
- package/dist/client/index.mjs +9 -1413
- package/dist/index.cjs +30 -2529
- package/dist/index.d.cts +12 -143
- package/dist/index.d.mts +12 -143
- package/dist/index.mjs +13 -2526
- package/dist/primitives/Array.cjs +302 -0
- package/dist/primitives/Array.d.cts +95 -0
- package/dist/primitives/Array.d.cts.map +1 -0
- package/dist/primitives/Array.d.mts +95 -0
- package/dist/primitives/Array.d.mts.map +1 -0
- package/dist/primitives/Array.mjs +301 -0
- package/dist/primitives/Array.mjs.map +1 -0
- package/dist/primitives/Boolean.cjs +95 -0
- package/dist/primitives/Boolean.d.cts +44 -0
- package/dist/primitives/Boolean.d.cts.map +1 -0
- package/dist/primitives/Boolean.d.mts +44 -0
- package/dist/primitives/Boolean.d.mts.map +1 -0
- package/dist/primitives/Boolean.mjs +94 -0
- package/dist/primitives/Boolean.mjs.map +1 -0
- package/dist/primitives/Either.cjs +200 -0
- package/dist/primitives/Either.d.cts +113 -0
- package/dist/primitives/Either.d.cts.map +1 -0
- package/dist/primitives/Either.d.mts +113 -0
- package/dist/primitives/Either.d.mts.map +1 -0
- package/dist/primitives/Either.mjs +199 -0
- package/dist/primitives/Either.mjs.map +1 -0
- package/dist/primitives/Lazy.cjs +46 -0
- package/dist/primitives/Lazy.d.cts +46 -0
- package/dist/primitives/Lazy.d.cts.map +1 -0
- package/dist/primitives/Lazy.d.mts +46 -0
- package/dist/primitives/Lazy.d.mts.map +1 -0
- package/dist/primitives/Lazy.mjs +46 -0
- package/dist/primitives/Lazy.mjs.map +1 -0
- package/dist/primitives/Literal.cjs +91 -0
- package/dist/primitives/Literal.d.cts +46 -0
- package/dist/primitives/Literal.d.cts.map +1 -0
- package/dist/primitives/Literal.d.mts +46 -0
- package/dist/primitives/Literal.d.mts.map +1 -0
- package/dist/primitives/Literal.mjs +90 -0
- package/dist/primitives/Literal.mjs.map +1 -0
- package/dist/primitives/Number.cjs +115 -0
- package/dist/primitives/Number.d.cts +54 -0
- package/dist/primitives/Number.d.cts.map +1 -0
- package/dist/primitives/Number.d.mts +54 -0
- package/dist/primitives/Number.d.mts.map +1 -0
- package/dist/primitives/Number.mjs +114 -0
- package/dist/primitives/Number.mjs.map +1 -0
- package/dist/primitives/String.cjs +127 -0
- package/dist/primitives/String.d.cts +56 -0
- package/dist/primitives/String.d.cts.map +1 -0
- package/dist/primitives/String.d.mts +56 -0
- package/dist/primitives/String.d.mts.map +1 -0
- package/dist/primitives/String.mjs +126 -0
- package/dist/primitives/String.mjs.map +1 -0
- package/dist/primitives/Struct.cjs +207 -0
- package/dist/primitives/Struct.d.cts +96 -0
- package/dist/primitives/Struct.d.cts.map +1 -0
- package/dist/primitives/Struct.d.mts +97 -0
- package/dist/primitives/Struct.d.mts.map +1 -0
- package/dist/primitives/Struct.mjs +206 -0
- package/dist/primitives/Struct.mjs.map +1 -0
- package/dist/primitives/Tree.cjs +575 -0
- package/dist/primitives/Tree.d.cts +185 -0
- package/dist/primitives/Tree.d.cts.map +1 -0
- package/dist/primitives/Tree.d.mts +185 -0
- package/dist/primitives/Tree.d.mts.map +1 -0
- package/dist/primitives/Tree.mjs +574 -0
- package/dist/primitives/Tree.mjs.map +1 -0
- package/dist/primitives/TreeNode.cjs +73 -0
- package/dist/primitives/TreeNode.d.cts +92 -0
- package/dist/primitives/TreeNode.d.cts.map +1 -0
- package/dist/primitives/TreeNode.d.mts +93 -0
- package/dist/primitives/TreeNode.d.mts.map +1 -0
- package/dist/primitives/TreeNode.mjs +72 -0
- package/dist/primitives/TreeNode.mjs.map +1 -0
- package/dist/primitives/Union.cjs +170 -0
- package/dist/primitives/Union.d.cts +81 -0
- package/dist/primitives/Union.d.cts.map +1 -0
- package/dist/primitives/Union.d.mts +81 -0
- package/dist/primitives/Union.d.mts.map +1 -0
- package/dist/primitives/Union.mjs +169 -0
- package/dist/primitives/Union.mjs.map +1 -0
- package/dist/primitives/shared.cjs +60 -0
- package/dist/primitives/shared.d.cts +147 -0
- package/dist/primitives/shared.d.cts.map +1 -0
- package/dist/primitives/shared.d.mts +147 -0
- package/dist/primitives/shared.d.mts.map +1 -0
- package/dist/primitives/shared.mjs +58 -0
- package/dist/primitives/shared.mjs.map +1 -0
- package/dist/server/ServerDocument.cjs +110 -0
- package/dist/server/ServerDocument.d.cts +98 -0
- package/dist/server/ServerDocument.d.cts.map +1 -0
- package/dist/server/ServerDocument.d.mts +99 -0
- package/dist/server/ServerDocument.d.mts.map +1 -0
- package/dist/server/ServerDocument.mjs +106 -0
- package/dist/server/ServerDocument.mjs.map +1 -0
- package/dist/server/errors.cjs +85 -0
- package/dist/server/errors.d.cts +53 -0
- package/dist/server/errors.d.cts.map +1 -0
- package/dist/server/errors.d.mts +53 -0
- package/dist/server/errors.d.mts.map +1 -0
- package/dist/server/errors.mjs +81 -0
- package/dist/server/errors.mjs.map +1 -0
- package/dist/server/index.cjs +9 -185
- package/dist/server/index.d.cts +3 -148
- package/dist/server/index.d.mts +3 -148
- package/dist/server/index.mjs +3 -181
- package/dist/types/index.cjs +16 -0
- package/dist/types/index.d.cts +16 -0
- package/dist/types/index.d.cts.map +1 -0
- package/dist/types/index.d.mts +16 -0
- package/dist/types/index.d.mts.map +1 -0
- package/dist/types/index.mjs +12 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/utils/tree-helpers.cjs +443 -0
- package/dist/utils/tree-helpers.d.cts +280 -0
- package/dist/utils/tree-helpers.d.cts.map +1 -0
- package/dist/utils/tree-helpers.d.mts +280 -0
- package/dist/utils/tree-helpers.d.mts.map +1 -0
- package/dist/utils/tree-helpers.mjs +439 -0
- package/dist/utils/tree-helpers.mjs.map +1 -0
- package/package.json +2 -2
- package/src/index.ts +2 -0
- package/src/primitives/shared.ts +7 -1
- package/src/types/index.ts +137 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/tree-helpers.ts +648 -0
- package/tsdown.config.ts +1 -1
- package/dist/Document-ChuFrTk1.cjs +0 -571
- package/dist/Document-CwiAFTIq.mjs +0 -438
- package/dist/Document-CwiAFTIq.mjs.map +0 -1
- package/dist/Presence-DKKP4v5X.d.cts.map +0 -1
- package/dist/Presence-DdMVKcOv.mjs.map +0 -1
- package/dist/Presence-N8u7Eppr.d.mts.map +0 -1
- package/dist/Primitive-CvFVxR8_.d.cts +0 -1175
- package/dist/Primitive-CvFVxR8_.d.cts.map +0 -1
- package/dist/Primitive-lEhQyGVL.d.mts +0 -1175
- package/dist/Primitive-lEhQyGVL.d.mts.map +0 -1
- package/dist/client/index.d.cts.map +0 -1
- package/dist/client/index.d.mts.map +0 -1
- package/dist/client/index.mjs.map +0 -1
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/server/index.d.cts.map +0 -1
- package/dist/server/index.d.mts.map +0 -1
- package/dist/server/index.mjs.map +0 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/FractionalIndex.ts
|
|
4
|
+
function createCharSetDicts(charSet) {
|
|
5
|
+
const byCode = {};
|
|
6
|
+
const byChar = {};
|
|
7
|
+
const length = charSet.length;
|
|
8
|
+
for (let i = 0; i < length; i++) {
|
|
9
|
+
const char = charSet[i];
|
|
10
|
+
if (char === void 0) throw new Error("invalid charSet: missing character at index " + i);
|
|
11
|
+
byCode[i] = char;
|
|
12
|
+
byChar[char] = i;
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
byCode,
|
|
16
|
+
byChar,
|
|
17
|
+
length
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function integerLimits(dicts, firstPositive, mostPositive, mostNegative) {
|
|
21
|
+
return Effect.gen(function* () {
|
|
22
|
+
const firstPositiveIndex = firstPositive ? dicts.byChar[firstPositive] : Math.ceil(dicts.length / 2);
|
|
23
|
+
const mostPositiveIndex = mostPositive ? dicts.byChar[mostPositive] : dicts.length - 1;
|
|
24
|
+
const mostNegativeIndex = mostNegative ? dicts.byChar[mostNegative] : 0;
|
|
25
|
+
if (firstPositiveIndex === void 0 || mostPositiveIndex === void 0 || mostNegativeIndex === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid charSet"));
|
|
26
|
+
if (mostPositiveIndex - firstPositiveIndex < 3) return yield* Effect.fail(/* @__PURE__ */ new Error("mostPositive must be at least 3 characters away from neutral"));
|
|
27
|
+
if (firstPositiveIndex - mostNegativeIndex < 3) return yield* Effect.fail(/* @__PURE__ */ new Error("mostNegative must be at least 3 characters away from neutral"));
|
|
28
|
+
const firstPositiveChar = dicts.byCode[firstPositiveIndex];
|
|
29
|
+
const mostPositiveChar = dicts.byCode[mostPositiveIndex];
|
|
30
|
+
const firstNegativeChar = dicts.byCode[firstPositiveIndex - 1];
|
|
31
|
+
const mostNegativeChar = dicts.byCode[mostNegativeIndex];
|
|
32
|
+
if (firstPositiveChar === void 0 || mostPositiveChar === void 0 || firstNegativeChar === void 0 || mostNegativeChar === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid charSet"));
|
|
33
|
+
return {
|
|
34
|
+
firstPositive: firstPositiveChar,
|
|
35
|
+
mostPositive: mostPositiveChar,
|
|
36
|
+
firstNegative: firstNegativeChar,
|
|
37
|
+
mostNegative: mostNegativeChar
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function paddingDict(jitterRange, charSetLength) {
|
|
42
|
+
const paddingDict$1 = {};
|
|
43
|
+
for (let i = 0; i < 100; i++) {
|
|
44
|
+
const value = Math.pow(charSetLength, i);
|
|
45
|
+
paddingDict$1[i] = value;
|
|
46
|
+
if (value > jitterRange) break;
|
|
47
|
+
}
|
|
48
|
+
return paddingDict$1;
|
|
49
|
+
}
|
|
50
|
+
function validateChars(characters) {
|
|
51
|
+
if (characters.length < 7) return Effect.fail(/* @__PURE__ */ new Error("charSet must be at least 7 characters long"));
|
|
52
|
+
if (!(characters.split("").sort().join("") === characters)) return Effect.fail(/* @__PURE__ */ new Error("charSet must be sorted"));
|
|
53
|
+
return Effect.void;
|
|
54
|
+
}
|
|
55
|
+
function indexCharacterSet(options) {
|
|
56
|
+
return Effect.gen(function* () {
|
|
57
|
+
var _options$jitterRange;
|
|
58
|
+
yield* validateChars(options.chars);
|
|
59
|
+
const dicts = createCharSetDicts(options.chars);
|
|
60
|
+
const limits = yield* integerLimits(dicts, options.firstPositive, options.mostPositive, options.mostNegative);
|
|
61
|
+
const jitterRange = (_options$jitterRange = options.jitterRange) !== null && _options$jitterRange !== void 0 ? _options$jitterRange : Math.floor(Math.pow(dicts.length, 3) / 5);
|
|
62
|
+
const paddingRange = paddingDict(jitterRange, dicts.length);
|
|
63
|
+
const first = dicts.byCode[0];
|
|
64
|
+
const last = dicts.byCode[dicts.length - 1];
|
|
65
|
+
if (first === void 0 || last === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid charSet"));
|
|
66
|
+
return {
|
|
67
|
+
chars: options.chars,
|
|
68
|
+
byChar: dicts.byChar,
|
|
69
|
+
byCode: dicts.byCode,
|
|
70
|
+
length: dicts.length,
|
|
71
|
+
first,
|
|
72
|
+
last,
|
|
73
|
+
firstPositive: limits.firstPositive,
|
|
74
|
+
mostPositive: limits.mostPositive,
|
|
75
|
+
firstNegative: limits.firstNegative,
|
|
76
|
+
mostNegative: limits.mostNegative,
|
|
77
|
+
jitterRange,
|
|
78
|
+
paddingDict: paddingRange
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
let _base62CharSet = null;
|
|
83
|
+
function base62CharSet() {
|
|
84
|
+
if (_base62CharSet) return _base62CharSet;
|
|
85
|
+
_base62CharSet = Effect.runSync(indexCharacterSet({
|
|
86
|
+
chars: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
87
|
+
firstPositive: "a",
|
|
88
|
+
mostPositive: "z",
|
|
89
|
+
mostNegative: "A"
|
|
90
|
+
}));
|
|
91
|
+
return _base62CharSet;
|
|
92
|
+
}
|
|
93
|
+
function makeSameLength(a, b, pad, fillChar, forceLength) {
|
|
94
|
+
const max = forceLength !== null && forceLength !== void 0 ? forceLength : Math.max(a.length, b.length);
|
|
95
|
+
if (pad === "start") return [a.padStart(max, fillChar), b.padStart(max, fillChar)];
|
|
96
|
+
return [a.padEnd(max, fillChar), b.padEnd(max, fillChar)];
|
|
97
|
+
}
|
|
98
|
+
function distanceBetween(a, b, charSet) {
|
|
99
|
+
const indexA = charSet.byChar[a];
|
|
100
|
+
const indexB = charSet.byChar[b];
|
|
101
|
+
if (indexA === void 0 || indexB === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid character in distance calculation"));
|
|
102
|
+
return Effect.succeed(Math.abs(indexA - indexB));
|
|
103
|
+
}
|
|
104
|
+
function integerLengthFromSecondLevel(key, direction, charSet) {
|
|
105
|
+
if (key.length === 0) return Effect.succeed(0);
|
|
106
|
+
const firstChar = key[0];
|
|
107
|
+
if (!firstChar || firstChar > charSet.mostPositive || firstChar < charSet.mostNegative) return Effect.fail(/* @__PURE__ */ new Error("invalid firstChar on key"));
|
|
108
|
+
if (firstChar === charSet.mostPositive && direction === "positive") return Effect.gen(function* () {
|
|
109
|
+
const totalPositiveRoom = yield* distanceBetween(firstChar, charSet.mostNegative, charSet);
|
|
110
|
+
const rest = yield* integerLengthFromSecondLevel(key.slice(1), direction, charSet);
|
|
111
|
+
return totalPositiveRoom + 1 + rest;
|
|
112
|
+
});
|
|
113
|
+
if (firstChar === charSet.mostNegative && direction === "negative") return Effect.gen(function* () {
|
|
114
|
+
const totalNegativeRoom = yield* distanceBetween(firstChar, charSet.mostPositive, charSet);
|
|
115
|
+
const rest = yield* integerLengthFromSecondLevel(key.slice(1), direction, charSet);
|
|
116
|
+
return totalNegativeRoom + 1 + rest;
|
|
117
|
+
});
|
|
118
|
+
if (direction === "positive") return Effect.gen(function* () {
|
|
119
|
+
return (yield* distanceBetween(firstChar, charSet.mostNegative, charSet)) + 2;
|
|
120
|
+
});
|
|
121
|
+
else return Effect.gen(function* () {
|
|
122
|
+
return (yield* distanceBetween(firstChar, charSet.mostPositive, charSet)) + 2;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function integerLength(head, charSet) {
|
|
126
|
+
if (head.length === 0) return Effect.fail(/* @__PURE__ */ new Error("head cannot be empty"));
|
|
127
|
+
const firstChar = head[0];
|
|
128
|
+
if (!firstChar || firstChar > charSet.mostPositive || firstChar < charSet.mostNegative) return Effect.fail(/* @__PURE__ */ new Error("invalid firstChar on key"));
|
|
129
|
+
if (firstChar === charSet.mostPositive) return Effect.gen(function* () {
|
|
130
|
+
const firstLevel = yield* distanceBetween(firstChar, charSet.firstPositive, charSet);
|
|
131
|
+
const rest = yield* integerLengthFromSecondLevel(head.slice(1), "positive", charSet);
|
|
132
|
+
return firstLevel + 1 + rest;
|
|
133
|
+
});
|
|
134
|
+
if (firstChar === charSet.mostNegative) return Effect.gen(function* () {
|
|
135
|
+
const firstLevel = yield* distanceBetween(firstChar, charSet.firstNegative, charSet);
|
|
136
|
+
const rest = yield* integerLengthFromSecondLevel(head.slice(1), "negative", charSet);
|
|
137
|
+
return firstLevel + 1 + rest;
|
|
138
|
+
});
|
|
139
|
+
if (firstChar >= charSet.firstPositive) return Effect.gen(function* () {
|
|
140
|
+
return (yield* distanceBetween(firstChar, charSet.firstPositive, charSet)) + 2;
|
|
141
|
+
});
|
|
142
|
+
else return Effect.gen(function* () {
|
|
143
|
+
return (yield* distanceBetween(firstChar, charSet.firstNegative, charSet)) + 2;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function encodeToCharSet(int, charSet) {
|
|
147
|
+
if (int === 0) {
|
|
148
|
+
const zero = charSet.byCode[0];
|
|
149
|
+
if (zero === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid charSet: missing code 0"));
|
|
150
|
+
return Effect.succeed(zero);
|
|
151
|
+
}
|
|
152
|
+
let res = "";
|
|
153
|
+
const max = charSet.length;
|
|
154
|
+
while (int > 0) {
|
|
155
|
+
const code = charSet.byCode[int % max];
|
|
156
|
+
if (code === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid character code in encodeToCharSet"));
|
|
157
|
+
res = code + res;
|
|
158
|
+
int = Math.floor(int / max);
|
|
159
|
+
}
|
|
160
|
+
return Effect.succeed(res);
|
|
161
|
+
}
|
|
162
|
+
function decodeCharSetToNumber(key, charSet) {
|
|
163
|
+
let res = 0;
|
|
164
|
+
const length = key.length;
|
|
165
|
+
const max = charSet.length;
|
|
166
|
+
for (let i = 0; i < length; i++) {
|
|
167
|
+
const char = key[i];
|
|
168
|
+
if (char === void 0) continue;
|
|
169
|
+
const charIndex = charSet.byChar[char];
|
|
170
|
+
if (charIndex === void 0) continue;
|
|
171
|
+
res += charIndex * Math.pow(max, length - i - 1);
|
|
172
|
+
}
|
|
173
|
+
return res;
|
|
174
|
+
}
|
|
175
|
+
function addCharSetKeys(a, b, charSet) {
|
|
176
|
+
const base = charSet.length;
|
|
177
|
+
const [paddedA, paddedB] = makeSameLength(a, b, "start", charSet.first);
|
|
178
|
+
const result = [];
|
|
179
|
+
let carry = 0;
|
|
180
|
+
for (let i = paddedA.length - 1; i >= 0; i--) {
|
|
181
|
+
const charA = paddedA[i];
|
|
182
|
+
const charB = paddedB[i];
|
|
183
|
+
if (!charA || !charB) return Effect.fail(/* @__PURE__ */ new Error("invalid character in addCharSetKeys"));
|
|
184
|
+
const digitA = charSet.byChar[charA];
|
|
185
|
+
const digitB = charSet.byChar[charB];
|
|
186
|
+
if (digitA === void 0 || digitB === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid character in addCharSetKeys"));
|
|
187
|
+
const sum = digitA + digitB + carry;
|
|
188
|
+
carry = Math.floor(sum / base);
|
|
189
|
+
const remainder = sum % base;
|
|
190
|
+
const codeChar = charSet.byCode[remainder];
|
|
191
|
+
if (codeChar === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid character code in addCharSetKeys"));
|
|
192
|
+
result.unshift(codeChar);
|
|
193
|
+
}
|
|
194
|
+
if (carry > 0) {
|
|
195
|
+
const carryChar = charSet.byCode[carry];
|
|
196
|
+
if (carryChar === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid carry character code"));
|
|
197
|
+
result.unshift(carryChar);
|
|
198
|
+
}
|
|
199
|
+
return Effect.succeed(result.join(""));
|
|
200
|
+
}
|
|
201
|
+
function subtractCharSetKeys(a, b, charSet, stripLeadingZeros = true) {
|
|
202
|
+
const base = charSet.length;
|
|
203
|
+
const [paddedA, paddedB] = makeSameLength(a, b, "start", charSet.first);
|
|
204
|
+
const result = [];
|
|
205
|
+
let borrow = 0;
|
|
206
|
+
for (let i = paddedA.length - 1; i >= 0; i--) {
|
|
207
|
+
const charA = paddedA[i];
|
|
208
|
+
const charB = paddedB[i];
|
|
209
|
+
if (!charA || !charB) return Effect.fail(/* @__PURE__ */ new Error("invalid character in subtractCharSetKeys"));
|
|
210
|
+
let digitA = charSet.byChar[charA];
|
|
211
|
+
const digitBValue = charSet.byChar[charB];
|
|
212
|
+
if (digitA === void 0 || digitBValue === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid character in subtractCharSetKeys"));
|
|
213
|
+
const digitB = digitBValue + borrow;
|
|
214
|
+
if (digitA < digitB) {
|
|
215
|
+
borrow = 1;
|
|
216
|
+
digitA += base;
|
|
217
|
+
} else borrow = 0;
|
|
218
|
+
const difference = digitA - digitB;
|
|
219
|
+
const codeChar = charSet.byCode[difference];
|
|
220
|
+
if (codeChar === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid character code in subtractCharSetKeys"));
|
|
221
|
+
result.unshift(codeChar);
|
|
222
|
+
}
|
|
223
|
+
if (borrow > 0) return Effect.fail(/* @__PURE__ */ new Error("Subtraction result is negative. Ensure a is greater than or equal to b."));
|
|
224
|
+
while (stripLeadingZeros && result.length > 1 && result[0] === charSet.first) result.shift();
|
|
225
|
+
return Effect.succeed(result.join(""));
|
|
226
|
+
}
|
|
227
|
+
function incrementKey(key, charSet) {
|
|
228
|
+
const one = charSet.byCode[1];
|
|
229
|
+
if (one === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid charSet: missing code 1"));
|
|
230
|
+
return addCharSetKeys(key, one, charSet);
|
|
231
|
+
}
|
|
232
|
+
function decrementKey(key, charSet) {
|
|
233
|
+
const one = charSet.byCode[1];
|
|
234
|
+
if (one === void 0) return Effect.fail(/* @__PURE__ */ new Error("invalid charSet: missing code 1"));
|
|
235
|
+
return subtractCharSetKeys(key, one, charSet, false);
|
|
236
|
+
}
|
|
237
|
+
function lexicalDistance(a, b, charSet) {
|
|
238
|
+
const [lower, upper] = makeSameLength(a, b, "end", charSet.first).sort();
|
|
239
|
+
return Effect.gen(function* () {
|
|
240
|
+
return decodeCharSetToNumber(yield* subtractCharSetKeys(upper, lower, charSet), charSet);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
function midPoint(lower, upper, charSet) {
|
|
244
|
+
return Effect.gen(function* () {
|
|
245
|
+
let [paddedLower, paddedUpper] = makeSameLength(lower, upper, "end", charSet.first);
|
|
246
|
+
let distance = yield* lexicalDistance(paddedLower, paddedUpper, charSet);
|
|
247
|
+
if (distance === 1) {
|
|
248
|
+
paddedLower = paddedLower.padEnd(paddedLower.length + 1, charSet.first);
|
|
249
|
+
distance = charSet.length;
|
|
250
|
+
}
|
|
251
|
+
const mid = yield* encodeToCharSet(Math.floor(distance / 2), charSet);
|
|
252
|
+
return yield* addCharSetKeys(paddedLower, mid, charSet);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
function startKey(charSet) {
|
|
256
|
+
return charSet.firstPositive + charSet.byCode[0];
|
|
257
|
+
}
|
|
258
|
+
function validInteger(integer, charSet) {
|
|
259
|
+
return Effect.gen(function* () {
|
|
260
|
+
return (yield* integerLength(integer, charSet)) === integer.length;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function validateOrderKey(orderKey, charSet) {
|
|
264
|
+
return Effect.gen(function* () {
|
|
265
|
+
yield* getIntegerPart(orderKey, charSet);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
function getIntegerPart(orderKey, charSet) {
|
|
269
|
+
return Effect.gen(function* () {
|
|
270
|
+
const integerPartLength = yield* integerLength(integerHead(orderKey, charSet), charSet);
|
|
271
|
+
if (integerPartLength > orderKey.length) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid order key length: " + orderKey));
|
|
272
|
+
return orderKey.slice(0, integerPartLength);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
function validateInteger(integer, charSet) {
|
|
276
|
+
return Effect.gen(function* () {
|
|
277
|
+
if (!(yield* validInteger(integer, charSet))) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid integer length: " + integer));
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function integerHead(integer, charSet) {
|
|
281
|
+
let i = 0;
|
|
282
|
+
if (integer[0] === charSet.mostPositive) while (integer[i] === charSet.mostPositive) i = i + 1;
|
|
283
|
+
if (integer[0] === charSet.mostNegative) while (integer[i] === charSet.mostNegative) i = i + 1;
|
|
284
|
+
return integer.slice(0, i + 1);
|
|
285
|
+
}
|
|
286
|
+
function splitInteger(integer, charSet) {
|
|
287
|
+
return Effect.gen(function* () {
|
|
288
|
+
const head = integerHead(integer, {
|
|
289
|
+
firstPositive: charSet.firstPositive,
|
|
290
|
+
mostPositive: charSet.mostPositive,
|
|
291
|
+
firstNegative: charSet.firstNegative,
|
|
292
|
+
mostNegative: charSet.mostNegative
|
|
293
|
+
});
|
|
294
|
+
return [head, integer.slice(head.length)];
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
function incrementIntegerHead(head, charSet) {
|
|
298
|
+
return Effect.gen(function* () {
|
|
299
|
+
const inPositiveRange = head >= charSet.firstPositive;
|
|
300
|
+
const nextHead = yield* incrementKey(head, charSet);
|
|
301
|
+
const headIsLimitMax = head[head.length - 1] === charSet.mostPositive;
|
|
302
|
+
const nextHeadIsLimitMax = nextHead[nextHead.length - 1] === charSet.mostPositive;
|
|
303
|
+
if (inPositiveRange && nextHeadIsLimitMax) return nextHead + charSet.mostNegative;
|
|
304
|
+
if (!inPositiveRange && headIsLimitMax) return head.slice(0, head.length - 1);
|
|
305
|
+
return nextHead;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
function decrementIntegerHead(head, charSet) {
|
|
309
|
+
return Effect.gen(function* () {
|
|
310
|
+
const inPositiveRange = head >= charSet.firstPositive;
|
|
311
|
+
const headIsLimitMin = head[head.length - 1] === charSet.mostNegative;
|
|
312
|
+
if (inPositiveRange && headIsLimitMin) return yield* decrementKey(head.slice(0, head.length - 1), charSet);
|
|
313
|
+
if (!inPositiveRange && headIsLimitMin) return head + charSet.mostPositive;
|
|
314
|
+
return yield* decrementKey(head, charSet);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
function startOnNewHead(head, limit, charSet) {
|
|
318
|
+
return Effect.gen(function* () {
|
|
319
|
+
const newLength = yield* integerLength(head, charSet);
|
|
320
|
+
const fillCharCode = limit === "upper" ? charSet.length - 1 : 0;
|
|
321
|
+
const fillChar = charSet.byCode[fillCharCode];
|
|
322
|
+
if (fillChar === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid fill character code"));
|
|
323
|
+
return head + fillChar.repeat(newLength - head.length);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
function incrementInteger(integer, charSet) {
|
|
327
|
+
return Effect.gen(function* () {
|
|
328
|
+
yield* validateInteger(integer, charSet);
|
|
329
|
+
const [head, digs] = yield* splitInteger(integer, charSet);
|
|
330
|
+
const maxChar = charSet.byCode[charSet.length - 1];
|
|
331
|
+
if (maxChar === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid charSet: missing max character"));
|
|
332
|
+
if (digs.split("").some((d) => d !== maxChar)) return head + (yield* incrementKey(digs, charSet));
|
|
333
|
+
return yield* startOnNewHead(yield* incrementIntegerHead(head, charSet), "lower", charSet);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
function decrementInteger(integer, charSet) {
|
|
337
|
+
return Effect.gen(function* () {
|
|
338
|
+
yield* validateInteger(integer, charSet);
|
|
339
|
+
const [head, digs] = yield* splitInteger(integer, charSet);
|
|
340
|
+
const minChar = charSet.byCode[0];
|
|
341
|
+
if (minChar === void 0) return yield* Effect.fail(/* @__PURE__ */ new Error("invalid charSet: missing min character"));
|
|
342
|
+
if (digs.split("").some((d) => d !== minChar)) return head + (yield* decrementKey(digs, charSet));
|
|
343
|
+
return yield* startOnNewHead(yield* decrementIntegerHead(head, charSet), "upper", charSet);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Generate a key between two other keys.
|
|
348
|
+
* If either lower or upper is null, the key will be generated at the start or end of the list.
|
|
349
|
+
*/
|
|
350
|
+
function generateKeyBetween(lower, upper, charSet = base62CharSet()) {
|
|
351
|
+
return Effect.gen(function* () {
|
|
352
|
+
if (lower !== null) yield* validateOrderKey(lower, charSet);
|
|
353
|
+
if (upper !== null) yield* validateOrderKey(upper, charSet);
|
|
354
|
+
if (lower === null && upper === null) return startKey(charSet);
|
|
355
|
+
if (lower === null) return yield* decrementInteger(yield* getIntegerPart(upper, charSet), charSet);
|
|
356
|
+
if (upper === null) return yield* incrementInteger(yield* getIntegerPart(lower, charSet), charSet);
|
|
357
|
+
if (lower >= upper) return yield* Effect.fail(/* @__PURE__ */ new Error(lower + " >= " + upper));
|
|
358
|
+
return yield* midPoint(lower, upper, charSet);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
//#endregion
|
|
363
|
+
export { base62CharSet, generateKeyBetween };
|
|
364
|
+
//# sourceMappingURL=FractionalIndex.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FractionalIndex.mjs","names":["byCode: Record<number, string>","byChar: Record<string, number>","paddingDict: Record<number, number>","paddingDict","_base62CharSet: IndexedCharacterSet | null","result: string[]"],"sources":["../src/FractionalIndex.ts"],"sourcesContent":["import { Effect, Random } from \"effect\"\n\n// ============================================================================\n// Types and Interfaces\n// ============================================================================\n\nexport interface IndexCharacterSetOptions {\n chars: string // sorted string of unique characters like \"0123456789ABC\"\n jitterRange?: number // default is 1/5 of the total range created by adding 3 characters\n firstPositive?: string // default is the middle character\n mostPositive?: string // default is the last character\n mostNegative?: string // default is the first character\n}\n\nexport interface IndexedCharacterSet {\n chars: string\n byChar: Record<string, number>\n byCode: Record<number, string>\n paddingDict: Record<number, number>\n length: number\n first: string\n last: string\n firstPositive: string\n mostPositive: string\n firstNegative: string\n mostNegative: string\n jitterRange: number\n}\n\nexport type IntegerLimits = {\n firstPositive: string\n mostPositive: string\n firstNegative: string\n mostNegative: string\n}\n\nexport interface GeneratorOptions {\n charSet?: IndexedCharacterSet\n useJitter?: boolean\n groupIdLength?: number\n}\n\n// ============================================================================\n// Character Set Functions\n// ============================================================================\n\ntype CharSetDicts = {\n byCode: Record<number, string>\n byChar: Record<string, number>\n length: number\n}\n\nfunction createCharSetDicts(charSet: string): CharSetDicts {\n const byCode: Record<number, string> = {}\n const byChar: Record<string, number> = {}\n const length = charSet.length\n\n for (let i = 0; i < length; i++) {\n const char = charSet[i]\n if (char === undefined) {\n throw new Error(\"invalid charSet: missing character at index \" + i)\n }\n byCode[i] = char\n byChar[char] = i\n }\n return {\n byCode: byCode,\n byChar: byChar,\n length: length,\n }\n}\n\nfunction integerLimits(\n dicts: CharSetDicts,\n firstPositive?: string,\n mostPositive?: string,\n mostNegative?: string\n): Effect.Effect<IntegerLimits, Error> {\n return Effect.gen(function* () {\n const firstPositiveIndex = firstPositive\n ? dicts.byChar[firstPositive]\n : Math.ceil(dicts.length / 2)\n const mostPositiveIndex = mostPositive\n ? dicts.byChar[mostPositive]\n : dicts.length - 1\n const mostNegativeIndex = mostNegative ? dicts.byChar[mostNegative] : 0\n\n if (\n firstPositiveIndex === undefined ||\n mostPositiveIndex === undefined ||\n mostNegativeIndex === undefined\n ) {\n return yield* Effect.fail(new Error(\"invalid charSet\"))\n }\n if (mostPositiveIndex - firstPositiveIndex < 3) {\n return yield* Effect.fail(\n new Error(\"mostPositive must be at least 3 characters away from neutral\")\n )\n }\n if (firstPositiveIndex - mostNegativeIndex < 3) {\n return yield* Effect.fail(\n new Error(\"mostNegative must be at least 3 characters away from neutral\")\n )\n }\n\n const firstPositiveChar = dicts.byCode[firstPositiveIndex]\n const mostPositiveChar = dicts.byCode[mostPositiveIndex]\n const firstNegativeChar = dicts.byCode[firstPositiveIndex - 1]\n const mostNegativeChar = dicts.byCode[mostNegativeIndex]\n\n if (\n firstPositiveChar === undefined ||\n mostPositiveChar === undefined ||\n firstNegativeChar === undefined ||\n mostNegativeChar === undefined\n ) {\n return yield* Effect.fail(new Error(\"invalid charSet\"))\n }\n\n return {\n firstPositive: firstPositiveChar,\n mostPositive: mostPositiveChar,\n firstNegative: firstNegativeChar,\n mostNegative: mostNegativeChar,\n }\n })\n}\n\nfunction paddingDict(jitterRange: number, charSetLength: number): Record<number, number> {\n const paddingDict: Record<number, number> = {}\n for (let i = 0; i < 100; i++) {\n const value = Math.pow(charSetLength, i)\n paddingDict[i] = value\n if (value > jitterRange) {\n break\n }\n }\n return paddingDict\n}\n\nexport function validateChars(characters: string): Effect.Effect<void, Error> {\n if (characters.length < 7) {\n return Effect.fail(new Error(\"charSet must be at least 7 characters long\"))\n }\n const chars = characters.split(\"\")\n const sorted = chars.sort()\n const isEqual = sorted.join(\"\") === characters\n if (!isEqual) {\n return Effect.fail(new Error(\"charSet must be sorted\"))\n }\n return Effect.void\n}\n\nexport function indexCharacterSet(\n options: IndexCharacterSetOptions\n): Effect.Effect<IndexedCharacterSet, Error> {\n return Effect.gen(function* () {\n yield* validateChars(options.chars)\n const dicts = createCharSetDicts(options.chars)\n const limits = yield* integerLimits(\n dicts,\n options.firstPositive,\n options.mostPositive,\n options.mostNegative\n )\n // 1/5 of the total range if we add 3 characters, TODO: feels a bit arbitrary and could be improved\n const jitterRange =\n options.jitterRange ?? Math.floor(Math.pow(dicts.length, 3) / 5)\n\n const paddingRange = paddingDict(jitterRange, dicts.length)\n\n const first = dicts.byCode[0]\n const last = dicts.byCode[dicts.length - 1]\n\n if (first === undefined || last === undefined) {\n return yield* Effect.fail(new Error(\"invalid charSet\"))\n }\n\n return {\n chars: options.chars,\n byChar: dicts.byChar,\n byCode: dicts.byCode,\n length: dicts.length,\n first,\n last,\n firstPositive: limits.firstPositive,\n mostPositive: limits.mostPositive,\n firstNegative: limits.firstNegative,\n mostNegative: limits.mostNegative,\n jitterRange,\n paddingDict: paddingRange,\n }\n })\n}\n\n// cache the base62 charSet since it's the default\nlet _base62CharSet: IndexedCharacterSet | null = null\n\nexport function base62CharSet(): IndexedCharacterSet {\n if (_base62CharSet) return _base62CharSet\n // We use Effect.runSync here because base62CharSet is a synchronous API\n // and we know the parameters are valid\n _base62CharSet = Effect.runSync(\n indexCharacterSet({\n // Base62 are all the alphanumeric characters, database and user friendly\n // For shorter strings and more room you could opt for more characters\n chars: \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\",\n // This gives us nice human readable keys to start with a0 a1 etc\n firstPositive: \"a\",\n mostPositive: \"z\",\n mostNegative: \"A\",\n })\n )\n return _base62CharSet\n}\n\n// ============================================================================\n// Padding Functions\n// ============================================================================\n\nexport function makeSameLength(\n a: string,\n b: string,\n pad: \"start\" | \"end\",\n fillChar: string,\n forceLength?: number\n): [string, string] {\n const max = forceLength ?? Math.max(a.length, b.length)\n if (pad === \"start\") {\n return [a.padStart(max, fillChar), b.padStart(max, fillChar)]\n }\n return [a.padEnd(max, fillChar), b.padEnd(max, fillChar)]\n}\n\n// ============================================================================\n// Integer Length Functions\n// ============================================================================\n\nfunction distanceBetween(\n a: string,\n b: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<number, Error> {\n const indexA = charSet.byChar[a]\n const indexB = charSet.byChar[b]\n if (indexA === undefined || indexB === undefined) {\n return Effect.fail(new Error(\"invalid character in distance calculation\"))\n }\n return Effect.succeed(Math.abs(indexA - indexB))\n}\n\nfunction integerLengthFromSecondLevel(\n key: string,\n direction: \"positive\" | \"negative\",\n charSet: IndexedCharacterSet\n): Effect.Effect<number, Error> {\n if (key.length === 0) {\n return Effect.succeed(0)\n }\n const firstChar = key[0]\n if (!firstChar || firstChar > charSet.mostPositive || firstChar < charSet.mostNegative) {\n return Effect.fail(new Error(\"invalid firstChar on key\"))\n }\n if (firstChar === charSet.mostPositive && direction === \"positive\") {\n return Effect.gen(function* () {\n const totalPositiveRoom = yield* distanceBetween(firstChar, charSet.mostNegative, charSet)\n const rest = yield* integerLengthFromSecondLevel(key.slice(1), direction, charSet)\n return totalPositiveRoom + 1 + rest\n })\n }\n if (firstChar === charSet.mostNegative && direction === \"negative\") {\n return Effect.gen(function* () {\n const totalNegativeRoom = yield* distanceBetween(firstChar, charSet.mostPositive, charSet)\n const rest = yield* integerLengthFromSecondLevel(key.slice(1), direction, charSet)\n return totalNegativeRoom + 1 + rest\n })\n }\n if (direction === \"positive\") {\n return Effect.gen(function* () {\n const dist = yield* distanceBetween(firstChar, charSet.mostNegative, charSet)\n return dist + 2\n })\n } else {\n return Effect.gen(function* () {\n const dist = yield* distanceBetween(firstChar, charSet.mostPositive, charSet)\n return dist + 2\n })\n }\n}\n\nexport function integerLength(\n head: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<number, Error> {\n if (head.length === 0) {\n return Effect.fail(new Error(\"head cannot be empty\"))\n }\n const firstChar = head[0]\n if (!firstChar || firstChar > charSet.mostPositive || firstChar < charSet.mostNegative) {\n return Effect.fail(new Error(\"invalid firstChar on key\"))\n }\n if (firstChar === charSet.mostPositive) {\n return Effect.gen(function* () {\n const firstLevel = yield* distanceBetween(firstChar, charSet.firstPositive, charSet)\n const rest = yield* integerLengthFromSecondLevel(head.slice(1), \"positive\", charSet)\n return firstLevel + 1 + rest\n })\n }\n if (firstChar === charSet.mostNegative) {\n return Effect.gen(function* () {\n const firstLevel = yield* distanceBetween(firstChar, charSet.firstNegative, charSet)\n const rest = yield* integerLengthFromSecondLevel(head.slice(1), \"negative\", charSet)\n return firstLevel + 1 + rest\n })\n }\n const isPositiveRange = firstChar >= charSet.firstPositive\n if (isPositiveRange) {\n return Effect.gen(function* () {\n const dist = yield* distanceBetween(firstChar, charSet.firstPositive, charSet)\n return dist + 2\n })\n } else {\n return Effect.gen(function* () {\n const dist = yield* distanceBetween(firstChar, charSet.firstNegative, charSet)\n return dist + 2\n })\n }\n}\n\n// ============================================================================\n// Key as Number Functions\n// ============================================================================\n\nexport function encodeToCharSet(int: number, charSet: IndexedCharacterSet): Effect.Effect<string, Error> {\n if (int === 0) {\n const zero = charSet.byCode[0]\n if (zero === undefined) {\n return Effect.fail(new Error(\"invalid charSet: missing code 0\"))\n }\n return Effect.succeed(zero)\n }\n let res = \"\"\n const max = charSet.length\n while (int > 0) {\n const code = charSet.byCode[int % max]\n if (code === undefined) {\n return Effect.fail(new Error(\"invalid character code in encodeToCharSet\"))\n }\n res = code + res\n int = Math.floor(int / max)\n }\n return Effect.succeed(res)\n}\n\nexport function decodeCharSetToNumber(\n key: string,\n charSet: IndexedCharacterSet\n): number {\n let res = 0\n const length = key.length\n const max = charSet.length\n for (let i = 0; i < length; i++) {\n const char = key[i]\n if (char === undefined) {\n continue\n }\n const charIndex = charSet.byChar[char]\n if (charIndex === undefined) {\n continue\n }\n res += charIndex * Math.pow(max, length - i - 1)\n }\n return res\n}\n\nexport function addCharSetKeys(\n a: string,\n b: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n const base = charSet.length\n const [paddedA, paddedB] = makeSameLength(a, b, \"start\", charSet.first)\n\n const result: string[] = []\n let carry = 0\n\n // Iterate over the digits from right to left\n for (let i = paddedA.length - 1; i >= 0; i--) {\n const charA = paddedA[i]\n const charB = paddedB[i]\n if (!charA || !charB) {\n return Effect.fail(new Error(\"invalid character in addCharSetKeys\"))\n }\n const digitA = charSet.byChar[charA]\n const digitB = charSet.byChar[charB]\n if (digitA === undefined || digitB === undefined) {\n return Effect.fail(new Error(\"invalid character in addCharSetKeys\"))\n }\n const sum = digitA + digitB + carry\n carry = Math.floor(sum / base)\n const remainder = sum % base\n\n const codeChar = charSet.byCode[remainder]\n if (codeChar === undefined) {\n return Effect.fail(new Error(\"invalid character code in addCharSetKeys\"))\n }\n result.unshift(codeChar)\n }\n\n // If there's a carry left, add it to the result\n if (carry > 0) {\n const carryChar = charSet.byCode[carry]\n if (carryChar === undefined) {\n return Effect.fail(new Error(\"invalid carry character code\"))\n }\n result.unshift(carryChar)\n }\n\n return Effect.succeed(result.join(\"\"))\n}\n\nexport function subtractCharSetKeys(\n a: string,\n b: string,\n charSet: IndexedCharacterSet,\n stripLeadingZeros = true\n): Effect.Effect<string, Error> {\n const base = charSet.length\n const [paddedA, paddedB] = makeSameLength(a, b, \"start\", charSet.first)\n\n const result: string[] = []\n let borrow = 0\n\n // Iterate over the digits from right to left\n for (let i = paddedA.length - 1; i >= 0; i--) {\n const charA = paddedA[i]\n const charB = paddedB[i]\n if (!charA || !charB) {\n return Effect.fail(new Error(\"invalid character in subtractCharSetKeys\"))\n }\n let digitA = charSet.byChar[charA]\n const digitBValue = charSet.byChar[charB]\n if (digitA === undefined || digitBValue === undefined) {\n return Effect.fail(new Error(\"invalid character in subtractCharSetKeys\"))\n }\n const digitB = digitBValue + borrow\n\n // Handle borrowing\n if (digitA < digitB) {\n borrow = 1\n digitA += base\n } else {\n borrow = 0\n }\n\n const difference = digitA - digitB\n const codeChar = charSet.byCode[difference]\n if (codeChar === undefined) {\n return Effect.fail(new Error(\"invalid character code in subtractCharSetKeys\"))\n }\n result.unshift(codeChar)\n }\n\n // If there's a borrow left, we have a negative result, which is not supported\n if (borrow > 0) {\n return Effect.fail(\n new Error(\"Subtraction result is negative. Ensure a is greater than or equal to b.\")\n )\n }\n\n // Remove leading zeros\n while (\n stripLeadingZeros &&\n result.length > 1 &&\n result[0] === charSet.first\n ) {\n result.shift()\n }\n\n return Effect.succeed(result.join(\"\"))\n}\n\nexport function incrementKey(key: string, charSet: IndexedCharacterSet): Effect.Effect<string, Error> {\n const one = charSet.byCode[1]\n if (one === undefined) {\n return Effect.fail(new Error(\"invalid charSet: missing code 1\"))\n }\n return addCharSetKeys(key, one, charSet)\n}\n\nexport function decrementKey(key: string, charSet: IndexedCharacterSet): Effect.Effect<string, Error> {\n // we should not strip leading zeros here, this will break the sorting if the key already has leading zeros\n const one = charSet.byCode[1]\n if (one === undefined) {\n return Effect.fail(new Error(\"invalid charSet: missing code 1\"))\n }\n return subtractCharSetKeys(key, one, charSet, false)\n}\n\nexport function lexicalDistance(\n a: string,\n b: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<number, Error> {\n const [lower, upper] = makeSameLength(a, b, \"end\", charSet.first).sort()\n return Effect.gen(function* () {\n const distance = yield* subtractCharSetKeys(upper, lower, charSet)\n return decodeCharSetToNumber(distance, charSet)\n })\n}\n\nexport function midPoint(\n lower: string,\n upper: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n let [paddedLower, paddedUpper] = makeSameLength(\n lower,\n upper,\n \"end\",\n charSet.first\n )\n let distance = yield* lexicalDistance(paddedLower, paddedUpper, charSet)\n if (distance === 1) {\n // if the numbers are consecutive we need more padding\n paddedLower = paddedLower.padEnd(paddedLower.length + 1, charSet.first)\n // the new distance will always be the length of the charSet\n distance = charSet.length\n }\n const mid = yield* encodeToCharSet(Math.floor(distance / 2), charSet)\n return yield* addCharSetKeys(paddedLower, mid, charSet)\n })\n}\n\n// ============================================================================\n// Integer Functions\n// ============================================================================\n\nexport function startKey(charSet: IndexedCharacterSet): string {\n return charSet.firstPositive + charSet.byCode[0]\n}\n\nexport function validInteger(integer: string, charSet: IndexedCharacterSet): Effect.Effect<boolean, Error> {\n return Effect.gen(function* () {\n const length = yield* integerLength(integer, charSet)\n return length === integer.length\n })\n}\n\nexport function validateOrderKey(\n orderKey: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<void, Error> {\n return Effect.gen(function* () {\n yield* getIntegerPart(orderKey, charSet)\n })\n}\n\nexport function getIntegerPart(\n orderKey: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n const head = integerHead(orderKey, charSet)\n const integerPartLength = yield* integerLength(head, charSet)\n if (integerPartLength > orderKey.length) {\n return yield* Effect.fail(new Error(\"invalid order key length: \" + orderKey))\n }\n return orderKey.slice(0, integerPartLength)\n })\n}\n\nfunction validateInteger(integer: string, charSet: IndexedCharacterSet): Effect.Effect<void, Error> {\n return Effect.gen(function* () {\n const isValid = yield* validInteger(integer, charSet)\n if (!isValid) {\n return yield* Effect.fail(new Error(\"invalid integer length: \" + integer))\n }\n })\n}\n\nexport function integerHead(integer: string, charSet: IntegerLimits): string {\n let i = 0\n if (integer[0] === charSet.mostPositive) {\n while (integer[i] === charSet.mostPositive) {\n i = i + 1\n }\n }\n if (integer[0] === charSet.mostNegative) {\n while (integer[i] === charSet.mostNegative) {\n i = i + 1\n }\n }\n return integer.slice(0, i + 1)\n}\n\nexport function splitInteger(\n integer: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<[string, string], Error> {\n return Effect.gen(function* () {\n // We need to get the limits from the charSet\n const head = integerHead(integer, {\n firstPositive: charSet.firstPositive,\n mostPositive: charSet.mostPositive,\n firstNegative: charSet.firstNegative,\n mostNegative: charSet.mostNegative,\n })\n const tail = integer.slice(head.length)\n return [head, tail] as [string, string]\n })\n}\n\nexport function incrementIntegerHead(\n head: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n const inPositiveRange = head >= charSet.firstPositive\n const nextHead = yield* incrementKey(head, charSet)\n const headIsLimitMax = head[head.length - 1] === charSet.mostPositive\n const nextHeadIsLimitMax =\n nextHead[nextHead.length - 1] === charSet.mostPositive\n\n // we can not leave the head on the limit value, we have no way to know where the head ends\n if (inPositiveRange && nextHeadIsLimitMax) {\n return nextHead + charSet.mostNegative\n }\n // we are already at the limit of this level, so we need to go up a level\n if (!inPositiveRange && headIsLimitMax) {\n return head.slice(0, head.length - 1)\n }\n return nextHead\n })\n}\n\nexport function decrementIntegerHead(\n head: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n const inPositiveRange = head >= charSet.firstPositive\n const headIsLimitMin = head[head.length - 1] === charSet.mostNegative\n if (inPositiveRange && headIsLimitMin) {\n const nextLevel = head.slice(0, head.length - 1)\n // we can not leave the head on the limit value, we have no way to know where the head ends\n // so we take one extra step down\n const decremented = yield* decrementKey(nextLevel, charSet)\n return decremented\n }\n\n if (!inPositiveRange && headIsLimitMin) {\n return head + charSet.mostPositive\n }\n\n return yield* decrementKey(head, charSet)\n })\n}\n\nfunction startOnNewHead(\n head: string,\n limit: \"upper\" | \"lower\",\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n const newLength = yield* integerLength(head, charSet)\n const fillCharCode = limit === \"upper\" ? charSet.length - 1 : 0\n const fillChar = charSet.byCode[fillCharCode]\n if (fillChar === undefined) {\n return yield* Effect.fail(new Error(\"invalid fill character code\"))\n }\n return head + fillChar.repeat(newLength - head.length)\n })\n}\n\nexport function incrementInteger(\n integer: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n yield* validateInteger(integer, charSet)\n const [head, digs] = yield* splitInteger(integer, charSet)\n const maxChar = charSet.byCode[charSet.length - 1]\n if (maxChar === undefined) {\n return yield* Effect.fail(new Error(\"invalid charSet: missing max character\"))\n }\n const anyNonMaxedDigit = digs\n .split(\"\")\n .some((d) => d !== maxChar)\n\n // we have room to increment\n if (anyNonMaxedDigit) {\n const newDigits = yield* incrementKey(digs, charSet)\n return head + newDigits\n }\n const nextHead = yield* incrementIntegerHead(head, charSet)\n return yield* startOnNewHead(nextHead, \"lower\", charSet)\n })\n}\n\nexport function decrementInteger(\n integer: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n yield* validateInteger(integer, charSet)\n const [head, digs] = yield* splitInteger(integer, charSet)\n const minChar = charSet.byCode[0]\n if (minChar === undefined) {\n return yield* Effect.fail(new Error(\"invalid charSet: missing min character\"))\n }\n const anyNonLimitDigit = digs.split(\"\").some((d) => d !== minChar)\n\n // we have room to decrement\n if (anyNonLimitDigit) {\n const newDigits = yield* decrementKey(digs, charSet)\n return head + newDigits\n }\n const nextHead = yield* decrementIntegerHead(head, charSet)\n return yield* startOnNewHead(nextHead, \"upper\", charSet)\n })\n}\n\n// ============================================================================\n// Jittering Functions\n// ============================================================================\n\nexport function jitterString(\n orderKey: string,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error, Random.Random> {\n return Effect.gen(function* () {\n const randomValue = yield* Random.next\n const shift = yield* encodeToCharSet(\n Math.floor(randomValue * charSet.jitterRange),\n charSet\n )\n return yield* addCharSetKeys(orderKey, shift, charSet)\n })\n}\n\nexport function padAndJitterString(\n orderKey: string,\n numberOfChars: number,\n charSet: IndexedCharacterSet\n): Effect.Effect<string, Error, Random.Random> {\n return Effect.gen(function* () {\n const paddedKey = orderKey.padEnd(\n orderKey.length + numberOfChars,\n charSet.first\n )\n return yield* jitterString(paddedKey, charSet)\n })\n}\n\nexport function paddingNeededForDistance(\n distance: number,\n charSet: IndexedCharacterSet\n): number {\n const gap = charSet.jitterRange - distance\n const firstBigger = Object.entries(charSet.paddingDict).find(\n ([_key, value]) => {\n return value > gap\n }\n )\n\n return firstBigger ? parseInt(firstBigger[0]) : 0\n}\n\nexport function paddingNeededForJitter(\n orderKey: string,\n b: string | null,\n charSet: IndexedCharacterSet\n): Effect.Effect<number, Error> {\n return Effect.gen(function* () {\n const integer = yield* getIntegerPart(orderKey, charSet)\n const nextInteger = yield* incrementInteger(integer, charSet)\n let needed = 0\n if (b !== null) {\n const distanceToB = yield* lexicalDistance(orderKey, b, charSet)\n if (distanceToB < charSet.jitterRange + 1) {\n needed = Math.max(needed, paddingNeededForDistance(distanceToB, charSet))\n }\n }\n const distanceToNextInteger = yield* lexicalDistance(orderKey, nextInteger, charSet)\n if (distanceToNextInteger < charSet.jitterRange + 1) {\n needed = Math.max(\n needed,\n paddingNeededForDistance(distanceToNextInteger, charSet)\n )\n }\n\n return needed\n })\n}\n\n// ============================================================================\n// Key Generation Functions\n// ============================================================================\n\n/**\n * Generate a key between two other keys.\n * If either lower or upper is null, the key will be generated at the start or end of the list.\n */\nexport function generateKeyBetween(\n lower: string | null,\n upper: string | null,\n charSet: IndexedCharacterSet = base62CharSet()\n): Effect.Effect<string, Error> {\n return Effect.gen(function* () {\n if (lower !== null) {\n yield* validateOrderKey(lower, charSet)\n }\n if (upper !== null) {\n yield* validateOrderKey(upper, charSet)\n }\n if (lower === null && upper === null) {\n return startKey(charSet)\n }\n if (lower === null) {\n const integer = yield* getIntegerPart(upper!, charSet)\n return yield* decrementInteger(integer, charSet)\n }\n if (upper === null) {\n const integer = yield* getIntegerPart(lower, charSet)\n return yield* incrementInteger(integer, charSet)\n }\n if (lower >= upper) {\n return yield* Effect.fail(new Error(lower + \" >= \" + upper))\n }\n return yield* midPoint(lower, upper, charSet)\n })\n}\n\ntype GenerateKeyBetweenFunc = (\n lower: string | null,\n upper: string | null,\n charSet?: IndexedCharacterSet\n) => Effect.Effect<string, Error>\n\ntype GenerateNKeysBetweenFunc = (\n lower: string | null,\n upper: string | null,\n n: number,\n charSet?: IndexedCharacterSet\n) => Effect.Effect<string[], Error>\n\nfunction spreadGeneratorResults(\n lower: string | null,\n upper: string | null,\n n: number,\n charSet: IndexedCharacterSet,\n generateKey: GenerateKeyBetweenFunc,\n generateNKeys: GenerateNKeysBetweenFunc\n): Effect.Effect<string[], Error> {\n if (n === 0) {\n return Effect.succeed([])\n }\n if (n === 1) {\n return generateKey(lower, upper, charSet).pipe(Effect.map((key) => [key]))\n }\n if (upper == null) {\n return Effect.gen(function* () {\n let newUpper = yield* generateKey(lower, upper, charSet)\n const result = [newUpper]\n for (let i = 0; i < n - 1; i++) {\n newUpper = yield* generateKey(newUpper, upper, charSet)\n result.push(newUpper)\n }\n return result\n })\n }\n if (lower == null) {\n return Effect.gen(function* () {\n let newLower = yield* generateKey(lower, upper, charSet)\n const result = [newLower]\n for (let i = 0; i < n - 1; i++) {\n newLower = yield* generateKey(lower, newLower, charSet)\n result.push(newLower)\n }\n result.reverse()\n return result\n })\n }\n return Effect.gen(function* () {\n const mid = Math.floor(n / 2)\n const midOrderKey = yield* generateKey(lower, upper, charSet)\n const leftKeys = yield* generateNKeys(lower, midOrderKey, mid, charSet)\n const rightKeys = yield* generateNKeys(midOrderKey, upper, n - mid - 1, charSet)\n return [...leftKeys, midOrderKey, ...rightKeys]\n })\n}\n\n/**\n * Generate any number of keys between two other keys.\n * If either lower or upper is null, the keys will be generated at the start or end of the list.\n */\nexport function generateNKeysBetween(\n a: string | null,\n b: string | null,\n n: number,\n charSet: IndexedCharacterSet = base62CharSet()\n): Effect.Effect<string[], Error> {\n return spreadGeneratorResults(\n a,\n b,\n n,\n charSet,\n (lower, upper, charSet = base62CharSet()) => generateKeyBetween(lower, upper, charSet),\n (lower, upper, n, charSet = base62CharSet()) => generateNKeysBetween(lower, upper, n, charSet)\n )\n}\n\n/**\n * Generate a key between two other keys with jitter.\n * If either lower or upper is null, the key will be generated at the start or end of the list.\n */\nexport function generateJitteredKeyBetween(\n lower: string | null,\n upper: string | null,\n charSet: IndexedCharacterSet = base62CharSet()\n): Effect.Effect<string, Error, Random.Random> {\n return Effect.gen(function* () {\n const key = yield* generateKeyBetween(lower, upper, charSet)\n const paddingNeeded = yield* paddingNeededForJitter(key, upper, charSet)\n if (paddingNeeded) {\n return yield* padAndJitterString(key, paddingNeeded, charSet)\n }\n return yield* jitterString(key, charSet)\n })\n}\n\n/**\n * Generate any number of keys between two other keys with jitter.\n * If either lower or upper is null, the keys will be generated at the start or end of the list.\n */\nexport function generateNJitteredKeysBetween(\n lower: string | null,\n upper: string | null,\n n: number,\n charSet: IndexedCharacterSet = base62CharSet()\n): Effect.Effect<string[], Error, Random.Random> {\n return Effect.gen(function* () {\n if (n === 0) {\n return []\n }\n if (n === 1) {\n const key = yield* generateJitteredKeyBetween(lower, upper, charSet)\n return [key]\n }\n if (upper == null) {\n let newUpper = yield* generateJitteredKeyBetween(lower, upper, charSet)\n const result = [newUpper]\n for (let i = 0; i < n - 1; i++) {\n newUpper = yield* generateJitteredKeyBetween(newUpper, upper, charSet)\n result.push(newUpper)\n }\n return result\n }\n if (lower == null) {\n let newLower = yield* generateJitteredKeyBetween(lower, upper, charSet)\n const result = [newLower]\n for (let i = 0; i < n - 1; i++) {\n newLower = yield* generateJitteredKeyBetween(lower, newLower, charSet)\n result.push(newLower)\n }\n result.reverse()\n return result\n }\n const mid = Math.floor(n / 2)\n const midOrderKey = yield* generateJitteredKeyBetween(lower, upper, charSet)\n const leftKeys = yield* generateNJitteredKeysBetween(lower, midOrderKey, mid, charSet)\n const rightKeys = yield* generateNJitteredKeysBetween(midOrderKey, upper, n - mid - 1, charSet)\n return [...leftKeys, midOrderKey, ...rightKeys]\n })\n}\n\n// ============================================================================\n// Index Generator Class\n// ============================================================================\n\nexport class IndexGenerator {\n private charSet: IndexedCharacterSet\n private useJitter: boolean\n private list: string[]\n private useGroups: boolean\n private groupIdLength: number\n\n constructor(list: string[], options: GeneratorOptions = {}) {\n this.charSet = options.charSet ?? base62CharSet()\n this.useJitter = options.useJitter ?? true\n this.list = list\n this.useGroups = !!options.groupIdLength && options.groupIdLength > 0\n this.groupIdLength = options.groupIdLength ?? 0\n }\n\n /**\n * Updates the list that the generator uses to generate keys.\n * The generator will not mutate the internal list when generating keys.\n */\n public updateList(list: string[]) {\n this.list = [...list].sort()\n }\n\n /**\n * Generate any number of keys at the start of the list (before the first key).\n * Optionally you can supply a groupId to generate keys at the start of a specific group.\n */\n public nKeysStart(n: number, groupId?: string): Effect.Effect<string[], Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n yield* Effect.try(() => {\n self.validateGroupId(groupId)\n })\n const firstKey = self.firstOfGroup(groupId)\n return yield* self.generateNKeysBetween(null, firstKey, n, groupId)\n })\n }\n\n /**\n * Generate a single key at the start of the list (before the first key).\n * Optionally you can supply a groupId to generate a key at the start of a specific group.\n */\n public keyStart(groupId?: string): Effect.Effect<string, Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n const keys = yield* self.nKeysStart(1, groupId)\n return keys[0]!\n })\n }\n\n /**\n * Generate any number of keys at the end of the list (after the last key).\n * Optionally you can supply a groupId to generate keys at the end of a specific group.\n */\n public nKeysEnd(n: number, groupId?: string): Effect.Effect<string[], Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n yield* Effect.try(() => {\n self.validateGroupId(groupId)\n })\n const lastKey = self.lastOfGroup(groupId)\n return yield* self.generateNKeysBetween(lastKey, null, n, groupId)\n })\n }\n\n /**\n * Generate a single key at the end of the list (after the last key).\n * Optionally you can supply a groupId to generate a key at the end of a specific group.\n */\n public keyEnd(groupId?: string): Effect.Effect<string, Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n const keys = yield* self.nKeysEnd(1, groupId)\n return keys[0]!\n })\n }\n\n /**\n * Generate any number of keys behind a specific key and in front of the next key.\n * GroupId will be inferred from the orderKey if working with groups\n */\n public nKeysAfter(orderKey: string, n: number): Effect.Effect<string[], Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n const keyAfter = yield* self.getKeyAfter(orderKey)\n return yield* self.generateNKeysBetween(orderKey, keyAfter, n, self.groupId(orderKey))\n })\n }\n\n /**\n * Generate a single key behind a specific key and in front of the next key.\n * GroupId will be inferred from the orderKey if working with groups\n */\n public keyAfter(orderKey: string): Effect.Effect<string, Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n const keys = yield* self.nKeysAfter(orderKey, 1)\n return keys[0]!\n })\n }\n\n /**\n * Generate any number of keys in front of a specific key and behind the previous key.\n * GroupId will be inferred from the orderKey if working with groups\n */\n public nKeysBefore(orderKey: string, n: number): Effect.Effect<string[], Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n const keyBefore = yield* self.getKeyBefore(orderKey)\n return yield* self.generateNKeysBetween(keyBefore, orderKey, n, self.groupId(orderKey))\n })\n }\n\n /**\n * Generate a single key in front of a specific key and behind the previous key.\n * GroupId will be inferred from the orderKey if working with groups\n */\n public keyBefore(orderKey: string): Effect.Effect<string, Error, Random.Random> {\n const self = this\n return Effect.gen(function* () {\n const keys = yield* self.nKeysBefore(orderKey, 1)\n return keys[0]!\n })\n }\n\n /**\n * private function responsible for calling the correct generate function\n */\n private generateNKeysBetween(\n lowerKey: string | null,\n upperKey: string | null,\n n: number,\n groupId: string | undefined\n ): Effect.Effect<string[], Error, Random.Random> {\n const self = this\n const lower = self.groupLessKey(lowerKey)\n const upper = self.groupLessKey(upperKey)\n if (self.useJitter) {\n return Effect.gen(function* () {\n const keys = yield* generateNJitteredKeysBetween(lower, upper, n, self.charSet)\n return !groupId ? keys : keys.map((key) => groupId + key)\n })\n } else {\n // When not using jitter, we don't need Random, but TypeScript requires it\n // So we provide a default Random service that won't be used\n return Effect.gen(function* () {\n const keys = yield* generateNKeysBetween(lower, upper, n, self.charSet)\n return !groupId ? keys : keys.map((key) => groupId + key)\n }).pipe(Effect.provideService(Random as any, Random.make(Math.random())))\n }\n }\n\n /**\n * get the key before the supplied orderKey, if it exists and is in the same group\n */\n private getKeyBefore(orderKey: string): Effect.Effect<string | null, Error> {\n const index = this.list.indexOf(orderKey)\n if (index === -1) {\n return Effect.fail(new Error(`orderKey is not in the list`))\n }\n const before = this.list[index - 1]\n return Effect.succeed(!!before && this.isSameGroup(orderKey, before) ? before : null)\n }\n\n /**\n * get the key after the supplied orderKey, if it exists and is in the same group\n */\n private getKeyAfter(orderKey: string): Effect.Effect<string | null, Error> {\n const index = this.list.indexOf(orderKey)\n if (index === -1) {\n return Effect.fail(new Error(`orderKey is not in the list`))\n }\n const after = this.list[index + 1]\n return Effect.succeed(!!after && this.isSameGroup(orderKey, after) ? after : null)\n }\n\n /**\n * get the first key of the group (or the first key of the list if not using groups)\n */\n private firstOfGroup(groupId: string | undefined): string | null {\n if (!this.useGroups) return this.list[0] ?? null\n const first = this.list.find((key) => this.isPartOfGroup(key, groupId))\n return first ?? null\n }\n\n /**\n * get the last key of the group (or the last key of the list if not using groups)\n */\n private lastOfGroup(groupId: string | undefined): string | null {\n if (!this.useGroups) return this.list[this.list.length - 1] ?? null\n const allGroupItems = this.list.filter((key) =>\n this.isPartOfGroup(key, groupId)\n )\n const last = allGroupItems[allGroupItems.length - 1]\n return last ?? null\n }\n\n /**\n * throw an error if the groupId is invalid or supplied when not using groups\n */\n private validateGroupId(groupId: string | undefined): void {\n if (!this.useGroups) {\n if (groupId) {\n console.warn(\"groupId should not used when not using groups\")\n }\n return\n }\n if (!groupId) {\n throw new Error(\"groupId is required when using groups\")\n }\n if (groupId.length !== this.groupIdLength) {\n throw new Error(`groupId must be the lenght supplied in the options`)\n }\n }\n\n /**\n * get the groupId from the orderKey\n */\n private groupId(orderKey: string): string | undefined {\n if (!this.useGroups) return undefined\n return this.splitIntoGroupIdAndOrderKey(orderKey)[0]\n }\n\n /**\n * remove the groupId from the orderKey\n */\n private groupLessKey(orderKey: string | null): string | null {\n if (!this.useGroups) return orderKey\n return this.splitIntoGroupIdAndOrderKey(orderKey)[1]\n }\n\n /**\n * split the orderKey into groupId and key\n * if not using groups, orderKey will be the same as key\n */\n private splitIntoGroupIdAndOrderKey(\n orderKey: string | null\n ): [string | undefined, string | null] {\n if (!this.useGroups || !orderKey) {\n return [undefined, orderKey]\n }\n const groupId = orderKey.substring(0, this.groupIdLength)\n const key = orderKey.substring(this.groupIdLength)\n return [groupId, key]\n }\n\n /**\n * check if two keys are in the same group\n * if not using groups, keys will always be in the same group\n */\n private isSameGroup(a: string, b: string): boolean {\n if (!this.useGroups) return true\n const [aGroupId] = this.splitIntoGroupIdAndOrderKey(a)\n const [bGroupId] = this.splitIntoGroupIdAndOrderKey(b)\n return aGroupId === bGroupId\n }\n\n /**\n * check if the key is part of the group\n * if not using groups, key will always be part of the group\n */\n private isPartOfGroup(orderKey: string, groupId?: string): boolean {\n if (!this.useGroups) return true\n const [keyGroupId] = this.splitIntoGroupIdAndOrderKey(orderKey)\n return keyGroupId === groupId\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_OperationPath = require('./OperationPath.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/Operation.ts
|
|
5
|
+
var Operation_exports = /* @__PURE__ */ require_rolldown_runtime.__export({
|
|
6
|
+
decode: () => decode,
|
|
7
|
+
encode: () => encode,
|
|
8
|
+
fromDefinition: () => fromDefinition
|
|
9
|
+
});
|
|
10
|
+
const fromDefinition = (operationPath, definition, payload) => {
|
|
11
|
+
return {
|
|
12
|
+
kind: definition.kind,
|
|
13
|
+
path: operationPath,
|
|
14
|
+
payload
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Encodes an Operation to a JSON-serializable format for network transport.
|
|
19
|
+
* @param operation - The operation to encode.
|
|
20
|
+
* @returns The encoded representation.
|
|
21
|
+
*/
|
|
22
|
+
const encode = (operation) => {
|
|
23
|
+
return {
|
|
24
|
+
kind: operation.kind,
|
|
25
|
+
path: require_OperationPath.encode(operation.path),
|
|
26
|
+
payload: operation.payload
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Decodes an encoded operation back to an Operation.
|
|
31
|
+
* Note: This returns a partial operation without the definition methods.
|
|
32
|
+
* The caller must have the operation definitions to fully reconstruct if needed.
|
|
33
|
+
* @param encoded - The encoded representation.
|
|
34
|
+
* @returns The decoded Operation (without definition-specific methods).
|
|
35
|
+
*/
|
|
36
|
+
const decode = (encoded) => {
|
|
37
|
+
return {
|
|
38
|
+
kind: encoded.kind,
|
|
39
|
+
path: require_OperationPath.decode(encoded.path),
|
|
40
|
+
payload: encoded.payload
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
Object.defineProperty(exports, 'Operation_exports', {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function () {
|
|
48
|
+
return Operation_exports;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
exports.decode = decode;
|
|
52
|
+
exports.encode = encode;
|
|
53
|
+
exports.fromDefinition = fromDefinition;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EncodedOperationPath, OperationPath } from "./OperationPath.cjs";
|
|
2
|
+
import { OperationDefinition } from "./OperationDefinition.cjs";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/Operation.d.ts
|
|
6
|
+
declare namespace Operation_d_exports {
|
|
7
|
+
export { EncodedOperation, Operation, decode, encode, fromDefinition };
|
|
8
|
+
}
|
|
9
|
+
type Operation<TKind, TPayload extends Schema.Schema.Any, TDef extends OperationDefinition<TKind, TPayload, any>> = {
|
|
10
|
+
readonly kind: TKind;
|
|
11
|
+
readonly path: OperationPath;
|
|
12
|
+
readonly payload: Schema.Schema.Type<TPayload>;
|
|
13
|
+
} & TDef;
|
|
14
|
+
declare const fromDefinition: <TKind, TPayload extends Schema.Schema.Any, TDef extends OperationDefinition<TKind, TPayload, any>>(operationPath: OperationPath, definition: TDef, payload: Schema.Schema.Type<TPayload>) => Operation<TKind, TPayload, TDef>;
|
|
15
|
+
/**
|
|
16
|
+
* Encoded representation of an Operation for network transport.
|
|
17
|
+
*/
|
|
18
|
+
interface EncodedOperation {
|
|
19
|
+
readonly kind: unknown;
|
|
20
|
+
readonly path: EncodedOperationPath;
|
|
21
|
+
readonly payload: unknown;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Encodes an Operation to a JSON-serializable format for network transport.
|
|
25
|
+
* @param operation - The operation to encode.
|
|
26
|
+
* @returns The encoded representation.
|
|
27
|
+
*/
|
|
28
|
+
declare const encode: <TKind, TPayload extends Schema.Schema.Any, TDef extends OperationDefinition<TKind, TPayload, any>>(operation: Operation<TKind, TPayload, TDef>) => EncodedOperation;
|
|
29
|
+
/**
|
|
30
|
+
* Decodes an encoded operation back to an Operation.
|
|
31
|
+
* Note: This returns a partial operation without the definition methods.
|
|
32
|
+
* The caller must have the operation definitions to fully reconstruct if needed.
|
|
33
|
+
* @param encoded - The encoded representation.
|
|
34
|
+
* @returns The decoded Operation (without definition-specific methods).
|
|
35
|
+
*/
|
|
36
|
+
declare const decode: (encoded: EncodedOperation) => Operation<unknown, Schema.Schema.Any, any>;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { EncodedOperation, Operation, Operation_d_exports };
|
|
39
|
+
//# sourceMappingURL=Operation.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Operation.d.cts","names":[],"sources":["../src/Operation.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAMY,kCAAkC,MAAA,CAAO,MAAA,CAAO,kBAAkB,oBAAwC,OAAO;iBAC1G;iBACA;oBACG,MAAA,CAAO,MAAA,CAAO,KAAK;IAErC;cAES,yCAA0C,MAAA,CAAO,MAAA,CAAO,kBAAkB,oBAAwC,OAAO,+BAA+B,2BAAyC,eAAe,MAAA,CAAO,MAAA,CAAO,KAAK,cAAY,UAAU,OAAO,UAAU;;;;UAWtQ,gBAAA;EAlBL,SAAA,IAAS,EAAA,OAAA;EAAyB,SAAO,IAAO,EAoBzC,oBApByC;EAA0D,SAAA,OAAA,EAAA,OAAA;;;;;;;AAKlH,cAwBS,MAxBT,EAAA,CAAA,KAAA,EAAA,iBAwB2C,MAAA,CAAO,MAAA,CAAO,GAxBzD,EAAA,aAwB2E,mBAxB3E,CAwBmH,KAxBnH,EAwB0H,QAxB1H,EAAA,GAAA,CAAA,CAAA,CAAA,SAAA,EAyBW,SAzBX,CAyBqB,KAzBrB,EAyB4B,QAzB5B,EAyBsC,IAzBtC,CAAA,EAAA,GA0BD,gBA1BC;;AAEJ;;;;;;AAA8M,cAuCjM,MAvCiM,EAAA,CAAA,OAAA,EAuC9K,gBAvC8K,EAAA,GAuC3J,SAvC2J,CAAA,OAAA,EAuCxI,MAAA,CAAO,MAAA,CAAO,GAvC0H,EAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EncodedOperationPath, OperationPath } from "./OperationPath.mjs";
|
|
2
|
+
import { OperationDefinition } from "./OperationDefinition.mjs";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/Operation.d.ts
|
|
6
|
+
declare namespace Operation_d_exports {
|
|
7
|
+
export { EncodedOperation, Operation, decode, encode, fromDefinition };
|
|
8
|
+
}
|
|
9
|
+
type Operation<TKind, TPayload extends Schema.Schema.Any, TDef extends OperationDefinition<TKind, TPayload, any>> = {
|
|
10
|
+
readonly kind: TKind;
|
|
11
|
+
readonly path: OperationPath;
|
|
12
|
+
readonly payload: Schema.Schema.Type<TPayload>;
|
|
13
|
+
} & TDef;
|
|
14
|
+
declare const fromDefinition: <TKind, TPayload extends Schema.Schema.Any, TDef extends OperationDefinition<TKind, TPayload, any>>(operationPath: OperationPath, definition: TDef, payload: Schema.Schema.Type<TPayload>) => Operation<TKind, TPayload, TDef>;
|
|
15
|
+
/**
|
|
16
|
+
* Encoded representation of an Operation for network transport.
|
|
17
|
+
*/
|
|
18
|
+
interface EncodedOperation {
|
|
19
|
+
readonly kind: unknown;
|
|
20
|
+
readonly path: EncodedOperationPath;
|
|
21
|
+
readonly payload: unknown;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Encodes an Operation to a JSON-serializable format for network transport.
|
|
25
|
+
* @param operation - The operation to encode.
|
|
26
|
+
* @returns The encoded representation.
|
|
27
|
+
*/
|
|
28
|
+
declare const encode: <TKind, TPayload extends Schema.Schema.Any, TDef extends OperationDefinition<TKind, TPayload, any>>(operation: Operation<TKind, TPayload, TDef>) => EncodedOperation;
|
|
29
|
+
/**
|
|
30
|
+
* Decodes an encoded operation back to an Operation.
|
|
31
|
+
* Note: This returns a partial operation without the definition methods.
|
|
32
|
+
* The caller must have the operation definitions to fully reconstruct if needed.
|
|
33
|
+
* @param encoded - The encoded representation.
|
|
34
|
+
* @returns The decoded Operation (without definition-specific methods).
|
|
35
|
+
*/
|
|
36
|
+
declare const decode: (encoded: EncodedOperation) => Operation<unknown, Schema.Schema.Any, any>;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { EncodedOperation, Operation, Operation_d_exports };
|
|
39
|
+
//# sourceMappingURL=Operation.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Operation.d.mts","names":[],"sources":["../src/Operation.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAMY,kCAAkC,MAAA,CAAO,MAAA,CAAO,kBAAkB,oBAAwC,OAAO;iBAC1G;iBACA;oBACG,MAAA,CAAO,MAAA,CAAO,KAAK;IAErC;cAES,yCAA0C,MAAA,CAAO,MAAA,CAAO,kBAAkB,oBAAwC,OAAO,+BAA+B,2BAAyC,eAAe,MAAA,CAAO,MAAA,CAAO,KAAK,cAAY,UAAU,OAAO,UAAU;;;;UAWtQ,gBAAA;EAlBL,SAAA,IAAS,EAAA,OAAA;EAAyB,SAAO,IAAO,EAoBzC,oBApByC;EAA0D,SAAA,OAAA,EAAA,OAAA;;;;;;;AAKlH,cAwBS,MAxBT,EAAA,CAAA,KAAA,EAAA,iBAwB2C,MAAA,CAAO,MAAA,CAAO,GAxBzD,EAAA,aAwB2E,mBAxB3E,CAwBmH,KAxBnH,EAwB0H,QAxB1H,EAAA,GAAA,CAAA,CAAA,CAAA,SAAA,EAyBW,SAzBX,CAyBqB,KAzBrB,EAyB4B,QAzB5B,EAyBsC,IAzBtC,CAAA,EAAA,GA0BD,gBA1BC;;AAEJ;;;;;;AAA8M,cAuCjM,MAvCiM,EAAA,CAAA,OAAA,EAuC9K,gBAvC8K,EAAA,GAuC3J,SAvC2J,CAAA,OAAA,EAuCxI,MAAA,CAAO,MAAA,CAAO,GAvC0H,EAAA,GAAA,CAAA"}
|