@neondatabase/env 0.13.0 → 0.13.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.
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * Resolve the Neon API key for a `neon-env` CLI invocation. Precedence (each wins over the
4
4
  * next): `--api-key` flag → `NEON_API_KEY` → `access_token` from the Neon CLI's
5
- * `credentials.json`.
5
+ * `credentials.json`, located by `@neon/config/paths`.
6
6
  *
7
7
  * The CLI owns this resolution — `@neon/config` and `@neon/env` are deliberately
8
8
  * environment- and filesystem-agnostic and only ever accept an explicit `apiKey`, so the
@@ -1,10 +1,10 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
2
+ import { resolveConfigFile } from "@neon/config/paths";
3
3
  //#region src/lib/cli/resolve-api-key.ts
4
4
  /**
5
5
  * Resolve the Neon API key for a `neon-env` CLI invocation. Precedence (each wins over the
6
6
  * next): `--api-key` flag → `NEON_API_KEY` → `access_token` from the Neon CLI's
7
- * `credentials.json`.
7
+ * `credentials.json`, located by `@neon/config/paths`.
8
8
  *
9
9
  * The CLI owns this resolution — `@neon/config` and `@neon/env` are deliberately
10
10
  * environment- and filesystem-agnostic and only ever accept an explicit `apiKey`, so the
@@ -19,18 +19,23 @@ function resolveApiKey(options) {
19
19
  return nonEmpty(options.apiKey) ?? nonEmpty(env.NEON_API_KEY) ?? readStoredAccessToken(env);
20
20
  }
21
21
  /**
22
- * Read `access_token` from the Neon CLI's credentials file, the same location and
23
- * precedence `neon auth` writes to: `NEONCTL_CONFIG_DIR` → `<home>/.config/neonctl`
24
- * (`HOME`, falling back to `USERPROFILE` for Windows parity).
22
+ * Read `access_token` from the Neon CLI's credentials file.
25
23
  *
26
- * Never throws a missing, unreadable, malformed, or token-less file is simply "no key",
24
+ * Location resolution is delegated to `@neon/config/paths` so this agrees with the `neon`
25
+ * CLI itself — `NEON_CONFIG_DIR` / `NEONCTL_CONFIG_DIR`, else `$XDG_CONFIG_HOME/neon`, else
26
+ * `~/.config/neon`, with an existing legacy `neonctl` directory still read. Rolling that
27
+ * lookup by hand here is how the two drifted in the first place: this file honoured the env
28
+ * var but not XDG, while the CLI honoured XDG but not the env var, so with
29
+ * `XDG_CONFIG_HOME` set they disagreed about where credentials lived.
30
+ *
31
+ * Reads only `DEFAULT` — a profile is a CLI-invocation concept, and `neon-env` has no
32
+ * `--profile` of its own to read one from.
33
+ *
34
+ * Never throws: a missing, unreadable, malformed, or token-less file is simply "no key",
27
35
  * so this can sit in a resolution chain without try/catch noise.
28
36
  */
