@nubase/create 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +148 -0
  3. package/package.json +55 -0
  4. package/templates/backend/.env.development.template +4 -0
  5. package/templates/backend/.env.test.template +4 -0
  6. package/templates/backend/db/schema.sql +95 -0
  7. package/templates/backend/docker/dev/docker-compose.yml +21 -0
  8. package/templates/backend/docker/dev/postgresql-init/dump.sql +95 -0
  9. package/templates/backend/docker/test/docker-compose.yml +21 -0
  10. package/templates/backend/docker/test/postgresql-init/dump.sql +95 -0
  11. package/templates/backend/drizzle.config.ts +10 -0
  12. package/templates/backend/package.json +47 -0
  13. package/templates/backend/src/api/routes/auth.ts +209 -0
  14. package/templates/backend/src/api/routes/index.ts +2 -0
  15. package/templates/backend/src/api/routes/ticket.ts +62 -0
  16. package/templates/backend/src/auth/index.ts +37 -0
  17. package/templates/backend/src/db/helpers/drizzle.ts +34 -0
  18. package/templates/backend/src/db/schema/index.ts +4 -0
  19. package/templates/backend/src/db/schema/ticket.ts +13 -0
  20. package/templates/backend/src/db/schema/user-workspace.ts +17 -0
  21. package/templates/backend/src/db/schema/user.ts +10 -0
  22. package/templates/backend/src/db/schema/workspace.ts +9 -0
  23. package/templates/backend/src/db/seed.ts +71 -0
  24. package/templates/backend/src/helpers/env.ts +10 -0
  25. package/templates/backend/src/index.ts +55 -0
  26. package/templates/backend/src/middleware/workspace-middleware.ts +11 -0
  27. package/templates/backend/tsconfig.json +15 -0
  28. package/templates/backend/vitest.config.ts +8 -0
  29. package/templates/frontend/.env.development.template +1 -0
  30. package/templates/frontend/index.html +13 -0
  31. package/templates/frontend/package.json +30 -0
  32. package/templates/frontend/postcss.config.js +5 -0
  33. package/templates/frontend/src/auth/__PROJECT_NAME_PASCAL__AuthController.ts +59 -0
  34. package/templates/frontend/src/config.tsx +76 -0
  35. package/templates/frontend/src/main.tsx +6 -0
  36. package/templates/frontend/src/resources/ticket.ts +32 -0
  37. package/templates/frontend/src/styles/theme.css +3 -0
  38. package/templates/frontend/src/vite-env.d.ts +9 -0
  39. package/templates/frontend/tsconfig.json +17 -0
  40. package/templates/frontend/vite.config.ts +14 -0
  41. package/templates/root/README.md +94 -0
  42. package/templates/root/biome.json.template +40 -0
  43. package/templates/root/package.json +30 -0
  44. package/templates/root/turbo.json +18 -0
  45. package/templates/schema/package.json +28 -0
  46. package/templates/schema/src/api-endpoints.ts +34 -0
  47. package/templates/schema/src/index.ts +3 -0
  48. package/templates/schema/src/schema/auth.ts +89 -0
  49. package/templates/schema/src/schema/ticket.ts +68 -0
  50. package/templates/schema/tsconfig.json +14 -0
