@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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +148 -0
- package/package.json +55 -0
- package/templates/backend/.env.development.template +4 -0
- package/templates/backend/.env.test.template +4 -0
- package/templates/backend/db/schema.sql +95 -0
- package/templates/backend/docker/dev/docker-compose.yml +21 -0
- package/templates/backend/docker/dev/postgresql-init/dump.sql +95 -0
- package/templates/backend/docker/test/docker-compose.yml +21 -0
- package/templates/backend/docker/test/postgresql-init/dump.sql +95 -0
- package/templates/backend/drizzle.config.ts +10 -0
- package/templates/backend/package.json +47 -0
- package/templates/backend/src/api/routes/auth.ts +209 -0
- package/templates/backend/src/api/routes/index.ts +2 -0
- package/templates/backend/src/api/routes/ticket.ts +62 -0
- package/templates/backend/src/auth/index.ts +37 -0
- package/templates/backend/src/db/helpers/drizzle.ts +34 -0
- package/templates/backend/src/db/schema/index.ts +4 -0
- package/templates/backend/src/db/schema/ticket.ts +13 -0
- package/templates/backend/src/db/schema/user-workspace.ts +17 -0
- package/templates/backend/src/db/schema/user.ts +10 -0
- package/templates/backend/src/db/schema/workspace.ts +9 -0
- package/templates/backend/src/db/seed.ts +71 -0
- package/templates/backend/src/helpers/env.ts +10 -0
- package/templates/backend/src/index.ts +55 -0
- package/templates/backend/src/middleware/workspace-middleware.ts +11 -0
- package/templates/backend/tsconfig.json +15 -0
- package/templates/backend/vitest.config.ts +8 -0
- package/templates/frontend/.env.development.template +1 -0
- package/templates/frontend/index.html +13 -0
- package/templates/frontend/package.json +30 -0
- package/templates/frontend/postcss.config.js +5 -0
- package/templates/frontend/src/auth/__PROJECT_NAME_PASCAL__AuthController.ts +59 -0
- package/templates/frontend/src/config.tsx +76 -0
- package/templates/frontend/src/main.tsx +6 -0
- package/templates/frontend/src/resources/ticket.ts +32 -0
- package/templates/frontend/src/styles/theme.css +3 -0
- package/templates/frontend/src/vite-env.d.ts +9 -0
- package/templates/frontend/tsconfig.json +17 -0
- package/templates/frontend/vite.config.ts +14 -0
- package/templates/root/README.md +94 -0
- package/templates/root/biome.json.template +40 -0
- package/templates/root/package.json +30 -0
- package/templates/root/turbo.json +18 -0
- package/templates/schema/package.json +28 -0
- package/templates/schema/src/api-endpoints.ts +34 -0
- package/templates/schema/src/index.ts +3 -0
- package/templates/schema/src/schema/auth.ts +89 -0
- package/templates/schema/src/schema/ticket.ts +68 -0
- 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,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,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,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
|
+
}
|