Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
b0df896a14 | |||
ed969cee47 | |||
61fafd2c8f | |||
33a5b6b11c |
48
changelog.md
48
changelog.md
@@ -1,5 +1,53 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-08-15 - 5.3.0 - feat(AppData)
|
||||||
|
Refactor AppData class for declarative env mapping and enhanced static helpers
|
||||||
|
|
||||||
|
- Introduced a singleton Qenv provider to optimize environment variable resolution.
|
||||||
|
- Centralized type conversion logic with utility functions for boolean, JSON, base64, number, and string conversions.
|
||||||
|
- Replaced complex switch statements with a composable, declarative mapping pipeline for processing envMapping.
|
||||||
|
- Enhanced logging during AppData initialization to clearly report key processing and overwrite operations.
|
||||||
|
- Added new static helper methods for environment variable access (valueAsBoolean, valueAsJson, valueAsBase64, valueAsString, valueAsNumber).
|
||||||
|
- Fixed boolean conversion issues and ensured backward compatibility with the deprecated 'ephermal' option.
|
||||||
|
|
||||||
|
## 2025-08-15 - 5.2.0 - feat(AppData)
|
||||||
|
Major refactoring of AppData class for improved elegance and maintainability
|
||||||
|
|
||||||
|
- **New Features:**
|
||||||
|
- Added static helper methods for direct environment variable access:
|
||||||
|
- `AppData.valueAsBoolean()` - Convert env vars to boolean
|
||||||
|
- `AppData.valueAsJson()` - Parse env vars as JSON
|
||||||
|
- `AppData.valueAsBase64()` - Decode base64 env vars
|
||||||
|
- `AppData.valueAsString()` - Get env vars as string
|
||||||
|
- `AppData.valueAsNumber()` - Parse env vars as number
|
||||||
|
- Enhanced logging for AppData initialization and key processing:
|
||||||
|
- Shows which storage type is being used (custom, ephemeral, auto-selected)
|
||||||
|
- Logs each key being processed with its spec type
|
||||||
|
- Reports success/failure for each key with type information
|
||||||
|
- Provides summary statistics of processed keys
|
||||||
|
|
||||||
|
- **Architecture Improvements:**
|
||||||
|
- Replaced 100+ line switch statement with declarative pipeline architecture
|
||||||
|
- Introduced centralized type converters and transform registry
|
||||||
|
- Implemented composable transform pipeline: `parseMappingSpec()` → `resolveSource()` → `applyTransforms()`
|
||||||
|
- Added singleton Qenv provider to reduce allocations
|
||||||
|
- Reduced code complexity by ~70% while maintaining 100% backward compatibility
|
||||||
|
|
||||||
|
- **Bug Fixes:**
|
||||||
|
- Fixed boolean conversion to properly handle both string and boolean inputs
|
||||||
|
- Added `ephemeral` option (correctly spelled) while maintaining backward compatibility with deprecated `ephermal`
|
||||||
|
|
||||||
|
- **Performance:**
|
||||||
|
- Optimized environment variable resolution with shared Qenv instance
|
||||||
|
- Reduced object allocations in static helpers
|
||||||
|
|
||||||
|
## 2025-08-15 - 5.1.4 - fix(AppData, dev dependencies, settings)
|
||||||
|
Improve boolean conversion in AppData, update @types/node dependency, and add local settings file.
|
||||||
|
|
||||||
|
- Fixed env var boolean conversion to properly handle non-string values in AppData.
|
||||||
|
- Updated @types/node from ^20.14.5 to ^22 in package.json.
|
||||||
|
- Added .claude/settings.local.json to configure project permissions locally.
|
||||||
|
|
||||||
## 2025-08-15 - 5.1.3 - fix(appdata)
|
## 2025-08-15 - 5.1.3 - fix(appdata)
|
||||||
Fix iteration over overwriteObject in AppData and update configuration for dependency and path handling
|
Fix iteration over overwriteObject in AppData and update configuration for dependency and path handling
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/npmextra",
|
"name": "@push.rocks/npmextra",
|
||||||
"version": "5.1.3",
|
"version": "5.3.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A utility to enhance npm with additional configuration, tool management capabilities, and a key-value store for project setups.",
|
"description": "A utility to enhance npm with additional configuration, tool management capabilities, and a key-value store for project setups.",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"@git.zone/tsbuild": "^2.6.4",
|
"@git.zone/tsbuild": "^2.6.4",
|
||||||
"@git.zone/tsrun": "^1.3.3",
|
"@git.zone/tsrun": "^1.3.3",
|
||||||
"@git.zone/tstest": "^2.3.2",
|
"@git.zone/tstest": "^2.3.2",
|
||||||
"@types/node": "^20.14.5"
|
"@types/node": "^22"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts/**/*",
|
"ts/**/*",
|
||||||
|
220
pnpm-lock.yaml
generated
220
pnpm-lock.yaml
generated
@@ -46,8 +46,8 @@ importers:
|
|||||||
specifier: ^2.3.2
|
specifier: ^2.3.2
|
||||||
version: 2.3.2(@aws-sdk/credential-providers@3.864.0)(socks@2.8.7)(typescript@5.8.3)
|
version: 2.3.2(@aws-sdk/credential-providers@3.864.0)(socks@2.8.7)(typescript@5.8.3)
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.14.5
|
specifier: ^22
|
||||||
version: 20.14.5
|
version: 22.17.2
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -572,9 +572,6 @@ packages:
|
|||||||
'@push.rocks/levelcache@3.1.1':
|
'@push.rocks/levelcache@3.1.1':
|
||||||
resolution: {integrity: sha512-+JpDNEt+EuvmbtADGH9SkODxBy+slHDDzs43mAbuMbwpVvi6uNuMK0Mkhrfz9UFpxUSp+cJE/jl/OxdpD0xL1A==}
|
resolution: {integrity: sha512-+JpDNEt+EuvmbtADGH9SkODxBy+slHDDzs43mAbuMbwpVvi6uNuMK0Mkhrfz9UFpxUSp+cJE/jl/OxdpD0xL1A==}
|
||||||
|
|
||||||
'@push.rocks/lik@6.0.15':
|
|
||||||
resolution: {integrity: sha512-rZxln6l4NAU931MTxnsjy1pue+S3AXtDCidHH/tbkqBtrWIzWuXduo6Nz3zYkndbD64Knyta7F60JRvcOe4XqA==}
|
|
||||||
|
|
||||||
'@push.rocks/lik@6.2.2':
|
'@push.rocks/lik@6.2.2':
|
||||||
resolution: {integrity: sha512-j64FFPPyMXeeUorjKJVF6PWaJUfiIrF3pc41iJH4lOh0UUpBAHpcNzHVxTR58orwbVA/h3Hz+DQd4b1Rq0dFDQ==}
|
resolution: {integrity: sha512-j64FFPPyMXeeUorjKJVF6PWaJUfiIrF3pc41iJH4lOh0UUpBAHpcNzHVxTR58orwbVA/h3Hz+DQd4b1Rq0dFDQ==}
|
||||||
|
|
||||||
@@ -617,9 +614,6 @@ packages:
|
|||||||
'@push.rocks/smartdelay@3.0.5':
|
'@push.rocks/smartdelay@3.0.5':
|
||||||
resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==}
|
resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==}
|
||||||
|
|
||||||
'@push.rocks/smartenv@5.0.12':
|
|
||||||
resolution: {integrity: sha512-tDEFwywzq0FNzRYc9qY2dRl2pgQuZG0G2/yml2RLWZWSW+Fn1EHshnKOGHz8o77W7zvu4hTgQQX42r/JY5XHTg==}
|
|
||||||
|
|
||||||
'@push.rocks/smartenv@5.0.13':
|
'@push.rocks/smartenv@5.0.13':
|
||||||
resolution: {integrity: sha512-ACXmUcHZHl2CF2jnVuRw9saRRrZvJblCRs2d+K5aLR1DfkYFX3eA21kcMlKeLisI3aGNbIj9vz/rowN5qkRkfA==}
|
resolution: {integrity: sha512-ACXmUcHZHl2CF2jnVuRw9saRRrZvJblCRs2d+K5aLR1DfkYFX3eA21kcMlKeLisI3aGNbIj9vz/rowN5qkRkfA==}
|
||||||
|
|
||||||
@@ -752,9 +746,6 @@ packages:
|
|||||||
'@push.rocks/smartstring@4.0.15':
|
'@push.rocks/smartstring@4.0.15':
|
||||||
resolution: {integrity: sha512-NTNeOjWyg+aHtBTiQEyXamr7oTvYZ3wS1fudHo9ua7CLrykpK+i+RxFyJaLg1zB5x9xQF3NLEQecB14HPFX8Cg==}
|
resolution: {integrity: sha512-NTNeOjWyg+aHtBTiQEyXamr7oTvYZ3wS1fudHo9ua7CLrykpK+i+RxFyJaLg1zB5x9xQF3NLEQecB14HPFX8Cg==}
|
||||||
|
|
||||||
'@push.rocks/smarttime@4.0.6':
|
|
||||||
resolution: {integrity: sha512-1whOow0YJw/TbN758TedRRxApoZbsvyxCVpoGjXh7DE/fEEgs7RCr4vVF5jYpyXNQuNMLpKJcTsSfyQ6RvH4Aw==}
|
|
||||||
|
|
||||||
'@push.rocks/smarttime@4.1.1':
|
'@push.rocks/smarttime@4.1.1':
|
||||||
resolution: {integrity: sha512-Ha/3J/G+zfTl4ahpZgF6oUOZnUjpLhrBja0OQ2cloFxF9sKT8I1COaSqIfBGDtoK2Nly4UD4aTJ3JcJNOg/kgA==}
|
resolution: {integrity: sha512-Ha/3J/G+zfTl4ahpZgF6oUOZnUjpLhrBja0OQ2cloFxF9sKT8I1COaSqIfBGDtoK2Nly4UD4aTJ3JcJNOg/kgA==}
|
||||||
|
|
||||||
@@ -1379,8 +1370,8 @@ packages:
|
|||||||
'@types/node-forge@1.3.13':
|
'@types/node-forge@1.3.13':
|
||||||
resolution: {integrity: sha512-zePQJSW5QkwSHKRApqWCVKeKoSOt4xvEnLENZPjyvm9Ezdf/EyDeJM7jqLzOwjVICQQzvLZ63T55MKdJB5H6ww==}
|
resolution: {integrity: sha512-zePQJSW5QkwSHKRApqWCVKeKoSOt4xvEnLENZPjyvm9Ezdf/EyDeJM7jqLzOwjVICQQzvLZ63T55MKdJB5H6ww==}
|
||||||
|
|
||||||
'@types/node@20.14.5':
|
'@types/node@22.17.2':
|
||||||
resolution: {integrity: sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==}
|
resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==}
|
||||||
|
|
||||||
'@types/ping@0.4.4':
|
'@types/ping@0.4.4':
|
||||||
resolution: {integrity: sha512-ifvo6w2f5eJYlXm+HiVx67iJe8WZp87sfa683nlqED5Vnt9Z93onkokNoWqOG21EaE8fMxyKPobE+mkPEyxsdw==}
|
resolution: {integrity: sha512-ifvo6w2f5eJYlXm+HiVx67iJe8WZp87sfa683nlqED5Vnt9Z93onkokNoWqOG21EaE8fMxyKPobE+mkPEyxsdw==}
|
||||||
@@ -1643,8 +1634,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
call-bind@1.0.7:
|
call-bind@1.0.8:
|
||||||
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
|
resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
call-bound@1.0.4:
|
call-bound@1.0.4:
|
||||||
@@ -1814,10 +1805,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-9pSLe+tDJnmNak2JeMkz6ZmTCXP5p6vCxSd4kvDqrTJkqAP62j2uAEIZjf8cPDZIakStujqVzh5Y5MIWH3yYAw==}
|
resolution: {integrity: sha512-9pSLe+tDJnmNak2JeMkz6ZmTCXP5p6vCxSd4kvDqrTJkqAP62j2uAEIZjf8cPDZIakStujqVzh5Y5MIWH3yYAw==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
|
|
||||||
croner@7.0.7:
|
|
||||||
resolution: {integrity: sha512-05wALDHKjt9zG1JbpziNnWPCwwv9fUKbNf6q0dWaDMJ/eDxW0394Q2R1VAzKvDgoEZBT9FhWSHHFIcgwLgXjcQ==}
|
|
||||||
engines: {node: '>=6.0'}
|
|
||||||
|
|
||||||
croner@9.1.0:
|
croner@9.1.0:
|
||||||
resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==}
|
resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==}
|
||||||
engines: {node: '>=18.0'}
|
engines: {node: '>=18.0'}
|
||||||
@@ -1837,9 +1824,6 @@ packages:
|
|||||||
date-fns@4.1.0:
|
date-fns@4.1.0:
|
||||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||||
|
|
||||||
dayjs@1.11.11:
|
|
||||||
resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
|
|
||||||
|
|
||||||
dayjs@1.11.13:
|
dayjs@1.11.13:
|
||||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||||
|
|
||||||
@@ -2002,10 +1986,6 @@ packages:
|
|||||||
error-ex@1.3.2:
|
error-ex@1.3.2:
|
||||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||||
|
|
||||||
es-define-property@1.0.0:
|
|
||||||
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
es-define-property@1.0.1:
|
es-define-property@1.0.1:
|
||||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2243,10 +2223,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||||
engines: {node: 6.* || 8.* || >= 10.*}
|
engines: {node: 6.* || 8.* || >= 10.*}
|
||||||
|
|
||||||
get-intrinsic@1.2.4:
|
|
||||||
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2286,9 +2262,6 @@ packages:
|
|||||||
glob@7.2.3:
|
glob@7.2.3:
|
||||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||||
|
|
||||||
gopd@1.0.1:
|
|
||||||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
|
||||||
|
|
||||||
gopd@1.2.0:
|
gopd@1.2.0:
|
||||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2322,14 +2295,6 @@ packages:
|
|||||||
has-property-descriptors@1.0.2:
|
has-property-descriptors@1.0.2:
|
||||||
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
|
||||||
|
|
||||||
has-proto@1.0.3:
|
|
||||||
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
has-symbols@1.0.3:
|
|
||||||
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
has-symbols@1.1.0:
|
has-symbols@1.1.0:
|
||||||
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2529,9 +2494,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
|
resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
js-base64@3.7.7:
|
|
||||||
resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
|
|
||||||
|
|
||||||
js-base64@3.7.8:
|
js-base64@3.7.8:
|
||||||
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
|
resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
|
||||||
|
|
||||||
@@ -3024,9 +2986,6 @@ packages:
|
|||||||
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
|
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
object-inspect@1.13.1:
|
|
||||||
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
|
|
||||||
|
|
||||||
object-inspect@1.13.4:
|
object-inspect@1.13.4:
|
||||||
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -3267,10 +3226,6 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
qs@6.12.1:
|
|
||||||
resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==}
|
|
||||||
engines: {node: '>=0.6'}
|
|
||||||
|
|
||||||
qs@6.13.0:
|
qs@6.13.0:
|
||||||
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
@@ -3461,10 +3416,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
|
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
side-channel@1.0.6:
|
|
||||||
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
|
|
||||||
engines: {node: '>= 0.4'}
|
|
||||||
|
|
||||||
side-channel@1.1.0:
|
side-channel@1.1.0:
|
||||||
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -3727,8 +3678,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-+NWHrac9dvilNgme+gP4YrBSumsaMZP0fNBtXXFIf33RLLKEcBUKaQZ7ULUbS0sBfcjxIZ4V96OTRkCbM7hxpw==}
|
resolution: {integrity: sha512-+NWHrac9dvilNgme+gP4YrBSumsaMZP0fNBtXXFIf33RLLKEcBUKaQZ7ULUbS0sBfcjxIZ4V96OTRkCbM7hxpw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
undici-types@5.26.5:
|
undici-types@6.21.0:
|
||||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
unified@11.0.5:
|
unified@11.0.5:
|
||||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||||
@@ -3766,9 +3717,6 @@ packages:
|
|||||||
upper-case@1.1.3:
|
upper-case@1.1.3:
|
||||||
resolution: {integrity: sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=}
|
resolution: {integrity: sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=}
|
||||||
|
|
||||||
url@0.11.3:
|
|
||||||
resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==}
|
|
||||||
|
|
||||||
url@0.11.4:
|
url@0.11.4:
|
||||||
resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==}
|
resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -4982,17 +4930,6 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- aws-crt
|
- aws-crt
|
||||||
|
|
||||||
'@push.rocks/lik@6.0.15':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
|
||||||
'@push.rocks/smartmatch': 2.0.0
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
'@push.rocks/smartrx': 3.0.10
|
|
||||||
'@push.rocks/smarttime': 4.0.6
|
|
||||||
'@types/minimatch': 5.1.2
|
|
||||||
'@types/symbol-tree': 3.2.5
|
|
||||||
symbol-tree: 3.2.4
|
|
||||||
|
|
||||||
'@push.rocks/lik@6.2.2':
|
'@push.rocks/lik@6.2.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
@@ -5139,10 +5076,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
|
|
||||||
'@push.rocks/smartenv@5.0.12':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
|
|
||||||
'@push.rocks/smartenv@5.0.13':
|
'@push.rocks/smartenv@5.0.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
@@ -5221,7 +5154,7 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/smartjson@5.0.20':
|
'@push.rocks/smartjson@5.0.20':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartenv': 5.0.12
|
'@push.rocks/smartenv': 5.0.13
|
||||||
'@push.rocks/smartstring': 4.0.15
|
'@push.rocks/smartstring': 4.0.15
|
||||||
fast-json-stable-stringify: 2.1.0
|
fast-json-stable-stringify: 2.1.0
|
||||||
lodash.clonedeep: 4.5.0
|
lodash.clonedeep: 4.5.0
|
||||||
@@ -5515,23 +5448,13 @@ snapshots:
|
|||||||
'@push.rocks/smartstring@4.0.15':
|
'@push.rocks/smartstring@4.0.15':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/isounique': 1.0.5
|
'@push.rocks/isounique': 1.0.5
|
||||||
'@push.rocks/smartenv': 5.0.12
|
'@push.rocks/smartenv': 5.0.13
|
||||||
'@types/randomatic': 3.1.5
|
'@types/randomatic': 3.1.5
|
||||||
crypto-random-string: 5.0.0
|
crypto-random-string: 5.0.0
|
||||||
js-base64: 3.7.7
|
js-base64: 3.7.8
|
||||||
randomatic: 3.1.1
|
randomatic: 3.1.1
|
||||||
strip-indent: 4.0.0
|
strip-indent: 4.0.0
|
||||||
url: 0.11.3
|
url: 0.11.4
|
||||||
|
|
||||||
'@push.rocks/smarttime@4.0.6':
|
|
||||||
dependencies:
|
|
||||||
'@push.rocks/lik': 6.0.15
|
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
|
||||||
croner: 7.0.7
|
|
||||||
dayjs: 1.11.11
|
|
||||||
is-nan: 1.3.2
|
|
||||||
pretty-ms: 8.0.0
|
|
||||||
|
|
||||||
'@push.rocks/smarttime@4.1.1':
|
'@push.rocks/smarttime@4.1.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5569,12 +5492,12 @@ snapshots:
|
|||||||
|
|
||||||
'@push.rocks/taskbuffer@3.1.7':
|
'@push.rocks/taskbuffer@3.1.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/lik': 6.0.15
|
'@push.rocks/lik': 6.2.2
|
||||||
'@push.rocks/smartdelay': 3.0.5
|
'@push.rocks/smartdelay': 3.0.5
|
||||||
'@push.rocks/smartlog': 3.1.8
|
'@push.rocks/smartlog': 3.1.8
|
||||||
'@push.rocks/smartpromise': 4.2.3
|
'@push.rocks/smartpromise': 4.2.3
|
||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
'@push.rocks/smarttime': 4.0.6
|
'@push.rocks/smarttime': 4.1.1
|
||||||
'@push.rocks/smartunique': 3.0.9
|
'@push.rocks/smartunique': 3.0.9
|
||||||
|
|
||||||
'@push.rocks/webrequest@3.0.37':
|
'@push.rocks/webrequest@3.0.37':
|
||||||
@@ -6244,22 +6167,22 @@ snapshots:
|
|||||||
'@types/body-parser@1.19.6':
|
'@types/body-parser@1.19.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/connect': 3.4.38
|
'@types/connect': 3.4.38
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/buffer-json@2.0.3': {}
|
'@types/buffer-json@2.0.3': {}
|
||||||
|
|
||||||
'@types/clean-css@4.2.11':
|
'@types/clean-css@4.2.11':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
'@types/connect@3.4.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/cors@2.8.19':
|
'@types/cors@2.8.19':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/debug@4.1.12':
|
'@types/debug@4.1.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6269,7 +6192,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/express-serve-static-core@5.0.7':
|
'@types/express-serve-static-core@5.0.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
'@types/qs': 6.14.0
|
'@types/qs': 6.14.0
|
||||||
'@types/range-parser': 1.2.7
|
'@types/range-parser': 1.2.7
|
||||||
'@types/send': 0.17.5
|
'@types/send': 0.17.5
|
||||||
@@ -6286,30 +6209,30 @@ snapshots:
|
|||||||
|
|
||||||
'@types/from2@2.3.5':
|
'@types/from2@2.3.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/fs-extra@11.0.4':
|
'@types/fs-extra@11.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/jsonfile': 6.1.4
|
'@types/jsonfile': 6.1.4
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/fs-extra@9.0.13':
|
'@types/fs-extra@9.0.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/glob@7.2.0':
|
'@types/glob@7.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/minimatch': 6.0.0
|
'@types/minimatch': 6.0.0
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/glob@8.1.0':
|
'@types/glob@8.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/minimatch': 5.1.2
|
'@types/minimatch': 5.1.2
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/gunzip-maybe@1.4.2':
|
'@types/gunzip-maybe@1.4.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/hast@3.0.4':
|
'@types/hast@3.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6331,7 +6254,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/jsonfile@6.1.4':
|
'@types/jsonfile@6.1.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/mdast@4.0.4':
|
'@types/mdast@4.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6353,11 +6276,11 @@ snapshots:
|
|||||||
|
|
||||||
'@types/node-forge@1.3.13':
|
'@types/node-forge@1.3.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/node@20.14.5':
|
'@types/node@22.17.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 5.26.5
|
undici-types: 6.21.0
|
||||||
|
|
||||||
'@types/ping@0.4.4': {}
|
'@types/ping@0.4.4': {}
|
||||||
|
|
||||||
@@ -6371,30 +6294,30 @@ snapshots:
|
|||||||
|
|
||||||
'@types/s3rver@3.7.4':
|
'@types/s3rver@3.7.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/semver@7.7.0': {}
|
'@types/semver@7.7.0': {}
|
||||||
|
|
||||||
'@types/send@0.17.5':
|
'@types/send@0.17.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/mime': 1.3.5
|
'@types/mime': 1.3.5
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/serve-static@1.15.8':
|
'@types/serve-static@1.15.8':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/http-errors': 2.0.5
|
'@types/http-errors': 2.0.5
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
'@types/send': 0.17.5
|
'@types/send': 0.17.5
|
||||||
|
|
||||||
'@types/symbol-tree@3.2.5': {}
|
'@types/symbol-tree@3.2.5': {}
|
||||||
|
|
||||||
'@types/tar-stream@2.2.3':
|
'@types/tar-stream@2.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/through2@2.0.41':
|
'@types/through2@2.0.41':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/triple-beam@1.3.5': {}
|
'@types/triple-beam@1.3.5': {}
|
||||||
|
|
||||||
@@ -6418,18 +6341,18 @@ snapshots:
|
|||||||
|
|
||||||
'@types/whatwg-url@8.2.2':
|
'@types/whatwg-url@8.2.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
'@types/webidl-conversions': 7.0.3
|
'@types/webidl-conversions': 7.0.3
|
||||||
|
|
||||||
'@types/which@3.0.4': {}
|
'@types/which@3.0.4': {}
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
|
|
||||||
'@types/yauzl@2.10.3':
|
'@types/yauzl@2.10.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0': {}
|
'@ungap/structured-clone@1.3.0': {}
|
||||||
@@ -6628,12 +6551,11 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
call-bind@1.0.7:
|
call-bind@1.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-define-property: 1.0.0
|
call-bind-apply-helpers: 1.0.2
|
||||||
es-errors: 1.3.0
|
es-define-property: 1.0.1
|
||||||
function-bind: 1.1.2
|
get-intrinsic: 1.3.0
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
set-function-length: 1.2.2
|
set-function-length: 1.2.2
|
||||||
|
|
||||||
call-bound@1.0.4:
|
call-bound@1.0.4:
|
||||||
@@ -6785,8 +6707,6 @@ snapshots:
|
|||||||
|
|
||||||
croner@5.7.0: {}
|
croner@5.7.0: {}
|
||||||
|
|
||||||
croner@7.0.7: {}
|
|
||||||
|
|
||||||
croner@9.1.0: {}
|
croner@9.1.0: {}
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
@@ -6803,8 +6723,6 @@ snapshots:
|
|||||||
|
|
||||||
date-fns@4.1.0: {}
|
date-fns@4.1.0: {}
|
||||||
|
|
||||||
dayjs@1.11.11: {}
|
|
||||||
|
|
||||||
dayjs@1.11.13: {}
|
dayjs@1.11.13: {}
|
||||||
|
|
||||||
debug@2.6.9:
|
debug@2.6.9:
|
||||||
@@ -6835,9 +6753,9 @@ snapshots:
|
|||||||
|
|
||||||
define-data-property@1.1.4:
|
define-data-property@1.1.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-define-property: 1.0.0
|
es-define-property: 1.0.1
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
gopd: 1.0.1
|
gopd: 1.2.0
|
||||||
|
|
||||||
define-lazy-prop@2.0.0: {}
|
define-lazy-prop@2.0.0: {}
|
||||||
|
|
||||||
@@ -6931,7 +6849,7 @@ snapshots:
|
|||||||
engine.io@6.6.4:
|
engine.io@6.6.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/cors': 2.8.19
|
'@types/cors': 2.8.19
|
||||||
'@types/node': 20.14.5
|
'@types/node': 22.17.2
|
||||||
accepts: 1.3.8
|
accepts: 1.3.8
|
||||||
base64id: 2.0.0
|
base64id: 2.0.0
|
||||||
cookie: 0.7.2
|
cookie: 0.7.2
|
||||||
@@ -6954,10 +6872,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish: 0.2.1
|
is-arrayish: 0.2.1
|
||||||
|
|
||||||
es-define-property@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
|
|
||||||
es-define-property@1.0.1: {}
|
es-define-property@1.0.1: {}
|
||||||
|
|
||||||
es-errors@1.3.0: {}
|
es-errors@1.3.0: {}
|
||||||
@@ -7269,14 +7183,6 @@ snapshots:
|
|||||||
|
|
||||||
get-caller-file@2.0.5: {}
|
get-caller-file@2.0.5: {}
|
||||||
|
|
||||||
get-intrinsic@1.2.4:
|
|
||||||
dependencies:
|
|
||||||
es-errors: 1.3.0
|
|
||||||
function-bind: 1.1.2
|
|
||||||
has-proto: 1.0.3
|
|
||||||
has-symbols: 1.0.3
|
|
||||||
hasown: 2.0.2
|
|
||||||
|
|
||||||
get-intrinsic@1.3.0:
|
get-intrinsic@1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind-apply-helpers: 1.0.2
|
call-bind-apply-helpers: 1.0.2
|
||||||
@@ -7345,10 +7251,6 @@ snapshots:
|
|||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
path-is-absolute: 1.0.1
|
path-is-absolute: 1.0.1
|
||||||
|
|
||||||
gopd@1.0.1:
|
|
||||||
dependencies:
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
|
|
||||||
gopd@1.2.0: {}
|
gopd@1.2.0: {}
|
||||||
|
|
||||||
got@12.6.1:
|
got@12.6.1:
|
||||||
@@ -7402,11 +7304,7 @@ snapshots:
|
|||||||
|
|
||||||
has-property-descriptors@1.0.2:
|
has-property-descriptors@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-define-property: 1.0.0
|
es-define-property: 1.0.1
|
||||||
|
|
||||||
has-proto@1.0.3: {}
|
|
||||||
|
|
||||||
has-symbols@1.0.3: {}
|
|
||||||
|
|
||||||
has-symbols@1.1.0: {}
|
has-symbols@1.1.0: {}
|
||||||
|
|
||||||
@@ -7560,7 +7458,7 @@ snapshots:
|
|||||||
|
|
||||||
is-nan@1.3.2:
|
is-nan@1.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.7
|
call-bind: 1.0.8
|
||||||
define-properties: 1.2.1
|
define-properties: 1.2.1
|
||||||
|
|
||||||
is-number@4.0.0: {}
|
is-number@4.0.0: {}
|
||||||
@@ -7610,8 +7508,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@isaacs/cliui': 8.0.2
|
'@isaacs/cliui': 8.0.2
|
||||||
|
|
||||||
js-base64@3.7.7: {}
|
|
||||||
|
|
||||||
js-base64@3.7.8: {}
|
js-base64@3.7.8: {}
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
@@ -8291,8 +8187,6 @@ snapshots:
|
|||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
object-inspect@1.13.1: {}
|
|
||||||
|
|
||||||
object-inspect@1.13.4: {}
|
object-inspect@1.13.4: {}
|
||||||
|
|
||||||
object-keys@1.1.1: {}
|
object-keys@1.1.1: {}
|
||||||
@@ -8546,10 +8440,6 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
qs@6.12.1:
|
|
||||||
dependencies:
|
|
||||||
side-channel: 1.0.6
|
|
||||||
|
|
||||||
qs@6.13.0:
|
qs@6.13.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.1.0
|
side-channel: 1.1.0
|
||||||
@@ -8814,8 +8704,8 @@ snapshots:
|
|||||||
define-data-property: 1.1.4
|
define-data-property: 1.1.4
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
get-intrinsic: 1.2.4
|
get-intrinsic: 1.3.0
|
||||||
gopd: 1.0.1
|
gopd: 1.2.0
|
||||||
has-property-descriptors: 1.0.2
|
has-property-descriptors: 1.0.2
|
||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
@@ -8846,13 +8736,6 @@ snapshots:
|
|||||||
object-inspect: 1.13.4
|
object-inspect: 1.13.4
|
||||||
side-channel-map: 1.0.1
|
side-channel-map: 1.0.1
|
||||||
|
|
||||||
side-channel@1.0.6:
|
|
||||||
dependencies:
|
|
||||||
call-bind: 1.0.7
|
|
||||||
es-errors: 1.3.0
|
|
||||||
get-intrinsic: 1.2.4
|
|
||||||
object-inspect: 1.13.1
|
|
||||||
|
|
||||||
side-channel@1.1.0:
|
side-channel@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
@@ -9152,7 +9035,7 @@ snapshots:
|
|||||||
|
|
||||||
uint8array-extras@1.4.1: {}
|
uint8array-extras@1.4.1: {}
|
||||||
|
|
||||||
undici-types@5.26.5: {}
|
undici-types@6.21.0: {}
|
||||||
|
|
||||||
unified@11.0.5:
|
unified@11.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9197,11 +9080,6 @@ snapshots:
|
|||||||
|
|
||||||
upper-case@1.1.3: {}
|
upper-case@1.1.3: {}
|
||||||
|
|
||||||
url@0.11.3:
|
|
||||||
dependencies:
|
|
||||||
punycode: 1.4.1
|
|
||||||
qs: 6.12.1
|
|
||||||
|
|
||||||
url@0.11.4:
|
url@0.11.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode: 1.4.1
|
punycode: 1.4.1
|
||||||
|
38
readme.md
38
readme.md
@@ -259,6 +259,44 @@ AppData intelligently handles boolean conversions:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Static Helper Functions
|
||||||
|
|
||||||
|
AppData provides convenient static methods for directly accessing and converting environment variables without creating an instance:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { AppData } from '@push.rocks/npmextra';
|
||||||
|
|
||||||
|
// Get environment variable as boolean
|
||||||
|
const isEnabled = await AppData.valueAsBoolean('FEATURE_ENABLED');
|
||||||
|
// Returns: true if "true", false otherwise
|
||||||
|
|
||||||
|
// Get environment variable as parsed JSON
|
||||||
|
interface Config {
|
||||||
|
timeout: number;
|
||||||
|
retries: number;
|
||||||
|
}
|
||||||
|
const config = await AppData.valueAsJson<Config>('SERVICE_CONFIG');
|
||||||
|
// Returns: Parsed object or undefined
|
||||||
|
|
||||||
|
// Get environment variable as base64 decoded string
|
||||||
|
const secret = await AppData.valueAsBase64('ENCODED_SECRET');
|
||||||
|
// Returns: Decoded string or undefined
|
||||||
|
|
||||||
|
// Get environment variable as string
|
||||||
|
const apiUrl = await AppData.valueAsString('API_URL');
|
||||||
|
// Returns: String value or undefined
|
||||||
|
|
||||||
|
// Get environment variable as number
|
||||||
|
const port = await AppData.valueAsNumber('PORT');
|
||||||
|
// Returns: Number value or undefined
|
||||||
|
```
|
||||||
|
|
||||||
|
These static methods are perfect for:
|
||||||
|
- Quick environment variable access without setup
|
||||||
|
- Simple type conversions in utility functions
|
||||||
|
- One-off configuration checks
|
||||||
|
- Scenarios where you don't need the full AppData instance
|
||||||
|
|
||||||
## Advanced Patterns 🎨
|
## Advanced Patterns 🎨
|
||||||
|
|
||||||
### Reactive Configuration
|
### Reactive Configuration
|
||||||
|
225
readme.plan.md
Normal file
225
readme.plan.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
# AppData Refactoring Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Refactor the AppData class to improve elegance, maintainability, and extensibility while maintaining 100% backward compatibility.
|
||||||
|
|
||||||
|
## Current Issues
|
||||||
|
- 100+ lines of nested switch statements in processEnvMapping
|
||||||
|
- Static helpers recreate Qenv instances on every call
|
||||||
|
- Complex boolean conversion logic scattered across multiple places
|
||||||
|
- Typo: "ephermal" should be "ephemeral"
|
||||||
|
- Difficult to test and extend with new transformations
|
||||||
|
|
||||||
|
## Architecture Improvements
|
||||||
|
|
||||||
|
### 1. Singleton Qenv Provider
|
||||||
|
Create a shared Qenv instance to avoid repeated instantiation:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
let sharedQenv: plugins.qenv.Qenv | undefined;
|
||||||
|
|
||||||
|
function getQenv(): plugins.qenv.Qenv {
|
||||||
|
if (!sharedQenv) {
|
||||||
|
sharedQenv = new plugins.qenv.Qenv(
|
||||||
|
process.cwd(),
|
||||||
|
plugins.path.join(process.cwd(), '.nogit')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return sharedQenv;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Centralized Type Converters
|
||||||
|
Extract all conversion logic into pure utility functions:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function toBoolean(value: unknown): boolean {
|
||||||
|
if (typeof value === 'boolean') return value;
|
||||||
|
if (value == null) return false;
|
||||||
|
const s = String(value).toLowerCase();
|
||||||
|
return s === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJson<T>(value: unknown): T | undefined {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromBase64(value: unknown): string {
|
||||||
|
if (value == null) return '';
|
||||||
|
return Buffer.from(String(value), 'base64').toString('utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toNumber(value: unknown): number | undefined {
|
||||||
|
if (value == null) return undefined;
|
||||||
|
const num = Number(value);
|
||||||
|
return Number.isNaN(num) ? undefined : num;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(value: unknown): string | undefined {
|
||||||
|
if (value == null) return undefined;
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Declarative Pipeline Architecture
|
||||||
|
|
||||||
|
Replace the giant switch statement with a composable pipeline:
|
||||||
|
|
||||||
|
#### Data Structures
|
||||||
|
```typescript
|
||||||
|
type MappingSpec = {
|
||||||
|
source:
|
||||||
|
| { type: 'env', key: string }
|
||||||
|
| { type: 'hard', value: string };
|
||||||
|
transforms: Transform[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type Transform = 'boolean' | 'json' | 'base64' | 'number';
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Pipeline Functions
|
||||||
|
```typescript
|
||||||
|
// Parse mapping string into spec
|
||||||
|
function parseMappingSpec(input: string): MappingSpec
|
||||||
|
|
||||||
|
// Resolve the source value
|
||||||
|
async function resolveSource(source: MappingSpec['source']): Promise<unknown>
|
||||||
|
|
||||||
|
// Apply transformations
|
||||||
|
function applyTransforms(value: unknown, transforms: Transform[]): unknown
|
||||||
|
|
||||||
|
// Complete pipeline
|
||||||
|
async function processMappingValue(mappingString: string): Promise<unknown>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Transform Registry
|
||||||
|
Enable easy extension with new transforms:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const transformRegistry: Record<string, (v: unknown) => unknown> = {
|
||||||
|
boolean: toBoolean,
|
||||||
|
json: toJson,
|
||||||
|
base64: fromBase64,
|
||||||
|
number: toNumber,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Simplified processEnvMapping
|
||||||
|
Build pure object tree first, then write to kvStore:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async function evaluateMappingValue(mappingValue: any): Promise<any> {
|
||||||
|
if (typeof mappingValue === 'string') {
|
||||||
|
return processMappingValue(mappingValue);
|
||||||
|
}
|
||||||
|
if (mappingValue && typeof mappingValue === 'object') {
|
||||||
|
const out: any = {};
|
||||||
|
for (const [k, v] of Object.entries(mappingValue)) {
|
||||||
|
out[k] = await evaluateMappingValue(v);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main loop becomes:
|
||||||
|
for (const key in this.options.envMapping) {
|
||||||
|
const evaluated = await evaluateMappingValue(this.options.envMapping[key]);
|
||||||
|
if (evaluated !== undefined) {
|
||||||
|
await this.kvStore.writeKey(key as keyof T, evaluated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backward Compatibility
|
||||||
|
|
||||||
|
### Supported Prefixes (Maintained)
|
||||||
|
- `hard:` - Hardcoded value
|
||||||
|
- `hard_boolean:` - Hardcoded boolean
|
||||||
|
- `hard_json:` - Hardcoded JSON
|
||||||
|
- `hard_base64:` - Hardcoded base64
|
||||||
|
- `boolean:` - Environment variable as boolean
|
||||||
|
- `json:` - Environment variable as JSON
|
||||||
|
- `base64:` - Environment variable as base64
|
||||||
|
|
||||||
|
### Supported Suffixes (Maintained)
|
||||||
|
- `_JSON` - Auto-parse as JSON
|
||||||
|
- `_BASE64` - Auto-decode from base64
|
||||||
|
|
||||||
|
### Typo Fix Strategy
|
||||||
|
- Add `ephemeral` option to interface
|
||||||
|
- Keep reading `ephermal` for backward compatibility
|
||||||
|
- Log deprecation warning when old spelling is used
|
||||||
|
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
1. **Add utility functions** at the top of the file
|
||||||
|
2. **Implement pipeline functions** (parseMappingSpec, resolveSource, applyTransforms)
|
||||||
|
3. **Refactor processEnvMapping** to use the pipeline
|
||||||
|
4. **Update static helpers** to use shared utilities
|
||||||
|
5. **Fix typo** with compatibility shim
|
||||||
|
6. **Add error boundaries** for better error reporting
|
||||||
|
7. **Test** to ensure backward compatibility
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
- **70% reduction** in processEnvMapping complexity
|
||||||
|
- **Better separation** of concerns
|
||||||
|
- **Easier testing** - each function is pure and testable
|
||||||
|
- **Cleaner error handling** with boundaries
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- **Shared Qenv instance** reduces allocations
|
||||||
|
- **Optional parallelization** with Promise.all
|
||||||
|
- **Fewer repeated operations**
|
||||||
|
|
||||||
|
### Maintainability
|
||||||
|
- **Extensible** - Easy to add new transforms
|
||||||
|
- **Readable** - Clear pipeline flow
|
||||||
|
- **Debuggable** - Each step can be logged
|
||||||
|
- **Type-safe** - Better TypeScript support
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
1. **Unit tests** for each utility function
|
||||||
|
2. **Integration tests** for the full pipeline
|
||||||
|
3. **Backward compatibility tests** for all existing prefixes/suffixes
|
||||||
|
4. **Edge case tests** for error conditions
|
||||||
|
|
||||||
|
## Future Extensions
|
||||||
|
|
||||||
|
With the transform registry, adding new features becomes trivial:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Add YAML support
|
||||||
|
transformRegistry['yaml'] = (v) => YAML.parse(String(v));
|
||||||
|
|
||||||
|
// Add integer parsing
|
||||||
|
transformRegistry['int'] = (v) => parseInt(String(v), 10);
|
||||||
|
|
||||||
|
// Add custom transformers
|
||||||
|
transformRegistry['uppercase'] = (v) => String(v).toUpperCase();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Path
|
||||||
|
|
||||||
|
1. Implement new architecture alongside existing code
|
||||||
|
2. Gradually migrate internal usage
|
||||||
|
3. Mark old patterns as deprecated (with warnings)
|
||||||
|
4. Remove deprecated code in next major version
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
- All existing tests pass
|
||||||
|
- No breaking changes for users
|
||||||
|
- Reduced code complexity (measurable via cyclomatic complexity)
|
||||||
|
- Improved test coverage
|
||||||
|
- Better performance (fewer allocations, optional parallelization)
|
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/npmextra',
|
name: '@push.rocks/npmextra',
|
||||||
version: '5.1.3',
|
version: '5.3.0',
|
||||||
description: 'A utility to enhance npm with additional configuration, tool management capabilities, and a key-value store for project setups.'
|
description: 'A utility to enhance npm with additional configuration, tool management capabilities, and a key-value store for project setups.'
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,224 @@
|
|||||||
import * as plugins from './npmextra.plugins.js';
|
import * as plugins from './npmextra.plugins.js';
|
||||||
import * as paths from './npmextra.paths.js';
|
|
||||||
import { KeyValueStore } from './npmextra.classes.keyvaluestore.js';
|
import { KeyValueStore } from './npmextra.classes.keyvaluestore.js';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Singleton Qenv Provider
|
||||||
|
// ============================================================================
|
||||||
|
let sharedQenv: plugins.qenv.Qenv | undefined;
|
||||||
|
|
||||||
|
function getQenv(): plugins.qenv.Qenv {
|
||||||
|
if (!sharedQenv) {
|
||||||
|
sharedQenv = new plugins.qenv.Qenv(
|
||||||
|
process.cwd(),
|
||||||
|
plugins.path.join(process.cwd(), '.nogit')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return sharedQenv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Type Converters - Centralized conversion logic
|
||||||
|
// ============================================================================
|
||||||
|
function toBoolean(value: unknown): boolean {
|
||||||
|
if (typeof value === 'boolean') return value;
|
||||||
|
if (value == null) return false;
|
||||||
|
const s = String(value).toLowerCase();
|
||||||
|
return s === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJson<T = any>(value: unknown): T | undefined {
|
||||||
|
if (value == null) return undefined;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
try {
|
||||||
|
return JSON.parse(value);
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromBase64(value: unknown): string | undefined {
|
||||||
|
if (value == null) return undefined;
|
||||||
|
try {
|
||||||
|
return Buffer.from(String(value), 'base64').toString('utf8');
|
||||||
|
} catch {
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toNumber(value: unknown): number | undefined {
|
||||||
|
if (value == null) return undefined;
|
||||||
|
const num = Number(value);
|
||||||
|
return Number.isNaN(num) ? undefined : num;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toString(value: unknown): string | undefined {
|
||||||
|
if (value == null) return undefined;
|
||||||
|
return String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Declarative Pipeline Architecture
|
||||||
|
// ============================================================================
|
||||||
|
type Transform = 'boolean' | 'json' | 'base64' | 'number';
|
||||||
|
|
||||||
|
type MappingSpec = {
|
||||||
|
source:
|
||||||
|
| { type: 'env'; key: string }
|
||||||
|
| { type: 'hard'; value: string };
|
||||||
|
transforms: Transform[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transform registry for extensibility
|
||||||
|
const transformRegistry: Record<string, (v: unknown) => unknown> = {
|
||||||
|
boolean: toBoolean,
|
||||||
|
json: toJson,
|
||||||
|
base64: fromBase64,
|
||||||
|
number: toNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a mapping string into a declarative spec
|
||||||
|
*/
|
||||||
|
function parseMappingSpec(input: string): MappingSpec {
|
||||||
|
const transforms: Transform[] = [];
|
||||||
|
let remaining = input;
|
||||||
|
|
||||||
|
// Check for hardcoded prefixes with type conversion
|
||||||
|
if (remaining.startsWith('hard_boolean:')) {
|
||||||
|
return {
|
||||||
|
source: { type: 'hard', value: remaining.slice(13) },
|
||||||
|
transforms: ['boolean']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining.startsWith('hard_json:')) {
|
||||||
|
return {
|
||||||
|
source: { type: 'hard', value: remaining.slice(10) },
|
||||||
|
transforms: ['json']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining.startsWith('hard_base64:')) {
|
||||||
|
return {
|
||||||
|
source: { type: 'hard', value: remaining.slice(12) },
|
||||||
|
transforms: ['base64']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for generic hard: prefix
|
||||||
|
if (remaining.startsWith('hard:')) {
|
||||||
|
remaining = remaining.slice(5);
|
||||||
|
// Check for legacy suffixes on hardcoded values
|
||||||
|
if (remaining.endsWith('_JSON')) {
|
||||||
|
transforms.push('json');
|
||||||
|
remaining = remaining.slice(0, -5);
|
||||||
|
} else if (remaining.endsWith('_BASE64')) {
|
||||||
|
transforms.push('base64');
|
||||||
|
remaining = remaining.slice(0, -7);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
source: { type: 'hard', value: remaining },
|
||||||
|
transforms
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for env var prefixes
|
||||||
|
if (remaining.startsWith('boolean:')) {
|
||||||
|
transforms.push('boolean');
|
||||||
|
remaining = remaining.slice(8);
|
||||||
|
} else if (remaining.startsWith('json:')) {
|
||||||
|
transforms.push('json');
|
||||||
|
remaining = remaining.slice(5);
|
||||||
|
} else if (remaining.startsWith('base64:')) {
|
||||||
|
transforms.push('base64');
|
||||||
|
remaining = remaining.slice(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for legacy suffixes on env vars
|
||||||
|
if (remaining.endsWith('_JSON')) {
|
||||||
|
transforms.push('json');
|
||||||
|
remaining = remaining.slice(0, -5);
|
||||||
|
} else if (remaining.endsWith('_BASE64')) {
|
||||||
|
transforms.push('base64');
|
||||||
|
remaining = remaining.slice(0, -7);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
source: { type: 'env', key: remaining },
|
||||||
|
transforms
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the source value (env var or hardcoded)
|
||||||
|
*/
|
||||||
|
async function resolveSource(source: MappingSpec['source']): Promise<unknown> {
|
||||||
|
if (source.type === 'hard') {
|
||||||
|
return source.value;
|
||||||
|
}
|
||||||
|
// source.type === 'env'
|
||||||
|
return await getQenv().getEnvVarOnDemand(source.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply transformations in sequence
|
||||||
|
*/
|
||||||
|
function applyTransforms(value: unknown, transforms: Transform[]): unknown {
|
||||||
|
return transforms.reduce((acc, transform) => {
|
||||||
|
const fn = transformRegistry[transform];
|
||||||
|
return fn ? fn(acc) : acc;
|
||||||
|
}, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a mapping value through the complete pipeline
|
||||||
|
*/
|
||||||
|
async function processMappingValue(mappingString: string): Promise<unknown> {
|
||||||
|
const spec = parseMappingSpec(mappingString);
|
||||||
|
const rawValue = await resolveSource(spec.source);
|
||||||
|
|
||||||
|
if (rawValue === undefined || rawValue === null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyTransforms(rawValue, spec.transforms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively evaluate mapping values (strings or nested objects)
|
||||||
|
*/
|
||||||
|
async function evaluateMappingValue(mappingValue: any): Promise<any> {
|
||||||
|
if (typeof mappingValue === 'string') {
|
||||||
|
return processMappingValue(mappingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mappingValue && typeof mappingValue === 'object' && !Array.isArray(mappingValue)) {
|
||||||
|
const result: any = {};
|
||||||
|
for (const [key, value] of Object.entries(mappingValue)) {
|
||||||
|
result[key] = await evaluateMappingValue(value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// AppData Interface and Class
|
||||||
|
// ============================================================================
|
||||||
export interface IAppDataOptions<T = any> {
|
export interface IAppDataOptions<T = any> {
|
||||||
dirPath?: string;
|
dirPath?: string;
|
||||||
requiredKeys?: Array<keyof T>;
|
requiredKeys?: Array<keyof T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wether keys should be persisted on disk or not
|
* Whether keys should be persisted on disk or not
|
||||||
|
*/
|
||||||
|
ephemeral?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use 'ephemeral' instead
|
||||||
*/
|
*/
|
||||||
ephermal?: boolean;
|
ephermal?: boolean;
|
||||||
|
|
||||||
@@ -33,6 +244,56 @@ export class AppData<T = any> {
|
|||||||
return appData;
|
return appData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helper to get an environment variable as a boolean
|
||||||
|
* @param envVarName The name of the environment variable
|
||||||
|
* @returns boolean value (true if env var is "true", false otherwise)
|
||||||
|
*/
|
||||||
|
public static async valueAsBoolean(envVarName: string): Promise<boolean> {
|
||||||
|
const value = await getQenv().getEnvVarOnDemand(envVarName);
|
||||||
|
return toBoolean(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helper to get an environment variable as parsed JSON
|
||||||
|
* @param envVarName The name of the environment variable
|
||||||
|
* @returns Parsed JSON object/array
|
||||||
|
*/
|
||||||
|
public static async valueAsJson<R = any>(envVarName: string): Promise<R | undefined> {
|
||||||
|
const value = await getQenv().getEnvVarOnDemand(envVarName);
|
||||||
|
return toJson<R>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helper to get an environment variable as base64 decoded string
|
||||||
|
* @param envVarName The name of the environment variable
|
||||||
|
* @returns Decoded string
|
||||||
|
*/
|
||||||
|
public static async valueAsBase64(envVarName: string): Promise<string | undefined> {
|
||||||
|
const value = await getQenv().getEnvVarOnDemand(envVarName);
|
||||||
|
return fromBase64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helper to get an environment variable as a string
|
||||||
|
* @param envVarName The name of the environment variable
|
||||||
|
* @returns String value
|
||||||
|
*/
|
||||||
|
public static async valueAsString(envVarName: string): Promise<string | undefined> {
|
||||||
|
const value = await getQenv().getEnvVarOnDemand(envVarName);
|
||||||
|
return toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helper to get an environment variable as a number
|
||||||
|
* @param envVarName The name of the environment variable
|
||||||
|
* @returns Number value
|
||||||
|
*/
|
||||||
|
public static async valueAsNumber(envVarName: string): Promise<number | undefined> {
|
||||||
|
const value = await getQenv().getEnvVarOnDemand(envVarName);
|
||||||
|
return toNumber(value);
|
||||||
|
}
|
||||||
|
|
||||||
// instance
|
// instance
|
||||||
public readyDeferred = plugins.smartpromise.defer<void>();
|
public readyDeferred = plugins.smartpromise.defer<void>();
|
||||||
public options: IAppDataOptions<T>;
|
public options: IAppDataOptions<T>;
|
||||||
@@ -45,11 +306,20 @@ export class AppData<T = any> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* inits app data
|
* inits app data
|
||||||
* @param pathArg
|
|
||||||
*/
|
*/
|
||||||
private async init(pathArg?: string) {
|
private async init() {
|
||||||
if (this.options.dirPath || this.options.ephermal) {
|
console.log('🚀 Initializing AppData...');
|
||||||
// ok, nothing to do here;
|
|
||||||
|
// Handle backward compatibility for typo
|
||||||
|
const isEphemeral = this.options.ephemeral ?? this.options.ephermal ?? false;
|
||||||
|
if (this.options.ephermal && !this.options.ephemeral) {
|
||||||
|
console.warn('⚠️ Option "ephermal" is deprecated, use "ephemeral" instead.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.dirPath) {
|
||||||
|
console.log(` 📁 Using custom directory: ${this.options.dirPath}`);
|
||||||
|
} else if (isEphemeral) {
|
||||||
|
console.log(` 💨 Using ephemeral storage (in-memory only)`);
|
||||||
} else {
|
} else {
|
||||||
const appDataDir = '/app/data';
|
const appDataDir = '/app/data';
|
||||||
const dataDir = '/data';
|
const dataDir = '/data';
|
||||||
@@ -58,147 +328,73 @@ export class AppData<T = any> {
|
|||||||
const dataExists = plugins.smartfile.fs.isDirectory(dataDir);
|
const dataExists = plugins.smartfile.fs.isDirectory(dataDir);
|
||||||
if (appDataExists) {
|
if (appDataExists) {
|
||||||
this.options.dirPath = appDataDir;
|
this.options.dirPath = appDataDir;
|
||||||
|
console.log(` 📁 Auto-selected container directory: ${appDataDir}`);
|
||||||
} else if (dataExists) {
|
} else if (dataExists) {
|
||||||
this.options.dirPath = dataDir;
|
this.options.dirPath = dataDir;
|
||||||
|
console.log(` 📁 Auto-selected data directory: ${dataDir}`);
|
||||||
} else {
|
} else {
|
||||||
await plugins.smartfile.fs.ensureDir(nogitAppData);
|
await plugins.smartfile.fs.ensureDir(nogitAppData);
|
||||||
this.options.dirPath = nogitAppData;
|
this.options.dirPath = nogitAppData;
|
||||||
|
console.log(` 📁 Auto-selected local directory: ${nogitAppData}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.kvStore = new KeyValueStore<T>({
|
this.kvStore = new KeyValueStore<T>({
|
||||||
typeArg: this.options.ephermal ? 'ephemeral' : 'custom',
|
typeArg: isEphemeral ? 'ephemeral' : 'custom',
|
||||||
identityArg: 'appkv',
|
identityArg: 'appkv',
|
||||||
customPath: this.options.dirPath,
|
customPath: this.options.dirPath,
|
||||||
mandatoryKeys: this.options.requiredKeys as Array<keyof T>,
|
mandatoryKeys: this.options.requiredKeys as Array<keyof T>,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.options.envMapping) {
|
if (this.options.envMapping) {
|
||||||
const qenvInstance = new plugins.qenv.Qenv(
|
console.log(`📦 Processing envMapping for AppData...`);
|
||||||
process.cwd(),
|
const totalKeys = Object.keys(this.options.envMapping).length;
|
||||||
plugins.path.join(process.cwd(), '.nogit'),
|
let processedCount = 0;
|
||||||
);
|
|
||||||
|
|
||||||
// Recursive function to handle nested objects, now includes key parameter
|
|
||||||
const processEnvMapping = async (
|
|
||||||
key: keyof T,
|
|
||||||
mappingValue: any,
|
|
||||||
parentKey: keyof T | '' = '',
|
|
||||||
): Promise<any> => {
|
|
||||||
if (typeof mappingValue === 'string') {
|
|
||||||
let envValue: string | boolean | T[keyof T];
|
|
||||||
let convert: 'none' | 'json' | 'base64' | 'boolean' = 'none';
|
|
||||||
switch (true) {
|
|
||||||
case mappingValue.startsWith('hard:'):
|
|
||||||
envValue = mappingValue.replace('hard:', '') as T[keyof T];
|
|
||||||
break;
|
|
||||||
case mappingValue.startsWith('hard_boolean:'):
|
|
||||||
envValue = mappingValue.replace('hard_boolean:', '') === 'true';
|
|
||||||
convert = 'boolean';
|
|
||||||
break;
|
|
||||||
case mappingValue.startsWith('hard_json:'):
|
|
||||||
envValue = JSON.parse(
|
|
||||||
mappingValue.replace('hard_json:', ''),
|
|
||||||
) as T[keyof T];
|
|
||||||
convert = 'json';
|
|
||||||
break;
|
|
||||||
case mappingValue.startsWith('hard_base64:'):
|
|
||||||
envValue = Buffer.from(
|
|
||||||
mappingValue.replace('hard_base64:', ''),
|
|
||||||
'base64',
|
|
||||||
).toString() as T[keyof T];
|
|
||||||
convert = 'base64';
|
|
||||||
break;
|
|
||||||
case mappingValue.startsWith('boolean:'):
|
|
||||||
envValue = (await qenvInstance.getEnvVarOnDemand(
|
|
||||||
mappingValue.replace('boolean:', ''),
|
|
||||||
)) as T[keyof T];
|
|
||||||
convert = 'boolean';
|
|
||||||
break;
|
|
||||||
case mappingValue.startsWith('json:'):
|
|
||||||
envValue = (await qenvInstance.getEnvVarOnDemand(
|
|
||||||
mappingValue.replace('json:', ''),
|
|
||||||
)) as T[keyof T];
|
|
||||||
convert = 'json';
|
|
||||||
break;
|
|
||||||
case mappingValue.startsWith('base64:'):
|
|
||||||
envValue = (await qenvInstance.getEnvVarOnDemand(
|
|
||||||
mappingValue.replace('base64:', ''),
|
|
||||||
)) as T[keyof T];
|
|
||||||
convert = 'base64';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
envValue = (await qenvInstance.getEnvVarOnDemand(
|
|
||||||
mappingValue,
|
|
||||||
)) as T[keyof T];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lets format the env value
|
|
||||||
if (envValue) {
|
|
||||||
if (typeof envValue === 'string' && convert === 'boolean') {
|
|
||||||
envValue = envValue === 'true';
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof envValue === 'string' &&
|
|
||||||
(mappingValue.endsWith('_JSON') || convert === 'json')
|
|
||||||
) {
|
|
||||||
envValue = JSON.parse(envValue as string) as T[keyof T];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeof envValue === 'string' &&
|
|
||||||
(mappingValue.endsWith('_BASE64') || convert === 'base64')
|
|
||||||
) {
|
|
||||||
envValue = Buffer.from(envValue as string, 'base64').toString();
|
|
||||||
}
|
|
||||||
if (!parentKey) {
|
|
||||||
await this.kvStore.writeKey(key, envValue as any);
|
|
||||||
} else {
|
|
||||||
return envValue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
} else if (typeof mappingValue === 'object' && mappingValue !== null) {
|
|
||||||
const resultObject: Partial<T> = {};
|
|
||||||
for (const innerKey in mappingValue) {
|
|
||||||
const nestedValue = mappingValue[innerKey];
|
|
||||||
// For nested objects, call recursively but do not immediately write to kvStore
|
|
||||||
const nestedResult = await processEnvMapping(
|
|
||||||
innerKey as keyof T,
|
|
||||||
nestedValue,
|
|
||||||
key,
|
|
||||||
);
|
|
||||||
resultObject[innerKey as keyof T] = nestedResult;
|
|
||||||
}
|
|
||||||
if (parentKey === '') {
|
|
||||||
// Only write to kvStore if at the top level
|
|
||||||
await this.kvStore.writeKey(key, resultObject as T[keyof T]);
|
|
||||||
} else {
|
|
||||||
// For nested objects, return the constructed object instead of writing to kvStore
|
|
||||||
return resultObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Process each top-level key in envMapping
|
||||||
for (const key in this.options.envMapping) {
|
for (const key in this.options.envMapping) {
|
||||||
await processEnvMapping(key as keyof T, this.options.envMapping[key]);
|
try {
|
||||||
|
const mappingSpec = this.options.envMapping[key];
|
||||||
|
console.log(` → Processing key "${key}" with spec:`, typeof mappingSpec === 'string' ? mappingSpec : 'nested object');
|
||||||
|
|
||||||
|
const evaluated = await evaluateMappingValue(mappingSpec);
|
||||||
|
if (evaluated !== undefined) {
|
||||||
|
await this.kvStore.writeKey(key as keyof T, evaluated);
|
||||||
|
processedCount++;
|
||||||
|
const valueType = Array.isArray(evaluated) ? 'array' : typeof evaluated;
|
||||||
|
console.log(` ✅ Successfully processed key "${key}" (type: ${valueType})`);
|
||||||
|
} else {
|
||||||
|
console.log(` ⚠️ Key "${key}" evaluated to undefined, skipping`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(` ❌ Failed to evaluate envMapping for key "${key}":`, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`📊 EnvMapping complete: ${processedCount}/${totalKeys} keys successfully processed`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply overwrite object after env mapping
|
||||||
if (this.options.overwriteObject) {
|
if (this.options.overwriteObject) {
|
||||||
for (const key of Object.keys(this.options.overwriteObject)) {
|
const overwriteKeys = Object.keys(this.options.overwriteObject);
|
||||||
console.log(
|
console.log(`🔄 Applying overwriteObject with ${overwriteKeys.length} key(s)...`);
|
||||||
`-> heads up: overwriting key ${key} from options.overwriteObject`,
|
|
||||||
);
|
for (const key of overwriteKeys) {
|
||||||
|
const value = this.options.overwriteObject[key];
|
||||||
|
const valueType = Array.isArray(value) ? 'array' : typeof value;
|
||||||
|
console.log(` 🔧 Overwriting key "${key}" with ${valueType} value`);
|
||||||
|
|
||||||
await this.kvStore.writeKey(
|
await this.kvStore.writeKey(
|
||||||
key as keyof T,
|
key as keyof T,
|
||||||
this.options.overwriteObject[key],
|
value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
console.log(`✅ OverwriteObject complete: ${overwriteKeys.length} key(s) overwritten`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.readyDeferred.resolve();
|
this.readyDeferred.resolve();
|
||||||
|
console.log('✨ AppData initialization complete!');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user