@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 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. With `dnd.enabled: true` and `strategy: delay`, initialize it first and ensure the queue table is available; otherwise `reach.init()` returns `CONFIG_ERROR`. Optional for other sends.
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
- const initialized = await reach.init({
45
- providers: [{ name: 'local', type: 'console' }],
46
- templates: [{ name: 'welcome', provider: 'local', subject: 'Welcome', body: 'Hello {userName}' }],
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
- const result = await reach.send({
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
- finally {
60
- await reach.close()
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`, `headers.Authorization`, SMTP `pass`, SMS keys, and other secrets are hidden automatically.
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`:送信ログ・テンプレートの永続化。`dnd.enabled: true` と `strategy: delay` を使う場合は事前初期化とキューテーブルが必須で、利用できなければ `reach.init()` は `CONFIG_ERROR` を返します。それ以外の送信では任意です。
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
- const initialized = await reach.init({
45
- providers: [{ name: 'local', type: 'console' }],
46
- templates: [{ name: 'welcome', provider: 'local', subject: 'Welcome', body: 'Hello {userName}' }],
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
- const result = await reach.send({
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
- finally {
60
- await reach.close()
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` 内の認証情報、`headers.Authorization`、SMTP の `pass`、SMS の鍵などは自動的に非表示になります。
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` — 数据库(发送日志与模板持久化);启用 `dnd.enabled: true` 与 `strategy: delay` 时必须先初始化且队列表可用,否则 `reach.init()` 返回 `CONFIG_ERROR`。其他发送场景可选
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
- const initialized = await reach.init({
45
- providers: [{ name: 'local', type: 'console' }],
46
- templates: [{ name: 'welcome', provider: 'local', subject: 'Welcome', body: 'Hello {userName}' }],
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
- const result = await reach.send({
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
- finally {
60
- await reach.close()
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` 的内嵌凭证,以及 `headers.Authorization`、SMTP `pass`、短信密钥等敏感值会自动隐藏。
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 { type AliyunSmsProviderConfig, AliyunSmsProviderConfigSchema, type ApiProviderConfig, ApiProviderConfigSchema, type ConsoleProviderConfig, ConsoleProviderConfigSchema, type DndConfig, DndConfigSchema, HaiReachError, type ProviderConfig, ProviderConfigSchema, type ReachChannel, type ReachConfig, type ReachConfigInput, ReachConfigSchema, type ReachDeadRequeue, ReachDeadRequeueSchema, type ReachFunctions, type ReachGatewayHook, type ReachInitOptions, type ReachMessage, type ReachQueueConfig, ReachQueueConfigSchema, type ReachQueueEntry, type ReachQueueFailure, ReachQueueIdSchema, type ReachQueueListOptions, ReachQueueListSchema, type ReachQueueOperations, type ReachQueueStatus, type ReachTemplate, type ReachTemplateRegistry, type ReachUnknownResolution, ReachUnknownResolutionSchema, type RenderedTemplate, type SendOperations, type SendResult, type SmtpProviderConfig, SmtpProviderConfigSchema, type TemplateConfig, TemplateConfigSchema, migrateReach, reach };
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 };