29
37
  function readStoredAccessToken(env) {
30
- const home = env.HOME ?? env.USERPROFILE;
31
- const configDir = nonEmpty(env.NEONCTL_CONFIG_DIR) ?? (home ? resolve(home, ".config", "neonctl") : void 0);
32
- if (!configDir) return void 0;
33
- const credentialsPath = resolve(configDir, "credentials.json");
38
+ const { path: credentialsPath } = resolveConfigFile("credentials.json", { env });
34
39
  if (!existsSync(credentialsPath)) return void 0;
35
40
  let parsed;
36
41
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-api-key.js","names":[],"sources":["../../../src/lib/cli/resolve-api-key.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\n/**\n * Resolve the Neon API key for a `neon-env` CLI invocation. Precedence (each wins over the\n * next): `--api-key` flag → `NEON_API_KEY` → `access_token` from the Neon CLI's\n * `credentials.json`.\n *\n * The CLI owns this resolution — `@neon/config` and `@neon/env` are deliberately\n * environment- and filesystem-agnostic and only ever accept an explicit `apiKey`, so the\n * ambient sources a *user* expects have to be read here. This mirrors `resolveContext`,\n * which does the same for project and branch.\n *\n * Returns `undefined` rather than throwing when nothing provides a key: the caller passes\n * it straight through, and the library raises the uniform `PLATFORM_MISSING_API_KEY` error.\n */\nexport function resolveApiKey(options: {\n\tapiKey?: string;\n\tenv?: NodeJS.ProcessEnv;\n}): string | undefined {\n\tconst env = options.env ?? process.env;\n\treturn (\n\t\tnonEmpty(options.apiKey) ??\n\t\tnonEmpty(env.NEON_API_KEY) ??\n\t\treadStoredAccessToken(env)\n\t);\n}\n\n/**\n * Read `access_token` from the Neon CLI's credentials file, the same location and\n * precedence `neon auth` writes to: `NEONCTL_CONFIG_DIR` `<home>/.config/neonctl`\n * (`HOME`, falling back to `USERPROFILE` for Windows parity).\n *\n * Never throws a missing, unreadable, malformed, or token-less file is simply \"no key\",\n * so this can sit in a resolution chain without try/catch noise.\n */\nfunction readStoredAccessToken(env: NodeJS.ProcessEnv): string | undefined {\n\tconst home = env.HOME ?? env.USERPROFILE;\n\tconst configDir =\n\t\tnonEmpty(env.NEONCTL_CONFIG_DIR) ??\n\t\t(home ? resolve(home, \".config\", \"neonctl\") : undefined);\n\tif (!configDir) return undefined;\n\n\tconst credentialsPath = resolve(configDir, \"credentials.json\");\n\tif (!existsSync(credentialsPath)) return undefined;\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(credentialsPath, \"utf-8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\treturn undefined;\n\treturn nonEmpty((parsed as Record<string, unknown>).access_token as string);\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed === \"\" ? undefined : trimmed;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,cAAc,SAGP;CACtB,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,OACC,SAAS,QAAQ,MAAM,KACvB,SAAS,IAAI,YAAY,KACzB,sBAAsB,GAAG;AAE3B;;;;;;;;;AAUA,SAAS,sBAAsB,KAA4C;CAC1E,MAAM,OAAO,IAAI,QAAQ,IAAI;CAC7B,MAAM,YACL,SAAS,IAAI,kBAAkB,MAC9B,OAAO,QAAQ,MAAM,WAAW,SAAS,IAAI,KAAA;CAC/C,IAAI,CAAC,WAAW,OAAO,KAAA;CAEvB,MAAM,kBAAkB,QAAQ,WAAW,kBAAkB;CAC7D,IAAI,CAAC,WAAW,eAAe,GAAG,OAAO,KAAA;CAEzC,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;CAC3D,QAAQ;EACP;CACD;CAEA,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GACxE,OAAO,KAAA;CACR,OAAO,SAAU,OAAmC,YAAsB;AAC3E;AAEA,SAAS,SAAS,OAA+C;CAChE,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,UAAU,MAAM,KAAK;CAC3B,OAAO,YAAY,KAAK,KAAA,IAAY;AACrC"}
1
+ {"version":3,"file":"resolve-api-key.js","names":[],"sources":["../../../src/lib/cli/resolve-api-key.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { resolveConfigFile } from \"@neon/config/paths\";\n\n/**\n * Resolve the Neon API key for a `neon-env` CLI invocation. Precedence (each wins over the\n * next): `--api-key` flag → `NEON_API_KEY` → `access_token` from the Neon CLI's\n * `credentials.json`, located by `@neon/config/paths`.\n *\n * The CLI owns this resolution — `@neon/config` and `@neon/env` are deliberately\n * environment- and filesystem-agnostic and only ever accept an explicit `apiKey`, so the\n * ambient sources a *user* expects have to be read here. This mirrors `resolveContext`,\n * which does the same for project and branch.\n *\n * Returns `undefined` rather than throwing when nothing provides a key: the caller passes\n * it straight through, and the library raises the uniform `PLATFORM_MISSING_API_KEY` error.\n */\nexport function resolveApiKey(options: {\n\tapiKey?: string;\n\tenv?: NodeJS.ProcessEnv;\n}): string | undefined {\n\tconst env = options.env ?? process.env;\n\treturn (\n\t\tnonEmpty(options.apiKey) ??\n\t\tnonEmpty(env.NEON_API_KEY) ??\n\t\treadStoredAccessToken(env)\n\t);\n}\n\n/**\n * Read `access_token` from the Neon CLI's credentials file.\n *\n * Location resolution is delegated to `@neon/config/paths` so this agrees with the `neon`\n * CLI itself — `NEON_CONFIG_DIR` / `NEONCTL_CONFIG_DIR`, else `$XDG_CONFIG_HOME/neon`, else\n * `~/.config/neon`, with an existing legacy `neonctl` directory still read. Rolling that\n * lookup by hand here is how the two drifted in the first place: this file honoured the env\n * var but not XDG, while the CLI honoured XDG but not the env var, so with\n * `XDG_CONFIG_HOME` set they disagreed about where credentials lived.\n *\n * Reads only `DEFAULT` a profile is a CLI-invocation concept, and `neon-env` has no\n * `--profile` of its own to read one from.\n *\n * Never throws: a missing, unreadable, malformed, or token-less file is simply \"no key\",\n * so this can sit in a resolution chain without try/catch noise.\n */\nfunction readStoredAccessToken(env: NodeJS.ProcessEnv): string | undefined {\n\tconst { path: credentialsPath } = resolveConfigFile(\"credentials.json\", {\n\t\tenv,\n\t});\n\tif (!existsSync(credentialsPath)) return undefined;\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(credentialsPath, \"utf-8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\treturn undefined;\n\treturn nonEmpty((parsed as Record<string, unknown>).access_token as string);\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed === \"\" ? undefined : trimmed;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,cAAc,SAGP;CACtB,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,OACC,SAAS,QAAQ,MAAM,KACvB,SAAS,IAAI,YAAY,KACzB,sBAAsB,GAAG;AAE3B;;;;;;;;;;;;;;;;;AAkBA,SAAS,sBAAsB,KAA4C;CAC1E,MAAM,EAAE,MAAM,oBAAoB,kBAAkB,oBAAoB,EACvE,IACD,CAAC;CACD,IAAI,CAAC,WAAW,eAAe,GAAG,OAAO,KAAA;CAEzC,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;CAC3D,QAAQ;EACP;CACD;CAEA,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GACxE,OAAO,KAAA;CACR,OAAO,SAAU,OAAmC,YAAsB;AAC3E;AAEA,SAAS,SAAS,OAA+C;CAChE,IAAI,OAAO,UAAU,UAAU,OAAO,KAAA;CACtC,MAAM,UAAU,MAAM,KAAK;CAC3B,OAAO,YAAY,KAAK,KAAA,IAAY;AACrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neondatabase/env",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Resolve and inject Neon connection strings for the branch selected by your neon.ts policy. fetchEnv / parseEnv plus a `neon-env` CLI with `run` and `export`.",
5
5
  "keywords": [
6
6
  "neon",
@@ -51,12 +51,12 @@
51
51
  "typescript": "^5.9.0",
52
52
  "vitest": "^3.0.9",
53
53
  "@neon/e2e-harness": "0.0.0",
54
- "@neon/sdk": "1.4.0"
54
+ "@neon/sdk": "1.4.1"
55
55
  },
56
56
  "dependencies": {
57
57
  "zod": "^4.4.3",
58
58
  "yargs": "^18.0.0",
59
- "@neon/config": "0.12.0"
59
+ "@neon/config": "0.13.1"
60
60
  },
61
61
  "engines": {
62
62
  "node": ">=20.19.0"