39 lines
1 KiB
TypeScript
39 lines
1 KiB
TypeScript
import Sqids from "sqids";
|
|
|
|
export type Slug = string & { readonly __tag: unique symbol };
|
|
|
|
export class Slugs {
|
|
private static instance: Slugs;
|
|
private sqids!: Sqids;
|
|
|
|
private constructor() {
|
|
if (Slugs.instance) return Slugs.instance;
|
|
Slugs.instance = this;
|
|
|
|
this.sqids = new Sqids({
|
|
alphabet: "dbnixSPYJNy5hvsqCWIHwEKTFutV6r4Xa32okL8RQUj7Am9DcpgfZezMBG",
|
|
});
|
|
}
|
|
|
|
static encode(num: number | bigint): Slug {
|
|
const sqids = new Slugs().sqids;
|
|
const thirtyTwoBitMax = BigInt(0xffffffff);
|
|
if (typeof num === "bigint" && num > thirtyTwoBitMax) {
|
|
const arr = [];
|
|
while (num > 0) {
|
|
arr.push(Number(num & thirtyTwoBitMax));
|
|
num >>= 32n;
|
|
}
|
|
return sqids.encode(arr) as Slug;
|
|
} else {
|
|
return sqids.encode([Number(num)]) as Slug;
|
|
}
|
|
}
|
|
|
|
static decode(slug: Slug): number | bigint {
|
|
const ns = new Slugs().sqids.decode(slug);
|
|
if (ns.length === 1) return ns[0];
|
|
|
|
return ns.reduceRight((big, each) => (big << 32n) + BigInt(each), 0n);
|
|
}
|
|
}
|