@rei-standard/amsg-server 1.2.1 → 2.0.1

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/README.md CHANGED
@@ -1,17 +1,18 @@
1
1
  # @rei-standard/amsg-server
2
2
 
3
- `@rei-standard/amsg-server` 是 ReiStandard 主动消息标准的服务端 SDK 包。
3
+ `@rei-standard/amsg-server` 是 ReiStandard 主动消息标准的服务端 SDK(v2.0.1),提供 Blob 租户配置、租户 token 鉴权和标准路由处理器。
4
4
 
5
- ## 文档导航
5
+ ## v2.0.1 变更摘要
6
6
 
7
- - [SDK 总览](../README.md)
8
- - [主 README](../../../README.md)
9
- - [API 技术规范](../../../standards/active-messaging-api.md)
7
+ - 初始化流程合并为 `POST /api/v1/init-tenant`
8
+ - 移除旧端点:`init-database`、`init-master-key`
9
+ - 业务端点统一使用 `Authorization: Bearer <tenantToken>`
10
+ - `send-notifications` 支持 `cronToken`(Header 或 query token)
10
11
 
11
12
  ## 安装
12
13
 
13
14
  ```bash
14
- npm install @rei-standard/amsg-server web-push
15
+ npm install @rei-standard/amsg-server web-push @netlify/blobs
15
16
 
16
17
  # 数据库驱动二选一
17
18
  npm install @neondatabase/serverless
@@ -19,43 +20,96 @@ npm install @neondatabase/serverless
19
20
  npm install pg
20
21
  ```
21
22
 
22
- ## 使用
23
+ ## 快速使用
23
24
 
24
25
  ```js
25
26
  import { createReiServer } from '@rei-standard/amsg-server';
26
27
 
27
28
  const rei = await createReiServer({
28
- db: {
29
- driver: 'neon',
30
- connectionString: process.env.DATABASE_URL
31
- },
32
- cronSecret: process.env.CRON_SECRET,
33
29
  vapid: {
34
30
  email: process.env.VAPID_EMAIL,
35
31
  publicKey: process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY,
36
32
  privateKey: process.env.VAPID_PRIVATE_KEY
33
+ },
34
+ tenant: {
35
+ blobNamespace: 'rei-tenants',
36
+ kek: process.env.TENANT_CONFIG_KEK,
37
+ tokenSigningKey: process.env.TENANT_TOKEN_SIGNING_KEY,
38
+ initSecret: process.env.INIT_SECRET,
39
+ publicBaseUrl: process.env.PUBLIC_BASE_URL
37
40
  }
38
41
  });
42
+
43
+ // 映射路由
44
+ // POST /api/v1/init-tenant -> rei.handlers.initTenant.POST
45
+ // GET /api/v1/get-user-key -> rei.handlers.getUserKey.GET
46
+ // POST /api/v1/schedule-message -> rei.handlers.scheduleMessage.POST
47
+ // POST /api/v1/send-notifications -> rei.handlers.sendNotifications.POST
48
+ // PUT /api/v1/update-message -> rei.handlers.updateMessage.PUT
49
+ // DELETE /api/v1/cancel-message -> rei.handlers.cancelMessage.DELETE
50
+ // GET /api/v1/messages -> rei.handlers.messages.GET
39
51
  ```
40
52
 
41
- 导出的标准 handler:
53
+ ## AI 接口 `apiUrl` 约束
54
+
55
+ 当 `messageType` 为 `prompted` / `auto`,或 `instant` 使用 AI 配置时:
56
+
57
+ - `apiUrl` 必须是完整聊天端点(例如:`https://api.openai.com/v1/chat/completions`)。
58
+ - SDK 会自动做最小规范化:去首尾空白、去路径尾部多余 `/`。
59
+ - SDK **不会**自动补全 `/v1`、`/chat/completions` 等路径。
60
+ - `maxTokens` 为可选字段:传了就映射为 `max_tokens`;不传则不指定(由上游模型默认策略决定)。
61
+
62
+ 如果上游返回 `405 Method Not Allowed`,通常表示 `apiUrl` 指向了基础域名而非聊天端点,请优先检查配置值。
63
+
64
+ ## 一体化初始化流程
65
+
66
+ 1. 管理员配置环境变量(VAPID + tenant secrets)
67
+ 2. 租户调用 `POST /api/v1/init-tenant` 提交自己的 `databaseUrl`
68
+ 3. 服务端自动完成:建表 + 生成 masterKey + 写入 Blob + 返回 `tenantToken`/`cronToken`
69
+ 4. 前端使用 `tenantToken`,cron 使用 `cronToken`
70
+
71
+ ## 端点鉴权
72
+
73
+ - `get-user-key`、`schedule-message`、`update-message`、`cancel-message`、`messages`
74
+ - `Authorization: Bearer <tenantToken>`
75
+ - `send-notifications`
76
+ - `Authorization: Bearer <cronToken>` 或 `?token=<cronToken>`
77
+
78
+ ## 导出 API(Exports)
42
79
 
