@h-ai/core 0.1.0-alpha.66 → 0.1.0-alpha.68
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 +60 -34
- package/README.ja.md +60 -34
- package/README.md +61 -35
- package/dist/browser.d.ts +4 -4
- package/dist/browser.js +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/{chunk-RXNSRXYF.js → chunk-AWUFXC35.js} +283 -165
- package/dist/chunk-AWUFXC35.js.map +1 -0
- package/dist/{core-function-config.node-7KVlEiFk.d.ts → core-function-config.node-DJ6Hb1ee.d.ts} +499 -175
- package/dist/node.d.ts +23 -7
- package/dist/node.js +26 -5
- package/dist/node.js.map +1 -1
- package/package.json +5 -2
- package/dist/chunk-RXNSRXYF.js.map +0 -1
package/README.en.md
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
[Framework home](../../README.en.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Introduction
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The core of hai Agent Framework: shared utilities, types, configuration management, and logging.
|
|
10
|
+
|
|
11
|
+
## Core features
|
|
10
12
|
|
|
11
13
|
- **HaiResult types**: functional error handling (`ok` / `err`) with a shared result format across modules.
|
|
12
14
|
- **Unified logging**: pino on Node.js and loglevel in browsers, with the same API.
|
|
@@ -18,9 +20,11 @@
|
|
|
18
20
|
- **Module utilities**: NotInitializedKit proxies and shared lifecycle infrastructure.
|
|
19
21
|
- **Utility library**: type checks and object / string / array / async / time operations.
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## Getting started
|
|
24
|
+
|
|
25
|
+
### Quick start
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
#### Node.js environment
|
|
24
28
|
|
|
25
29
|
```typescript
|
|
26
30
|
import { core } from '@h-ai/core'
|
|
@@ -72,7 +76,7 @@ core.time.formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss')
|
|
|
72
76
|
core.typeUtils.isDefined(value)
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
#### Browser environment
|
|
76
80
|
|
|
77
81
|
```typescript
|
|
78
82
|
import { core } from '@h-ai/core'
|
|
@@ -95,13 +99,13 @@ The browser retains the `core.config` API shape for type compatibility, but does
|
|
|
95
99
|
- `watch()` immediately calls its callback with the same error and returns a safe no-op unsubscribe function.
|
|
96
100
|
- Read configuration on the server and deliver it through an API, or use `core.init({ logging })` only to configure browser logging.
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
### Detailed API
|
|
99
103
|
|
|
100
|
-
|
|
104
|
+
#### Logging (Logger)
|
|
101
105
|
|
|
102
106
|
`core.logger` is both the default Logger instance and the shared entry point for logger management.
|
|
103
107
|
|
|
104
|
-
|
|
108
|
+
##### Write logs
|
|
105
109
|
|
|
106
110
|
Six levels: `trace` / `debug` / `info` / `warn` / `error` / `fatal`.
|
|
107
111
|
|
|
@@ -111,7 +115,7 @@ core.logger.error('Failed to connect', { error })
|
|
|
111
115
|
core.logger.debug('Processing item', { id, step: 'validation' })
|
|
112
116
|
```
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
##### Create a module logger
|
|
115
119
|
|
|
116
120
|
```typescript
|
|
117
121
|
// 独立名称空间,适合模块内全局使用
|
|
@@ -119,7 +123,7 @@ const logger = core.logger.create({ name: 'payment' })
|
|
|
119
123
|
logger.info('Payment processed')
|
|
120
124
|
```
|
|
121
125
|
|
|
122
|
-
|
|
126
|
+
##### Child loggers
|
|
123
127
|
|
|
124
128
|
```typescript
|
|
125
129
|
// 携带固定上下文,每条日志自动附带这些字段
|
|
@@ -135,7 +139,7 @@ opLogger.error('Login failed', { reason: 'invalid_password' })
|
|
|
135
139
|
|
|
136
140
|
> **Typical usage**: create `reqLogger` at the request entry, pass it to the service layer, and add operation context with `child`. Logs then include the complete request context.
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
##### Logger management
|
|
139
143
|
|
|
140
144
|
```typescript
|
|
141
145
|
// 配置输出格式和级别(Node.js / Browser)
|
|
@@ -154,9 +158,11 @@ After `core.init()` loads `_core.yml.logging`, or after `configure` / `setLevel`
|
|
|
154
158
|
|
|
155
159
|
Browser logs still use the DevTools console: `pretty` prints readable messages with context, while `json` prints a JSON string containing `level` / `msg`. Default credential masking and configured path redaction both apply, including nested dot/bracket paths and `*`. Callers remain responsible for redacting message text.
|
|
156
160
|
|
|
157
|
-
`
|
|
161
|
+
Native `Error` values in log context are copied into diagnostics containing `name`, `message`, `stack`, `cause`, `AggregateError.errors`, and enumerable own context before default field/URL masking and configured `redact` paths run. Both backends use the same rules and leave the original error unchanged. Error-subgraph cycles become `[Circular]` and the 32-level limit becomes `[MaxDepth]`; custom replacements in these subgraphs follow the same normalization, while ordinary-object replacement behavior is unchanged. Ordinary-object cycles without an Error retain their original structure and are not guaranteed to be directly JSON-serializable. `name/message/stack` are free text: secrets embedded in them are not automatically parsed. Clean them before logging or mask whole paths such as `error.message` / `error.stack`.
|
|
158
162
|
|
|
159
|
-
|
|
163
|
+
`core.logger` redacts log context by default: credentials such as `password`, `token`, `secret`, `privateKey`, and `apiV3Key` become `[REDACTED]`. Fields such as `url` / `baseUrl` / `endpoint` mask embedded usernames/passwords, sensitive query parameters, and OAuth key/value fragments; malformed URLs return a fixed placeholder. Email addresses and phone numbers are not masked by default.
|
|
164
|
+
|
|
165
|
+
##### Log level conventions
|
|
160
166
|
|
|
161
167
|
| Level | Use case |
|
|
162
168
|
| ------- | --------------------------------------------------- |
|
|
@@ -167,7 +173,9 @@ Browser logs still use the DevTools console: `pretty` prints readable messages w
|
|
|
167
173
|
| `error` | Operation failures requiring investigation |
|
|
168
174
|
| `fatal` | Fatal errors preventing continued service |
|
|
169
175
|
|
|
170
|
-
|
|
176
|
+
#### Internationalization (i18n)
|
|
177
|
+
|
|
178
|
+
Built-in locales are `zh-CN`, `en-US` and `ja-JP`. The `ja` alias normalizes to `ja-JP`; all modules share this setting.
|
|
171
179
|
|
|
172
180
|
```typescript
|
|
173
181
|
// 设置全局语言(所有 getMessage 函数自动响应)
|
|
@@ -187,13 +195,13 @@ getMessage('welcome', { params: { name: 'Alice' } }) // 'Welcome Alice'
|
|
|
187
195
|
getMessage('welcome', { locale: 'zh-CN', params: { name: 'Alice' } }) // '欢迎 Alice'
|
|
188
196
|
|
|
189
197
|
// 常量
|
|
190
|
-
core.i18n.DEFAULT_LOCALES // [{ code: 'zh-CN', label: '简体中文' }, { code: 'en-US', label: 'English' }]
|
|
198
|
+
core.i18n.DEFAULT_LOCALES // [{ code: 'zh-CN', label: '简体中文' }, { code: 'en-US', label: 'English' }, { code: 'ja-JP', label: '日本語' }]
|
|
191
199
|
core.i18n.DEFAULT_LOCALE // 'zh-CN'
|
|
192
200
|
```
|
|
193
201
|
|
|
194
|
-
|
|
202
|
+
#### Redaction utilities
|
|
195
203
|
|
|
196
|
-
`core.sanitize.sanitizeSensitiveFields()` recursively redacts objects and arrays. By default it handles password, token, secret, privateKey, apiV3Key, and similar credentials, and masks embedded credentials in `url` / `baseUrl` / `endpoint`.
|
|
204
|
+
`core.sanitize.sanitizeSensitiveFields()` recursively redacts objects and arrays. By default it handles password, token, secret, privateKey, apiV3Key, and similar credentials, and masks embedded credentials in `url` / `baseUrl` / `endpoint`. `core.sanitize.sanitizeUrl(url, options)` also handles individual URLs and returns `(invalid url)` for malformed input. Custom matchers apply to parameter names as well.
|
|
197
205
|
|
|
198
206
|
```typescript
|
|
199
207
|
core.sanitize.sanitizeSensitiveFields({
|
|
@@ -211,7 +219,7 @@ core.sanitize.sanitizeSensitiveFields({ email: 'user@example.com' }, {
|
|
|
211
219
|
// => { email: '***' }
|
|
212
220
|
```
|
|
213
221
|
|
|
214
|
-
|
|
222
|
+
#### Zod validation error localization
|
|
215
223
|
|
|
216
224
|
`core.zodValidation` converts Zod `SafeParseError` / `ZodError` into flat form errors and maps Zod's
|
|
217
225
|
default English messages to the caller's own localized messages.
|
|
@@ -272,17 +280,19 @@ if (!result.success) {
|
|
|
272
280
|
}
|
|
273
281
|
```
|
|
274
282
|
|
|
275
|
-
|
|
283
|
+
#### Configuration management (Node.js only)
|
|
276
284
|
|
|
277
285
|
> Browsers have no filesystem access. `core.config` offers placeholder APIs only: file-related methods return `SERVICE_UNAVAILABLE` and do not load YAML.
|
|
278
286
|
|
|
287
|
+
Node automatically loads and watches runtime `.yml` / `.yaml` files, excluding exactly `_deploy.yml` and `_deploy.yaml`. The deployment CLI parses those reserved files after loading its target environment and credentials. Business `deploy.yml` and explicit `core.config.load` remain supported. A failed per-file load result is logged and loading continues; applications must validate required configuration and check `success`. Directory scanning, logger setup and other exceptions may still propagate.
|
|
288
|
+
|
|
279
289
|
```typescript
|
|
280
290
|
import { core, HaiConfigError } from '@h-ai/core'
|
|
281
291
|
import { z } from 'zod'
|
|
282
292
|
|
|
283
|
-
// 方式 1:init
|
|
293
|
+
// 方式 1:init 时自动加载运行时配置
|
|
284
294
|
core.init({
|
|
285
|
-
configDir: './config', //
|
|
295
|
+
configDir: './config', // 扫描 .yml / .yaml,排除 _deploy.yml / _deploy.yaml
|
|
286
296
|
watchConfig: true, // 监听变更并自动重载
|
|
287
297
|
})
|
|
288
298
|
|
|
@@ -304,8 +314,8 @@ const validResult = core.config.validate('app', AppSchema)
|
|
|
304
314
|
|
|
305
315
|
// 查询和获取
|
|
306
316
|
if (core.config.has('app')) {
|
|
307
|
-
const cfg = core.config.get<typeof AppSchema
|
|
308
|
-
const cfg2 = core.config.getOrThrow<typeof AppSchema
|
|
317
|
+
const cfg = core.config.get<z.infer<typeof AppSchema>>('app') // undefined 或配置
|
|
318
|
+
const cfg2 = core.config.getOrThrow<z.infer<typeof AppSchema>>('app') // 未加载时抛异常
|
|
309
319
|
}
|
|
310
320
|
core.config.keys() // ['core', 'app', 'db', ...]
|
|
311
321
|
|
|
@@ -327,7 +337,7 @@ core.config.clear('app') // 清除单个
|
|
|
327
337
|
core.config.clear() // 清除全部
|
|
328
338
|
```
|
|
329
339
|
|
|
330
|
-
|
|
340
|
+
##### Dotenv files and environment modes
|
|
331
341
|
|
|
332
342
|
Node-only `core.config.loadEnvFiles({ mode, envDir })` returns HaiResult and merges `.env` → `.env.<mode>` → `.env.local`, with existing process variables taking priority. development/production map to dev/prod; missing files are skipped. It does not mutate the process: check success before assigning. Track public environment files and `.env.example`; ignore private `.env.local`. core.init does not load dotenv. Browser calls return SERVICE_UNAVAILABLE.
|
|
333
343
|
|
|
@@ -339,7 +349,7 @@ Object.assign(process.env, env.data)
|
|
|
339
349
|
core.init({ configDir: './config' })
|
|
340
350
|
```
|
|
341
351
|
|
|
342
|
-
|
|
352
|
+
##### Environment variable mapping and interpolation
|
|
343
353
|
|
|
344
354
|
`core.config.load(name, ...)` automatically maps each YAML leaf to an
|
|
345
355
|
environment variable named `HAI_<CONFIG_NAME>_<YAML_PATH>`. Configuration names and keys are uppercased, levels are separated by `_`,
|
|
@@ -382,7 +392,7 @@ database: ${DB_CONNECTION} # → 环境变量缺失时报错
|
|
|
382
392
|
url: http://${HOST}:${PORT} # → string(混合文本)
|
|
383
393
|
```
|
|
384
394
|
|
|
385
|
-
|
|
395
|
+
#### ID generation
|
|
386
396
|
|
|
387
397
|
```typescript
|
|
388
398
|
const id = core.id.generate() // nanoid 21 字符
|
|
@@ -398,7 +408,9 @@ core.id.isValidUUID('f47ac10b-...') // true/false
|
|
|
398
408
|
core.id.isValidNanoId('abc123', 6) // true/false
|
|
399
409
|
```
|
|
400
410
|
|
|
401
|
-
|
|
411
|
+
UUID generation requires cryptographic randomUUID/getRandomValues and throws if neither is available; it never falls back to Math.random.
|
|
412
|
+
|
|
413
|
+
#### Utilities
|
|
402
414
|
|
|
403
415
|
```typescript
|
|
404
416
|
// 类型检查
|
|
@@ -434,7 +446,7 @@ core.string.isBlank('') // true
|
|
|
434
446
|
core.string.isNotBlank('x') // true
|
|
435
447
|
core.string.padStart('5', 3, '0') // '005'
|
|
436
448
|
core.string.padEnd('5', 3, '0') // '500'
|
|
437
|
-
core.string.constantTimeEqual(a, b) //
|
|
449
|
+
core.string.constantTimeEqual(a, b) // Node 使用原生等长比较;浏览器不保证恒时
|
|
438
450
|
|
|
439
451
|
// 数组操作
|
|
440
452
|
core.array.unique([1, 1, 2]) // [1, 2]
|
|
@@ -470,7 +482,9 @@ core.time.startOfDay(date)
|
|
|
470
482
|
core.time.endOfDay(date)
|
|
471
483
|
```
|
|
472
484
|
|
|
473
|
-
|
|
485
|
+
The Node entry uses node:crypto.timingSafeEqual over equal-length UTF-16LE code units. Different lengths return false; length is not hidden. The browser implementation avoids content-based early returns but has no JavaScript-engine timing guarantee and is not a server credential boundary. Surrounding branches, encoding and request handling are not made timing-safe by this helper.
|
|
486
|
+
|
|
487
|
+
#### Module utilities (module)
|
|
474
488
|
|
|
475
489
|
Shared initialization error handling for modules:
|
|
476
490
|
|
|
@@ -488,9 +502,9 @@ const currentDdl: DdlOperations = notInitialized.proxy<DdlOperations>()
|
|
|
488
502
|
const currentHash: HashOperations = notInitialized.proxy<HashOperations>('sync')
|
|
489
503
|
```
|
|
490
504
|
|
|
491
|
-
|
|
505
|
+
### Error handling
|
|
492
506
|
|
|
493
|
-
|
|
507
|
+
#### HaiResult types
|
|
494
508
|
|
|
495
509
|
All operations that may fail return `HaiResult<T>`:
|
|
496
510
|
|
|
@@ -513,7 +527,7 @@ else {
|
|
|
513
527
|
}
|
|
514
528
|
```
|
|
515
529
|
|
|
516
|
-
|
|
530
|
+
#### Custom error codes (per module)
|
|
517
531
|
|
|
518
532
|
```typescript
|
|
519
533
|
import type { ErrorInfo } from '@h-ai/core'
|
|
@@ -539,7 +553,7 @@ const errorInst = core.error.buildHaiErrorInst(
|
|
|
539
553
|
)
|
|
540
554
|
```
|
|
541
555
|
|
|
542
|
-
|
|
556
|
+
#### Configuration error codes
|
|
543
557
|
|
|
544
558
|
```typescript
|
|
545
559
|
import { HaiConfigError } from '@h-ai/core'
|
|
@@ -551,12 +565,24 @@ HaiConfigError.CONFIG_ENV_VAR_MISSING // hai:core:013 - 环境变量缺失
|
|
|
551
565
|
HaiConfigError.CONFIG_NOT_LOADED // hai:core:014 - 配置未加载
|
|
552
566
|
```
|
|
553
567
|
|
|
554
|
-
|
|
568
|
+
### Request locale isolation
|
|
569
|
+
|
|
570
|
+
Wrap Node requests and SSR in `core.i18n.runWithLocale(locale, () => handleRequest())`. SvelteKit can use `kit.i18n.runWithLocale(locale, () => resolve(event))`; serv creates the scope automatically from request headers. Async descendants inherit it. Explicit `MessageOptions.locale` takes precedence over the request locale and the startup default. Within a scope, `setGlobalLocale` only changes that request; outside a scope it configures the startup default and must not be called by request hooks.
|
|
571
|
+
|
|
572
|
+
Browsers keep application-level `setGlobalLocale` / `createLocaleStore`. During SSR, UI store initialization and setters only update the store; messages read the request scope. `runWithLocale` requires the Node entry; browser translations use explicit locale options or application state.
|
|
573
|
+
|
|
574
|
+
## Configuration consumption
|
|
575
|
+
|
|
576
|
+
`_core.yml` accepts only name/version/env/defaultLocale metadata and logging; unknown fields fail loading. Core has no global debug, ID length/prefix, business features or locale registration list. Use logging.level, per-call core.id arguments, and application-owned app.yml with its own schema. defaultLocale is metadata, not automatic translation registration or a Paraglide switch. Importing Logger preserves LANG, LC_ALL and PYTHONIOENCODING, including Windows TTY. See the [configuration-to-consumer map (Chinese)](../../.agents/skills/hai-module-create/configuration.md).
|
|
577
|
+
|
|
578
|
+
## Development and testing
|
|
555
579
|
|
|
556
580
|
```bash
|
|
557
581
|
pnpm --filter @h-ai/core test
|
|
558
582
|
```
|
|
559
583
|
|
|
584
|
+
See the [module JSDoc conventions (Chinese)](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证) for declaration comments and compilable examples. Node core.init is synchronous and returns void. A failed per-file config.load result is logged and loading continues; validate required configuration and check success. Directory scanning and other exceptions may still throw. Business HaiResult APIs require a success check.
|
|
585
|
+
|
|
560
586
|
## License
|
|
561
587
|
|
|
562
588
|
Apache-2.0
|
package/README.ja.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[フレームワークのホーム](../../README.ja.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 概要
|
|
8
|
+
|
|
9
|
+
hai Agent Framework の中核モジュール。共通ツール、型定義、設定管理、ログ機能を提供します。
|
|
8
10
|
|
|
9
11
|
## 主な機能
|
|
10
12
|
|
|
@@ -18,9 +20,11 @@
|
|
|
18
20
|
- **モジュールツール**:NotInitializedKit のプロキシと共通のライフサイクル基盤。
|
|
19
21
|
- **ツール関数**:型確認、オブジェクト・文字列・配列・非同期・時刻の操作。
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## 使い始める
|
|
24
|
+
|
|
25
|
+
### クイックスタート
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
#### Node.js 環境
|
|
24
28
|
|
|
25
29
|
```typescript
|
|
26
30
|
import { core } from '@h-ai/core'
|
|
@@ -72,7 +76,7 @@ core.time.formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss')
|
|
|
72
76
|
core.typeUtils.isDefined(value)
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
#### ブラウザー環境
|
|
76
80
|
|
|
77
81
|
```typescript
|
|
78
82
|
import { core } from '@h-ai/core'
|
|
@@ -95,13 +99,13 @@ core.array.unique([1, 1, 2])
|
|
|
95
99
|
- `watch()` は同じエラーで直ちにコールバックを呼び、安全な no-op の監視解除関数を返します。
|
|
96
100
|
- 設定が必要な場合はサーバーで読み込み API で渡すか、ブラウザーでは `core.init({ logging })` でログのみ設定してください。
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
### API の詳細
|
|
99
103
|
|
|
100
|
-
|
|
104
|
+
#### ログ(Logger)
|
|
101
105
|
|
|
102
106
|
`core.logger` は既定の Logger インスタンスであり、ログ管理の共通入口でもあります。
|
|
103
107
|
|
|
104
|
-
|
|
108
|
+
##### ログの記録
|
|
105
109
|
|
|
106
110
|
6 つのレベル:`trace` / `debug` / `info` / `warn` / `error` / `fatal`。
|
|
107
111
|
|
|
@@ -111,7 +115,7 @@ core.logger.error('Failed to connect', { error })
|
|
|
111
115
|
core.logger.debug('Processing item', { id, step: 'validation' })
|
|
112
116
|
```
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
##### モジュール用 logger の作成
|
|
115
119
|
|
|
116
120
|
```typescript
|
|
117
121
|
// 独立名称空间,适合模块内全局使用
|
|
@@ -119,7 +123,7 @@ const logger = core.logger.create({ name: 'payment' })
|
|
|
119
123
|
logger.info('Payment processed')
|
|
120
124
|
```
|
|
121
125
|
|
|
122
|
-
|
|
126
|
+
##### 子 logger(child)
|
|
123
127
|
|
|
124
128
|
```typescript
|
|
125
129
|
// 携带固定上下文,每条日志自动附带这些字段
|
|
@@ -135,7 +139,7 @@ opLogger.error('Login failed', { reason: 'invalid_password' })
|
|
|
135
139
|
|
|
136
140
|
> **典型的な使い方**:リクエスト入口で `reqLogger` を作成してサービス層に渡し、サービス層で `child` に操作コンテキストを追加します。ログに処理全体のコンテキストが自動的に含まれます。
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
##### ログの管理
|
|
139
143
|
|
|
140
144
|
```typescript
|
|
141
145
|
// 配置输出格式和级别(Node.js / Browser)
|
|
@@ -154,9 +158,11 @@ const level = core.logger.getLevel() // 'debug'
|
|
|
154
158
|
|
|
155
159
|
ブラウザーでは引き続き DevTools console に出力します。`pretty` は読みやすいメッセージと context、`json` は `level` / `msg` を含む JSON 文字列です。既定の認証情報マスキングと設定したパスのマスキングを併用し、ネストしたドット・括弧パスと `*` に対応します。メッセージ本文の機密情報は呼び出し側で除去してください。
|
|
156
160
|
|
|
157
|
-
`
|
|
161
|
+
ログ文脈のネイティブ `Error` は、`name`、`message`、`stack`、`cause`、`AggregateError.errors` と列挙可能な自身の文脈を持つコピーに変換してから、既定のフィールド/URL マスクと設定済み `redact` を適用します。両環境で同じ規則を使い、元の例外は変更しません。例外サブグラフの循環は `[Circular]`、32 階層の上限は `[MaxDepth]` になり、この範囲の独自置換値にも同じ正規化を適用します。通常オブジェクトの置換動作は変えません。Error を含まない通常オブジェクトの循環は元の構造を保持し、直接 JSON 化できる保証はありません。`name/message/stack` は自由文で、含まれる秘密を自動解析しません。記録前に除去するか、`error.message` / `error.stack` などのパス全体を隠してください。
|
|
158
162
|
|
|
159
|
-
|
|
163
|
+
`core.logger` は既定でログの機密情報をマスクします。`password`、`token`、`secret`、`privateKey`、`apiV3Key` などは `[REDACTED]` に置換されます。`url` / `baseUrl` / `endpoint` は URL 内のユーザー名・パスワード、機密クエリ値、OAuth 形式の fragment をマスクします。不正な URL は固定値を返します。メールアドレス・電話番号は既定では隠しません。
|
|
164
|
+
|
|
165
|
+
##### ログレベルの規約
|
|
160
166
|
|
|
161
167
|
| レベル | 用途 |
|
|
162
168
|
| ------- | ---------------------------------------- |
|
|
@@ -167,7 +173,9 @@ const level = core.logger.getLevel() // 'debug'
|
|
|
167
173
|
| `error` | 調査が必要な操作の失敗 |
|
|
168
174
|
| `fatal` | サービス継続不能の致命的エラー |
|
|
169
175
|
|
|
170
|
-
|
|
176
|
+
#### 国際化(i18n)
|
|
177
|
+
|
|
178
|
+
組み込みの言語は `zh-CN`、`en-US`、`ja-JP` です。略記 `ja` は `ja-JP` に正規化され、すべてのモジュールで設定を共有します。
|
|
171
179
|
|
|
172
180
|
```typescript
|
|
173
181
|
// 设置全局语言(所有 getMessage 函数自动响应)
|
|
@@ -187,13 +195,13 @@ getMessage('welcome', { params: { name: 'Alice' } }) // 'Welcome Alice'
|
|
|
187
195
|
getMessage('welcome', { locale: 'zh-CN', params: { name: 'Alice' } }) // '欢迎 Alice'
|
|
188
196
|
|
|
189
197
|
// 常量
|
|
190
|
-
core.i18n.DEFAULT_LOCALES // [{ code: 'zh-CN', label: '简体中文' }, { code: 'en-US', label: 'English' }]
|
|
198
|
+
core.i18n.DEFAULT_LOCALES // [{ code: 'zh-CN', label: '简体中文' }, { code: 'en-US', label: 'English' }, { code: 'ja-JP', label: '日本語' }]
|
|
191
199
|
core.i18n.DEFAULT_LOCALE // 'zh-CN'
|
|
192
200
|
```
|
|
193
201
|
|
|
194
|
-
|
|
202
|
+
#### 機密情報のマスク
|
|
195
203
|
|
|
196
|
-
`core.sanitize.sanitizeSensitiveFields()` はオブジェクト・配列内の機密情報を再帰的にマスクします。既定では password、token、secret、privateKey、apiV3Key などを処理し、`url` / `baseUrl` / `endpoint`
|
|
204
|
+
`core.sanitize.sanitizeSensitiveFields()` はオブジェクト・配列内の機密情報を再帰的にマスクします。既定では password、token、secret、privateKey、apiV3Key などを処理し、`url` / `baseUrl` / `endpoint` の認証情報もマスクします。`core.sanitize.sanitizeUrl(url, options)` は単独の URL にも使用でき、不正な URL は `(invalid url)` を返します。独自の matcher はクエリ名にも適用されます。
|
|
197
205
|
|
|
198
206
|
```typescript
|
|
199
207
|
core.sanitize.sanitizeSensitiveFields({
|
|
@@ -211,7 +219,7 @@ core.sanitize.sanitizeSensitiveFields({ email: 'user@example.com' }, {
|
|
|
211
219
|
// => { email: '***' }
|
|
212
220
|
```
|
|
213
221
|
|
|
214
|
-
|
|
222
|
+
#### Zod 検証エラーの i18n 変換
|
|
215
223
|
|
|
216
224
|
`core.zodValidation` は Zod の `SafeParseError` / `ZodError` をフラットなフォームエラーに変換し、
|
|
217
225
|
Zod の既定の英語メッセージを呼び出し元の i18n 文言に変換します。
|
|
@@ -272,17 +280,19 @@ if (!result.success) {
|
|
|
272
280
|
}
|
|
273
281
|
```
|
|
274
282
|
|
|
275
|
-
|
|
283
|
+
#### 設定管理(Node.js 専用)
|
|
276
284
|
|
|
277
285
|
> ブラウザーにはファイルシステムがないため、`core.config` は代替 API の形状のみを提供します。ファイル関連メソッドは `SERVICE_UNAVAILABLE` を返し、YAML を読み込みません。
|
|
278
286
|
|
|
287
|
+
Node は実行時の `.yml` / `.yaml` を自動読み込み・監視しますが、予約名 `_deploy.yml` と `_deploy.yaml` は除外します。これらはデプロイ CLI が対象環境と認証情報の読み込み後に個別解析します。業務用 `deploy.yml` と明示的な `core.config.load` は引き続き利用できます。単一ファイルの失敗結果はログに記録して続行するため、アプリは必須設定を validate して `success` を確認してください。ディレクトリー走査や Logger 設定などの例外は伝播する場合があります。
|
|
288
|
+
|
|
279
289
|
```typescript
|
|
280
290
|
import { core, HaiConfigError } from '@h-ai/core'
|
|
281
291
|
import { z } from 'zod'
|
|
282
292
|
|
|
283
|
-
// 方式 1:init
|
|
293
|
+
// 方式 1:init 时自动加载运行时配置
|
|
284
294
|
core.init({
|
|
285
|
-
configDir: './config', //
|
|
295
|
+
configDir: './config', // 扫描 .yml / .yaml,排除 _deploy.yml / _deploy.yaml
|
|
286
296
|
watchConfig: true, // 监听变更并自动重载
|
|
287
297
|
})
|
|
288
298
|
|
|
@@ -304,8 +314,8 @@ const validResult = core.config.validate('app', AppSchema)
|
|
|
304
314
|
|
|
305
315
|
// 查询和获取
|
|
306
316
|
if (core.config.has('app')) {
|
|
307
|
-
const cfg = core.config.get<typeof AppSchema
|
|
308
|
-
const cfg2 = core.config.getOrThrow<typeof AppSchema
|
|
317
|
+
const cfg = core.config.get<z.infer<typeof AppSchema>>('app') // undefined 或配置
|
|
318
|
+
const cfg2 = core.config.getOrThrow<z.infer<typeof AppSchema>>('app') // 未加载时抛异常
|
|
309
319
|
}
|
|
310
320
|
core.config.keys() // ['core', 'app', 'db', ...]
|
|
311
321
|
|
|
@@ -327,7 +337,7 @@ core.config.clear('app') // 清除单个
|
|
|
327
337
|
core.config.clear() // 清除全部
|
|
328
338
|
```
|
|
329
339
|
|
|
330
|
-
|
|
340
|
+
##### dotenv ファイルと環境切り替え
|
|
331
341
|
|
|
332
342
|
Node 専用の `core.config.loadEnvFiles({ mode, envDir })` は HaiResult を返し、`.env` → `.env.<mode>` → `.env.local` の順で読み込みます。既存のプロセス変数が最優先です。development/production は dev/prod に対応し、存在しないファイルは省略します。プロセスは変更しないため、success を確認してから代入します。公開設定と `.env.example` は Git 登録し、私有の `.env.local` は除外します。core.init は dotenv を読み込まず、ブラウザーでは SERVICE_UNAVAILABLE を返します。
|
|
333
343
|
|
|
@@ -339,7 +349,7 @@ Object.assign(process.env, env.data)
|
|
|
339
349
|
core.init({ configDir: './config' })
|
|
340
350
|
```
|
|
341
351
|
|
|
342
|
-
|
|
352
|
+
##### 環境変数のマッピングと展開
|
|
343
353
|
|
|
344
354
|
`core.config.load(name, ...)` は YAML の各末端設定を
|
|
345
355
|
`HAI_<CONFIG_NAME>_<YAML_PATH>` の環境変数に自動対応付けします。設定名・各 key は大文字化し、階層は `_` で区切り、
|
|
@@ -382,7 +392,7 @@ database: ${DB_CONNECTION} # → 环境变量缺失时报错
|
|
|
382
392
|
url: http://${HOST}:${PORT} # → string(混合文本)
|
|
383
393
|
```
|
|
384
394
|
|
|
385
|
-
|
|
395
|
+
#### ID 生成
|
|
386
396
|
|
|
387
397
|
```typescript
|
|
388
398
|
const id = core.id.generate() // nanoid 21 字符
|
|
@@ -398,7 +408,9 @@ core.id.isValidUUID('f47ac10b-...') // true/false
|
|
|
398
408
|
core.id.isValidNanoId('abc123', 6) // true/false
|
|
399
409
|
```
|
|
400
410
|
|
|
401
|
-
|
|
411
|
+
UUID は暗号学的乱数の randomUUID/getRandomValues のみを使用し、どちらも利用できない場合は例外を送出します。Math.random にはフォールバックしません。
|
|
412
|
+
|
|
413
|
+
#### ツール関数
|
|
402
414
|
|
|
403
415
|
```typescript
|
|
404
416
|
// 类型检查
|
|
@@ -434,7 +446,7 @@ core.string.isBlank('') // true
|
|
|
434
446
|
core.string.isNotBlank('x') // true
|
|
435
447
|
core.string.padStart('5', 3, '0') // '005'
|
|
436
448
|
core.string.padEnd('5', 3, '0') // '500'
|
|
437
|
-
core.string.constantTimeEqual(a, b) //
|
|
449
|
+
core.string.constantTimeEqual(a, b) // Node 使用原生等长比较;浏览器不保证恒时
|
|
438
450
|
|
|
439
451
|
// 数组操作
|
|
440
452
|
core.array.unique([1, 1, 2]) // [1, 2]
|
|
@@ -470,7 +482,9 @@ core.time.startOfDay(date)
|
|
|
470
482
|
core.time.endOfDay(date)
|
|
471
483
|
```
|
|
472
484
|
|
|
473
|
-
|
|
485
|
+
Node 入口は元の UTF-16 コード単位を UTF-16LE に変換し、同じバイト長を node:crypto.timingSafeEqual で比較します。長さが違えば false となり、長さ自体は隠しません。ブラウザー実装には JavaScript エンジンの定時間保証がなく、サーバーの認証境界には使用しません。周辺の分岐・変換・リクエスト処理まで定時間になるわけではありません。
|
|
486
|
+
|
|
487
|
+
#### モジュール共通ツール(module)
|
|
474
488
|
|
|
475
489
|
モジュール共通の初期化エラー処理:
|
|
476
490
|
|
|
@@ -488,9 +502,9 @@ const currentDdl: DdlOperations = notInitialized.proxy<DdlOperations>()
|
|
|
488
502
|
const currentHash: HashOperations = notInitialized.proxy<HashOperations>('sync')
|
|
489
503
|
```
|
|
490
504
|
|
|
491
|
-
|
|
505
|
+
### エラー処理
|
|
492
506
|
|
|
493
|
-
|
|
507
|
+
#### HaiResult 型
|
|
494
508
|
|
|
495
509
|
失敗する可能性がある操作は `HaiResult<T>` を返します:
|
|
496
510
|
|
|
@@ -513,7 +527,7 @@ else {
|
|
|
513
527
|
}
|
|
514
528
|
```
|
|
515
529
|
|
|
516
|
-
|
|
530
|
+
#### 独自のエラーコード(モジュール単位)
|
|
517
531
|
|
|
518
532
|
```typescript
|
|
519
533
|
import type { ErrorInfo } from '@h-ai/core'
|
|
@@ -539,7 +553,7 @@ const errorInst = core.error.buildHaiErrorInst(
|
|
|
539
553
|
)
|
|
540
554
|
```
|
|
541
555
|
|
|
542
|
-
|
|
556
|
+
#### 設定エラーコード
|
|
543
557
|
|
|
544
558
|
```typescript
|
|
545
559
|
import { HaiConfigError } from '@h-ai/core'
|
|
@@ -551,12 +565,24 @@ HaiConfigError.CONFIG_ENV_VAR_MISSING // hai:core:013 - 环境变量缺失
|
|
|
551
565
|
HaiConfigError.CONFIG_NOT_LOADED // hai:core:014 - 配置未加载
|
|
552
566
|
```
|
|
553
567
|
|
|
554
|
-
|
|
568
|
+
### リクエスト言語の分離
|
|
569
|
+
|
|
570
|
+
Node リクエストと SSR は `core.i18n.runWithLocale(locale, () => handleRequest())` で囲みます。SvelteKit は `kit.i18n.runWithLocale(locale, () => resolve(event))` を使えます。serv はリクエストヘッダーから自動設定します。非同期の子処理も言語を継承し、明示的な `MessageOptions.locale`、リクエスト言語、起動時の既定値の順で優先します。コンテキスト内の `setGlobalLocale` はそのリクエストだけを変更します。コンテキスト外の設定は起動時に限定し、リクエスト hook から呼びません。
|
|
571
|
+
|
|
572
|
+
ブラウザーはアプリ全体の `setGlobalLocale` / `createLocaleStore` を使います。SSR の UI store 初期化と setter は自身の状態のみ変更し、メッセージはリクエストコンテキストを参照します。`runWithLocale` は Node 入口専用です。
|
|
573
|
+
|
|
574
|
+
## 設定の消費範囲
|
|
575
|
+
|
|
576
|
+
`_core.yml` は name/version/env/defaultLocale のメタデータと logging のみを受け付け、不明なフィールドでは読み込みに失敗します。グローバルな debug、ID 長/接頭辞、業務 features、言語登録リストは提供しません。logging.level、core.id の呼び出し引数、独自 Schema で検証する app.yml を使用してください。defaultLocale はメタデータであり、翻訳登録や Paraglide の切り替えを自動実行しません。Logger の import は Windows TTY でも LANG、LC_ALL、PYTHONIOENCODING を変更しません。[設定と消費点の対応表(中国語)](../../.agents/skills/hai-module-create/configuration.md)を参照してください。
|
|
577
|
+
|
|
578
|
+
## 開発とテスト
|
|
555
579
|
|
|
556
580
|
```bash
|
|
557
581
|
pnpm --filter @h-ai/core test
|
|
558
582
|
```
|
|
559
583
|
|
|
560
|
-
|
|
584
|
+
宣言の注釈と型検査できる例は [JSDoc 規約(中国語)](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证) を参照してください。Node core.init は同期的に void を返します。単一ファイルの config.load 失敗結果は記録して続行するため、必須設定は validate して success を確認してください。ディレクトリー走査などの例外は伝播する場合があります。業務 HaiResult API は success を先に確認します。
|
|
585
|
+
|
|
586
|
+
## ライセンス
|
|
561
587
|
|
|
562
588
|
Apache-2.0
|