@h-ai/reach 1.0.0-beta.18 → 1.0.0-beta.19
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.en.md +51 -13
- package/README.ja.md +51 -13
- package/README.md +51 -13
- package/dist/index.d.ts +2 -1
- package/dist/index.js +496 -280
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/README.en.md
CHANGED
|
@@ -23,7 +23,7 @@ Template sends need only `template`, `to` and `vars`; the provider comes from th
|
|
|
23
23
|
|
|
24
24
|
### Dependencies
|
|
25
25
|
|
|
26
|
-
- `@h-ai/reldb`: persistence for delivery logs and templates.
|
|
26
|
+
- `@h-ai/reldb`: persistence for delivery logs and templates. Initialize it before configuring nonempty `templates` or DND delay. Failed template persistence or required table preparation makes `reach.init()` return `CONFIG_ERROR` and close candidate providers. Optional for immediate sends without templates or delayed queues.
|
|
27
27
|
- `@h-ai/cache`: optional distributed locks for DND delay; enabled automatically when initialized.
|
|
28
28
|
|
|
29
29
|
### Quick start
|
|
@@ -39,31 +39,69 @@ Install `nodemailer` for email delivery.
|
|
|
39
39
|
#### Initialize multiple providers
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
+
import { core } from '@h-ai/core'
|
|
42
43
|
import { reach } from '@h-ai/reach'
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
import { reldb } from '@h-ai/reldb'
|
|
45
|
+
|
|
46
|
+
const runtime = core.module.createRuntime([
|
|
47
|
+
{
|
|
48
|
+
name: 'reldb',
|
|
49
|
+
start: () => reldb.init({ type: 'sqlite', database: ':memory:' }),
|
|
50
|
+
close: () => reldb.close()
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'reach',
|
|
54
|
+
start: () => reach.init({
|
|
55
|
+
providers: [
|
|
56
|
+
{ name: 'local', type: 'console' }
|
|
57
|
+
],
|
|
58
|
+
templates: [
|
|
59
|
+
{
|
|
60
|
+
name: 'welcome',
|
|
61
|
+
provider: 'local',
|
|
62
|
+
subject: 'Welcome',
|
|
63
|
+
body: 'Hello {userName}'
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
}),
|
|
67
|
+
close: () => reach.close()
|
|
68
|
+
},
|
|
69
|
+
])
|
|
70
|
+
const initialized = await runtime.start()
|
|
48
71
|
if (!initialized.success)
|
|
49
72
|
throw new Error(initialized.error.message)
|
|
73
|
+
|
|
74
|
+
let result: Awaited<ReturnType<typeof reach.send>>
|
|
50
75
|
try {
|
|
51
|
-
|
|
76
|
+
result = await reach.send({
|
|
52
77
|
to: 'user@example.com',
|
|
53
78
|
template: 'welcome',
|
|
54
|
-
vars: { userName: 'Alice' }
|
|
79
|
+
vars: { userName: 'Alice' }
|
|
55
80
|
})
|
|
56
|
-
if (!result.success)
|
|
57
|
-
throw new Error(result.error.message)
|
|
58
81
|
}
|
|
59
|
-
|
|
60
|
-
await
|
|
82
|
+
catch (error) {
|
|
83
|
+
const closed = await runtime.close()
|
|
84
|
+
throw new AggregateError(closed.success
|
|
85
|
+
? [error]
|
|
86
|
+
: [error, closed.error], 'Reach operation failed')
|
|
61
87
|
}
|
|
88
|
+
const closed = await runtime.close()
|
|
89
|
+
if (!closed.success) {
|
|
90
|
+
throw new AggregateError(result.success
|
|
91
|
+
? [closed.error]
|
|
92
|
+
: [result.error, closed.error], 'Reach cleanup failed')
|
|
93
|
+
}
|
|
94
|
+
if (!result.success)
|
|
95
|
+
throw new Error(result.error.message)
|
|
62
96
|
```
|
|
63
97
|
|
|
64
98
|
This example uses the development Console provider. It records delivery metadata and does not send email or SMS. Configure SMTP, SMS or API providers below for real delivery; initialize optional persistence/shared cache when needed.
|
|
65
99
|
|
|
66
|
-
`reach.config` returns a **redacted configuration snapshot**. Embedded credentials in `api.url` / `endpoint`,
|
|
100
|
+
`reach.config` returns a **redacted configuration snapshot**. Embedded credentials in `api.url` / `endpoint`, every custom header value, SMTP `pass` and SMS keys are hidden. Gateway bodies are omitted. Deployment stores API headers entirely in private environment files, regardless of header names.
|
|
101
|
+
|
|
102
|
+
Provider failures retain the complete module error definition, including HTTP status. Raw SMTP/SMS responses are excluded from returned messages and causes; clients receive localized guidance while server logs retain diagnostic context.
|
|
103
|
+
|
|
104
|
+
Each template send uses one template snapshot for its subject, body and default provider, keeping concurrent edits from mixing versions. An explicit `provider` still overrides the template route.
|
|
67
105
|
|
|
68
106
|
### Configuration
|
|
69
107
|
|
package/README.ja.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
### 依存関係
|
|
25
25
|
|
|
26
|
-
- `@h-ai/reldb
|
|
26
|
+
- `@h-ai/reldb`:送信ログ・テンプレートの永続化。空でない `templates` または DND delay を設定する前に初期化します。テンプレートの保存や必須テーブルの準備に失敗した場合、`reach.init()` は候補 Provider を閉じて `CONFIG_ERROR` を返します。テンプレート・延期キューを使わない即時送信では任意です。
|
|
27
27
|
- `@h-ai/cache`:DND delay 用の分散ロック(任意)。初期化済みなら自動有効化。
|
|
28
28
|
|
|
29
29
|
### クイックスタート
|
|
@@ -39,31 +39,69 @@ pnpm add @h-ai/reach
|
|
|
39
39
|
#### 複数 Provider の初期化
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
+
import { core } from '@h-ai/core'
|
|
42
43
|
import { reach } from '@h-ai/reach'
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
import { reldb } from '@h-ai/reldb'
|
|
45
|
+
|
|
46
|
+
const runtime = core.module.createRuntime([
|
|
47
|
+
{
|
|
48
|
+
name: 'reldb',
|
|
49
|
+
start: () => reldb.init({ type: 'sqlite', database: ':memory:' }),
|
|
50
|
+
close: () => reldb.close()
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'reach',
|
|
54
|
+
start: () => reach.init({
|
|
55
|
+
providers: [
|
|
56
|
+
{ name: 'local', type: 'console' }
|
|
57
|
+
],
|
|
58
|
+
templates: [
|
|
59
|
+
{
|
|
60
|
+
name: 'welcome',
|
|
61
|
+
provider: 'local',
|
|
62
|
+
subject: 'Welcome',
|
|
63
|
+
body: 'Hello {userName}'
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
}),
|
|
67
|
+
close: () => reach.close()
|
|
68
|
+
},
|
|
69
|
+
])
|
|
70
|
+
const initialized = await runtime.start()
|
|
48
71
|
if (!initialized.success)
|
|
49
72
|
throw new Error(initialized.error.message)
|
|
73
|
+
|
|
74
|
+
let result: Awaited<ReturnType<typeof reach.send>>
|
|
50
75
|
try {
|
|
51
|
-
|
|
76
|
+
result = await reach.send({
|
|
52
77
|
to: 'user@example.com',
|
|
53
78
|
template: 'welcome',
|
|
54
|
-
vars: { userName: 'Alice' }
|
|
79
|
+
vars: { userName: 'Alice' }
|
|
55
80
|
})
|
|
56
|
-
if (!result.success)
|
|
57
|
-
throw new Error(result.error.message)
|
|
58
81
|
}
|
|
59
|
-
|
|
60
|
-
await
|
|
82
|
+
catch (error) {
|
|
83
|
+
const closed = await runtime.close()
|
|
84
|
+
throw new AggregateError(closed.success
|
|
85
|
+
? [error]
|
|
86
|
+
: [error, closed.error], 'Reach operation failed')
|
|
61
87
|
}
|
|
88
|
+
const closed = await runtime.close()
|
|
89
|
+
if (!closed.success) {
|
|
90
|
+
throw new AggregateError(result.success
|
|
91
|
+
? [closed.error]
|
|
92
|
+
: [result.error, closed.error], 'Reach cleanup failed')
|
|
93
|
+
}
|
|
94
|
+
if (!result.success)
|
|
95
|
+
throw new Error(result.error.message)
|
|
62
96
|
```
|
|
63
97
|
|
|
64
98
|
この例は開発用 Console Provider で送信メタデータを記録し、実メールや SMS は送りません。実送信には下記の SMTP・SMS・API を設定し、必要に応じて永続化と共有キャッシュを初期化してください。
|
|
65
99
|
|
|
66
|
-
`reach.config` は**機密情報をマスクした設定スナップショット**を返します。`api.url` / `endpoint`
|
|
100
|
+
`reach.config` は**機密情報をマスクした設定スナップショット**を返します。`api.url` / `endpoint` 内の認証情報、すべてのカスタムヘッダー値、SMTP の `pass` と SMS の鍵を隠します。ゲートウェイ本文は含めません。デプロイはヘッダー名に依存せず、API ヘッダー全体を非公開の環境ファイルに保存します。
|
|
101
|
+
|
|
102
|
+
Provider の失敗では HTTP ステータスを含む完全なモジュールエラー定義を保持します。SMTP/SMS の生の応答は返却メッセージや cause に含めず、利用者には翻訳済みの案内、サーバーログには診断情報を残します。
|
|
103
|
+
|
|
104
|
+
テンプレート送信は一つのスナップショットから件名・本文・既定 Provider を決め、並行編集による異なる版の混在を防ぎます。明示的な `provider` は従来どおり優先します。
|
|
67
105
|
|
|
68
106
|
### 設定
|
|
69
107
|
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
### 依赖
|
|
25
25
|
|
|
26
|
-
- `@h-ai/reldb` —
|
|
26
|
+
- `@h-ai/reldb` — 数据库(发送日志与模板持久化);配置非空 `templates` 或启用 DND delay 时必须先初始化,模板保存或必需表准备失败时 `reach.init()` 返回 `CONFIG_ERROR` 并关闭候选 Provider。不使用模板/延迟队列的即时发送可选
|
|
27
27
|
- `@h-ai/cache` — 缓存(DND delay 策略分布式锁),可选;已初始化时自动启用分布式锁
|
|
28
28
|
|
|
29
29
|
### 快速开始
|
|
@@ -39,31 +39,69 @@ pnpm add @h-ai/reach
|
|
|
39
39
|
#### 多 Provider 初始化
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
+
import { core } from '@h-ai/core'
|
|
42
43
|
import { reach } from '@h-ai/reach'
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
import { reldb } from '@h-ai/reldb'
|
|
45
|
+
|
|
46
|
+
const runtime = core.module.createRuntime([
|
|
47
|
+
{
|
|
48
|
+
name: 'reldb',
|
|
49
|
+
start: () => reldb.init({ type: 'sqlite', database: ':memory:' }),
|
|
50
|
+
close: () => reldb.close()
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'reach',
|
|
54
|
+
start: () => reach.init({
|
|
55
|
+
providers: [
|
|
56
|
+
{ name: 'local', type: 'console' }
|
|
57
|
+
],
|
|
58
|
+
templates: [
|
|
59
|
+
{
|
|
60
|
+
name: 'welcome',
|
|
61
|
+
provider: 'local',
|
|
62
|
+
subject: 'Welcome',
|
|
63
|
+
body: 'Hello {userName}'
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
}),
|
|
67
|
+
close: () => reach.close()
|
|
68
|
+
},
|
|
69
|
+
])
|
|
70
|
+
const initialized = await runtime.start()
|
|
48
71
|
if (!initialized.success)
|
|
49
72
|
throw new Error(initialized.error.message)
|
|
73
|
+
|
|
74
|
+
let result: Awaited<ReturnType<typeof reach.send>>
|
|
50
75
|
try {
|
|
51
|
-
|
|
76
|
+
result = await reach.send({
|
|
52
77
|
to: 'user@example.com',
|
|
53
78
|
template: 'welcome',
|
|
54
|
-
vars: { userName: 'Alice' }
|
|
79
|
+
vars: { userName: 'Alice' }
|
|
55
80
|
})
|
|
56
|
-
if (!result.success)
|
|
57
|
-
throw new Error(result.error.message)
|
|
58
81
|
}
|
|
59
|
-
|
|
60
|
-
await
|
|
82
|
+
catch (error) {
|
|
83
|
+
const closed = await runtime.close()
|
|
84
|
+
throw new AggregateError(closed.success
|
|
85
|
+
? [error]
|
|
86
|
+
: [error, closed.error], 'Reach operation failed')
|
|
61
87
|
}
|
|
88
|
+
const closed = await runtime.close()
|
|
89
|
+
if (!closed.success) {
|
|
90
|
+
throw new AggregateError(result.success
|
|
91
|
+
? [closed.error]
|
|
92
|
+
: [result.error, closed.error], 'Reach cleanup failed')
|
|
93
|
+
}
|
|
94
|
+
if (!result.success)
|
|
95
|
+
throw new Error(result.error.message)
|
|
62
96
|
```
|
|
63
97
|
|
|
64
98
|
以上示例使用开发 Console Provider,只记录发送元数据,不实际发邮件或短信。需要真实投递时,按下方配置 SMTP、短信或 API Provider;数据库持久化和共享缓存按需初始化。
|
|
65
99
|
|
|
66
|
-
`reach.config` 返回的是**脱敏后的配置快照**:`api.url` / `endpoint`
|
|
100
|
+
`reach.config` 返回的是**脱敏后的配置快照**:`api.url` / `endpoint` 的内嵌凭证、所有自定义请求头值、SMTP `pass` 和短信密钥都会隐藏。网关正文不进入快照;部署向导把 API 请求头整体保存到私有环境文件,不依赖头名猜测认证信息。
|
|
101
|
+
|
|
102
|
+
Provider 失败保留完整模块错误定义(含 HTTP 状态),SMTP/短信原始响应不进入返回消息或 cause;前端使用本地化提示,服务端日志保留诊断上下文。
|
|
103
|
+
|
|
104
|
+
一次模板发送使用同一个模板快照渲染主题、正文并选择默认 Provider,避免并发编辑时混用不同版本。显式 `provider` 仍可覆盖模板渠道。
|
|
67
105
|
|
|
68
106
|
### 配置
|
|
69
107
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1389,4 +1389,5 @@ declare function migrateReach(options?: {
|
|
|
1389
1389
|
dryRun?: boolean;
|
|
1390
1390
|
}, db?: ReldbFunctions): Promise<_h_ai_core.HaiResult<_h_ai_reldb.SchemaMigrationPlan>>;
|
|
1391
1391
|
|
|
1392
|
-
export {
|
|
1392
|
+
export { AliyunSmsProviderConfigSchema, ApiProviderConfigSchema, ConsoleProviderConfigSchema, DndConfigSchema, HaiReachError, ProviderConfigSchema, ReachConfigSchema, ReachDeadRequeueSchema, ReachQueueConfigSchema, ReachQueueIdSchema, ReachQueueListSchema, ReachUnknownResolutionSchema, SmtpProviderConfigSchema, TemplateConfigSchema, migrateReach, reach };
|
|
1393
|
+
export type { AliyunSmsProviderConfig, ApiProviderConfig, ConsoleProviderConfig, DndConfig, ProviderConfig, ReachChannel, ReachConfig, ReachConfigInput, ReachDeadRequeue, ReachFunctions, ReachGatewayHook, ReachInitOptions, ReachMessage, ReachQueueConfig, ReachQueueEntry, ReachQueueFailure, ReachQueueListOptions, ReachQueueOperations, ReachQueueStatus, ReachTemplate, ReachTemplateRegistry, ReachUnknownResolution, RenderedTemplate, SendOperations, SendResult, SmtpProviderConfig, TemplateConfig };
|