43
- - `rei.handlers.initDatabase`
44
- - `rei.handlers.initMasterKey`
45
- - `rei.handlers.getUserKey`
46
- - `rei.handlers.scheduleMessage`
47
- - `rei.handlers.sendNotifications`
48
- - `rei.handlers.updateMessage`
49
- - `rei.handlers.cancelMessage`
50
- - `rei.handlers.messages`
80
+ - `createReiServer`
81
+ - `createAdapter`
82
+ - `createTenantToken`
83
+ - `verifyTenantToken`
84
+ - `deriveUserEncryptionKey`
85
+ - `decryptPayload`
86
+ - `encryptForStorage`
87
+ - `decryptFromStorage`
88
+ - `validateScheduleMessagePayload`
89
+ - `isValidISO8601`
90
+ - `isValidUrl`
91
+ - `isValidUUID`
92
+ - `isValidUUIDv4`
51
93
 
52
- 推荐初始化顺序:
94
+ ## 运行环境与要求
53
95
 
54
- 1. 调用 `initDatabase.GET`(幂等创建表)
55
- 2. 调用 `initMasterKey.POST`(一次性初始化系统密钥)
56
- 3. 客户端携带 UUID v4 `X-User-Id` 调用 `getUserKey.GET`
96
+ - Node.js `>=20`
97
+ - 必须安装 `web-push`
98
+ - 必须安装 `@netlify/blobs`
99
+ - 必须安装至少一个数据库驱动(`@neondatabase/serverless` 或 `pg`)
100
+ - 必须配置:
101
+ - `VAPID_EMAIL`
102
+ - `NEXT_PUBLIC_VAPID_PUBLIC_KEY`
103
+ - `VAPID_PRIVATE_KEY`
104
+ - `TENANT_CONFIG_KEK`
105
+ - `TENANT_TOKEN_SIGNING_KEY`
106
+ - 可选配置:
107
+ - `INIT_SECRET`(配置后 `init-tenant` 必须带 `X-Init-Secret`)
57
108
 
58
- ## 相关包
109
+ ## 相关链接(绝对 URL)
59
110
 
