Compare commits

...

6 Commits

Author SHA1 Message Date
jkunz 521628cb72 v6.1.4
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-05-01 15:54:40 +00:00
jkunz 5e31dc93a3 fix(qenv): replace smartfile-based config loading with native fs and yaml parsing for env files 2026-05-01 15:54:39 +00:00
jkunz c0d33340c3 6.1.3 2025-08-16 12:35:35 +00:00
jkunz 5a81caa7bb fix(qenv): Handle falsy environment values correctly, improve env source resolution, add tests and update test script 2025-08-16 12:35:35 +00:00
jkunz a7e3bf1223 6.1.2 2025-08-14 07:22:44 +00:00
jkunz aedbc25269 fix(readme): Correct DATABASE_CONFIG example formatting in README and add local settings configuration file 2025-08-14 07:22:44 +00:00
14 changed files with 3956 additions and 3830 deletions
+36
View File
@@ -0,0 +1,36 @@
{
"@git.zone/cli": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "qenv",
"description": "A module for easily handling environment variables in Node.js projects with support for .yml and .json configuration.",
"npmPackagename": "@push.rocks/qenv",
"license": "MIT",
"keywords": [
"environment variables",
"configuration management",
"Node.js",
"TypeScript",
"Docker secrets",
"CI/CD",
"testing"
]
},
"release": {
"registries": [
"https://verdaccio.lossless.digital",
"https://registry.npmjs.org"
],
"accessLevel": "public"
}
},
"@git.zone/tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
},
"@ship.zone/szci": {
"npmGlobalTools": [],
"npmRegistryUrl": "registry.npmjs.org"
}
}
+23
View File
@@ -1,5 +1,28 @@
# Changelog
## 2026-05-01 - 6.1.4 - fix(qenv)
replace smartfile-based config loading with native fs and yaml parsing for env files
- switch env and qenv file parsing to native fs with explicit JSON/YAML handling
- tighten TypeScript typings and optional path handling to avoid undefined and non-Error access issues
- update ConfigVault adapter to return the env bundle shape expected by consumers
- refresh build tooling and add yaml as a runtime dependency
## 2025-08-16 - 6.1.3 - fix(qenv)
Handle falsy environment values correctly, improve env source resolution, add tests and update test script
- Treat 0, false and empty string as valid environment values by checking for !== undefined when resolving env vars
- Refactor source resolution to iterate over environment, env file, Docker secrets and secret.json, returning the first defined value
- Ensure env.json and Docker secret JSON return strings for scalar values and base64-encode object values
- Add tests covering falsy values and lookup behavior (test/test.falsy.ts)
- Update package.json test script to run tstest with --verbose --testlog --timeout flags
## 2025-08-14 - 6.1.2 - fix(readme)
Correct DATABASE_CONFIG example formatting in README and add local settings configuration file
- Fix YAML formatting in DATABASE_CONFIG example to reflect proper YAML syntax
- Introduce .claude/settings.local.json with updated permission settings
## 2025-08-14 - 6.1.1 - fix(qenv)
Improve documentation, update dependencies, and refine project configuration
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2026 Task Venture Capital GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+13 -6
View File
@@ -1,9 +1,5 @@
{
"npmci": {
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"gitzone": {
"@git.zone/cli": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
@@ -21,9 +17,20 @@
"CI/CD",
"testing"
]
},
"release": {
"registries": [
"https://verdaccio.lossless.digital",
"https://registry.npmjs.org"
],
"accessLevel": "public"
}
},
"tsdoc": {
"@git.zone/tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
},
"@ship.zone/szci": {
"npmGlobalTools": [],
"npmRegistryUrl": "registry.npmjs.org"
}
}
+15 -12
View File
@@ -1,14 +1,15 @@
{
"name": "@push.rocks/qenv",
"version": "6.1.1",
"version": "6.1.4",
"private": false,
"description": "A module for easily handling environment variables in Node.js projects with support for .yml and .json configuration.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"type": "module",
"scripts": {
"test": "(tstest test/)",
"build": "(tsbuild --web --allowimplicitany)",
"test": "(tstest test/ --verbose --testlog --timeout 20)",
"build": "tsbuild --web",
"format": "gitzone format",
"buildDocs": "tsdoc"
},
"repository": {
@@ -24,24 +25,24 @@
"CI/CD",
"testing"
],
"author": "Lossless GmbH",
"author": "Task Venture Capital GmbH <hello@task.vc>",
"license": "MIT",
"bugs": {
"url": "https://gitlab.com/pushrocks/qenv/issues"
},
"homepage": "https://code.foss.global/push.rocks/qenv",
"devDependencies": {
"@git.zone/tsbuild": "^2.6.4",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^2.3.2",
"@types/node": "^22.13.13"
"@git.zone/tsbuild": "^4.4.0",
"@git.zone/tsrun": "^2.0.3",
"@git.zone/tstest": "^3.6.3",
"@types/node": "^25.6.0"
},
"dependencies": {
"@api.global/typedrequest": "^3.1.10",
"@api.global/typedrequest": "^3.3.0",
"@configvault.io/interfaces": "^1.0.17",
"@push.rocks/smartfile": "^11.2.5",
"@push.rocks/smartlog": "^3.1.8",
"@push.rocks/smartpath": "^6.0.0"
"@push.rocks/smartlog": "^3.2.2",
"@push.rocks/smartpath": "^6.0.0",
"yaml": "^2.8.3"
},
"files": [
"ts/**/*",
@@ -52,6 +53,8 @@
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
".smartconfig.json",
"license",
"npmextra.json",
"readme.md"
],
+3618 -3754
View File
File diff suppressed because it is too large Load Diff
+7 -10
View File
@@ -102,17 +102,14 @@ Qenv loads variables in this order (first found wins):
Store and retrieve complex configuration objects:
```typescript
// In env.yml
const config = {
database: {
host: 'localhost',
port: 5432,
options: {
ssl: true,
# In env.yml
DATABASE_CONFIG:
database:
host: localhost
port: 5432
options:
ssl: true
poolSize: 10
}
}
};
// Qenv automatically handles base64 encoding
const dbConfig = await qenv.getEnvVarOnDemandAsObject('DATABASE_CONFIG');
+120
View File
@@ -0,0 +1,120 @@
import * as path from 'path';
import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as qenv from '../ts/index.js';
const testDir = path.dirname(new URL(import.meta.url).pathname);
// Test falsy values handling
tap.test('should handle falsy values correctly', async () => {
// Set up environment variables with falsy values
process.env['FALSY_FALSE'] = 'false';
process.env['FALSY_ZERO'] = '0';
process.env['FALSY_EMPTY'] = '';
const testQenv = new qenv.Qenv(testDir, testDir, false);
// Test that falsy values are returned, not undefined
expect(await testQenv.getEnvVarOnDemand('FALSY_FALSE')).toEqual('false');
expect(await testQenv.getEnvVarOnDemand('FALSY_ZERO')).toEqual('0');
expect(await testQenv.getEnvVarOnDemand('FALSY_EMPTY')).toEqual('');
// Test sync versions
expect(testQenv.getEnvVarOnDemandSync('FALSY_FALSE')).toEqual('false');
expect(testQenv.getEnvVarOnDemandSync('FALSY_ZERO')).toEqual('0');
expect(testQenv.getEnvVarOnDemandSync('FALSY_EMPTY')).toEqual('');
// Test that undefined is still returned for non-existent variables
expect(await testQenv.getEnvVarOnDemand('NON_EXISTENT')).toBeUndefined();
expect(testQenv.getEnvVarOnDemandSync('NON_EXISTENT')).toBeUndefined();
// Clean up
delete process.env['FALSY_FALSE'];
delete process.env['FALSY_ZERO'];
delete process.env['FALSY_EMPTY'];
});
tap.test('should handle falsy values in env.json file', async () => {
// Create a test env.json with falsy values
const testAssetsDir = path.join(testDir, 'assets-falsy');
const fs = await import('fs');
// Create directory if it doesn't exist
if (!fs.existsSync(testAssetsDir)) {
fs.mkdirSync(testAssetsDir, { recursive: true });
}
// Create env.json with falsy values
const envJsonContent = {
JSON_FALSE: false,
JSON_ZERO: 0,
JSON_EMPTY: ''
};
fs.writeFileSync(
path.join(testAssetsDir, 'env.json'),
JSON.stringify(envJsonContent, null, 2)
);
const testQenv = new qenv.Qenv(testAssetsDir, testAssetsDir, false);
// Test that falsy values from JSON are returned correctly
expect(await testQenv.getEnvVarOnDemand('JSON_FALSE')).toEqual('false');
expect(await testQenv.getEnvVarOnDemand('JSON_ZERO')).toEqual('0');
expect(await testQenv.getEnvVarOnDemand('JSON_EMPTY')).toEqual('');
// Clean up
fs.rmSync(testAssetsDir, { recursive: true, force: true });
});
tap.test('should throw error for undefined in strict mode', async () => {
const testQenv = new qenv.Qenv(testDir, testDir, false);
// Set a falsy value
process.env['FALSY_VALUE'] = '0';
// Should NOT throw for falsy value
let result;
try {
result = await testQenv.getEnvVarOnDemandStrict('FALSY_VALUE');
} catch (error) {
// Should not reach here
expect(true).toBeFalse();
}
expect(result).toEqual('0');
// Should throw for non-existent variable
let threwError = false;
try {
await testQenv.getEnvVarOnDemandStrict('NON_EXISTENT_VAR');
} catch (error) {
threwError = true;
const errorMessage = error instanceof Error ? error.message : String(error);
expect(errorMessage).toContain('is not set');
}
expect(threwError).toBeTrue();
// Clean up
delete process.env['FALSY_VALUE'];
});
tap.test('should handle array of env vars with falsy values', async () => {
const testQenv = new qenv.Qenv(testDir, testDir, false);
// Set up test environment
process.env['FIRST_VAR'] = '0';
process.env['SECOND_VAR'] = 'false';
// Test that it returns the first defined value, even if falsy
const result = await testQenv.getEnvVarOnDemand(['NON_EXISTENT', 'FIRST_VAR', 'SECOND_VAR']);
expect(result).toEqual('0');
// Test sync version
const resultSync = testQenv.getEnvVarOnDemandSync(['NON_EXISTENT', 'FIRST_VAR', 'SECOND_VAR']);
expect(resultSync).toEqual('0');
// Clean up
delete process.env['FIRST_VAR'];
delete process.env['SECOND_VAR'];
});
export default tap.start();
+1 -1
View File
@@ -32,4 +32,4 @@ tap.test('keyValueObjectArray should hold all retrieved values', async () => {
expect(await testQenv.keyValueObject.key2).toEqual('fromJson');
});
tap.start();
export default tap.start();
+1 -1
View File
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/qenv',
version: '6.1.1',
version: '6.1.4',
description: 'A module for easily handling environment variables in Node.js projects with support for .yml and .json configuration.'
}
+3 -2
View File
@@ -1,13 +1,13 @@
import * as plugins from './qenv.plugins.js';
export class CloudlyAdapter {
public configVaultUrl: string;
public configVaultUrl?: string;
constructor(configVaultUrl?: string) {
this.configVaultUrl = configVaultUrl;
}
public async getConfigBundle(): Promise<plugins.configvaultInterfaces.data.IConfigBundle> {
public async getConfigBundle(): Promise<plugins.configvaultInterfaces.data.IEnvBundle | null> {
if (this.configVaultUrl) {
console.log(`ConfigVault specified through constructor`)
} else if (process.env['CONFIGVAULT_URL']) {
@@ -26,5 +26,6 @@ export class CloudlyAdapter {
const response = await tr.fire({
authorization: parsedUrl.pathname.replace('/', ''),
})
return response.envBundle;
}
}
+85 -36
View File
@@ -2,18 +2,19 @@ import { CloudlyAdapter } from './qenv.classes.configvaultadapter.js';
import * as plugins from './qenv.plugins.js';
export type TEnvVarRef = string | (() => Promise<string>);
type TKeyValueObject = Record<string, any>;
export class Qenv {
public requiredEnvVars: string[] = [];
public availableEnvVars: string[] = [];
public missingEnvVars: string[] = [];
public keyValueObject: { [key: string]: any } = {};
public keyValueObject: TKeyValueObject = {};
public logger = new plugins.smartlog.ConsoleLog();
public cloudlyAdapter: CloudlyAdapter;
public qenvFilePathAbsolute: string;
public envFilePathAbsolute: string;
public qenvFilePathAbsolute = '';
public envFilePathAbsolute?: string;
constructor(
qenvFileBasePathArg: string = process.cwd(),
@@ -27,7 +28,7 @@ export class Qenv {
this.checkForMissingEnvVars(failOnMissing);
}
private initializeFilePaths(qenvFileBasePathArg: string, envFileBasePathArg: string) {
private initializeFilePaths(qenvFileBasePathArg: string, envFileBasePathArg?: string) {
this.qenvFilePathAbsolute = plugins.path.join(
plugins.path.resolve(qenvFileBasePathArg),
'qenv.yml'
@@ -40,9 +41,9 @@ export class Qenv {
const envFileYmlPath = plugins.path.join(envFileBasePath, 'env.yml');
const envFileYamlPath = plugins.path.join(envFileBasePath, 'env.yaml');
const envFileJsonExists = plugins.smartfile.fs.fileExistsSync(envFileJsonPath);
const envFileYmlExists = plugins.smartfile.fs.fileExistsSync(envFileYmlPath);
const envFileYamlExists = plugins.smartfile.fs.fileExistsSync(envFileYamlPath);
const envFileJsonExists = this.fileExists(envFileJsonPath);
const envFileYmlExists = this.fileExists(envFileYmlPath);
const envFileYamlExists = this.fileExists(envFileYamlPath);
if (envFileJsonExists && (envFileYmlExists || envFileYamlExists)) {
this.logger.log('warn', 'Both env.json and env.yml files exist! Using env.json');
@@ -58,10 +59,13 @@ export class Qenv {
}
private loadRequiredEnvVars() {
if (plugins.smartfile.fs.fileExistsSync(this.qenvFilePathAbsolute)) {
const qenvFile = plugins.smartfile.fs.toObjectSync(this.qenvFilePathAbsolute);
if (qenvFile?.required && Array.isArray(qenvFile.required)) {
this.requiredEnvVars.push(...qenvFile.required);
if (this.fileExists(this.qenvFilePathAbsolute)) {
const qenvFile = this.readObjectFromFile(this.qenvFilePathAbsolute);
const requiredEnvVars = qenvFile.required;
if (Array.isArray(requiredEnvVars)) {
this.requiredEnvVars.push(
...requiredEnvVars.filter((envVar): envVar is string => typeof envVar === 'string')
);
} else {
this.logger.log('warn', 'qenv.yml does not contain a "required" Array!');
}
@@ -71,7 +75,7 @@ export class Qenv {
private loadAvailableEnvVars() {
for (const envVar of this.requiredEnvVars) {
const value = this.getEnvVarOnDemand(envVar);
if (value) {
if (value !== undefined) {
this.availableEnvVars.push(envVar);
this.keyValueObject[envVar] = value;
}
@@ -101,7 +105,7 @@ export class Qenv {
if (Array.isArray(envVarNameOrNames)) {
for (const envVarName of envVarNameOrNames) {
const value = await this.tryGetEnvVar(envVarName);
if (value) {
if (value !== undefined) {
return value;
}
}
@@ -120,7 +124,7 @@ export class Qenv {
envVarNameOrNames: TEnvVarRef | TEnvVarRef[]
): Promise<string> {
const value = await this.getEnvVarOnDemand(envVarNameOrNames);
if (!value) {
if (value === undefined) {
throw new Error(`Env var ${envVarNameOrNames} is not set!`);
}
return value;
@@ -132,7 +136,7 @@ export class Qenv {
if (Array.isArray(envVarNameOrNames)) {
for (const envVarName of envVarNameOrNames) {
const value = this.tryGetEnvVarSync(envVarName);
if (value) {
if (value !== undefined) {
return value;
}
}
@@ -156,21 +160,37 @@ export class Qenv {
return await envVarRefArg();
}
return (
this.getFromEnvironmentVariable(envVarRefArg) ||
this.getFromEnvYamlOrJsonFile(envVarRefArg) ||
this.getFromDockerSecret(envVarRefArg) ||
const sources = [
this.getFromEnvironmentVariable(envVarRefArg),
this.getFromEnvYamlOrJsonFile(envVarRefArg),
this.getFromDockerSecret(envVarRefArg),
this.getFromDockerSecretJson(envVarRefArg)
);
];
for (const value of sources) {
if (value !== undefined) {
return value;
}
}
return undefined;
}
private tryGetEnvVarSync(envVarName: string): string | undefined {
return (
this.getFromEnvironmentVariable(envVarName) ||
this.getFromEnvYamlOrJsonFile(envVarName) ||
this.getFromDockerSecret(envVarName) ||
const sources = [
this.getFromEnvironmentVariable(envVarName),
this.getFromEnvYamlOrJsonFile(envVarName),
this.getFromDockerSecret(envVarName),
this.getFromDockerSecretJson(envVarName)
);
];
for (const value of sources) {
if (value !== undefined) {
return value;
}
}
return undefined;
}
private getFromEnvironmentVariable(envVarName: string): string | undefined {
@@ -178,16 +198,19 @@ export class Qenv {
}
private getFromEnvYamlOrJsonFile(envVarName: string): string | undefined {
if (!plugins.smartfile.fs.fileExistsSync(this.envFilePathAbsolute)) {
if (!this.fileExists(this.envFilePathAbsolute)) {
return undefined;
}
try {
const envJson = plugins.smartfile.fs.toObjectSync(this.envFilePathAbsolute);
const envJson = this.readObjectFromFile(this.envFilePathAbsolute);
const value = envJson[envVarName];
if (typeof value === 'object') {
if (value === undefined) {
return undefined;
}
if (typeof value === 'object' && value !== null) {
return 'base64Object:' + this.encodeBase64(value);
}
return value;
return String(value);
} catch (error) {
return undefined;
}
@@ -195,23 +218,26 @@ export class Qenv {
private getFromDockerSecret(envVarName: string): string | undefined {
const secretPath = `/run/secrets/${envVarName}`;
if (plugins.smartfile.fs.fileExistsSync(secretPath)) {
return plugins.smartfile.fs.toStringSync(secretPath);
if (this.fileExists(secretPath)) {
return plugins.fs.readFileSync(secretPath, 'utf8');
}
return undefined;
}
private getFromDockerSecretJson(envVarName: string): string | undefined {
if (plugins.smartfile.fs.isDirectory('/run/secrets')) {
const availableSecrets = plugins.smartfile.fs.listAllItemsSync('/run/secrets');
if (this.directoryExists('/run/secrets')) {
const availableSecrets = plugins.fs.readdirSync('/run/secrets');
for (const secret of availableSecrets) {
if (secret.includes('secret.json')) {
const secretObject = plugins.smartfile.fs.toObjectSync(`/run/secrets/${secret}`);
const secretObject = this.readObjectFromFile(`/run/secrets/${secret}`);
const value = secretObject[envVarName];
if (typeof value === 'object') {
if (value === undefined) {
continue;
}
if (typeof value === 'object' && value !== null) {
return 'base64Object:' + this.encodeBase64(value);
}
return value;
return String(value);
}
}
}
@@ -227,4 +253,27 @@ export class Qenv {
const decodedString = Buffer.from(encodedString, 'base64').toString('utf-8');
return JSON.parse(decodedString);
}
private fileExists(filePath: string | undefined): filePath is string {
if (!filePath) {
return false;
}
return plugins.fs.existsSync(filePath);
}
private directoryExists(directoryPath: string): boolean {
try {
return plugins.fs.statSync(directoryPath).isDirectory();
} catch {
return false;
}
}
private readObjectFromFile(filePath: string): TKeyValueObject {
const fileString = plugins.fs.readFileSync(filePath, 'utf8');
const parsedObject = filePath.endsWith('.json')
? JSON.parse(fileString)
: plugins.yaml.parse(fileString);
return typeof parsedObject === 'object' && parsedObject !== null ? parsedObject : {};
}
}
+8 -3
View File
@@ -1,7 +1,8 @@
// native
import * as fs from 'node:fs';
import * as path from 'path';
export { path };
export { fs, path };
// @api.global scope
import * as typedrequest from '@api.global/typedrequest';
@@ -11,12 +12,16 @@ export {
}
// @pushrocks scope
import * as smartfile from '@push.rocks/smartfile';
import * as smartlog from '@push.rocks/smartlog';
export { smartfile, smartlog };
export { smartlog };
// @configvault.io scope
import * as configvaultInterfaces from '@configvault.io/interfaces';
export { configvaultInterfaces };
// third party scope
import * as yaml from 'yaml';
export { yaml };
+4 -4
View File
@@ -5,10 +5,10 @@
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noImplicitAny": true,
"esModuleInterop": true,
"verbatimModuleSyntax": true
"verbatimModuleSyntax": true,
"types": ["node"]
},
"exclude": [
"dist_*/**/*.d.ts"
]
"exclude": ["dist_*/**/*.d.ts"]
}