@theholocron/holocron-plugin-neon 2.0.0-alpha.0 → 2.0.0-alpha.10

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
@@ -3,6 +3,12 @@
3
3
  Neon plugin for [Holocron](../cli). Implements the `storage`
4
4
  capability against [Neon's REST API](https://api-docs.neon.tech/reference/getting-started-with-neon-api).
5
5
 
6
+ ## Install
7
+
8
+ ```bash
9
+ pnpm add -D @theholocron/holocron-plugin-neon@alpha
10
+ ```
11
+
6
12
  ## Auth
7
13
 
8
14
  Token resolution order:
@@ -15,25 +21,25 @@ Token resolution order:
15
21
 
16
22
  ```jsonc
17
23
  {
18
- "providers": {
19
- "storage": ["neon", { "projectId": "ancient-resonance-…" }]
20
- }
24
+ "providers": {
25
+ "storage": ["neon", { "projectId": "ancient-resonance-…" }],
26
+ },
21
27
  }
22
28
  ```
23
29
 
24
30
  - `projectId` (required) — the Neon project id. The plugin binds to
25
- this project; every method operates within it.
31
+ this project; every method operates within it.
26
32
 
27
33
  ## What's implemented
28
34
 
29
- | Method | What it does |
30
- | ----------------------- | --------------------------------------------------------- |
31
- | `getConnectionString` | Fetches the connection URI for a branch. `pooled: true` returns the PgBouncer URL. |
32
- | `listBranches` | All branches on the bound project. |
33
- | `createBranch` | Provisions a branch + a read_write compute endpoint inline (so the next connection-string call doesn't 404). |
34
- | `destroyBranch` | DELETEs a branch. |
35
- | `resetBranch` | Restores one branch to match another (Neon "restore branch" endpoint). |
36
- | `enableExtension` | Runs `CREATE EXTENSION IF NOT EXISTS "..."` against the branch's default database via Neon's run_sql endpoint. Used for PostGIS, pgvector, etc. |
35
+ | Method | What it does |
36
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
37
+ | `getConnectionString` | Fetches the connection URI for a branch. `pooled: true` returns the PgBouncer URL. |
38
+ | `listBranches` | All branches on the bound project. |
39
+ | `createBranch` | Provisions a branch + a read_write compute endpoint inline (so the next connection-string call doesn't 404). |
40
+ | `destroyBranch` | DELETEs a branch. |
41
+ | `resetBranch` | Restores one branch to match another (Neon "restore branch" endpoint). |
42
+ | `enableExtension` | Runs `CREATE EXTENSION IF NOT EXISTS "..."` against the branch's default database via Neon's run_sql endpoint. Used for PostGIS, pgvector, etc. |
37
43
 
38
44
  Vercel-managed Neon orgs reject project-create at the Neon API level
39
45
  ("organization is managed by Vercel"). For those setups, provision
@@ -45,4 +51,6 @@ later).
45
51
 
46
52
  ## Status
47
53
 
48
- **v0.0.0 — first port.**
54
+ **`v2.0.0-alpha.0`**published on npm under the `alpha` dist-tag.
55
+ [Release notes](https://github.com/theholocron/holocron/releases/tag/v2.0.0-alpha.0).
56
+ APIs may still shift before stable v2.0.0.
package/dist/index.d.mts CHANGED
@@ -4,10 +4,13 @@ import { ConnectionStringOptions, Storage, StorageBranch } from "@theholocron/cl
4
4
  /**
5
5
  * Token resolution for the Neon plugin.
6
6
  *
7
- * Resolution order:
7
+ * Resolution order (matches the standard 4-step precedence set by
8
+ * `.notes/tech-auth-bootstrap.spec.md`):
8
9
  * 1. explicit `cliToken` argument (from `--token` flag)
9
10
  * 2. HOLOCRON_NEON_API_KEY env var (preferred — explicit intent)
10
11
  * 3. NEON_API_KEY env var (the default Neon CLI reads)
12
+ * 4. keyring (com.theholocron.cli / "neon")
13
+ * 5. AuthError naming all four options + the bootstrap hint
11
14
  */
12
15
  declare class AuthError extends Error {
13
16
  name: string;
@@ -17,6 +20,8 @@ interface ResolveTokenInput {
17
20
  cliToken?: string;
18
21
  /** Env vars; passed in for testability. Defaults to `process.env`. */
19
22
  env?: NodeJS.ProcessEnv;
23
+ /** Keyring lookup fn; passed in for testability. Defaults to `getToken(provider)`. */
24
+ keyring?: (provider: string) => string | null;
20
25
  }
21
26
  declare function resolveToken(input?: ResolveTokenInput): string;
22
27
  //#endregion
@@ -35,7 +40,7 @@ interface RestClientOptions {
35
40
  baseUrl?: string;
36
41
  }
37
42
  interface RequestOptions {
38
- method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
43
+ method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
39
44
  body?: unknown;
40
45
  query?: Record<string, string>;
41
46
  }
@@ -80,6 +85,28 @@ declare class NeonStorage implements Storage {
80
85
  private firstDatabase;
81
86
  }
82
87
  //#endregion
88
+ //#region src/verify-token.d.ts
89
+ /**
90
+ * `verifyToken` — plugin-level export used by `holocron auth set` +
91
+ * `holocron auth check`. Hits Neon's `/users/me` endpoint and
92
+ * translates the response into the normalized `VerifyTokenResult`
93
+ * shape.
94
+ */
95
+ interface VerifyTokenSuccess {
96
+ ok: true;
97
+ subject: string;
98
+ }
99
+ interface VerifyTokenFailure {
100
+ ok: false;
101
+ message: string;
102
+ }
103
+ type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
104
+ interface VerifyTokenOptions {
105
+ baseUrl?: string;
106
+ fetch?: typeof fetch;
107
+ }
108
+ declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
109
+ //#endregion
83
110
  //#region src/index.d.ts
84
111
  interface NeonPluginOptions extends ResolveTokenInput {
85
112
  /** Neon project id this plugin is bound to. Required. */
@@ -101,5 +128,12 @@ declare function createPlugin(options: NeonPluginOptions): {
101
128
  storage: () => Storage;
102
129
  };
103
130
  };
131
+ /**
132
+ * One-line hint printed by `holocron auth set neon` when no token
133
+ * is supplied or the supplied token is rejected. Points operators
134
+ * at https://console.neon.tech/app/settings/api-keys where API keys
135
+ * are minted.
136
+ */
137
+ declare const AUTH_HINT: string;
104
138
  //#endregion
105
- export { AuthError, NeonPluginOptions, NeonRestClient, NeonStorage, PluginContext, ResolveTokenInput, createContext, createPlugin, resolveToken, storage };
139
+ export { AUTH_HINT, AuthError, NeonPluginOptions, NeonRestClient, NeonStorage, PluginContext, ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin, resolveToken, storage, verifyToken };
package/dist/index.mjs CHANGED
@@ -1,20 +1,24 @@
1
- import { ProviderApiError } from "@theholocron/cli";
1
+ import { ProviderApiError, getToken } from "@theholocron/cli";
2
2
  //#region src/auth.ts
3
3
  /**
4
4
  * Token resolution for the Neon plugin.
5
5
  *
6
- * Resolution order:
6
+ * Resolution order (matches the standard 4-step precedence set by
7
+ * `.notes/tech-auth-bootstrap.spec.md`):
7
8
  * 1. explicit `cliToken` argument (from `--token` flag)
8
9
  * 2. HOLOCRON_NEON_API_KEY env var (preferred — explicit intent)
9
10
  * 3. NEON_API_KEY env var (the default Neon CLI reads)
11
+ * 4. keyring (com.theholocron.cli / "neon")
12
+ * 5. AuthError naming all four options + the bootstrap hint
10
13
  */
11
14
  var AuthError = class extends Error {
12
15
  name = "AuthError";
13
16
  };
14
17
  function resolveToken(input = {}) {
15
18
  const env = input.env ?? process.env;
16
- const token = input.cliToken || env.HOLOCRON_NEON_API_KEY || env.NEON_API_KEY;
17
- if (!token) throw new AuthError("no Neon API key found. Pass --token <KEY>, or set HOLOCRON_NEON_API_KEY / NEON_API_KEY.");
19
+ const keyring = input.keyring ?? getToken;
20
+ const token = input.cliToken || env["HOLOCRON_NEON_API_KEY"] || env["NEON_API_KEY"] || keyring("neon");
21
+ if (!token) throw new AuthError("no Neon API key found. Pass --token <KEY>, set HOLOCRON_NEON_API_KEY / NEON_API_KEY, or run: holocron auth set neon <KEY>");
18
22
  return token;
19
23
  }
20
24
  //#endregion
@@ -124,7 +128,9 @@ var NeonRestClient = class {
124
128
  constructor(opts) {
125
129
  this.token = opts.token;
126
130
  this.fetchImpl = opts.fetch ?? globalThis.fetch;
127
- this.baseUrl = (opts.baseUrl ?? "https://console.neon.tech/api/v2").replace(/\/+$/, "");
131
+ let url = opts.baseUrl ?? "https://console.neon.tech/api/v2";
132
+ while (url.endsWith("/")) url = url.slice(0, -1);
133
+ this.baseUrl = url;
128
134
  }
129
135
  async request(path, opts = {}) {
130
136
  const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : "/" + path}`);
@@ -160,6 +166,32 @@ var NeonRestClient = class {
160
166
  }
161
167
  };
162
168
  //#endregion
169
+ //#region src/verify-token.ts
170
+ /**
171
+ * `verifyToken` — plugin-level export used by `holocron auth set` +
172
+ * `holocron auth check`. Hits Neon's `/users/me` endpoint and
173
+ * translates the response into the normalized `VerifyTokenResult`
174
+ * shape.
175
+ */
176
+ async function verifyToken(token, opts = {}) {
177
+ const restOpts = { token };
178
+ if (opts.baseUrl !== void 0) restOpts.baseUrl = opts.baseUrl;
179
+ if (opts.fetch !== void 0) restOpts.fetch = opts.fetch;
180
+ const rest = new NeonRestClient(restOpts);
181
+ try {
182
+ const me = await rest.request("/users/me");
183
+ return {
184
+ ok: true,
185
+ subject: `user @ ${me?.email ?? me?.login ?? me?.name ?? me?.id ?? "unknown"}`
186
+ };
187
+ } catch (err) {
188
+ return {
189
+ ok: false,
190
+ message: err instanceof Error ? err.message : String(err)
191
+ };
192
+ }
193
+ }
194
+ //#endregion
163
195
  //#region src/index.ts
164
196
  function createContext(options) {
165
197
  if (!options.projectId) throw new Error("@theholocron/holocron-plugin-neon requires `projectId` in options");
@@ -181,5 +213,12 @@ function createPlugin(options) {
181
213
  capabilities: { storage: () => storage(ctx) }
182
214
  };
183
215
  }
216
+ /**
217
+ * One-line hint printed by `holocron auth set neon` when no token
218
+ * is supplied or the supplied token is rejected. Points operators
219
+ * at https://console.neon.tech/app/settings/api-keys where API keys
220
+ * are minted.
221
+ */
222
+ const AUTH_HINT = "generate a Neon API key at https://console.neon.tech/app/settings/api-keys, then run: holocron auth set neon <KEY>";
184
223
  //#endregion
185
- export { AuthError, NeonRestClient, NeonStorage, createContext, createPlugin, resolveToken, storage };
224
+ export { AUTH_HINT, AuthError, NeonRestClient, NeonStorage, createContext, createPlugin, resolveToken, storage, verifyToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/holocron-plugin-neon",
3
- "version": "2.0.0-alpha.0",
3
+ "version": "2.0.0-alpha.10",
4
4
  "description": "Holocron plugin for Neon. Implements the storage capability against Neon's REST API — branch ops, connection strings, extensions.",
5
5
  "homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-neon#readme",
6
6
  "bugs": "https://github.com/theholocron/holocron/issues",
@@ -21,7 +21,7 @@
21
21
  }
22
22
  },
23
23
  "peerDependencies": {
24
- "@theholocron/cli": "2.0.0-alpha.0"
24
+ "@theholocron/cli": "2.0.0-alpha.10"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@theholocron/tsconfig": "^4.1.0",
@@ -32,7 +32,8 @@
32
32
  "typescript": "^5.9.3",
33
33
  "vitest": "^3.2.6",
34
34
  "tsdown": "^0.22.3",
35
- "@theholocron/cli": "2.0.0-alpha.0"
35
+ "tsx": "^4.22.4",
36
+ "@theholocron/cli": "2.0.0-alpha.10"
36
37
  },
37
38
  "publishConfig": {
38
39
  "access": "public"
@@ -47,7 +48,8 @@
47
48
  "typecheck": "tsc --noEmit",
48
49
  "test": "vitest run",
49
50
  "test:watch": "vitest",
50
- "test:coverage": "vitest run --coverage"
51
+ "test:coverage": "vitest run --coverage",
52
+ "validate": "tsx scripts/validate.mjs"
51
53
  },
52
54
  "types": "./dist/index.d.mts"
53
55
  }