@nodetool-ai/config 0.7.0-rc.22 → 0.8.1
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 +50 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/__tests__/credit-policy.test.d.ts +2 -0
- package/dist/__tests__/credit-policy.test.d.ts.map +1 -0
- package/dist/__tests__/credit-policy.test.js +48 -0
- package/dist/__tests__/credit-policy.test.js.map +1 -0
- package/dist/__tests__/env-file.test.d.ts +2 -0
- package/dist/__tests__/env-file.test.d.ts.map +1 -0
- package/dist/__tests__/env-file.test.js +100 -0
- package/dist/__tests__/env-file.test.js.map +1 -0
- package/dist/__tests__/google-workspace.test.d.ts +2 -0
- package/dist/__tests__/google-workspace.test.d.ts.map +1 -0
- package/dist/__tests__/google-workspace.test.js +40 -0
- package/dist/__tests__/google-workspace.test.js.map +1 -0
- package/dist/__tests__/retention.test.d.ts +2 -0
- package/dist/__tests__/retention.test.d.ts.map +1 -0
- package/dist/__tests__/retention.test.js +21 -0
- package/dist/__tests__/retention.test.js.map +1 -0
- package/dist/byte-limits.d.ts +13 -0
- package/dist/byte-limits.d.ts.map +1 -0
- package/dist/byte-limits.js +28 -0
- package/dist/byte-limits.js.map +1 -0
- package/dist/credit-policy.d.ts +25 -0
- package/dist/credit-policy.d.ts.map +1 -0
- package/dist/credit-policy.js +63 -0
- package/dist/credit-policy.js.map +1 -0
- package/dist/deployment.d.ts +8 -0
- package/dist/deployment.d.ts.map +1 -0
- package/dist/deployment.js +19 -0
- package/dist/deployment.js.map +1 -0
- package/dist/env-file.d.ts +33 -0
- package/dist/env-file.d.ts.map +1 -0
- package/dist/env-file.js +83 -0
- package/dist/env-file.js.map +1 -0
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +20 -17
- package/dist/environment.js.map +1 -1
- package/dist/google-workspace.d.ts +3 -0
- package/dist/google-workspace.d.ts.map +1 -0
- package/dist/google-workspace.js +23 -0
- package/dist/google-workspace.js.map +1 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/logging.d.ts.map +1 -1
- package/dist/logging.js +46 -28
- package/dist/logging.js.map +1 -1
- package/dist/node-import.d.ts +37 -0
- package/dist/node-import.d.ts.map +1 -0
- package/dist/node-import.js +119 -0
- package/dist/node-import.js.map +1 -0
- package/dist/optional-modules.d.ts +8 -0
- package/dist/optional-modules.d.ts.map +1 -0
- package/dist/optional-modules.js +42 -0
- package/dist/optional-modules.js.map +1 -0
- package/dist/package-asset-registry.d.ts +102 -0
- package/dist/package-asset-registry.d.ts.map +1 -0
- package/dist/package-asset-registry.js +154 -0
- package/dist/package-asset-registry.js.map +1 -0
- package/dist/package-assets.d.ts +52 -0
- package/dist/package-assets.d.ts.map +1 -0
- package/dist/package-assets.js +98 -0
- package/dist/package-assets.js.map +1 -0
- package/dist/paths.d.ts +52 -23
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +166 -47
- package/dist/paths.js.map +1 -1
- package/dist/retention.d.ts +3 -0
- package/dist/retention.d.ts.map +1 -0
- package/dist/retention.js +19 -0
- package/dist/retention.js.map +1 -0
- package/dist/setting-catalog.d.ts +28 -0
- package/dist/setting-catalog.d.ts.map +1 -0
- package/dist/setting-catalog.js +161 -0
- package/dist/setting-catalog.js.map +1 -0
- package/dist/storage-config.d.ts +45 -0
- package/dist/storage-config.d.ts.map +1 -0
- package/dist/storage-config.js +62 -0
- package/dist/storage-config.js.map +1 -0
- package/package.json +23 -8
- package/dist/diagnostics.d.ts +0 -27
- package/dist/diagnostics.d.ts.map +0 -1
- package/dist/diagnostics.js +0 -42
- package/dist/diagnostics.js.map +0 -1
- package/dist/settings.d.ts +0 -29
- package/dist/settings.d.ts.map +0 -1
- package/dist/settings.js +0 -29
- package/dist/settings.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @nodetool-ai/config
|
|
2
|
+
|
|
3
|
+
Configuration and environment loading for [NodeTool](https://nodetool.ai) — settings, paths, logging, byte limits, and cross-runtime module loading.
|
|
4
|
+
|
|
5
|
+
This is the base dependency for the backend: it loads and reads environment variables, resolves data/asset/database paths, registers typed settings, configures logging, and diagnoses the running environment. It also provides cross-runtime helpers for importing Node built-ins and optional modules from code that also runs in the browser.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @nodetool-ai/config
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Exported symbols
|
|
14
|
+
|
|
15
|
+
| Symbol | Kind | Description |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `loadEnvironment` / `resetEnvironment` | function | Load and reset the process environment (dotenv) |
|
|
18
|
+
| `getEnv` / `requireEnv` | function | Read an env var, optionally throwing if missing |
|
|
19
|
+
| `getByteLimitEnv` | function | Parse a byte-size limit from an env var |
|
|
20
|
+
| `settingCatalog` / `settingDefinition` | function | Read the catalog of every configuration knob NodeTool ships |
|
|
21
|
+
| `SettingCatalogEntry` | type | One catalog definition: env var, group, description, `isSecret` |
|
|
22
|
+
| `configureLogging` / `getLogLevel` / `createLogger` | function | Configure logging and create named loggers |
|
|
23
|
+
| `LogLevel` / `LoggingOptions` / `Logger` | type | Logging types |
|
|
24
|
+
| `getNodetoolDataDir` / `getDefaultDbPath` / `getDefaultAssetsPath` | function | Resolve standard data, database, and asset paths |
|
|
25
|
+
| `getPostgresDatabaseUrl` / `getDefaultVectorstoreDbPath` | function | Resolve Postgres and vectorstore locations |
|
|
26
|
+
| `getAssetFilePath` / `buildAssetUrl` | function | Map asset keys to file paths and URLs |
|
|
27
|
+
| `loadAssetStorageConfig` / `loadTempStorageConfig` | function | Load storage configuration from the environment |
|
|
28
|
+
| `StorageConfig` / `SIGNED_URL_TTL` | type / const | Storage config shape and signed-URL lifetime |
|
|
29
|
+
| `IS_NODE` / `importNodeBuiltin` / `importHidden` / `importOptionalModule` | const / function | Cross-runtime module loading helpers |
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {
|
|
35
|
+
loadEnvironment,
|
|
36
|
+
requireEnv,
|
|
37
|
+
createLogger,
|
|
38
|
+
getDefaultDbPath
|
|
39
|
+
} from "@nodetool-ai/config";
|
|
40
|
+
|
|
41
|
+
loadEnvironment();
|
|
42
|
+
const log = createLogger("server");
|
|
43
|
+
log.info("db path", getDefaultDbPath());
|
|
44
|
+
const token = requireEnv("NODETOOL_TOKEN");
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Links
|
|
48
|
+
|
|
49
|
+
- [NodeTool](https://nodetool.ai)
|
|
50
|
+
- [GitHub](https://github.com/nodetool-ai/nodetool)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2026-09-28T09:19:01.424Z
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credit-policy.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/credit-policy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { CREDIT_MODELS_ENV, DEFAULT_SIGNUP_CREDITS, SIGNUP_CREDITS_ENV, creditModelAllowlist, isCreditModelAllowed, signupGrantCredits } from "../credit-policy.js";
|
|
3
|
+
const env = (value) => value;
|
|
4
|
+
describe("creditModelAllowlist", () => {
|
|
5
|
+
it("is null when the operator restricted nothing — the whole catalog", () => {
|
|
6
|
+
expect(creditModelAllowlist({})).toBeNull();
|
|
7
|
+
expect(creditModelAllowlist(env({ [CREDIT_MODELS_ENV]: " " }))).toBeNull();
|
|
8
|
+
expect(creditModelAllowlist(env({ [CREDIT_MODELS_ENV]: ", ," }))).toBeNull();
|
|
9
|
+
});
|
|
10
|
+
it("splits on commas, spaces, and newlines", () => {
|
|
11
|
+
const allowed = creditModelAllowlist(env({
|
|
12
|
+
[CREDIT_MODELS_ENV]: "nodetool/flux-schnell, nodetool/kokoro\n nodetool/hailuo-fast"
|
|
13
|
+
}));
|
|
14
|
+
expect([...allowed].sort()).toEqual([
|
|
15
|
+
"nodetool/flux-schnell",
|
|
16
|
+
"nodetool/hailuo-fast",
|
|
17
|
+
"nodetool/kokoro"
|
|
18
|
+
]);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe("isCreditModelAllowed", () => {
|
|
22
|
+
it("allows everything when nothing is whitelisted", () => {
|
|
23
|
+
expect(isCreditModelAllowed("nodetool/seedream", {})).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it("allows only what the whitelist names", () => {
|
|
26
|
+
const configured = env({
|
|
27
|
+
[CREDIT_MODELS_ENV]: "nodetool/flux-schnell,nodetool/kokoro"
|
|
28
|
+
});
|
|
29
|
+
expect(isCreditModelAllowed("nodetool/flux-schnell", configured)).toBe(true);
|
|
30
|
+
expect(isCreditModelAllowed("nodetool/seedream", configured)).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("signupGrantCredits", () => {
|
|
34
|
+
it("defaults when unset or blank", () => {
|
|
35
|
+
expect(signupGrantCredits({})).toBe(DEFAULT_SIGNUP_CREDITS);
|
|
36
|
+
expect(signupGrantCredits(env({ [SIGNUP_CREDITS_ENV]: " " }))).toBe(DEFAULT_SIGNUP_CREDITS);
|
|
37
|
+
});
|
|
38
|
+
it("reads a configured amount, floored to whole credits", () => {
|
|
39
|
+
expect(signupGrantCredits(env({ [SIGNUP_CREDITS_ENV]: "1200" }))).toBe(1200);
|
|
40
|
+
expect(signupGrantCredits(env({ [SIGNUP_CREDITS_ENV]: "12.9" }))).toBe(12);
|
|
41
|
+
});
|
|
42
|
+
it("treats zero, negatives, and junk as no welcome grant", () => {
|
|
43
|
+
for (const raw of ["0", "-5", "lots"]) {
|
|
44
|
+
expect(signupGrantCredits(env({ [SIGNUP_CREDITS_ENV]: raw }))).toBe(0);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=credit-policy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credit-policy.test.js","sourceRoot":"","sources":["../../src/__tests__/credit-policy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-file.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/env-file.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { loadEnvFile, parseEnvFile } from "../env-file.js";
|
|
7
|
+
describe("parseEnvFile", () => {
|
|
8
|
+
it("parses simple KEY=VALUE pairs", () => {
|
|
9
|
+
expect(parseEnvFile("A=1\nB=two")).toEqual({ A: "1", B: "two" });
|
|
10
|
+
});
|
|
11
|
+
it("skips blank lines and # comments", () => {
|
|
12
|
+
const input = "\n# a comment\nA=1\n\n # indented comment\nB=2\n";
|
|
13
|
+
expect(parseEnvFile(input)).toEqual({ A: "1", B: "2" });
|
|
14
|
+
});
|
|
15
|
+
it("strips an optional export prefix", () => {
|
|
16
|
+
expect(parseEnvFile("export A=1\nexport B=2")).toEqual({ A: "1", B: "2" });
|
|
17
|
+
});
|
|
18
|
+
it("trims unquoted values", () => {
|
|
19
|
+
expect(parseEnvFile("A= spaced ")).toEqual({ A: "spaced" });
|
|
20
|
+
});
|
|
21
|
+
it("keeps single-quoted values literal", () => {
|
|
22
|
+
expect(parseEnvFile("A='line\\n still'")).toEqual({ A: "line\\n still" });
|
|
23
|
+
});
|
|
24
|
+
it("expands \\n \\r \\t in double-quoted values", () => {
|
|
25
|
+
expect(parseEnvFile('A="line1\\nline2\\tend"')).toEqual({
|
|
26
|
+
A: "line1\nline2\tend"
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it("preserves surrounding whitespace inside quotes", () => {
|
|
30
|
+
expect(parseEnvFile('A=" padded "')).toEqual({ A: " padded " });
|
|
31
|
+
});
|
|
32
|
+
it("handles values containing =", () => {
|
|
33
|
+
expect(parseEnvFile("URL=postgres://u:p@h/db?a=b&c=d")).toEqual({
|
|
34
|
+
URL: "postgres://u:p@h/db?a=b&c=d"
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("strips inline comments from unquoted values", () => {
|
|
38
|
+
expect(parseEnvFile("A=bar # explanation\nB=bar#explanation")).toEqual({
|
|
39
|
+
A: "bar",
|
|
40
|
+
B: "bar"
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it("preserves hashes inside quoted values before inline comments", () => {
|
|
44
|
+
expect(parseEnvFile(`A="double # value" # comment\nB='single # value'#comment`)).toEqual({
|
|
45
|
+
A: "double # value",
|
|
46
|
+
B: "single # value"
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
it("preserves hashes after escaped quotes inside quoted values", () => {
|
|
50
|
+
expect(parseEnvFile('A="quoted \\"text\\" # value" # comment')).toEqual({
|
|
51
|
+
A: 'quoted \\"text\\" # value'
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it("treats hashes after backslashes in unquoted values as comments", () => {
|
|
55
|
+
expect(parseEnvFile("A=bar\\#comment")).toEqual({ A: "bar\\" });
|
|
56
|
+
});
|
|
57
|
+
it("ignores lines without = and empty keys", () => {
|
|
58
|
+
expect(parseEnvFile("NOTAKEY\n=value\nA=1")).toEqual({ A: "1" });
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe("loadEnvFile", () => {
|
|
62
|
+
let dir;
|
|
63
|
+
const created = [];
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
dir = mkdtempSync(join(tmpdir(), "envfile-"));
|
|
66
|
+
});
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
for (const key of created)
|
|
69
|
+
delete process.env[key];
|
|
70
|
+
created.length = 0;
|
|
71
|
+
rmSync(dir, { recursive: true, force: true });
|
|
72
|
+
});
|
|
73
|
+
const write = (name, content) => {
|
|
74
|
+
const file = join(dir, name);
|
|
75
|
+
writeFileSync(file, content);
|
|
76
|
+
return file;
|
|
77
|
+
};
|
|
78
|
+
it("applies pairs to process.env", () => {
|
|
79
|
+
created.push("ENVFILE_TEST_A");
|
|
80
|
+
const file = write(".env", "ENVFILE_TEST_A=hello");
|
|
81
|
+
const parsed = loadEnvFile(fs, file);
|
|
82
|
+
expect(parsed).toEqual({ ENVFILE_TEST_A: "hello" });
|
|
83
|
+
expect(process.env.ENVFILE_TEST_A).toBe("hello");
|
|
84
|
+
});
|
|
85
|
+
it("overrides existing process.env values", () => {
|
|
86
|
+
created.push("ENVFILE_TEST_B");
|
|
87
|
+
process.env.ENVFILE_TEST_B = "first";
|
|
88
|
+
const first = write(".env", "ENVFILE_TEST_B=first-file");
|
|
89
|
+
loadEnvFile(fs, first);
|
|
90
|
+
expect(process.env.ENVFILE_TEST_B).toBe("first-file");
|
|
91
|
+
const second = write(".env.local", "ENVFILE_TEST_B=second-file");
|
|
92
|
+
loadEnvFile(fs, second);
|
|
93
|
+
expect(process.env.ENVFILE_TEST_B).toBe("second-file");
|
|
94
|
+
});
|
|
95
|
+
it("tolerates a missing file silently", () => {
|
|
96
|
+
const parsed = loadEnvFile(fs, join(dir, "does-not-exist.env"));
|
|
97
|
+
expect(parsed).toEqual({});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=env-file.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-file.test.js","sourceRoot":"","sources":["../../src/__tests__/env-file.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-workspace.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/google-workspace.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { isGoogleWorkspaceEnabled } from "../google-workspace.js";
|
|
3
|
+
const KEYS = ["SUPABASE_URL", "SUPABASE_KEY", "NODETOOL_GOOGLE_WORKSPACE"];
|
|
4
|
+
describe("isGoogleWorkspaceEnabled", () => {
|
|
5
|
+
let saved;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
saved = Object.fromEntries(KEYS.map((k) => [k, process.env[k]]));
|
|
8
|
+
for (const key of KEYS)
|
|
9
|
+
delete process.env[key];
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
for (const key of KEYS) {
|
|
13
|
+
if (saved[key] === undefined)
|
|
14
|
+
delete process.env[key];
|
|
15
|
+
else
|
|
16
|
+
process.env[key] = saved[key];
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
it("is off in local mode", () => {
|
|
20
|
+
expect(isGoogleWorkspaceEnabled()).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it("is on when Supabase auth is configured", () => {
|
|
23
|
+
process.env.SUPABASE_URL = "https://project.supabase.co";
|
|
24
|
+
process.env.SUPABASE_KEY = "service-role-key";
|
|
25
|
+
expect(isGoogleWorkspaceEnabled()).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it("stays off when only one Supabase variable is set", () => {
|
|
28
|
+
process.env.SUPABASE_URL = "https://project.supabase.co";
|
|
29
|
+
expect(isGoogleWorkspaceEnabled()).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
it("honours the explicit override in both directions", () => {
|
|
32
|
+
process.env.NODETOOL_GOOGLE_WORKSPACE = "1";
|
|
33
|
+
expect(isGoogleWorkspaceEnabled()).toBe(true);
|
|
34
|
+
process.env.SUPABASE_URL = "https://project.supabase.co";
|
|
35
|
+
process.env.SUPABASE_KEY = "service-role-key";
|
|
36
|
+
process.env.NODETOOL_GOOGLE_WORKSPACE = "0";
|
|
37
|
+
expect(isGoogleWorkspaceEnabled()).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=google-workspace.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-workspace.test.js","sourceRoot":"","sources":["../../src/__tests__/google-workspace.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,IAAI,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,2BAA2B,CAAC,CAAC;AAE3E,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,IAAI,KAAyC,CAAC;IAE9C,UAAU,CAAC,GAAG,EAAE;QACd,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjE,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;;gBACjD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,6BAA6B,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,kBAAkB,CAAC;QAC9C,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,6BAA6B,CAAC;QACzD,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,GAAG,CAAC;QAC5C,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE9C,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,6BAA6B,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,kBAAkB,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,GAAG,CAAC;QAC5C,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/retention.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { isAutomaticStorageCleanupEnabled } from "../retention.js";
|
|
3
|
+
describe("isAutomaticStorageCleanupEnabled", () => {
|
|
4
|
+
it("is off when the variable is unset", () => {
|
|
5
|
+
expect(isAutomaticStorageCleanupEnabled({})).toBe(false);
|
|
6
|
+
});
|
|
7
|
+
it("is on for 1 and true", () => {
|
|
8
|
+
expect(isAutomaticStorageCleanupEnabled({ NODETOOL_STORAGE_AUTO_CLEANUP: "1" })).toBe(true);
|
|
9
|
+
expect(isAutomaticStorageCleanupEnabled({
|
|
10
|
+
NODETOOL_STORAGE_AUTO_CLEANUP: " TRUE "
|
|
11
|
+
})).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
it("is off for 0, false, and anything else", () => {
|
|
14
|
+
for (const value of ["0", "false", "", "yes please"]) {
|
|
15
|
+
expect(isAutomaticStorageCleanupEnabled({
|
|
16
|
+
NODETOOL_STORAGE_AUTO_CLEANUP: value
|
|
17
|
+
})).toBe(false);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=retention.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention.test.js","sourceRoot":"","sources":["../../src/__tests__/retention.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AAEnE,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,gCAAgC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CACJ,gCAAgC,CAAC,EAAE,6BAA6B,EAAE,GAAG,EAAE,CAAC,CACzE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,MAAM,CACJ,gCAAgC,CAAC;YAC/B,6BAA6B,EAAE,QAAQ;SACxC,CAAC,CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,CAAC,EAAE,CAAC;YACrD,MAAM,CACJ,gCAAgC,CAAC;gBAC/B,6BAA6B,EAAE,KAAK;aACrC,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a byte-size limit from an environment variable.
|
|
3
|
+
*
|
|
4
|
+
* Returns `fallback` when the variable is unset, blank, non-numeric, or not a
|
|
5
|
+
* positive finite number. This is deliberately strict: a bad value (e.g.
|
|
6
|
+
* `"unlimited"`, `"-1"`, `"0"`) falls back to the safe default rather than
|
|
7
|
+
* resolving to `NaN`/`0` and turning the cap off.
|
|
8
|
+
*
|
|
9
|
+
* @param key Environment variable name (e.g. `NODETOOL_MAX_UPLOAD_BYTES`).
|
|
10
|
+
* @param fallback Default limit in bytes, used when the env var is invalid.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getByteLimitEnv(key: string, fallback: number): number;
|
|
13
|
+
//# sourceMappingURL=byte-limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-limits.d.ts","sourceRoot":"","sources":["../src/byte-limits.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMrE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-size limit helpers.
|
|
3
|
+
*
|
|
4
|
+
* Centralizes parsing of configurable size caps (upload size, message size,
|
|
5
|
+
* IPC frame size) so a malformed override can never silently disable a guard.
|
|
6
|
+
*/
|
|
7
|
+
import { getEnv } from "./environment.js";
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a byte-size limit from an environment variable.
|
|
10
|
+
*
|
|
11
|
+
* Returns `fallback` when the variable is unset, blank, non-numeric, or not a
|
|
12
|
+
* positive finite number. This is deliberately strict: a bad value (e.g.
|
|
13
|
+
* `"unlimited"`, `"-1"`, `"0"`) falls back to the safe default rather than
|
|
14
|
+
* resolving to `NaN`/`0` and turning the cap off.
|
|
15
|
+
*
|
|
16
|
+
* @param key Environment variable name (e.g. `NODETOOL_MAX_UPLOAD_BYTES`).
|
|
17
|
+
* @param fallback Default limit in bytes, used when the env var is invalid.
|
|
18
|
+
*/
|
|
19
|
+
export function getByteLimitEnv(key, fallback) {
|
|
20
|
+
const raw = getEnv(key);
|
|
21
|
+
if (raw === undefined || raw.trim() === "")
|
|
22
|
+
return fallback;
|
|
23
|
+
const parsed = Number(raw);
|
|
24
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
25
|
+
return fallback;
|
|
26
|
+
return Math.floor(parsed);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=byte-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-limits.js","sourceRoot":"","sources":["../src/byte-limits.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,QAAgB;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACxB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Names the managed models credits may be spent on. */
|
|
2
|
+
export declare const CREDIT_MODELS_ENV = "NODETOOL_CREDIT_MODELS";
|
|
3
|
+
/** One-time welcome grant, in credits, for a user seen for the first time. */
|
|
4
|
+
export declare const SIGNUP_CREDITS_ENV = "NODETOOL_SIGNUP_CREDITS";
|
|
5
|
+
/** Credits a new user is granted when no override is configured. */
|
|
6
|
+
export declare const DEFAULT_SIGNUP_CREDITS = 500;
|
|
7
|
+
type Env = Record<string, string | undefined>;
|
|
8
|
+
/**
|
|
9
|
+
* The configured allowlist of managed model ids, or `null` when the operator
|
|
10
|
+
* set none — `null` is "the whole catalog", not "nothing".
|
|
11
|
+
*
|
|
12
|
+
* Entries are separated by commas, whitespace, or newlines, so the variable
|
|
13
|
+
* reads the same in a `.env` file, a `fly secrets` line, and a Compose file.
|
|
14
|
+
*/
|
|
15
|
+
export declare function creditModelAllowlist(env?: Env): ReadonlySet<string> | null;
|
|
16
|
+
/** Whether `modelId` may be served by the managed provider on this server. */
|
|
17
|
+
export declare function isCreditModelAllowed(modelId: string, env?: Env): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Credits granted once, the first time a user is seen. `0` (or any negative
|
|
20
|
+
* or unparseable value) means no welcome grant — the monthly plan grant is
|
|
21
|
+
* then all a new user gets.
|
|
22
|
+
*/
|
|
23
|
+
export declare function signupGrantCredits(env?: Env): number;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=credit-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credit-policy.d.ts","sourceRoot":"","sources":["../src/credit-policy.ts"],"names":[],"mappings":"AAqBA,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAC1D,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAE5D,oEAAoE;AACpE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,GAAsB,GAC1B,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAQ5B;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,GAAsB,GAC1B,OAAO,CAGT;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,GAAsB,GAAG,MAAM,CAMtE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which managed models credits may be spent on, and what a new user starts
|
|
3
|
+
* with — the two knobs a production operator turns.
|
|
4
|
+
*
|
|
5
|
+
* NodeTool's `nodetool` provider runs curated delegates on platform-owned
|
|
6
|
+
* keys, so every call through it spends the operator's money. The operator
|
|
7
|
+
* therefore decides which of the catalog's entries are open for business:
|
|
8
|
+
* `NODETOOL_CREDIT_MODELS` names them, and anything else is refused before a
|
|
9
|
+
* key is used. Unset means the whole catalog — the right default for a
|
|
10
|
+
* staging or dev server that holds platform keys.
|
|
11
|
+
*
|
|
12
|
+
* None of this reaches a local install: `nodetool` is a cloud-only provider
|
|
13
|
+
* (`CLOUD_ONLY_PROVIDER_IDS`), unregistered off the cloud profile, so a
|
|
14
|
+
* desktop or self-hosted server has no managed provider to whitelist.
|
|
15
|
+
*
|
|
16
|
+
* Parsing lives here rather than next to the catalog because the catalog
|
|
17
|
+
* (`@nodetool-ai/protocol`) is browser-safe pure data with no environment to
|
|
18
|
+
* read. Callers resolve names against the catalog themselves.
|
|
19
|
+
*/
|
|
20
|
+
import { safeProcessEnv } from "./node-import.js";
|
|
21
|
+
/** Names the managed models credits may be spent on. */
|
|
22
|
+
export const CREDIT_MODELS_ENV = "NODETOOL_CREDIT_MODELS";
|
|
23
|
+
/** One-time welcome grant, in credits, for a user seen for the first time. */
|
|
24
|
+
export const SIGNUP_CREDITS_ENV = "NODETOOL_SIGNUP_CREDITS";
|
|
25
|
+
/** Credits a new user is granted when no override is configured. */
|
|
26
|
+
export const DEFAULT_SIGNUP_CREDITS = 500;
|
|
27
|
+
/**
|
|
28
|
+
* The configured allowlist of managed model ids, or `null` when the operator
|
|
29
|
+
* set none — `null` is "the whole catalog", not "nothing".
|
|
30
|
+
*
|
|
31
|
+
* Entries are separated by commas, whitespace, or newlines, so the variable
|
|
32
|
+
* reads the same in a `.env` file, a `fly secrets` line, and a Compose file.
|
|
33
|
+
*/
|
|
34
|
+
export function creditModelAllowlist(env = safeProcessEnv()) {
|
|
35
|
+
const raw = env[CREDIT_MODELS_ENV]?.trim();
|
|
36
|
+
if (!raw)
|
|
37
|
+
return null;
|
|
38
|
+
const ids = raw
|
|
39
|
+
.split(/[\s,]+/)
|
|
40
|
+
.map((id) => id.trim())
|
|
41
|
+
.filter((id) => id.length > 0);
|
|
42
|
+
return ids.length > 0 ? new Set(ids) : null;
|
|
43
|
+
}
|
|
44
|
+
/** Whether `modelId` may be served by the managed provider on this server. */
|
|
45
|
+
export function isCreditModelAllowed(modelId, env = safeProcessEnv()) {
|
|
46
|
+
const allowed = creditModelAllowlist(env);
|
|
47
|
+
return allowed === null || allowed.has(modelId);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Credits granted once, the first time a user is seen. `0` (or any negative
|
|
51
|
+
* or unparseable value) means no welcome grant — the monthly plan grant is
|
|
52
|
+
* then all a new user gets.
|
|
53
|
+
*/
|
|
54
|
+
export function signupGrantCredits(env = safeProcessEnv()) {
|
|
55
|
+
const raw = env[SIGNUP_CREDITS_ENV]?.trim();
|
|
56
|
+
if (raw === undefined || raw === "")
|
|
57
|
+
return DEFAULT_SIGNUP_CREDITS;
|
|
58
|
+
const parsed = Number(raw);
|
|
59
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
60
|
+
return 0;
|
|
61
|
+
return Math.floor(parsed);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=credit-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credit-policy.js","sourceRoot":"","sources":["../src/credit-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,wDAAwD;AACxD,MAAM,CAAC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AAC1D,8EAA8E;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAE5D,oEAAoE;AACpE,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAI1C;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,GAAG,GAAQ,cAAc,EAAE;IAE3B,MAAM,GAAG,GAAG,GAAG,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,GAAG,GAAG;SACZ,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;SACtB,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,GAAG,GAAQ,cAAc,EAAE;IAE3B,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAG,GAAQ,cAAc,EAAE;IAC5D,MAAM,GAAG,GAAG,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC;IAC5C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,sBAAsB,CAAC;IACnE,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when the server enforces authentication — a remote identity provider
|
|
3
|
+
* (`SUPABASE_URL` + `SUPABASE_KEY`) is configured, so every request carries a
|
|
4
|
+
* user token and the host is shared. False for a local install, where loopback
|
|
5
|
+
* is trusted and the machine belongs to the person using it.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isAuthEnforced(env?: Record<string, string | undefined>): boolean;
|
|
8
|
+
//# sourceMappingURL=deployment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../src/deployment.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAoB,GACzD,OAAO,CAET"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How this server is deployed — one answer, read from the environment.
|
|
3
|
+
*
|
|
4
|
+
* `NODE_ENV` does not answer it: the desktop backend (`electron/src/server.ts`)
|
|
5
|
+
* and the Docker image both set `NODE_ENV=production` while serving one user on
|
|
6
|
+
* their own machine. What separates a shared deployment from a local install is
|
|
7
|
+
* whether a remote identity provider is configured, so that is what this asks.
|
|
8
|
+
*/
|
|
9
|
+
import { safeProcessEnv } from "./node-import.js";
|
|
10
|
+
/**
|
|
11
|
+
* True when the server enforces authentication — a remote identity provider
|
|
12
|
+
* (`SUPABASE_URL` + `SUPABASE_KEY`) is configured, so every request carries a
|
|
13
|
+
* user token and the host is shared. False for a local install, where loopback
|
|
14
|
+
* is trusted and the machine belongs to the person using it.
|
|
15
|
+
*/
|
|
16
|
+
export function isAuthEnforced(env = safeProcessEnv()) {
|
|
17
|
+
return Boolean(env["SUPABASE_URL"]?.trim() && env["SUPABASE_KEY"]?.trim());
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=deployment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.js","sourceRoot":"","sources":["../src/deployment.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAG,GAAuC,cAAc,EAAE;IAE1D,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `.env` file parser — a drop-in for the small subset of `dotenv`
|
|
3
|
+
* we relied on. Node 22's `process.loadEnvFile()` can't override existing
|
|
4
|
+
* `process.env` values, so we parse by hand.
|
|
5
|
+
*
|
|
6
|
+
* Supported syntax (matching dotenv where it matters in practice):
|
|
7
|
+
* - `KEY=VALUE` pairs, one per line.
|
|
8
|
+
* - Blank lines and `#` comment lines are skipped.
|
|
9
|
+
* - An optional `export ` prefix on the key is stripped.
|
|
10
|
+
* - Single- or double-quoted values; double-quoted values expand `\n`,
|
|
11
|
+
* `\r`, and `\t` escapes. Single-quoted values are taken literally.
|
|
12
|
+
* - Unquoted values are trimmed, may contain `=`, and end at `#` comments.
|
|
13
|
+
* Hashes inside quoted values are preserved.
|
|
14
|
+
*
|
|
15
|
+
* Not supported (and not needed by callers): `dotenv-expand`-style
|
|
16
|
+
* `${VAR}` interpolation.
|
|
17
|
+
*/
|
|
18
|
+
/** Environment variable names to their values, as a `.env` file spells them. */
|
|
19
|
+
export type EnvPairs = Record<string, string>;
|
|
20
|
+
/** Parse the text of a `.env` file into key/value pairs. */
|
|
21
|
+
export declare function parseEnvFile(content: string): EnvPairs;
|
|
22
|
+
type FsApi = {
|
|
23
|
+
existsSync: (path: string) => boolean;
|
|
24
|
+
readFileSync: (path: string, encoding: "utf8") => string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Read a `.env` file and apply its pairs to `process.env`, overriding any
|
|
28
|
+
* existing values. Missing files are tolerated silently. Returns the parsed
|
|
29
|
+
* pairs (empty when the file is absent).
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadEnvFile(fs: FsApi, file: string): EnvPairs;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=env-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-file.d.ts","sourceRoot":"","sources":["../src/env-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAoBtD;AAoCD,KAAK,KAAK,GAAG;IACX,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAO7D"}
|
package/dist/env-file.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal `.env` file parser — a drop-in for the small subset of `dotenv`
|
|
3
|
+
* we relied on. Node 22's `process.loadEnvFile()` can't override existing
|
|
4
|
+
* `process.env` values, so we parse by hand.
|
|
5
|
+
*
|
|
6
|
+
* Supported syntax (matching dotenv where it matters in practice):
|
|
7
|
+
* - `KEY=VALUE` pairs, one per line.
|
|
8
|
+
* - Blank lines and `#` comment lines are skipped.
|
|
9
|
+
* - An optional `export ` prefix on the key is stripped.
|
|
10
|
+
* - Single- or double-quoted values; double-quoted values expand `\n`,
|
|
11
|
+
* `\r`, and `\t` escapes. Single-quoted values are taken literally.
|
|
12
|
+
* - Unquoted values are trimmed, may contain `=`, and end at `#` comments.
|
|
13
|
+
* Hashes inside quoted values are preserved.
|
|
14
|
+
*
|
|
15
|
+
* Not supported (and not needed by callers): `dotenv-expand`-style
|
|
16
|
+
* `${VAR}` interpolation.
|
|
17
|
+
*/
|
|
18
|
+
/** Parse the text of a `.env` file into key/value pairs. */
|
|
19
|
+
export function parseEnvFile(content) {
|
|
20
|
+
const pairs = [];
|
|
21
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
22
|
+
const line = rawLine.trim();
|
|
23
|
+
if (line === "" || line.startsWith("#"))
|
|
24
|
+
continue;
|
|
25
|
+
const withoutExport = line.startsWith("export ")
|
|
26
|
+
? line.slice("export ".length)
|
|
27
|
+
: line;
|
|
28
|
+
const eq = withoutExport.indexOf("=");
|
|
29
|
+
if (eq === -1)
|
|
30
|
+
continue;
|
|
31
|
+
const key = withoutExport.slice(0, eq).trim();
|
|
32
|
+
if (key === "")
|
|
33
|
+
continue;
|
|
34
|
+
const rawValue = stripInlineComment(withoutExport.slice(eq + 1));
|
|
35
|
+
pairs.push([key, unquoteValue(rawValue)]);
|
|
36
|
+
}
|
|
37
|
+
return Object.fromEntries(pairs);
|
|
38
|
+
}
|
|
39
|
+
function stripInlineComment(raw) {
|
|
40
|
+
const value = raw.trim();
|
|
41
|
+
const quote = value[0];
|
|
42
|
+
if (quote === "'" || quote === '"') {
|
|
43
|
+
for (let index = 1; index < value.length; index += 1) {
|
|
44
|
+
if (value[index] === quote && value[index - 1] !== "\\") {
|
|
45
|
+
const comment = value.indexOf("#", index + 1);
|
|
46
|
+
return comment === -1 ? value : value.slice(0, comment).trim();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const comment = value.indexOf("#");
|
|
51
|
+
return comment === -1 ? value : value.slice(0, comment).trim();
|
|
52
|
+
}
|
|
53
|
+
function unquoteValue(raw) {
|
|
54
|
+
if (raw.length >= 2) {
|
|
55
|
+
const quote = raw[0];
|
|
56
|
+
if ((quote === '"' || quote === "'") && raw[raw.length - 1] === quote) {
|
|
57
|
+
const inner = raw.slice(1, -1);
|
|
58
|
+
if (quote === '"') {
|
|
59
|
+
return inner
|
|
60
|
+
.replace(/\\n/g, "\n")
|
|
61
|
+
.replace(/\\r/g, "\r")
|
|
62
|
+
.replace(/\\t/g, "\t");
|
|
63
|
+
}
|
|
64
|
+
return inner;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return raw;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read a `.env` file and apply its pairs to `process.env`, overriding any
|
|
71
|
+
* existing values. Missing files are tolerated silently. Returns the parsed
|
|
72
|
+
* pairs (empty when the file is absent).
|
|
73
|
+
*/
|
|
74
|
+
export function loadEnvFile(fs, file) {
|
|
75
|
+
if (!fs.existsSync(file))
|
|
76
|
+
return {};
|
|
77
|
+
const parsed = parseEnvFile(fs.readFileSync(file, "utf8"));
|
|
78
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
79
|
+
process.env[key] = value;
|
|
80
|
+
}
|
|
81
|
+
return parsed;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=env-file.js.map
|