@@ -0,0 +1,59 @@
1
+ import type { AuthController, AuthState } from "@nubase/frontend";
2
+ import type { ApiEndpoints } from "__PROJECT_NAME__-schema";
3
+
4
+ const TOKEN_KEY = "__PROJECT_NAME___auth_token";
5
+
6
+ export class __PROJECT_NAME_PASCAL__AuthController implements AuthController<ApiEndpoints> {
7
+ private token: string | null = null;
8
+
9
+ constructor() {
10
+ this.token = localStorage.getItem(TOKEN_KEY);
11
+ }
12
+
13
+ async getAuthState(
14
+ httpClient: {
15
+ request: <E extends keyof ApiEndpoints>(
16
+ endpoint: E,
17
+ options?: { body?: unknown; params?: unknown },
18
+ ) => Promise<ApiEndpoints[E]["responseBody"]>;
19
+ },
20
+ workspace: string,
21
+ ): Promise<AuthState> {
22
+ if (!this.token) {
23
+ return { isAuthenticated: false };
24
+ }
25
+
26
+ try {
27
+ const response = await httpClient.request("getMe", {});
28
+ return {
29
+ isAuthenticated: true,
30
+ user: response.user,
31
+ workspace: response.workspace,
32
+ };
33
+ } catch {
34
+ this.clearToken();
35
+ return { isAuthenticated: false };
36
+ }
37
+ }
38
+
39
+ getAuthHeaders(): Record<string, string> {
40
+ if (!this.token) {
41
+ return {};
42
+ }
43
+ return { Authorization: `Bearer ${this.token}` };
44
+ }
45
+
46
+ setToken(token: string): void {
47
+ this.token = token;
48
+ localStorage.setItem(TOKEN_KEY, token);
49
+ }
50
+
51
+ clearToken(): void {
52
+ this.token = null;
53
+ localStorage.removeItem(TOKEN_KEY);
54
+ }
55
+
56
+ getToken(): string | null {
57
+ return this.token;
58
+ }
59
+ }
@@ -0,0 +1,76 @@
1
+ import {
2
+ type NubaseFrontendConfig,
3
+ defaultKeybindings,
4
+ resourceLink,
5
+ } from "@nubase/frontend";
6
+ import { apiEndpoints } from "__PROJECT_NAME__-schema";
7
+ import { __PROJECT_NAME_PASCAL__AuthController } from "./auth/__PROJECT_NAME_PASCAL__AuthController";
8
+ import { ticketResource } from "./resources/ticket";
9
+
10
+ // Icons (inline SVG from Tabler Icons)
11
+ const HomeIcon = () => (
12
+ <svg
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ width="20"
15
+ height="20"
16
+ viewBox="0 0 24 24"
17
+ fill="none"
18
+ stroke="currentColor"
19
+ strokeWidth="2"
20
+ strokeLinecap="round"
21
+ strokeLinejoin="round"
22
+ >
23
+ <path d="M5 12l-2 0l9 -9l9 9l-2 0" />
24
+ <path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" />
25
+ <path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" />
26
+ </svg>
27
+ );
28
+
29
+ const TicketIcon = () => (
30
+ <svg
31
+ xmlns="http://www.w3.org/2000/svg"
32
+ width="20"
33
+ height="20"
34
+ viewBox="0 0 24 24"
35
+ fill="none"
36
+ stroke="currentColor"
37
+ strokeWidth="2"
38
+ strokeLinecap="round"
39
+ strokeLinejoin="round"
40
+ >
41
+ <path d="M15 5l0 2" />
42
+ <path d="M15 11l0 2" />
43
+ <path d="M15 17l0 2" />
44
+ <path d="M5 5h14a2 2 0 0 1 2 2v3a2 2 0 0 0 0 4v3a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-3a2 2 0 0 0 0 -4v-3a2 2 0 0 1 2 -2" />
45
+ </svg>
46
+ );
47
+
48
+ const authController = new __PROJECT_NAME_PASCAL__AuthController();
49
+
50
+ export const config: NubaseFrontendConfig<typeof apiEndpoints> = {
51
+ appName: "__PROJECT_NAME_PASCAL__",
52
+ mainMenu: [
53
+ {
54
+ id: "home",
55
+ icon: HomeIcon,
56
+ label: "Home",
57
+ href: "/",
58
+ },
59
+ {
60
+ id: "tickets",
61
+ icon: TicketIcon,
62
+ label: "Tickets",
63
+ href: resourceLink(ticketResource, "search"),
64
+ },
65
+ ],
66
+ resources: {
67
+ [ticketResource.id]: ticketResource,
68
+ },
69
+ keybindings: defaultKeybindings,
70
+ apiBaseUrl: import.meta.env.VITE_API_BASE_URL || "http://localhost:__BACKEND_PORT__",
71
+ apiEndpoints,
72
+ themeIds: ["dark", "light"],
73
+ defaultThemeId: "dark",
74
+ authentication: authController,
75
+ publicRoutes: ["/signin"],
76
+ };
@@ -0,0 +1,6 @@
1
+ import { NubaseApp } from "@nubase/frontend";
2
+ import { createRoot } from "react-dom/client";
3
+ import { config } from "./config";
4
+ import "./styles/theme.css";
5
+
6
+ createRoot(document.getElementById("root")!).render(<NubaseApp config={config} />);
@@ -0,0 +1,32 @@
1
+ import { createResource } from "@nubase/frontend";
2
+ import { apiEndpoints, ticketBaseSchema } from "__PROJECT_NAME__-schema";
3
+
4
+ export const ticketResource = createResource("ticket")
5
+ .withApiEndpoints(apiEndpoints)
6
+ .withViews({
7
+ create: {
8
+ type: "resource-create",
9
+ title: "Create Ticket",
10
+ schema: ticketBaseSchema.omit("id", "createdAt", "updatedAt"),
11
+ submitEndpoint: "postTicket",
12
+ },
13
+ view: {
14
+ type: "resource-view",
15
+ title: "View Ticket",
16
+ schema: ticketBaseSchema,
17
+ fetchEndpoint: "getTicket",
18
+ },
19
+ edit: {
20
+ type: "resource-edit",
21
+ title: "Edit Ticket",
22
+ schema: ticketBaseSchema,
23
+ fetchEndpoint: "getTicket",
24
+ submitEndpoint: "patchTicket",
25
+ },
26
+ search: {
27
+ type: "resource-search",
28
+ title: "Tickets",
29
+ schema: ticketBaseSchema,
30
+ fetchEndpoint: "getTickets",
31
+ },
32
+ });
@@ -0,0 +1,3 @@
1
+ @import "@nubase/frontend/theme";
2
+
3
+ /* Custom theme overrides can be added here */
@@ -0,0 +1,9 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly VITE_API_BASE_URL: string;
5
+ }
6
+
7
+ interface ImportMeta {
8
+ readonly env: ImportMetaEnv;
9
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "esModuleInterop": true,
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "noEmit": true,
11
+ "jsx": "react-jsx",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true
14
+ },
15
+ "include": ["src/**/*"],
16
+ "exclude": ["node_modules"]
17
+ }
@@ -0,0 +1,14 @@
1
+ import tailwindcss from "@tailwindcss/vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import { defineConfig } from "vite";
4
+
5
+ export default defineConfig({
6
+ plugins: [react(), tailwindcss()],
7
+ build: {
8
+ outDir: "dist",
9
+ },
10
+ server: {
11
+ port: __FRONTEND_PORT__,
12
+ open: "http://localhost:__FRONTEND_PORT__/default",
13
+ },
14
+ });
@@ -0,0 +1,94 @@
1
+ # __PROJECT_NAME_PASCAL__
2
+
3
+ A Nubase application.
4
+
5
+ ## Getting Started
6
+
7
+ ### Prerequisites
8
+
9
+ - Node.js >= 18
10
+ - Docker and Docker Compose
11
+ - npm
12
+
13
+ ### Setup
14
+
15
+ 1. Install dependencies:
16
+
17
+ ```bash
18
+ npm install
19
+ ```
20
+
21
+ 2. Start the database:
22
+
23
+ ```bash
24
+ npm run db:up
25
+ ```
26
+
27
+ 3. Seed the database with sample data:
28
+
29
+ ```bash
30
+ npm run db:seed
31
+ ```
32
+
33
+ 4. Start the development servers:
34
+
35
+ ```bash
36
+ npm run dev
37
+ ```
38
+
39
+ The application will be available at:
40
+ - Frontend: http://localhost:__FRONTEND_PORT__/default
41
+ - Backend API: http://localhost:__BACKEND_PORT__
42
+
43
+ ### Default Credentials
44
+
45
+ - Email: demo@example.com
46
+ - Password: password123
47
+
48
+ ## Project Structure
49
+
50
+ ```
51
+ __PROJECT_NAME__/
52
+ ├── __PROJECT_NAME__-schema/ # Shared API schemas and types
53
+ ├── __PROJECT_NAME__-backend/ # Node.js backend (Hono + PostgreSQL)
54
+ ├── __PROJECT_NAME__-frontend/ # React frontend (Vite + Nubase)
55
+ └── package.json # Root workspace configuration
56
+ ```
57
+
58
+ ## Available Scripts
59
+
60
+ - `npm run dev` - Start both frontend and backend in development mode
61
+ - `npm run build` - Build all packages
62
+ - `npm run db:up` - Start PostgreSQL database
63
+ - `npm run db:down` - Stop PostgreSQL database
64
+ - `npm run db:seed` - Seed database with sample data
65
+ - `npm run typecheck` - Run TypeScript type checking
66
+ - `npm run lint` - Run linting
67
+ - `npm run lint:fix` - Fix linting issues
68
+
69
+ ## Database
70
+
71
+ The application uses PostgreSQL with Row Level Security (RLS) for multi-tenant data isolation.
72
+
73
+ ### Connection Details
74
+
75
+ - Host: localhost
76
+ - Port: __DEV_PORT__
77
+ - Database: __DB_NAME__
78
+ - User: __DB_USER__
79
+ - Password: __DB_PASSWORD__
80
+
81
+ ### Schema
82
+
83
+ The database includes the following tables:
84
+ - `workspaces` - Multi-tenant workspace isolation
85
+ - `users` - User accounts
86
+ - `user_workspaces` - User-workspace associations
87
+ - `tickets` - Sample entity with RLS policies
88
+
89
+ ## Learn More
90
+
91
+ - [Nubase Documentation](https://nubase.dev)
92
+ - [Hono](https://hono.dev)
93
+ - [Drizzle ORM](https://orm.drizzle.team)
94
+ - [TanStack Router](https://tanstack.com/router)
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
3
+ "vcs": {
4
+ "enabled": true,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": true
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false,
10
+ "includes": [
11
+ "**",
12
+ "!**/build",
13
+ "!**/dist",
14
+ "!**/node_modules",
15
+ "!**/docker"
16
+ ]
17
+ },
18
+ "formatter": {
19
+ "enabled": true,
20
+ "indentStyle": "space",
21
+ "indentWidth": 2
22
+ },
23
+ "linter": {
24
+ "enabled": true,
25
+ "rules": {
26
+ "recommended": true,
27
+ "style": {
28
+ "noNonNullAssertion": "off"
29
+ },
30
+ "suspicious": {
31
+ "noExplicitAny": "off"
32
+ }
33
+ }
34
+ },
35
+ "javascript": {
36
+ "formatter": {
37
+ "quoteStyle": "double"
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "workspaces": [
7
+ "__PROJECT_NAME__-schema",
8
+ "__PROJECT_NAME__-backend",
9
+ "__PROJECT_NAME__-frontend"
10
+ ],
11
+ "scripts": {
12
+ "dev": "turbo run dev",
13
+ "build": "turbo run build",
14
+ "db:up": "cd __PROJECT_NAME__-backend && npm run db:dev:up",
15
+ "db:down": "cd __PROJECT_NAME__-backend && npm run db:dev:down",
16
+ "db:kill": "cd __PROJECT_NAME__-backend && npm run db:dev:kill",
17
+ "db:seed": "cd __PROJECT_NAME__-backend && npm run db:seed",
18
+ "typecheck": "turbo run typecheck",
19
+ "lint": "turbo run lint",
20
+ "lint:fix": "turbo run lint:fix"
21
+ },
22
+ "devDependencies": {
23
+ "@biomejs/biome": "^2.3.10",
24
+ "turbo": "^2.7.2",
25
+ "typescript": "^5.7.2"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "https://turbo.build/schema.json",
3
+ "tasks": {
4
+ "build": {
5
+ "dependsOn": ["^build"],
6
+ "outputs": ["dist/**"]
7
+ },
8
+ "dev": {
9
+ "cache": false,
10
+ "persistent": true
11
+ },
12
+ "typecheck": {
13
+ "dependsOn": ["^build"]
14
+ },
15
+ "lint": {},
16
+ "lint:fix": {}
17
+ }
18
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "__PROJECT_NAME__-schema",
3
+ "version": "0.1.0",
4
+ "description": "Schema for __PROJECT_NAME_PASCAL__",
5
+ "type": "module",
6
+ "files": [
7
+ "src"
8
+ ],
9
+ "exports": {
10
+ ".": {
11
+ "types": "./src/index.ts",
12
+ "import": "./src/index.ts",
13
+ "require": "./src/index.ts"
14
+ }
15
+ },
16
+ "license": "MIT",
17
+ "scripts": {
18
+ "typecheck": "tsc --noEmit",
19
+ "lint": "biome check .",
20
+ "lint:fix": "biome check . --write --unsafe"
21
+ },
22
+ "dependencies": {
23
+ "@nubase/core": "*"
24
+ },
25
+ "devDependencies": {
26
+ "typescript": "^5.7.2"
27
+ }
28
+ }
@@ -0,0 +1,34 @@
1
+ import {
2
+ deleteTicketSchema,
3
+ getTicketSchema,
4
+ getTicketsSchema,
5
+ patchTicketSchema,
6
+ postTicketSchema,
7
+ } from "./schema/ticket";
8
+ import {
9
+ getMeSchema,
10
+ loginCompleteSchema,
11
+ loginSchema,
12
+ loginStartSchema,
13
+ logoutSchema,
14
+ signupSchema,
15
+ } from "./schema/auth";
16
+
17
+ export const apiEndpoints = {
18
+ // Tickets
19
+ getTickets: getTicketsSchema,
20
+ getTicket: getTicketSchema,
21
+ postTicket: postTicketSchema,
22
+ patchTicket: patchTicketSchema,
23
+ deleteTicket: deleteTicketSchema,
24
+
25
+ // Auth
26
+ loginStart: loginStartSchema,
27
+ loginComplete: loginCompleteSchema,
28
+ login: loginSchema,
29
+ logout: logoutSchema,
30
+ getMe: getMeSchema,
31
+ signup: signupSchema,
32
+ } as const;
33
+
34
+ export type ApiEndpoints = typeof apiEndpoints;
@@ -0,0 +1,3 @@
1
+ export * from "./api-endpoints";
2
+ export * from "./schema/ticket";
3
+ export * from "./schema/auth";
@@ -0,0 +1,89 @@
1
+ import { type RequestSchema, nu } from "@nubase/core";
2
+
3
+ export const workspaceSchema = nu.object({
4
+ id: nu.number(),
5
+ slug: nu.string(),
6
+ name: nu.string(),
7
+ });
8
+
9
+ export type Workspace = (typeof workspaceSchema)["_output"];
10
+
11
+ export const userSchema = nu.object({
12
+ id: nu.number(),
13
+ email: nu.string(),
14
+ username: nu.string(),
15
+ });
16
+
17
+ export type User = (typeof userSchema)["_output"];
18
+
19
+ export const loginStartSchema = {
20
+ method: "POST",
21
+ path: "/auth/login/start",
22
+ requestBody: nu.object({
23
+ email: nu.string(),
24
+ password: nu.string(),
25
+ }),
26
+ responseBody: nu.object({
27
+ workspaces: nu.array(workspaceSchema),
28
+ }),
29
+ } satisfies RequestSchema;
30
+
31
+ export const loginCompleteSchema = {
32
+ method: "POST",
33
+ path: "/auth/login/complete",
34
+ requestBody: nu.object({
35
+ email: nu.string(),
36
+ password: nu.string(),
37
+ workspaceId: nu.number(),
38
+ }),
39
+ responseBody: nu.object({
40
+ token: nu.string(),
41
+ user: userSchema,
42
+ workspace: workspaceSchema,
43
+ }),
44
+ } satisfies RequestSchema;
45
+
46
+ export const loginSchema = {
47
+ method: "POST",
48
+ path: "/auth/login",
49
+ requestBody: nu.object({
50
+ email: nu.string(),
51
+ password: nu.string(),
52
+ }),
53
+ responseBody: nu.object({
54
+ token: nu.string(),
55
+ user: userSchema,
56
+ workspace: workspaceSchema,
57
+ }),
58
+ } satisfies RequestSchema;
59
+
60
+ export const logoutSchema = {
61
+ method: "POST",
62
+ path: "/auth/logout",
63
+ responseBody: nu.object({ success: nu.boolean() }),
64
+ } satisfies RequestSchema;
65
+
66
+ export const getMeSchema = {
67
+ method: "GET",
68
+ path: "/auth/me",
69
+ responseBody: nu.object({
70
+ user: userSchema,
71
+ workspace: workspaceSchema,
72
+ }),
73
+ } satisfies RequestSchema;
74
+
75
+ export const signupSchema = {
76
+ method: "POST",
77
+ path: "/auth/signup",
78
+ requestBody: nu.object({
79
+ email: nu.string(),
80
+ username: nu.string(),
81
+ password: nu.string(),
82
+ workspaceName: nu.string().optional(),
83
+ }),
84
+ responseBody: nu.object({
85
+ token: nu.string(),
86
+ user: userSchema,
87
+ workspace: workspaceSchema,
88
+ }),
89
+ } satisfies RequestSchema;
@@ -0,0 +1,68 @@
1
+ import { type RequestSchema, nu } from "@nubase/core";
2
+
3
+ export const ticketBaseSchema = nu
4
+ .object({
5
+ id: nu.number(),
6
+ title: nu.string().withMeta({
7
+ label: "Title",
8
+ placeholder: "Enter ticket title",
9
+ }),
10
+ description: nu.string().optional().withMeta({
11
+ label: "Description",
12
+ placeholder: "Enter ticket description",
13
+ renderer: "multiline",
14
+ }),
15
+ createdAt: nu.string().optional().withMeta({
16
+ label: "Created At",
17
+ }),
18
+ updatedAt: nu.string().optional().withMeta({
19
+ label: "Updated At",
20
+ }),
21
+ })
22
+ .withId("id")
23
+ .withTableLayouts({
24
+ default: {
25
+ fields: ["id", "title", "description", "createdAt"],
26
+ metadata: {
27
+ linkFields: ["title"],
28
+ },
29
+ },
30
+ });
31
+
32
+ export type Ticket = (typeof ticketBaseSchema)["_output"];
33
+
34
+ export const getTicketsSchema = {
35
+ method: "GET",
36
+ path: "/tickets",
37
+ requestParams: ticketBaseSchema.omit("id", "createdAt", "updatedAt").partial(),
38
+ responseBody: nu.array(ticketBaseSchema),
39
+ } satisfies RequestSchema;
40
+
41
+ export const getTicketSchema = {
42
+ method: "GET",
43
+ path: "/tickets/:id",
44
+ pathParams: nu.object({ id: nu.number() }),
45
+ responseBody: ticketBaseSchema,
46
+ } satisfies RequestSchema;
47
+
48
+ export const postTicketSchema = {
49
+ method: "POST",
50
+ path: "/tickets",
51
+ requestBody: ticketBaseSchema.omit("id", "createdAt", "updatedAt"),
52
+ responseBody: ticketBaseSchema,
53
+ } satisfies RequestSchema;
54
+
55
+ export const patchTicketSchema = {
56
+ method: "PATCH",
57
+ path: "/tickets/:id",
58
+ pathParams: nu.object({ id: nu.number() }),
59
+ requestBody: ticketBaseSchema.omit("id", "createdAt", "updatedAt").partial(),
60
+ responseBody: ticketBaseSchema,
61
+ } satisfies RequestSchema;
62
+
63
+ export const deleteTicketSchema = {
64
+ method: "DELETE",
65
+ path: "/tickets/:id",
66
+ pathParams: nu.object({ id: nu.number() }),
67
+ responseBody: nu.object({ success: nu.boolean() }),
68
+ } satisfies RequestSchema;
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "declaration": true,
10
+ "noEmit": true
11
+ },
12
+ "include": ["src/**/*"],
13
+ "exclude": ["node_modules"]
14
+ }