105 lines
3.6 KiB
Markdown
105 lines
3.6 KiB
Markdown
|
|
# KOC LOOP
|
||
|
|
|
||
|
|
KOC 内容分发与数据回收闭环,运行于 vinext、Cloudflare D1 和 R2。
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- Node.js `>=22.13.0`
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npm install
|
||
|
|
npm run dev
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
复制 `.dev.vars.example` 为 `.dev.vars` 并配置运行时变量。飞书动态导入需要:
|
||
|
|
|
||
|
|
- `FEISHU_APP_ID`
|
||
|
|
- `FEISHU_APP_SECRET`
|
||
|
|
|
||
|
|
飞书自建应用需开通电子表格读取、知识库节点读取和云文档素材下载权限,
|
||
|
|
并将应用添加到目标知识库或电子表格的文档应用中。
|
||
|
|
|
||
|
|
This starter does not use `wrangler.jsonc`.
|
||
|
|
|
||
|
|
## Included Shape
|
||
|
|
|
||
|
|
- edit site code under `app/`
|
||
|
|
- `.openai/hosting.json` declares optional Sites D1 and R2 bindings
|
||
|
|
- `vite.config.ts` simulates declared bindings for local development
|
||
|
|
- `db/schema.ts` starts intentionally empty
|
||
|
|
- `examples/d1/` contains an optional D1 example surface
|
||
|
|
- `drizzle.config.ts` supports local migration generation when needed
|
||
|
|
|
||
|
|
## Workspace Auth Headers
|
||
|
|
|
||
|
|
OpenAI workspace sites can read the current user's email from
|
||
|
|
`oai-authenticated-user-email`.
|
||
|
|
|
||
|
|
SIWC-authenticated workspace sites may also receive
|
||
|
|
`oai-authenticated-user-full-name` when the user's SIWC profile has a non-empty
|
||
|
|
`name` claim. The full-name value is percent-encoded UTF-8 and is accompanied by
|
||
|
|
`oai-authenticated-user-full-name-encoding: percent-encoded-utf-8`.
|
||
|
|
|
||
|
|
Treat the full name as optional and fall back to email when it is absent:
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
import { headers } from "next/headers";
|
||
|
|
|
||
|
|
export default async function Home() {
|
||
|
|
const requestHeaders = await headers();
|
||
|
|
const email = requestHeaders.get("oai-authenticated-user-email");
|
||
|
|
const encodedFullName = requestHeaders.get("oai-authenticated-user-full-name");
|
||
|
|
const fullName =
|
||
|
|
encodedFullName &&
|
||
|
|
requestHeaders.get("oai-authenticated-user-full-name-encoding") ===
|
||
|
|
"percent-encoded-utf-8"
|
||
|
|
? decodeURIComponent(encodedFullName)
|
||
|
|
: null;
|
||
|
|
|
||
|
|
const displayName = fullName ?? email;
|
||
|
|
// ...
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Optional Dispatch-Owned ChatGPT Sign-In
|
||
|
|
|
||
|
|
Import the ready-to-use helpers from `app/chatgpt-auth.ts` when the site needs
|
||
|
|
optional or required ChatGPT sign-in:
|
||
|
|
|
||
|
|
- Use `getChatGPTUser()` for optional signed-in UI.
|
||
|
|
- Use `requireChatGPTUser(returnTo)` for server-rendered pages that should send
|
||
|
|
anonymous visitors through Sign in with ChatGPT.
|
||
|
|
- Use `chatGPTSignInPath(returnTo)` and `chatGPTSignOutPath(returnTo)` for
|
||
|
|
browser links or actions.
|
||
|
|
- Pass a same-origin relative `returnTo` path for the destination after sign-in
|
||
|
|
or sign-out. The helper validates and safely encodes it.
|
||
|
|
- Mark protected pages with `export const dynamic = "force-dynamic"` because
|
||
|
|
they depend on per-request identity headers.
|
||
|
|
|
||
|
|
Dispatch owns `/signin-with-chatgpt`, `/signout-with-chatgpt`, `/callback`, the
|
||
|
|
OAuth cookies, and identity header injection. Do not implement app routes for
|
||
|
|
those reserved paths. Routes that do not import and call the helper remain
|
||
|
|
anonymous-compatible.
|
||
|
|
|
||
|
|
SIWC establishes identity only; it does not prove workspace membership. Use the
|
||
|
|
Sites hosting platform's access policy controls for workspace-wide restrictions,
|
||
|
|
or enforce explicit server-side membership or allowlist checks.
|
||
|
|
|
||
|
|
Use SIWC for account pages, user-specific dashboards, saved records, and write
|
||
|
|
actions tied to the current ChatGPT user. Leave public content anonymous.
|
||
|
|
|
||
|
|
## Useful Commands
|
||
|
|
|
||
|
|
- `npm run dev`: start local development
|
||
|
|
- `npm run build`: verify the vinext build output
|
||
|
|
- `npm test`: build the starter and verify its rendered loading skeleton
|
||
|
|
- `npm run db:generate`: generate Drizzle migrations after schema changes
|
||
|
|
|
||
|
|
## Learn More
|
||
|
|
|
||
|
|
- [vinext Documentation](https://github.com/cloudflare/vinext)
|
||
|
|
- [Drizzle D1 Guide](https://orm.drizzle.team/docs/get-started/d1-new)
|