@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.
- package/README.md +9 -7
- package/dist/lib/define-config.d.ts +1 -1
- package/dist/lib/define-config.js +1 -1
- package/dist/lib/define-config.js.map +1 -1
- package/dist/lib/diff.js +1 -1
- package/dist/lib/diff.js.map +1 -1
- package/dist/lib/errors.d.ts +1 -1
- package/dist/lib/errors.js +2 -2
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/loader.js +1 -1
- package/dist/lib/loader.js.map +1 -1
- package/dist/lib/neon-api-real.d.ts +1 -1
- package/dist/lib/neon-api-real.d.ts.map +1 -1
- package/dist/lib/neon-api-real.js +152 -46
- package/dist/lib/neon-api-real.js.map +1 -1
- package/dist/lib/patterns.js +1 -1
- package/dist/lib/patterns.js.map +1 -1
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/v1.js +4 -4
- package/dist/v1.js.map +1 -1
- package/package.json +4 -4
|
@@ -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 {
|
|
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 `@
|
|
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
|
-
|
|
153
|
+
const client = createNeonClient({
|
|
139
154
|
apiKey: options.apiKey,
|
|
140
|
-
|
|
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
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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:
|
|
303
|
+
type: "read_write",
|
|
271
304
|
...computeSettingsToEndpointOptions(input.computeSettings)
|
|
272
|
-
} : { type:
|
|
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
|
|
316
|
+
const data = unwrap(await createProjectBranch({
|
|
317
|
+
client: this.client,
|
|
318
|
+
path: { project_id: projectId },
|
|
319
|
+
body
|
|
320
|
+
}));
|
|
284
321
|
return {
|
|
285
|
-
branch: branchToSnapshot(
|
|
286
|
-
endpoints: (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
434
|
-
|
|
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 ===
|
|
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)
|