@theholocron/holocron-plugin-neon 2.0.0-alpha.20 → 2.0.0-alpha.22

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
@@ -1,3 +1,5 @@
1
+ <!-- editorconfig-checker-disable-file -->
2
+
1
3
  # `@theholocron/holocron-plugin-neon`
2
4
 
3
5
  Neon plugin for [Holocron](../cli). Implements the `storage`
@@ -28,7 +30,7 @@ Token resolution order:
28
30
  ```
29
31
 
30
32
  - `projectId` (required) — the Neon project id. The plugin binds to
31
- this project; every method operates within it.
33
+ this project; every method operates within it.
32
34
 
33
35
  ## What's implemented
34
36
 
package/dist/index.d.mts CHANGED
@@ -1,56 +1,14 @@
1
- import { ConnectionStringOptions, Storage, StorageBranch } from "@theholocron/cli";
1
+ import { AuthError, ConnectionStringOptions, ResolveTokenInput, RestClient, RestClient as RestClient$1, Storage, StorageBranch } from "@theholocron/cli";
2
2
 
3
3
  //#region src/auth.d.ts
4
- /**
5
- * Token resolution for the Neon plugin.
6
- *
7
- * Resolution order (matches the standard 4-step precedence set by
8
- * `.notes/tech-auth-bootstrap.spec.md`):
9
- * 1. explicit `cliToken` argument (from `--token` flag)
10
- * 2. HOLOCRON_NEON_API_KEY env var (preferred — explicit intent)
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
14
- */
15
- declare class AuthError extends Error {
16
- name: string;
17
- }
18
- interface ResolveTokenInput {
19
- /** From `--token` CLI flag. */
20
- cliToken?: string;
21
- /** Env vars; passed in for testability. Defaults to `process.env`. */
22
- env?: NodeJS.ProcessEnv;
23
- /** Keyring lookup fn; passed in for testability. Defaults to `getToken(provider)`. */
24
- keyring?: (provider: string) => string | null;
25
- }
26
- declare function resolveToken(input?: ResolveTokenInput): string;
4
+ declare const resolveToken: (input?: import("@theholocron/http-client").ResolveTokenInput) => string;
27
5
  //#endregion
28
6
  //#region src/rest.d.ts
29
- /**
30
- * Thin REST wrapper around console.neon.tech/api/v2.
31
- *
32
- * Same pattern as the GitHub + Vercel REST clients — bearer auth,
33
- * JSON-only bodies, transport-failure wrapping with status: 0 so the
34
- * orchestrator's soft-skip path sees a clear "Neon GET /path failed"
35
- * message instead of a generic `TypeError: fetch failed`.
36
- */
37
- interface RestClientOptions {
7
+ declare function createNeonRestClient(opts: {
38
8
  token: string;
39
- fetch?: typeof fetch;
40
9
  baseUrl?: string;
41
- }
42
- interface RequestOptions {
43
- method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
44
- body?: unknown;
45
- query?: Record<string, string>;
46
- }
47
- declare class NeonRestClient {
48
- private readonly token;
49
- private readonly fetchImpl;
50
- readonly baseUrl: string;
51
- constructor(opts: RestClientOptions);
52
- request<T>(path: string, opts?: RequestOptions): Promise<T>;
53
- }
10
+ fetch?: typeof fetch;
11
+ }): RestClient$1;
54
12
  //#endregion
55
13
  //#region src/capabilities/storage.d.ts
56
14
  interface StorageOptions {
@@ -61,7 +19,7 @@ declare class NeonStorage implements Storage {
61
19
  readonly key: "storage";
62
20
  readonly providerName = "neon";
63
21
  private readonly base;
64
- constructor(rest: NeonRestClient, opts: StorageOptions);
22
+ constructor(rest: RestClient, opts: StorageOptions);
65
23
  getConnectionString(scope: string, options?: ConnectionStringOptions): Promise<string>;
66
24
  listBranches(): Promise<StorageBranch[]>;
67
25
  createBranch(input: {
@@ -118,7 +76,7 @@ interface NeonPluginOptions extends ResolveTokenInput {
118
76
  }
119
77
  interface PluginContext {
120
78
  options: NeonPluginOptions;
121
- rest: NeonRestClient;
79
+ rest: RestClient;
122
80
  }
123
81
  declare function createContext(options: NeonPluginOptions): PluginContext;
124
82
  declare function storage(ctx: PluginContext): Storage;
@@ -136,4 +94,4 @@ declare function createPlugin(options: NeonPluginOptions): {
136
94
  */
137
95
  declare const AUTH_HINT: string;
138
96
  //#endregion
139
- export { AUTH_HINT, AuthError, NeonPluginOptions, NeonRestClient, NeonStorage, PluginContext, ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createPlugin, resolveToken, storage, verifyToken };
97
+ export { AUTH_HINT, AuthError, NeonPluginOptions, NeonStorage, PluginContext, type ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createContext, createNeonRestClient, createPlugin, resolveToken, storage, verifyToken };
package/dist/index.mjs CHANGED
@@ -1,26 +1,11 @@
1
- import { ProviderApiError, getToken } from "@theholocron/cli";
1
+ import { AuthError, ProviderApiError, createResolveToken, createRestClient } from "@theholocron/cli";
2
2
  //#region src/auth.ts
3
- /**
4
- * Token resolution for the Neon plugin.
5
- *
6
- * Resolution order (matches the standard 4-step precedence set by
7
- * `.notes/tech-auth-bootstrap.spec.md`):
8
- * 1. explicit `cliToken` argument (from `--token` flag)
9
- * 2. HOLOCRON_NEON_API_KEY env var (preferred — explicit intent)
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
13
- */
14
- var AuthError = class extends Error {
15
- name = "AuthError";
16
- };
17
- function resolveToken(input = {}) {
18
- const env = input.env ?? process.env;
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>");
22
- return token;
23
- }
3
+ const resolveToken = createResolveToken({
4
+ envName: "HOLOCRON_NEON_API_KEY",
5
+ vendorEnvName: "NEON_API_KEY",
6
+ keyringService: "neon",
7
+ errorMessage: "no Neon API key found. Pass --token <KEY>, set HOLOCRON_NEON_API_KEY / NEON_API_KEY, or run: holocron auth set neon <KEY>"
8
+ });
24
9
  //#endregion
25
10
  //#region src/capabilities/storage.ts
26
11
  /**
@@ -113,58 +98,14 @@ function mapBranch(raw) {
113
98
  }
114
99
  //#endregion
115
100
  //#region src/rest.ts
116
- /**
117
- * Thin REST wrapper around console.neon.tech/api/v2.
118
- *
119
- * Same pattern as the GitHub + Vercel REST clients — bearer auth,
120
- * JSON-only bodies, transport-failure wrapping with status: 0 so the
121
- * orchestrator's soft-skip path sees a clear "Neon GET /path failed"
122
- * message instead of a generic `TypeError: fetch failed`.
123
- */
124
- var NeonRestClient = class {
125
- token;
126
- fetchImpl;
127
- baseUrl;
128
- constructor(opts) {
129
- this.token = opts.token;
130
- this.fetchImpl = opts.fetch ?? globalThis.fetch;
131
- let url = opts.baseUrl ?? "https://console.neon.tech/api/v2";
132
- while (url.endsWith("/")) url = url.slice(0, -1);
133
- this.baseUrl = url;
134
- }
135
- async request(path, opts = {}) {
136
- const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : "/" + path}`);
137
- for (const [k, v] of Object.entries(opts.query ?? {})) url.searchParams.set(k, v);
138
- const fullUrl = url.toString();
139
- const headers = {
140
- authorization: `Bearer ${this.token}`,
141
- accept: "application/json"
142
- };
143
- const init = {
144
- method: opts.method ?? "GET",
145
- headers
146
- };
147
- if (opts.body !== void 0) {
148
- headers["content-type"] = "application/json";
149
- init.body = JSON.stringify(opts.body);
150
- }
151
- let res;
152
- try {
153
- res = await this.fetchImpl(fullUrl, init);
154
- } catch (err) {
155
- const detail = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
156
- throw new ProviderApiError(`Neon ${init.method} ${path} failed: ${detail}`, 0, void 0);
157
- }
158
- if (!res.ok) {
159
- const body = await res.text().catch(() => "");
160
- throw new ProviderApiError(`Neon ${init.method} ${path} → ${res.status}`, res.status, body);
161
- }
162
- if (res.status === 204) return void 0;
163
- const text = await res.text();
164
- if (!text) return void 0;
165
- return JSON.parse(text);
166
- }
167
- };
101
+ function createNeonRestClient(opts) {
102
+ return createRestClient({
103
+ baseUrl: opts.baseUrl ?? "https://console.neon.tech/api/v2",
104
+ token: opts.token,
105
+ vendor: "Neon",
106
+ fetch: opts.fetch
107
+ });
108
+ }
168
109
  //#endregion
