@neondatabase/config 0.11.0 → 0.13.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/README.md CHANGED
@@ -143,7 +143,9 @@ const live = await inspect(target);
143
143
  | `plan(config, options)` | Returns the dry-run diff — what `apply` would do for the branch, with no mutations. Returns a `PushResult` whose `applied` holds the plan and `conflicts` holds blocking drift. |
144
144
  | `apply(config, options)` | Reconciles your local `neon.ts` policy onto the branch. Pass `updateExisting` to auto-confirm overriding existing remote settings and `allowProtectedBranch` to auto-confirm applying to a protected branch. |
145
145
 
146
- `options` requires both `projectId` and `branchId` (a Neon branch id, `br-…`). Resolve branch names to ids before calling. The Neon API key resolves via the `apiKey` option → `NEON_API_KEY` → `~/.config/neonctl/credentials.json`.
146
+ `options` requires both `projectId` and `branchId` (a Neon branch id, `br-…`). Resolve branch names to ids before calling.
147
+
148
+ **Pass `apiKey` explicitly** (or inject your own `api` adapter). This package reads no environment variables and no files on your behalf — it will not pick up `NEON_API_KEY` or `~/.config/neonctl/credentials.json`, and omitting the key raises `PLATFORM_MISSING_API_KEY`. Resolving where a credential comes from belongs to the application or CLI embedding this package, because only it knows which ambient sources its users expect. `packages/cli` and `packages/env`'s `neon-env` both implement that chain; the latter's `src/lib/cli/resolve-api-key.ts` is a ~60-line reference implementation of flag → `NEON_API_KEY` → stored credentials.
147
149
 
148
150
  ## Lower-level engine
149
151
 
@@ -159,7 +161,6 @@ import {
159
161
  pullConfig,
160
162
  loadConfigFromFile,
161
163
  createRealNeonApi,
162
- resolveApiKey,
163
164
  PlatformError,
164
165
  ErrorCode,
165
166
  errors,
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
2
2
  import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
3
3
  import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput } from "./lib/neon-api.js";
