diff --git a/apps/client/app/components/create-volume-dialog.tsx b/apps/client/app/components/create-volume-dialog.tsx index c88d7cc..1b53ace 100644 --- a/apps/client/app/components/create-volume-dialog.tsx +++ b/apps/client/app/components/create-volume-dialog.tsx @@ -1,4 +1,5 @@ import { arktypeResolver } from "@hookform/resolvers/arktype"; +import { volumeConfigSchema } from "@ironmount/schemas"; import { type } from "arktype"; import { Plus } from "lucide-react"; import { useForm } from "react-hook-form"; @@ -19,15 +20,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from ". export const formSchema = type({ name: "2<=string<=32", - backend: "'directory'", -}).or({ - name: "2<=string<=32", - backend: "'nfs'", - server: "string", - exportPath: "string", - port: "number >= 1", - version: "'3' | '4' | '4.1'", -}); +}).and(volumeConfigSchema); type FormValues = typeof formSchema.infer; type Props = { diff --git a/apps/client/package.json b/apps/client/package.json index 564b905..b647b21 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@hookform/resolvers": "^5.2.1", - "@ironmount/server": "workspace:*", + "@ironmount/schemas": "workspace:*", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.7", diff --git a/apps/server/package.json b/apps/server/package.json index 180368f..6463398 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -3,10 +3,12 @@ "type": "module", "scripts": { "dev": "bun run --hot src/index.ts", + "typecheck": "tsc --noEmit", "gen:migrations": "drizzle-kit generate" }, "dependencies": { "@hono/arktype-validator": "^2.0.1", + "@ironmount/schemas": "workspace:*", "@scalar/hono-api-reference": "^0.9.13", "arktype": "^2.1.20", "dotenv": "^17.2.1", diff --git a/apps/server/src/db/schema.ts b/apps/server/src/db/schema.ts index b198581..b050044 100644 --- a/apps/server/src/db/schema.ts +++ b/apps/server/src/db/schema.ts @@ -1,34 +1,7 @@ -import { type } from "arktype"; +import type { volumeConfigSchema } from "@ironmount/schemas"; import { sql } from "drizzle-orm"; import { int, sqliteTable, text } from "drizzle-orm/sqlite-core"; -const BACKEND_TYPES = { - nfs: "nfs", - smb: "smb", - directory: "directory", -}; -export type BackendType = keyof typeof BACKEND_TYPES; - -const nfsConfigSchema = type({ - backend: "'nfs'", - server: "string", - exportPath: "string", - port: "number >= 1", - version: "'3' | '4' | '4.1'", -}); - -const smbConfigSchema = type({ - backend: "'smb'", -}); - -const directoryConfigSchema = type({ - backend: "'directory'", -}); - -export const volumeConfigSchema = nfsConfigSchema.or(smbConfigSchema).or(directoryConfigSchema); - -export type BackendConfig = typeof volumeConfigSchema.infer; - export const volumesTable = sqliteTable("volumes_table", { id: int().primaryKey({ autoIncrement: true }), name: text().notNull().unique(), diff --git a/apps/server/src/modules/backends/nfs/nfs-backend.ts b/apps/server/src/modules/backends/nfs/nfs-backend.ts index dd12aca..6e89d50 100644 --- a/apps/server/src/modules/backends/nfs/nfs-backend.ts +++ b/apps/server/src/modules/backends/nfs/nfs-backend.ts @@ -1,6 +1,6 @@ import { exec } from "node:child_process"; import * as os from "node:os"; -import type { BackendConfig } from "../../../db/schema"; +import type { BackendConfig } from "@ironmount/schemas"; import type { VolumeBackend } from "../backend"; const mount = async (config: BackendConfig, path: string) => { diff --git a/apps/server/src/modules/volumes/volume.dto.ts b/apps/server/src/modules/volumes/volume.dto.ts index e5514ef..db145cf 100644 --- a/apps/server/src/modules/volumes/volume.dto.ts +++ b/apps/server/src/modules/volumes/volume.dto.ts @@ -1,7 +1,7 @@ +import { volumeConfigSchema } from "@ironmount/schemas"; import { type } from "arktype"; import { describeRoute } from "hono-openapi"; import { resolver } from "hono-openapi/arktype"; -import { volumeConfigSchema } from "../../db/schema"; /** * List all volumes diff --git a/apps/server/src/modules/volumes/volume.service.ts b/apps/server/src/modules/volumes/volume.service.ts index ef29d0a..5918d9b 100644 --- a/apps/server/src/modules/volumes/volume.service.ts +++ b/apps/server/src/modules/volumes/volume.service.ts @@ -1,10 +1,11 @@ import * as path from "node:path"; +import type { BackendConfig } from "@ironmount/schemas"; import { eq } from "drizzle-orm"; import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced"; import slugify from "slugify"; import { config } from "../../core/config"; import { db } from "../../db/db"; -import { type BackendConfig, volumesTable } from "../../db/schema"; +import { volumesTable } from "../../db/schema"; import { createVolumeBackend } from "../backends/backend"; const listVolumes = async () => { diff --git a/bun.lock b/bun.lock index e8b4ae1..47614cd 100644 --- a/bun.lock +++ b/bun.lock @@ -12,7 +12,7 @@ "name": "@ironmount/client", "dependencies": { "@hookform/resolvers": "^5.2.1", - "@ironmount/server": "workspace:*", + "@ironmount/schemas": "workspace:*", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.7", @@ -52,6 +52,7 @@ "name": "@ironmount/server", "dependencies": { "@hono/arktype-validator": "^2.0.1", + "@ironmount/schemas": "workspace:*", "@scalar/hono-api-reference": "^0.9.13", "arktype": "^2.1.20", "dotenv": "^17.2.1", @@ -66,6 +67,13 @@ "drizzle-kit": "^0.31.4", }, }, + "packages/schemas": { + "name": "@ironmount/schemas", + "version": "0.0.0", + "peerDependencies": { + "arktype": ">=2", + }, + }, }, "packages": { "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], @@ -208,6 +216,8 @@ "@ironmount/client": ["@ironmount/client@workspace:apps/client"], + "@ironmount/schemas": ["@ironmount/schemas@workspace:packages/schemas"], + "@ironmount/server": ["@ironmount/server@workspace:apps/server"], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], diff --git a/package.json b/package.json index b4b29b6..a8df523 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "gen:api-client": "openapi-ts" }, "workspaces": [ - "apps/*" + "apps/*", + "packages/*" ], "devDependencies": { "@hey-api/openapi-ts": "^0.80.17", diff --git a/packages/schemas/package.json b/packages/schemas/package.json new file mode 100644 index 0000000..a21a19b --- /dev/null +++ b/packages/schemas/package.json @@ -0,0 +1,11 @@ +{ + "name": "@ironmount/schemas", + "version": "0.0.0", + "private": true, + "main": "./src/index.ts", + "types": "./src/index.ts", + "type": "module", + "peerDependencies": { + "arktype": ">=2" + } +} diff --git a/packages/schemas/src/index.ts b/packages/schemas/src/index.ts new file mode 100644 index 0000000..3eed4e2 --- /dev/null +++ b/packages/schemas/src/index.ts @@ -0,0 +1,29 @@ +import { type } from "arktype"; + +export const BACKEND_TYPES = { + nfs: "nfs", + smb: "smb", + directory: "directory", +} as const; + +export type BackendType = keyof typeof BACKEND_TYPES; + +export const nfsConfigSchema = type({ + backend: "'nfs'", + server: "string", + exportPath: "string", + port: "number >= 1", + version: "'3' | '4' | '4.1'", +}); + +export const smbConfigSchema = type({ + backend: "'smb'", +}); + +export const directoryConfigSchema = type({ + backend: "'directory'", +}); + +export const volumeConfigSchema = nfsConfigSchema.or(smbConfigSchema).or(directoryConfigSchema); + +export type BackendConfig = typeof volumeConfigSchema.infer; diff --git a/packages/schemas/tsconfig.json b/packages/schemas/tsconfig.json new file mode 100644 index 0000000..a71a862 --- /dev/null +++ b/packages/schemas/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "allowJs": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +}