chore: import existing Endoleap Pages Router project
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
export type Profile = {
|
||||
id: string;
|
||||
username: string;
|
||||
display_name: string | null;
|
||||
email: string | null;
|
||||
};
|
||||
export async function api<T>(
|
||||
path: string,
|
||||
options: RequestInit = {},
|
||||
): Promise<T> {
|
||||
const res = await fetch("/api/foundry/" + path, {
|
||||
...options,
|
||||
headers: { "Content-Type": "application/json", ...options.headers },
|
||||
});
|
||||
const body = await res.json().catch(() => null);
|
||||
if (!res.ok)
|
||||
throw new Error(body?.error?.code || body?.error || "request_failed");
|
||||
return body as T;
|
||||
}
|
||||
export const PROJECT = process.env.NEXT_PUBLIC_FOUNDRY_PROJECT || "endoleap";
|
||||
export async function startOAuth(provider: "google" | "slack") {
|
||||
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
||||
const verifier = btoa(String.fromCharCode(...bytes))
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=/g, "");
|
||||
const digest = await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
new TextEncoder().encode(verifier),
|
||||
);
|
||||
const challenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=/g, "");
|
||||
sessionStorage.setItem("foundry_verifier", verifier);
|
||||
window.location.assign("/api/oauth/" + provider + "?challenge=" + challenge);
|
||||
}
|
||||
export const errorText = (error: unknown) => {
|
||||
const code = error instanceof Error ? error.message : "";
|
||||
const messages: Record<string, string> = {
|
||||
invalid_credentials: "邮箱或密码不正确,或邮箱尚未验证。",
|
||||
rate_limited: "请求太频繁,请稍后再试。",
|
||||
invalid_session: "登录已过期,请重新登录。",
|
||||
workspace_not_loaded: "空间列表尚未加载成功,请刷新页面后重试。",
|
||||
workspace_required: "请先创建或选择一个工作空间。",
|
||||
invalid_workspace: "工作空间名称不符合要求,请修改后重试。",
|
||||
invalid_material: "画布名称或内容不符合要求,请修改后重试。",
|
||||
invalid_reference: "工作空间不存在或当前账户无权访问,请刷新空间列表。",
|
||||
upstream_timeout: "连接服务超时,请稍后再试。",
|
||||
upstream_unavailable: "暂时无法连接服务,请稍后重试。",
|
||||
not_found: "接口暂未上线,请稍后重试。",
|
||||
invalid_verification: "验证链接无效或已过期,请重新注册以获取邮件。",
|
||||
slack_not_configured: "Slack 登录尚未配置完成。",
|
||||
};
|
||||
return messages[code] || "操作未完成,请稍后重试。";
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { Profile } from "./api";
|
||||
|
||||
export type Workspace = { id: string; name: string };
|
||||
type Request = <T>(path: string, options?: RequestInit) => Promise<T>;
|
||||
|
||||
export async function loadWorkspaceHome(
|
||||
request: Request,
|
||||
signal?: AbortSignal,
|
||||
) {
|
||||
const [profile, result] = await Promise.all([
|
||||
request<Profile>("profile", { signal }),
|
||||
request<Workspace[] | { items: Workspace[] }>("workspaces", { signal }),
|
||||
]);
|
||||
return {
|
||||
profile,
|
||||
workspaces: Array.isArray(result) ? result : result.items || [],
|
||||
};
|
||||
}
|
||||
|
||||
export async function createBoard(
|
||||
request: Request,
|
||||
title: string,
|
||||
workspaceId: string,
|
||||
onWorkspaceCreated: (workspace: Workspace) => void,
|
||||
) {
|
||||
let id = workspaceId;
|
||||
if (!id) {
|
||||
const workspace = await request<Workspace>("workspaces", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name: "个人空间" }),
|
||||
});
|
||||
id = workspace.id;
|
||||
onWorkspaceCreated(workspace);
|
||||
}
|
||||
return request<{ id: string }>("workspaces/" + id + "/materials", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
kind: "board",
|
||||
title: title.trim(),
|
||||
content: { schema_version: 1 },
|
||||
}),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user