4
- import { createNeonApiFromOptions, resolveApiKey } from "./lib/auth.js";
4
+ import { createNeonApiFromOptions } from "./lib/auth.js";
5
5
  import { CredentialFeatureFlags, credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
6
6
  import { defineConfig, resolveConfig } from "./lib/define-config.js";
7
7
  import { DiffOptions, DiffResult, PlanStep, RemotePreviewState, RemoteServiceState, RemoteState, diffConfig } from "./lib/diff.js";
8
8
  import { LoadConfigOptions, loadConfigFromFile } from "./lib/loader.js";
9
9
  import { createRealNeonApi } from "./lib/neon-api-real.js";
10
10
  import { errors, schemas } from "./v1.js";
11
- export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConfigLoadError, ConfigValidationError, ConflictReport, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, CredentialFeatureFlags, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployFunctionInput, DiffOptions, DiffResult, DurationString, DurationUnit, EnableDataApiInput, ErrorCode, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, GetConnectionUriInput, LoadConfigOptions, MissingContextError, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, PartialBranchCreateError, PlanStep, PlatformError, PostgresConfig, PreviewInput, PreviewTuning, PushAbortedError, PushConflictError, PushResult, RemotePreviewState, RemoteServiceState, RemoteState, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveApiKey, resolveConfig, schemas };
11
+ export { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConfigLoadError, ConfigValidationError, ConflictReport, CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, CredentialFeatureFlags, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DeployFunctionInput, DiffOptions, DiffResult, DurationString, DurationUnit, EnableDataApiInput, ErrorCode, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, GetConnectionUriInput, LoadConfigOptions, MissingContextError, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, PartialBranchCreateError, PlanStep, PlatformError, PostgresConfig, PreviewInput, PreviewTuning, PushAbortedError, PushConflictError, PushResult, RemotePreviewState, RemoteServiceState, RemoteState, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput, UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
2
2
  import { createRealNeonApi } from "./lib/neon-api-real.js";
3
- import { createNeonApiFromOptions, resolveApiKey } from "./lib/auth.js";
3
+ import { createNeonApiFromOptions } from "./lib/auth.js";
4
4
  import { credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
5
5
  import { defineConfig, resolveConfig } from "./lib/define-config.js";
6
6
  import { diffConfig } from "./lib/diff.js";
7
7
  import { loadConfigFromFile } from "./lib/loader.js";
8
8
  import { DATA_API_AUTH_PROVIDERS } from "./lib/types.js";
9
9
  import { errors, schemas } from "./v1.js";
10
- export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveApiKey, resolveConfig, schemas };
10
+ export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
@@ -3,65 +3,30 @@ import { NeonApi } from "./neon-api.js";
3
3
  //#region src/lib/auth.d.ts
4
4
 
5
5
  /**
6
- * Minimal shape of `~/.config/neonctl/credentials.json` we read. `neonctl` writes more
7
- * fields (refresh_token, expires_at, …) but only `access_token` is what we need — it's a
8
- * Bearer token the Neon API accepts on the same endpoints `napi_*` API keys do.
9
- */
10
- interface NeonctlCredentials {
11
- access_token: string;
12
- [key: string]: unknown;
13
- }
14
- /**
15
- * Locate and read the OAuth credentials neonctl writes after `neon auth`.
16
- *
17
- * Resolution:
18
- * 1. `options.configDir` (explicit override — mirrors neonctl's `--config-dir` flag).
19
- * 2. `NEONCTL_CONFIG_DIR` environment variable.
20
- * 3. `<home>/.config/neonctl/credentials.json` (the neonctl default; `home` reads
21
- * `HOME`, falling back to `USERPROFILE` for Windows parity).
22
- *
23
- * Returns `null` (never throws) when the file is missing, unreadable, malformed, or has
24
- * no `access_token` — so callers can use this as a quiet fallback in a resolution chain
25
- * without try/catch noise.
26
- */
27
- declare function readNeonctlCredentials(options?: {
28
- configDir?: string;
29
- }): NeonctlCredentials | null;
30
- /**
31
- * Resolution chain for the Bearer token sent to the Neon API. Each entry wins over the
32
- * next:
33
- *
34
- * 1. `options.apiKey` (explicit).
35
- * 2. `NEON_API_KEY` environment variable.
36
- * 3. `access_token` from `~/.config/neonctl/credentials.json` (or `NEONCTL_CONFIG_DIR`).
6
+ * Build a real {@link NeonApi} adapter from an explicit API key, or throw a uniform
7
+ * `PLATFORM_MISSING_API_KEY` error when the caller didn't supply one.
37
8
  *
38
- * Returns `null` when no source provides one. Callers wrap the null case in a
39
- * `PLATFORM_MISSING_API_KEY` error with a message tailored to the operation.
40
- */
41
- declare function resolveApiKey(options?: {
42
- apiKey?: string;
43
- configDir?: string;
44
- }): {
45
- token: string;
46
- source: "option" | "env" | "neonctl";
47
- } | null;
48
- /**
49
- * Resolve the Neon API key via the standard chain (option → `NEON_API_KEY` env →
50
- * `~/.config/neonctl/credentials.json`) and construct a real {@link NeonApi} adapter from
51
- * it, or throw a uniform `PLATFORM_MISSING_API_KEY` error if no key can be found.
9
+ * **This function is pure with respect to its environment**: it reads no environment
10
+ * variables and no files. Everything it needs arrives in `options`. Resolving *where* a
11
+ * credential comes from — a flag, `NEON_API_KEY`, a credentials file on disk — is the
12
+ * caller's job, because only the caller knows which of those its users expect. See
13
+ * `packages/cli` (`ensureAuth` + `resolveApiKeyFromEnv`) and `packages/init`
14
+ * (`src/lib/auth.ts`) for the two implementations in this repo.
52
15
  *
53
- * The API host is resolved via: `options.apiHost` `NEON_API_HOST` env production
54
- * default (`https://console.neon.tech/api/v2`).
16
+ * `apiHost` stays **optional** and defaults to production
17
+ * (`https://console.neon.tech/api/v2`, applied by {@link createRealNeonApi}) — only pass it
18
+ * to target a non-production API. It is the *ambient* `NEON_API_HOST` lookup that's gone,
19
+ * not the default.
55
20
  *
56
21
  * Used by `pullConfig`, `pushConfig`, `fetchEnv`, and `branch` to build their default
57
- * `NeonApi` when the caller doesn't inject one. `operation` is the calling function's
58
- * name (e.g. `"pushConfig"`, `"branch"`) — it's prepended to the error message so users
59
- * can tell which call surfaced the missing key.
22
+ * adapter when the caller doesn't inject one. `operation` is the calling function's name
23
+ * (e.g. `"pushConfig"`, `"branch"`) — it's prepended to the error message so users can tell
24
+ * which call surfaced the missing key.
60
25
  */
61
26
  declare function createNeonApiFromOptions(operation: string, options?: {
62
27
  apiKey?: string;
63
28
  apiHost?: string;
64
29
  }): NeonApi;
65
30
  //#endregion
66
- export { NeonctlCredentials, createNeonApiFromOptions, readNeonctlCredentials, resolveApiKey };
31
+ export { createNeonApiFromOptions };
67
32
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/lib/auth.ts"],"mappings":";;;;;;AAWA;AAkBA;AA8CA;AAsCgB,UAtGC,kBAAA,CAsGuB;;;;;;;;;;;;;;;;;iBApFxB,sBAAA;;IAEb;;;;;;;;;;;;iBA4Ca,aAAA;;;;;;;;;;;;;;;;;;;;iBAsCA,wBAAA;;;IAMb"}
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/lib/auth.ts"],"mappings":";;;;;;AA+BA;;;;;;;;;;;;;;;;;;;iBAAgB,wBAAA;;;IAMb"}
package/dist/lib/auth.js CHANGED
@@ -1,107 +1,47 @@
1
1
  import { ErrorCode, PlatformError } from "./errors.js";
2
2
  import { createRealNeonApi } from "./neon-api-real.js";
3
- import { existsSync, readFileSync } from "node:fs";
4
- import { resolve } from "node:path";
5
3
  //#region src/lib/auth.ts
6
- /**
7
- * Locate and read the OAuth credentials neonctl writes after `neon auth`.
8
- *
9
- * Resolution:
10
- * 1. `options.configDir` (explicit override — mirrors neonctl's `--config-dir` flag).
11
- * 2. `NEONCTL_CONFIG_DIR` environment variable.
12
- * 3. `<home>/.config/neonctl/credentials.json` (the neonctl default; `home` reads
13
- * `HOME`, falling back to `USERPROFILE` for Windows parity).
14
- *
15
- * Returns `null` (never throws) when the file is missing, unreadable, malformed, or has
16
- * no `access_token` — so callers can use this as a quiet fallback in a resolution chain
17
- * without try/catch noise.
18
- */
19
- function readNeonctlCredentials(options = {}) {
20
- const home = process.env.HOME ?? process.env.USERPROFILE;
21
- const configDir = options.configDir ?? process.env.NEONCTL_CONFIG_DIR ?? (home ? resolve(home, ".config", "neonctl") : void 0);
22
- if (!configDir) return null;
23
- const credentialsPath = resolve(configDir, "credentials.json");
24
- if (!existsSync(credentialsPath)) return null;
25
- let raw;
26
- try {
27
- raw = readFileSync(credentialsPath, "utf-8");
28
- } catch {
29
- return null;
30
- }
31
- let parsed;
32
- try {
33
- parsed = JSON.parse(raw);
34
- } catch {
35
- return null;
36
- }
37
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
38
- const obj = parsed;
39
- if (typeof obj.access_token !== "string" || obj.access_token === "") return null;
40
- return obj;
41
- }
42
- /**
43
- * Resolution chain for the Bearer token sent to the Neon API. Each entry wins over the
44
- * next:
45
- *
46
- * 1. `options.apiKey` (explicit).
47
- * 2. `NEON_API_KEY` environment variable.
48
- * 3. `access_token` from `~/.config/neonctl/credentials.json` (or `NEONCTL_CONFIG_DIR`).
49
- *
50
- * Returns `null` when no source provides one. Callers wrap the null case in a
51
- * `PLATFORM_MISSING_API_KEY` error with a message tailored to the operation.
52
- */
53
- function resolveApiKey(options = {}) {
54
- if (options.apiKey && options.apiKey.trim() !== "") return {
55
- token: options.apiKey.trim(),
56
- source: "option"
57
- };
58
- const envKey = process.env.NEON_API_KEY;
59
- if (typeof envKey === "string" && envKey.trim() !== "") return {
60
- token: envKey.trim(),
61
- source: "env"
62
- };
63
- const creds = readNeonctlCredentials(options.configDir ? { configDir: options.configDir } : {});
64
- if (creds) return {
65
- token: creds.access_token,
66
- source: "neonctl"
67
- };
68
- return null;
69
- }
70
4
  /** Trim trailing slashes and surrounding whitespace; treat empty as unset. */
71
5
  function normalizeApiHost(url) {
72
6
  const trimmed = url?.trim().replace(/\/+$/, "");
73
7
  return trimmed ? trimmed : void 0;
74
8
  }
75
9
  /**
76
- * Resolve the Neon API key via the standard chain (option `NEON_API_KEY` env
77
- * `~/.config/neonctl/credentials.json`) and construct a real {@link NeonApi} adapter from
78
- * it, or throw a uniform `PLATFORM_MISSING_API_KEY` error if no key can be found.
10
+ * Build a real {@link NeonApi} adapter from an explicit API key, or throw a uniform
11
+ * `PLATFORM_MISSING_API_KEY` error when the caller didn't supply one.
12
+ *
13
+ * **This function is pure with respect to its environment**: it reads no environment
14
+ * variables and no files. Everything it needs arrives in `options`. Resolving *where* a
15
+ * credential comes from — a flag, `NEON_API_KEY`, a credentials file on disk — is the
16
+ * caller's job, because only the caller knows which of those its users expect. See
17
+ * `packages/cli` (`ensureAuth` + `resolveApiKeyFromEnv`) and `packages/init`
18
+ * (`src/lib/auth.ts`) for the two implementations in this repo.
79
19
  *
80
- * The API host is resolved via: `options.apiHost` `NEON_API_HOST` env production
81
- * default (`https://console.neon.tech/api/v2`).
20
+ * `apiHost` stays **optional** and defaults to production
21
+ * (`https://console.neon.tech/api/v2`, applied by {@link createRealNeonApi}) — only pass it
22
+ * to target a non-production API. It is the *ambient* `NEON_API_HOST` lookup that's gone,
23
+ * not the default.
82
24
  *
83
25
  * Used by `pullConfig`, `pushConfig`, `fetchEnv`, and `branch` to build their default
84
- * `NeonApi` when the caller doesn't inject one. `operation` is the calling function's
85
- * name (e.g. `"pushConfig"`, `"branch"`) — it's prepended to the error message so users
86
- * can tell which call surfaced the missing key.
26
+ * adapter when the caller doesn't inject one. `operation` is the calling function's name
27
+ * (e.g. `"pushConfig"`, `"branch"`) — it's prepended to the error message so users can tell
28
+ * which call surfaced the missing key.
87
29
  */
88
30
  function createNeonApiFromOptions(operation, options = {}) {
89
- const resolved = resolveApiKey(options.apiKey ? { apiKey: options.apiKey } : {});
90
- if (resolved) {
91
- const baseUrl = normalizeApiHost(options.apiHost) ?? normalizeApiHost(process.env.NEON_API_HOST);
92
- return createRealNeonApi({
93
- apiKey: resolved.token,
94
- ...baseUrl ? { baseUrl } : {}
95
- });
96
- }
97
- throw new PlatformError(ErrorCode.MissingApiKey, [
98
- `${operation} has no Neon API key to work with.`,
99
- "Tried (in order): `apiKey` option, NEON_API_KEY env, and `~/.config/neonctl/credentials.json`.",
100
- "Either pass `apiKey` directly, set NEON_API_KEY, run `npx neonctl auth` to populate the credentials file, or pass a custom `api` adapter (e.g. an in-memory fake for tests).",
31
+ const apiKey = options.apiKey?.trim();
32
+ if (!apiKey) throw new PlatformError(ErrorCode.MissingApiKey, [
33
+ `${operation} was not given a Neon API key.`,
34
+ "Pass `apiKey` explicitly, or inject your own `api` adapter (e.g. an in-memory fake for tests).",
35
+ "This package never reads NEON_API_KEY or a credentials file on your behalf — resolve the key in your own application or CLI and pass it in.",
101
36
  "Generate a key at https://console.neon.tech/app/settings/api-keys."
102
37
  ].join(" "));
38
+ const baseUrl = normalizeApiHost(options.apiHost);
39
+ return createRealNeonApi({
40
+ apiKey,
41
+ ...baseUrl ? { baseUrl } : {}
42
+ });
103
43
  }
104
44
  //#endregion
105
- export { createNeonApiFromOptions, readNeonctlCredentials, resolveApiKey };
45
+ export { createNeonApiFromOptions };
106
46
 
107
47
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","names":[],"sources":["../../src/lib/auth.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { ErrorCode, PlatformError } from \"./errors.js\";\nimport type { NeonApi } from \"./neon-api.js\";\nimport { createRealNeonApi } from \"./neon-api-real.js\";\n\n/**\n * Minimal shape of `~/.config/neonctl/credentials.json` we read. `neonctl` writes more\n * fields (refresh_token, expires_at, …) but only `access_token` is what we need — it's a\n * Bearer token the Neon API accepts on the same endpoints `napi_*` API keys do.\n */\nexport interface NeonctlCredentials {\n\taccess_token: string;\n\t[key: string]: unknown;\n}\n\n/**\n * Locate and read the OAuth credentials neonctl writes after `neon auth`.\n *\n * Resolution:\n * 1. `options.configDir` (explicit override — mirrors neonctl's `--config-dir` flag).\n * 2. `NEONCTL_CONFIG_DIR` environment variable.\n * 3. `<home>/.config/neonctl/credentials.json` (the neonctl default; `home` reads\n * `HOME`, falling back to `USERPROFILE` for Windows parity).\n *\n * Returns `null` (never throws) when the file is missing, unreadable, malformed, or has\n * no `access_token` — so callers can use this as a quiet fallback in a resolution chain\n * without try/catch noise.\n */\nexport function readNeonctlCredentials(\n\toptions: { configDir?: string } = {},\n): NeonctlCredentials | null {\n\tconst home = process.env.HOME ?? process.env.USERPROFILE;\n\tconst configDir =\n\t\toptions.configDir ??\n\t\tprocess.env.NEONCTL_CONFIG_DIR ??\n\t\t(home ? resolve(home, \".config\", \"neonctl\") : undefined);\n\tif (!configDir) return null;\n\n\tconst credentialsPath = resolve(configDir, \"credentials.json\");\n\tif (!existsSync(credentialsPath)) return null;\n\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(credentialsPath, \"utf-8\");\n\t} catch {\n\t\treturn null;\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\n\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed))\n\t\treturn null;\n\tconst obj = parsed as Record<string, unknown>;\n\tif (typeof obj.access_token !== \"string\" || obj.access_token === \"\")\n\t\treturn null;\n\treturn obj as NeonctlCredentials;\n}\n\n/**\n * Resolution chain for the Bearer token sent to the Neon API. Each entry wins over the\n * next:\n *\n * 1. `options.apiKey` (explicit).\n * 2. `NEON_API_KEY` environment variable.\n * 3. `access_token` from `~/.config/neonctl/credentials.json` (or `NEONCTL_CONFIG_DIR`).\n *\n * Returns `null` when no source provides one. Callers wrap the null case in a\n * `PLATFORM_MISSING_API_KEY` error with a message tailored to the operation.\n */\nexport function resolveApiKey(\n\toptions: { apiKey?: string; configDir?: string } = {},\n): { token: string; source: \"option\" | \"env\" | \"neonctl\" } | null {\n\tif (options.apiKey && options.apiKey.trim() !== \"\") {\n\t\treturn { token: options.apiKey.trim(), source: \"option\" };\n\t}\n\tconst envKey = process.env.NEON_API_KEY;\n\tif (typeof envKey === \"string\" && envKey.trim() !== \"\") {\n\t\treturn { token: envKey.trim(), source: \"env\" };\n\t}\n\tconst creds = readNeonctlCredentials(\n\t\toptions.configDir ? { configDir: options.configDir } : {},\n\t);\n\tif (creds) {\n\t\treturn { token: creds.access_token, source: \"neonctl\" };\n\t}\n\treturn null;\n}\n\n/** Trim trailing slashes and surrounding whitespace; treat empty as unset. */\nfunction normalizeApiHost(url: string | undefined): string | undefined {\n\tconst trimmed = url?.trim().replace(/\\/+$/, \"\");\n\treturn trimmed ? trimmed : undefined;\n}\n\n/**\n * Resolve the Neon API key via the standard chain (option → `NEON_API_KEY` env →\n * `~/.config/neonctl/credentials.json`) and construct a real {@link NeonApi} adapter from\n * it, or throw a uniform `PLATFORM_MISSING_API_KEY` error if no key can be found.\n *\n * The API host is resolved via: `options.apiHost` → `NEON_API_HOST` env production\n * default (`https://console.neon.tech/api/v2`).\n *\n * Used by `pullConfig`, `pushConfig`, `fetchEnv`, and `branch` to build their default\n * `NeonApi` when the caller doesn't inject one. `operation` is the calling function's\n * name (e.g. `\"pushConfig\"`, `\"branch\"`) — it's prepended to the error message so users\n * can tell which call surfaced the missing key.\n */\nexport function createNeonApiFromOptions(\n\toperation: string,\n\toptions: {\n\t\tapiKey?: string;\n\t\tapiHost?: string;\n\t} = {},\n): NeonApi {\n\tconst resolved = resolveApiKey(\n\t\toptions.apiKey ? { apiKey: options.apiKey } : {},\n\t);\n\tif (resolved) {\n\t\tconst baseUrl =\n\t\t\tnormalizeApiHost(options.apiHost) ??\n\t\t\tnormalizeApiHost(process.env.NEON_API_HOST);\n\t\treturn createRealNeonApi({\n\t\t\tapiKey: resolved.token,\n\t\t\t...(baseUrl ? { baseUrl } : {}),\n\t\t});\n\t}\n\tthrow new PlatformError(\n\t\tErrorCode.MissingApiKey,\n\t\t[\n\t\t\t`${operation} has no Neon API key to work with.`,\n\t\t\t\"Tried (in order): `apiKey` option, NEON_API_KEY env, and `~/.config/neonctl/credentials.json`.\",\n\t\t\t\"Either pass `apiKey` directly, set NEON_API_KEY, run `npx neonctl auth` to populate the credentials file, or pass a custom `api` adapter (e.g. an in-memory fake for tests).\",\n\t\t\t\"Generate a key at https://console.neon.tech/app/settings/api-keys.\",\n\t\t].join(\" \"),\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6BA,SAAgB,uBACf,UAAkC,CAAC,GACP;CAC5B,MAAM,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI;CAC7C,MAAM,YACL,QAAQ,aACR,QAAQ,IAAI,uBACX,OAAO,QAAQ,MAAM,WAAW,SAAS,IAAI,KAAA;CAC/C,IAAI,CAAC,WAAW,OAAO;CAEvB,MAAM,kBAAkB,QAAQ,WAAW,kBAAkB;CAC7D,IAAI,CAAC,WAAW,eAAe,GAAG,OAAO;CAEzC,IAAI;CACJ,IAAI;EACH,MAAM,aAAa,iBAAiB,OAAO;CAC5C,QAAQ;EACP,OAAO;CACR;CAEA,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,GAAG;CACxB,QAAQ;EACP,OAAO;CACR;CAEA,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GACxE,OAAO;CACR,MAAM,MAAM;CACZ,IAAI,OAAO,IAAI,iBAAiB,YAAY,IAAI,iBAAiB,IAChE,OAAO;CACR,OAAO;AACR;;;;;;;;;;;;AAaA,SAAgB,cACf,UAAmD,CAAC,GACa;CACjE,IAAI,QAAQ,UAAU,QAAQ,OAAO,KAAK,MAAM,IAC/C,OAAO;EAAE,OAAO,QAAQ,OAAO,KAAK;EAAG,QAAQ;CAAS;CAEzD,MAAM,SAAS,QAAQ,IAAI;CAC3B,IAAI,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM,IACnD,OAAO;EAAE,OAAO,OAAO,KAAK;EAAG,QAAQ;CAAM;CAE9C,MAAM,QAAQ,uBACb,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC,CACzD;CACA,IAAI,OACH,OAAO;EAAE,OAAO,MAAM;EAAc,QAAQ;CAAU;CAEvD,OAAO;AACR;;AAGA,SAAS,iBAAiB,KAA6C;CACtE,MAAM,UAAU,KAAK,KAAK,CAAC,CAAC,QAAQ,QAAQ,EAAE;CAC9C,OAAO,UAAU,UAAU,KAAA;AAC5B;;;;;;;;;;;;;;AAeA,SAAgB,yBACf,WACA,UAGI,CAAC,GACK;CACV,MAAM,WAAW,cAChB,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC,CAChD;CACA,IAAI,UAAU;EACb,MAAM,UACL,iBAAiB,QAAQ,OAAO,KAChC,iBAAiB,QAAQ,IAAI,aAAa;EAC3C,OAAO,kBAAkB;GACxB,QAAQ,SAAS;GACjB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC9B,CAAC;CACF;CACA,MAAM,IAAI,cACT,UAAU,eACV;EACC,GAAG,UAAU;EACb;EACA;EACA;CACD,CAAC,CAAC,KAAK,GAAG,CACX;AACD"}
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../src/lib/auth.ts"],"sourcesContent":["import { ErrorCode, PlatformError } from \"./errors.js\";\nimport type { NeonApi } from \"./neon-api.js\";\nimport { createRealNeonApi } from \"./neon-api-real.js\";\n\n/** Trim trailing slashes and surrounding whitespace; treat empty as unset. */\nfunction normalizeApiHost(url: string | undefined): string | undefined {\n\tconst trimmed = url?.trim().replace(/\\/+$/, \"\");\n\treturn trimmed ? trimmed : undefined;\n}\n\n/**\n * Build a real {@link NeonApi} adapter from an explicit API key, or throw a uniform\n * `PLATFORM_MISSING_API_KEY` error when the caller didn't supply one.\n *\n * **This function is pure with respect to its environment**: it reads no environment\n * variables and no files. Everything it needs arrives in `options`. Resolving *where* a\n * credential comes from a flag, `NEON_API_KEY`, a credentials file on disk is the\n * caller's job, because only the caller knows which of those its users expect. See\n * `packages/cli` (`ensureAuth` + `resolveApiKeyFromEnv`) and `packages/init`\n * (`src/lib/auth.ts`) for the two implementations in this repo.\n *\n * `apiHost` stays **optional** and defaults to production\n * (`https://console.neon.tech/api/v2`, applied by {@link createRealNeonApi}) only pass it\n * to target a non-production API. It is the *ambient* `NEON_API_HOST` lookup that's gone,\n * not the default.\n *\n * Used by `pullConfig`, `pushConfig`, `fetchEnv`, and `branch` to build their default\n * adapter when the caller doesn't inject one. `operation` is the calling function's name\n * (e.g. `\"pushConfig\"`, `\"branch\"`) — it's prepended to the error message so users can tell\n * which call surfaced the missing key.\n */\nexport function createNeonApiFromOptions(\n\toperation: string,\n\toptions: {\n\t\tapiKey?: string;\n\t\tapiHost?: string;\n\t} = {},\n): NeonApi {\n\tconst apiKey = options.apiKey?.trim();\n\tif (!apiKey) {\n\t\tthrow new PlatformError(\n\t\t\tErrorCode.MissingApiKey,\n\t\t\t[\n\t\t\t\t`${operation} was not given a Neon API key.`,\n\t\t\t\t\"Pass `apiKey` explicitly, or inject your own `api` adapter (e.g. an in-memory fake for tests).\",\n\t\t\t\t\"This package never reads NEON_API_KEY or a credentials file on your behalf resolve the key in your own application or CLI and pass it in.\",\n\t\t\t\t\"Generate a key at https://console.neon.tech/app/settings/api-keys.\",\n\t\t\t].join(\" \"),\n\t\t);\n\t}\n\n\tconst baseUrl = normalizeApiHost(options.apiHost);\n\treturn createRealNeonApi({\n\t\tapiKey,\n\t\t...(baseUrl ? { baseUrl } : {}),\n\t});\n}\n"],"mappings":";;;;AAKA,SAAS,iBAAiB,KAA6C;CACtE,MAAM,UAAU,KAAK,KAAK,CAAC,CAAC,QAAQ,QAAQ,EAAE;CAC9C,OAAO,UAAU,UAAU,KAAA;AAC5B;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,yBACf,WACA,UAGI,CAAC,GACK;CACV,MAAM,SAAS,QAAQ,QAAQ,KAAK;CACpC,IAAI,CAAC,QACJ,MAAM,IAAI,cACT,UAAU,eACV;EACC,GAAG,UAAU;EACb;EACA;EACA;CACD,CAAC,CAAC,KAAK,GAAG,CACX;CAGD,MAAM,UAAU,iBAAiB,QAAQ,OAAO;CAChD,OAAO,kBAAkB;EACxB;EACA,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAC9B,CAAC;AACF"}
@@ -1,8 +1,8 @@
1
1
  import { ConfigLoadError, isPlatformError } from "./errors.js";
