create-next-imagicma 0.1.14 → 0.2.0
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/README.md +2 -0
- package/package.json +1 -1
- package/template-hono/.env.example +6 -14
- package/template-hono/.imagicma/AGENTS.md +7 -0
- package/template-hono/AGENTS.md +98 -120
- package/template-hono/README.md +86 -118
- package/template-hono/client/index.html +1 -1
- package/template-hono/client/public/imagicma-picker-bridge.js +2 -6
- package/template-hono/client/public/imagicma-preview-feedback.js +0 -1
- package/template-hono/client/src/components/HelloClient.tsx +1 -1
- package/template-hono/client/src/globals.css +417 -1
- package/template-hono/client/src/lib/imagicma-preview-bridge.ts +1 -1
- package/template-hono/client/src/lib/imagicma-preview-picker.ts +28 -130
- package/template-hono/client/src/providers.tsx +1 -1
- package/template-hono/gitignore +2 -1
- package/template-hono/package.json +9 -9
- package/template-hono/pnpm-lock.yaml +646 -1173
- package/template-hono/server/app.ts +3 -2
- package/template-hono/server/controllers/greeting.controller.ts +22 -0
- package/template-hono/server/db/index.ts +129 -0
- package/template-hono/server/index.ts +3 -3
- package/template-hono/server/middlewares/error-handler.ts +8 -0
- package/template-hono/server/models/entities/message.entity.ts +13 -0
- package/template-hono/server/models/repositories/message.repository.ts +43 -0
- package/template-hono/server/models/services/greeting.service.ts +14 -0
- package/template-hono/server/models/types/message.ts +7 -0
- package/template-hono/server/routes/greeting.ts +1 -1
- package/template-hono/shared/constants/greeting.ts +1 -0
- package/template-hono/shared/contracts/routes.ts +14 -0
- package/template-hono/shared/routes.ts +1 -68
- package/template-hono/shared/schema.ts +5 -8
- package/template-hono/shared/types/greeting.ts +3 -0
- package/template-hono/tailwind.config.mjs +62 -111
- package/template-hono/tsconfig.json +3 -2
- package/template-hono/tsconfig.server.json +2 -0
- package/template-hono/vite.config.ts +4 -4
- package/template-hono/client/src/lib/ai-ui-stream.ts +0 -64
- package/template-hono/client/src/theme/default-theme.css +0 -482
- package/template-hono/drizzle.config.ts +0 -13
- package/template-hono/server/controllers/ai-chat-controller.ts +0 -49
- package/template-hono/server/controllers/greeting-controller.ts +0 -25
- package/template-hono/server/db/client.ts +0 -25
- package/template-hono/server/env.ts +0 -89
- package/template-hono/server/lib/ai-provider.ts +0 -74
- package/template-hono/server/lib/ai.ts +0 -205
- package/template-hono/server/middlewares/auth.ts +0 -69
- package/template-hono/server/middlewares/index.ts +0 -12
- package/template-hono/server/repositories/message-repository.ts +0 -13
- package/template-hono/server/routes/ai-chat.ts +0 -9
- package/template-hono/shared/schema/greeting.ts +0 -17
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
3
|
-
import {
|
|
3
|
+
import { registerErrorHandler } from "./middlewares/error-handler";
|
|
4
4
|
import { greetingRoute } from "./routes/greeting";
|
|
5
5
|
|
|
6
6
|
type CreateAppOptions = {
|
|
@@ -10,6 +10,8 @@ type CreateAppOptions = {
|
|
|
10
10
|
export function createApp({ serveClient = false }: CreateAppOptions = {}) {
|
|
11
11
|
const app = new Hono();
|
|
12
12
|
|
|
13
|
+
registerErrorHandler(app);
|
|
14
|
+
|
|
13
15
|
app.get("/__health", (c) => {
|
|
14
16
|
return c.json({
|
|
15
17
|
status: "ok",
|
|
@@ -20,7 +22,6 @@ export function createApp({ serveClient = false }: CreateAppOptions = {}) {
|
|
|
20
22
|
});
|
|
21
23
|
|
|
22
24
|
app.route("/", greetingRoute);
|
|
23
|
-
app.route("/", aiChatRoute);
|
|
24
25
|
|
|
25
26
|
if (serveClient) {
|
|
26
27
|
const serveClientFiles = serveStatic({ root: "./dist/client" });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import { api } from "../../shared/routes";
|
|
3
|
+
import { greetingService } from "../models/services/greeting.service";
|
|
4
|
+
|
|
5
|
+
export async function getGreeting(c: Context) {
|
|
6
|
+
try {
|
|
7
|
+
const body = {
|
|
8
|
+
message: await greetingService.getGreetingMessage(),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
api.greeting.get.responses[200].parse(body);
|
|
12
|
+
|
|
13
|
+
return c.json(body);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error("GET /api/greeting failed:", error);
|
|
16
|
+
|
|
17
|
+
const message =
|
|
18
|
+
error instanceof Error ? error.message : "Internal Server Error";
|
|
19
|
+
|
|
20
|
+
return c.json({ message }, 500);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { DataSource, type DataSourceOptions } from "typeorm";
|
|
5
|
+
import { MessageEntity } from "../models/entities/message.entity";
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
var __appDataSource: Promise<DataSource> | undefined;
|
|
9
|
+
var __appDataSourceKey: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const DEFAULT_DATABASE_FILE = "./.data/app.db";
|
|
13
|
+
|
|
14
|
+
type DatabaseConfig =
|
|
15
|
+
| {
|
|
16
|
+
type: "sqlite";
|
|
17
|
+
databaseFilePath: string;
|
|
18
|
+
}
|
|
19
|
+
| {
|
|
20
|
+
type: "postgres";
|
|
21
|
+
databaseUrl: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class DatabaseConfigurationError extends Error {
|
|
25
|
+
constructor(message: string) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "DatabaseConfigurationError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveDatabaseConfig(): DatabaseConfig {
|
|
32
|
+
const databaseType = process.env.DB_TYPE?.trim().toLowerCase() || "sqlite";
|
|
33
|
+
|
|
34
|
+
if (databaseType === "sqlite") {
|
|
35
|
+
const configuredPath = process.env.DATABASE_FILE?.trim();
|
|
36
|
+
const databaseFilePath = path.resolve(
|
|
37
|
+
process.cwd(),
|
|
38
|
+
configuredPath && configuredPath.length > 0 ? configuredPath : DEFAULT_DATABASE_FILE,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
fs.mkdirSync(path.dirname(databaseFilePath), { recursive: true });
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
type: "sqlite",
|
|
45
|
+
databaseFilePath,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (databaseType === "postgres") {
|
|
50
|
+
const databaseUrl = process.env.DATABASE_URL?.trim();
|
|
51
|
+
|
|
52
|
+
if (!databaseUrl) {
|
|
53
|
+
throw new DatabaseConfigurationError(
|
|
54
|
+
"DATABASE_URL 未设置:当 DB_TYPE=postgres 时,请在 .env.local 中配置 Postgres 连接串。",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
type: "postgres",
|
|
60
|
+
databaseUrl,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new DatabaseConfigurationError(
|
|
65
|
+
`无效 DB_TYPE=${JSON.stringify(process.env.DB_TYPE)},仅支持 sqlite 或 postgres。`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const databaseConfig = resolveDatabaseConfig();
|
|
70
|
+
const dataSourceKey =
|
|
71
|
+
databaseConfig.type === "sqlite"
|
|
72
|
+
? `sqlite:${databaseConfig.databaseFilePath}`
|
|
73
|
+
: `postgres:${databaseConfig.databaseUrl}`;
|
|
74
|
+
|
|
75
|
+
function createDataSourceOptions(): DataSourceOptions {
|
|
76
|
+
const entities = [MessageEntity];
|
|
77
|
+
const baseOptions = {
|
|
78
|
+
entities,
|
|
79
|
+
synchronize: true,
|
|
80
|
+
logging: false,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (databaseConfig.type === "sqlite") {
|
|
84
|
+
return {
|
|
85
|
+
...baseOptions,
|
|
86
|
+
type: "better-sqlite3",
|
|
87
|
+
database: databaseConfig.databaseFilePath,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
...baseOptions,
|
|
93
|
+
type: "postgres",
|
|
94
|
+
url: databaseConfig.databaseUrl,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function initializeDataSource() {
|
|
99
|
+
const dataSource = new DataSource(createDataSourceOptions());
|
|
100
|
+
return dataSource.initialize();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getDataSource() {
|
|
104
|
+
if (globalThis.__appDataSourceKey !== dataSourceKey) {
|
|
105
|
+
globalThis.__appDataSource = undefined;
|
|
106
|
+
globalThis.__appDataSourceKey = dataSourceKey;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!globalThis.__appDataSource) {
|
|
110
|
+
globalThis.__appDataSource = initializeDataSource().catch((error) => {
|
|
111
|
+
globalThis.__appDataSource = undefined;
|
|
112
|
+
throw error;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return globalThis.__appDataSource;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getDatabaseReadHelpMessage() {
|
|
120
|
+
if (databaseConfig.type === "sqlite") {
|
|
121
|
+
const relativePath =
|
|
122
|
+
path.relative(process.cwd(), databaseConfig.databaseFilePath) ||
|
|
123
|
+
path.basename(databaseConfig.databaseFilePath);
|
|
124
|
+
|
|
125
|
+
return `请确认 SQLite 数据库路径可写(${relativePath})。`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return "请确认已设置 DATABASE_URL,并且 Postgres 服务可连接。";
|
|
129
|
+
}
|
|
@@ -79,10 +79,10 @@ async function readRuntimeEnvPort() {
|
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
async function resolveRuntimePort(raw
|
|
83
|
-
let candidate = raw;
|
|
82
|
+
async function resolveRuntimePort(raw = process.env.PORT) {
|
|
83
|
+
let candidate: string | undefined = raw;
|
|
84
84
|
if (candidate === undefined || candidate === null || candidate === "") {
|
|
85
|
-
candidate = await readRuntimeEnvPort();
|
|
85
|
+
candidate = (await readRuntimeEnvPort()) ?? undefined;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
if (candidate === undefined || candidate === null || candidate === "") {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
|
2
|
+
|
|
3
|
+
@Entity({ name: "messages" })
|
|
4
|
+
export class MessageEntity {
|
|
5
|
+
@PrimaryGeneratedColumn()
|
|
6
|
+
id!: number;
|
|
7
|
+
|
|
8
|
+
@Column({ type: "text" })
|
|
9
|
+
content!: string;
|
|
10
|
+
|
|
11
|
+
@Column({ name: "is_read", type: "boolean", default: false })
|
|
12
|
+
isRead!: boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DatabaseConfigurationError,
|
|
3
|
+
getDataSource,
|
|
4
|
+
getDatabaseReadHelpMessage,
|
|
5
|
+
} from "../../db";
|
|
6
|
+
import { MessageEntity } from "../entities/message.entity";
|
|
7
|
+
import type { Message } from "../types/message";
|
|
8
|
+
|
|
9
|
+
export interface MessageRepository {
|
|
10
|
+
findLatestMessage(): Promise<Message | null>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function toMessage(entity: MessageEntity): Message {
|
|
14
|
+
return {
|
|
15
|
+
id: entity.id,
|
|
16
|
+
content: entity.content,
|
|
17
|
+
isRead: entity.isRead,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class DatabaseMessageRepository implements MessageRepository {
|
|
22
|
+
async findLatestMessage(): Promise<Message | null> {
|
|
23
|
+
try {
|
|
24
|
+
const dataSource = await getDataSource();
|
|
25
|
+
const rows = await dataSource.getRepository(MessageEntity).find({
|
|
26
|
+
order: { id: "DESC" },
|
|
27
|
+
take: 1,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return rows[0] ? toMessage(rows[0]) : null;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error("DatabaseMessageRepository.findLatestMessage() failed:", error);
|
|
33
|
+
|
|
34
|
+
if (error instanceof DatabaseConfigurationError) {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
throw new Error(`数据库读取失败:${getDatabaseReadHelpMessage()}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const messageRepository = new DatabaseMessageRepository();
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { messageRepository, type MessageRepository } from "../repositories/message.repository";
|
|
2
|
+
|
|
3
|
+
const DEFAULT_GREETING_MESSAGE = "Hello from the Backend API!";
|
|
4
|
+
|
|
5
|
+
export class GreetingService {
|
|
6
|
+
constructor(private readonly messageRepository: MessageRepository) {}
|
|
7
|
+
|
|
8
|
+
async getGreetingMessage(): Promise<string> {
|
|
9
|
+
const latestMessage = await this.messageRepository.findLatestMessage();
|
|
10
|
+
return latestMessage?.content ?? DEFAULT_GREETING_MESSAGE;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const greetingService = new GreetingService(messageRepository);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const GREETING_ROUTE_PATH = "/api/greeting";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GREETING_ROUTE_PATH } from "../constants/greeting";
|
|
2
|
+
import { GreetingResponseSchema } from "../schema";
|
|
3
|
+
|
|
4
|
+
export const api = {
|
|
5
|
+
greeting: {
|
|
6
|
+
get: {
|
|
7
|
+
method: "GET",
|
|
8
|
+
path: GREETING_ROUTE_PATH,
|
|
9
|
+
responses: {
|
|
10
|
+
200: GreetingResponseSchema,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
} as const;
|
|
@@ -1,68 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const aiTextPartSchema = z.object({
|
|
4
|
-
type: z.literal("text"),
|
|
5
|
-
text: z.string().min(1),
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
const aiFilePartSchema = z.object({
|
|
9
|
-
type: z.literal("file"),
|
|
10
|
-
filename: z.string().min(1).optional(),
|
|
11
|
-
mediaType: z.string().min(1),
|
|
12
|
-
url: z.string().min(1),
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const aiMessagePartSchema = z.discriminatedUnion("type", [
|
|
16
|
-
aiTextPartSchema,
|
|
17
|
-
aiFilePartSchema,
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
const aiMessageSchema = z.object({
|
|
21
|
-
id: z.string().min(1).optional(),
|
|
22
|
-
role: z.enum(["system", "user", "assistant"]),
|
|
23
|
-
parts: z.array(aiMessagePartSchema).min(1),
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
export const aiChatRequestSchema = z.object({
|
|
27
|
-
messages: z.array(aiMessageSchema).min(1),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
export const aiErrorResponseSchema = z.object({
|
|
31
|
-
error: z.object({
|
|
32
|
-
code: z.string(),
|
|
33
|
-
message: z.string(),
|
|
34
|
-
}),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
export const api = {
|
|
38
|
-
greeting: {
|
|
39
|
-
get: {
|
|
40
|
-
method: "GET",
|
|
41
|
-
path: "/api/greeting",
|
|
42
|
-
responses: {
|
|
43
|
-
200: z.object({ message: z.string() }),
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
ai: {
|
|
48
|
-
chat: {
|
|
49
|
-
post: {
|
|
50
|
-
method: "POST",
|
|
51
|
-
path: "/api/ai/chat",
|
|
52
|
-
request: {
|
|
53
|
-
body: aiChatRequestSchema,
|
|
54
|
-
},
|
|
55
|
-
responses: {
|
|
56
|
-
400: aiErrorResponseSchema,
|
|
57
|
-
500: aiErrorResponseSchema,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type AITextPart = z.infer<typeof aiTextPartSchema>;
|
|
65
|
-
export type AIFilePart = z.infer<typeof aiFilePartSchema>;
|
|
66
|
-
export type AIMessagePart = z.infer<typeof aiMessagePartSchema>;
|
|
67
|
-
export type AIMessage = z.infer<typeof aiMessageSchema>;
|
|
68
|
-
export type AIChatRequest = z.infer<typeof aiChatRequestSchema>;
|
|
1
|
+
export { api } from "./contracts/routes";
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
messages,
|
|
4
|
-
} from "./schema/greeting";
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { GreetingResponse } from "./types/greeting";
|
|
5
3
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "./schema/greeting";
|
|
4
|
+
export const GreetingResponseSchema: z.ZodType<GreetingResponse> = z.object({
|
|
5
|
+
message: z.string(),
|
|
6
|
+
});
|
|
@@ -1,114 +1,5 @@
|
|
|
1
1
|
import animate from "tailwindcss-animate";
|
|
2
2
|
|
|
3
|
-
const withAlpha = (name) => `hsl(var(--${name}) / <alpha-value>)`;
|
|
4
|
-
|
|
5
|
-
const themeBorderRadius = {
|
|
6
|
-
lg: "var(--radius)",
|
|
7
|
-
md: "calc(var(--radius) - 0.125rem)",
|
|
8
|
-
sm: "calc(var(--radius) - 0.25rem)",
|
|
9
|
-
full: "var(--radius-full-token)",
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const themeColors = {
|
|
13
|
-
background: withAlpha("background"),
|
|
14
|
-
foreground: withAlpha("foreground"),
|
|
15
|
-
border: withAlpha("border"),
|
|
16
|
-
input: withAlpha("input"),
|
|
17
|
-
ring: withAlpha("ring"),
|
|
18
|
-
|
|
19
|
-
card: withAlpha("card"),
|
|
20
|
-
"card-foreground": withAlpha("card-foreground"),
|
|
21
|
-
"card-border": withAlpha("card-border"),
|
|
22
|
-
|
|
23
|
-
popover: withAlpha("popover"),
|
|
24
|
-
"popover-foreground": withAlpha("popover-foreground"),
|
|
25
|
-
"popover-border": withAlpha("popover-border"),
|
|
26
|
-
|
|
27
|
-
primary: withAlpha("primary"),
|
|
28
|
-
"primary-foreground": withAlpha("primary-foreground"),
|
|
29
|
-
"primary-border": "var(--primary-border)",
|
|
30
|
-
|
|
31
|
-
secondary: withAlpha("secondary"),
|
|
32
|
-
"secondary-foreground": withAlpha("secondary-foreground"),
|
|
33
|
-
"secondary-border": "var(--secondary-border)",
|
|
34
|
-
|
|
35
|
-
muted: withAlpha("muted"),
|
|
36
|
-
"muted-foreground": withAlpha("muted-foreground"),
|
|
37
|
-
"muted-border": "var(--muted-border)",
|
|
38
|
-
|
|
39
|
-
accent: withAlpha("accent"),
|
|
40
|
-
"accent-foreground": withAlpha("accent-foreground"),
|
|
41
|
-
"accent-border": "var(--accent-border)",
|
|
42
|
-
|
|
43
|
-
destructive: withAlpha("destructive"),
|
|
44
|
-
"destructive-foreground": withAlpha("destructive-foreground"),
|
|
45
|
-
"destructive-border": "var(--destructive-border)",
|
|
46
|
-
|
|
47
|
-
sidebar: withAlpha("sidebar"),
|
|
48
|
-
"sidebar-foreground": withAlpha("sidebar-foreground"),
|
|
49
|
-
"sidebar-border": withAlpha("sidebar-border"),
|
|
50
|
-
"sidebar-ring": withAlpha("sidebar-ring"),
|
|
51
|
-
"sidebar-accent": withAlpha("sidebar-accent"),
|
|
52
|
-
"sidebar-accent-foreground": withAlpha("sidebar-accent-foreground"),
|
|
53
|
-
|
|
54
|
-
"chart-1": withAlpha("chart-1"),
|
|
55
|
-
"chart-2": withAlpha("chart-2"),
|
|
56
|
-
"chart-3": withAlpha("chart-3"),
|
|
57
|
-
"chart-4": withAlpha("chart-4"),
|
|
58
|
-
"chart-5": withAlpha("chart-5"),
|
|
59
|
-
|
|
60
|
-
"background-base": withAlpha("background-base"),
|
|
61
|
-
"on-background": withAlpha("on-background"),
|
|
62
|
-
surface: withAlpha("surface"),
|
|
63
|
-
"surface-bright": withAlpha("surface-bright"),
|
|
64
|
-
"surface-dim": withAlpha("surface-dim"),
|
|
65
|
-
"surface-container-lowest": withAlpha("surface-container-lowest"),
|
|
66
|
-
"surface-container-low": withAlpha("surface-container-low"),
|
|
67
|
-
"surface-container": withAlpha("surface-container"),
|
|
68
|
-
"surface-container-high": withAlpha("surface-container-high"),
|
|
69
|
-
"surface-container-highest": withAlpha("surface-container-highest"),
|
|
70
|
-
"surface-variant": withAlpha("surface-variant"),
|
|
71
|
-
"surface-tint": withAlpha("surface-tint"),
|
|
72
|
-
"on-surface": withAlpha("on-surface"),
|
|
73
|
-
"on-surface-variant": withAlpha("on-surface-variant"),
|
|
74
|
-
|
|
75
|
-
"primary-container": withAlpha("primary-container"),
|
|
76
|
-
"on-primary": withAlpha("on-primary"),
|
|
77
|
-
"on-primary-container": withAlpha("on-primary-container"),
|
|
78
|
-
"primary-fixed": withAlpha("primary-fixed"),
|
|
79
|
-
"primary-fixed-dim": withAlpha("primary-fixed-dim"),
|
|
80
|
-
"on-primary-fixed": withAlpha("on-primary-fixed"),
|
|
81
|
-
"on-primary-fixed-variant": withAlpha("on-primary-fixed-variant"),
|
|
82
|
-
"inverse-primary": withAlpha("inverse-primary"),
|
|
83
|
-
|
|
84
|
-
"secondary-container": withAlpha("secondary-container"),
|
|
85
|
-
"on-secondary": withAlpha("on-secondary"),
|
|
86
|
-
"on-secondary-container": withAlpha("on-secondary-container"),
|
|
87
|
-
"secondary-fixed": withAlpha("secondary-fixed"),
|
|
88
|
-
"secondary-fixed-dim": withAlpha("secondary-fixed-dim"),
|
|
89
|
-
"on-secondary-fixed": withAlpha("on-secondary-fixed"),
|
|
90
|
-
"on-secondary-fixed-variant": withAlpha("on-secondary-fixed-variant"),
|
|
91
|
-
|
|
92
|
-
tertiary: withAlpha("tertiary"),
|
|
93
|
-
"tertiary-container": withAlpha("tertiary-container"),
|
|
94
|
-
"on-tertiary": withAlpha("on-tertiary"),
|
|
95
|
-
"on-tertiary-container": withAlpha("on-tertiary-container"),
|
|
96
|
-
"tertiary-fixed": withAlpha("tertiary-fixed"),
|
|
97
|
-
"tertiary-fixed-dim": withAlpha("tertiary-fixed-dim"),
|
|
98
|
-
"on-tertiary-fixed": withAlpha("on-tertiary-fixed"),
|
|
99
|
-
"on-tertiary-fixed-variant": withAlpha("on-tertiary-fixed-variant"),
|
|
100
|
-
|
|
101
|
-
error: withAlpha("error"),
|
|
102
|
-
"on-error": withAlpha("on-error"),
|
|
103
|
-
"error-container": withAlpha("error-container"),
|
|
104
|
-
"on-error-container": withAlpha("on-error-container"),
|
|
105
|
-
|
|
106
|
-
outline: withAlpha("outline"),
|
|
107
|
-
"outline-variant": withAlpha("outline-variant"),
|
|
108
|
-
"inverse-surface": withAlpha("inverse-surface"),
|
|
109
|
-
"inverse-on-surface": withAlpha("inverse-on-surface"),
|
|
110
|
-
};
|
|
111
|
-
|
|
112
3
|
/** @type {import("tailwindcss").Config} */
|
|
113
4
|
const config = {
|
|
114
5
|
darkMode: ["class"],
|
|
@@ -119,8 +10,68 @@ const config = {
|
|
|
119
10
|
],
|
|
120
11
|
theme: {
|
|
121
12
|
extend: {
|
|
122
|
-
borderRadius:
|
|
123
|
-
|
|
13
|
+
borderRadius: {
|
|
14
|
+
lg: "var(--radius)",
|
|
15
|
+
md: "calc(var(--radius) - 2px)",
|
|
16
|
+
sm: "calc(var(--radius) - 4px)",
|
|
17
|
+
},
|
|
18
|
+
colors: {
|
|
19
|
+
background: "hsl(var(--background) / <alpha-value>)",
|
|
20
|
+
foreground: "hsl(var(--foreground) / <alpha-value>)",
|
|
21
|
+
border: "hsl(var(--border) / <alpha-value>)",
|
|
22
|
+
input: "hsl(var(--input) / <alpha-value>)",
|
|
23
|
+
ring: "hsl(var(--ring) / <alpha-value>)",
|
|
24
|
+
card: {
|
|
25
|
+
DEFAULT: "hsl(var(--card) / <alpha-value>)",
|
|
26
|
+
foreground: "hsl(var(--card-foreground) / <alpha-value>)",
|
|
27
|
+
border: "hsl(var(--card-border) / <alpha-value>)",
|
|
28
|
+
},
|
|
29
|
+
popover: {
|
|
30
|
+
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
|
|
31
|
+
foreground: "hsl(var(--popover-foreground) / <alpha-value>)",
|
|
32
|
+
border: "hsl(var(--popover-border) / <alpha-value>)",
|
|
33
|
+
},
|
|
34
|
+
primary: {
|
|
35
|
+
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
|
|
36
|
+
foreground: "hsl(var(--primary-foreground) / <alpha-value>)",
|
|
37
|
+
border: "var(--primary-border)",
|
|
38
|
+
},
|
|
39
|
+
secondary: {
|
|
40
|
+
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
|
|
41
|
+
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)",
|
|
42
|
+
border: "var(--secondary-border)",
|
|
43
|
+
},
|
|
44
|
+
muted: {
|
|
45
|
+
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
|
|
46
|
+
foreground: "hsl(var(--muted-foreground) / <alpha-value>)",
|
|
47
|
+
border: "var(--muted-border)",
|
|
48
|
+
},
|
|
49
|
+
accent: {
|
|
50
|
+
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
|
|
51
|
+
foreground: "hsl(var(--accent-foreground) / <alpha-value>)",
|
|
52
|
+
border: "var(--accent-border)",
|
|
53
|
+
},
|
|
54
|
+
destructive: {
|
|
55
|
+
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
|
|
56
|
+
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)",
|
|
57
|
+
border: "var(--destructive-border)",
|
|
58
|
+
},
|
|
59
|
+
chart: {
|
|
60
|
+
"1": "hsl(var(--chart-1) / <alpha-value>)",
|
|
61
|
+
"2": "hsl(var(--chart-2) / <alpha-value>)",
|
|
62
|
+
"3": "hsl(var(--chart-3) / <alpha-value>)",
|
|
63
|
+
"4": "hsl(var(--chart-4) / <alpha-value>)",
|
|
64
|
+
"5": "hsl(var(--chart-5) / <alpha-value>)",
|
|
65
|
+
},
|
|
66
|
+
sidebar: {
|
|
67
|
+
DEFAULT: "hsl(var(--sidebar) / <alpha-value>)",
|
|
68
|
+
foreground: "hsl(var(--sidebar-foreground) / <alpha-value>)",
|
|
69
|
+
border: "hsl(var(--sidebar-border) / <alpha-value>)",
|
|
70
|
+
ring: "hsl(var(--sidebar-ring) / <alpha-value>)",
|
|
71
|
+
accent: "hsl(var(--accent) / <alpha-value>)",
|
|
72
|
+
"accent-foreground": "hsl(var(--accent-foreground) / <alpha-value>)",
|
|
73
|
+
},
|
|
74
|
+
},
|
|
124
75
|
keyframes: {
|
|
125
76
|
"accordion-down": {
|
|
126
77
|
from: { height: "0" },
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
"strict": true,
|
|
8
8
|
"noEmit": true,
|
|
9
9
|
"esModuleInterop": true,
|
|
10
|
+
"experimentalDecorators": true,
|
|
11
|
+
"emitDecoratorMetadata": true,
|
|
10
12
|
"module": "esnext",
|
|
11
13
|
"moduleResolution": "bundler",
|
|
12
14
|
"resolveJsonModule": true,
|
|
@@ -26,8 +28,7 @@
|
|
|
26
28
|
"shared/**/*.tsx",
|
|
27
29
|
"server/**/*.ts",
|
|
28
30
|
"types/**/*.d.ts",
|
|
29
|
-
"vite.config.ts"
|
|
30
|
-
"drizzle.config.ts"
|
|
31
|
+
"vite.config.ts"
|
|
31
32
|
],
|
|
32
33
|
"exclude": ["node_modules", "dist"]
|
|
33
34
|
}
|
|
@@ -50,10 +50,10 @@ async function readRuntimeEnvPort() {
|
|
|
50
50
|
return null;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
async function resolveRuntimePort(raw
|
|
54
|
-
let candidate = raw;
|
|
53
|
+
async function resolveRuntimePort(raw = process.env.PORT) {
|
|
54
|
+
let candidate: string | undefined = raw;
|
|
55
55
|
if (candidate === undefined || candidate === null || candidate === "") {
|
|
56
|
-
candidate = await readRuntimeEnvPort();
|
|
56
|
+
candidate = (await readRuntimeEnvPort()) ?? undefined;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
if (candidate === undefined || candidate === null || candidate === "") {
|
|
@@ -126,7 +126,7 @@ export default defineConfig(async ({ command }) => {
|
|
|
126
126
|
: {
|
|
127
127
|
host: "0.0.0.0",
|
|
128
128
|
port: runtimePort,
|
|
129
|
-
allowedHosts: ["localhost", "127.0.0.1", ".preview.imagicma.cn", ".preview.agentma.cn", ".preview.agentma.com"
|
|
129
|
+
allowedHosts: ["localhost", "127.0.0.1", ".preview.imagicma.cn", ".preview.agentma.cn", ".preview.agentma.com"],
|
|
130
130
|
strictPort: true,
|
|
131
131
|
hmr: { overlay: false },
|
|
132
132
|
},
|