opencode-dotenv 0.2.0 → 0.3.2
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/README.md +27 -160
- package/dist/index.js +146 -43
- package/package.json +20 -2
package/README.md
CHANGED
|
@@ -2,28 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
OpenCode plugin to load `.env` files at startup.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Setup
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Load `.env` from current working directory (optional)
|
|
9
|
-
- Override existing environment variables (later files override earlier ones)
|
|
10
|
-
- Configurable logging to `/tmp/opencode-dotenv.log` (enabled by default)
|
|
11
|
-
- Prevents double loading with load guard
|
|
12
|
-
- JSONC config file format (supports comments and trailing commas)
|
|
13
|
-
- **Requires Bun runtime**
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
Add to your `opencode.jsonc`:
|
|
18
|
-
|
|
19
|
-
```jsonc
|
|
20
|
-
{
|
|
21
|
-
"$schema": "https://opencode.ai/config.json",
|
|
22
|
-
"plugin": ["file:./plugins/opencode-dotenv"]
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
After publishing to npm, you can use:
|
|
7
|
+
Add to `~/.config/opencode/opencode.jsonc`:
|
|
27
8
|
|
|
28
9
|
```jsonc
|
|
29
10
|
{
|
|
@@ -31,165 +12,51 @@ After publishing to npm, you can use:
|
|
|
31
12
|
}
|
|
32
13
|
```
|
|
33
14
|
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
Create `opencode-dotenv.jsonc` in one of these locations:
|
|
37
|
-
|
|
38
|
-
1. `~/.config/opencode/opencode-dotenv.jsonc` (recommended, global config)
|
|
39
|
-
2. `./opencode-dotenv.jsonc` in current working directory (project-specific)
|
|
40
|
-
|
|
41
|
-
**Note:** Config files are loaded in the order above; the first found file is used.
|
|
42
|
-
|
|
43
|
-
### Config Schema
|
|
44
|
-
|
|
45
|
-
Config file uses **JSONC format** (JSON with Comments), which supports:
|
|
46
|
-
- `//` single-line comments
|
|
47
|
-
- `/* */` multi-line comments
|
|
48
|
-
- Trailing commas
|
|
49
|
-
- Trailing spaces
|
|
50
|
-
|
|
51
|
-
```jsonc
|
|
52
|
-
{
|
|
53
|
-
"files": [
|
|
54
|
-
"~/.config/opencode/.env",
|
|
55
|
-
"~/a/.env"
|
|
56
|
-
],
|
|
57
|
-
"load_cwd_env": true,
|
|
58
|
-
"logging": {
|
|
59
|
-
"enabled": true
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
**Fields:**
|
|
65
|
-
- `files` (array, optional): List of `.env` file paths to load in order. Later files override earlier ones.
|
|
66
|
-
- `load_cwd_env` (boolean, optional): Whether to load `.env` from the directory where OpenCode is opened. Defaults to `true`.
|
|
67
|
-
- `logging.enabled` (boolean, optional): Enable/disable logging to `/tmp/opencode-dotenv.log`. Defaults to `true`.
|
|
68
|
-
|
|
69
|
-
**Notes:**
|
|
70
|
-
- Use `~` for home directory (automatically expanded)
|
|
71
|
-
- Paths are expanded before loading
|
|
72
|
-
- If no config file exists, only loads `./.env` from cwd (if present)
|
|
73
|
-
- Logging writes to `/tmp/opencode-dotenv.log` for debugging
|
|
74
|
-
|
|
75
|
-
### Load Order
|
|
76
|
-
|
|
77
|
-
1. Files listed in `config.files` array (in order, later files override earlier ones)
|
|
78
|
-
2. `.env` from current working directory (if `load_cwd_env: true`)
|
|
15
|
+
## Config
|
|
79
16
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
## Usage Examples
|
|
83
|
-
|
|
84
|
-
### Load global and project-specific .env files
|
|
85
|
-
|
|
86
|
-
Config (`~/.config/opencode/opencode-dotenv.jsonc`):
|
|
17
|
+
Create `~/.config/opencode/opencode-dotenv.jsonc`:
|
|
87
18
|
|
|
88
19
|
```jsonc
|
|
89
20
|
{
|
|
90
|
-
"files": [
|
|
91
|
-
"~/.config/opencode/.env"
|
|
92
|
-
],
|
|
21
|
+
"files": ["~/.config/opencode/.env"],
|
|
93
22
|
"load_cwd_env": true,
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Result:
|
|
101
|
-
1. Loads `~/.config/opencode/.env`
|
|
102
|
-
2. Loads `./.env` from cwd (overrides any conflicts)
|
|
103
|
-
3. Logs all activity to `/tmp/opencode-dotenv.log`
|
|
104
|
-
|
|
105
|
-
### Load multiple global files without cwd .env
|
|
106
|
-
|
|
107
|
-
Config (`~/.config/opencode/opencode-dotenv.jsonc`):
|
|
108
|
-
|
|
109
|
-
```jsonc
|
|
110
|
-
{
|
|
111
|
-
"files": [
|
|
112
|
-
"~/.config/opencode/.env",
|
|
113
|
-
"~/a/.env"
|
|
114
|
-
],
|
|
115
|
-
"load_cwd_env": false,
|
|
116
|
-
"logging": {
|
|
117
|
-
"enabled": false
|
|
118
|
-
}
|
|
23
|
+
"prefix": "", // or "MYAPP_"
|
|
24
|
+
"logging": { "enabled": true }
|
|
119
25
|
}
|
|
120
26
|
```
|
|
121
27
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
### Example .env files
|
|
28
|
+
| Option | Default | Description |
|
|
29
|
+
|--------|---------|-------------|
|
|
30
|
+
| `files` | `[]` | `.env` files to load (later overrides earlier) |
|
|
31
|
+
| `load_cwd_env` | `true` | Load `.env` from cwd |
|
|
32
|
+
| `prefix` | `""` | Prefix for all variable names |
|
|
33
|
+
| `logging.enabled` | `true` | Log to `/tmp/opencode-dotenv.log` |
|
|
129
34
|
|
|
130
|
-
|
|
35
|
+
## .env Format
|
|
131
36
|
|
|
132
37
|
```bash
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
38
|
+
KEY=value
|
|
39
|
+
export EXPORTED=value
|
|
40
|
+
QUOTED="with spaces"
|
|
41
|
+
SINGLE='literal'
|
|
42
|
+
MULTILINE=first\
|
|
43
|
+
second
|
|
44
|
+
INLINE=value # comment stripped
|
|
45
|
+
ESCAPES="line1\nline2\ttab"
|
|
137
46
|
```
|
|
138
47
|
|
|
139
|
-
|
|
48
|
+
## Security
|
|
140
49
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
PROJECT_API_KEY=project_specific_key
|
|
145
|
-
```
|
|
50
|
+
- Paths restricted to `$HOME` or cwd
|
|
51
|
+
- Path traversal rejected
|
|
52
|
+
- Keys validated: `^[a-zA-Z_][a-zA-Z0-9_]*$`
|
|
146
53
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
### Logging
|
|
150
|
-
|
|
151
|
-
View plugin activity logs:
|
|
54
|
+
## Debug
|
|
152
55
|
|
|
153
56
|
```bash
|
|
154
57
|
tail -f /tmp/opencode-dotenv.log
|
|
155
58
|
```
|
|
156
59
|
|
|
157
|
-
Disable logging in config:
|
|
158
|
-
|
|
159
|
-
```jsonc
|
|
160
|
-
{
|
|
161
|
-
"files": ["~/.config/opencode/.env"],
|
|
162
|
-
"logging": {
|
|
163
|
-
"enabled": false
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## Development
|
|
169
|
-
|
|
170
|
-
### Plugin structure
|
|
171
|
-
|
|
172
|
-
```
|
|
173
|
-
opencode-dotenv/
|
|
174
|
-
├── package.json
|
|
175
|
-
├── src/
|
|
176
|
-
│ └── index.ts
|
|
177
|
-
└── dist/
|
|
178
|
-
└── index.js (built)
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### Build
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
bun run build
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Publish
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
npm publish
|
|
191
|
-
```
|
|
192
|
-
|
|
193
60
|
## License
|
|
194
61
|
|
|
195
62
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// src/index.ts
|
|
3
|
-
import { homedir } from "os";
|
|
4
|
-
|
|
5
2
|
// node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
6
3
|
function createScanner(text, ignoreTrivia = false) {
|
|
7
4
|
const len = text.length;
|
|
@@ -807,114 +804,220 @@ var ParseErrorCode;
|
|
|
807
804
|
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
808
805
|
|
|
809
806
|
// src/index.ts
|
|
807
|
+
import { resolve, normalize } from "path";
|
|
808
|
+
import { homedir as osHomedir } from "os";
|
|
810
809
|
var LOG_FILE = "/tmp/opencode-dotenv.log";
|
|
811
810
|
var LOAD_GUARD = "__opencodeDotenvLoaded";
|
|
811
|
+
var VALID_ENV_KEY = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
812
|
+
function getHomeDir() {
|
|
813
|
+
return process.env.HOME ?? osHomedir();
|
|
814
|
+
}
|
|
812
815
|
function parseDotenv(content) {
|
|
813
816
|
const result = {};
|
|
814
|
-
|
|
815
|
-
`)
|
|
816
|
-
|
|
817
|
-
|
|
817
|
+
const lines = content.split(`
|
|
818
|
+
`);
|
|
819
|
+
let i = 0;
|
|
820
|
+
while (i < lines.length) {
|
|
821
|
+
let line = lines[i].trim();
|
|
822
|
+
i++;
|
|
823
|
+
if (!line || line.startsWith("#"))
|
|
818
824
|
continue;
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
825
|
+
while (line.endsWith("\\") && i < lines.length) {
|
|
826
|
+
line = line.slice(0, -1) + lines[i];
|
|
827
|
+
i++;
|
|
828
|
+
}
|
|
829
|
+
const exportMatch = line.match(/^export\s+(.*)$/);
|
|
830
|
+
if (exportMatch) {
|
|
831
|
+
line = exportMatch[1];
|
|
832
|
+
}
|
|
833
|
+
const eqIndex = line.indexOf("=");
|
|
834
|
+
if (eqIndex === -1)
|
|
835
|
+
continue;
|
|
836
|
+
const key = line.substring(0, eqIndex).trim();
|
|
837
|
+
const value = parseValue(line.substring(eqIndex + 1));
|
|
838
|
+
if (key && isValidEnvKey(key)) {
|
|
839
|
+
result[key] = value;
|
|
828
840
|
}
|
|
829
841
|
}
|
|
830
842
|
return result;
|
|
831
843
|
}
|
|
832
|
-
function
|
|
833
|
-
|
|
844
|
+
function parseValue(raw) {
|
|
845
|
+
let value = raw.trim();
|
|
846
|
+
if (value.startsWith('"')) {
|
|
847
|
+
const endQuote = findClosingQuote(value, '"');
|
|
848
|
+
if (endQuote !== -1) {
|
|
849
|
+
value = value.substring(1, endQuote);
|
|
850
|
+
return value.replace(/\\n/g, `
|
|
851
|
+
`).replace(/\\r/g, "\r").replace(/\\t/g, "\t").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
852
|
+
}
|
|
853
|
+
return value;
|
|
854
|
+
}
|
|
855
|
+
if (value.startsWith("'")) {
|
|
856
|
+
const endQuote = findClosingQuote(value, "'");
|
|
857
|
+
if (endQuote !== -1) {
|
|
858
|
+
return value.substring(1, endQuote);
|
|
859
|
+
}
|
|
860
|
+
return value;
|
|
861
|
+
}
|
|
862
|
+
const inlineCommentIndex = value.indexOf(" #");
|
|
863
|
+
if (inlineCommentIndex !== -1) {
|
|
864
|
+
value = value.substring(0, inlineCommentIndex);
|
|
865
|
+
}
|
|
866
|
+
return value.trim();
|
|
867
|
+
}
|
|
868
|
+
function findClosingQuote(str, quote) {
|
|
869
|
+
let i = 1;
|
|
870
|
+
while (i < str.length) {
|
|
871
|
+
if (str[i] === "\\" && i + 1 < str.length) {
|
|
872
|
+
i += 2;
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
if (str[i] === quote) {
|
|
876
|
+
return i;
|
|
877
|
+
}
|
|
878
|
+
i++;
|
|
879
|
+
}
|
|
880
|
+
return -1;
|
|
881
|
+
}
|
|
882
|
+
function isValidEnvKey(key) {
|
|
883
|
+
return VALID_ENV_KEY.test(key);
|
|
884
|
+
}
|
|
885
|
+
function expandPath(rawPath) {
|
|
886
|
+
if (typeof rawPath !== "string") {
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
const home = getHomeDir();
|
|
890
|
+
const expanded = rawPath.replace(/^~/, home);
|
|
891
|
+
const resolved = resolve(expanded);
|
|
892
|
+
const normalized = normalize(resolved);
|
|
893
|
+
const cwd = process.cwd();
|
|
894
|
+
const isWithinAllowedDirectory = normalized.startsWith(home) || normalized.startsWith(cwd);
|
|
895
|
+
return isWithinAllowedDirectory ? normalized : null;
|
|
834
896
|
}
|
|
835
897
|
var loggingEnabled = true;
|
|
898
|
+
var logBuffer = [];
|
|
899
|
+
var flushScheduled = false;
|
|
836
900
|
function logToFile(message) {
|
|
837
901
|
if (!loggingEnabled)
|
|
838
902
|
return;
|
|
903
|
+
const timestamp = new Date().toISOString();
|
|
904
|
+
logBuffer.push(`[${timestamp}] ${message}`);
|
|
905
|
+
if (!flushScheduled) {
|
|
906
|
+
flushScheduled = true;
|
|
907
|
+
queueMicrotask(flushLogs);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
async function flushLogs() {
|
|
911
|
+
if (logBuffer.length === 0) {
|
|
912
|
+
flushScheduled = false;
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const messages = logBuffer.join(`
|
|
916
|
+
`) + `
|
|
917
|
+
`;
|
|
918
|
+
logBuffer = [];
|
|
919
|
+
flushScheduled = false;
|
|
839
920
|
try {
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
} catch
|
|
921
|
+
const file = Bun.file(LOG_FILE);
|
|
922
|
+
const existing = await file.exists() ? await file.text() : "";
|
|
923
|
+
await Bun.write(LOG_FILE, existing + messages);
|
|
924
|
+
} catch {
|
|
925
|
+
loggingEnabled = false;
|
|
926
|
+
}
|
|
844
927
|
}
|
|
845
928
|
async function loadConfig() {
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
for (const configPath of configPaths) {
|
|
851
|
-
try {
|
|
852
|
-
const file = Bun.file(configPath);
|
|
853
|
-
if (!await file.exists())
|
|
854
|
-
continue;
|
|
929
|
+
const configPath = `${getHomeDir()}/.config/opencode/opencode-dotenv.jsonc`;
|
|
930
|
+
try {
|
|
931
|
+
const file = Bun.file(configPath);
|
|
932
|
+
if (await file.exists()) {
|
|
855
933
|
const content = await file.text();
|
|
856
|
-
const config = parse2(content, [], {
|
|
934
|
+
const config = parse2(content, [], {
|
|
935
|
+
allowTrailingComma: true
|
|
936
|
+
});
|
|
857
937
|
loggingEnabled = config.logging?.enabled !== false;
|
|
858
938
|
return config;
|
|
859
|
-
} catch (e) {
|
|
860
|
-
logToFile(`Failed to load config: ${e}`);
|
|
861
939
|
}
|
|
940
|
+
} catch (e) {
|
|
941
|
+
logToFile(`Failed to load config: ${e}`);
|
|
862
942
|
}
|
|
863
943
|
return { files: [], load_cwd_env: true };
|
|
864
944
|
}
|
|
865
|
-
async function loadDotenvFile(filePath) {
|
|
945
|
+
async function loadDotenvFile(filePath, prefix) {
|
|
946
|
+
const skipped = [];
|
|
866
947
|
try {
|
|
867
948
|
const file = Bun.file(filePath);
|
|
868
949
|
if (!await file.exists()) {
|
|
869
950
|
logToFile(`File not found: ${filePath}`);
|
|
870
|
-
return { count: 0, success: false };
|
|
951
|
+
return { count: 0, success: false, skipped };
|
|
871
952
|
}
|
|
872
953
|
const content = await file.text();
|
|
873
954
|
const envVars = parseDotenv(content);
|
|
955
|
+
let count = 0;
|
|
874
956
|
for (const [key, value] of Object.entries(envVars)) {
|
|
875
|
-
|
|
957
|
+
if (!isValidEnvKey(key)) {
|
|
958
|
+
skipped.push(key);
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
const envKey = prefix ? `${prefix}${key}` : key;
|
|
962
|
+
process.env[envKey] = value;
|
|
963
|
+
count++;
|
|
876
964
|
}
|
|
877
|
-
return { count
|
|
965
|
+
return { count, success: true, skipped };
|
|
878
966
|
} catch (error) {
|
|
879
967
|
logToFile(`Failed to load ${filePath}: ${error}`);
|
|
880
|
-
return { count: 0, success: false };
|
|
968
|
+
return { count: 0, success: false, skipped };
|
|
881
969
|
}
|
|
882
970
|
}
|
|
883
|
-
var DotEnvPlugin = async (
|
|
971
|
+
var DotEnvPlugin = async () => {
|
|
884
972
|
if (globalThis[LOAD_GUARD]) {
|
|
885
973
|
return {};
|
|
886
974
|
}
|
|
887
975
|
globalThis[LOAD_GUARD] = true;
|
|
888
976
|
logToFile("Plugin started");
|
|
889
977
|
const config = await loadConfig();
|
|
890
|
-
logToFile(`Config loaded: ${config.files.length} files, load_cwd_env=${config.load_cwd_env}, logging=${loggingEnabled}`);
|
|
978
|
+
logToFile(`Config loaded: ${config.files.length} files, load_cwd_env=${config.load_cwd_env}, prefix=${config.prefix ?? "(none)"}, logging=${loggingEnabled}`);
|
|
891
979
|
let totalFiles = 0;
|
|
892
980
|
let totalVars = 0;
|
|
893
981
|
for (const rawPath of config.files) {
|
|
894
982
|
const filePath = expandPath(rawPath);
|
|
983
|
+
if (!filePath) {
|
|
984
|
+
logToFile(`SECURITY: Rejected path outside allowed directories: ${rawPath}`);
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
895
987
|
logToFile(`Loading: ${filePath}`);
|
|
896
|
-
const result = await loadDotenvFile(filePath);
|
|
988
|
+
const result = await loadDotenvFile(filePath, config.prefix);
|
|
897
989
|
if (result.success) {
|
|
898
990
|
totalFiles++;
|
|
899
991
|
totalVars += result.count;
|
|
900
992
|
logToFile(`Loaded ${result.count} vars`);
|
|
993
|
+
if (result.skipped.length > 0) {
|
|
994
|
+
logToFile(`Skipped invalid keys: ${result.skipped.join(", ")}`);
|
|
995
|
+
}
|
|
901
996
|
}
|
|
902
997
|
}
|
|
903
998
|
if (config.load_cwd_env !== false) {
|
|
904
999
|
const cwdEnvPath = `${process.cwd()}/.env`;
|
|
905
1000
|
logToFile(`Loading cwd: ${cwdEnvPath}`);
|
|
906
|
-
const result = await loadDotenvFile(cwdEnvPath);
|
|
1001
|
+
const result = await loadDotenvFile(cwdEnvPath, config.prefix);
|
|
907
1002
|
if (result.success) {
|
|
908
1003
|
totalFiles++;
|
|
909
1004
|
totalVars += result.count;
|
|
910
1005
|
logToFile(`Loaded ${result.count} vars from cwd`);
|
|
1006
|
+
if (result.skipped.length > 0) {
|
|
1007
|
+
logToFile(`Skipped invalid keys: ${result.skipped.join(", ")}`);
|
|
1008
|
+
}
|
|
911
1009
|
}
|
|
912
1010
|
}
|
|
913
1011
|
logToFile(`Plugin finished: ${totalFiles} files, ${totalVars} vars`);
|
|
1012
|
+
await flushLogs();
|
|
914
1013
|
return {};
|
|
915
1014
|
};
|
|
916
1015
|
var src_default = DotEnvPlugin;
|
|
917
1016
|
export {
|
|
1017
|
+
parseValue,
|
|
1018
|
+
parseDotenv,
|
|
1019
|
+
isValidEnvKey,
|
|
1020
|
+
expandPath,
|
|
918
1021
|
src_default as default,
|
|
919
1022
|
DotEnvPlugin
|
|
920
1023
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-dotenv",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "OpenCode plugin to load .env files at startup",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/assagman/opencode-dotenv.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/assagman/opencode-dotenv/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"opencode",
|
|
17
|
+
"plugin",
|
|
18
|
+
"dotenv",
|
|
19
|
+
"env",
|
|
20
|
+
"environment",
|
|
21
|
+
"variables"
|
|
22
|
+
],
|
|
8
23
|
"scripts": {
|
|
9
24
|
"build": "bun build src/index.ts --outdir dist --target bun",
|
|
25
|
+
"test": "bun test",
|
|
10
26
|
"prepublishOnly": "bun run build"
|
|
11
27
|
},
|
|
12
28
|
"files": [
|
|
@@ -20,5 +36,7 @@
|
|
|
20
36
|
"dependencies": {
|
|
21
37
|
"jsonc-parser": "^3.3.1"
|
|
22
38
|
},
|
|
23
|
-
"devDependencies": {
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/bun": "^1.2.4"
|
|
41
|
+
}
|
|
24
42
|
}
|