2
2
  import { defineConfig } from "./define-config.js";
3
3
  import { existsSync, statSync } from "node:fs";
4
- import { dirname, isAbsolute, resolve } from "node:path";
5
4
  import { homedir } from "node:os";
5
+ import { dirname, isAbsolute, resolve } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  //#region src/lib/loader.ts
8
8
  /**
@@ -0,0 +1,79 @@
1
+ //#region src/paths.d.ts
2
+ /**
3
+ * # `@neon/config/paths` — where the Neon CLIs keep their files on disk
4
+ *
5
+ * **Implementor-only, and deliberately impure.** This subpath reads environment variables
6
+ * and touches the filesystem, which the root `@neon/config` export must never do — the same
7
+ * split as `@neon/env` (pure) versus `@neon/env/runtime` (stateful). Import it from a CLI,
8
+ * never from a `neon.ts` policy. It imports nothing from the rest of the package, so pulling
9
+ * it in costs one module.
10
+ *
11
+ * It exists because three separate readers each grew their own answer to "where is the
12
+ * config directory", and all three disagreed: `packages/cli` honoured `XDG_CONFIG_HOME` but
13
+ * not `NEONCTL_CONFIG_DIR`, `packages/env` honoured the env var but not XDG, and
14
+ * `packages/init` hardcoded `~/.config/neonctl`. With `XDG_CONFIG_HOME` set, the CLI wrote
15
+ * credentials somewhere the other two never looked.
16
+ *
17
+ * ## The directory
18
+ *
19
+ * `neon` is the current name; `neonctl` is the legacy one, kept readable forever. Resolution,
20
+ * each entry winning over the next:
21
+ *
22
+ * 1. An explicit directory (a `--config-dir` flag) — **exact**, no legacy fallback.
23
+ * 2. `NEON_CONFIG_DIR` — exact.
24
+ * 3. `NEONCTL_CONFIG_DIR` (legacy name) — exact.
25
+ * 4. `$XDG_CONFIG_HOME/neon`, else `<home>/.config/neon`.
26
+ *
27
+ * An explicitly chosen directory is never paired with a fallback: `--config-dir /tmp/ci` that
28
+ * quietly read `~/.config/neonctl` would defeat the point of passing it.
29
+ *
30
+ * ## The files
31
+ *
32
+ * {@link resolveConfigFile} answers "which path should I use for this file", and it is the
33
+ * same answer for reading and writing:
34
+ *
35
+ * - Present in `neon/` → use it.
36
+ * - Present only in `neonctl/` → **use it there, in place.** An existing credentials file is
37
+ * never copied or moved, so nothing is left behind to go stale and no other tool starts
38
+ * reading an abandoned token.
39
+ * - Present in neither → the new location. New files only ever appear under `neon/`.
40
+ */
41
+ /** Current directory name. New files are created here. */
42
+ declare const CONFIG_DIR_NAME = "neon";
43
+ /** Legacy directory name, read forever so existing installs keep working untouched. */
44
+ declare const LEGACY_CONFIG_DIR_NAME = "neonctl";
45
+ interface ConfigPathOptions {
46
+ /**
47
+ * An explicit directory, e.g. from a `--config-dir` flag. Used exactly as given: no
48
+ * environment variables are consulted and the legacy directory is never searched.
49
+ */
50
+ dir?: string;
51
+ /** Environment to read. Defaults to `process.env`. Injectable for tests. */
52
+ env?: NodeJS.ProcessEnv;
53
+ }
54
+ /** Where files are created. See the module docs for the precedence. */
55
+ declare function configDir(options?: ConfigPathOptions): string;
56
+ /**
57
+ * The legacy directory, or `undefined` when the location was chosen explicitly (in which
58
+ * case there is no legacy counterpart to fall back to).
59
+ */
60
+ declare function legacyConfigDir(options?: ConfigPathOptions): string | undefined;
61
+ interface ResolvedConfigFile {
62
+ /** The path to use, for both reading and writing. */
63
+ path: string;
64
+ /** The directory `path` lives in. */
65
+ dir: string;
66
+ /** True when the file was found in the legacy `neonctl` directory. */
67
+ isLegacy: boolean;
68
+ /** Whether the file exists at `path` right now. */
69
+ exists: boolean;
70
+ }
71
+ /**
72
+ * Resolve one file inside the config directory. Prefers the current location, falls back to
73
+ * an existing legacy file **in place**, and otherwise points at the current location so new
74
+ * files are created there.
75
+ */
76
+ declare function resolveConfigFile(fileName: string, options?: ConfigPathOptions): ResolvedConfigFile;
77
+ //#endregion
78
+ export { CONFIG_DIR_NAME, ConfigPathOptions, LEGACY_CONFIG_DIR_NAME, ResolvedConfigFile, configDir, legacyConfigDir, resolveConfigFile };
79
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","names":[],"sources":["../src/paths.ts"],"mappings":";;AA4CA;AAGA;AAEA;AAWA;AAUA;AAOA;AAgBA;AAAiC;AAEvB;AACP;AAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cApDR,eAAA;;cAGA,sBAAA;UAEI,iBAAA;;;;;;;QAOV,MAAA,CAAO;;;iBAIE,SAAA,WAAmB;;;;;iBAUnB,eAAA,WACN;UAMO,kBAAA;;;;;;;;;;;;;;;iBAgBD,iBAAA,6BAEN,oBACP"}
package/dist/paths.js ADDED
@@ -0,0 +1,111 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ //#region src/paths.ts
4
+ /**
5
+ * # `@neon/config/paths` — where the Neon CLIs keep their files on disk
6
+ *
7
+ * **Implementor-only, and deliberately impure.** This subpath reads environment variables
8
+ * and touches the filesystem, which the root `@neon/config` export must never do — the same
9
+ * split as `@neon/env` (pure) versus `@neon/env/runtime` (stateful). Import it from a CLI,
10
+ * never from a `neon.ts` policy. It imports nothing from the rest of the package, so pulling
11
+ * it in costs one module.
12
+ *
13
+ * It exists because three separate readers each grew their own answer to "where is the
14
+ * config directory", and all three disagreed: `packages/cli` honoured `XDG_CONFIG_HOME` but
15
+ * not `NEONCTL_CONFIG_DIR`, `packages/env` honoured the env var but not XDG, and
16
+ * `packages/init` hardcoded `~/.config/neonctl`. With `XDG_CONFIG_HOME` set, the CLI wrote
17
+ * credentials somewhere the other two never looked.
18
+ *
19
+ * ## The directory
20
+ *
21
+ * `neon` is the current name; `neonctl` is the legacy one, kept readable forever. Resolution,
22
+ * each entry winning over the next:
23
+ *
24
+ * 1. An explicit directory (a `--config-dir` flag) — **exact**, no legacy fallback.
25
+ * 2. `NEON_CONFIG_DIR` — exact.
26
+ * 3. `NEONCTL_CONFIG_DIR` (legacy name) — exact.
27
+ * 4. `$XDG_CONFIG_HOME/neon`, else `<home>/.config/neon`.
28
+ *
29
+ * An explicitly chosen directory is never paired with a fallback: `--config-dir /tmp/ci` that
30
+ * quietly read `~/.config/neonctl` would defeat the point of passing it.
31
+ *
32
+ * ## The files
33
+ *
34
+ * {@link resolveConfigFile} answers "which path should I use for this file", and it is the
35
+ * same answer for reading and writing:
36
+ *
37
+ * - Present in `neon/` → use it.
38
+ * - Present only in `neonctl/` → **use it there, in place.** An existing credentials file is
39
+ * never copied or moved, so nothing is left behind to go stale and no other tool starts
40
+ * reading an abandoned token.
41
+ * - Present in neither → the new location. New files only ever appear under `neon/`.
42
+ */
43
+ /** Current directory name. New files are created here. */
44
+ const CONFIG_DIR_NAME = "neon";
45
+ /** Legacy directory name, read forever so existing installs keep working untouched. */
46
+ const LEGACY_CONFIG_DIR_NAME = "neonctl";
47
+ /** Where files are created. See the module docs for the precedence. */
48
+ function configDir(options = {}) {
49
+ const explicit = explicitDir(options);
50
+ if (explicit) return explicit;
51
+ return join(configHome(options.env ?? process.env), CONFIG_DIR_NAME);
52
+ }
53
+ /**
54
+ * The legacy directory, or `undefined` when the location was chosen explicitly (in which
55
+ * case there is no legacy counterpart to fall back to).
56
+ */
57
+ function legacyConfigDir(options = {}) {
58
+ if (explicitDir(options)) return void 0;
59
+ return join(configHome(options.env ?? process.env), LEGACY_CONFIG_DIR_NAME);
60
+ }
61
+ /**
62
+ * Resolve one file inside the config directory. Prefers the current location, falls back to
63
+ * an existing legacy file **in place**, and otherwise points at the current location so new
64
+ * files are created there.
65
+ */
66
+ function resolveConfigFile(fileName, options = {}) {
67
+ const dir = configDir(options);
68
+ const current = resolve(dir, fileName);
69
+ if (existsSync(current)) return {
70
+ path: current,
71
+ dir,
72
+ isLegacy: false,
73
+ exists: true
74
+ };
75
+ const legacyDir = legacyConfigDir(options);
76
+ if (legacyDir) {
77
+ const legacy = resolve(legacyDir, fileName);
78
+ if (existsSync(legacy)) return {
79
+ path: legacy,
80
+ dir: legacyDir,
81
+ isLegacy: true,
82
+ exists: true
83
+ };
84
+ }
85
+ return {
86
+ path: current,
87
+ dir,
88
+ isLegacy: false,
89
+ exists: false
90
+ };
91
+ }
92
+ /** `$XDG_CONFIG_HOME`, else `<home>/.config`. Falls back to a relative `.config` with no home. */
93
+ function configHome(env) {
94
+ const xdg = nonEmpty(env.XDG_CONFIG_HOME);
95
+ if (xdg) return xdg;
96
+ const home = nonEmpty(env.HOME) ?? nonEmpty(env.USERPROFILE);
97
+ return home ? join(home, ".config") : ".config";
98
+ }
99
+ function explicitDir(options) {
100
+ const env = options.env ?? process.env;
101
+ return nonEmpty(options.dir) ?? nonEmpty(env.NEON_CONFIG_DIR) ?? nonEmpty(env.NEONCTL_CONFIG_DIR);
102
+ }
103
+ function nonEmpty(value) {
104
+ if (typeof value !== "string") return void 0;
105
+ const trimmed = value.trim();
106
+ return trimmed === "" ? void 0 : trimmed;
107
+ }
108
+ //#endregion
109
+ export { CONFIG_DIR_NAME, LEGACY_CONFIG_DIR_NAME, configDir, legacyConfigDir, resolveConfigFile };
110
+
111
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","names":[],"sources":["../src/paths.ts"],"sourcesContent":["/**\n * # `@neon/config/paths` — where the Neon CLIs keep their files on disk\n *\n * **Implementor-only, and deliberately impure.** This subpath reads environment variables\n * and touches the filesystem, which the root `@neon/config` export must never do — the same\n * split as `@neon/env` (pure) versus `@neon/env/runtime` (stateful). Import it from a CLI,\n * never from a `neon.ts` policy. It imports nothing from the rest of the package, so pulling\n * it in costs one module.\n *\n * It exists because three separate readers each grew their own answer to \"where is the\n * config directory\", and all three disagreed: `packages/cli` honoured `XDG_CONFIG_HOME` but\n * not `NEONCTL_CONFIG_DIR`, `packages/env` honoured the env var but not XDG, and\n * `packages/init` hardcoded `~/.config/neonctl`. With `XDG_CONFIG_HOME` set, the CLI wrote\n * credentials somewhere the other two never looked.\n *\n * ## The directory\n *\n * `neon` is the current name; `neonctl` is the legacy one, kept readable forever. Resolution,\n * each entry winning over the next:\n *\n * 1. An explicit directory (a `--config-dir` flag) — **exact**, no legacy fallback.\n * 2. `NEON_CONFIG_DIR` — exact.\n * 3. `NEONCTL_CONFIG_DIR` (legacy name) — exact.\n * 4. `$XDG_CONFIG_HOME/neon`, else `<home>/.config/neon`.\n *\n * An explicitly chosen directory is never paired with a fallback: `--config-dir /tmp/ci` that\n * quietly read `~/.config/neonctl` would defeat the point of passing it.\n *\n * ## The files\n *\n * {@link resolveConfigFile} answers \"which path should I use for this file\", and it is the\n * same answer for reading and writing:\n *\n * - Present in `neon/` → use it.\n * - Present only in `neonctl/` → **use it there, in place.** An existing credentials file is\n * never copied or moved, so nothing is left behind to go stale and no other tool starts\n * reading an abandoned token.\n * - Present in neither → the new location. New files only ever appear under `neon/`.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\n/** Current directory name. New files are created here. */\nexport const CONFIG_DIR_NAME = \"neon\";\n\n/** Legacy directory name, read forever so existing installs keep working untouched. */\nexport const LEGACY_CONFIG_DIR_NAME = \"neonctl\";\n\nexport interface ConfigPathOptions {\n\t/**\n\t * An explicit directory, e.g. from a `--config-dir` flag. Used exactly as given: no\n\t * environment variables are consulted and the legacy directory is never searched.\n\t */\n\tdir?: string;\n\t/** Environment to read. Defaults to `process.env`. Injectable for tests. */\n\tenv?: NodeJS.ProcessEnv;\n}\n\n/** Where files are created. See the module docs for the precedence. */\nexport function configDir(options: ConfigPathOptions = {}): string {\n\tconst explicit = explicitDir(options);\n\tif (explicit) return explicit;\n\treturn join(configHome(options.env ?? process.env), CONFIG_DIR_NAME);\n}\n\n/**\n * The legacy directory, or `undefined` when the location was chosen explicitly (in which\n * case there is no legacy counterpart to fall back to).\n */\nexport function legacyConfigDir(\n\toptions: ConfigPathOptions = {},\n): string | undefined {\n\tif (explicitDir(options)) return undefined;\n\treturn join(configHome(options.env ?? process.env), LEGACY_CONFIG_DIR_NAME);\n}\n\nexport interface ResolvedConfigFile {\n\t/** The path to use, for both reading and writing. */\n\tpath: string;\n\t/** The directory `path` lives in. */\n\tdir: string;\n\t/** True when the file was found in the legacy `neonctl` directory. */\n\tisLegacy: boolean;\n\t/** Whether the file exists at `path` right now. */\n\texists: boolean;\n}\n\n/**\n * Resolve one file inside the config directory. Prefers the current location, falls back to\n * an existing legacy file **in place**, and otherwise points at the current location so new\n * files are created there.\n */\nexport function resolveConfigFile(\n\tfileName: string,\n\toptions: ConfigPathOptions = {},\n): ResolvedConfigFile {\n\tconst dir = configDir(options);\n\tconst current = resolve(dir, fileName);\n\tif (existsSync(current))\n\t\treturn { path: current, dir, isLegacy: false, exists: true };\n\n\tconst legacyDir = legacyConfigDir(options);\n\tif (legacyDir) {\n\t\tconst legacy = resolve(legacyDir, fileName);\n\t\tif (existsSync(legacy))\n\t\t\treturn {\n\t\t\t\tpath: legacy,\n\t\t\t\tdir: legacyDir,\n\t\t\t\tisLegacy: true,\n\t\t\t\texists: true,\n\t\t\t};\n\t}\n\n\treturn { path: current, dir, isLegacy: false, exists: false };\n}\n\n/** `$XDG_CONFIG_HOME`, else `<home>/.config`. Falls back to a relative `.config` with no home. */\nfunction configHome(env: NodeJS.ProcessEnv): string {\n\tconst xdg = nonEmpty(env.XDG_CONFIG_HOME);\n\tif (xdg) return xdg;\n\tconst home = nonEmpty(env.HOME) ?? nonEmpty(env.USERPROFILE);\n\treturn home ? join(home, \".config\") : \".config\";\n}\n\nfunction explicitDir(options: ConfigPathOptions): string | undefined {\n\tconst env = options.env ?? process.env;\n\treturn (\n\t\tnonEmpty(options.dir) ??\n\t\tnonEmpty(env.NEON_CONFIG_DIR) ??\n\t\tnonEmpty(env.NEONCTL_CONFIG_DIR)\n\t);\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,MAAa,kBAAkB;;AAG/B,MAAa,yBAAyB;;AAatC,SAAgB,UAAU,UAA6B,CAAC,GAAW;CAClE,MAAM,WAAW,YAAY,OAAO;CACpC,IAAI,UAAU,OAAO;CACrB,OAAO,KAAK,WAAW,QAAQ,OAAO,QAAQ,GAAG,GAAG,eAAe;AACpE;;;;;AAMA,SAAgB,gBACf,UAA6B,CAAC,GACT;CACrB,IAAI,YAAY,OAAO,GAAG,OAAO,KAAA;CACjC,OAAO,KAAK,WAAW,QAAQ,OAAO,QAAQ,GAAG,GAAG,sBAAsB;AAC3E;;;;;;AAkBA,SAAgB,kBACf,UACA,UAA6B,CAAC,GACT;CACrB,MAAM,MAAM,UAAU,OAAO;CAC7B,MAAM,UAAU,QAAQ,KAAK,QAAQ;CACrC,IAAI,WAAW,OAAO,GACrB,OAAO;EAAE,MAAM;EAAS;EAAK,UAAU;EAAO,QAAQ;CAAK;CAE5D,MAAM,YAAY,gBAAgB,OAAO;CACzC,IAAI,WAAW;EACd,MAAM,SAAS,QAAQ,WAAW,QAAQ;EAC1C,IAAI,WAAW,MAAM,GACpB,OAAO;GACN,MAAM;GACN,KAAK;GACL,UAAU;GACV,QAAQ;EACT;CACF;CAEA,OAAO;EAAE,MAAM;EAAS;EAAK,UAAU;EAAO,QAAQ;CAAM;AAC7D;;AAGA,SAAS,WAAW,KAAgC;CACnD,MAAM,MAAM,SAAS,IAAI,eAAe;CACxC,IAAI,KAAK,OAAO;CAChB,MAAM,OAAO,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,WAAW;CAC3D,OAAO,OAAO,KAAK,MAAM,SAAS,IAAI;AACvC;AAEA,SAAS,YAAY,SAAgD;CACpE,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,OACC,SAAS,QAAQ,GAAG,KACpB,SAAS,IAAI,eAAe,KAC5B,SAAS,IAAI,kBAAkB;AAEjC;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/dist/v1.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AppliedChange, BranchTarget, BranchTuning, BranchTuningFn, BucketAccessLevel, BucketDef, ComputeSettings, ComputeUnit, Config, ConflictReport, CredentialPrincipalType, CredentialScope, DATA_API_AUTH_PROVIDERS, DataApiAuthProvider, DataApiConfig, DataApiExternalAuthConfig, DataApiInput, DataApiNeonAuthConfig, DataApiSettings, DurationString, DurationUnit, FunctionDef, FunctionDevConfig, FunctionRuntime, FunctionTuning, PostgresConfig, PreviewInput, PreviewTuning, PushResult, ResolvedBranchConfig, ResolvedBucketConfig, ResolvedDataApiConfig, ResolvedFunctionConfig, ResolvedPreviewConfig, ServiceEnabled, ServiceToggle, ServiceToggleInput } from "./lib/types.js";
2
2
  import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
