@spences10/pi-child-env 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
- package/src/index.test.ts +78 -0
- package/src/index.ts +87 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +14 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Scott Spence
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @spences10/pi-child-env
|
|
2
|
+
|
|
3
|
+
Shared safe environment builder for Pi child processes.
|
|
4
|
+
|
|
5
|
+
By default it passes only a minimal non-secret baseline (`PATH`,
|
|
6
|
+
locale, terminal, temp, home/user, color, and `LC_*` vars). Secrets
|
|
7
|
+
and provider credentials are not inherited unless explicitly
|
|
8
|
+
allowlisted.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { create_child_process_env } from '@spences10/pi-child-env';
|
|
14
|
+
|
|
15
|
+
spawn(command, args, {
|
|
16
|
+
env: create_child_process_env({
|
|
17
|
+
profile: 'team-mode',
|
|
18
|
+
explicit_env: {
|
|
19
|
+
MY_PI_TEAM_MEMBER: 'alice',
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Allowlists
|
|
26
|
+
|
|
27
|
+
All profiles honor `MY_PI_CHILD_ENV_ALLOWLIST=NAME,OTHER_NAME`.
|
|
28
|
+
|
|
29
|
+
Profile-specific allowlists:
|
|
30
|
+
|
|
31
|
+
- `mcp` — `MY_PI_MCP_ENV_ALLOWLIST`
|
|
32
|
+
- `lsp` — `MY_PI_LSP_ENV_ALLOWLIST`
|
|
33
|
+
- `hooks` — `MY_PI_HOOKS_ENV_ALLOWLIST`
|
|
34
|
+
- `team-mode` — `MY_PI_TEAM_MODE_ENV_ALLOWLIST`
|
|
35
|
+
|
|
36
|
+
Use allowlists only for variables the child process truly needs.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ChildEnvProfile = 'mcp' | 'lsp' | 'hooks' | 'team-mode';
|
|
2
|
+
export interface CreateChildProcessEnvOptions {
|
|
3
|
+
profile?: ChildEnvProfile;
|
|
4
|
+
explicit_env?: Record<string, string | undefined>;
|
|
5
|
+
source_env?: NodeJS.ProcessEnv;
|
|
6
|
+
extra_allowed_keys?: readonly string[];
|
|
7
|
+
extra_allowlist_env_keys?: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function create_child_process_env(options?: CreateChildProcessEnvOptions): NodeJS.ProcessEnv;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.create_child_process_env = create_child_process_env;
|
|
4
|
+
const BASE_CHILD_ENV_KEYS = new Set([
|
|
5
|
+
'CI',
|
|
6
|
+
'COLORTERM',
|
|
7
|
+
'FORCE_COLOR',
|
|
8
|
+
'HOME',
|
|
9
|
+
'LANG',
|
|
10
|
+
'LOGNAME',
|
|
11
|
+
'NO_COLOR',
|
|
12
|
+
'PATH',
|
|
13
|
+
'SHELL',
|
|
14
|
+
'TEMP',
|
|
15
|
+
'TERM',
|
|
16
|
+
'TMP',
|
|
17
|
+
'TMPDIR',
|
|
18
|
+
'USER',
|
|
19
|
+
]);
|
|
20
|
+
const SHARED_ENV_ALLOWLIST_KEY = 'MY_PI_CHILD_ENV_ALLOWLIST';
|
|
21
|
+
const PROFILE_ENV_ALLOWLIST_KEYS = {
|
|
22
|
+
mcp: 'MY_PI_MCP_ENV_ALLOWLIST',
|
|
23
|
+
lsp: 'MY_PI_LSP_ENV_ALLOWLIST',
|
|
24
|
+
hooks: 'MY_PI_HOOKS_ENV_ALLOWLIST',
|
|
25
|
+
'team-mode': 'MY_PI_TEAM_MODE_ENV_ALLOWLIST',
|
|
26
|
+
};
|
|
27
|
+
function create_child_process_env(options = {}) {
|
|
28
|
+
const source_env = options.source_env ?? process.env;
|
|
29
|
+
const env = {};
|
|
30
|
+
const allowed_keys = new Set(BASE_CHILD_ENV_KEYS);
|
|
31
|
+
for (const key of Object.keys(source_env)) {
|
|
32
|
+
if (key.startsWith('LC_'))
|
|
33
|
+
allowed_keys.add(key);
|
|
34
|
+
}
|
|
35
|
+
for (const key of options.extra_allowed_keys ?? []) {
|
|
36
|
+
if (key.trim())
|
|
37
|
+
allowed_keys.add(key.trim());
|
|
38
|
+
}
|
|
39
|
+
const allowlist_env_keys = [
|
|
40
|
+
SHARED_ENV_ALLOWLIST_KEY,
|
|
41
|
+
...(options.profile
|
|
42
|
+
? [PROFILE_ENV_ALLOWLIST_KEYS[options.profile]]
|
|
43
|
+
: []),
|
|
44
|
+
...(options.extra_allowlist_env_keys ?? []),
|
|
45
|
+
];
|
|
46
|
+
for (const allowlist_key of allowlist_env_keys) {
|
|
47
|
+
for (const key of parse_env_allowlist(source_env[allowlist_key])) {
|
|
48
|
+
allowed_keys.add(key);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const key of allowed_keys) {
|
|
52
|
+
const value = source_env[key];
|
|
53
|
+
if (typeof value === 'string')
|
|
54
|
+
env[key] = value;
|
|
55
|
+
}
|
|
56
|
+
for (const [key, value] of Object.entries(options.explicit_env ?? {})) {
|
|
57
|
+
if (typeof value === 'string')
|
|
58
|
+
env[key] = value;
|
|
59
|
+
}
|
|
60
|
+
return env;
|
|
61
|
+
}
|
|
62
|
+
function parse_env_allowlist(value) {
|
|
63
|
+
if (!value)
|
|
64
|
+
return [];
|
|
65
|
+
return value
|
|
66
|
+
.split(',')
|
|
67
|
+
.map((key) => key.trim())
|
|
68
|
+
.filter(Boolean);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAoCA,4DA0CC;AApED,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IACnC,IAAI;IACJ,WAAW;IACX,aAAa;IACb,MAAM;IACN,MAAM;IACN,SAAS;IACT,UAAU;IACV,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,KAAK;IACL,QAAQ;IACR,MAAM;CACN,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,2BAA2B,CAAC;AAE7D,MAAM,0BAA0B,GAAoC;IACnE,GAAG,EAAE,yBAAyB;IAC9B,GAAG,EAAE,yBAAyB;IAC9B,KAAK,EAAE,2BAA2B;IAClC,WAAW,EAAE,+BAA+B;CAC5C,CAAC;AAEF,SAAgB,wBAAwB,CACvC,UAAwC,EAAE;IAE1C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC;IACrD,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAElD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3C,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,kBAAkB,IAAI,EAAE,EAAE,CAAC;QACpD,IAAI,GAAG,CAAC,IAAI,EAAE;YAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,kBAAkB,GAAG;QAC1B,wBAAwB;QACxB,GAAG,CAAC,OAAO,CAAC,OAAO;YAClB,CAAC,CAAC,CAAC,0BAA0B,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC/C,CAAC,CAAC,EAAE,CAAC;QACN,GAAG,CAAC,OAAO,CAAC,wBAAwB,IAAI,EAAE,CAAC;KAC3C,CAAC;IACF,KAAK,MAAM,aAAa,IAAI,kBAAkB,EAAE,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,mBAAmB,CACpC,UAAU,CAAC,aAAa,CAAC,CACzB,EAAE,CAAC;YACH,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACjD,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CACxC,OAAO,CAAC,YAAY,IAAI,EAAE,CAC1B,EAAE,CAAC;QACH,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACjD,CAAC;IAED,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAyB;IACrD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,KAAK;SACV,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spences10/pi-child-env",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared safe environment builder for Pi child processes",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"env",
|
|
7
|
+
"pi",
|
|
8
|
+
"pi-package",
|
|
9
|
+
"security"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": "Scott Spence <me@scottspence.com>",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/scottspence/my-pi.git",
|
|
16
|
+
"directory": "packages/pi-child-env"
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^25.6.0",
|
|
28
|
+
"typescript": "^6.0.0",
|
|
29
|
+
"vitest": "^4.1.5"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=22.0.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.build.json",
|
|
36
|
+
"check": "tsc --noEmit -p tsconfig.json",
|
|
37
|
+
"test": "vitest run"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { create_child_process_env } from './index.js';
|
|
3
|
+
|
|
4
|
+
describe('create_child_process_env', () => {
|
|
5
|
+
it('keeps baseline env and strips common secrets by default', () => {
|
|
6
|
+
const env = create_child_process_env({
|
|
7
|
+
source_env: {
|
|
8
|
+
PATH: '/bin',
|
|
9
|
+
HOME: '/home/test',
|
|
10
|
+
LANG: 'en_GB.UTF-8',
|
|
11
|
+
LC_ALL: 'en_GB.UTF-8',
|
|
12
|
+
ANTHROPIC_API_KEY: 'secret',
|
|
13
|
+
OPENAI_API_KEY: 'secret',
|
|
14
|
+
AWS_SECRET_ACCESS_KEY: 'secret',
|
|
15
|
+
DATABASE_URL: 'postgres://secret',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(env).toMatchObject({
|
|
20
|
+
PATH: '/bin',
|
|
21
|
+
HOME: '/home/test',
|
|
22
|
+
LANG: 'en_GB.UTF-8',
|
|
23
|
+
LC_ALL: 'en_GB.UTF-8',
|
|
24
|
+
});
|
|
25
|
+
expect(env.ANTHROPIC_API_KEY).toBeUndefined();
|
|
26
|
+
expect(env.OPENAI_API_KEY).toBeUndefined();
|
|
27
|
+
expect(env.AWS_SECRET_ACCESS_KEY).toBeUndefined();
|
|
28
|
+
expect(env.DATABASE_URL).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('honors shared allowlist entries', () => {
|
|
32
|
+
const env = create_child_process_env({
|
|
33
|
+
source_env: {
|
|
34
|
+
PATH: '/bin',
|
|
35
|
+
AWS_PROFILE: 'dev',
|
|
36
|
+
MY_PI_CHILD_ENV_ALLOWLIST: ' AWS_PROFILE, , ',
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(env.AWS_PROFILE).toBe('dev');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('honors profile-specific allowlist entries', () => {
|
|
44
|
+
const env = create_child_process_env({
|
|
45
|
+
profile: 'team-mode',
|
|
46
|
+
source_env: {
|
|
47
|
+
PATH: '/bin',
|
|
48
|
+
ANTHROPIC_API_KEY: 'secret',
|
|
49
|
+
MY_PI_TEAM_MODE_ENV_ALLOWLIST: 'ANTHROPIC_API_KEY',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(env.ANTHROPIC_API_KEY).toBe('secret');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('supports explicit env overrides and custom allowlist env keys', () => {
|
|
57
|
+
const env = create_child_process_env({
|
|
58
|
+
explicit_env: {
|
|
59
|
+
API_KEY: 'explicit',
|
|
60
|
+
EMPTY: undefined,
|
|
61
|
+
},
|
|
62
|
+
extra_allowed_keys: ['CUSTOM_HOME'],
|
|
63
|
+
extra_allowlist_env_keys: ['CUSTOM_ALLOWLIST'],
|
|
64
|
+
source_env: {
|
|
65
|
+
PATH: '/bin',
|
|
66
|
+
CUSTOM_HOME: '/custom',
|
|
67
|
+
EXTRA: 'value',
|
|
68
|
+
API_KEY: 'ambient',
|
|
69
|
+
CUSTOM_ALLOWLIST: 'EXTRA',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(env.API_KEY).toBe('explicit');
|
|
74
|
+
expect(env.EMPTY).toBeUndefined();
|
|
75
|
+
expect(env.CUSTOM_HOME).toBe('/custom');
|
|
76
|
+
expect(env.EXTRA).toBe('value');
|
|
77
|
+
});
|
|
78
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export type ChildEnvProfile = 'mcp' | 'lsp' | 'hooks' | 'team-mode';
|
|
2
|
+
|
|
3
|
+
export interface CreateChildProcessEnvOptions {
|
|
4
|
+
profile?: ChildEnvProfile;
|
|
5
|
+
explicit_env?: Record<string, string | undefined>;
|
|
6
|
+
source_env?: NodeJS.ProcessEnv;
|
|
7
|
+
extra_allowed_keys?: readonly string[];
|
|
8
|
+
extra_allowlist_env_keys?: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const BASE_CHILD_ENV_KEYS = new Set([
|
|
12
|
+
'CI',
|
|
13
|
+
'COLORTERM',
|
|
14
|
+
'FORCE_COLOR',
|
|
15
|
+
'HOME',
|
|
16
|
+
'LANG',
|
|
17
|
+
'LOGNAME',
|
|
18
|
+
'NO_COLOR',
|
|
19
|
+
'PATH',
|
|
20
|
+
'SHELL',
|
|
21
|
+
'TEMP',
|
|
22
|
+
'TERM',
|
|
23
|
+
'TMP',
|
|
24
|
+
'TMPDIR',
|
|
25
|
+
'USER',
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
const SHARED_ENV_ALLOWLIST_KEY = 'MY_PI_CHILD_ENV_ALLOWLIST';
|
|
29
|
+
|
|
30
|
+
const PROFILE_ENV_ALLOWLIST_KEYS: Record<ChildEnvProfile, string> = {
|
|
31
|
+
mcp: 'MY_PI_MCP_ENV_ALLOWLIST',
|
|
32
|
+
lsp: 'MY_PI_LSP_ENV_ALLOWLIST',
|
|
33
|
+
hooks: 'MY_PI_HOOKS_ENV_ALLOWLIST',
|
|
34
|
+
'team-mode': 'MY_PI_TEAM_MODE_ENV_ALLOWLIST',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function create_child_process_env(
|
|
38
|
+
options: CreateChildProcessEnvOptions = {},
|
|
39
|
+
): NodeJS.ProcessEnv {
|
|
40
|
+
const source_env = options.source_env ?? process.env;
|
|
41
|
+
const env: NodeJS.ProcessEnv = {};
|
|
42
|
+
const allowed_keys = new Set(BASE_CHILD_ENV_KEYS);
|
|
43
|
+
|
|
44
|
+
for (const key of Object.keys(source_env)) {
|
|
45
|
+
if (key.startsWith('LC_')) allowed_keys.add(key);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const key of options.extra_allowed_keys ?? []) {
|
|
49
|
+
if (key.trim()) allowed_keys.add(key.trim());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const allowlist_env_keys = [
|
|
53
|
+
SHARED_ENV_ALLOWLIST_KEY,
|
|
54
|
+
...(options.profile
|
|
55
|
+
? [PROFILE_ENV_ALLOWLIST_KEYS[options.profile]]
|
|
56
|
+
: []),
|
|
57
|
+
...(options.extra_allowlist_env_keys ?? []),
|
|
58
|
+
];
|
|
59
|
+
for (const allowlist_key of allowlist_env_keys) {
|
|
60
|
+
for (const key of parse_env_allowlist(
|
|
61
|
+
source_env[allowlist_key],
|
|
62
|
+
)) {
|
|
63
|
+
allowed_keys.add(key);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const key of allowed_keys) {
|
|
68
|
+
const value = source_env[key];
|
|
69
|
+
if (typeof value === 'string') env[key] = value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const [key, value] of Object.entries(
|
|
73
|
+
options.explicit_env ?? {},
|
|
74
|
+
)) {
|
|
75
|
+
if (typeof value === 'string') env[key] = value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return env;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parse_env_allowlist(value: string | undefined): string[] {
|
|
82
|
+
if (!value) return [];
|
|
83
|
+
return value
|
|
84
|
+
.split(',')
|
|
85
|
+
.map((key) => key.trim())
|
|
86
|
+
.filter(Boolean);
|
|
87
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "nodenext",
|
|
5
|
+
"moduleResolution": "nodenext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"types": ["node", "vitest/globals"]
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["node_modules"]
|
|
14
|
+
}
|