60
- - 浏览器 SDK:[`@rei-standard/amsg-client`](../client/README.md)
61
- - Service Worker SDK:[`@rei-standard/amsg-sw`](../sw/README.md)
111
+ - [SDK Workspace 总览](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/README.md)
112
+ - [Client 包 README](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/client/README.md)
113
+ - [SW 包 README](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/sw/README.md)
114
+ - [API 技术规范](https://github.com/Tosd0/ReiStandard/blob/main/standards/active-messaging-api.md)
115
+ - [Service Worker 规范](https://github.com/Tosd0/ReiStandard/blob/main/standards/service-worker-specification.md)
@@ -13,14 +13,6 @@ var TABLE_SQL = `
13
13
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
14
14
  )
15
15
  `;
16
- var SYSTEM_CONFIG_SQL = `
17
- CREATE TABLE IF NOT EXISTS system_config (
18
- key TEXT PRIMARY KEY,
19
- value TEXT NOT NULL,
20
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
21
- updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
22
- )
23
- `;
24
16
  var INDEXES = [
25
17
  {
26
18
  name: "idx_pending_tasks_optimized",
@@ -64,12 +56,6 @@ var VERIFY_TABLE_SQL = `
64
56
  WHERE table_schema = 'public'
65
57
  AND table_name = 'scheduled_messages'
66
58
  `;
67
- var VERIFY_SYSTEM_CONFIG_SQL = `
68
- SELECT table_name
69
- FROM information_schema.tables
70
- WHERE table_schema = 'public'
71
- AND table_name = 'system_config'
72
- `;
73
59
  var COLUMNS_SQL = `
74
60
  SELECT column_name, data_type, is_nullable
75
61
  FROM information_schema.columns
@@ -77,31 +63,10 @@ var COLUMNS_SQL = `
77
63
  AND table_name = 'scheduled_messages'
78
64
  ORDER BY ordinal_position
79
65
  `;
80
- var SYSTEM_CONFIG_COLUMNS_SQL = `
81
- SELECT column_name, data_type, is_nullable
82
- FROM information_schema.columns
83
- WHERE table_schema = 'public'
84
- AND table_name = 'system_config'
85
- ORDER BY ordinal_position
86
- `;
87
- var REQUIRED_COLUMNS = [
88
- "id",
89
- "user_id",
90
- "uuid",
91
- "encrypted_payload",
92
- "message_type",
93
- "next_send_at",
94
- "status",
95
- "retry_count"
96
- ];
97
66
 
98
67
  export {
99
68
  TABLE_SQL,
100
- SYSTEM_CONFIG_SQL,
101
69
  INDEXES,
102
70
  VERIFY_TABLE_SQL,
103
- VERIFY_SYSTEM_CONFIG_SQL,
104
- COLUMNS_SQL,
105
- SYSTEM_CONFIG_COLUMNS_SQL,
106
- REQUIRED_COLUMNS
71
+ COLUMNS_SQL
107
72
  };
@@ -13,14 +13,6 @@ var TABLE_SQL = `
13
13
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
14
14
  )
15
15
  `;
16
- var SYSTEM_CONFIG_SQL = `
17
- CREATE TABLE IF NOT EXISTS system_config (
18
- key TEXT PRIMARY KEY,
19
- value TEXT NOT NULL,
20
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
21
- updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
22
- )
23
- `;
24
16
  var INDEXES = [
25
17
  {
26
18
  name: "idx_pending_tasks_optimized",
@@ -64,12 +56,6 @@ var VERIFY_TABLE_SQL = `
64
56
  WHERE table_schema = 'public'
65
57
  AND table_name = 'scheduled_messages'
66
58
  `;
67
- var VERIFY_SYSTEM_CONFIG_SQL = `
68
- SELECT table_name
69
- FROM information_schema.tables
70
- WHERE table_schema = 'public'
71
- AND table_name = 'system_config'
72
- `;
73
59
  var COLUMNS_SQL = `
74
60
  SELECT column_name, data_type, is_nullable
75
61
  FROM information_schema.columns
@@ -77,31 +63,10 @@ var COLUMNS_SQL = `
77
63
  AND table_name = 'scheduled_messages'
78
64
  ORDER BY ordinal_position
79
65
  `;
80
- var SYSTEM_CONFIG_COLUMNS_SQL = `
81
- SELECT column_name, data_type, is_nullable
82
- FROM information_schema.columns
83
- WHERE table_schema = 'public'
84
- AND table_name = 'system_config'
85
- ORDER BY ordinal_position
86
- `;
87
- var REQUIRED_COLUMNS = [
88
- "id",
89
- "user_id",
90
- "uuid",
91
- "encrypted_payload",
92
- "message_type",
93
- "next_send_at",
94
- "status",
95
- "retry_count"
96
- ];
97
-
98
-
99
-
100
-
101
66
 
102
67
 
103
68
 
104
69
 
105
70
 
106
71
 
107
- exports.TABLE_SQL = TABLE_SQL; exports.SYSTEM_CONFIG_SQL = SYSTEM_CONFIG_SQL; exports.INDEXES = INDEXES; exports.VERIFY_TABLE_SQL = VERIFY_TABLE_SQL; exports.VERIFY_SYSTEM_CONFIG_SQL = VERIFY_SYSTEM_CONFIG_SQL; exports.COLUMNS_SQL = COLUMNS_SQL; exports.SYSTEM_CONFIG_COLUMNS_SQL = SYSTEM_CONFIG_COLUMNS_SQL; exports.REQUIRED_COLUMNS = REQUIRED_COLUMNS;
72
+ exports.TABLE_SQL = TABLE_SQL; exports.INDEXES = INDEXES; exports.VERIFY_TABLE_SQL = VERIFY_TABLE_SQL; exports.COLUMNS_SQL = COLUMNS_SQL;