3
3
  import { CreateBranchInput, CreateBucketInput, CreateCredentialInput, CreateProjectInput, DeployFunctionInput, EnableDataApiInput, GetConnectionUriInput, NeonApi, NeonAuthSnapshot, NeonBranchSnapshot, NeonBranchStorageSnapshot, NeonBucketSnapshot, NeonCredentialMeta, NeonCredentialSecret, NeonDataApiSnapshot, NeonDatabaseSnapshot, NeonEndpointSnapshot, NeonFunctionDeploymentSnapshot, NeonFunctionSnapshot, NeonProjectSnapshot, NeonRoleSnapshot, UpdateBranchInput } from "./lib/neon-api.js";
4
- import { createNeonApiFromOptions, resolveApiKey } from "./lib/auth.js";
4
+ import { createNeonApiFromOptions } from "./lib/auth.js";
5
5
  import { CredentialFeatureFlags, credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
6
6
  import { defineConfig, resolveConfig } from "./lib/define-config.js";
7
7
  import { DiffOptions, DiffResult, PlanStep, RemotePreviewState, RemoteServiceState, RemoteState, diffConfig } from "./lib/diff.js";
@@ -213,5 +213,5 @@ declare const schemas: {
213
213
  }, zod_v4_core0.$strict>]>;
