hazo_config 1.3.0 → 1.4.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.
@@ -48,4 +48,29 @@ alwaysApply: true
48
48
  - When error messages are shown to the user, they should always be logged verbatem in the serverside log file as well
49
49
  - pretty print the json output
50
50
  - don't import the logger in the client side code
51
- - whenever there's any actions on the database, or any API calls, please add details of the payload and update as well as the resulsts in the log file to help debug issues. For API calls, don't save any base64 data as it is too large.
51
+ - whenever there's any actions on the database, or any API calls, please add details of the payload and update as well as the resulsts in the log file to help debug issues. For API calls, don't save any base64 data as it is too large.
52
+
53
+ [For Packages ES Module Exports]
54
+ - When creating npm packages that will be consumed by ES module bundlers (Next.js, Vite, etc.), ALL export statements MUST use explicit file paths with .js extensions
55
+ - Directory imports like `export * from './components'` are INVALID in ES modules and will fail at runtime
56
+ - ALWAYS use explicit paths: `export * from './components/index.js'` instead of `export * from './components'`
57
+ - Even though source files are .ts, TypeScript requires .js extensions in import/export paths for ES module output
58
+ - This applies to all export statements in index.ts files and any barrel export files
59
+
60
+ [For packages: TypeScript Configuration]
61
+ - For package builds (tsconfig.build.json), set moduleResolution to "node16" or "node" (not "bundler") when shipping compiled output
62
+ - Ensure module is set to "ESNext" or "ES2020" for modern ES module output
63
+ - Add "type": "module" to package.json if shipping pure ESM packages
64
+
65
+ [For Packages: Export Path Rules]
66
+ - ✅ CORRECT: `export * from './lib/index.js'`
67
+ - ✅ CORRECT: `export * from './components/index.js'`
68
+ - ✅ CORRECT: `export { Something } from './utils.js'`
69
+ - ❌ WRONG: `export * from './lib'`
70
+ - ❌ WRONG: `export * from './components'`
71
+ - ❌ WRONG: `export { Something } from './utils'` (without extension)
72
+
73
+ [Verification]
74
+ - After building, check dist/index.js and ensure all export paths have .js extensions
75
+ - Test the built package in a consuming Next.js or ES module project to verify imports work
76
+ - If using TypeScript path aliases (@/...), ensure they are resolved to relative paths in the compiled output (not left as aliases)
@@ -0,0 +1,34 @@
1
+ ---
2
+ description: Rules for package/library development to ensure ES module compatibility
3
+ globs:
4
+ - "src/**/*.ts"
5
+ - "src/**/*.tsx"
6
+ - "tsconfig*.json"
7
+ - "package.json"
8
+ alwaysApply: true
9
+ ---
10
+
11
+ [Package Development - ES Module Exports]
12
+ - When creating npm packages that will be consumed by ES module bundlers (Next.js, Vite, etc.), ALL export statements MUST use explicit file paths with .js extensions
13
+ - Directory imports like `export * from './components'` are INVALID in ES modules and will fail at runtime
14
+ - ALWAYS use explicit paths: `export * from './components/index.js'` instead of `export * from './components'`
15
+ - Even though source files are .ts, TypeScript requires .js extensions in import/export paths for ES module output
16
+ - This applies to all export statements in index.ts files and any barrel export files
17
+
18
+ [TypeScript Configuration for Packages]
19
+ - For package builds (tsconfig.build.json), set moduleResolution to "node16" or "node" (not "bundler") when shipping compiled output
20
+ - Ensure module is set to "ESNext" or "ES2020" for modern ES module output
21
+ - Add "type": "module" to package.json if shipping pure ESM packages
22
+
23
+ [Export Path Rules]
24
+ - ✅ CORRECT: `export * from './lib/index.js'`
25
+ - ✅ CORRECT: `export * from './components/index.js'`
26
+ - ✅ CORRECT: `export { Something } from './utils.js'`
27
+ - ❌ WRONG: `export * from './lib'`
28
+ - ❌ WRONG: `export * from './components'`
29
+ - ❌ WRONG: `export { Something } from './utils'` (without extension)
30
+
31
+ [Verification]
32
+ - After building, check dist/index.js and ensure all export paths have .js extensions
33
+ - Test the built package in a consuming Next.js or ES module project to verify imports work
34
+ - If using TypeScript path aliases (@/...), ensure they are resolved to relative paths in the compiled output (not left as aliases)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 pub12
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
- export { ExampleComponent } from './example_component';
2
- export { ConfigViewer } from './config_viewer';
3
- export { ConfigEditor } from './config_editor';
4
- export type { ConfigViewerProps } from './config_viewer';
5
- export type { ConfigEditorProps } from './config_editor';
1
+ export { ExampleComponent } from './example_component.js';
2
+ export { ConfigViewer } from './config_viewer.js';
3
+ export { ConfigEditor } from './config_editor.js';
4
+ export type { ConfigViewerProps } from './config_viewer.js';
5
+ export type { ConfigEditorProps } from './config_editor.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,5 +1,5 @@
1
1
  // Component exports
2
2
  // Export all components from this file for easy importing
3
- export { ExampleComponent } from './example_component';
4
- export { ConfigViewer } from './config_viewer';
5
- export { ConfigEditor } from './config_editor';
3
+ export { ExampleComponent } from './example_component.js';
4
+ export { ConfigViewer } from './config_viewer.js';
5
+ export { ConfigEditor } from './config_editor.js';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './components';
2
- export * from './lib/utils';
3
- export * from './lib';
1
+ export * from './components/index.js';
2
+ export * from './lib/utils.js';
3
+ export * from './lib/index.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,OAAO,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,uBAAuB,CAAA;AACrC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Main entry point for the component library
2
2
  // Export all components and utilities from this file
3
- export * from './components';
4
- export * from './lib/utils';
5
- export * from './lib';
3
+ export * from './components/index.js';
4
+ export * from './lib/utils.js';
5
+ export * from './lib/index.js';
@@ -11,18 +11,26 @@ import type { ConfigProvider, HazoConfigOptions } from './types';
11
11
  * HazoConfig class
12
12
  *
13
13
  * Implements ConfigProvider interface for managing INI configuration files.
14
- * Provides sync read/write operations with in-memory caching.
14
+ * Provides sync read/write operations with in-memory caching and automatic cache refresh.
15
15
  */
