add utils package + move get tokens to lib folder

This commit is contained in:
2026-05-11 23:16:26 +08:00
parent d2c2a46e54
commit f47491ad86
18 changed files with 482 additions and 54 deletions
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@koins/utils",
"version": "0.0.0",
"private": true,
"description": "A simple example library built by tsdown",
"type": "module",
"files": [
"dist"
],
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"
},
"scripts": {
"build": "tsdown",
"dev": "tsdown --watch"
},
"devDependencies": {
"tsdown": "^0.15.12"
}
}
+3
View File
@@ -0,0 +1,3 @@
export * from './try-catch'
export * from './username-generator'
export * from './nanoid'
+14
View File
@@ -0,0 +1,14 @@
// nanoid code
const urlAlphabet =
'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'
export const nanoid = (size = 32) => {
let id = ''
let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))
while (size--) {
// Using the bitwise AND operator to "cap" the value of
// the random byte from 255 to 63, in that way we can make sure
// that the value will be a valid index for the "chars" string.
id += urlAlphabet[bytes[size] & 63]
}
return id
}
+16
View File
@@ -0,0 +1,16 @@
type SuccessResult<T> = readonly [T, null]
type ErrorResult<E = Error> = readonly [null, E]
type Result<T, E = Error> = SuccessResult<T> | ErrorResult<E>
export async function tryCatch<T, E = Error>(
promise: Promise<T>,
): Promise<Result<T, E>> {
try {
const data = await promise
return [data, null] as const
} catch (error) {
return [null, error as E] as const
}
}
@@ -0,0 +1,41 @@
import { randomNumber } from './random-number'
export interface EmailOptions {
randomDigits?: number
stripLeadingDigits?: boolean // default: true
leadingFallback?: string // default: "user"
}
export function generateHandleFromEmail(
email: string,
second?: number | EmailOptions,
): string {
// Retrieve name from email address
const nameParts = email.replace(/@.+/, '')
// Replace all special characters like "@ . _ ";
let name = nameParts.replace(/[&/\\#,+()$~%._@'":*?<>{}]/g, '')
const opts: EmailOptions =
typeof second === 'object' && second !== null
? second
: {
randomDigits:
typeof second === 'number' ? second : undefined,
}
const stripLeading = opts.stripLeadingDigits !== false // default true
const fallback = opts.leadingFallback ?? 'user'
if (stripLeading) {
name = name.replace(/^[0-9]+/, '')
if (name.length === 0) {
name = fallback
}
}
// Create and return unique username
const digits =
typeof opts.randomDigits === 'number'
? opts.randomDigits
: undefined
return name + randomNumber(digits)
}
@@ -0,0 +1 @@
export { generateHandleFromEmail } from './generate-handle-from-email'
@@ -0,0 +1,89 @@
export const randomNumber = (maxNumber: number | undefined) => {
let randomNumberString
switch (maxNumber) {
case 1:
randomNumberString = Math.floor(getRandomInt(1, 9)).toString()
break
case 2:
randomNumberString = Math.floor(getRandomInt(10, 90)).toString()
break
case 3:
randomNumberString = Math.floor(
getRandomInt(100, 900),
).toString()
break
case 4:
randomNumberString = Math.floor(
getRandomInt(1000, 9000),
).toString()
break
case 5:
randomNumberString = Math.floor(
getRandomInt(10000, 90000),
).toString()
break
case 6:
randomNumberString = Math.floor(
getRandomInt(100000, 900000),
).toString()
break
default:
randomNumberString = ''
break
}
return randomNumberString
}
const getRandomInt = (
minInclusive: number,
maxInclusive: number,
): number => {
if (
!Number.isFinite(minInclusive) ||
!Number.isFinite(maxInclusive)
) {
throw new Error('Invalid bounds for getRandomInt')
}
if (maxInclusive < minInclusive) {
throw new Error('maxInclusive must be >= minInclusive')
}
if (minInclusive === maxInclusive) return minInclusive
const [rand] = getRandomValues(1)
const range = maxInclusive - minInclusive + 1
return minInclusive + (rand % range)
}
function getRandomValues(length: number): Uint32Array {
const cryptoApi = getCrypto()
if (cryptoApi && typeof cryptoApi.getRandomValues === 'function') {
const buffer = new Uint32Array(length)
cryptoApi.getRandomValues(buffer)
return buffer
}
const buffer = new Uint32Array(length)
for (let i = 0; i < length; i++) {
buffer[i] = nextFallback32()
}
return buffer
}
function getCrypto(): Crypto | undefined {
const g =
typeof globalThis !== 'undefined'
? (globalThis as unknown as { crypto?: Crypto })
: undefined
return g && g.crypto ? (g.crypto as Crypto) : undefined
}
let fallbackSeed: number = (Date.now() ^ 0x9e3779b9) >>> 0
function nextFallback32(): number {
// xorshift32 advancing persistent state
fallbackSeed ^= fallbackSeed << 13
fallbackSeed >>>= 0
fallbackSeed ^= fallbackSeed >>> 17
fallbackSeed >>>= 0
fallbackSeed ^= fallbackSeed << 5
fallbackSeed >>>= 0
return fallbackSeed >>> 0
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2021",
"module": "ES2022",
"moduleResolution": "node10",
"paths": {
"$lib/*": ["./lib/*"]
},
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
+9
View File
@@ -0,0 +1,9 @@
import { defineConfig } from 'tsdown'
export default defineConfig({
entry: ['src/index.ts'],
platform: 'neutral',
clean: false,
dts: true,
ignoreWatch: ['./.turbo'],
})