@neondatabase/config 0.8.0 → 0.9.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.
@@ -2,9 +2,24 @@ import { ErrorCode, PlatformError } from "./errors.js";
2
2
  import { formatSuspendTimeout, parseSuspendTimeout } from "./duration.js";
3
3
  import { wrapNeonError } from "./wrap-neon-error.js";
4
4
  import { z } from "zod";
5
- import { EndpointType, createApiClient } from "@neondatabase/api-client";
5
+ import { createNeonClient } from "@neon/sdk";
6
+ import { createProject, createProjectBranch, createProjectBranchDataApi, getConnectionUri, getNeonAuth, getProject, getProjectBranchDataApi, listProjectBranchDatabases, listProjectBranchRoles, listProjectBranches, listProjectEndpoints, listProjects, updateProject, updateProjectBranch, updateProjectBranchDataApi, updateProjectEndpoint } from "@neon/sdk/raw";
6
7
  //#region src/lib/neon-api-real.ts
7
8
  const DEFAULT_NEON_API_BASE_URL = "https://console.neon.tech/api/v2";
9
+ /**
10
+ * Unwrap a `@neon/sdk` raw `{ data, error, response }` result into the bare body, throwing
11
+ * on a non-2xx response. The thrown shape (`{ response: { status, data } }`) deliberately
12
+ * matches what the package's REST fallbacks already throw, so {@link wrapNeonError} and the
13
+ * 423 {@link retryOnLocked} retry keep working unchanged across both transports.
14
+ */
15
+ function unwrap(result) {
16
+ const response = result.response;
17
+ if (!response || !response.ok) throw { response: {
18
+ status: response?.status,
19
+ data: result.error
20
+ } };
21
+ return result.data;
22
+ }
8
23
  const neonAuthResponseSchema = z.object({
9
24
  auth_provider_project_id: z.string(),
10
25
  pub_client_key: z.string().optional(),
@@ -129,16 +144,18 @@ const credentialMetaSchema = z.object({
129
144
  });
130
145
  const listCredentialsResponseSchema = z.object({ credentials: z.array(credentialMetaSchema) });
131
146
  /**
132
- * Adapt `@neondatabase/api-client` to the narrow {@link NeonApi} façade used by the rest of
147
+ * Adapt `@neon/sdk` (raw layer) to the narrow {@link NeonApi} façade used by the rest of
133
148
  * this package. Constructs are restricted to whole-object read/write of just the fields we
134
149
  * model in {@link Config}; anything else stays untouched on the remote.
135
150
  */
136
151
  function createRealNeonApi(options) {
137
152
  if (!options.apiKey || options.apiKey.trim() === "") throw new PlatformError(ErrorCode.MissingApiKey, ["createRealNeonApi requires a non-empty `apiKey`.", "Generate one at https://console.neon.tech/app/settings/api-keys and pass it as { apiKey: process.env.NEON_API_KEY }."].join(" "));
138
- return new RealNeonApi(createApiClient({
153
+ const client = createNeonClient({
139
154
  apiKey: options.apiKey,
140
- ...options.baseUrl ? { baseURL: options.baseUrl } : {}
141
- }), {
155
+ retries: 0,
156
+ ...options.baseUrl ? { baseUrl: options.baseUrl } : {}
157
+ }).client;
158
+ return new RealNeonApi(client, {
142
159
  maxAttempts: options.retryOnLocked?.maxAttempts ?? 12,
143
160
  initialDelayMs: options.retryOnLocked?.initialDelayMs ?? 250,
144
161
  maxDelayMs: options.retryOnLocked?.maxDelayMs ?? 5e3
@@ -204,13 +221,16 @@ var RealNeonApi = class {
204
221
  const projects = [];
205
222
  let cursor;
206
223
  while (true) {
207
- const res = await this.client.listProjects({
208
- ...filter.orgId ? { org_id: filter.orgId } : {},
209
- ...cursor ? { cursor } : {},
210
- limit: 100
211
- });
212
- projects.push(...res.data.projects);
213
- const next = res.data.pagination?.next;
224
+ const body = unwrap(await listProjects({
225
+ client: this.client,
226
+ query: {
227
+ ...filter.orgId ? { org_id: filter.orgId } : {},
228
+ ...cursor ? { cursor } : {},
229
+ limit: 100
230
+ }
231
+ }));
232
+ projects.push(...body.projects);
233
+ const next = body.pagination?.next;
214
234
  if (!next || next === cursor) break;
215
235
  cursor = next;
216
236
  }
@@ -219,7 +239,10 @@ var RealNeonApi = class {
219
239
  }
220
240
  async getProject(projectId) {
221
241
  return this.call(`getProject(${projectId})`, async () => {
222
- return projectToSnapshot((await this.client.getProject(projectId)).data.project);
242
+ return projectToSnapshot(unwrap(await getProject({
243
+ client: this.client,
244
+ path: { project_id: projectId }
245
+ })).project);
223
246
  }, { projectId });
224
247
  }
225
248
  async createProject(input) {
@@ -232,7 +255,10 @@ var RealNeonApi = class {
232
255
  ...input.defaultBranchName ? { branch: { name: input.defaultBranchName } } : {}
233
256
  } };
234
257
  return this.call(`createProject(${input.name})`, async () => {
235
- return projectToSnapshot((await this.client.createProject(body)).data.project);
258
+ return projectToSnapshot(unwrap(await createProject({
259
+ client: this.client,
260
+ body
261
+ })).project);
236
262
  }, { mutating: true });
237
263
  }
238
264
  async updateProject(projectId, input) {
@@ -241,7 +267,11 @@ var RealNeonApi = class {
241
267
  ...input.defaultEndpointSettings ? { default_endpoint_settings: computeSettingsToDefaults(input.defaultEndpointSettings) } : {}
242
268
  } };
243
269
  return this.call(`updateProject(${projectId})`, async () => {
244
- return projectToSnapshot((await this.client.updateProject(projectId, body)).data.project);
270
+ return projectToSnapshot(unwrap(await updateProject({
271
+ client: this.client,
272
+ path: { project_id: projectId },
273
+ body
274
+ })).project);
245
275
  }, {
246
276
  projectId,
247
277
  mutating: true
@@ -252,13 +282,16 @@ var RealNeonApi = class {
252
282
  const branches = [];
253
283
  let cursor;
254
284
  while (true) {
255
- const res = await this.client.listProjectBranches({
256
- projectId,
257
- limit: 100,
258
- ...cursor ? { cursor } : {}
259
- });
260
- branches.push(...res.data.branches);
261
- const next = res.data.pagination?.next;
285
+ const body = unwrap(await listProjectBranches({
286
+ client: this.client,
287
+ path: { project_id: projectId },
288
+ query: {
289
+ limit: 100,
290
+ ...cursor ? { cursor } : {}
291
+ }
292
+ }));
293
+ branches.push(...body.branches);
294
+ const next = body.pagination?.next;
262
295
  if (!next || next === cursor) break;
263
296
  cursor = next;
264
297
  }
@@ -267,9 +300,9 @@ var RealNeonApi = class {
267
300
  }
268
301
  async createBranch(projectId, input) {
269
302
  const endpointOptions = input.computeSettings ? {
270
- type: EndpointType.ReadWrite,
303
+ type: "read_write",
271
304
  ...computeSettingsToEndpointOptions(input.computeSettings)
272
- } : { type: EndpointType.ReadWrite };
305
+ } : { type: "read_write" };
273
306
  const body = {
274
307
  branch: {
275
308
  name: input.name,
@@ -280,10 +313,14 @@ var RealNeonApi = class {
280
313
  endpoints: [endpointOptions]
281
314
  };
282
315
  return this.call(`createBranch(${projectId}/${input.name})`, async () => {
283
- const res = await this.client.createProjectBranch(projectId, body);
316
+ const data = unwrap(await createProjectBranch({
317
+ client: this.client,
318
+ path: { project_id: projectId },
319
+ body
320
+ }));
284
321
  return {
285
- branch: branchToSnapshot(res.data.branch),
286
- endpoints: (res.data.endpoints ?? []).map(endpointToSnapshot)
322
+ branch: branchToSnapshot(data.branch),
323
+ endpoints: (data.endpoints ?? []).map(endpointToSnapshot)
287
324
  };
288
325
  }, {
289
326
  projectId,
@@ -296,7 +333,14 @@ var RealNeonApi = class {
296
333
  if (input.expiresAt !== void 0) branch.expires_at = input.expiresAt;
297
334
  if (input.protected !== void 0) branch.protected = input.protected;
298
335
  return this.call(`updateBranch(${projectId}/${branchId})`, async () => {
299
- return branchToSnapshot((await this.client.updateProjectBranch(projectId, branchId, { branch })).data.branch);
336
+ return branchToSnapshot(unwrap(await updateProjectBranch({
337
+ client: this.client,
338
+ path: {
339
+ project_id: projectId,
340
+ branch_id: branchId
341
+ },
342
+ body: { branch }
343
+ })).branch);
300
344
  }, {
301
345
  projectId,
302
346
  mutating: true
@@ -304,13 +348,23 @@ var RealNeonApi = class {
304
348
  }
305
349
  async listEndpoints(projectId) {
306
350
  return this.call(`listEndpoints(${projectId})`, async () => {
307
- return (await this.client.listProjectEndpoints(projectId)).data.endpoints.map(endpointToSnapshot);
351
+ return unwrap(await listProjectEndpoints({
352
+ client: this.client,
353
+ path: { project_id: projectId }
354
+ })).endpoints.map(endpointToSnapshot);
308
355
  }, { projectId });
309
356
  }
310
357
  async updateEndpoint(projectId, endpointId, settings) {
311
358
  const endpoint = computeSettingsToEndpointOptions(settings);
312
359
  return this.call(`updateEndpoint(${projectId}/${endpointId})`, async () => {
313
- return endpointToSnapshot((await this.client.updateProjectEndpoint(projectId, endpointId, { endpoint })).data.endpoint);
360
+ return endpointToSnapshot(unwrap(await updateProjectEndpoint({
361
+ client: this.client,
362
+ path: {
363
+ project_id: projectId,
364
+ endpoint_id: endpointId
365
+ },
366
+ body: { endpoint }
367
+ })).endpoint);
314
368
  }, {
315
369
  projectId,
316
370
  mutating: true
@@ -318,32 +372,54 @@ var RealNeonApi = class {
318
372
  }
319
373
  async listBranchRoles(projectId, branchId) {
320
374
  return this.call(`listBranchRoles(${projectId}/${branchId})`, async () => {
321
- return (await this.client.listProjectBranchRoles(projectId, branchId)).data.roles.map(roleToSnapshot);
375
+ return unwrap(await listProjectBranchRoles({
376
+ client: this.client,
377
+ path: {
378
+ project_id: projectId,
379
+ branch_id: branchId
380
+ }
381
+ })).roles.map(roleToSnapshot);
322
382
  }, { projectId });
323
383
  }
324
384
  async listBranchDatabases(projectId, branchId) {
325
385
  return this.call(`listBranchDatabases(${projectId}/${branchId})`, async () => {
326
- return (await this.client.listProjectBranchDatabases(projectId, branchId)).data.databases.map(databaseToSnapshot);
386
+ return unwrap(await listProjectBranchDatabases({
387
+ client: this.client,
388
+ path: {
389
+ project_id: projectId,
390
+ branch_id: branchId
391
+ }
392
+ })).databases.map(databaseToSnapshot);
327
393
  }, { projectId });
328
394
  }
329
395
  async getConnectionUri(projectId, input) {
330
396
  const op = `getConnectionUri(${projectId}/${input.databaseName}@${input.roleName}${input.pooled ? " pooled" : ""})`;
331
397
  const pooled = input.pooled === true;
332
398
  return this.call(op, async () => {
333
- return { uri: (await this.client.getConnectionUri({
334
- projectId,
335
- database_name: input.databaseName,
336
- role_name: input.roleName,
337
- ...input.branchId ? { branch_id: input.branchId } : {},
338
- ...input.endpointId ? { endpoint_id: input.endpointId } : {},
339
- pooled
340
- })).data.uri };
399
+ return { uri: unwrap(await getConnectionUri({
400
+ client: this.client,
401
+ path: { project_id: projectId },
402
+ query: {
403
+ database_name: input.databaseName,
404
+ role_name: input.roleName,
405
+ ...input.branchId ? { branch_id: input.branchId } : {},
406
+ ...input.endpointId ? { endpoint_id: input.endpointId } : {},
407
+ pooled
408
+ }
409
+ })).uri };
341
410
  }, { projectId });
342
411
  }
343
412
  async getNeonAuth(projectId, branchId) {
344
413
  try {
345
414
  return await this.call(`getNeonAuth(${projectId}/${branchId})`, async () => {
346
- return neonAuthResponseToSnapshot((await this.client.getNeonAuth(projectId, branchId)).data);
415
+ const data = unwrap(await getNeonAuth({
416
+ client: this.client,
417
+ path: {
418
+ project_id: projectId,
419
+ branch_id: branchId
420
+ }
421
+ }));
422
+ return neonAuthResponseToSnapshot(neonAuthResponseSchema.parse(data));
347
423
  }, { projectId });
348
424
  } catch (err) {
349
425
  if (err instanceof PlatformError && err.code === ErrorCode.NotFound) return null;
@@ -406,7 +482,14 @@ var RealNeonApi = class {
406
482
  }
407
483
  async getNeonDataApi(projectId, branchId, databaseName) {
408
484
  try {
409
- return await this.call(`getNeonDataApi(${projectId}/${branchId}/${databaseName})`, async () => dataApiSnapshotFromResponse(await this.client.getProjectBranchDataApi(projectId, branchId, databaseName).then((res) => res.data)), { projectId });
485
+ return await this.call(`getNeonDataApi(${projectId}/${branchId}/${databaseName})`, async () => dataApiSnapshotFromResponse(unwrap(await getProjectBranchDataApi({
486
+ client: this.client,
487
+ path: {
488
+ project_id: projectId,
489
+ branch_id: branchId,
490
+ database_name: databaseName
491
+ }
492
+ }))), { projectId });
410
493
  } catch (err) {
411
494
  if (err instanceof PlatformError && err.code === ErrorCode.NotFound) return null;
412
495
  throw err;
@@ -415,7 +498,15 @@ var RealNeonApi = class {
415
498
  async enableProjectBranchDataApi(projectId, branchId, databaseName, input) {
416
499
  try {
417
500
  return await this.call(`enableProjectBranchDataApi(${projectId}/${branchId}/${databaseName})`, async () => {
418
- return { url: (await this.client.createProjectBranchDataApi(projectId, branchId, databaseName, dataApiCreateRequest(input))).data.url };
501
+ return { url: unwrap(await createProjectBranchDataApi({
502
+ client: this.client,
503
+ path: {
504
+ project_id: projectId,
505
+ branch_id: branchId,
506
+ database_name: databaseName
507
+ },
508
+ body: dataApiCreateRequest(input)
509
+ })).url };
419
510
  }, {
420
511
  projectId,
421
512
  mutating: true
@@ -430,8 +521,23 @@ var RealNeonApi = class {
430
521
  }
431
522
  async updateProjectBranchDataApi(projectId, branchId, databaseName, settings) {
432
523
  return await this.call(`updateProjectBranchDataApi(${projectId}/${branchId}/${databaseName})`, async () => {
433
- await this.client.updateProjectBranchDataApi(projectId, branchId, databaseName, { settings: dataApiSettingsToApi(settings) });
434
- return dataApiSnapshotFromResponse((await this.client.getProjectBranchDataApi(projectId, branchId, databaseName)).data);
524
+ unwrap(await updateProjectBranchDataApi({
525
+ client: this.client,
526
+ path: {
527
+ project_id: projectId,
528
+ branch_id: branchId,
529
+ database_name: databaseName
530
+ },
531
+ body: { settings: dataApiSettingsToApi(settings) }
532
+ }));
533
+ return dataApiSnapshotFromResponse(unwrap(await getProjectBranchDataApi({
534
+ client: this.client,
535
+ path: {
536
+ project_id: projectId,
537
+ branch_id: branchId,
538
+ database_name: databaseName
539
+ }
540
+ })));
435
541
  }, {
436
542
  projectId,
437
543
  mutating: true
@@ -796,7 +902,7 @@ function endpointToSnapshot(endpoint) {
796
902
  return {
797
903
  id: endpoint.id,
798
904
  branchId: endpoint.branch_id,
799
- type: endpoint.type === EndpointType.ReadOnly ? "read_only" : "read_write",
905
+ type: endpoint.type === "read_only" ? "read_only" : "read_write",
800
906
  autoscalingLimitMinCu: endpoint.autoscaling_limit_min_cu,
801
907
  autoscalingLimitMaxCu: endpoint.autoscaling_limit_max_cu,
802
908
  suspendTimeout: formatSuspendTimeout(endpoint.suspend_timeout_seconds)