hazo_config 1.3.1 → 1.4.1

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/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,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { ConfigProvider } from '../lib/types';
2
+ import type { ConfigProvider } from '../lib/types.js';
3
3
  /**
4
4
  * Config editor component props
5
5
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config_editor.d.ts","sourceRoot":"","sources":["../../src/components/config_editor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,eAAe,EAAE,cAAc,CAAA;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmLpD,CAAA"}
1
+ {"version":3,"file":"config_editor.d.ts","sourceRoot":"","sources":["../../src/components/config_editor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGrD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,eAAe,EAAE,cAAc,CAAA;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmLpD,CAAA"}
@@ -1,23 +1,20 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConfigEditor = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
5
2
  // Config editor component for managing configuration
6
3
  // Provides a more advanced interface for editing configuration values
7
- const react_1 = require("react");
8
- const utils_1 = require("../lib/utils");
9
- const lucide_react_1 = require("lucide-react");
4
+ import { useState, useEffect } from 'react';
5
+ import { cn } from '../lib/utils.js';
6
+ import { RefreshCw, Save } from 'lucide-react';
10
7
  /**
11
8
  * Config editor component
12
9
  * Provides interface for viewing and editing configuration with refresh and save capabilities
13
10
  * @param props - Component props
14
11
  * @returns React component
15
12
  */
16
- const ConfigEditor = ({ config_provider, className, on_update, }) => {
17
- const [sections, set_sections] = (0, react_1.useState)({});
18
- const [selected_section, set_selected_section] = (0, react_1.useState)(null);
19
- const [new_key, set_new_key] = (0, react_1.useState)('');
20
- const [new_value, set_new_value] = (0, react_1.useState)('');
13
+ export const ConfigEditor = ({ config_provider, className, on_update, }) => {
14
+ const [sections, set_sections] = useState({});
15
+ const [selected_section, set_selected_section] = useState(null);
16
+ const [new_key, set_new_key] = useState('');
17
+ const [new_value, set_new_value] = useState('');
21
18
  /**
22
19
  * Load configuration from provider
23
20
  */
@@ -32,7 +29,7 @@ const ConfigEditor = ({ config_provider, className, on_update, }) => {
32
29
  set_selected_section(Object.keys(all_sections)[0]);
33
30
  }
34
31
  };
35
- (0, react_1.useEffect)(() => {
32
+ useEffect(() => {
36
33
  load_config();
37
34
  }, [config_provider]);
38
35
  /**
@@ -77,9 +74,8 @@ const ConfigEditor = ({ config_provider, className, on_update, }) => {
77
74
  load_config();
78
75
  };
79
76
  const current_section_data = selected_section ? sections[selected_section] : null;
80
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('cls_config_editor space-y-4', className), children: [(0, jsx_runtime_1.jsxs)("div", { className: "cls_config_editor_header flex items-center justify-between border-b pb-2", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-xl font-semibold", children: "Configuration Editor" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: handle_refresh, className: "px-3 py-1 border rounded hover:bg-muted flex items-center gap-2", "aria-label": "Refresh", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.RefreshCw, { size: 16 }), "Refresh"] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handle_save, className: "px-3 py-1 bg-primary text-primary-foreground rounded hover:bg-primary/90 flex items-center gap-2", "aria-label": "Save", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Save, { size: 16 }), "Save"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "cls_config_editor_content grid grid-cols-1 md:grid-cols-3 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "cls_config_sections_list border rounded p-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-semibold mb-2", children: "Sections" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-1", children: Object.keys(sections).map((section_name) => ((0, jsx_runtime_1.jsx)("button", { onClick: () => set_selected_section(section_name), className: (0, utils_1.cn)('w-full text-left px-2 py-1 rounded text-sm', selected_section === section_name
77
+ return (_jsxs("div", { className: cn('cls_config_editor space-y-4', className), children: [_jsxs("div", { className: "cls_config_editor_header flex items-center justify-between border-b pb-2", children: [_jsx("h2", { className: "text-xl font-semibold", children: "Configuration Editor" }), _jsxs("div", { className: "flex gap-2", children: [_jsxs("button", { onClick: handle_refresh, className: "px-3 py-1 border rounded hover:bg-muted flex items-center gap-2", "aria-label": "Refresh", children: [_jsx(RefreshCw, { size: 16 }), "Refresh"] }), _jsxs("button", { onClick: handle_save, className: "px-3 py-1 bg-primary text-primary-foreground rounded hover:bg-primary/90 flex items-center gap-2", "aria-label": "Save", children: [_jsx(Save, { size: 16 }), "Save"] })] })] }), _jsxs("div", { className: "cls_config_editor_content grid grid-cols-1 md:grid-cols-3 gap-4", children: [_jsxs("div", { className: "cls_config_sections_list border rounded p-4", children: [_jsx("h3", { className: "font-semibold mb-2", children: "Sections" }), _jsx("div", { className: "space-y-1", children: Object.keys(sections).map((section_name) => (_jsx("button", { onClick: () => set_selected_section(section_name), className: cn('w-full text-left px-2 py-1 rounded text-sm', selected_section === section_name
81
78
  ? 'bg-primary text-primary-foreground'
82
- : 'hover:bg-muted'), children: section_name }, section_name))) })] }), (0, jsx_runtime_1.jsx)("div", { className: "cls_config_section_content md:col-span-2 border rounded p-4", children: selected_section ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-semibold mb-4", children: selected_section }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [current_section_data &&
83
- Object.entries(current_section_data).map(([key, value]) => ((0, jsx_runtime_1.jsxs)("div", { className: "cls_config_item", children: [(0, jsx_runtime_1.jsx)("label", { className: "block text-sm font-medium mb-1", children: key }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: value, onChange: (e) => handle_update_value(selected_section, key, e.target.value), className: "w-full px-2 py-1 border rounded" })] }, key))), (0, jsx_runtime_1.jsxs)("div", { className: "cls_add_new_key border-t pt-3 mt-3", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-sm font-medium mb-2", children: "Add New Key" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Key name", value: new_key, onChange: (e) => set_new_key(e.target.value), className: "w-full px-2 py-1 border rounded text-sm" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Value", value: new_value, onChange: (e) => set_new_value(e.target.value), className: "w-full px-2 py-1 border rounded text-sm" }), (0, jsx_runtime_1.jsx)("button", { onClick: handle_add_key, className: "px-3 py-1 bg-primary text-primary-foreground rounded hover:bg-primary/90 text-sm", children: "Add Key" })] })] })] })] })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-center text-muted-foreground py-8", children: "Select a section to view/edit" })) })] })] }));
79
+ : 'hover:bg-muted'), children: section_name }, section_name))) })] }), _jsx("div", { className: "cls_config_section_content md:col-span-2 border rounded p-4", children: selected_section ? (_jsxs(_Fragment, { children: [_jsx("h3", { className: "font-semibold mb-4", children: selected_section }), _jsxs("div", { className: "space-y-3", children: [current_section_data &&
80
+ Object.entries(current_section_data).map(([key, value]) => (_jsxs("div", { className: "cls_config_item", children: [_jsx("label", { className: "block text-sm font-medium mb-1", children: key }), _jsx("input", { type: "text", value: value, onChange: (e) => handle_update_value(selected_section, key, e.target.value), className: "w-full px-2 py-1 border rounded" })] }, key))), _jsxs("div", { className: "cls_add_new_key border-t pt-3 mt-3", children: [_jsx("h4", { className: "text-sm font-medium mb-2", children: "Add New Key" }), _jsxs("div", { className: "space-y-2", children: [_jsx("input", { type: "text", placeholder: "Key name", value: new_key, onChange: (e) => set_new_key(e.target.value), className: "w-full px-2 py-1 border rounded text-sm" }), _jsx("input", { type: "text", placeholder: "Value", value: new_value, onChange: (e) => set_new_value(e.target.value), className: "w-full px-2 py-1 border rounded text-sm" }), _jsx("button", { onClick: handle_add_key, className: "px-3 py-1 bg-primary text-primary-foreground rounded hover:bg-primary/90 text-sm", children: "Add Key" })] })] })] })] })) : (_jsx("div", { className: "text-center text-muted-foreground py-8", children: "Select a section to view/edit" })) })] })] }));
84
81
  };
85
- exports.ConfigEditor = ConfigEditor;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { ConfigProvider } from '../lib/types';
2
+ import type { ConfigProvider } from '../lib/types.js';
3
3
  /**
4
4
  * Config viewer component props
5
5
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config_viewer.d.ts","sourceRoot":"","sources":["../../src/components/config_viewer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,eAAe,EAAE,cAAc,CAAA;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAwIpD,CAAA"}
1
+ {"version":3,"file":"config_viewer.d.ts","sourceRoot":"","sources":["../../src/components/config_viewer.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGrD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,eAAe,EAAE,cAAc,CAAA;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAwIpD,CAAA"}
@@ -1,22 +1,19 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConfigViewer = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
2
  // Config viewer component for displaying configuration data
6
3
  // Displays configuration sections and values in a readable format
7
- const react_1 = require("react");
8
- const utils_1 = require("../lib/utils");
9
- const lucide_react_1 = require("lucide-react");
4
+ import { useState, useEffect } from 'react';
5
+ import { cn } from '../lib/utils.js';
6
+ import { Pencil, CheckCircle2, XCircle } from 'lucide-react';
10
7
  /**
11
8
  * Config viewer component
12
9
  * Displays configuration sections and allows viewing/editing values
13
10
  * @param props - Component props
14
11
  * @returns React component
15
12
  */
16
- const ConfigViewer = ({ config_provider, className, on_update, }) => {
17
- const [sections, set_sections] = (0, react_1.useState)({});
18
- const [editing, set_editing] = (0, react_1.useState)(null);
19
- const [edit_value, set_edit_value] = (0, react_1.useState)('');
13
+ export const ConfigViewer = ({ config_provider, className, on_update, }) => {
14
+ const [sections, set_sections] = useState({});
15
+ const [editing, set_editing] = useState(null);
16
+ const [edit_value, set_edit_value] = useState('');
20
17
  /**
21
18
  * Load configuration from provider
22
19
  */
@@ -39,7 +36,7 @@ const ConfigViewer = ({ config_provider, className, on_update, }) => {
39
36
  }
40
37
  set_sections(all_sections);
41
38
  };
42
- (0, react_1.useEffect)(() => {
39
+ useEffect(() => {
43
40
  load_config();
44
41
  }, [config_provider]);
45
42
  /**
@@ -72,9 +69,8 @@ const ConfigViewer = ({ config_provider, className, on_update, }) => {
72
69
  }
73
70
  }
74
71
  };
75
- return ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)('cls_config_viewer space-y-4', className), children: Object.keys(sections).length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "p-4 text-center text-muted-foreground", children: "No configuration sections found" })) : (Object.entries(sections).map(([section_name, section_data]) => ((0, jsx_runtime_1.jsxs)("div", { className: "cls_config_section border rounded-lg p-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-3", children: section_name }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: Object.entries(section_data).map(([key, value]) => {
72
+ return (_jsx("div", { className: cn('cls_config_viewer space-y-4', className), children: Object.keys(sections).length === 0 ? (_jsx("div", { className: "p-4 text-center text-muted-foreground", children: "No configuration sections found" })) : (Object.entries(sections).map(([section_name, section_data]) => (_jsxs("div", { className: "cls_config_section border rounded-lg p-4", children: [_jsx("h3", { className: "text-lg font-semibold mb-3", children: section_name }), _jsx("div", { className: "space-y-2", children: Object.entries(section_data).map(([key, value]) => {
76
73
  const is_editing = editing?.section === section_name && editing?.key === key;
77
- return ((0, jsx_runtime_1.jsx)("div", { className: "cls_config_item flex items-center gap-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex-1", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm font-medium text-muted-foreground", children: key }), is_editing ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: edit_value, onChange: (e) => set_edit_value(e.target.value), className: "flex-1 px-2 py-1 border rounded text-sm", autoFocus: true }), (0, jsx_runtime_1.jsx)("button", { onClick: save_edit, className: "text-green-600 hover:text-green-700", "aria-label": "Save", children: (0, jsx_runtime_1.jsx)(lucide_react_1.CheckCircle2, { size: 20 }) }), (0, jsx_runtime_1.jsx)("button", { onClick: cancel_edit, className: "text-red-600 hover:text-red-700", "aria-label": "Cancel", children: (0, jsx_runtime_1.jsx)(lucide_react_1.XCircle, { size: 20 }) })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mt-1", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 px-2 py-1 bg-muted rounded text-sm", children: value || '(empty)' }), (0, jsx_runtime_1.jsx)("button", { onClick: () => start_edit(section_name, key), className: "text-blue-600 hover:text-blue-700", "aria-label": "Edit", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 18 }) })] }))] }) }, key));
74
+ return (_jsx("div", { className: "cls_config_item flex items-center gap-2", children: _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-sm font-medium text-muted-foreground", children: key }), is_editing ? (_jsxs("div", { className: "flex items-center gap-2 mt-1", children: [_jsx("input", { type: "text", value: edit_value, onChange: (e) => set_edit_value(e.target.value), className: "flex-1 px-2 py-1 border rounded text-sm", autoFocus: true }), _jsx("button", { onClick: save_edit, className: "text-green-600 hover:text-green-700", "aria-label": "Save", children: _jsx(CheckCircle2, { size: 20 }) }), _jsx("button", { onClick: cancel_edit, className: "text-red-600 hover:text-red-700", "aria-label": "Cancel", children: _jsx(XCircle, { size: 20 }) })] })) : (_jsxs("div", { className: "flex items-center gap-2 mt-1", children: [_jsx("div", { className: "flex-1 px-2 py-1 bg-muted rounded text-sm", children: value || '(empty)' }), _jsx("button", { onClick: () => start_edit(section_name, key), className: "text-blue-600 hover:text-blue-700", "aria-label": "Edit", children: _jsx(Pencil, { size: 18 }) })] }))] }) }, key));
78
75
  }) })] }, section_name)))) }));
79
76
  };
80
- exports.ConfigViewer = ConfigViewer;
@@ -1,14 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExampleComponent = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const utils_1 = require("../lib/utils");
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../lib/utils.js';
6
3
  /**
7
4
  * Example component for demonstrating the component library setup
8
5
  * @param props - Component props
9
6
  * @returns React component
10
7
  */
11
- const ExampleComponent = ({ title = 'Example Component', className, }) => {
12
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)('cls_example_component p-4 border rounded-lg', className), children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-xl font-semibold", children: title }), (0, jsx_runtime_1.jsx)("p", { className: "text-muted-foreground mt-2", children: "This is an example component for the config management library." })] }));
8
+ export const ExampleComponent = ({ title = 'Example Component', className, }) => {
9
+ return (_jsxs("div", { className: cn('cls_example_component p-4 border rounded-lg', className), children: [_jsx("h2", { className: "text-xl font-semibold", children: title }), _jsx("p", { className: "text-muted-foreground mt-2", children: "This is an example component for the config management library." })] }));
13
10
  };
14
- exports.ExampleComponent = ExampleComponent;
@@ -1,11 +1,5 @@
1
- "use strict";
2
1
  // Component exports
3
2
  // Export all components from this file for easy importing
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.ConfigEditor = exports.ConfigViewer = exports.ExampleComponent = void 0;
6
- var example_component_js_1 = require("./example_component.js");
7
- Object.defineProperty(exports, "ExampleComponent", { enumerable: true, get: function () { return example_component_js_1.ExampleComponent; } });
8
- var config_viewer_js_1 = require("./config_viewer.js");
9
- Object.defineProperty(exports, "ConfigViewer", { enumerable: true, get: function () { return config_viewer_js_1.ConfigViewer; } });
10
- var config_editor_js_1 = require("./config_editor.js");
11
- Object.defineProperty(exports, "ConfigEditor", { enumerable: true, get: function () { return config_editor_js_1.ConfigEditor; } });
3
+ export { ExampleComponent } from './example_component.js';
4
+ export { ConfigViewer } from './config_viewer.js';
5
+ export { ConfigEditor } from './config_editor.js';
package/dist/index.js CHANGED
@@ -1,21 +1,5 @@
1
- "use strict";
2
1
  // Main entry point for the component library
3
2
  // Export all components and utilities from this file
4
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
- if (k2 === undefined) k2 = k;
6
- var desc = Object.getOwnPropertyDescriptor(m, k);
7
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
- desc = { enumerable: true, get: function() { return m[k]; } };
9
- }
10
- Object.defineProperty(o, k2, desc);
11
- }) : (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- o[k2] = m[k];
14
- }));
15
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
- };
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- __exportStar(require("./components/index.js"), exports);
20
- __exportStar(require("./lib/utils.js"), exports);
21
- __exportStar(require("./lib/index.js"), exports);
3
+ export * from './components/index.js';
4
+ export * from './lib/utils.js';
5
+ export * from './lib/index.js';
@@ -6,23 +6,31 @@
6
6
  * in-memory caching, sync operations, and preservation of file formatting.
7
7
  * Zero dependencies - only Node.js built-ins and the 'ini' package.
8
8
  */
9
- import type { ConfigProvider, HazoConfigOptions } from './types';
9
+ import type { ConfigProvider, HazoConfigOptions } from './types.js';
10
10
  /**
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,YAAY,CAAA;AAa3E;;;;;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"}
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Purpose: Main implementation of HazoConfig
4
3
  *
@@ -7,15 +6,10 @@
7
6
  * in-memory caching, sync operations, and preservation of file formatting.
8
7
  * Zero dependencies - only Node.js built-ins and the 'ini' package.
9
8
  */
10
- var __importDefault = (this && this.__importDefault) || function (mod) {
11
- return (mod && mod.__esModule) ? mod : { "default": mod };
12
- };
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.HazoConfig = void 0;
15
- const fs_1 = __importDefault(require("fs"));
16
- const path_1 = __importDefault(require("path"));
17
- const ini_1 = __importDefault(require("ini"));
18
- const types_1 = require("./types");
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import ini from 'ini';
12
+ import { ConfigErrorCode as EC } from './types.js';
19
13
  /**
20
14
  * No-op logger implementation (default when no logger provided)
21
15
  */
@@ -29,12 +23,12 @@ const no_op_logger = {
29
23
  * HazoConfig class
30
24
  *
31
25
  * Implements ConfigProvider interface for managing INI configuration files.
32
- * Provides sync read/write operations with in-memory caching.
26
+ * Provides sync read/write operations with in-memory caching and automatic cache refresh.
33
27
  */
34
- class HazoConfig {
28
+ export class HazoConfig {
35
29
  /**
36
30
  * Constructor
37
- * @param options - Configuration options including filePath and optional logger
31
+ * @param options - Configuration options including filePath, optional logger, cache settings
38
32
  * @throws Error if file doesn't exist
39
33
  */
40
34
  constructor(options) {
@@ -56,18 +50,60 @@ class HazoConfig {
56
50
  writable: true,
57
51
  value: {}
58
52
  });
59
- this.filePath = path_1.default.resolve(options.filePath);
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
+ });
71
+ this.filePath = path.resolve(options.filePath);
60
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
61
75
  // Validate file exists
62
- if (!fs_1.default.existsSync(this.filePath)) {
76
+ if (!fs.existsSync(this.filePath)) {
63
77
  const error = new Error(`Configuration file not found: ${this.filePath}`);
64
- error.code = types_1.ConfigErrorCode.FILE_NOT_FOUND;
78
+ error.code = EC.FILE_NOT_FOUND;
65
79
  this.logger.error(`[HazoConfig] Configuration file not found: ${this.filePath}`);
66
80
  throw error;
67
81
  }
68
82
  // Load initial configuration
69
83
  this.refresh();
70
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
+ }
71
107
  /**
72
108
  * Get a configuration value by section and key
73
109
  * @param section - The configuration section name
@@ -75,6 +111,7 @@ class HazoConfig {
75
111
  * @returns The configuration value, or undefined if not found
76
112
  */
77
113
  get(section, key) {
114
+ this.ensure_cache_fresh();
78
115
  return this.config[section]?.[key];
79
116
  }
80
117
  /**
@@ -83,6 +120,7 @@ class HazoConfig {
83
120
  * @returns A record of key-value pairs for the section, or undefined if section doesn't exist
84
121
  */
85
122
  getSection(section) {
123
+ this.ensure_cache_fresh();
86
124
  return this.config[section] ? { ...this.config[section] } : undefined;
87
125
  }
88
126
  /**
@@ -105,17 +143,17 @@ class HazoConfig {
105
143
  save() {
106
144
  try {
107
145
  // Convert config object back to INI format
108
- const iniContent = ini_1.default.stringify(this.config, {
146
+ const iniContent = ini.stringify(this.config, {
109
147
  section: '[',
110
148
  whitespace: true
111
149
  });
112
150
  // Write to file
113
- fs_1.default.writeFileSync(this.filePath, iniContent, 'utf-8');
151
+ fs.writeFileSync(this.filePath, iniContent, 'utf-8');
114
152
  this.logger.info(`[HazoConfig] Configuration saved to: ${this.filePath}`);
115
153
  }
116
154
  catch (error) {
117
155
  const configError = new Error(`Failed to save configuration: ${error.message || String(error)}`);
118
- configError.code = types_1.ConfigErrorCode.WRITE_ERROR;
156
+ configError.code = EC.WRITE_ERROR;
119
157
  configError.originalError = error;
120
158
  this.logger.error(`[HazoConfig] Failed to save configuration: ${this.filePath}`, { error: String(error) });
121
159
  throw configError;
@@ -128,9 +166,9 @@ class HazoConfig {
128
166
  refresh() {
129
167
  try {
130
168
  // Read file content
131
- const content = fs_1.default.readFileSync(this.filePath, 'utf-8');
169
+ const content = fs.readFileSync(this.filePath, 'utf-8');
132
170
  // Parse INI content
133
- const parsed = ini_1.default.parse(content);
171
+ const parsed = ini.parse(content);
134
172
  // Convert to our internal format (ensure all values are strings)
135
173
  this.config = {};
136
174
  for (const [section, values] of Object.entries(parsed)) {
@@ -141,6 +179,8 @@ class HazoConfig {
141
179
  }
142
180
  }
143
181
  }
182
+ // Update cache timestamp
183
+ this.last_cache_refresh = Date.now();
144
184
  this.logger.info(`[HazoConfig] Configuration refreshed from: ${this.filePath}`, {
145
185
  sections: Object.keys(this.config)
146
186
  });
@@ -149,13 +189,13 @@ class HazoConfig {
149
189
  // Handle file read errors
150
190
  if (error.code === 'ENOENT') {
151
191
  const configError = new Error(`Configuration file not found: ${this.filePath}`);
152
- configError.code = types_1.ConfigErrorCode.FILE_NOT_FOUND;
192
+ configError.code = EC.FILE_NOT_FOUND;
153
193
  this.logger.error(`[HazoConfig] Configuration file not found: ${this.filePath}`);
154
194
  throw configError;
155
195
  }
156
196
  // Handle parse errors
157
197
  const configError = new Error(`Failed to parse configuration: ${error.message || String(error)}`);
158
- configError.code = types_1.ConfigErrorCode.PARSE_ERROR;
198
+ configError.code = EC.PARSE_ERROR;
159
199
  configError.originalError = error;
160
200
  this.logger.error(`[HazoConfig] Failed to parse configuration: ${this.filePath}`, { error: String(error) });
161
201
  throw configError;
@@ -173,6 +213,7 @@ class HazoConfig {
173
213
  * @returns A record of all sections and their key-value pairs
174
214
  */
175
215
  getAllSections() {
216
+ this.ensure_cache_fresh();
176
217
  // Return a deep copy to prevent external modification
177
218
  const result = {};
178
219
  for (const [section, values] of Object.entries(this.config)) {
@@ -181,4 +222,3 @@ class HazoConfig {
181
222
  return result;
182
223
  }
183
224
  }
184
- exports.HazoConfig = HazoConfig;
package/dist/lib/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Purpose: Main export for the HazoConfig library.
4
3
  *
@@ -6,11 +5,6 @@
6
5
  * configuration management utility. It serves as the primary entry point
7
6
  * for consumers of the library.
8
7
  */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.ConfigErrorCode = exports.MockConfigProvider = exports.HazoConfig = void 0;
11
- var config_loader_js_1 = require("./config-loader.js");
12
- Object.defineProperty(exports, "HazoConfig", { enumerable: true, get: function () { return config_loader_js_1.HazoConfig; } });
13
- var mock_config_provider_js_1 = require("./mock_config_provider.js");
14
- Object.defineProperty(exports, "MockConfigProvider", { enumerable: true, get: function () { return mock_config_provider_js_1.MockConfigProvider; } });
15
- var types_js_1 = require("./types.js");
16
- Object.defineProperty(exports, "ConfigErrorCode", { enumerable: true, get: function () { return types_js_1.ConfigErrorCode; } });
8
+ export { HazoConfig } from './config-loader.js';
9
+ export { MockConfigProvider } from './mock_config_provider.js';
10
+ export { ConfigErrorCode } from './types.js';
@@ -1,4 +1,4 @@
1
- import type { ConfigProvider } from './types';
1
+ import type { ConfigProvider } from './types.js';
2
2
  /**
3
3
  * Mock config provider that stores configuration in memory
4
4
  * Useful for testing and Storybook demonstrations where file system is not available
@@ -1 +1 @@
1
- {"version":3,"file":"mock_config_provider.d.ts","sourceRoot":"","sources":["../../src/lib/mock_config_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,cAAc;IACvD,OAAO,CAAC,MAAM,CAA6C;IAE3D;;;OAGG;gBACS,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAMnE;;;;;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;IAOtD;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;;OAGG;IACH,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAQxD;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI;CAOjE"}
1
+ {"version":3,"file":"mock_config_provider.d.ts","sourceRoot":"","sources":["../../src/lib/mock_config_provider.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,cAAc;IACvD,OAAO,CAAC,MAAM,CAA6C;IAE3D;;;OAGG;gBACS,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAMnE;;;;;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;IAOtD;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;;OAGG;IACH,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAQxD;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI;CAOjE"}
@@ -1,13 +1,10 @@
1
- "use strict";
2
1
  // Mock config provider for browser/Storybook testing
3
2
  // Implements ConfigProvider interface using in-memory storage instead of file system
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.MockConfigProvider = void 0;
6
3
  /**
7
4
  * Mock config provider that stores configuration in memory
8
5
  * Useful for testing and Storybook demonstrations where file system is not available
9
6
  */
10
- class MockConfigProvider {
7
+ export class MockConfigProvider {
11
8
  /**
12
9
  * Constructor
13
10
  * @param initial_config - Optional initial configuration data
@@ -88,4 +85,3 @@ class MockConfigProvider {
88
85
  }
89
86
  }
90
87
  }
91
- exports.MockConfigProvider = MockConfigProvider;
@@ -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/dist/lib/types.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Purpose: Core interfaces and types for the HazoConfig component.
4
3
  *
@@ -7,16 +6,14 @@
7
6
  * ConfigProvider pattern, configuration options, and error types, ensuring
8
7
  * loose coupling and reusability across different projects.
9
8
  */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.ConfigErrorCode = void 0;
12
9
  /**
13
10
  * Error codes for configuration operations
14
11
  */
15
- var ConfigErrorCode;
12
+ export var ConfigErrorCode;
16
13
  (function (ConfigErrorCode) {
17
14
  ConfigErrorCode["FILE_NOT_FOUND"] = "HAZO_CONFIG_FILE_NOT_FOUND";
18
15
  ConfigErrorCode["READ_ERROR"] = "HAZO_CONFIG_READ_ERROR";
19
16
  ConfigErrorCode["WRITE_ERROR"] = "HAZO_CONFIG_WRITE_ERROR";
20
17
  ConfigErrorCode["PARSE_ERROR"] = "HAZO_CONFIG_PARSE_ERROR";
21
18
  ConfigErrorCode["VALIDATION_ERROR"] = "HAZO_CONFIG_VALIDATION_ERROR";
22
- })(ConfigErrorCode || (exports.ConfigErrorCode = ConfigErrorCode = {}));
19
+ })(ConfigErrorCode || (ConfigErrorCode = {}));
package/dist/lib/utils.js CHANGED
@@ -1,15 +1,12 @@
1
- "use strict";
2
1
  // Utility functions for the component library
3
2
  // Provides class name merging functionality using clsx and tailwind-merge
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.cn = cn;
6
- const clsx_1 = require("clsx");
7
- const tailwind_merge_1 = require("tailwind-merge");
3
+ import { clsx } from "clsx";
4
+ import { twMerge } from "tailwind-merge";
8
5
  /**
9
6
  * Merges class names using clsx and tailwind-merge
10
7
  * @param inputs - Class values to merge
11
8
  * @returns Merged class string
12
9
  */
13
- function cn(...inputs) {
14
- return (0, tailwind_merge_1.twMerge)((0, clsx_1.clsx)(inputs));
10
+ export function cn(...inputs) {
11
+ return twMerge(clsx(inputs));
15
12
  }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "hazo_config",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
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": {
@@ -2,8 +2,8 @@
2
2
  // Demonstrates the config editor component with mock config provider
3
3
 
4
4
  import type { Meta, StoryObj } from '@storybook/react'
5
- import { ConfigEditor } from './config_editor'
6
- import { MockConfigProvider } from '../lib/mock_config_provider'
5
+ import { ConfigEditor } from './config_editor.js'
6
+ import { MockConfigProvider } from '../lib/mock_config_provider.js'
7
7
 
8
8
  /**
9
9
  * Sample configuration data for testing
@@ -2,8 +2,8 @@
2
2
  // Provides a more advanced interface for editing configuration values
3
3
 
4
4
  import React, { useState, useEffect } from 'react'
5
- import { cn } from '../lib/utils'
6
- import type { ConfigProvider } from '../lib/types'
5
+ import { cn } from '../lib/utils.js'
6
+ import type { ConfigProvider } from '../lib/types.js'
7
7
  import { RefreshCw, Save } from 'lucide-react'
8
8
 
9
9
  /**
@@ -2,8 +2,8 @@
2
2
  // Demonstrates the config viewer component with mock config provider
3
3
 
4
4
  import type { Meta, StoryObj } from '@storybook/react'
5
- import { ConfigViewer } from './config_viewer'
6
- import { MockConfigProvider } from '../lib/mock_config_provider'
5
+ import { ConfigViewer } from './config_viewer.js'
6
+ import { MockConfigProvider } from '../lib/mock_config_provider.js'
7
7
 
8
8
  /**
9
9
  * Sample configuration data for testing
@@ -2,8 +2,8 @@
2
2
  // Displays configuration sections and values in a readable format
3
3
 
4
4
  import React, { useState, useEffect } from 'react'
5
- import { cn } from '../lib/utils'
6
- import type { ConfigProvider } from '../lib/types'
5
+ import { cn } from '../lib/utils.js'
6
+ import type { ConfigProvider } from '../lib/types.js'
7
7
  import { Pencil, CheckCircle2, XCircle } from 'lucide-react'
8
8
 
9
9
  /**
@@ -2,7 +2,7 @@
2
2
  // Demonstrates how to create stories for components
3
3
 
4
4
  import type { Meta, StoryObj } from '@storybook/react'
5
- import { ExampleComponent } from './example_component'
5
+ import { ExampleComponent } from './example_component.js'
6
6
 
7
7
  /**
8
8
  * Meta configuration for ExampleComponent stories
@@ -2,7 +2,7 @@
2
2
  // This is a placeholder component to demonstrate the setup
3
3
 
4
4
  import React from 'react'
5
- import { cn } from '../lib/utils'
5
+ import { cn } from '../lib/utils.js'
6
6
 
7
7
  /**
8
8
  * Example component props interface
@@ -10,8 +10,8 @@
10
10
  import fs from 'fs'
11
11
  import path from 'path'
12
12
  import ini from 'ini'
13
- import type { ConfigProvider, HazoConfigOptions, Logger } from './types'
14
- import { ConfigErrorCode as EC } from './types'
13
+ import type { ConfigProvider, HazoConfigOptions, Logger } from './types.js'
14
+ import { ConfigErrorCode as EC } from './types.js'
15
15
 
16
16
  /**
17
17
  * No-op logger implementation (default when no logger provided)
@@ -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)) {
@@ -1,7 +1,7 @@
1
1
  // Mock config provider for browser/Storybook testing
2
2
  // Implements ConfigProvider interface using in-memory storage instead of file system
3
3
 
4
- import type { ConfigProvider } from './types'
4
+ import type { ConfigProvider } from './types.js'
5
5
 
6
6
  /**
7
7
  * Mock config provider that stores configuration in memory
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,13 +2,15 @@
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "noEmit": false,
5
- "module": "Node16",
5
+ "module": "ESNext",
6
6
  "declaration": true,
7
7
  "declarationMap": true,
8
8
  "outDir": "./dist",
9
9
  "rootDir": "./src",
10
10
  "allowImportingTsExtensions": false,
11
- "moduleResolution": "Node16"
11
+ "moduleResolution": "node",
12
+ "allowSyntheticDefaultImports": true,
13
+ "esModuleInterop": true
12
14
  },
13
15
  "include": ["src"],
14
16
  "exclude": ["**/*.stories.tsx", "**/*.test.tsx", "**/*.test.ts"]