16
16
  export declare class HazoConfig implements ConfigProvider {
17
17
  private filePath;
18
18
  private logger;
19
19
  private config;
20
+ private cache_ttl_ms;
21
+ private disable_cache;
22
+ private last_cache_refresh;
20
23
  /**
21
24
  * Constructor
22
- * @param options - Configuration options including filePath and optional logger
25
+ * @param options - Configuration options including filePath, optional logger, cache settings
23
26
  * @throws Error if file doesn't exist
24
27
  */
25
28
  constructor(options: HazoConfigOptions);
29
+ /**
30
+ * Check if cache needs to be refreshed and refresh if needed
31
+ * This method is called before read operations to ensure cache is up to date
32
+ */
33
+ private ensure_cache_fresh;
26
34
  /**
27
35
  * Get a configuration value by section and key
28
36
  * @param section - The configuration section name
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/lib/config-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAU,MAAM,SAAS,CAAA;AAaxE;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAA6C;IAE3D;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IAgBtC;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIrD;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;IAI/D;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQtD;;;OAGG;IACH,IAAI,IAAI,IAAI;IAqBZ;;;OAGG;IACH,OAAO,IAAI,IAAI;IAuCf;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB;;;OAGG;IACH,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAQzD"}
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/lib/config-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAU,MAAM,SAAS,CAAA;AAaxE;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC/C,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,kBAAkB,CAAY;IAEtC;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IAkBtC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAsB1B;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKrD;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;IAK/D;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQtD;;;OAGG;IACH,IAAI,IAAI,IAAI;IAqBZ;;;OAGG;IACH,OAAO,IAAI,IAAI;IA0Cf;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB;;;OAGG;IACH,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CASzD"}
@@ -23,12 +23,12 @@ const no_op_logger = {
23
23
  * HazoConfig class
24
24
  *
25
25
  * Implements ConfigProvider interface for managing INI configuration files.
26
- * Provides sync read/write operations with in-memory caching.
26
+ * Provides sync read/write operations with in-memory caching and automatic cache refresh.
27
27
  */
28
28
  export class HazoConfig {
29
29
  /**
30
30
  * Constructor
31
- * @param options - Configuration options including filePath and optional logger
31
+ * @param options - Configuration options including filePath, optional logger, cache settings
32
32
  * @throws Error if file doesn't exist
33
33
  */
34
34
  constructor(options) {
@@ -50,8 +50,28 @@ export class HazoConfig {
50
50
  writable: true,
51
51
  value: {}
52
52
  });
53
+ Object.defineProperty(this, "cache_ttl_ms", {
54
+ enumerable: true,
55
+ configurable: true,
56
+ writable: true,
57
+ value: void 0
58
+ });
59
+ Object.defineProperty(this, "disable_cache", {
60
+ enumerable: true,
61
+ configurable: true,
62
+ writable: true,
63
+ value: void 0
64
+ });
65
+ Object.defineProperty(this, "last_cache_refresh", {
66
+ enumerable: true,
67
+ configurable: true,
68
+ writable: true,
69
+ value: 0
70
+ });
53
71
  this.filePath = path.resolve(options.filePath);
54
72
  this.logger = options.logger || no_op_logger;
73
+ this.cache_ttl_ms = options.cache_ttl_ms ?? 5000; // Default 5 seconds
74
+ this.disable_cache = options.disable_cache ?? false; // Default: caching enabled
55
75
  // Validate file exists
56
76
  if (!fs.existsSync(this.filePath)) {
57
77
  const error = new Error(`Configuration file not found: ${this.filePath}`);
@@ -62,6 +82,28 @@ export class HazoConfig {
62
82
  // Load initial configuration
63
83
  this.refresh();
64
84
  }
85
+ /**
86
+ * Check if cache needs to be refreshed and refresh if needed
87
+ * This method is called before read operations to ensure cache is up to date
88
+ */
89
+ ensure_cache_fresh() {
90
+ if (this.disable_cache) {
91
+ // If caching is disabled, always refresh from disk
92
+ this.refresh();
93
+ return;
94
+ }
95
+ if (this.cache_ttl_ms === 0) {
96
+ // If TTL is 0, cache never expires (only manual refresh)
97
+ return;
98
+ }
99
+ const now = Date.now();
100
+ const cache_age = now - this.last_cache_refresh;
101
+ if (cache_age >= this.cache_ttl_ms) {
102
+ // Cache has expired, refresh from disk
103
+ this.logger.debug(`[HazoConfig] Cache expired (age: ${cache_age}ms, ttl: ${this.cache_ttl_ms}ms), refreshing from disk`);
104
+ this.refresh();
105
+ }
106
+ }
65
107
  /**
66
108
  * Get a configuration value by section and key
67
109
  * @param section - The configuration section name
@@ -69,6 +111,7 @@ export class HazoConfig {
69
111
  * @returns The configuration value, or undefined if not found
70
112
  */
71
113
  get(section, key) {
114
+ this.ensure_cache_fresh();
72
115
  return this.config[section]?.[key];
73
116
  }
74
117
  /**
@@ -77,6 +120,7 @@ export class HazoConfig {
77
120
  * @returns A record of key-value pairs for the section, or undefined if section doesn't exist
78
121
  */
79
122
  getSection(section) {
123
+ this.ensure_cache_fresh();
80
124
  return this.config[section] ? { ...this.config[section] } : undefined;
81
125
  }
82
126
  /**
@@ -135,6 +179,8 @@ export class HazoConfig {
135
179
  }
136
180
  }
137
181
  }
182
+ // Update cache timestamp
183
+ this.last_cache_refresh = Date.now();
138
184
  this.logger.info(`[HazoConfig] Configuration refreshed from: ${this.filePath}`, {
139
185
  sections: Object.keys(this.config)
140
186
  });
@@ -167,6 +213,7 @@ export class HazoConfig {
167
213
  * @returns A record of all sections and their key-value pairs
168
214
  */
169
215
  getAllSections() {
216
+ this.ensure_cache_fresh();
170
217
  // Return a deep copy to prevent external modification
171
218
  const result = {};
172
219
  for (const [section, values] of Object.entries(this.config)) {
@@ -5,8 +5,8 @@
5
5
  * configuration management utility. It serves as the primary entry point
6
6
  * for consumers of the library.
7
7
  */
8
- export { HazoConfig } from './config-loader';
9
- export { MockConfigProvider } from './mock_config_provider';
10
- export { ConfigErrorCode } from './types';
11
- export type { ConfigProvider, HazoConfigOptions, Logger, HazoConfigError } from './types';
8
+ export { HazoConfig } from './config-loader.js';
9
+ export { MockConfigProvider } from './mock_config_provider.js';
10
+ export { ConfigErrorCode } from './types.js';
11
+ export type { ConfigProvider, HazoConfigOptions, Logger, HazoConfigError } from './types.js';
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,MAAM,EACN,eAAe,EAChB,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,MAAM,EACN,eAAe,EAChB,MAAM,YAAY,CAAA"}
package/dist/lib/index.js CHANGED
@@ -5,6 +5,6 @@
5
5
  * configuration management utility. It serves as the primary entry point
6
6
  * for consumers of the library.
7
7
  */
8
- export { HazoConfig } from './config-loader';
9
- export { MockConfigProvider } from './mock_config_provider';
10
- export { ConfigErrorCode } from './types';
8
+ export { HazoConfig } from './config-loader.js';
9
+ export { MockConfigProvider } from './mock_config_provider.js';
10
+ export { ConfigErrorCode } from './types.js';
@@ -68,6 +68,18 @@ export interface HazoConfigOptions {
68
68
  * Optional logger instance for logging operations
69
69
  */
70
70
  logger?: Logger;
71
+ /**
72
+ * Cache time-to-live in milliseconds (default: 5000ms)
73
+ * When cache expires, configuration will be automatically refreshed from disk
74
+ * Set to 0 to disable automatic cache expiration (cache will only refresh on manual refresh() call)
75
+ */
76
+ cache_ttl_ms?: number;
77
+ /**
78
+ * Disable caching entirely (default: false)
79
+ * When true, every get() and getSection() call will read from disk
80
+ * When false, values are cached in memory and refreshed based on cache_ttl_ms
81
+ */
82
+ disable_cache?: boolean;
71
83
  }
72
84
  /**
73
85
  * Error codes for configuration operations
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACxC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACvC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACvC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CACzC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAErD;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IAE/D;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAEtD;;;OAGG;IACH,IAAI,IAAI,IAAI,CAAA;IAEZ;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,cAAc,+BAA+B;IAC7C,UAAU,2BAA2B;IACrC,WAAW,4BAA4B;IACvC,WAAW,4BAA4B;IACvC,gBAAgB,iCAAiC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,GAAG,CAAA;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACxC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACvC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;IACvC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CACzC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAErD;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IAE/D;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAEtD;;;OAGG;IACH,IAAI,IAAI,IAAI,CAAA;IAEZ;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,cAAc,+BAA+B;IAC7C,UAAU,2BAA2B;IACrC,WAAW,4BAA4B;IACvC,WAAW,4BAA4B;IACvC,gBAAgB,iCAAiC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,GAAG,CAAA;CACpB"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "hazo_config",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Config wrapper with error handling",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
7
8
  "scripts": {
@@ -1,9 +1,9 @@
1
1
  // Component exports
2
2
  // Export all components from this file for easy importing
3
3
 
4
- export { ExampleComponent } from './example_component'
5
- export { ConfigViewer } from './config_viewer'
6
- export { ConfigEditor } from './config_editor'
7
- export type { ConfigViewerProps } from './config_viewer'
8
- export type { ConfigEditorProps } from './config_editor'
4
+ export { ExampleComponent } from './example_component.js'
5
+ export { ConfigViewer } from './config_viewer.js'
6
+ export { ConfigEditor } from './config_editor.js'
7
+ export type { ConfigViewerProps } from './config_viewer.js'
8
+ export type { ConfigEditorProps } from './config_editor.js'
9
9
 
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // Main entry point for the component library
2
2
  // Export all components and utilities from this file
3
3
 
4
- export * from './components'
5
- export * from './lib/utils'
6
- export * from './lib'
4
+ export * from './components/index.js'
5
+ export * from './lib/utils.js'
6
+ export * from './lib/index.js'
7
7
 
@@ -27,21 +27,26 @@ const no_op_logger: Logger = {
27
27
  * HazoConfig class
28
28
  *
29
29
  * Implements ConfigProvider interface for managing INI configuration files.
30
- * Provides sync read/write operations with in-memory caching.
30
+ * Provides sync read/write operations with in-memory caching and automatic cache refresh.
31
31
  */
32
32
  export class HazoConfig implements ConfigProvider {
33
33
  private filePath: string
34
34
  private logger: Logger
35
35
  private config: Record<string, Record<string, string>> = {}
36
+ private cache_ttl_ms: number
37
+ private disable_cache: boolean
38
+ private last_cache_refresh: number = 0
36
39
 
37
40
  /**
38
41
  * Constructor
39
- * @param options - Configuration options including filePath and optional logger
42
+ * @param options - Configuration options including filePath, optional logger, cache settings
40
43
  * @throws Error if file doesn't exist
41
44
  */
42
45
  constructor(options: HazoConfigOptions) {
43
46
  this.filePath = path.resolve(options.filePath)
44
47
  this.logger = options.logger || no_op_logger
48
+ this.cache_ttl_ms = options.cache_ttl_ms ?? 5000 // Default 5 seconds
49
+ this.disable_cache = options.disable_cache ?? false // Default: caching enabled
45
50
 
46
51
  // Validate file exists
47
52
  if (!fs.existsSync(this.filePath)) {
@@ -55,6 +60,32 @@ export class HazoConfig implements ConfigProvider {
55
60
  this.refresh()
56
61
  }
57
62
 
63
+ /**
64
+ * Check if cache needs to be refreshed and refresh if needed
65
+ * This method is called before read operations to ensure cache is up to date
66
+ */
67
+ private ensure_cache_fresh(): void {
68
+ if (this.disable_cache) {
69
+ // If caching is disabled, always refresh from disk
70
+ this.refresh()
71
+ return
72
+ }
73
+
74
+ if (this.cache_ttl_ms === 0) {
75
+ // If TTL is 0, cache never expires (only manual refresh)
76
+ return
77
+ }
78
+
79
+ const now = Date.now()
80
+ const cache_age = now - this.last_cache_refresh
81
+
82
+ if (cache_age >= this.cache_ttl_ms) {
83
+ // Cache has expired, refresh from disk
84
+ this.logger.debug(`[HazoConfig] Cache expired (age: ${cache_age}ms, ttl: ${this.cache_ttl_ms}ms), refreshing from disk`)
85
+ this.refresh()
86
+ }
87
+ }
88
+
58
89
  /**
59
90
  * Get a configuration value by section and key
60
91
  * @param section - The configuration section name
@@ -62,6 +93,7 @@ export class HazoConfig implements ConfigProvider {
62
93
  * @returns The configuration value, or undefined if not found
63
94
  */
64
95
  get(section: string, key: string): string | undefined {
96
+ this.ensure_cache_fresh()
65
97
  return this.config[section]?.[key]
66
98
  }
67
99
 
@@ -71,6 +103,7 @@ export class HazoConfig implements ConfigProvider {
71
103
  * @returns A record of key-value pairs for the section, or undefined if section doesn't exist
72
104
  */
73
105
  getSection(section: string): Record<string, string> | undefined {
106
+ this.ensure_cache_fresh()
74
107
  return this.config[section] ? { ...this.config[section] } : undefined
75
108
  }
76
109
 
@@ -135,6 +168,9 @@ export class HazoConfig implements ConfigProvider {
135
168
  }
136
169
  }
137
170
 
171
+ // Update cache timestamp
172
+ this.last_cache_refresh = Date.now()
173
+
138
174
  this.logger.info(`[HazoConfig] Configuration refreshed from: ${this.filePath}`, {
139
175
  sections: Object.keys(this.config)
140
176
  })
@@ -169,6 +205,7 @@ export class HazoConfig implements ConfigProvider {
169
205
  * @returns A record of all sections and their key-value pairs
170
206
  */
171
207
  getAllSections(): Record<string, Record<string, string>> {
208
+ this.ensure_cache_fresh()
172
209
  // Return a deep copy to prevent external modification
173
210
  const result: Record<string, Record<string, string>> = {}
174
211
  for (const [section, values] of Object.entries(this.config)) {
package/src/lib/index.ts CHANGED
@@ -6,13 +6,13 @@
6
6
  * for consumers of the library.
7
7
  */
8
8
 
9
- export { HazoConfig } from './config-loader'
10
- export { MockConfigProvider } from './mock_config_provider'
11
- export { ConfigErrorCode } from './types'
9
+ export { HazoConfig } from './config-loader.js'
10
+ export { MockConfigProvider } from './mock_config_provider.js'
11
+ export { ConfigErrorCode } from './types.js'
12
12
  export type {
13
13
  ConfigProvider,
14
14
  HazoConfigOptions,
15
15
  Logger,
16
16
  HazoConfigError
17
- } from './types'
17
+ } from './types.js'
18
18
 
package/src/lib/types.ts CHANGED
@@ -76,6 +76,20 @@ export interface HazoConfigOptions {
76
76
  * Optional logger instance for logging operations
77
77
  */
78
78
  logger?: Logger
79
+
80
+ /**
81
+ * Cache time-to-live in milliseconds (default: 5000ms)
82
+ * When cache expires, configuration will be automatically refreshed from disk
83
+ * Set to 0 to disable automatic cache expiration (cache will only refresh on manual refresh() call)
84
+ */
85
+ cache_ttl_ms?: number
86
+
87
+ /**
88
+ * Disable caching entirely (default: false)
89
+ * When true, every get() and getSection() call will read from disk
90
+ * When false, values are cached in memory and refreshed based on cache_ttl_ms
91
+ */
92
+ disable_cache?: boolean
79
93
  }
80
94
 
81
95
  /**
@@ -2,11 +2,15 @@
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "noEmit": false,
5
+ "module": "ESNext",
5
6
  "declaration": true,
6
7
  "declarationMap": true,
7
8
  "outDir": "./dist",
8
9
  "rootDir": "./src",
9
- "allowImportingTsExtensions": false
10
+ "allowImportingTsExtensions": false,
11
+ "moduleResolution": "node",
12
+ "allowSyntheticDefaultImports": true,
13
+ "esModuleInterop": true
10
14
  },
11
15
  "include": ["src"],
12
16
  "exclude": ["**/*.stories.tsx", "**/*.test.tsx", "**/*.test.ts"]