@twikoojs/edgeone-makers 0.0.1 → 2.0.9
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/LICENSE +21 -0
- package/README.md +59 -14
- package/dist/cloud-functions/index.js +3 -3
- package/package.json +18 -14
- package/dist/cloud-functions/index.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020-present iMaeGoo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -8,13 +8,21 @@ Twikoo 2.0 服务端适配器。业务逻辑在 `@twikoojs/common`,本包仅
|
|
|
8
8
|
在控制台「创建项目 → 直接上传」时上传该 ZIP 即可。完整步骤(含自定义域名与 HTTPS 证书)
|
|
9
9
|
见[文档站](https://twikoo.js.org/backend)。
|
|
10
10
|
|
|
11
|
-
那个 ZIP
|
|
11
|
+
那个 ZIP 是**最小部署包**(三个文件,约 5 KB),只声明依赖 + 一个 Go 桥接源码:
|
|
12
12
|
|
|
13
13
|
| ZIP 内路径 | 内容 |
|
|
14
14
|
| --- | --- |
|
|
15
15
|
| `cloud-functions/index.js` | 一行转发:`export { onRequest } from "@twikoojs/edgeone-makers"` |
|
|
16
|
+
| `cloud-functions/smtp.go` | SMTP 桥接(Go 函数,映射到 `/smtp`),供自建 SMTP 通道使用 |
|
|
16
17
|
| `package.json` | `dependencies: { "@twikoojs/edgeone-makers": "latest" }` |
|
|
17
18
|
|
|
19
|
+
`package.json` 的 `files` 白名单写的是 `dist/cloud-functions/index.js`(而不是整个 `dist`):
|
|
20
|
+
本包唯一要交付的就是那个入口,**sourcemap 不进 npm 包**(7.9 MB,对平台无意义)。
|
|
21
|
+
注意 npm 在 `files` 存在时会忽略根 `.npmignore`,所以排除只能靠白名单本身。
|
|
22
|
+
|
|
23
|
+
**数据库零配置**:评论数据存在平台自动提供的 **Blob KV**(`@edgeone/pages-blob`,强一致读取)中,
|
|
24
|
+
首次写入时平台自动创建命名空间,用户不需要配置任何东西,也不需要自备数据库。
|
|
25
|
+
|
|
18
26
|
**本包在流水线中的角色**:`npm run build` 产出 `dist/`(发布到 npm 的实现)与上面那个 ZIP。
|
|
19
27
|
两者分工的依据是两条**实测确认**的平台行为(2026-09-24,真实项目):
|
|
20
28
|
|
|
@@ -31,7 +39,8 @@ Twikoo 2.0 服务端适配器。业务逻辑在 `@twikoojs/common`,本包仅
|
|
|
31
39
|
- `context` 实测键:`clientIp` / `env` / `geo` / `params` / `request` / `server` / `uuid`
|
|
32
40
|
- `context.clientIp` 可用;环境变量 `context.env` 与 `process.env` 高度重叠,入口以
|
|
33
41
|
`context.env` 为准合并进 `process.env`(`@twikoojs/common` 按 Node 惯例读后者)
|
|
34
|
-
- 运行时 **Node v20.19.3
|
|
42
|
+
- 运行时 **Node v20.19.3**;构建环境默认 Node v22.21.1,可在「项目设置 → Node.js 版本」调整
|
|
43
|
+
(文档站部署步骤要求设为 **24.18.0**;该项变更需再部署一次才生效)
|
|
35
44
|
- 默认域名(`*.edgeone.cool`)**仅 3 小时限时预览**,不带校验参数直接访问返回 401,
|
|
36
45
|
故生产必须绑定自定义域名
|
|
37
46
|
- **静态资源与函数路由冲突时静态资源优先**:根目录存在 `index.html` 时 `/` 返回网页而非函数
|
|
@@ -40,10 +49,36 @@ Twikoo 2.0 服务端适配器。业务逻辑在 `@twikoojs/common`,本包仅
|
|
|
40
49
|
- 平台侧打包器**解析不到任何裸导入就直接构建失败**(实测报
|
|
41
50
|
`✘ [ERROR] Could not resolve "nodemailer"`)
|
|
42
51
|
|
|
43
|
-
###
|
|
52
|
+
### 自建 SMTP 通道
|
|
53
|
+
|
|
54
|
+
Node 侧无法直连 SMTP,故由**同项目**的 Go 函数 `cloud-functions/smtp.go`(路由 `/smtp`)承担
|
|
55
|
+
「HTTP → SMTP」转发 —— **不需要另外部署一个桥接服务**。Node 侧的客户端在
|
|
56
|
+
`src/mail/smtp-bridge.ts`,两侧的请求/响应字段必须一致。
|
|
57
|
+
|
|
58
|
+
桥接地址由客户端自行推断(`createMailBridgeContext`):按「请求体里的 `envId` → `Origin` 头 →
|
|
59
|
+
`Host` 头」依次取候选,再统一规范到路径 `/smtp`,逐个探测直到有一个通过校验。
|
|
60
|
+
**没有需要用户填写的桥接地址配置**。
|
|
61
|
+
|
|
62
|
+
实测(2026-09-24)三个候选的真实取值:
|
|
44
63
|
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
| 候选 | 实际值 | 可用性 |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| 请求体 `envId` | 前端配置的 Twikoo 地址(如 `https://twikooeo.imaegoo.com`) | ✅ 正确,且**前端必带**(`client/src/utils/api.ts` 每次请求都塞 `envId`) |
|
|
67
|
+
| `Origin` 头 | 博客站点自己的域名 | ❌ 不是 Makers 域名,`<blog>/smtp` 不存在 |
|
|
68
|
+
| `Host` 头 | 平台内部域名(如 `pages-pro-13-…qcloudteo.com`) | ❌ 平台会改写 `Host` |
|
|
69
|
+
|
|
70
|
+
也就是说**桥接发现实际依赖 `envId`**;前两者只是 1.x 遗留的兜底。真实场景下前端必带 `envId`,
|
|
71
|
+
故可用;但若某个调用方不带 `envId`,会看到「自动发现失败」并列出那个内部域名候选 —— 属预期行为。
|
|
72
|
+
|
|
73
|
+
启用步骤:
|
|
74
|
+
|
|
75
|
+
1. 在项目环境变量中配置 `TWIKOO_SMTP_BRIDGE_TOKEN`(随机长字符串,**不是** SMTP 密码),
|
|
76
|
+
可用 `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` 生成
|
|
77
|
+
2. 在 Twikoo 管理面板配置 `SMTP_HOST` / `SMTP_PORT` / `SMTP_SECURE` / `SMTP_USER` / `SMTP_PASS` / `SENDER_EMAIL`
|
|
78
|
+
3. **不要**同时配置 `SMTP_SERVICE` —— 配了会走 SendGrid / MailChannels 的 HTTP 通道,不经过 Go 桥接
|
|
79
|
+
|
|
80
|
+
> 已实测(2026-09-24):Go 桥接随部署包编译并注册 `/smtp` 路由(控制台「函数」页显示
|
|
81
|
+
> `{ routePath: "/smtp", runtime: "Go" }`),且**真实投递成功** —— 详见下方核对清单。
|
|
47
82
|
|
|
48
83
|
## 构建
|
|
49
84
|
|
|
@@ -58,19 +93,26 @@ specifier 解析不到。
|
|
|
58
93
|
| --- | --- |
|
|
59
94
|
| `build-ip2region-data.mjs` | `src/ip2region/generated/ip2region-data.js`(**不进 git**) |
|
|
60
95
|
| `tsdown` | `dist/cloud-functions/index.js`(单文件,约 7.4 MB,含内联数据) |
|
|
61
|
-
| `build-zip.mjs` | `templates/edgeone-makers/twikoo-edgeone-makers.zip` |
|
|
96
|
+
| `build-zip.mjs` | `templates/edgeone-makers/twikoo-edgeone-makers.zip`(入口 + `smtp.go` + `package.json`) |
|
|
62
97
|
|
|
63
98
|
### 为什么 ip2region 数据必须内联
|
|
64
99
|
|
|
65
100
|
`@imaegoo/node-ip2region` 的 `binarySearchSync` 靠 `fs` 随机读 8.33 MB 的 db,而平台上
|
|
66
101
|
没有可读的兄弟数据文件。1.x 的做法是把 db gzip + base64 成独立模块、运行时按相对路径
|
|
67
|
-
**懒加载**;2.0
|
|
102
|
+
**懒加载**;2.0 改成**内联进函数单文件**,理由有两条:
|
|
103
|
+
|
|
104
|
+
1. **平台「构建产物」页只列出 `package.json` / `package-lock.json`**,`cloud-functions/`
|
|
105
|
+
下的兄弟文件不在其中(函数运行时是打包器打出的单文件 `/var/user/index.mjs`)。
|
|
106
|
+
兄弟文件能否落到运行时目录属**未文档化行为**,且失效时是**静默的**
|
|
107
|
+
—— `comment-dto` 的 `try/catch` 会把异常吞成「属地为空」,站长和访客都看不到报错。
|
|
108
|
+
2. **最小部署包形态要求如此**:函数实现来自 npm 上的本包,无法携带兄弟文件。
|
|
68
109
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
> (被 `comment-dto` 的 `try/catch` 吞掉,**站长和访客都看不到任何报错**)。
|
|
110
|
+
内联后不再依赖平台是否复制非入口文件。代价是产物从 ~950 KB 涨到 ~7.4 MB
|
|
111
|
+
(gzip 后约 226 KB),换来的是确定性。
|
|
72
112
|
|
|
73
|
-
|
|
113
|
+
> 顺带记一条排查经验:`ipRegion` 为空**未必**是数据没加载 —— `comment-dto` 里
|
|
114
|
+
> `ipRegion: showRegion ? … : ""`,配置项 `SHOW_REGION` 未开启时一律为空。
|
|
115
|
+
> 判断数据是否可用要先把 `SHOW_REGION` 打开(实测开启后返回 `河南`,说明内联数据可用)。
|
|
74
116
|
|
|
75
117
|
| 阶段 | 大小 |
|
|
76
118
|
| --- | --- |
|
|
@@ -78,7 +120,6 @@ specifier 解析不到。
|
|
|
78
120
|
| gzip -9 | 4.54 MB |
|
|
79
121
|
| base64(4/3 膨胀) | 6.06 MB |
|
|
80
122
|
|
|
81
|
-
代价是产物从 ~950 KB 涨到 ~7.4 MB(gzip 后约 226 KB),换来的是**真的能用**。
|
|
82
123
|
`getIp2RegionOverride()` 里的 specifier 必须是**字面量**,改成变量就会静默失去 IP 属地
|
|
83
124
|
(`src/ip2region/inline.ts` 里有详细说明;`loadIp2RegionOverride(specifier)` 那条参数化
|
|
84
125
|
路径只服务于降级测试)。
|
|
@@ -119,8 +160,12 @@ npm test
|
|
|
119
160
|
- [x] `context.clientIp` 可用(实测取到公网 IP)
|
|
120
161
|
- [x] 运行时 Node **v20.19.3**(构建环境为 v22.21.1)
|
|
121
162
|
- [x] 平台会 `npm install` 部署包声明的依赖,并把函数打成单文件
|
|
122
|
-
- [x]
|
|
163
|
+
- [x] 「构建产物」只列出 `package.json` / `package-lock.json`(`cloud-functions/` 下的兄弟文件不在其中)
|
|
123
164
|
- [x] `@edgeone/pages-blob` **平台不自带**,需由依赖提供
|
|
124
165
|
- [x] 默认域名仅 3 小时限时预览,生产必须绑定自定义域名
|
|
125
166
|
- [x] 端到端:`GET /` 健康检查、`GET_FUNC_VERSION`、`COMMENT_SUBMIT` 写入、`GET_COMMENTS_COUNT` 读取
|
|
126
|
-
- [
|
|
167
|
+
- [x] IP 属地:`SHOW_REGION=true` 时返回真实属地(如 `河南`),内联数据可用
|
|
168
|
+
- [x] 最小部署包(ZIP 仅 `cloud-functions/index.js` + `cloud-functions/smtp.go` + `package.json`)真实部署跑通
|
|
169
|
+
- [x] Go SMTP Bridge:随部署包编译(构建日志 `Go functions build completed: 1 functions (handler mode)`)、
|
|
170
|
+
路由注册为 `{ routePath: "/smtp", runtime: "Go" }`、**真实投递成功**
|
|
171
|
+
(正确密码 → `{"result":{"ok":true,"message":"ok"}}`;错误密码 → `SMTP auth failed`,非假阳性)
|