fraci
Version:
Fractional indexing that's robust, performant, and secure, with first-class support for Drizzle ORM and Prisma ORM.
728 lines (719 loc) • 15.8 kB
JavaScript
;
var P = Object.defineProperty;
var En = Object.getOwnPropertyDescriptor;
var mn = Object.getOwnPropertyNames;
var hn = Object.prototype.hasOwnProperty;
var An = (n, e) => {
for (var r in e)
P(n, r, { get: e[r], enumerable: !0 });
}, In = (n, e, r, t) => {
if (e && typeof e == "object" || typeof e == "function")
for (let o of mn(e))
!hn.call(n, o) && o !== r && P(n, o, { get: () => e[o], enumerable: !(t = En(e, o)) || t.enumerable });
return n;
};
var xn = (n) => In(P({}, "__esModule", { value: !0 }), n);
// src/index.ts
var Kn = {};
An(Kn, {
BASE10: () => Fn,
BASE16L: () => Bn,
BASE16U: () => _n,
BASE26L: () => bn,
BASE26U: () => wn,
BASE36L: () => Mn,
BASE36U: () => Un,
BASE52: () => Tn,
BASE62: () => Rn,
BASE64URL: () => Sn,
BASE88: () => Nn,
BASE95: () => Ln,
DEFAULT_MAX_LENGTH: () => z,
DEFAULT_MAX_RETRIES: () => J,
FraciError: () => c,
createFraciCache: () => Cn,
fraci: () => $n,
fraciBinary: () => gn,
fraciString: () => dn,
getFraciErrorCode: () => On,
isFraciError: () => Dn
});
module.exports = xn(Kn);
// src/bases.ts
var Fn = "0123456789", Bn = "0123456789abcdef", _n = "0123456789ABCDEF", bn = "abcdefghijklmnopqrstuvwxyz", wn = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", Mn = "0123456789abcdefghijklmnopqrstuvwxyz", Un = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", Tn = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", Rn = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", Sn = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz", Nn = "!#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~", Ln = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
// src/lib/errors.ts
var c = class extends Error {
constructor(r, t) {
super(`[${r}] ${t}`);
this.code = r;
this.message = t;
this.name = "FraciError";
}
name;
};
function Dn(n) {
return n instanceof c;
}
function On(n) {
return n instanceof c ? n.code : void 0;
}
// src/lib/decimal-binary.ts
var G = new Uint8Array([128, 0]), Xn = new Uint8Array([127, 255]);
function _(n, e) {
let r = Math.min(n.length, e.length), t = 0;
for (let o = 0; !t && o < r; o++)
t = n[o] - e[o];
return t || n.length - e.length;
}
function I(n, e) {
let r = new Uint8Array(n.length + e.length);
return r.set(n), r.set(e, n.length), r;
}
function V(n) {
let [e] = n;
return e - (e >= 128 ? 127 : 128);
}
function Q(n) {
return n + (n < 0 ? 128 : 127);
}
function R(n) {
return n.length === 129 && n.every((e) => e === 0);
}
function b(n) {
let e = Math.abs(V(n)) + 1;
if (!(Number.isNaN(e) || n.length < e))
return [n.subarray(0, e), n.subarray(e)];
}
function k(n) {
if (!n.length)
return;
let e = V(n), r = n.slice(0, Math.abs(e) + 1);
for (let i = r.length - 1; i >= 1; i--)
if (r[i]++ < 255)
return r;
if (e === -1)
return G.slice();
let t = e + 1;
if (t > 128)
return null;
let o = new Uint8Array(Math.abs(t) + 1);
return o[0] = Q(t), o;
}
function Y(n) {
let e = V(n);
if (Number.isNaN(e))
return;
let r = n.slice(0, Math.abs(e) + 1);
for (let i = r.length - 1; i >= 1; i--)
if (r[i]--)
return r;
if (e === 1)
return Xn.slice();
let t = e - 1;
if (t < -128)
return null;
let o = new Uint8Array(Math.abs(t) + 1).fill(255);
return o[0] = Q(t), o;
}
function F(n, e) {
if (e != null && _(n, e) >= 0)
return;
if (e) {
let a = e.findIndex((l, s) => l !== (n[s] ?? 0));
if (a > 0) {
let l = F(
n.subarray(a),
e.subarray(a)
);
return l ? I(e.subarray(0, a), l) : void 0;
}
}
let r = n[0] ?? 0, t = e ? e[0] : 256;
if (t == null)
return;
if (r + 1 !== t) {
let a = r + t >> 1;
return new Uint8Array([a]);
}
if (e && e.length > 1)
return new Uint8Array([e[0]]);
let o = F(n.subarray(1), null);
if (!o)
return;
let i = new Uint8Array(1 + o.length);
return i[0] = r, i.set(o, 1), i;
}
// src/lib/decimal-string.ts
function Z(n, e) {
return e.get(n[0]);
}
function w(n, e) {
let r = Math.abs(Z(n, e) ?? 0) + 1;
if (!(r < 2 || n.length < r))
return [n.slice(0, r), n.slice(r)];
}
function nn(n, e) {
return e.get(1) + n[0];
}
function en(n, e) {
let r = Math.min(...Array.from(e.keys()));
return `${e.get(r)}${n[0].repeat(Math.abs(r))}`;
}
function j(n, e, r, t, o) {
let i = Z(n, o);
if (!i)
return;
let a = e[0], [l, ...s] = n.slice(0, Math.abs(i) + 1);
for (let y = s.length - 1; y >= 0; y--) {
let g = r.get(s[y]);
if (g == null)
return;
if (g < e.length - 1)
return s[y] = e[g + 1], `${l}${s.join("")}`;
s[y] = a;
}
if (i === -1)
return `${t.get(1)}${a}`;
let u = i + 1, f = t.get(u);
return f ? `${f}${a.repeat(Math.abs(u))}` : null;
}
function rn(n, e, r, t, o) {
let i = Z(n, o);
if (!i)
return;
let a = e[e.length - 1], [l, ...s] = n.slice(0, Math.abs(i) + 1);
for (let y = s.length - 1; y >= 0; y--) {
let g = r.get(s[y]);
if (g == null)
return;
if (g > 0)
return s[y] = e[g - 1], `${l}${s.join("")}`;
s[y] = a;
}
if (i === 1)
return `${t.get(-1)}${a}`;
let u = i - 1, f = t.get(u);
return f ? `${f}${a.repeat(Math.abs(u))}` : null;
}
function B(n, e, r, t) {
if (e != null && e <= n)
return;
if (e) {
let a = n.padEnd(e.length, r[0]), l = Array.prototype.findIndex.call(
e,
(s, u) => s !== a[u]
);
if (l > 0)
return `${e.slice(0, l)}${B(
n.slice(l),
e.slice(l),
r,
t
)}`;
}
let o = n ? t.get(n[0]) : 0, i = e ? t.get(e[0]) : r.length;
if (!(o == null || i == null)) {
if (o + 1 !== i) {
let a = o + i >> 1;
return r[a];
}
return e && e.length > 1 ? e[0] : `${r[o]}${B(
n.slice(1),
null,
r,
t
)}`;
}
}
// src/lib/fractional-indexing-binary.ts
function S(n) {
return n?.constructor.name === "Buffer" ? new Uint8Array(n.buffer, n.byteOffset, n.length) : n;
}
function N(n) {
if (!n.length || R(n))
return !1;
let e = b(n);
if (!e)
return !1;
let [, r] = e;
return r?.at(-1) !== 0;
}
function E(n) {
if (n === void 0)
throw console.error(
"FraciError: [INTERNAL_ERROR] Unexpected undefined. Please file an issue to report this error."
), new c("INTERNAL_ERROR", "Unexpected undefined");
return n;
}
function M(n, e) {
if (!n) {
if (!e)
return G.slice();
let [l, s] = E(b(e));
if (R(l))
return I(
l,
E(F(new Uint8Array(), s))
);
if (s.length)
return l.slice();
let u = E(
Y(l)
);
if (!R(u))
return u;
let f = new Uint8Array(u.length + 1);
return f.set(u), f[u.length] = 255, f;
}
if (!e) {
let l = E(b(n)), [s, u] = l, f = E(k(s));
return f || I(s, E(F(u, null)));
}
let [r, t] = E(b(n)), [o, i] = E(b(e));
if (!_(r, o))
return I(
r,
E(F(t, i))
);
let a = E(k(r));
return a && _(a, o) ? (
// 1. If incrementing a's integer doesn't reach b's integer,
// we can use the incremented value (shorter key)
a
) : (
// 2. If incrementing a's integer equals b's integer or we can't increment,
// we need to use a's integer with a fractional part that sorts after a's fractional part
I(r, E(F(t, null)))
);
}
function tn(n, e) {
return n != null && !N(n) || e != null && !N(e) || n != null && e != null && _(n, e) >= 0 ? void 0 : M(S(n), S(e));
}
function H(n, e, r) {
if (r < 1)
return [];
if (r === 1)
return [M(n, e)];
if (e == null) {
let i = n;
return Array.from(
{ length: r },
() => i = M(i, e)
);
}
if (n == null) {
let i = e;
return Array.from(
{ length: r },
() => i = M(n, i)
).reverse();
}
let t = r >> 1, o = M(n, e);
return [
...H(n, o, t),
o,
...H(o, e, r - t - 1)
];
}
function on(n, e, r) {
return n != null && !N(n) || e != null && !N(e) || n != null && e != null && _(n, e) >= 0 ? void 0 : H(S(n), S(e), r);
}
function q(n) {
let e = [];
for (; n > 0; )
e.push(n & 255), n >>= 8;
return new Uint8Array(e);
}
// src/lib/fractional-indexing-string.ts
function L(n, e, r, t, o) {
if (!n || n === o)
return !1;
let i = w(n, t);
if (!i)
return !1;
let [a, l] = i;
if (l.endsWith(e[0]))
return !1;
for (let s of a.slice(1))
if (!r.has(s))
return !1;
for (let s of l)
if (!r.has(s))
return !1;
return !0;
}
function m(n) {
if (n === void 0)
throw console.error(
"FraciError: [INTERNAL_ERROR] Unexpected undefined. Please file an issue to report this error."
), new c("INTERNAL_ERROR", "Unexpected undefined");
return n;
}
function U(n, e, r, t, o, i, a) {
if (!n) {
if (!e)
return nn(r, o);
let [d, h] = m(w(e, i));
if (d === a)
return `${d}${m(
B("", h, r, t)
)}`;
if (h)
return d;
let p = m(
rn(
d,
r,
t,
o,
i
)
);
return p === a ? `${p}${r[r.length - 1]}` : p;
}
if (!e) {
let d = m(w(n, i)), [h, p] = d, x = m(
j(
h,
r,
t,
o,
i
)
);
return x !== null ? x : `${h}${m(
B(p, null, r, t)
)}`;
}
let l = m(w(n, i)), s = m(w(e, i)), [u, f] = l, [y, g] = s;
if (u === y)
return `${u}${m(
B(f, g, r, t)
)}`;
let A = m(
j(
u,
r,
t,
o,
i
)
);
return A !== null && A !== y ? (
// 1. If incrementing a's integer doesn't reach b's integer,
// we can use the incremented value (shorter key)
A
) : (
// 2. If incrementing a's integer equals b's integer or we can't increment,
// we need to use a's integer with a fractional part that sorts after a's fractional part
`${u}${m(
B(f, null, r, t)
)}`
);
}
function an(n, e, r, t, o, i, a) {
return n != null && !L(
n,
r,
t,
i,
a
) || e != null && !L(
e,
r,
t,
i,
a
) || n != null && e != null && e <= n ? void 0 : U(
n,
e,
r,
t,
o,
i,
a
);
}
function W(n, e, r, ...t) {
if (r < 1)
return [];
if (r === 1)
return [U(n, e, ...t)];
if (e == null) {
let a = n;
return Array.from(
{ length: r },
() => a = U(a, e, ...t)
);
}
if (n == null) {
let a = e;
return Array.from(
{ length: r },
() => a = U(n, a, ...t)
).reverse();
}
let o = r >> 1, i = U(n, e, ...t);
return [
...W(n, i, o, ...t),
i,
...W(i, e, r - o - 1, ...t)
];
}
function ln(n, e, r, t, o, i, a, l) {
return n != null && !L(
n,
t,
o,
a,
l
) || e != null && !L(
e,
t,
o,
a,
l
) || n != null && e != null && e <= n ? void 0 : W(
n,
e,
r,
t,
o,
i,
a,
l
);
}
function v(n, e) {
let r = e.length, t = "";
for (; n > 0; )
t += e[n % r], n = Math.floor(n / r);
return t;
}
// src/lib/utils.ts
var sn = "INITIALIZATION_FAILED";
function un(n) {
let e = n.split("");
if (e.length < 4)
throw new c(
sn,
"Base string must have at least 4 unique characters"
);
let r = -1;
for (let t of e) {
let o = t.charCodeAt(0);
if (o <= r)
throw new c(
sn,
"Base string characters must be unique and in ascending order"
);
r = o;
}
return e;
}
function cn(n) {
let e = un(n);
return [e, new Map(e.map((r, t) => [r, t]))];
}
function fn(n) {
let e = un(n), r = e.length >> 1, t = e.map(
(o, i) => [
i < r ? (
// For characters in the first half, assign negative values starting from -1
i - r
) : (
// For characters in the second half, assign positive values starting from 1
i - r + 1
),
// This maps to 1, 2, 3, etc. (skipping 0)
o
]
);
return [
new Map(t),
new Map(t.map(([o, i]) => [i, o]))
];
}
// src/factory.ts
var z = 50, J = 5, D = "INVALID_FRACTIONAL_INDEX", T = "Invalid indices provided", O = "MAX_LENGTH_EXCEEDED", X = "Exceeded maximum length", C = "MAX_RETRIES_EXCEEDED", $ = "Exceeded maximum retries";
function Cn() {
return /* @__PURE__ */ new Map();
}
function yn(n, e, r) {
if (!n)
return r();
let t = n.get(e);
return t === void 0 && (t = r(), n.set(e, t)), t;
}
function K(n, e, r) {
console.error(
`FraciError: [INVALID_FRACTIONAL_INDEX] ${T}. a = ${n}, b = ${e}, skip = ${r}
Make sure that
- Fractional indices generated by the same fraci instance with the same configuration are being used as-is
- Indices in different groups have not been mixed up
- a (the first argument item) comes before b (the second argument item) in the group
File an issue if you use the library correctly and still encounter this error.`
);
}
function gn({
maxLength: n = z,
maxRetries: e = J
} = {}) {
return {
base: { type: "binary" },
*generateKeyBetween(r, t, o = 0) {
let i = tn(r, t);
if (!i)
throw K(r, t, o), new c(
D,
T
);
for (let a = 0; a < e; a++) {
let l = I(i, q(a + o));
if (l.length > n)
throw new c(
O,
X
);
yield l;
}
throw new c(
C,
$
);
},
*generateNKeysBetween(r, t, o, i = 0) {
let a = on(r, t, o);
if (!a)
throw K(r, t, i), new c(
D,
T
);
let l = a.reduce((s, u) => Math.max(s, u.length), 0);
for (let s = 0; s < e; s++) {
let u = q(s + i);
if (l + u.length > n)
throw new c(
O,
X
);
yield a.map((f) => I(f, u));
}
throw new c(
C,
$
);
}
};
}
function dn({
lengthBase: n,
digitBase: e,
maxLength: r = z,
maxRetries: t = J
}, o) {
let [i, a] = yn(
o,
`L${n}`,
fn.bind(null, n)
), [l, s] = yn(
o,
`D${e}`,
cn.bind(null, e)
), u = en(l, i);
return {
base: {
type: "string",
lengthBase: n,
digitBase: e
},
*generateKeyBetween(f, y, g = 0) {
let A = an(
f,
y,
l,
s,
i,
a,
u
);
if (!A)
throw K(f, y, g), new c(
D,
T
);
for (let d = 0; d < t; d++) {
let h = `${A}${v(d + g, l)}`;
if (h.length > r)
throw new c(
O,
X
);
yield h;
}
throw new c(
C,
$
);
},
*generateNKeysBetween(f, y, g, A = 0) {
let d = ln(
f,
y,
g,
l,
s,
i,
a,
u
);
if (!d)
throw K(f, y, A), new c(
D,
T
);
let h = d.reduce((p, x) => Math.max(p, x.length), 0);
for (let p = 0; p < t; p++) {
let x = v(p + A, l);
if (h + x.length > r)
throw new c(
O,
X
);
yield d.map((pn) => `${pn}${x}`);
}
throw new c(
C,
$
);
}
};
}
function $n(n, e) {
return n.type === "binary" ? (e && console.warn("Fraci: Cache is not used for binary base"), gn(n)) : dn(n, e);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BASE10,
BASE16L,
BASE16U,
BASE26L,
BASE26U,
BASE36L,
BASE36U,
BASE52,
BASE62,
BASE64URL,
BASE88,
BASE95,
DEFAULT_MAX_LENGTH,
DEFAULT_MAX_RETRIES,
FraciError,
createFraciCache,
fraci,
fraciBinary,
fraciString,
getFraciErrorCode,
isFraciError
});
//# sourceMappingURL=index.cjs.map