feat: auth pkg and file proxy scaffold

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2025-10-19 17:05:15 +00:00
parent c0f852ad35
commit e58caa6b16
14 changed files with 306 additions and 0 deletions

34
packages/auth/.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# dependencies (bun install)
node_modules
# output
out
dist
*.tgz
# code coverage
coverage
*.lcov
# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# caches
.eslintcache
.cache
*.tsbuildinfo
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

15
packages/auth/README.md Normal file
View File

@@ -0,0 +1,15 @@
# @drexa/auth
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run index.ts
```
This project was created using `bun init` in bun v1.3.0. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.

64
packages/auth/index.ts Normal file
View File

@@ -0,0 +1,64 @@
/**
* An unhashed api key.
* Always starts with sk, then the prefix specified at time of generation,
* and ends with the base64url-encoded key.
*/
export type UnhashedApiKey = `sk-${ApiKeyPrefix}-${string}`
export type ApiKeyPrefix = string & { __brand: "ApiKeyPrefix" }
export type GenerateApiKeyOptions = {
/**
* How long the key should be (excluding prefix) in bytes.
*/
keyByteLength: number
/**
* Prefix of the api key. Can be a brief name of the consumer of the key.
* For example, if the prefix is "proxy", the key will be "sk-proxy-asdasjdjsdkjd.."
*/
prefix: ApiKeyPrefix
expiresAt?: Date
description: string
}
export type GenerateApiKeyResult = {
unhashedKey: UnhashedApiKey
hashedKey: string
expiresAt?: Date
description: string
}
export function newPrefix(prefix: string): ApiKeyPrefix | null {
if (prefix.includes("-")) {
return null
}
return prefix as ApiKeyPrefix
}
export async function generateApiKey({
keyByteLength,
prefix,
expiresAt,
description,
}: GenerateApiKeyOptions): Promise<GenerateApiKeyResult> {
const keyContent = new Uint8Array(keyByteLength)
crypto.getRandomValues(keyContent)
const base64KeyContent = Buffer.from(keyContent).toString("base64url")
const unhashedKey: UnhashedApiKey = `sk-${prefix}-${base64KeyContent}`
const hashedKey = await Bun.password.hash(unhashedKey, {
algorithm: "argon2id",
memoryCost: 4, // memory usage in kibibytes
timeCost: 3, // the number of iterations
})
return {
unhashedKey,
hashedKey,
expiresAt,
description,
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "@drexa/auth",
"module": "index.ts",
"type": "module",
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
}
}

View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}