214
214
  };
215
215
  //#endregion
216
- export { type AppliedChange, type BranchTarget, type BranchTuning, type BranchTuningFn, type BucketAccessLevel, type BucketDef, type ComputeSettings, type ComputeUnit, type Config, ConfigLoadError, ConfigValidationError, type ConflictReport, type CreateBranchInput, type CreateBucketInput, type CreateCredentialInput, type CreateProjectInput, type CredentialFeatureFlags, type CredentialPrincipalType, type CredentialScope, DATA_API_AUTH_PROVIDERS, type DataApiAuthProvider, type DataApiConfig, type DataApiExternalAuthConfig, type DataApiInput, type DataApiNeonAuthConfig, type DataApiSettings, type DeployFunctionInput, type DiffOptions, type DiffResult, type DurationString, type DurationUnit, type EnableDataApiInput, ErrorCode, type FunctionDef, type FunctionDevConfig, type FunctionRuntime, type FunctionTuning, type GetConnectionUriInput, type LoadConfigOptions, MissingContextError, type NeonApi, type NeonAuthSnapshot, type NeonBranchSnapshot, type NeonBranchStorageSnapshot, type NeonBucketSnapshot, type NeonCredentialMeta, type NeonCredentialSecret, type NeonDataApiSnapshot, type NeonDatabaseSnapshot, type NeonEndpointSnapshot, type NeonFunctionDeploymentSnapshot, type NeonFunctionSnapshot, type NeonProjectSnapshot, type NeonRoleSnapshot, PartialBranchCreateError, type PlanStep, PlatformError, type PostgresConfig, type PreviewInput, type PreviewTuning, PushAbortedError, PushConflictError, type PushResult, type RemotePreviewState, type RemoteServiceState, type RemoteState, type ResolvedBranchConfig, type ResolvedBucketConfig, type ResolvedDataApiConfig, type ResolvedFunctionConfig, type ResolvedPreviewConfig, type ServiceEnabled, type ServiceToggle, type ServiceToggleInput, type UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveApiKey, resolveConfig, schemas };
216
+ export { type AppliedChange, type BranchTarget, type BranchTuning, type BranchTuningFn, type BucketAccessLevel, type BucketDef, type ComputeSettings, type ComputeUnit, type Config, ConfigLoadError, ConfigValidationError, type ConflictReport, type CreateBranchInput, type CreateBucketInput, type CreateCredentialInput, type CreateProjectInput, type CredentialFeatureFlags, type CredentialPrincipalType, type CredentialScope, DATA_API_AUTH_PROVIDERS, type DataApiAuthProvider, type DataApiConfig, type DataApiExternalAuthConfig, type DataApiInput, type DataApiNeonAuthConfig, type DataApiSettings, type DeployFunctionInput, type DiffOptions, type DiffResult, type DurationString, type DurationUnit, type EnableDataApiInput, ErrorCode, type FunctionDef, type FunctionDevConfig, type FunctionRuntime, type FunctionTuning, type GetConnectionUriInput, type LoadConfigOptions, MissingContextError, type NeonApi, type NeonAuthSnapshot, type NeonBranchSnapshot, type NeonBranchStorageSnapshot, type NeonBucketSnapshot, type NeonCredentialMeta, type NeonCredentialSecret, type NeonDataApiSnapshot, type NeonDatabaseSnapshot, type NeonEndpointSnapshot, type NeonFunctionDeploymentSnapshot, type NeonFunctionSnapshot, type NeonProjectSnapshot, type NeonRoleSnapshot, PartialBranchCreateError, type PlanStep, PlatformError, type PostgresConfig, type PreviewInput, type PreviewTuning, PushAbortedError, PushConflictError, type PushResult, type RemotePreviewState, type RemoteServiceState, type RemoteState, type ResolvedBranchConfig, type ResolvedBucketConfig, type ResolvedDataApiConfig, type ResolvedFunctionConfig, type ResolvedPreviewConfig, type ServiceEnabled, type ServiceToggle, type ServiceToggleInput, type UpdateBranchInput, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
217
217
  //# sourceMappingURL=v1.d.ts.map
package/dist/v1.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ConfigLoadError, ConfigValidationError, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, isPartialBranchCreateError, isPlatformError } from "./lib/errors.js";
2
2
  import { branchTuningSchema, bucketDefSchema, computeSettingsSchema, configInputSchema, dataApiConfigSchema, dataApiInputSchema, dataApiSettingsSchema, functionDefSchema, functionTuningSchema, postgresConfigSchema, previewInputSchema, serviceToggleInputSchema, serviceToggleSchema } from "./lib/schema.js";
