fix(deploy): keep fork configuration external
This commit is contained in:
1 parent
1f2582438d
commit
4c9dd2670c
21 files changed
+223
-103
No files matched your search
+1
-1
@@ -26,7 +26,7 @@ EDGE_EVER_R2_PREVIEW_BUCKET_NAME=edgeever-resources-preview
|
||||
# Authentication
|
||||
# Initial login credentials; the password is uploaded as a Worker Secret.
|
||||
EDGE_EVER_AUTH_USERNAME=admin
|
||||
EDGE_EVER_AUTH_PASSWORD=admin123
|
||||
EDGE_EVER_AUTH_PASSWORD=
|
||||
# Allowed range: 1-400 days.
|
||||
EDGE_EVER_SESSION_TTL_DAYS=400
|
||||
# Portable application-level login protection. These values work in both D1 and SQLite.
|
||||
|
||||
@@ -71,8 +71,8 @@ Copy the prompt below directly into an AI Agent (such as Codex, Claude, Cursor,
|
||||
Deploy EdgeEver online:
|
||||
1. Fork https://github.com/tianma-if/edgeever.
|
||||
2. Import the Fork into Cloudflare Workers & Pages.
|
||||
3. Configure D1, R2, `EDGE_EVER_AUTH_USERNAME` (prefilled as `admin`, customizable),
|
||||
the `EDGE_EVER_AUTH_PASSWORD` Worker Secret, and the production `main` build.
|
||||
3. Create D1 `edgeever` and R2 `edgeever-resources`, set the
|
||||
`EDGE_EVER_AUTH_PASSWORD` Worker Secret, and configure the production `main` build.
|
||||
4. Start the first build and verify `/api/health`, `/api/openapi.json`, and login.
|
||||
5. Enable and manually run the GitHub Actions workflow named `Update deployed EdgeEver`
|
||||
once so the Fork can automatically receive the latest EdgeEver features and fixes.
|
||||
@@ -87,7 +87,7 @@ Complete setup in 5 simple web steps:
|
||||
1. **Fork the Repository**: Click **Fork** at the top right of GitHub to fork EdgeEver into your personal account.
|
||||
2. **Enable Actions**: Open the Fork's **Actions** tab and click **I understand my workflows, go ahead and enable them** so the GitHub Actions workflow named **Update deployed EdgeEver** can run automatically, keeping you up to date with the latest **EdgeEver** features and fixes.
|
||||
3. **Import into Cloudflare**: Log into the Cloudflare Dashboard, navigate to **Workers & Pages**, and choose to import your Fork repository.
|
||||
4. **Bind Resources & Credentials**: Bind the D1 database (`DB`), R2 bucket (`RESOURCES`), set `EDGE_EVER_AUTH_USERNAME` (default `admin`, customizable), and set the Worker Secret `EDGE_EVER_AUTH_PASSWORD` as your admin password.
|
||||
4. **Create Resources & Credentials**: Create D1 `edgeever` and R2 `edgeever-resources`, then set the Worker Secret `EDGE_EVER_AUTH_PASSWORD` as your admin password. The deploy command creates the bindings; do not edit Fork files.
|
||||
5. **Build & Verify**: Start the first build with default settings. Once complete, visit `/api/health` to verify a `200` response before logging in.
|
||||
|
||||
> 📖 For full step-by-step instructions and configuration details, see the [Online Deployment Guide](docs/deploy-cloudflare-button.md).
|
||||
|
||||
+3
-3
@@ -71,8 +71,8 @@ EdgeEver 采用纯 Serverless 架构,完全运行在 Cloudflare 免费配额
|
||||
请在线完成 EdgeEver 部署:
|
||||
1. Fork https://github.com/tianma-if/edgeever。
|
||||
2. 将这个 Fork 导入 Cloudflare Workers & Pages。
|
||||
3. 配置 D1、R2、`EDGE_EVER_AUTH_USERNAME`(预填为 `admin`,可自定义)、
|
||||
`EDGE_EVER_AUTH_PASSWORD` Worker Secret 和生产环境 `main` 构建。
|
||||
3. 创建 D1 `edgeever` 与 R2 `edgeever-resources`,设置
|
||||
`EDGE_EVER_AUTH_PASSWORD` Worker Secret,并配置生产环境 `main` 构建。
|
||||
4. 启动首次构建,验证 `/api/health`、`/api/openapi.json` 和登录。
|
||||
5. 启用并手动运行一次名为 `Update deployed EdgeEver` 的 GitHub Actions 工作流,
|
||||
以便后续自动同步更新,持续获得 EdgeEver 最新的产品特性和问题修复。
|
||||
@@ -87,7 +87,7 @@ EdgeEver 采用纯 Serverless 架构,完全运行在 Cloudflare 免费配额
|
||||
1. **Fork 仓库**:在 GitHub 点击右上角 **Fork**,将项目 Fork 到您的个人账户下。
|
||||
2. **启用 Actions**:进入 Fork 的 **Actions** 标签页,点击 **I understand my workflows, go ahead and enable them**,确保名为 **Update deployed EdgeEver** 的 GitHub Actions 工作流能够自动运行,从而持续获得 **EdgeEver** 最新的产品特性和问题修复。
|
||||
3. **导入 Cloudflare**:登录 Cloudflare 控制台,进入 **Workers & Pages**,选择导入该 Fork 仓库。
|
||||
4. **绑定资源与登录凭据**:绑定 D1 数据库(`DB`)、R2 存储桶(`RESOURCES`),设置 `EDGE_EVER_AUTH_USERNAME`(默认为 `admin`,可自定义),并添加 Worker Secret `EDGE_EVER_AUTH_PASSWORD` 作为管理员登录密码。
|
||||
4. **创建资源与登录凭据**:创建 D1 `edgeever` 与 R2 `edgeever-resources`,并添加 Worker Secret `EDGE_EVER_AUTH_PASSWORD` 作为管理员登录密码。binding 由部署命令生成,不要修改 Fork 中的文件。
|
||||
5. **启动构建与验证**:使用默认构建配置启动首次构建,部署完成后访问 `/api/health` 确认返回 `200` 即可开始使用。
|
||||
|
||||
> 📖 包含具体参数与构建命令的详细步骤,请查看 [在线部署完整文档](docs/deploy-cloudflare-button.zh-CN.md)。
|
||||
|
||||
@@ -270,6 +270,18 @@ app.get("/api/health", async (c) => {
|
||||
return authNotConfigured(c);
|
||||
}
|
||||
|
||||
if (!c.env.storage.resources) {
|
||||
return c.json(
|
||||
{
|
||||
error: {
|
||||
code: "object_storage_not_ready",
|
||||
message: "Object storage is not configured. Bind RESOURCES and redeploy.",
|
||||
},
|
||||
},
|
||||
503,
|
||||
);
|
||||
}
|
||||
|
||||
return c.json({
|
||||
ok: true,
|
||||
name: "edgeever",
|
||||
|
||||
@@ -2,16 +2,16 @@ export const deploymentPrompts = {
|
||||
"en-US": `Deploy EdgeEver online:
|
||||
1. Fork https://github.com/tianma-if/edgeever.
|
||||
2. Import the Fork into Cloudflare Workers & Pages.
|
||||
3. Configure D1, R2, \`EDGE_EVER_AUTH_USERNAME\` (prefilled as \`admin\`, customizable),
|
||||
the \`EDGE_EVER_AUTH_PASSWORD\` Worker Secret, and the production \`main\` build.
|
||||
3. Create D1 \`edgeever\` and R2 \`edgeever-resources\`, set the
|
||||
\`EDGE_EVER_AUTH_PASSWORD\` Worker Secret, and configure the production \`main\` build.
|
||||
4. Start the first build and verify \`/api/health\`, \`/api/openapi.json\`, and login.
|
||||
5. Enable and manually run the GitHub Actions workflow named \`Update deployed EdgeEver\`
|
||||
once so the Fork can automatically receive the latest EdgeEver features and fixes.`,
|
||||
"zh-CN": `请在线完成 EdgeEver 部署:
|
||||
1. Fork https://github.com/tianma-if/edgeever。
|
||||
2. 将这个 Fork 导入 Cloudflare Workers & Pages。
|
||||
3. 配置 D1、R2、\`EDGE_EVER_AUTH_USERNAME\`(预填为 \`admin\`,可自定义)、
|
||||
\`EDGE_EVER_AUTH_PASSWORD\` Worker Secret 和生产环境 \`main\` 构建。
|
||||
3. 创建 D1 \`edgeever\` 与 R2 \`edgeever-resources\`,设置
|
||||
\`EDGE_EVER_AUTH_PASSWORD\` Worker Secret,并配置生产环境 \`main\` 构建。
|
||||
4. 启动首次构建,验证 \`/api/health\`、\`/api/openapi.json\` 和登录。
|
||||
5. 启用并手动运行一次名为 \`Update deployed EdgeEver\` 的 GitHub Actions 工作流,
|
||||
以便后续自动同步更新,持续获得 EdgeEver 最新的产品特性和问题修复。`,
|
||||
@@ -34,8 +34,8 @@ export const manualDeploymentCopy = {
|
||||
body: "Log into the Cloudflare Dashboard, navigate to Workers & Pages, and choose to import your Fork repository.",
|
||||
},
|
||||
{
|
||||
title: "Bind Resources & Credentials",
|
||||
body: "Bind the D1 database (DB), R2 bucket (RESOURCES), set EDGE_EVER_AUTH_USERNAME (default admin, customizable), and set the Worker Secret EDGE_EVER_AUTH_PASSWORD as your admin password.",
|
||||
title: "Create Resources & Credentials",
|
||||
body: "Create D1 edgeever and R2 edgeever-resources, then set the Worker Secret EDGE_EVER_AUTH_PASSWORD as your admin password. The deploy command creates the bindings; do not edit Fork files.",
|
||||
},
|
||||
{
|
||||
title: "Build & Verify",
|
||||
@@ -59,8 +59,8 @@ export const manualDeploymentCopy = {
|
||||
body: "登录 Cloudflare 控制台,进入 Workers & Pages,选择导入该 Fork 仓库。",
|
||||
},
|
||||
{
|
||||
title: "绑定资源与登录凭据",
|
||||
body: "绑定 D1 数据库(DB)、R2 存储桶(RESOURCES),设置 EDGE_EVER_AUTH_USERNAME(默认为 admin,可自定义),并添加 Worker Secret EDGE_EVER_AUTH_PASSWORD 作为管理员登录密码。",
|
||||
title: "创建资源与登录凭据",
|
||||
body: "创建 D1 edgeever 与 R2 edgeever-resources,并添加 Worker Secret EDGE_EVER_AUTH_PASSWORD 作为管理员登录密码。binding 由部署命令生成,不要修改 Fork 中的文件。",
|
||||
},
|
||||
{
|
||||
title: "启动构建与验证",
|
||||
|
||||
@@ -21,12 +21,12 @@ This document defines the standard operating specifications and conventions for
|
||||
- Log into the Cloudflare **Workers & Pages** console and import the Fork repository.
|
||||
- Configure the project to use the repository root, the production `main` branch, and read the root `wrangler.toml`.
|
||||
|
||||
4. **Resource Bindings & Secrets**
|
||||
- **D1 Database Binding**: Binding name `DB`, associated with a database named exactly `edgeever`.
|
||||
- **R2 Bucket Binding**: Binding name `RESOURCES`, associated with a globally unique R2 Bucket.
|
||||
- **Admin username**: Configure `EDGE_EVER_AUTH_USERNAME`; it defaults to `admin` and can be replaced with a custom username.
|
||||
4. **Resources & Secrets**
|
||||
- Create a D1 database named exactly `edgeever`.
|
||||
- Create an R2 bucket named exactly `edgeever-resources`.
|
||||
- **Worker Secret**: Add secret `EDGE_EVER_AUTH_PASSWORD` for initial admin password.
|
||||
- Keep this password only as a Worker runtime Secret; do not copy it into Workers Builds variables. The standard deploy entrypoint reuses and verifies the existing Secret.
|
||||
- Do not edit `wrangler.toml` or add duplicate bindings in the Dashboard. The deployment command generates the `DB` and `RESOURCES` bindings from these standard resource names.
|
||||
|
||||
5. **Configure Workers Builds Commands**
|
||||
- In the Cloudflare project build settings, set the standard commands:
|
||||
@@ -36,14 +36,14 @@ This document defines the standard operating specifications and conventions for
|
||||
Deploy command: bun run deploy:cloudflare-builds
|
||||
```
|
||||
|
||||
- The deploy command automatically resolves the D1 UUID from the `edgeever` database name and writes it only to a temporary generated Wrangler configuration. The tracked `wrangler.toml` must keep its all-zero `database_id` placeholder; deployment rejects an instance-specific ID committed there so a Fork cannot diverge on local infrastructure configuration.
|
||||
- Ensure the Workers Builds API token can read and edit D1. An advanced deployment that uses a differently named database must set the build variable `EDGE_EVER_D1_DATABASE_ID` explicitly.
|
||||
- The deploy command automatically resolves the D1 UUID from the `edgeever` database name and writes all instance settings only to a temporary generated Wrangler configuration. The tracked `wrangler.toml` must remain unchanged; deployment rejects instance-specific values committed there so a Fork cannot diverge on infrastructure configuration.
|
||||
- Ensure the Workers Builds API token can read and edit D1. Advanced non-secret customization belongs in `EDGE_EVER_*` Workers Builds variables. For a differently named database, set `EDGE_EVER_D1_DATABASE_NAME`; set `EDGE_EVER_D1_DATABASE_ID` only if automatic UUID discovery is unavailable. Passwords remain runtime Secrets.
|
||||
|
||||
6. **Start Initial Build & Verify Service**
|
||||
- Trigger the initial build. Once deployed, run the following automated verifications:
|
||||
- Check `https://<your-worker-domain>/api/health` returns HTTP `200` with JSON `{"ok": true}`.
|
||||
- Check `https://<your-worker-domain>/api/openapi.json` loads the OpenAPI schema properly.
|
||||
- Verify login API using the configured `EDGE_EVER_AUTH_USERNAME` (default `admin`) and `EDGE_EVER_AUTH_PASSWORD`.
|
||||
- Verify login API using username `admin` and `EDGE_EVER_AUTH_PASSWORD`. If an advanced deployment sets the `EDGE_EVER_AUTH_USERNAME` Builds variable, use that username instead.
|
||||
|
||||
7. **Verify Upstream Update Channel**
|
||||
- Manually trigger **Update deployed EdgeEver** once in the Fork's **Actions** tab.
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
- 登录 Cloudflare **Workers & Pages** 控制台,导入该 Fork 仓库。
|
||||
- 配置项目使用仓库根目录、生产环境 `main` 分支,并读取仓库根目录下的 `wrangler.toml`。
|
||||
|
||||
4. **绑定资源与凭据 (Bindings & Secrets)**
|
||||
- **D1 数据库绑定**:Binding 名称填 `DB`,关联名称严格为 `edgeever` 的数据库。
|
||||
- **R2 存储桶绑定**:Binding 名称填 `RESOURCES`,关联全局唯一的 R2 Bucket。
|
||||
- **管理员用户名**:配置 `EDGE_EVER_AUTH_USERNAME`,默认值为 `admin`;如需自定义,可替换为其他用户名。
|
||||
4. **资源与凭据 (Resources & Secrets)**
|
||||
- 创建名称严格为 `edgeever` 的 D1 数据库。
|
||||
- 创建名称严格为 `edgeever-resources` 的 R2 存储桶。
|
||||
- **Worker Secret**:添加密钥 `EDGE_EVER_AUTH_PASSWORD`,值为初始管理员登录密码。
|
||||
- 该密码只配置为 Worker 运行时 Secret,不要复制到 Workers Builds 构建变量;标准部署入口会复用并验证已存在的 Secret。
|
||||
- 不要修改 `wrangler.toml`,也不要在控制台重复添加 binding。部署命令会根据标准资源名称生成 `DB` 与 `RESOURCES` binding。
|
||||
|
||||
5. **配置 Workers Builds 命令**
|
||||
- 在 Cloudflare 项目的构建设置中,填入以下标准命令:
|
||||
@@ -36,14 +36,14 @@
|
||||
Deploy command: bun run deploy:cloudflare-builds
|
||||
```
|
||||
|
||||
- 部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID,并且只写入临时生成的 Wrangler 配置。受版本控制的 `wrangler.toml` 必须保留全零 `database_id` 占位符;若把实例专属 ID 提交到该文件,部署会直接拒绝,避免 Fork 因本地基础设施配置产生分叉。
|
||||
- 请确保 Workers Builds API Token 具有 D1 读取和编辑权限。使用其他数据库名称的高级部署需要显式设置构建变量 `EDGE_EVER_D1_DATABASE_ID`。
|
||||
- 部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID,并把所有实例参数仅写入临时生成的 Wrangler 配置。受版本控制的 `wrangler.toml` 必须保持不变;若把实例专属配置提交到该文件,部署会直接拒绝,避免 Fork 因基础设施配置产生分叉。
|
||||
- 请确保 Workers Builds API Token 具有 D1 读取和编辑权限。高级非敏感自定义参数应放在 `EDGE_EVER_*` Workers Builds 构建变量中。如使用其他数据库名称,设置 `EDGE_EVER_D1_DATABASE_NAME`;仅在无法自动查询 UUID 时设置 `EDGE_EVER_D1_DATABASE_ID`。密码始终属于运行时 Secret。
|
||||
|
||||
6. **启动首次构建与服务验证**
|
||||
- 触发启动首次构建,待构建部署完成后,进行如下自动化验证:
|
||||
- 检查 `https://<你的 Worker 域名>/api/health` 返回 `200` 状态码且 JSON 内容为 `{"ok": true}`。
|
||||
- 检查 `https://<你的 Worker 域名>/api/openapi.json` 能够正常加载 OpenAPI 规范。
|
||||
- 使用之前配置的 `EDGE_EVER_AUTH_USERNAME`(默认 `admin`)和 `EDGE_EVER_AUTH_PASSWORD` 验证登录 API 是否可用。
|
||||
- 使用用户名 `admin` 和 `EDGE_EVER_AUTH_PASSWORD` 验证登录 API;若高级部署设置了 `EDGE_EVER_AUTH_USERNAME` 构建变量,则改用对应用户名。
|
||||
|
||||
7. **验证上游更新通道**
|
||||
- 在 Fork 的 **Actions** 中手动运行一次 **Update deployed EdgeEver**。
|
||||
|
||||
@@ -12,6 +12,8 @@ Authorization:
|
||||
|
||||
Configure `EDGE_EVER_AUTH_PASSWORD` under the Worker's **Settings -> Variables and Secrets** as a runtime Secret; do not copy the password into Builds variables. `deploy:cloudflare-builds` reuses that Secret and verifies its presence after deployment.
|
||||
|
||||
Keep the tracked `wrangler.toml` unchanged. Ordinary deployments use D1 `edgeever`, R2 `edgeever-resources`, and username `admin`. Optional non-secret instance settings such as `EDGE_EVER_AUTH_USERNAME`, `EDGE_EVER_WORKER_NAME`, `EDGE_EVER_D1_DATABASE_NAME`, `EDGE_EVER_R2_BUCKET_NAME`, and custom routing belong under **Settings -> Builds -> Variables and secrets**. Workers Builds variables are available to the build command, not to the running Worker; the deploy command uses them to generate a temporary Wrangler configuration. Passwords and credentials remain runtime Secrets.
|
||||
|
||||
## Updates and troubleshooting
|
||||
|
||||
- A push to `main` builds, applies D1 migrations, deploys, and verifies EdgeEver.
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
`EDGE_EVER_AUTH_PASSWORD` 应配置在 Worker 的 **Settings -> Variables and Secrets** 中,作为运行时 Secret;不要把密码复制到 Builds 的构建变量。`deploy:cloudflare-builds` 会复用该 Secret,并在部署后验证它是否存在。
|
||||
|
||||
受版本控制的 `wrangler.toml` 必须保持不变。普通部署使用 D1 `edgeever`、R2 `edgeever-resources` 和用户名 `admin`。`EDGE_EVER_AUTH_USERNAME`、`EDGE_EVER_WORKER_NAME`、`EDGE_EVER_D1_DATABASE_NAME`、`EDGE_EVER_R2_BUCKET_NAME` 与自定义路由等可选非敏感实例参数,应放在 **Settings -> Builds -> Variables and secrets**。Workers Builds 变量只对构建命令可见,不会直接成为 Worker 运行时变量;部署命令会用它们生成临时 Wrangler 配置。密码及其他凭据始终属于运行时 Secret。
|
||||
|
||||
## 更新与排错
|
||||
|
||||
- `main` 推送会自动构建、执行 D1 migration、部署并验证。
|
||||
|
||||
@@ -32,30 +32,27 @@ Log into your [Cloudflare Dashboard](https://dash.cloudflare.com/):
|
||||
- Database name: exactly `edgeever`, then click **Create**.
|
||||
2. **Create an R2 Bucket** (for note attachments & images):
|
||||
- Navigate to **Workers & Pages** -> **R2**, then click **Create bucket**.
|
||||
- Enter a globally unique bucket name (e.g., `my-edgeever-resources`), then click **Create bucket**.
|
||||
- Bucket name: exactly `edgeever-resources`, then click **Create bucket**.
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Import Project & Configure Resources (Bindings & Secrets)
|
||||
### Step 3: Import Project & Configure the Login Secret
|
||||
|
||||
1. In Cloudflare Dashboard, navigate to **Workers & Pages** -> **Overview**, click **Create application** -> **Pages** / **Workers** (Import Git Repository).
|
||||
2. Click **Connect to Git**, authorize Cloudflare, and select your Forked `edgeever` repository.
|
||||
3. Project settings:
|
||||
- **Production branch**: `main`
|
||||
- **Root directory**: Leave blank or default `/`
|
||||
4. **Configure Bindings & Variables** (under **Settings** -> **Variables and Bindings**):
|
||||
4. Under **Settings** -> **Variables and Secrets**, add the login password:
|
||||
|
||||
| Type | Binding / Variable Name | Value / Bound Resource | Purpose |
|
||||
| Type | Name | Value | Purpose |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **D1 Database Binding** | `DB` | Select `edgeever` database | Stores notes & structured data |
|
||||
| **R2 Bucket Binding** | `RESOURCES` | Select your created R2 bucket | Stores images & file attachments |
|
||||
| **Environment Variable** | `EDGE_EVER_AUTH_USERNAME` | `admin` (customizable) | Admin login username |
|
||||
| **Environment Variable (Secret)** | `EDGE_EVER_AUTH_PASSWORD` | Set your admin password | Initial login credential |
|
||||
|
||||
> `EDGE_EVER_AUTH_USERNAME` is prefilled with `admin`. Most users can keep this value. Advanced users can replace it with a custom administrator username; the configured username is required at login.
|
||||
| **Secret** | `EDGE_EVER_AUTH_PASSWORD` | Set a strong admin password | Initial login credential |
|
||||
|
||||
> `EDGE_EVER_AUTH_PASSWORD` is a Worker runtime Secret, not a Workers Builds variable. The standard deploy command reuses and verifies this Secret; do not duplicate the password in build variables.
|
||||
|
||||
The repository's deployment command creates the `DB` and `RESOURCES` bindings from the standard resource names. Do not edit `wrangler.toml` or add duplicate bindings in the Dashboard.
|
||||
|
||||
---
|
||||
|
||||
### Step 4: Set Build Commands & Start Build
|
||||
@@ -69,9 +66,9 @@ Deploy command: bun run deploy:cloudflare-builds
|
||||
|
||||
Click **Save and Deploy** to trigger the initial build.
|
||||
|
||||
The deploy command automatically looks up the D1 UUID by the `edgeever` database name. Keep the tracked `wrangler.toml` on its all-zero `database_id` placeholder; deployment rejects an instance-specific ID committed there. The Workers Builds API token must have D1 read/edit permission.
|
||||
The deploy command automatically looks up the D1 UUID by the `edgeever` database name. Keep the tracked `wrangler.toml` unchanged; deployment rejects instance-specific values committed there. The Workers Builds API token must have D1 read/edit permission.
|
||||
|
||||
After publishing, the CI deployment records the actual public target reported by Wrangler and requests its `/api/health` endpoint. The build fails if the live Worker is missing its `DB` binding, uses an unprepared D1 database, or does not return a healthy response.
|
||||
After publishing, the CI deployment records the actual public target reported by Wrangler and requests its `/api/health` endpoint. The build fails if the live Worker is missing its `DB` or `RESOURCES` binding, uses an unprepared D1 database, or does not return a healthy response.
|
||||
|
||||
---
|
||||
|
||||
@@ -97,11 +94,28 @@ EDGE_EVER_UPDATE_CHANNEL=edge
|
||||
|
||||
You can also pick `stable` / `edge` when manually running the workflow.
|
||||
|
||||
## Advanced Configuration: Instance Settings
|
||||
|
||||
Ordinary deployments do not need these settings. To customize an instance, add non-secret values under **Settings -> Builds -> Variables and secrets** instead of changing repository files:
|
||||
|
||||
| Build variable | Purpose |
|
||||
| :--- | :--- |
|
||||
| `EDGE_EVER_AUTH_USERNAME` | Administrator username; defaults to `admin` |
|
||||
| `EDGE_EVER_WORKER_NAME` | Worker name |
|
||||
| `EDGE_EVER_D1_DATABASE_NAME` | D1 database name; its UUID is discovered automatically |
|
||||
| `EDGE_EVER_D1_DATABASE_ID` | Optional UUID fallback when discovery is unavailable |
|
||||
| `EDGE_EVER_R2_BUCKET_NAME` | Production R2 bucket name |
|
||||
| `EDGE_EVER_R2_PREVIEW_BUCKET_NAME` | Preview R2 bucket name |
|
||||
| `EDGE_EVER_WORKERS_DEV` | Enable or disable the `workers.dev` route |
|
||||
| `EDGE_EVER_CUSTOM_DOMAIN` / `EDGE_EVER_ROUTE_PATTERN` | Custom routing |
|
||||
|
||||
Passwords and other credentials remain Worker runtime Secrets and must never be added to Builds variables. An advanced local deployment may instead use the git-ignored `.env.local` or an external `WRANGLER_CONFIG` file.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Initial build failed**: Check the Worker **Deployments** log. Verify that the D1 binding is `DB`, its database is named exactly `edgeever`, the R2 binding is `RESOURCES`, and the Workers Builds API token has D1 read/edit permission. For an intentionally different D1 database, add the build variable `EDGE_EVER_D1_DATABASE_ID` with its UUID.
|
||||
- **Initial build failed**: Check the Worker **Deployments** log. Verify that the standard resources are named exactly `edgeever` and `edgeever-resources`, and that the Workers Builds API token has D1 read/edit permission. For an intentionally different D1 database, set `EDGE_EVER_D1_DATABASE_NAME`; add `EDGE_EVER_D1_DATABASE_ID` only if automatic UUID discovery is unavailable.
|
||||
- **Updates not syncing**:
|
||||
1. On the Fork **Actions** tab, enable **Update deployed EdgeEver** (scheduled workflows are off by default on public forks).
|
||||
2. Run it once with **Run workflow**. Open the job **Summary**: it states the upstream target version and whether the fork was updated, already aligned, or failed.
|
||||
|
||||
@@ -32,30 +32,27 @@
|
||||
- 数据库名称严格填入:`edgeever`,点击 **Create**。
|
||||
2. **创建 R2 存储桶**(用于存储笔记附件与图片):
|
||||
- 导航至 **Workers & Pages** -> **R2**,点击 **Create bucket**。
|
||||
- 填入自定义存储桶名称(全局唯一,如 `my-edgeever-resources`),点击 **Create bucket**。
|
||||
- 存储桶名称严格填入:`edgeever-resources`,点击 **Create bucket**。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3:导入项目并配置资源绑定 (Bindings & Secrets)
|
||||
### 步骤 3:导入项目并配置登录 Secret
|
||||
|
||||
1. 在 Cloudflare 控制台中,进入 **Workers & Pages** -> **Overview**,点击 **Create application** -> **Pages** / **Workers** (选择导入 Git 仓库)。
|
||||
2. 选择 **Connect to Git**,授权并选中您刚才 Fork 的 `edgeever` 仓库。
|
||||
3. 在项目设置中:
|
||||
- **Production branch**:选择 `main`
|
||||
- **Root directory**:保持留空或默认 `/`
|
||||
4. **配置环境变量与资源绑定**(在 **Settings** -> **Variables and Bindings**):
|
||||
4. 在 **Settings** -> **Variables and Secrets** 中添加登录密码:
|
||||
|
||||
| 类型 (Type) | 名称 (Binding / Variable Name) | 值 / 绑定的资源 (Value / Resource) | 说明 |
|
||||
| 类型 (Type) | 名称 (Name) | 值 (Value) | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **D1 Database Binding** | `DB` | 选择 `edgeever` 数据库 | 存放笔记与结构化数据 |
|
||||
| **R2 Bucket Binding** | `RESOURCES` | 选择您创建的 R2 Bucket | 存放图片与图片附件 |
|
||||
| **Environment Variable** | `EDGE_EVER_AUTH_USERNAME` | `admin`(可改为自定义用户名) | 管理员登录用户名 |
|
||||
| **Environment Variable (Secret)** | `EDGE_EVER_AUTH_PASSWORD` | 设置您的管理员登录密码 | 初始登录凭据 |
|
||||
|
||||
> `EDGE_EVER_AUTH_USERNAME` 默认预填为 `admin`。普通用户可以直接使用这个值;如果希望使用其他管理员用户名,可在这里修改。请记住部署时填写的用户名,登录时需要同时输入用户名和密码。
|
||||
| **Secret** | `EDGE_EVER_AUTH_PASSWORD` | 设置一个高强度管理员密码 | 初始登录凭据 |
|
||||
|
||||
> `EDGE_EVER_AUTH_PASSWORD` 是 Worker 运行时 Secret,不是 Workers Builds 构建变量。标准部署命令会复用并验证这个 Secret;无需、也不应把密码重复填写到构建变量中。
|
||||
|
||||
仓库中的部署命令会根据标准资源名称生成 `DB` 与 `RESOURCES` binding。不要修改 `wrangler.toml`,也不要在控制台中重复添加 binding。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4:设置构建命令并启动构建
|
||||
@@ -69,9 +66,9 @@ Deploy command: bun run deploy:cloudflare-builds
|
||||
|
||||
点击 **Save and Deploy** 启动首次构建部署。
|
||||
|
||||
部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID。受版本控制的 `wrangler.toml` 必须保留全零 `database_id` 占位符;若把实例专属 ID 提交到该文件,部署会直接拒绝。Workers Builds API Token 必须具有 D1 读取和编辑权限。
|
||||
部署命令会根据 `edgeever` 数据库名称自动查询 D1 UUID。受版本控制的 `wrangler.toml` 必须保持不变;若把实例专属配置提交到该文件,部署会直接拒绝。Workers Builds API Token 必须具有 D1 读取和编辑权限。
|
||||
|
||||
发布完成后,CI 部署会记录 Wrangler 返回的实际公网入口,并请求该入口的 `/api/health`。如果线上 Worker 缺少 `DB` binding、绑定了未初始化的 D1,或没有返回健康状态,构建会直接失败。
|
||||
发布完成后,CI 部署会记录 Wrangler 返回的实际公网入口,并请求该入口的 `/api/health`。如果线上 Worker 缺少 `DB` 或 `RESOURCES` binding、绑定了未初始化的 D1,或没有返回健康状态,构建会直接失败。
|
||||
|
||||
---
|
||||
|
||||
@@ -97,11 +94,28 @@ EDGE_EVER_UPDATE_CHANNEL=edge
|
||||
|
||||
手动运行工作流时也可以直接选择 `stable` / `edge`。
|
||||
|
||||
## 高级配置:实例参数
|
||||
|
||||
普通部署不需要配置以下参数。如需自定义实例,请在 **Settings -> Builds -> Variables and secrets** 中添加非敏感构建变量,不要修改仓库文件:
|
||||
|
||||
| 构建变量 | 用途 |
|
||||
| :--- | :--- |
|
||||
| `EDGE_EVER_AUTH_USERNAME` | 管理员用户名,默认为 `admin` |
|
||||
| `EDGE_EVER_WORKER_NAME` | Worker 名称 |
|
||||
| `EDGE_EVER_D1_DATABASE_NAME` | D1 数据库名称,UUID 会自动查询 |
|
||||
| `EDGE_EVER_D1_DATABASE_ID` | 自动查询不可用时的可选 UUID 兜底值 |
|
||||
| `EDGE_EVER_R2_BUCKET_NAME` | 生产环境 R2 存储桶名称 |
|
||||
| `EDGE_EVER_R2_PREVIEW_BUCKET_NAME` | 预览环境 R2 存储桶名称 |
|
||||
| `EDGE_EVER_WORKERS_DEV` | 启用或禁用 `workers.dev` 路由 |
|
||||
| `EDGE_EVER_CUSTOM_DOMAIN` / `EDGE_EVER_ROUTE_PATTERN` | 自定义路由 |
|
||||
|
||||
密码及其他凭据始终属于 Worker 运行时 Secret,绝不能放入 Builds 构建变量。高级本地部署也可以使用被 Git 忽略的 `.env.local`,或仓库外部的 `WRANGLER_CONFIG` 文件。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题与排错
|
||||
|
||||
- **首次构建失败**:请检查 Cloudflare 控制台中 Worker 的 **Deployments** 构建日志,确认 D1 Binding 为 `DB`、数据库名称严格为 `edgeever`、R2 Binding 为 `RESOURCES`,并确认 Workers Builds API Token 具有 D1 读取和编辑权限。如有意使用其他 D1 数据库,请添加构建变量 `EDGE_EVER_D1_DATABASE_ID` 并填入其 UUID。
|
||||
- **首次构建失败**:请检查 Cloudflare 控制台中 Worker 的 **Deployments** 构建日志,确认标准资源名称严格为 `edgeever` 与 `edgeever-resources`,并确认 Workers Builds API Token 具有 D1 读取和编辑权限。如有意使用其他 D1 数据库,请设置 `EDGE_EVER_D1_DATABASE_NAME`;仅在自动查询 UUID 不可用时再添加 `EDGE_EVER_D1_DATABASE_ID`。
|
||||
- **无法同步上游更新**:
|
||||
1. 打开 Fork 的 **Actions**,启用 **Update deployed EdgeEver**(公共 Fork 上定时任务默认关闭)。
|
||||
2. 手动 **Run workflow** 一次,打开 Job **Summary**:会写明上游目标版本,以及本次是「已更新」「已对齐」还是失败。
|
||||
|
||||
@@ -16,7 +16,7 @@ Use this page for advanced configuration, troubleshooting, and emergency recover
|
||||
bun run deploy:manual
|
||||
```
|
||||
|
||||
`deploy:setup` creates or reuses D1 and R2 and writes configuration to the git-ignored `.env.local`. Without `EDGE_EVER_PASSWORD`, the default login is `admin` / `admin123`.
|
||||
`deploy:setup` creates or reuses D1 and R2 and writes configuration to the git-ignored `.env.local`. `EDGE_EVER_PASSWORD` is required for a new deployment; there is no default production password.
|
||||
|
||||
For local CLI deployment, set `EDGE_EVER_DEPLOYMENT_URL=https://<your-worker-domain>` in `.env.local` to include the live `/api/health` request in deployment verification. CI deployments discover the public URL automatically from Wrangler output. Without an explicit URL, local verification still checks the remote D1 schema and Worker Secret, then reports that the live health check was skipped.
|
||||
|
||||
@@ -24,7 +24,7 @@ After deployment, confirm:
|
||||
|
||||
- `/api/health` returns `200` with `"ok": true`
|
||||
- `/api/openapi.json` is reachable
|
||||
- `admin` can log in
|
||||
- `admin` can log in with the password supplied through `EDGE_EVER_PASSWORD`
|
||||
|
||||
## Create resources manually
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
bun run deploy:manual
|
||||
```
|
||||
|
||||
`deploy:setup` 会创建或复用 D1、R2,并将配置写入被 Git 忽略的 `.env.local`。不设置 `EDGE_EVER_PASSWORD` 时,默认登录为 `admin` / `admin123`。
|
||||
`deploy:setup` 会创建或复用 D1、R2,并将配置写入被 Git 忽略的 `.env.local`。新部署必须提供 `EDGE_EVER_PASSWORD`,生产环境不存在默认密码。
|
||||
|
||||
使用本地 CLI 部署时,可在 `.env.local` 中设置 `EDGE_EVER_DEPLOYMENT_URL=https://<你的 Worker 域名>`,让部署验证同时请求线上的 `/api/health`;CI 部署会自动从 Wrangler 输出中识别公网地址。未显式配置地址时,本地验证仍会检查远端 D1 schema 和 Worker Secret,并明确提示已跳过线上健康检查。
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
- `/api/health` 返回 `200` 和 `"ok": true`
|
||||
- `/api/openapi.json` 可以访问
|
||||
- `admin` 可以登录
|
||||
- `admin` 可以使用通过 `EDGE_EVER_PASSWORD` 提供的密码登录
|
||||
|
||||
## 手动创建资源
|
||||
|
||||
|
||||
@@ -100,9 +100,6 @@
|
||||
"EDGE_EVER_AUTH_PASSWORD": {
|
||||
"description": "首次登录密码,必填。请设置一个仅用于此实例的强密码;部署后可在个人设置中修改。"
|
||||
},
|
||||
"EDGE_EVER_AUTH_USERNAME": {
|
||||
"description": "管理员登录用户名,默认值为 admin;高级用户可以改成自定义用户名。"
|
||||
},
|
||||
"EDGE_EVER_STORAGE_ENCRYPTION_KEY": {
|
||||
"description": "可选。启用高级设置中的第三方 OSS 时必填,用于加密保存在 D1 中的对象存储访问密钥。"
|
||||
},
|
||||
|
||||
@@ -92,7 +92,7 @@ const buildVariables = () => {
|
||||
if (current !== undefined) merged.set(key, current);
|
||||
}
|
||||
|
||||
const runtimeNames = [
|
||||
const deploymentNames = [
|
||||
"WORKER_NAME",
|
||||
"WORKERS_DEV",
|
||||
"D1_DATABASE_NAME",
|
||||
@@ -100,9 +100,12 @@ const buildVariables = () => {
|
||||
"R2_BUCKET_NAME",
|
||||
"R2_PREVIEW_BUCKET_NAME",
|
||||
"AUTH_USERNAME",
|
||||
"AUTH_PASSWORD",
|
||||
"AUTH_PASSWORD_HASH",
|
||||
"SESSION_TTL_DAYS",
|
||||
"AUTH_LOGIN_WINDOW_SECONDS",
|
||||
"AUTH_LOGIN_USERNAME_MAX_ATTEMPTS",
|
||||
"AUTH_LOGIN_USERNAME_COOLDOWN_SECONDS",
|
||||
"AUTH_LOGIN_IP_MAX_ATTEMPTS",
|
||||
"AUTH_LOGIN_IP_COOLDOWN_SECONDS",
|
||||
"DEMO_MODE",
|
||||
"DEMO_RESET_CRON",
|
||||
"CUSTOM_DOMAIN",
|
||||
@@ -111,20 +114,16 @@ const buildVariables = () => {
|
||||
const entries = [];
|
||||
|
||||
if (instanceKey) entries.push(["EDGE_EVER_INSTANCE", instanceKey]);
|
||||
for (const name of runtimeNames) {
|
||||
for (const name of deploymentNames) {
|
||||
const scoped = instanceKey ? `EDGE_EVER_${instanceKey}_${name}` : "";
|
||||
const key = scoped && merged.get(scoped)?.trim() ? scoped : `EDGE_EVER_${name}`;
|
||||
const current = merged.get(key)?.trim() || (name === "AUTH_USERNAME" ? "admin" : "");
|
||||
if (current) entries.push([key, current]);
|
||||
}
|
||||
|
||||
if (!entries.some(([key]) => key.endsWith("AUTH_PASSWORD") || key.endsWith("AUTH_PASSWORD_HASH"))) {
|
||||
throw new Error("Missing EDGE_EVER_AUTH_PASSWORD or EDGE_EVER_AUTH_PASSWORD_HASH. Run deploy:setup before configuring Workers Builds.");
|
||||
}
|
||||
|
||||
return Object.fromEntries(entries.map(([key, current]) => [key, {
|
||||
value: current.replace(/\\\$/g, "$"),
|
||||
is_secret: key.endsWith("AUTH_PASSWORD") || key.endsWith("AUTH_PASSWORD_HASH"),
|
||||
is_secret: false,
|
||||
}]));
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
normalizeD1MigrationSql,
|
||||
parseWranglerDeploymentUrls,
|
||||
PLACEHOLDER_D1_ID,
|
||||
repositoryD1ConfigError,
|
||||
repositoryWranglerConfigError,
|
||||
runWranglerSync,
|
||||
shouldCaptureDeploymentTargets,
|
||||
} from "./wrangler-runner.mjs";
|
||||
@@ -94,9 +94,9 @@ const generatedLocalDevEnvPath = resolve(".env.wrangler.generated.local");
|
||||
let config = readFileSync(baseConfigPath, "utf8");
|
||||
let changed = false;
|
||||
|
||||
const d1ConfigError = repositoryD1ConfigError(config, usesRepositoryConfig);
|
||||
if (d1ConfigError) {
|
||||
writeSync(2, `${d1ConfigError}\n`);
|
||||
const repositoryConfigError = repositoryWranglerConfigError(config, usesRepositoryConfig);
|
||||
if (repositoryConfigError) {
|
||||
writeSync(2, `${repositoryConfigError}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -137,6 +137,10 @@ export const verifyOnlineHealth = async ({
|
||||
lastFailure = new Error(
|
||||
`Deployed Worker reports database_not_ready at ${healthUrl}. The D1 database verified by Wrangler may differ from the DB binding used by the live Worker.`,
|
||||
);
|
||||
} else if (payload?.error?.code === "object_storage_not_ready") {
|
||||
lastFailure = new Error(
|
||||
`Deployed Worker reports object_storage_not_ready at ${healthUrl}. Check that the RESOURCES binding points to the configured R2 bucket.`,
|
||||
);
|
||||
} else {
|
||||
const diagnostic = payload?.error?.code || `${response.status} ${response.statusText}`.trim();
|
||||
lastFailure = new Error(`Deployed Worker health check failed at ${healthUrl}: ${diagnostic}.`);
|
||||
|
||||
@@ -1,20 +1,45 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { createHash } from "node:crypto";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
export const PLACEHOLDER_D1_ID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
export const repositoryD1ConfigError = (config, usesRepositoryConfig) => {
|
||||
const REPOSITORY_WRANGLER_VALUES = {
|
||||
name: "edgeever",
|
||||
workers_dev: "true",
|
||||
database_name: "edgeever",
|
||||
database_id: PLACEHOLDER_D1_ID,
|
||||
bucket_name: "edgeever-resources",
|
||||
preview_bucket_name: "edgeever-resources-preview",
|
||||
};
|
||||
const REPOSITORY_WRANGLER_SHA256 = "d49ed530169a8597d2c17d5c6b99e03e371c8710124bbce4e526cf2b3a720f7a";
|
||||
|
||||
const configValue = (config, key) => {
|
||||
const match = config.match(new RegExp(`^${key}\\s*=\\s*(?:"([^"]*)"|(true|false))`, "m"));
|
||||
return match?.[1] ?? match?.[2];
|
||||
};
|
||||
|
||||
export const repositoryWranglerConfigError = (config, usesRepositoryConfig) => {
|
||||
if (!usesRepositoryConfig) return undefined;
|
||||
|
||||
const configuredId = config.match(/^database_id\s*=\s*"([^"]+)"/m)?.[1];
|
||||
if (configuredId === PLACEHOLDER_D1_ID) return undefined;
|
||||
const changedEntry = Object.entries(REPOSITORY_WRANGLER_VALUES)
|
||||
.find(([key, expected]) => configValue(config, key) !== expected);
|
||||
const instanceSection = ["[[routes]]", "[vars]", "[triggers]"]
|
||||
.find((section) => config.includes(section));
|
||||
const normalizedConfig = config.replace(/\r\n/g, "\n");
|
||||
const repositoryConfigChanged = createHash("sha256")
|
||||
.update(normalizedConfig)
|
||||
.digest("hex") !== REPOSITORY_WRANGLER_SHA256;
|
||||
if (!changedEntry && !instanceSection && !repositoryConfigChanged) return undefined;
|
||||
|
||||
const changedSetting = changedEntry?.[0] ?? instanceSection ?? "tracked file contents";
|
||||
|
||||
return [
|
||||
"Refusing to use an instance-specific D1 database id from the repository wrangler.toml.",
|
||||
`Restore database_id to "${PLACEHOLDER_D1_ID}".`,
|
||||
"Provide the real id through EDGE_EVER_D1_DATABASE_ID, let deployment resolve it by database name,",
|
||||
"or point WRANGLER_CONFIG at an external configuration file.",
|
||||
`Refusing instance-specific setting ${changedSetting} in the repository wrangler.toml.`,
|
||||
"Restore the tracked file from upstream.",
|
||||
"Provide deployment settings through EDGE_EVER_* Workers Builds variables,",
|
||||
"or point WRANGLER_CONFIG at an external configuration file for an advanced deployment.",
|
||||
].join(" ");
|
||||
};
|
||||
|
||||
|
||||
@@ -51,6 +51,32 @@ describe("production authentication guard", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("reports a missing R2 binding as object_storage_not_ready", async () => {
|
||||
const response = await fetchApi("/api/health", {
|
||||
DB: createDatabase({ userId: "owner" }),
|
||||
EDGE_EVER_AUTH_PASSWORD: "configured-secret",
|
||||
});
|
||||
|
||||
expect(response.status).toBe(503);
|
||||
expect(await response.json()).toEqual({
|
||||
error: {
|
||||
code: "object_storage_not_ready",
|
||||
message: "Object storage is not configured. Bind RESOURCES and redeploy.",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("reports healthy only when D1, authentication, and object storage are ready", async () => {
|
||||
const response = await fetchApi("/api/health", {
|
||||
DB: createDatabase({ userId: "owner" }),
|
||||
RESOURCES: {},
|
||||
EDGE_EVER_AUTH_PASSWORD: "configured-secret",
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(await response.json()).toMatchObject({ ok: true });
|
||||
});
|
||||
|
||||
test("does not misreport transient D1 failures as unapplied migrations", async () => {
|
||||
const response = await fetchApi("/api/health", {
|
||||
DB: createDatabase({ error: new Error("D1_ERROR: Network connection lost.") }),
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
manualDeploymentCopy,
|
||||
} from "../apps/site/src/deployment-prompts";
|
||||
import { decideUpstreamSync } from "../scripts/upstream-sync-plan.mjs";
|
||||
import { repositoryD1ConfigError } from "../scripts/wrangler-runner.mjs";
|
||||
import { repositoryWranglerConfigError } from "../scripts/wrangler-runner.mjs";
|
||||
|
||||
const repositoryRoot = resolve(import.meta.dir, "..");
|
||||
const normalizeLineEndings = (value: string) => value.replace(/\r\n/g, "\n");
|
||||
@@ -122,6 +122,17 @@ describe("Cloudflare deployment entrypoints", () => {
|
||||
expect(chineseGuide).toContain("Worker 运行时 Secret,不是 Workers Builds 构建变量");
|
||||
});
|
||||
|
||||
test("Workers Builds receives configuration but never the runtime password", () => {
|
||||
const setup = readRepositoryFile("scripts/cloudflare-workers-builds.mjs");
|
||||
|
||||
expect(setup).toContain('"AUTH_USERNAME"');
|
||||
expect(setup).toContain('"AUTH_LOGIN_WINDOW_SECONDS"');
|
||||
expect(setup).not.toContain('"AUTH_PASSWORD",');
|
||||
expect(setup).not.toContain('"AUTH_PASSWORD_HASH",');
|
||||
expect(setup).not.toContain("Missing EDGE_EVER_AUTH_PASSWORD");
|
||||
expect(setup).toContain("is_secret: false");
|
||||
});
|
||||
|
||||
test("online deployment resolves the D1 id without editing the repository config", () => {
|
||||
const runner = readRepositoryFile("scripts/run-wrangler.mjs");
|
||||
const wranglerConfig = readRepositoryFile("wrangler.toml");
|
||||
@@ -133,32 +144,36 @@ describe("Cloudflare deployment entrypoints", () => {
|
||||
);
|
||||
expect(runner).toContain('"d1", "list", "--json"');
|
||||
expect(runner).toContain("findD1DatabaseIdByName");
|
||||
expect(runner).toContain("repositoryD1ConfigError(config, usesRepositoryConfig)");
|
||||
expect(runner).toContain("repositoryWranglerConfigError(config, usesRepositoryConfig)");
|
||||
expect(runner).not.toContain("replace the database_id placeholder");
|
||||
expect(englishAgentDoc).toContain("automatically resolves the D1 UUID");
|
||||
expect(chineseAgentDoc).toContain("自动查询 D1 UUID");
|
||||
});
|
||||
|
||||
test("rejects an instance-specific D1 id in the repository Wrangler config", () => {
|
||||
const instanceConfig = [
|
||||
'name = "edgeever"',
|
||||
'database_name = "edgeever"',
|
||||
'database_id = "11111111-1111-1111-1111-111111111111"',
|
||||
"",
|
||||
].join("\n");
|
||||
const placeholderConfig = instanceConfig.replace(
|
||||
"11111111-1111-1111-1111-111111111111",
|
||||
"00000000-0000-0000-0000-000000000000",
|
||||
);
|
||||
test("rejects instance-specific values in the repository Wrangler config", () => {
|
||||
const repositoryConfig = readRepositoryFile("wrangler.toml");
|
||||
const instanceConfigs = [
|
||||
repositoryConfig.replace('name = "edgeever"', 'name = "my-notes"'),
|
||||
repositoryConfig.replace("workers_dev = true", "workers_dev = false"),
|
||||
repositoryConfig.replace('database_name = "edgeever"', 'database_name = "my-notes"'),
|
||||
repositoryConfig.replace(
|
||||
'database_id = "00000000-0000-0000-0000-000000000000"',
|
||||
'database_id = "11111111-1111-1111-1111-111111111111"',
|
||||
),
|
||||
repositoryConfig.replace('bucket_name = "edgeever-resources"', 'bucket_name = "my-notes"'),
|
||||
repositoryConfig.replace('compatibility_date = "2026-06-26"', 'compatibility_date = "2026-08-17"'),
|
||||
`${repositoryConfig}\n[vars]\nEDGE_EVER_AUTH_USERNAME = "owner"\n`,
|
||||
`${repositoryConfig}\n[[routes]]\npattern = "notes.example.com"\ncustom_domain = true\n`,
|
||||
];
|
||||
|
||||
const error = repositoryD1ConfigError(instanceConfig, true);
|
||||
expect(error).toContain(
|
||||
"Refusing to use an instance-specific D1 database id from the repository wrangler.toml",
|
||||
);
|
||||
expect(error).toContain("EDGE_EVER_D1_DATABASE_ID");
|
||||
expect(error).toContain("WRANGLER_CONFIG");
|
||||
expect(repositoryD1ConfigError(placeholderConfig, true)).toBeUndefined();
|
||||
expect(repositoryD1ConfigError(instanceConfig, false)).toBeUndefined();
|
||||
for (const instanceConfig of instanceConfigs) {
|
||||
const error = repositoryWranglerConfigError(instanceConfig, true);
|
||||
expect(error).toContain("Refusing instance-specific setting");
|
||||
expect(error).toContain("EDGE_EVER_*");
|
||||
expect(error).toContain("WRANGLER_CONFIG");
|
||||
}
|
||||
expect(repositoryWranglerConfigError(repositoryConfig, true)).toBeUndefined();
|
||||
expect(repositoryWranglerConfigError(instanceConfigs[0], false)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("keeps D1 resolver diagnostics out of Wrangler JSON stdout", () => {
|
||||
|
||||
@@ -112,4 +112,14 @@ describe("deployment verification", () => {
|
||||
}, { status: 503 }),
|
||||
})).rejects.toThrow("may differ from the DB binding used by the live Worker");
|
||||
});
|
||||
|
||||
test("diagnoses a live Worker without its R2 binding", async () => {
|
||||
expect(verifyOnlineHealth({
|
||||
deploymentUrl: "https://notes.example.com",
|
||||
attempts: 1,
|
||||
fetchImpl: async () => Response.json({
|
||||
error: { code: "object_storage_not_ready" },
|
||||
}, { status: 503 }),
|
||||
})).rejects.toThrow("RESOURCES binding points to the configured R2 bucket");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user