feat: 将数据库模块迁移至 worker 服务,并实现 D1 数据库自动迁移
This commit is contained in:
1 parent
a35a6bd390
commit
62aefb1f9a
33 files changed
+78
-1598
No files matched your search
@@ -76,6 +76,14 @@ jobs:
|
||||
COOKIES_SECRET: ${{ secrets.COOKIES_SECRET }}
|
||||
TURNSTILE_KEY: ${{ secrets.TURNSTILE_KEY }}
|
||||
TURNSTILE_SECRET: ${{ secrets.TURNSTILE_SECRET }}
|
||||
|
||||
# 新增:在部署前应用 D1 数据库迁移
|
||||
# 这一步会明确地告诉 Wrangler 远程执行 D1 数据库的迁移脚本。
|
||||
- name: Apply D1 Migrations
|
||||
run: npx wrangler d1 migrations apply ${{ secrets.D1_DATABASE_NAME }} --remote
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
|
||||
# 部署到 Cloudflare Workers
|
||||
- name: Deploy
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
"@tanstack/react-query": "^5.17.10",
|
||||
"axios": "^1.6.7",
|
||||
"clsx": "^2.1.0",
|
||||
"database": "workspace:*",
|
||||
"date-fns": "^3.2.0",
|
||||
"framer-motion": "^11.0.24",
|
||||
"i18next": "^23.10.1",
|
||||
"i18next-browser-languagedetector": "^7.2.0",
|
||||
"i18next-http-backend": "^2.5.0",
|
||||
"icons": "workspace:*",
|
||||
"js-cookie": "^3.0.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useTranslation } from 'react-i18next';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { zhCN } from 'date-fns/locale';
|
||||
import clsx from 'clsx';
|
||||
import type { Email } from 'database';
|
||||
// refactor: 将导入从 'database' 包更改为本地的类型定义文件
|
||||
import type { Email } from '../database_types';
|
||||
|
||||
// 图标导入
|
||||
import MailIcon from './icons/MailIcon.tsx';
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// feat: 创建此文件以存放从后端共享的数据库类型定义
|
||||
// 从原 packages/database/schema.ts 迁移过来的类型定义
|
||||
|
||||
// 定义 Header 类型,用于存储邮件头信息
|
||||
export type Header = Record<string, string>;
|
||||
|
||||
// 定义 Address 类型,用于存储发件人、收件人等地址信息
|
||||
export type Address = {
|
||||
address: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
// 定义 Email 类型,这是邮件对象的主要结构
|
||||
export type Email = {
|
||||
id: string;
|
||||
messageFrom: string;
|
||||
messageTo: string;
|
||||
headers: Header[];
|
||||
from: Address;
|
||||
sender: Address | null;
|
||||
replyTo: Address[] | null;
|
||||
deliveredTo: string | null;
|
||||
returnPath: string | null;
|
||||
to: Address[] | null;
|
||||
cc: Address[] | null;
|
||||
bcc: Address[] | null;
|
||||
subject: string | null;
|
||||
messageId: string;
|
||||
inReplyTo: string | null;
|
||||
references: string | null;
|
||||
date: string | null;
|
||||
html: string | null;
|
||||
text: string | null;
|
||||
createdAt: Date; // 注意:这里是Date类型,但在API传输时通常是字符串,使用时请注意转换
|
||||
updatedAt: Date; // 注意:同上
|
||||
};
|
||||
@@ -23,8 +23,8 @@ import Cloudflare from "../components/icons/Cloudflare.tsx";
|
||||
import Clock from "../components/icons/Clock.tsx";
|
||||
import Info from "../components/icons/Info.tsx";
|
||||
|
||||
// 假设 Email 类型定义在 'database' 包中
|
||||
import type { Email } from 'database';
|
||||
// refactor: 将导入从 'database' 包更改为本地的类型定义文件
|
||||
import type { Email } from '../database_types.ts';
|
||||
|
||||
export function Home() {
|
||||
const config = useConfig();
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// 导入 Email 类型,'database' 是您 monorepo 中的包名
|
||||
import type { Email } from 'database';
|
||||
// refactor: 将导入从 'database' 包更改为本地的类型定义文件
|
||||
import type { Email } from '../database_types';
|
||||
|
||||
const API_BASE_URL = '/api';
|
||||
|
||||
// 定义 Turnstile 人机验证所需的 token
|
||||
// 恢复此接口定义,以备将来使用
|
||||
interface ApiPayload {
|
||||
token: string;
|
||||
[key: string]: any;
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { Config } from "drizzle-kit";
|
||||
export default {
|
||||
schema: "./schema.ts",
|
||||
out: "./drizzle",
|
||||
} satisfies Config;
|
||||
@@ -1,82 +0,0 @@
|
||||
import { createClient as createWebClient } from "@libsql/client/web";
|
||||
import * as orm from "drizzle-orm";
|
||||
import { LibSQLDatabase, drizzle } from "drizzle-orm/libsql";
|
||||
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import * as z from "zod";
|
||||
|
||||
function getWebTursoDBFromEnv(): LibSQLDatabase {
|
||||
const client = createWebClient({
|
||||
url: process.env.TURSO_DB_URL || "",
|
||||
authToken: process.env.TURSO_DB_AUTH_TOKEN || "",
|
||||
});
|
||||
return drizzle(client);
|
||||
}
|
||||
|
||||
function getWebTursoDB(url: string, authToken: string): LibSQLDatabase {
|
||||
return drizzle(createWebClient({ url, authToken }));
|
||||
}
|
||||
|
||||
type Header = Record<string, string>;
|
||||
|
||||
type Address = {
|
||||
address: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type Email = typeof emails.$inferSelect;
|
||||
|
||||
const emails = sqliteTable("emails", {
|
||||
id: text("id").primaryKey(),
|
||||
messageFrom: text("message_from").notNull(),
|
||||
messageTo: text("message_to").notNull(),
|
||||
headers: text("headers", { mode: "json" }).$type<Header[]>().notNull(),
|
||||
from: text("from", { mode: "json" }).$type<Address>().notNull(),
|
||||
sender: text("sender", { mode: "json" }).$type<Address>(),
|
||||
replyTo: text("reply_to", { mode: "json" }).$type<Address[]>(),
|
||||
deliveredTo: text("delivered_to"),
|
||||
returnPath: text("return_path"),
|
||||
to: text("to", { mode: "json" }).$type<Address[]>(),
|
||||
cc: text("cc", { mode: "json" }).$type<Address[]>(),
|
||||
bcc: text("bcc", { mode: "json" }).$type<Address[]>(),
|
||||
subject: text("subject"),
|
||||
messageId: text("message_id").notNull(),
|
||||
inReplyTo: text("in_reply_to"),
|
||||
references: text("references"),
|
||||
date: text("date"),
|
||||
html: text("html"),
|
||||
text: text("text"),
|
||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
||||
});
|
||||
|
||||
const AddressSchema = z.object({
|
||||
address: z.string(),
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
const insertEmailSchema = createInsertSchema(emails, {
|
||||
headers: z.array(z.record(z.string())),
|
||||
from: AddressSchema,
|
||||
sender: AddressSchema.optional(),
|
||||
replyTo: z.array(AddressSchema).optional(),
|
||||
to: z.array(AddressSchema).optional(),
|
||||
cc: z.array(AddressSchema).optional(),
|
||||
bcc: z.array(AddressSchema).optional(),
|
||||
});
|
||||
|
||||
type InsertEmail = z.infer<typeof insertEmailSchema>;
|
||||
|
||||
export {
|
||||
Address,
|
||||
AddressSchema,
|
||||
Email,
|
||||
Header,
|
||||
InsertEmail,
|
||||
emails,
|
||||
getWebTursoDB,
|
||||
getWebTursoDBFromEnv,
|
||||
insertEmailSchema,
|
||||
orm,
|
||||
z,
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
import * as orm from "drizzle-orm";
|
||||
|
||||
export default orm;
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "database",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"sqlite": "drizzle-kit generate:sqlite"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@libsql/client": "0.4.0-pre.7",
|
||||
"drizzle-orm": "^0.29.3",
|
||||
"drizzle-zod": "^0.5.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"drizzle-kit": "^0.20.12",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import ArrowUturnLeft from "./svg/ArrowUturnLeft";
|
||||
import CheckIcon from "./svg/CheckIcon";
|
||||
import CopyIcon from "./svg/CopyIcon";
|
||||
import ExclamationCircle from "./svg/ExclamationCircle";
|
||||
import GithubIcon from "./svg/GithubIcon";
|
||||
import InboxIcon from "./svg/InboxIcon";
|
||||
import MailIcon from "./svg/MailIcon";
|
||||
import RefreshIcon from "./svg/RefreshIcon";
|
||||
import ReloadIcon from "./svg/ReloadIcon";
|
||||
import UserCircleIcon from "./svg/UserCircleIcon";
|
||||
|
||||
export {
|
||||
ArrowUturnLeft,
|
||||
CheckIcon,
|
||||
CopyIcon,
|
||||
ExclamationCircle,
|
||||
GithubIcon,
|
||||
InboxIcon,
|
||||
MailIcon,
|
||||
RefreshIcon,
|
||||
ReloadIcon,
|
||||
UserCircleIcon,
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "icons",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.47",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function ArrowUturnLeft(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function CheckIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M5 12l5 5l10 -10" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function CopyIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M7 7m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z" />
|
||||
<path d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function ExclamationCircle(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
|
||||
<path d="M12 9v4" />
|
||||
<path d="M12 16v.01" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function GithubIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function InboxIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path d="M2.25 13.5h3.86a2.25 2.25 0 0 1 2.012 1.244l.256.512a2.25 2.25 0 0 0 2.013 1.244h3.218a2.25 2.25 0 0 0 2.013-1.244l.256-.512a2.25 2.25 0 0 1 2.013-1.244h3.859m-19.5.338V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 0 0-2.15-1.588H6.911a2.25 2.25 0 0 0-2.15 1.588L2.35 13.177a2.25 2.25 0 0 0-.1.661Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function MailIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function RefreshIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}>
|
||||
<path d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function ReloadIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M19.933 13.041a8 8 0 1 1 -9.925 -8.788c3.899 -1 7.935 1.007 9.425 4.747" />
|
||||
<path d="M20 4v5h-5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export default function UserCircleIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<path d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true,
|
||||
/* Skip type checking all .d.ts files. */
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
||||
Generated
-998
File diff suppressed because it is too large.
Load diff
+1
-2
@@ -1,4 +1,3 @@
|
||||
packages:
|
||||
- "worker"
|
||||
- "frontend"
|
||||
- "packages/*"
|
||||
- "frontend"
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { Config } from "drizzle-kit";
|
||||
|
||||
export default {
|
||||
// 指向新的 schema 文件位置
|
||||
schema: "./src/database/schema.ts",
|
||||
// 指定迁移文件的输出目录
|
||||
out: "./drizzle",
|
||||
} satisfies Config;
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
CREATE TABLE `emails` (
|
||||
-- fix: 添加 IF NOT EXISTS 以确保表创建的幂等性,防止重复执行时出错
|
||||
CREATE TABLE IF NOT EXISTS `emails` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`message_from` text NOT NULL,
|
||||
`message_to` text NOT NULL,
|
||||
@@ -20,4 +21,4 @@ CREATE TABLE `emails` (
|
||||
`text` text,
|
||||
`created_at` integer NOT NULL,
|
||||
`updated_at` integer NOT NULL
|
||||
);
|
||||
);
|
||||
@@ -1,6 +1,7 @@
|
||||
import { count, desc, eq, and, inArray, lt } from "drizzle-orm";
|
||||
// fix: 将数据库类型从 LibSQLDatabase 更改为 DrizzleD1Database,以匹配 Cloudflare D1
|
||||
import { DrizzleD1Database } from "drizzle-orm/d1";
|
||||
// refactor: 更新 schema 的导入路径
|
||||
import { emails, InsertEmail } from "./schema";
|
||||
|
||||
export async function insertEmail(db: DrizzleD1Database, email: InsertEmail) {
|
||||
File renamed without changes.
@@ -2,15 +2,19 @@ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import * as z from "zod";
|
||||
|
||||
// 定义 Header 类型,用于存储邮件头信息
|
||||
export type Header = Record<string, string>;
|
||||
|
||||
// 定义 Address 类型,用于存储发件人、收件人等地址信息
|
||||
export type Address = {
|
||||
address: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
// 定义 Email 类型,通过 drizzle-orm 从数据库表结构推断得出
|
||||
export type Email = typeof emails.$inferSelect;
|
||||
|
||||
// 使用 drizzle-orm 定义 emails 表的结构
|
||||
export const emails = sqliteTable("emails", {
|
||||
id: text("id").primaryKey(),
|
||||
messageFrom: text("message_from").notNull(),
|
||||
@@ -35,11 +39,13 @@ export const emails = sqliteTable("emails", {
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
|
||||
});
|
||||
|
||||
// 使用 Zod 定义 Address 对象的验证 schema
|
||||
const AddressSchema = z.object({
|
||||
address: z.string(),
|
||||
name: z.string(),
|
||||
});
|
||||
|
||||
// 使用 drizzle-zod 基于 emails 表结构创建用于插入操作的 Zod schema
|
||||
export const insertEmailSchema = createInsertSchema(emails, {
|
||||
headers: z.array(z.record(z.string())),
|
||||
from: AddressSchema,
|
||||
@@ -50,4 +56,5 @@ export const insertEmailSchema = createInsertSchema(emails, {
|
||||
bcc: z.array(AddressSchema).optional(),
|
||||
});
|
||||
|
||||
export type InsertEmail = z.infer<typeof insertEmailSchema>;
|
||||
// 定义 InsertEmail 类型,从 Zod schema 推断
|
||||
export type InsertEmail = z.infer<typeof insertEmailSchema>;
|
||||
+5
-8
@@ -1,13 +1,10 @@
|
||||
import { Hono } from 'hono';
|
||||
import { serveStatic } from 'hono/cloudflare-workers';
|
||||
import { cors } from 'hono/cors';
|
||||
// 路径修正:使用相对路径并导入正确的函数
|
||||
// feat: 导入 getEmailByPassword 函数
|
||||
import { deleteEmails, findEmailById, getEmailByPassword, getEmailsByMessageTo, insertEmail, deleteExpiredEmails } from '../../packages/database/dao';
|
||||
// fix: 修正数据库导入路径
|
||||
import { getD1DB } from '../../packages/database/db';
|
||||
import { InsertEmail, insertEmailSchema } from '../../packages/database/schema';
|
||||
// fix: 修复 nanoid 导入路径问题,解决部署报错
|
||||
// 导入数据库相关的模块
|
||||
import { deleteEmails, findEmailById, getEmailByPassword, getEmailsByMessageTo, insertEmail, deleteExpiredEmails } from './database/dao';
|
||||
import { getD1DB } from './database/db';
|
||||
import { InsertEmail, insertEmailSchema } from './database/schema';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import PostalMime from 'postal-mime';
|
||||
|
||||
@@ -233,4 +230,4 @@ export default {
|
||||
const oneHourAgo = new Date(Date.now() - 1000 * 60 * 60);
|
||||
await deleteExpiredEmails(db, oneHourAgo);
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -12,6 +12,8 @@ keep_vars = true
|
||||
binding = "DB"
|
||||
database_name = "${D1_DATABASE_NAME}"
|
||||
database_id = "${D1_DATABASE_ID}"
|
||||
# fix: 将迁移目录直接配置在这里,这是 D1 自动迁移的标准做法
|
||||
migrations_dir = "worker/drizzle"
|
||||
|
||||
# 定义环境变量和密钥
|
||||
[vars]
|
||||
|
||||
Reference in new issue
Block a user