3
3
  import { createRealNeonApi } from "./lib/neon-api-real.js";
4
- import { createNeonApiFromOptions, resolveApiKey } from "./lib/auth.js";
4
+ import { createNeonApiFromOptions } from "./lib/auth.js";
5
5
  import { credentialScopesSatisfied, deriveCredentialScopes } from "./lib/credentials.js";
6
6
  import { defineConfig, resolveConfig } from "./lib/define-config.js";
7
7
  import { diffConfig } from "./lib/diff.js";
@@ -79,6 +79,6 @@ const schemas = {
79
79
  serviceInput: serviceToggleInputSchema
80
80
  };
81
81
  //#endregion
82
- export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveApiKey, resolveConfig, schemas };
82
+ export { ConfigLoadError, ConfigValidationError, DATA_API_AUTH_PROVIDERS, ErrorCode, MissingContextError, PartialBranchCreateError, PlatformError, PushAbortedError, PushConflictError, createNeonApiFromOptions, createRealNeonApi, credentialScopesSatisfied, defineConfig, deriveCredentialScopes, diffConfig, errors, isPartialBranchCreateError, isPlatformError, loadConfigFromFile, resolveConfig, schemas };
83
83
 
84
84
  //# sourceMappingURL=v1.js.map
package/dist/v1.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"v1.js","names":[],"sources":["../src/v1.ts"],"sourcesContent":["/**\n * `@neon/config/v1` — the v1 public API for Config-as-Code on Neon.\n *\n * Usage in `neon.ts`:\n * ```ts\n * import { defineConfig } from \"@neon/config/v1\";\n *\n * export default defineConfig({\n * // Static: what *exists* on every branch (drives the typed env).\n * auth: true,\n * // Dynamic: per-branch tuning only — cannot add/remove services.\n * branch: (branch) => ({\n * protected: branch.name === \"main\",\n * ...(branch.name === \"main\" ? {} : { parent: \"main\", ttl: \"7d\" }),\n * }),\n * });\n * ```\n *\n * This is the **authoring** surface — `defineConfig`, types, schemas, the pure diff engine,\n * and the Neon API adapter. It is intentionally free of heavy/native dependencies so that\n * importing it from `neon.ts` stays cheap and bundler-safe.\n *\n * The imperative operations (`inspect` / `plan` / `apply`, `pushConfig` / `pullConfig`) and\n * function bundling/deploy live in **`@neon/config-runtime`**, which depends on this\n * package and pulls in `esbuild`. Import that from your CLI / CI, not from `neon.ts`:\n * ```ts\n * import config from \"../neon\";\n * import { inspect, plan, apply } from \"@neon/config-runtime/v1\";\n * ```\n *\n * Surface guidelines:\n * - Top-level: `defineConfig` / `resolveConfig`, the pure `diffConfig` engine, the\n * `createRealNeonApi` adapter + `NeonApi` types, the config loader, the `PlatformError`\n * base class + `ErrorCode` enum, and the config types used in `neon.ts`.\n * - `errors` namespace: specific `PlatformError` subclasses (`ConfigLoadError`,\n * `PushConflictError`, …).\n * - `schemas` namespace: the zod schemas underlying `defineConfig`.\n */\n\nimport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nimport {\n\tbranchTuningSchema,\n\tbucketDefSchema,\n\tcomputeSettingsSchema,\n\tconfigInputSchema,\n\tdataApiConfigSchema,\n\tdataApiInputSchema,\n\tdataApiSettingsSchema,\n\tfunctionDefSchema,\n\tfunctionTuningSchema,\n\tpostgresConfigSchema,\n\tpreviewInputSchema,\n\tserviceToggleInputSchema,\n\tserviceToggleSchema,\n} from \"./lib/schema.js\";\n\n/**\n * Specific `PlatformError` subclasses, grouped for `instanceof` / structured access.\n * Also available as top-level exports.\n */\nexport const errors = {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} as const;\n\n/** The zod schemas underlying `defineConfig`, grouped under product-friendly names. */\nexport const schemas = {\n\tconfig: configInputSchema,\n\tbranchTuning: branchTuningSchema,\n\tbucket: bucketDefSchema,\n\tcomputeSettings: computeSettingsSchema,\n\tdataApi: dataApiConfigSchema,\n\tdataApiInput: dataApiInputSchema,\n\tdataApiSettings: dataApiSettingsSchema,\n\tfunction: functionDefSchema,\n\tfunctionTuning: functionTuningSchema,\n\tpostgres: postgresConfigSchema,\n\tpreview: previewInputSchema,\n\tservice: serviceToggleSchema,\n\tserviceInput: serviceToggleInputSchema,\n} as const;\n\n// ─── Lower-level adapters ──────────────────────────────────────────────────────\nexport { createNeonApiFromOptions, resolveApiKey } from \"./lib/auth.js\";\n// ─── Credentials (pure scope derivation; Preview) ─────────────────────────────\nexport type { CredentialFeatureFlags } from \"./lib/credentials.js\";\nexport {\n\tcredentialScopesSatisfied,\n\tderiveCredentialScopes,\n} from \"./lib/credentials.js\";\nexport { defineConfig, resolveConfig } from \"./lib/define-config.js\";\n// ─── Diff engine (pure; consumed by @neon/config-runtime) ─────────────\nexport type {\n\tDiffOptions,\n\tDiffResult,\n\tPlanStep,\n\tRemotePreviewState,\n\tRemoteServiceState,\n\tRemoteState,\n} from \"./lib/diff.js\";\nexport { diffConfig } from \"./lib/diff.js\";\n// ─── Errors ────────────────────────────────────────────────────────────────────\nexport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nexport type { LoadConfigOptions } from \"./lib/loader.js\";\nexport { loadConfigFromFile } from \"./lib/loader.js\";\n// ─── NeonApi types (needed by callers implementing their own adapters) ────────\nexport type {\n\tCreateBranchInput,\n\tCreateBucketInput,\n\tCreateCredentialInput,\n\tCreateProjectInput,\n\tDeployFunctionInput,\n\tEnableDataApiInput,\n\tGetConnectionUriInput,\n\tNeonApi,\n\tNeonAuthSnapshot,\n\tNeonBranchSnapshot,\n\tNeonBranchStorageSnapshot,\n\tNeonBucketSnapshot,\n\tNeonCredentialMeta,\n\tNeonCredentialSecret,\n\tNeonDataApiSnapshot,\n\tNeonDatabaseSnapshot,\n\tNeonEndpointSnapshot,\n\tNeonFunctionDeploymentSnapshot,\n\tNeonFunctionSnapshot,\n\tNeonProjectSnapshot,\n\tNeonRoleSnapshot,\n\tUpdateBranchInput,\n} from \"./lib/neon-api.js\";\nexport { createRealNeonApi } from \"./lib/neon-api-real.js\";\nexport type {\n\tAppliedChange,\n\tBranchTarget,\n\tBranchTuning,\n\tBranchTuningFn,\n\tBucketAccessLevel,\n\tBucketDef,\n\tComputeSettings,\n\tComputeUnit,\n\tConfig,\n\tConflictReport,\n\tCredentialPrincipalType,\n\tCredentialScope,\n\tDataApiAuthProvider,\n\tDataApiConfig,\n\tDataApiExternalAuthConfig,\n\tDataApiInput,\n\tDataApiNeonAuthConfig,\n\tDataApiSettings,\n\tDurationString,\n\tDurationUnit,\n\tFunctionDef,\n\tFunctionDevConfig,\n\tFunctionRuntime,\n\tFunctionTuning,\n\tPostgresConfig,\n\tPreviewInput,\n\tPreviewTuning,\n\tPushResult,\n\tResolvedBranchConfig,\n\tResolvedBucketConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedPreviewConfig,\n\tServiceEnabled,\n\tServiceToggle,\n\tServiceToggleInput,\n} from \"./lib/types.js\";\n// ─── Config types (used in neon.ts and in operation return values) ────────────\nexport { DATA_API_AUTH_PROVIDERS } from \"./lib/types.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,MAAa,SAAS;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;AAGA,MAAa,UAAU;CACtB,QAAQ;CACR,cAAc;CACd,QAAQ;CACR,iBAAiB;CACjB,SAAS;CACT,cAAc;CACd,iBAAiB;CACjB,UAAU;CACV,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,SAAS;CACT,cAAc;AACf"}
1
+ {"version":3,"file":"v1.js","names":[],"sources":["../src/v1.ts"],"sourcesContent":["/**\n * `@neon/config/v1` — the v1 public API for Config-as-Code on Neon.\n *\n * Usage in `neon.ts`:\n * ```ts\n * import { defineConfig } from \"@neon/config/v1\";\n *\n * export default defineConfig({\n * // Static: what *exists* on every branch (drives the typed env).\n * auth: true,\n * // Dynamic: per-branch tuning only — cannot add/remove services.\n * branch: (branch) => ({\n * protected: branch.name === \"main\",\n * ...(branch.name === \"main\" ? {} : { parent: \"main\", ttl: \"7d\" }),\n * }),\n * });\n * ```\n *\n * This is the **authoring** surface — `defineConfig`, types, schemas, the pure diff engine,\n * and the Neon API adapter. It is intentionally free of heavy/native dependencies so that\n * importing it from `neon.ts` stays cheap and bundler-safe.\n *\n * The imperative operations (`inspect` / `plan` / `apply`, `pushConfig` / `pullConfig`) and\n * function bundling/deploy live in **`@neon/config-runtime`**, which depends on this\n * package and pulls in `esbuild`. Import that from your CLI / CI, not from `neon.ts`:\n * ```ts\n * import config from \"../neon\";\n * import { inspect, plan, apply } from \"@neon/config-runtime/v1\";\n * ```\n *\n * Surface guidelines:\n * - Top-level: `defineConfig` / `resolveConfig`, the pure `diffConfig` engine, the\n * `createRealNeonApi` adapter + `NeonApi` types, the config loader, the `PlatformError`\n * base class + `ErrorCode` enum, and the config types used in `neon.ts`.\n * - `errors` namespace: specific `PlatformError` subclasses (`ConfigLoadError`,\n * `PushConflictError`, …).\n * - `schemas` namespace: the zod schemas underlying `defineConfig`.\n */\n\nimport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nimport {\n\tbranchTuningSchema,\n\tbucketDefSchema,\n\tcomputeSettingsSchema,\n\tconfigInputSchema,\n\tdataApiConfigSchema,\n\tdataApiInputSchema,\n\tdataApiSettingsSchema,\n\tfunctionDefSchema,\n\tfunctionTuningSchema,\n\tpostgresConfigSchema,\n\tpreviewInputSchema,\n\tserviceToggleInputSchema,\n\tserviceToggleSchema,\n} from \"./lib/schema.js\";\n\n/**\n * Specific `PlatformError` subclasses, grouped for `instanceof` / structured access.\n * Also available as top-level exports.\n */\nexport const errors = {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} as const;\n\n/** The zod schemas underlying `defineConfig`, grouped under product-friendly names. */\nexport const schemas = {\n\tconfig: configInputSchema,\n\tbranchTuning: branchTuningSchema,\n\tbucket: bucketDefSchema,\n\tcomputeSettings: computeSettingsSchema,\n\tdataApi: dataApiConfigSchema,\n\tdataApiInput: dataApiInputSchema,\n\tdataApiSettings: dataApiSettingsSchema,\n\tfunction: functionDefSchema,\n\tfunctionTuning: functionTuningSchema,\n\tpostgres: postgresConfigSchema,\n\tpreview: previewInputSchema,\n\tservice: serviceToggleSchema,\n\tserviceInput: serviceToggleInputSchema,\n} as const;\n\n// ─── Lower-level adapters ──────────────────────────────────────────────────────\nexport { createNeonApiFromOptions } from \"./lib/auth.js\";\n// ─── Credentials (pure scope derivation; Preview) ─────────────────────────────\nexport type { CredentialFeatureFlags } from \"./lib/credentials.js\";\nexport {\n\tcredentialScopesSatisfied,\n\tderiveCredentialScopes,\n} from \"./lib/credentials.js\";\nexport { defineConfig, resolveConfig } from \"./lib/define-config.js\";\n// ─── Diff engine (pure; consumed by @neon/config-runtime) ─────────────\nexport type {\n\tDiffOptions,\n\tDiffResult,\n\tPlanStep,\n\tRemotePreviewState,\n\tRemoteServiceState,\n\tRemoteState,\n} from \"./lib/diff.js\";\nexport { diffConfig } from \"./lib/diff.js\";\n// ─── Errors ────────────────────────────────────────────────────────────────────\nexport {\n\tConfigLoadError,\n\tConfigValidationError,\n\tErrorCode,\n\tisPartialBranchCreateError,\n\tisPlatformError,\n\tMissingContextError,\n\tPartialBranchCreateError,\n\tPlatformError,\n\tPushAbortedError,\n\tPushConflictError,\n} from \"./lib/errors.js\";\nexport type { LoadConfigOptions } from \"./lib/loader.js\";\nexport { loadConfigFromFile } from \"./lib/loader.js\";\n// ─── NeonApi types (needed by callers implementing their own adapters) ────────\nexport type {\n\tCreateBranchInput,\n\tCreateBucketInput,\n\tCreateCredentialInput,\n\tCreateProjectInput,\n\tDeployFunctionInput,\n\tEnableDataApiInput,\n\tGetConnectionUriInput,\n\tNeonApi,\n\tNeonAuthSnapshot,\n\tNeonBranchSnapshot,\n\tNeonBranchStorageSnapshot,\n\tNeonBucketSnapshot,\n\tNeonCredentialMeta,\n\tNeonCredentialSecret,\n\tNeonDataApiSnapshot,\n\tNeonDatabaseSnapshot,\n\tNeonEndpointSnapshot,\n\tNeonFunctionDeploymentSnapshot,\n\tNeonFunctionSnapshot,\n\tNeonProjectSnapshot,\n\tNeonRoleSnapshot,\n\tUpdateBranchInput,\n} from \"./lib/neon-api.js\";\nexport { createRealNeonApi } from \"./lib/neon-api-real.js\";\nexport type {\n\tAppliedChange,\n\tBranchTarget,\n\tBranchTuning,\n\tBranchTuningFn,\n\tBucketAccessLevel,\n\tBucketDef,\n\tComputeSettings,\n\tComputeUnit,\n\tConfig,\n\tConflictReport,\n\tCredentialPrincipalType,\n\tCredentialScope,\n\tDataApiAuthProvider,\n\tDataApiConfig,\n\tDataApiExternalAuthConfig,\n\tDataApiInput,\n\tDataApiNeonAuthConfig,\n\tDataApiSettings,\n\tDurationString,\n\tDurationUnit,\n\tFunctionDef,\n\tFunctionDevConfig,\n\tFunctionRuntime,\n\tFunctionTuning,\n\tPostgresConfig,\n\tPreviewInput,\n\tPreviewTuning,\n\tPushResult,\n\tResolvedBranchConfig,\n\tResolvedBucketConfig,\n\tResolvedDataApiConfig,\n\tResolvedFunctionConfig,\n\tResolvedPreviewConfig,\n\tServiceEnabled,\n\tServiceToggle,\n\tServiceToggleInput,\n} from \"./lib/types.js\";\n// ─── Config types (used in neon.ts and in operation return values) ────────────\nexport { DATA_API_AUTH_PROVIDERS } from \"./lib/types.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,MAAa,SAAS;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;AAGA,MAAa,UAAU;CACtB,QAAQ;CACR,cAAc;CACd,QAAQ;CACR,iBAAiB;CACjB,SAAS;CACT,cAAc;CACd,iBAAiB;CACjB,UAAU;CACV,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,SAAS;CACT,cAAc;AACf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neondatabase/config",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Config-as-Code for Neon. Define a `neon.ts` policy and inspect/diff/deploy it against the Neon API as plain TypeScript functions.",
5
5
  "keywords": [
6
6
  "neon",
@@ -32,6 +32,11 @@
32
32
  "types": "./dist/v1.d.ts",
33
33
  "import": "./dist/v1.js",
34
34
  "default": "./dist/v1.js"
35
+ },
36
+ "./paths": {
37
+ "types": "./dist/paths.d.ts",
38
+ "import": "./dist/paths.js",
39
+ "default": "./dist/paths.js"
35
40
  }
36
41
  },
37
42
  "files": [