mirror of
https://github.com/get-drexa/drive.git
synced 2025-11-30 21:41:39 +00:00
feat: auth pkg and file proxy scaffold
Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
34
apps/file-proxy/.gitignore
vendored
Normal file
34
apps/file-proxy/.gitignore
vendored
Normal 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
apps/file-proxy/README.md
Normal file
15
apps/file-proxy/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# drive-file-proxy
|
||||||
|
|
||||||
|
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.
|
||||||
0
apps/file-proxy/convex.ts
Normal file
0
apps/file-proxy/convex.ts
Normal file
12
apps/file-proxy/files.ts
Normal file
12
apps/file-proxy/files.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Hono } from "hono"
|
||||||
|
|
||||||
|
const h = new Hono().basePath("/files")
|
||||||
|
|
||||||
|
h.get("/:fileId", async (c) => {
|
||||||
|
const fileId = c.req.param("fileId")
|
||||||
|
if (!fileId) {
|
||||||
|
return c.json({ error: "File ID is required" }, 400)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export { h as files }
|
||||||
10
apps/file-proxy/index.ts
Normal file
10
apps/file-proxy/index.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Hono } from "hono"
|
||||||
|
import { handleFileRequest } from "./files"
|
||||||
|
|
||||||
|
Bun.serve({
|
||||||
|
routes: {
|
||||||
|
"/files/:fileId": {
|
||||||
|
GET: handleFileRequest,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
17
apps/file-proxy/package.json
Normal file
17
apps/file-proxy/package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "@drexa/file-proxy",
|
||||||
|
"module": "index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fileone/convex": "workspace:*",
|
||||||
|
"convex": "^1.28.0",
|
||||||
|
"hono": "^4.10.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
apps/file-proxy/router.ts
Normal file
7
apps/file-proxy/router.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { RouterTypes } from "bun"
|
||||||
|
|
||||||
|
function router<
|
||||||
|
R extends { [K in keyof R]: RouterTypes.RouteValue<Extract<K, string>> },
|
||||||
|
>(routes: R): R {
|
||||||
|
return routes
|
||||||
|
}
|
||||||
29
apps/file-proxy/tsconfig.json
Normal file
29
apps/file-proxy/tsconfig.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
29
bun.lock
29
bun.lock
@@ -61,6 +61,29 @@
|
|||||||
"vite": "^7.1.10",
|
"vite": "^7.1.10",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"apps/file-proxy": {
|
||||||
|
"name": "@drexa/file-proxy",
|
||||||
|
"dependencies": {
|
||||||
|
"@fileone/convex": "workspace:*",
|
||||||
|
"convex": "^1.28.0",
|
||||||
|
"hono": "^4.10.1",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages/auth": {
|
||||||
|
"name": "@drexa/auth",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
"packages/convex": {
|
"packages/convex": {
|
||||||
"name": "@fileone/convex",
|
"name": "@fileone/convex",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -169,6 +192,10 @@
|
|||||||
|
|
||||||
"@convex-dev/better-auth": ["@convex-dev/better-auth@0.8.9", "", { "dependencies": { "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "is-network-error": "^1.1.0", "type-fest": "^4.39.1", "zod": "^3.24.4" }, "peerDependencies": { "better-auth": "1.3.8", "convex": "^1.26.2", "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-t6x2lYsgv0sGL14xmIsTqxVltkS//mWtIjb+Wm39rWUCgeqmCTqsyhQnmTDQNwaqZS0sH0WfTObNHu3xbCSx1w=="],
|
"@convex-dev/better-auth": ["@convex-dev/better-auth@0.8.9", "", { "dependencies": { "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "is-network-error": "^1.1.0", "type-fest": "^4.39.1", "zod": "^3.24.4" }, "peerDependencies": { "better-auth": "1.3.8", "convex": "^1.26.2", "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-t6x2lYsgv0sGL14xmIsTqxVltkS//mWtIjb+Wm39rWUCgeqmCTqsyhQnmTDQNwaqZS0sH0WfTObNHu3xbCSx1w=="],
|
||||||
|
|
||||||
|
"@drexa/auth": ["@drexa/auth@workspace:packages/auth"],
|
||||||
|
|
||||||
|
"@drexa/file-proxy": ["@drexa/file-proxy@workspace:apps/file-proxy"],
|
||||||
|
|
||||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
||||||
|
|
||||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
|
||||||
@@ -585,6 +612,8 @@
|
|||||||
|
|
||||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
|
"hono": ["hono@4.10.1", "", {}, "sha512-rpGNOfacO4WEPClfkEt1yfl8cbu10uB1lNpiI33AKoiAHwOS8lV748JiLx4b5ozO/u4qLjIvfpFsPXdY5Qjkmg=="],
|
||||||
|
|
||||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||||
|
|
||||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||||
|
|||||||
34
packages/auth/.gitignore
vendored
Normal file
34
packages/auth/.gitignore
vendored
Normal 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
15
packages/auth/README.md
Normal 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
64
packages/auth/index.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
11
packages/auth/package.json
Normal file
11
packages/auth/package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "@drexa/auth",
|
||||||
|
"module": "index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
29
packages/auth/tsconfig.json
Normal file
29
packages/auth/tsconfig.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user