169
110
  //#region src/verify-token.ts
170
111
  /**
@@ -174,10 +115,11 @@ var NeonRestClient = class {
174
115
  * shape.
175
116
  */
176
117
  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);
118
+ const rest = createNeonRestClient({
119
+ token,
120
+ baseUrl: opts.baseUrl,
121
+ fetch: opts.fetch
122
+ });
181
123
  try {
182
124
  const me = await rest.request("/users/me");
183
125
  return {
@@ -195,12 +137,13 @@ async function verifyToken(token, opts = {}) {
195
137
  //#region src/index.ts
196
138
  function createContext(options) {
197
139
  if (!options.projectId) throw new Error("@theholocron/holocron-plugin-neon requires `projectId` in options");
198
- const restOpts = { token: resolveToken(options) };
199
- if (options.baseUrl !== void 0) restOpts.baseUrl = options.baseUrl;
200
- if (options.fetch !== void 0) restOpts.fetch = options.fetch;
201
140
  return {
202
141
  options,
203
- rest: new NeonRestClient(restOpts)
142
+ rest: createNeonRestClient({
143
+ token: resolveToken(options),
144
+ baseUrl: options.baseUrl,
145
+ fetch: options.fetch
146
+ })
204
147
  };
205
148
  }
206
149
  function storage(ctx) {
@@ -221,4 +164,4 @@ function createPlugin(options) {
221
164
  */
222
165
  const AUTH_HINT = "generate a Neon API key at https://console.neon.tech/app/settings/api-keys, then run: holocron auth set neon <KEY>";
223
166
  //#endregion
224
- export { AUTH_HINT, AuthError, NeonRestClient, NeonStorage, createContext, createPlugin, resolveToken, storage, verifyToken };
167
+ export { AUTH_HINT, AuthError, NeonStorage, createContext, createNeonRestClient, 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.20",
3
+ "version": "2.0.0-alpha.22",
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,13 +21,14 @@
21
21
  }
22
22
  },
23
23
  "peerDependencies": {
24
- "@theholocron/cli": "2.0.0-alpha.20"
24
+ "@theholocron/cli": "2.0.0-alpha.22"
25
25
  },
26
26
  "devDependencies": {
27
- "@theholocron/eslint-config": "^5.1.2",
28
- "@theholocron/tsconfig": "^5.1.2",
29
- "@tsconfig/node-lts": "^24.0.0",
30
- "@vitest/coverage-v8": "^3.2.6",
27
+ "@types/node": "^26",
28
+ "@theholocron/eslint-config": "^5.2.0",
29
+ "@theholocron/tsconfig": "^6.0.0",
30
+ "@theholocron/tsdown-config": "^5.1.2",
31
+ "@theholocron/vitest-config": "^5.2.0",
31
32
  "@vitest/eslint-plugin": "^1.6.23",
32
33
  "eslint": "^10.7.0",
33
34
  "eslint-plugin-n": "^18.2.2",
@@ -35,8 +36,8 @@
35
36
  "tsdown": "^0.22.3",
36
37
  "tsx": "^4.22.4",
37
38
  "typescript": "^5.9.3",
38
- "vitest": "^3.2.6",
39
- "@theholocron/cli": "2.0.0-alpha.20"
39
+ "vitest": "^4.1.10",
40
+ "@theholocron/cli": "2.0.0-alpha.22"
40
41
  },
41
42
  "publishConfig": {
42
43
  "access": "public"