fix(storage): migrate filesystem operations to smartfs and tighten TypeScript initialization checks
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-04-30 - 6.1.1 - fix(storage)
|
||||||
|
migrate filesystem operations to smartfs and tighten TypeScript initialization checks
|
||||||
|
|
||||||
|
- replace @push.rocks/smartfile usage with smartfs and native node:fs across app data, key value store, and smartconfig handling
|
||||||
|
- improve JSON file read/write and deletion logic for persistent key value storage
|
||||||
|
- enable noImplicitAny in TypeScript config and add explicit initialization/type assertions where required
|
||||||
|
- update build tooling and runtime dependencies to match the new filesystem implementation
|
||||||
|
|
||||||
## 2026-03-24 - 6.1.0 - feat(docs)
|
## 2026-03-24 - 6.1.0 - feat(docs)
|
||||||
refresh project documentation and migrate smartconfig tool configuration keys
|
refresh project documentation and migrate smartconfig tool configuration keys
|
||||||
|
|
||||||
|
|||||||
+13
-14
@@ -7,7 +7,7 @@
|
|||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(tstest test/ --verbose --logfile --timeout 20)",
|
"test": "(tstest test/ --verbose --logfile --timeout 20)",
|
||||||
"build": "(tsbuild --web --allowimplicitany)",
|
"build": "(tsbuild --web)",
|
||||||
"buildDocs": "tsdoc"
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -22,20 +22,21 @@
|
|||||||
"homepage": "https://code.foss.global/push.rocks/smartconfig#readme",
|
"homepage": "https://code.foss.global/push.rocks/smartconfig#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@push.rocks/qenv": "^6.1.3",
|
"@push.rocks/qenv": "^6.1.3",
|
||||||
"@push.rocks/smartfile": "^11.2.5",
|
"@push.rocks/smartfs": "^1.5.1",
|
||||||
"@push.rocks/smartjson": "^5.0.20",
|
"@push.rocks/smartjson": "^6.0.1",
|
||||||
"@push.rocks/smartlog": "^3.1.8",
|
"@push.rocks/smartlog": "^3.2.2",
|
||||||
"@push.rocks/smartpath": "^6.0.0",
|
"@push.rocks/smartpath": "^6.0.0",
|
||||||
"@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/taskbuffer": "^3.1.7",
|
"@push.rocks/taskbuffer": "^8.0.2",
|
||||||
"@tsclass/tsclass": "^9.2.0"
|
"@tsclass/tsclass": "^9.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@git.zone/tsbuild": "^2.6.4",
|
"@git.zone/tsbuild": "^4.4.0",
|
||||||
"@git.zone/tsrun": "^1.3.3",
|
"@git.zone/tsrun": "^2.0.2",
|
||||||
"@git.zone/tstest": "^2.3.2",
|
"@git.zone/tstest": "^3.6.3",
|
||||||
"@types/node": "^22"
|
"@types/lodash.clonedeep": "^4.5.9",
|
||||||
|
"@types/node": "^25.6.0"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts/**/*",
|
"ts/**/*",
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
"assets/**/*",
|
"assets/**/*",
|
||||||
"cli.js",
|
"cli.js",
|
||||||
".smartconfig.json",
|
".smartconfig.json",
|
||||||
|
"license",
|
||||||
"readme.md"
|
"readme.md"
|
||||||
],
|
],
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
@@ -70,8 +72,5 @@
|
|||||||
"workflow improvement",
|
"workflow improvement",
|
||||||
"persistent storage"
|
"persistent storage"
|
||||||
],
|
],
|
||||||
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
|
"packageManager": "pnpm@10.28.2"
|
||||||
"pnpm": {
|
|
||||||
"overrides": {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2767
-3611
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartconfig',
|
name: '@push.rocks/smartconfig',
|
||||||
version: '6.1.0',
|
version: '6.1.1',
|
||||||
description: 'A comprehensive configuration management library providing key-value storage, environment variable mapping, and tool configuration.'
|
description: 'A comprehensive configuration management library providing key-value storage, environment variable mapping, and tool configuration.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,7 +403,7 @@ export class AppData<T = any> {
|
|||||||
// instance
|
// instance
|
||||||
public readyDeferred = plugins.smartpromise.defer<void>();
|
public readyDeferred = plugins.smartpromise.defer<void>();
|
||||||
public options: IAppDataOptions<T>;
|
public options: IAppDataOptions<T>;
|
||||||
private kvStore: KeyValueStore<T>;
|
private kvStore!: KeyValueStore<T>;
|
||||||
|
|
||||||
constructor(optionsArg: IAppDataOptions<T> = {}) {
|
constructor(optionsArg: IAppDataOptions<T> = {}) {
|
||||||
this.options = optionsArg;
|
this.options = optionsArg;
|
||||||
@@ -430,8 +430,8 @@ export class AppData<T = any> {
|
|||||||
const appDataDir = '/app/data';
|
const appDataDir = '/app/data';
|
||||||
const dataDir = '/data';
|
const dataDir = '/data';
|
||||||
const nogitAppData = '.nogit/appdata';
|
const nogitAppData = '.nogit/appdata';
|
||||||
const appDataExists = plugins.smartfile.fs.isDirectory(appDataDir);
|
const appDataExists = plugins.nodeFs.existsSync(appDataDir) && plugins.nodeFs.statSync(appDataDir).isDirectory();
|
||||||
const dataExists = plugins.smartfile.fs.isDirectory(dataDir);
|
const dataExists = plugins.nodeFs.existsSync(dataDir) && plugins.nodeFs.statSync(dataDir).isDirectory();
|
||||||
if (appDataExists) {
|
if (appDataExists) {
|
||||||
this.options.dirPath = appDataDir;
|
this.options.dirPath = appDataDir;
|
||||||
console.log(` 📁 Auto-selected container directory: ${appDataDir}`);
|
console.log(` 📁 Auto-selected container directory: ${appDataDir}`);
|
||||||
@@ -439,7 +439,7 @@ export class AppData<T = any> {
|
|||||||
this.options.dirPath = dataDir;
|
this.options.dirPath = dataDir;
|
||||||
console.log(` 📁 Auto-selected data directory: ${dataDir}`);
|
console.log(` 📁 Auto-selected data directory: ${dataDir}`);
|
||||||
} else {
|
} else {
|
||||||
await plugins.smartfile.fs.ensureDir(nogitAppData);
|
await plugins.smartFs.directory(nogitAppData).create();
|
||||||
this.options.dirPath = nogitAppData;
|
this.options.dirPath = nogitAppData;
|
||||||
console.log(` 📁 Auto-selected local directory: ${nogitAppData}`);
|
console.log(` 📁 Auto-selected local directory: ${nogitAppData}`);
|
||||||
}
|
}
|
||||||
@@ -494,17 +494,18 @@ export class AppData<T = any> {
|
|||||||
|
|
||||||
// Apply overwrite object after env mapping
|
// Apply overwrite object after env mapping
|
||||||
if (this.options.overwriteObject) {
|
if (this.options.overwriteObject) {
|
||||||
const overwriteKeys = Object.keys(this.options.overwriteObject);
|
const overwriteObject = this.options.overwriteObject as Record<string, unknown>;
|
||||||
|
const overwriteKeys = Object.keys(overwriteObject);
|
||||||
console.log(`🔄 Applying overwriteObject with ${overwriteKeys.length} key(s)...`);
|
console.log(`🔄 Applying overwriteObject with ${overwriteKeys.length} key(s)...`);
|
||||||
|
|
||||||
for (const key of overwriteKeys) {
|
for (const key of overwriteKeys) {
|
||||||
const value = this.options.overwriteObject[key];
|
const value = overwriteObject[key];
|
||||||
const valueType = Array.isArray(value) ? 'array' : typeof value;
|
const valueType = Array.isArray(value) ? 'array' : typeof value;
|
||||||
console.log(` 🔧 Overwriting key "${key}" with ${valueType} 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,
|
||||||
value,
|
value as T[keyof T],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-12
@@ -26,21 +26,18 @@ export class KeyValueStore<T = any> {
|
|||||||
name: 'syncTask',
|
name: 'syncTask',
|
||||||
buffered: true,
|
buffered: true,
|
||||||
bufferMax: 1,
|
bufferMax: 1,
|
||||||
execDelay: 0,
|
|
||||||
taskFunction: async () => {
|
taskFunction: async () => {
|
||||||
if (this.type !== 'ephemeral') {
|
if (this.type !== 'ephemeral') {
|
||||||
|
const storedJson = await plugins.smartFs.file(this.filePath!).encoding('utf8').read() as string;
|
||||||
this.dataObject = {
|
this.dataObject = {
|
||||||
...plugins.smartfile.fs.toObjectSync(this.filePath),
|
...plugins.smartjson.parse(storedJson || '{}'),
|
||||||
...this.dataObject,
|
...this.dataObject,
|
||||||
};
|
};
|
||||||
for (const key of Object.keys(this.deletedObject) as Array<keyof T>) {
|
for (const key of Object.keys(this.deletedObject) as Array<keyof T>) {
|
||||||
delete this.dataObject[key];
|
delete this.dataObject[key];
|
||||||
}
|
}
|
||||||
this.deletedObject = {};
|
this.deletedObject = {};
|
||||||
await plugins.smartfile.memory.toFs(
|
await plugins.smartFs.file(this.filePath!).encoding('utf8').write(plugins.smartjson.stringifyPretty(this.dataObject));
|
||||||
plugins.smartjson.stringifyPretty(this.dataObject),
|
|
||||||
this.filePath,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const newStateString = plugins.smartjson.stringify(this.dataObject);
|
const newStateString = plugins.smartjson.stringify(this.dataObject);
|
||||||
|
|
||||||
@@ -67,13 +64,16 @@ export class KeyValueStore<T = any> {
|
|||||||
paths.cwd,
|
paths.cwd,
|
||||||
);
|
);
|
||||||
this.filePath = absolutePath;
|
this.filePath = absolutePath;
|
||||||
if (plugins.smartfile.fs.isDirectorySync(this.filePath)) {
|
if (plugins.nodeFs.existsSync(this.filePath) && plugins.nodeFs.statSync(this.filePath).isDirectory()) {
|
||||||
this.filePath = plugins.path.join(
|
this.filePath = plugins.path.join(
|
||||||
this.filePath,
|
this.filePath,
|
||||||
this.identity + '.json',
|
this.identity + '.json',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
plugins.smartfile.fs.ensureFileSync(this.filePath, '{}');
|
plugins.nodeFs.mkdirSync(plugins.path.dirname(this.filePath), { recursive: true });
|
||||||
|
if (!plugins.nodeFs.existsSync(this.filePath)) {
|
||||||
|
plugins.nodeFs.writeFileSync(this.filePath, '{}');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +84,10 @@ export class KeyValueStore<T = any> {
|
|||||||
throw new Error('kv type not supported');
|
throw new Error('kv type not supported');
|
||||||
}
|
}
|
||||||
this.filePath = plugins.path.join(baseDir, this.identity + '.json');
|
this.filePath = plugins.path.join(baseDir, this.identity + '.json');
|
||||||
plugins.smartfile.fs.ensureDirSync(baseDir);
|
plugins.nodeFs.mkdirSync(baseDir, { recursive: true });
|
||||||
plugins.smartfile.fs.ensureFileSync(this.filePath, '{}');
|
if (!plugins.nodeFs.existsSync(this.filePath)) {
|
||||||
|
plugins.nodeFs.writeFileSync(this.filePath, '{}');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// if no custom path is provided, try to store at home directory
|
// if no custom path is provided, try to store at home directory
|
||||||
@@ -162,8 +164,11 @@ export class KeyValueStore<T = any> {
|
|||||||
*/
|
*/
|
||||||
public async wipe(): Promise<void> {
|
public async wipe(): Promise<void> {
|
||||||
this.dataObject = {};
|
this.dataObject = {};
|
||||||
if (this.type !== 'ephemeral') {
|
if (this.type !== 'ephemeral' && this.filePath) {
|
||||||
await plugins.smartfile.fs.remove(this.filePath);
|
const file = plugins.smartFs.file(this.filePath);
|
||||||
|
if (await file.exists()) {
|
||||||
|
await file.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import * as paths from './paths.js';
|
|||||||
*/
|
*/
|
||||||
export class Smartconfig {
|
export class Smartconfig {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
lookupPath: string;
|
lookupPath!: string;
|
||||||
smartconfigJsonExists: boolean;
|
smartconfigJsonExists = false;
|
||||||
smartconfigJsonData: any;
|
smartconfigJsonData: any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,9 +48,7 @@ export class Smartconfig {
|
|||||||
* checks if the JSON exists
|
* checks if the JSON exists
|
||||||
*/
|
*/
|
||||||
private checkSmartconfigJsonExists() {
|
private checkSmartconfigJsonExists() {
|
||||||
this.smartconfigJsonExists = plugins.smartfile.fs.fileExistsSync(
|
this.smartconfigJsonExists = plugins.nodeFs.existsSync(this.lookupPath);
|
||||||
this.lookupPath,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,8 +67,8 @@ export class Smartconfig {
|
|||||||
*/
|
*/
|
||||||
private checkSmartconfigJsonData() {
|
private checkSmartconfigJsonData() {
|
||||||
if (this.smartconfigJsonExists) {
|
if (this.smartconfigJsonExists) {
|
||||||
this.smartconfigJsonData = plugins.smartfile.fs.toObjectSync(
|
this.smartconfigJsonData = plugins.smartjson.parse(
|
||||||
this.lookupPath,
|
plugins.nodeFs.readFileSync(this.lookupPath, 'utf8'),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.smartconfigJsonData = {};
|
this.smartconfigJsonData = {};
|
||||||
|
|||||||
+6
-2
@@ -4,19 +4,23 @@ export { tsclass };
|
|||||||
|
|
||||||
import * as qenv from '@push.rocks/qenv';
|
import * as qenv from '@push.rocks/qenv';
|
||||||
import * as smartlog from '@push.rocks/smartlog';
|
import * as smartlog from '@push.rocks/smartlog';
|
||||||
|
import * as nodeFs from 'node:fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as smartfile from '@push.rocks/smartfile';
|
import * as smartfs from '@push.rocks/smartfs';
|
||||||
import * as smartjson from '@push.rocks/smartjson';
|
import * as smartjson from '@push.rocks/smartjson';
|
||||||
import * as smartpath from '@push.rocks/smartpath';
|
import * as smartpath from '@push.rocks/smartpath';
|
||||||
import * as smartpromise from '@push.rocks/smartpromise';
|
import * as smartpromise from '@push.rocks/smartpromise';
|
||||||
import * as smartrx from '@push.rocks/smartrx';
|
import * as smartrx from '@push.rocks/smartrx';
|
||||||
import * as taskbuffer from '@push.rocks/taskbuffer';
|
import * as taskbuffer from '@push.rocks/taskbuffer';
|
||||||
|
|
||||||
|
export const smartFs = new smartfs.SmartFs(new smartfs.SmartFsProviderNode());
|
||||||
|
|
||||||
export {
|
export {
|
||||||
qenv,
|
qenv,
|
||||||
smartlog,
|
smartlog,
|
||||||
|
nodeFs,
|
||||||
path,
|
path,
|
||||||
smartfile,
|
smartfs,
|
||||||
smartjson,
|
smartjson,
|
||||||
smartpath,
|
smartpath,
|
||||||
smartpromise,
|
smartpromise,
|
||||||
|
|||||||
+2
-2
@@ -6,10 +6,10 @@
|
|||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
|
"noImplicitAny": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": true,
|
||||||
"baseUrl": ".",
|
"types": ["node"]
|
||||||
"paths": {}
|
|
||||||
},
|
},
|
||||||
"exclude": ["dist_*/**/*.d.ts"]
|
"exclude": ["dist_*/**/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user