hazo_core 1.0.0
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 +84 -0
- package/SETUP_CHECKLIST.md +114 -0
- package/config/hazo_core_config.ini +14 -0
- package/dist/config/index.d.ts +35 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +117 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/ini_parser.d.ts +10 -0
- package/dist/config/ini_parser.d.ts.map +1 -0
- package/dist/config/ini_parser.js +45 -0
- package/dist/config/ini_parser.js.map +1 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +4 -0
- package/dist/constants.js.map +1 -0
- package/dist/context/client.d.ts +27 -0
- package/dist/context/client.d.ts.map +1 -0
- package/dist/context/client.js +66 -0
- package/dist/context/client.js.map +1 -0
- package/dist/context/index.d.ts +9 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +8 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/server.d.ts +23 -0
- package/dist/context/server.d.ts.map +1 -0
- package/dist/context/server.js +52 -0
- package/dist/context/server.js.map +1 -0
- package/dist/context/types.d.ts +14 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +2 -0
- package/dist/context/types.js.map +1 -0
- package/dist/debug/index.d.ts +20 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/index.js +78 -0
- package/dist/debug/index.js.map +1 -0
- package/dist/errors/auth.d.ts +14 -0
- package/dist/errors/auth.d.ts.map +1 -0
- package/dist/errors/auth.js +19 -0
- package/dist/errors/auth.js.map +1 -0
- package/dist/errors/base.d.ts +89 -0
- package/dist/errors/base.d.ts.map +1 -0
- package/dist/errors/base.js +152 -0
- package/dist/errors/base.js.map +1 -0
- package/dist/errors/config.d.ts +18 -0
- package/dist/errors/config.d.ts.map +1 -0
- package/dist/errors/config.js +14 -0
- package/dist/errors/config.js.map +1 -0
- package/dist/errors/conflict.d.ts +9 -0
- package/dist/errors/conflict.d.ts.map +1 -0
- package/dist/errors/conflict.js +14 -0
- package/dist/errors/conflict.js.map +1 -0
- package/dist/errors/external.d.ts +9 -0
- package/dist/errors/external.d.ts.map +1 -0
- package/dist/errors/external.js +14 -0
- package/dist/errors/external.js.map +1 -0
- package/dist/errors/from_zod.d.ts +33 -0
- package/dist/errors/from_zod.d.ts.map +1 -0
- package/dist/errors/from_zod.js +63 -0
- package/dist/errors/from_zod.js.map +1 -0
- package/dist/errors/index.d.ts +22 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +12 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/internal.d.ts +14 -0
- package/dist/errors/internal.d.ts.map +1 -0
- package/dist/errors/internal.js +14 -0
- package/dist/errors/internal.js.map +1 -0
- package/dist/errors/not_found.d.ts +9 -0
- package/dist/errors/not_found.d.ts.map +1 -0
- package/dist/errors/not_found.js +15 -0
- package/dist/errors/not_found.js.map +1 -0
- package/dist/errors/rate_limit.d.ts +9 -0
- package/dist/errors/rate_limit.d.ts.map +1 -0
- package/dist/errors/rate_limit.js +14 -0
- package/dist/errors/rate_limit.js.map +1 -0
- package/dist/errors/unavailable.d.ts +9 -0
- package/dist/errors/unavailable.d.ts.map +1 -0
- package/dist/errors/unavailable.js +14 -0
- package/dist/errors/unavailable.js.map +1 -0
- package/dist/errors/validation.d.ts +15 -0
- package/dist/errors/validation.d.ts.map +1 -0
- package/dist/errors/validation.js +17 -0
- package/dist/errors/validation.js.map +1 -0
- package/dist/http/fetch_with_request_id.d.ts +14 -0
- package/dist/http/fetch_with_request_id.d.ts.map +1 -0
- package/dist/http/fetch_with_request_id.js +29 -0
- package/dist/http/fetch_with_request_id.js.map +1 -0
- package/dist/http/get_origin_url.d.ts +23 -0
- package/dist/http/get_origin_url.d.ts.map +1 -0
- package/dist/http/get_origin_url.js +61 -0
- package/dist/http/get_origin_url.js.map +1 -0
- package/dist/http/request_id_middleware.d.ts +38 -0
- package/dist/http/request_id_middleware.d.ts.map +1 -0
- package/dist/http/request_id_middleware.js +57 -0
- package/dist/http/request_id_middleware.js.map +1 -0
- package/dist/index.client.d.ts +16 -0
- package/dist/index.client.d.ts.map +1 -0
- package/dist/index.client.js +19 -0
- package/dist/index.client.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +29 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +125 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/singleton/index.d.ts +16 -0
- package/dist/singleton/index.d.ts.map +1 -0
- package/dist/singleton/index.js +42 -0
- package/dist/singleton/index.js.map +1 -0
- package/dist/utils/dates.d.ts +45 -0
- package/dist/utils/dates.d.ts.map +1 -0
- package/dist/utils/dates.js +79 -0
- package/dist/utils/dates.js.map +1 -0
- package/dist/utils/env.d.ts +7 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +9 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/index.d.ts +69 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +174 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +82 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# hazo_core
|
|
2
|
+
|
|
3
|
+
Foundation package for every `hazo_*` package — errors, correlation ID propagation, config loading, logger factory, debug factory, singleton registry, and HTTP middleware.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install hazo_core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Required peer deps (ship alongside hazo_core in Wave 1):
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install hazo_logs hazo_debug
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createLogger, loadConfig, withContext, HazoError } from 'hazo_core';
|
|
21
|
+
import { defineConfig } from 'hazo_core';
|
|
22
|
+
import z from 'zod';
|
|
23
|
+
|
|
24
|
+
// Logger (auto-injects correlationId + pkg)
|
|
25
|
+
const log = createLogger('hazo_mypackage');
|
|
26
|
+
log.info('server.started', { port: 3000 });
|
|
27
|
+
|
|
28
|
+
// Config (reads hazo_mypackage_config.ini, validates with Zod)
|
|
29
|
+
const config = loadConfig({
|
|
30
|
+
pkg: 'hazo_mypackage',
|
|
31
|
+
schema: defineConfig({ port: z.number().default(3000) }),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Correlation ID (AsyncLocalStorage on server)
|
|
35
|
+
withContext({ correlationId: 'req_abc123' }, () => {
|
|
36
|
+
log.info('request.received'); // correlationId auto-included
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Errors
|
|
40
|
+
throw new HazoNotFoundError({ code: 'HAZO_MY_NOT_FOUND', pkg: 'hazo_mypackage', message: 'Resource missing' });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Public API
|
|
44
|
+
|
|
45
|
+
See `design/architecture.md §5` for the complete public API surface.
|
|
46
|
+
|
|
47
|
+
### Errors
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError,
|
|
51
|
+
HazoConflictError, HazoRateLimitError, HazoUnavailableError,
|
|
52
|
+
HazoExternalError, HazoConfigError, HazoInternalError } from 'hazo_core/errors';
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Context (correlation ID)
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { withContext, getContext, getCorrelationId } from 'hazo_core/context';
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Config, logger, debug, singletons
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { loadConfig, defineConfig, createLogger, createDebug,
|
|
65
|
+
registerSingleton, getSingleton, generateRequestId,
|
|
66
|
+
fetchWithRequestId, createRequestIdMiddleware, REQUEST_ID_HEADER } from 'hazo_core';
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Browser-safe subset
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { HazoError } from 'hazo_core/errors';
|
|
73
|
+
import { getCorrelationId, setBrowserCorrelationId } from 'hazo_core/context';
|
|
74
|
+
import { REQUEST_ID_HEADER } from 'hazo_core/client';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
Copy `config/hazo_core_config.ini` to your app's config directory. See `SETUP_CHECKLIST.md` for integration steps.
|
|
80
|
+
|
|
81
|
+
## See also
|
|
82
|
+
|
|
83
|
+
- `design/architecture.md` — full PRD and design rationale
|
|
84
|
+
- `SETUP_CHECKLIST.md` — step-by-step integration guide
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# hazo_core — Setup Checklist
|
|
2
|
+
|
|
3
|
+
Step-by-step guide for integrating `hazo_core` into a consuming app or hazo_* package.
|
|
4
|
+
|
|
5
|
+
## 1. Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install hazo_core hazo_logs hazo_debug
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2. Copy the config template
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cp node_modules/hazo_core/config/hazo_core_config.ini config/hazo_core_config.ini
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Edit `config/hazo_core_config.ini` as needed. Key settings:
|
|
18
|
+
|
|
19
|
+
| Key | Default | Description |
|
|
20
|
+
|-----|---------|-------------|
|
|
21
|
+
| `[log] include_stack` | `false` | Include stack traces in error JSON (set to `true` for local debug) |
|
|
22
|
+
|
|
23
|
+
## 3. Wire correlation ID at every entry point
|
|
24
|
+
|
|
25
|
+
**Next.js App Router** — add to `app/api/[...]/route.ts`:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { withRequestIdRouteHandler } from 'hazo_core';
|
|
29
|
+
export const GET = withRequestIdRouteHandler(async (req) => { ... });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Express** — add middleware:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createRequestIdMiddleware } from 'hazo_core';
|
|
36
|
+
app.use(createRequestIdMiddleware());
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Background jobs / cron** — wrap worker bootstrap:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { withContext, generateRequestId } from 'hazo_core';
|
|
43
|
+
const cid = process.env.CORRELATION_ID ?? generateRequestId();
|
|
44
|
+
withContext({ correlationId: cid }, () => runWorker());
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 4. Use the logger
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createLogger } from 'hazo_core';
|
|
51
|
+
const log = createLogger('myapp');
|
|
52
|
+
log.info('server.started', { port: 3000 });
|
|
53
|
+
// Logs include: pkg, correlationId, userId (if in context), env, timestamp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 5. Use the config loader
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { loadConfig, defineConfig } from 'hazo_core';
|
|
60
|
+
import z from 'zod';
|
|
61
|
+
|
|
62
|
+
const config = loadConfig({
|
|
63
|
+
pkg: 'myapp',
|
|
64
|
+
configDir: path.join(process.cwd(), 'config'),
|
|
65
|
+
schema: defineConfig({
|
|
66
|
+
port: z.number().default(3000),
|
|
67
|
+
secret: z.string(),
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 6. Browser context (React apps)
|
|
73
|
+
|
|
74
|
+
Wrap your React tree in `HazoContextProvider` (from `hazo_ui`):
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { HazoContextProvider } from 'hazo_ui';
|
|
78
|
+
export default function RootLayout({ children }) {
|
|
79
|
+
return <HazoContextProvider>{children}</HazoContextProvider>;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 7. HAZO_ENV convention
|
|
84
|
+
|
|
85
|
+
Set `HAZO_ENV` in your deployment environment to declare which environment is running. Falls back to `NODE_ENV` then `'development'`.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
HAZO_ENV=production node server.js
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Create per-env config overlays:
|
|
92
|
+
```
|
|
93
|
+
config/hazo_core_config.ini # base
|
|
94
|
+
config/hazo_core_config.production.ini # production overrides
|
|
95
|
+
config/hazo_core_config.staging.ini # staging overrides
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 8. Error handling
|
|
99
|
+
|
|
100
|
+
All `hazo_*` packages throw `HazoError` subclasses. Catch at API boundaries:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { HazoError } from 'hazo_core/errors';
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await doSomething();
|
|
107
|
+
} catch (err) {
|
|
108
|
+
if (HazoError.is(err)) {
|
|
109
|
+
const { status, body } = err.toHttpResponse();
|
|
110
|
+
return Response.json(body, { status });
|
|
111
|
+
}
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
; hazo_core configuration
|
|
2
|
+
; All values can be overridden via env vars: HAZO_CORE_<SECTION>_<KEY>=value
|
|
3
|
+
|
|
4
|
+
[log]
|
|
5
|
+
; Include stack traces in HazoError.toJSON() and log output.
|
|
6
|
+
; Default: false in production, true otherwise.
|
|
7
|
+
; Override with HAZO_INCLUDE_STACK=1 to force on.
|
|
8
|
+
include_stack = false
|
|
9
|
+
|
|
10
|
+
[env]
|
|
11
|
+
; This section is an example of the per-env overlay convention.
|
|
12
|
+
; Create hazo_core_config.<env>.ini alongside this file to override values
|
|
13
|
+
; for a specific HAZO_ENV (e.g. hazo_core_config.development.ini).
|
|
14
|
+
; See hazo_core/SETUP_CHECKLIST.md for details.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ZodSchema, ZodRawShape } from 'zod';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
interface LoadConfigOptions<T> {
|
|
4
|
+
/** Package name e.g. 'hazo_auth' — used to build filename and env-var prefix */
|
|
5
|
+
pkg: string;
|
|
6
|
+
/** Defaults to process.cwd()/config */
|
|
7
|
+
configDir?: string;
|
|
8
|
+
/** Zod schema to validate the merged config object */
|
|
9
|
+
schema: ZodSchema<T>;
|
|
10
|
+
/** Defaults to getCurrentEnv() */
|
|
11
|
+
env?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Load, merge, validate, and cache a package config.
|
|
15
|
+
*
|
|
16
|
+
* Load order (per §8 + D-003 + D-020 hook 2):
|
|
17
|
+
* 1. <configDir>/hazo_<pkg>_config.ini (base)
|
|
18
|
+
* 2. <configDir>/hazo_<pkg>_config.<env>.ini (env overlay, skipped when env is 'development')
|
|
19
|
+
* 3. HAZO_<PKG>_<SECTION>_<KEY> env-var overrides
|
|
20
|
+
* 4. Zod validation — throws HazoConfigError on failure
|
|
21
|
+
* 5. Cache under `${pkg}:${resolvedEnv}`
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadConfig<T>(opts: LoadConfigOptions<T>): T;
|
|
24
|
+
/**
|
|
25
|
+
* Invalidate the config cache for a given package (all envs).
|
|
26
|
+
* Primarily for tests and the hazo_debug "reload config" UI button.
|
|
27
|
+
*/
|
|
28
|
+
export declare function reloadConfig(pkg: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Thin wrapper around z.object() that documents intent.
|
|
31
|
+
* Each package keeps its schema in src/config/schema.ts.
|
|
32
|
+
*/
|
|
33
|
+
export declare function defineConfig<T extends ZodRawShape>(shape: T): z.ZodObject<T>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,UAAU,iBAAiB,CAAC,CAAC;IAC3B,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAqED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAoC3D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAM9C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAE5E"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { parseIniFile, mergeIni } from './ini_parser.js';
|
|
4
|
+
import { fromZodConfig } from '../errors/from_zod.js';
|
|
5
|
+
import { getCurrentEnv } from '../utils/env.js';
|
|
6
|
+
// Cache: `${pkg}:${env}` → parsed + validated config
|
|
7
|
+
const configCache = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* Normalize a package name to the UPPER_SNAKE form used in env-var prefixes.
|
|
10
|
+
* e.g. 'hazo_llm_api' → 'HAZO_LLM_API'
|
|
11
|
+
*/
|
|
12
|
+
function pkgToEnvPrefix(pkg) {
|
|
13
|
+
return pkg.toUpperCase();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Apply env-var overrides to a merged INI object.
|
|
17
|
+
*
|
|
18
|
+
* Scans process.env for keys matching HAZO_<PKG>_<SECTION>_<KEY> and writes
|
|
19
|
+
* them into the merged object at [section][key] (lowercase).
|
|
20
|
+
*
|
|
21
|
+
* Per D-003 and D-020 hook 6.
|
|
22
|
+
*/
|
|
23
|
+
function applyEnvVarOverrides(merged, pkg) {
|
|
24
|
+
const prefix = `${pkgToEnvPrefix(pkg)}_`;
|
|
25
|
+
const result = { ...merged };
|
|
26
|
+
const overrideKeys = [];
|
|
27
|
+
for (const [envKey, envValue] of Object.entries(process.env)) {
|
|
28
|
+
if (envValue === undefined)
|
|
29
|
+
continue;
|
|
30
|
+
if (!envKey.startsWith(prefix))
|
|
31
|
+
continue;
|
|
32
|
+
// Strip the prefix and split remaining into [SECTION, KEY]
|
|
33
|
+
const remainder = envKey.slice(prefix.length);
|
|
34
|
+
const parts = remainder.split('_');
|
|
35
|
+
if (parts.length < 2) {
|
|
36
|
+
// Must have at least SECTION_KEY
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
// Convention: everything except the last token is the section,
|
|
40
|
+
// and the last token is the key. This handles multi-word sections/keys
|
|
41
|
+
// that are already joined with underscores in the env-var name.
|
|
42
|
+
// Simple heuristic: first token is section, rest joined as key.
|
|
43
|
+
const sectionUpper = parts[0];
|
|
44
|
+
const keyUpper = parts.slice(1).join('_');
|
|
45
|
+
const section = sectionUpper.toLowerCase();
|
|
46
|
+
const key = keyUpper.toLowerCase();
|
|
47
|
+
// Ensure section exists
|
|
48
|
+
if (typeof result[section] !== 'object' || result[section] === null) {
|
|
49
|
+
result[section] = {};
|
|
50
|
+
}
|
|
51
|
+
result[section][key] = envValue;
|
|
52
|
+
overrideKeys.push(`${section}.${key}`);
|
|
53
|
+
}
|
|
54
|
+
if (overrideKeys.length > 0) {
|
|
55
|
+
console.info(`[hazo_core/loadConfig] ${pkg}: env-var overrides applied for: ${overrideKeys.join(', ')}`);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load, merge, validate, and cache a package config.
|
|
61
|
+
*
|
|
62
|
+
* Load order (per §8 + D-003 + D-020 hook 2):
|
|
63
|
+
* 1. <configDir>/hazo_<pkg>_config.ini (base)
|
|
64
|
+
* 2. <configDir>/hazo_<pkg>_config.<env>.ini (env overlay, skipped when env is 'development')
|
|
65
|
+
* 3. HAZO_<PKG>_<SECTION>_<KEY> env-var overrides
|
|
66
|
+
* 4. Zod validation — throws HazoConfigError on failure
|
|
67
|
+
* 5. Cache under `${pkg}:${resolvedEnv}`
|
|
68
|
+
*/
|
|
69
|
+
export function loadConfig(opts) {
|
|
70
|
+
const resolvedEnv = opts.env ?? getCurrentEnv();
|
|
71
|
+
const cacheKey = `${opts.pkg}:${resolvedEnv}`;
|
|
72
|
+
if (configCache.has(cacheKey)) {
|
|
73
|
+
return configCache.get(cacheKey);
|
|
74
|
+
}
|
|
75
|
+
const configDir = opts.configDir ?? path.join(process.cwd(), 'config');
|
|
76
|
+
// 1. Base INI
|
|
77
|
+
const baseFile = path.join(configDir, `hazo_${opts.pkg}_config.ini`);
|
|
78
|
+
let merged = parseIniFile(baseFile);
|
|
79
|
+
// 2. Env overlay (skip for development)
|
|
80
|
+
if (resolvedEnv !== 'development') {
|
|
81
|
+
const overlayFile = path.join(configDir, `hazo_${opts.pkg}_config.${resolvedEnv}.ini`);
|
|
82
|
+
const overlay = parseIniFile(overlayFile);
|
|
83
|
+
merged = mergeIni(merged, overlay);
|
|
84
|
+
}
|
|
85
|
+
// 3. Env-var overrides
|
|
86
|
+
merged = applyEnvVarOverrides(merged, opts.pkg);
|
|
87
|
+
// 4. Zod validation
|
|
88
|
+
const result = opts.schema.safeParse(merged);
|
|
89
|
+
if (!result.success) {
|
|
90
|
+
throw fromZodConfig(result.error, {
|
|
91
|
+
pkg: opts.pkg,
|
|
92
|
+
code: `HAZO_${opts.pkg.toUpperCase()}_CONFIG_INVALID`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// 5. Cache and return
|
|
96
|
+
configCache.set(cacheKey, result.data);
|
|
97
|
+
return result.data;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Invalidate the config cache for a given package (all envs).
|
|
101
|
+
* Primarily for tests and the hazo_debug "reload config" UI button.
|
|
102
|
+
*/
|
|
103
|
+
export function reloadConfig(pkg) {
|
|
104
|
+
for (const key of Array.from(configCache.keys())) {
|
|
105
|
+
if (key.startsWith(`${pkg}:`)) {
|
|
106
|
+
configCache.delete(key);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Thin wrapper around z.object() that documents intent.
|
|
112
|
+
* Each package keeps its schema in src/config/schema.ts.
|
|
113
|
+
*/
|
|
114
|
+
export function defineConfig(shape) {
|
|
115
|
+
return z.object(shape);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read and parse an INI file. Returns an empty object if file not found.
|
|
3
|
+
*/
|
|
4
|
+
export declare function parseIniFile(filePath: string): Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* Merge two parsed INI objects. Overlay values win for scalar conflicts;
|
|
7
|
+
* nested objects are shallow-merged.
|
|
8
|
+
*/
|
|
9
|
+
export declare function mergeIni(base: Record<string, unknown>, overlay: Record<string, unknown>): Record<string, unknown>;
|
|
10
|
+
//# sourceMappingURL=ini_parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ini_parser.d.ts","sourceRoot":"","sources":["../../src/config/ini_parser.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUtE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBzB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { parse } from 'ini';
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
/**
|
|
4
|
+
* Read and parse an INI file. Returns an empty object if file not found.
|
|
5
|
+
*/
|
|
6
|
+
export function parseIniFile(filePath) {
|
|
7
|
+
if (!existsSync(filePath)) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
12
|
+
return parse(content);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Merge two parsed INI objects. Overlay values win for scalar conflicts;
|
|
20
|
+
* nested objects are shallow-merged.
|
|
21
|
+
*/
|
|
22
|
+
export function mergeIni(base, overlay) {
|
|
23
|
+
const result = { ...base };
|
|
24
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
25
|
+
const baseValue = result[key];
|
|
26
|
+
if (value !== null &&
|
|
27
|
+
typeof value === 'object' &&
|
|
28
|
+
!Array.isArray(value) &&
|
|
29
|
+
baseValue !== null &&
|
|
30
|
+
typeof baseValue === 'object' &&
|
|
31
|
+
!Array.isArray(baseValue)) {
|
|
32
|
+
// Both sides are plain objects — shallow-merge
|
|
33
|
+
result[key] = {
|
|
34
|
+
...baseValue,
|
|
35
|
+
...value,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Overlay wins
|
|
40
|
+
result[key] = value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=ini_parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ini_parser.js","sourceRoot":"","sources":["../../src/config/ini_parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEnD;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,KAAK,CAAC,OAAO,CAA4B,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CACtB,IAA6B,EAC7B,OAAgC;IAEhC,MAAM,MAAM,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;IAEpD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,IACE,KAAK,KAAK,IAAI;YACd,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACrB,SAAS,KAAK,IAAI;YAClB,OAAO,SAAS,KAAK,QAAQ;YAC7B,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EACzB,CAAC;YACD,+CAA+C;YAC/C,MAAM,CAAC,GAAG,CAAC,GAAG;gBACZ,GAAI,SAAqC;gBACzC,GAAI,KAAiC;aACtC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,eAAe;YACf,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,iBAAiB,eAAgC,CAAC;AAC/D,eAAO,MAAM,mBAAmB,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAChD,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HazoContext } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Set (or clear) the browser-side correlation ID.
|
|
4
|
+
* Pass undefined to clear the current context.
|
|
5
|
+
* Typically called by hazo_ui's <HazoContextProvider> on mount.
|
|
6
|
+
*/
|
|
7
|
+
export declare function setBrowserCorrelationId(id?: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Read the current browser context.
|
|
10
|
+
* Returns undefined when no context has been set.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getContext(): HazoContext | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Convenience accessor for the correlation ID.
|
|
15
|
+
* Returns undefined when no context has been set.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getCorrelationId(): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Synchronously run `fn` within a new context derived from `values`.
|
|
20
|
+
* Saves and restores the previous context so calls can be nested.
|
|
21
|
+
*
|
|
22
|
+
* Unlike the server implementation, this is synchronous-only — there is no
|
|
23
|
+
* async boundary tracking. Concurrent async operations in a browser will share
|
|
24
|
+
* the same context ref, which is appropriate for the single-tab model.
|
|
25
|
+
*/
|
|
26
|
+
export declare function withContext<T>(values: Partial<HazoContext>, fn: () => T): T;
|
|
27
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/context/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAc9C;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CASzD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,WAAW,GAAG,SAAS,CAEpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAmB3E"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser context implementation — single mutable ref per tab.
|
|
3
|
+
*
|
|
4
|
+
* The server's AsyncLocalStorage is not available in browsers. A single module-level
|
|
5
|
+
* ref matches the one-tab-one-context reality (per D-004).
|
|
6
|
+
*
|
|
7
|
+
* In React apps, hazo_ui's <HazoContextProvider> calls setBrowserCorrelationId() on
|
|
8
|
+
* mount so all downstream code (fetch wrappers, error constructors) can read the ID.
|
|
9
|
+
*/
|
|
10
|
+
let _currentContext;
|
|
11
|
+
/**
|
|
12
|
+
* Set (or clear) the browser-side correlation ID.
|
|
13
|
+
* Pass undefined to clear the current context.
|
|
14
|
+
* Typically called by hazo_ui's <HazoContextProvider> on mount.
|
|
15
|
+
*/
|
|
16
|
+
export function setBrowserCorrelationId(id) {
|
|
17
|
+
if (id === undefined) {
|
|
18
|
+
_currentContext = undefined;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
_currentContext = {
|
|
22
|
+
..._currentContext,
|
|
23
|
+
correlationId: id,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Read the current browser context.
|
|
29
|
+
* Returns undefined when no context has been set.
|
|
30
|
+
*/
|
|
31
|
+
export function getContext() {
|
|
32
|
+
return _currentContext;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Convenience accessor for the correlation ID.
|
|
36
|
+
* Returns undefined when no context has been set.
|
|
37
|
+
*/
|
|
38
|
+
export function getCorrelationId() {
|
|
39
|
+
return _currentContext?.correlationId;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Synchronously run `fn` within a new context derived from `values`.
|
|
43
|
+
* Saves and restores the previous context so calls can be nested.
|
|
44
|
+
*
|
|
45
|
+
* Unlike the server implementation, this is synchronous-only — there is no
|
|
46
|
+
* async boundary tracking. Concurrent async operations in a browser will share
|
|
47
|
+
* the same context ref, which is appropriate for the single-tab model.
|
|
48
|
+
*/
|
|
49
|
+
export function withContext(values, fn) {
|
|
50
|
+
const previous = _currentContext;
|
|
51
|
+
const merged = values.correlationId !== undefined || previous !== undefined
|
|
52
|
+
? {
|
|
53
|
+
...previous,
|
|
54
|
+
...values,
|
|
55
|
+
correlationId: values.correlationId ?? previous?.correlationId ?? '',
|
|
56
|
+
}
|
|
57
|
+
: undefined;
|
|
58
|
+
_currentContext = merged;
|
|
59
|
+
try {
|
|
60
|
+
return fn();
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
_currentContext = previous;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/context/client.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,IAAI,eAAwC,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,EAAW;IACjD,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,eAAe,GAAG,SAAS,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,eAAe,GAAG;YAChB,GAAG,eAAe;YAClB,aAAa,EAAE,EAAE;SAClB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,eAAe,EAAE,aAAa,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAI,MAA4B,EAAE,EAAW;IACtE,MAAM,QAAQ,GAAG,eAAe,CAAC;IAEjC,MAAM,MAAM,GACV,MAAM,CAAC,aAAa,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS;QAC1D,CAAC,CAAC;YACE,GAAG,QAAQ;YACX,GAAG,MAAM;YACT,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,QAAQ,EAAE,aAAa,IAAI,EAAE;SACrE;QACH,CAAC,CAAC,SAAS,CAAC;IAEhB,eAAe,GAAG,MAAM,CAAC;IAEzB,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,eAAe,GAAG,QAAQ,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side context implementation (AsyncLocalStorage).
|
|
3
|
+
*
|
|
4
|
+
* Browser-safe consumers should import from 'hazo_core/client' or directly from
|
|
5
|
+
* './client.js' — they cannot use this file as it imports node:async_hooks.
|
|
6
|
+
*/
|
|
7
|
+
export { withContext, getContext, getCorrelationId } from './server.js';
|
|
8
|
+
export type { HazoContext } from './types.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side context implementation (AsyncLocalStorage).
|
|
3
|
+
*
|
|
4
|
+
* Browser-safe consumers should import from 'hazo_core/client' or directly from
|
|
5
|
+
* './client.js' — they cannot use this file as it imports node:async_hooks.
|
|
6
|
+
*/
|
|
7
|
+
export { withContext, getContext, getCorrelationId } from './server.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HazoContext } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Run `fn` within a new context that merges `values` on top of the parent context.
|
|
4
|
+
*
|
|
5
|
+
* Merge rules:
|
|
6
|
+
* 1. Parent context fields are inherited unless explicitly overridden by `values`.
|
|
7
|
+
* 2. `correlationId` is generated if neither `values` nor parent provides one.
|
|
8
|
+
*
|
|
9
|
+
* This means a child span always carries the parent's correlationId unless the caller
|
|
10
|
+
* explicitly wants to start a new correlation boundary.
|
|
11
|
+
*/
|
|
12
|
+
export declare function withContext<T>(values: Partial<HazoContext>, fn: () => T): T;
|
|
13
|
+
/**
|
|
14
|
+
* Read the current context, if any.
|
|
15
|
+
* Returns undefined when called outside a withContext() scope.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getContext(): HazoContext | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Convenience accessor for the most-commonly-needed context field.
|
|
20
|
+
* Returns undefined when called outside a withContext() scope.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getCorrelationId(): string | undefined;
|
|
23
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/context/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkB9C;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAc3E;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,WAAW,GAAG,SAAS,CAEpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAErD"}
|