create-db 1.0.1-pr43-DC-4828-json-flag-17103676514.0 → 1.0.1-pr43-DC-4828-json-flag-17106021047.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/index.js +89 -108
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -3,14 +3,7 @@
|
|
|
3
3
|
import dotenv from "dotenv";
|
|
4
4
|
dotenv.config();
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
select,
|
|
8
|
-
spinner,
|
|
9
|
-
intro,
|
|
10
|
-
outro,
|
|
11
|
-
log,
|
|
12
|
-
cancel,
|
|
13
|
-
} from "@clack/prompts";
|
|
6
|
+
import { select, spinner, intro, outro, log, cancel } from "@clack/prompts";
|
|
14
7
|
import chalk from "chalk";
|
|
15
8
|
import terminalLink from "terminal-link";
|
|
16
9
|
import { analytics } from "./analytics.js";
|
|
@@ -71,9 +64,7 @@ async function showHelp() {
|
|
|
71
64
|
if (regions && regions.length > 0) {
|
|
72
65
|
regionExamples = regions.map((r) => r.id).join(", ");
|
|
73
66
|
}
|
|
74
|
-
} catch {
|
|
75
|
-
// Fallback to default examples if fetching fails
|
|
76
|
-
}
|
|
67
|
+
} catch {}
|
|
77
68
|
|
|
78
69
|
console.log(`
|
|
79
70
|
${chalk.cyan.bold("Prisma Postgres Create DB")}
|
|
@@ -84,6 +75,8 @@ Usage:
|
|
|
84
75
|
Options:
|
|
85
76
|
${chalk.yellow(`--region <region>, -r <region>`)} Specify the region (e.g., ${regionExamples})
|
|
86
77
|
${chalk.yellow("--interactive, -i")} Run in interactive mode to select a region and create the database
|
|
78
|
+
${chalk.yellow("--json, -j")} Output machine-readable JSON and exit
|
|
79
|
+
${chalk.yellow("--list-regions")} List available regions and exit
|
|
87
80
|
${chalk.yellow("--help, -h")} Show this help message
|
|
88
81
|
|
|
89
82
|
Examples:
|
|
@@ -91,16 +84,22 @@ Examples:
|
|
|
91
84
|
${chalk.gray(`npx ${CLI_NAME} -r us-east-1`)}
|
|
92
85
|
${chalk.gray(`npx ${CLI_NAME} --interactive`)}
|
|
93
86
|
${chalk.gray(`npx ${CLI_NAME} -i`)}
|
|
87
|
+
${chalk.gray(`npx ${CLI_NAME} --json --region us-east-1`)}
|
|
94
88
|
`);
|
|
95
89
|
process.exit(0);
|
|
96
90
|
}
|
|
97
91
|
|
|
98
|
-
// Parse command line arguments into flags and positional arguments
|
|
99
92
|
async function parseArgs() {
|
|
100
93
|
const args = process.argv.slice(2);
|
|
101
94
|
const flags = {};
|
|
102
95
|
|
|
103
|
-
const allowedFlags = [
|
|
96
|
+
const allowedFlags = [
|
|
97
|
+
"region",
|
|
98
|
+
"help",
|
|
99
|
+
"list-regions",
|
|
100
|
+
"interactive",
|
|
101
|
+
"json",
|
|
102
|
+
];
|
|
104
103
|
const shorthandMap = {
|
|
105
104
|
r: "region",
|
|
106
105
|
i: "interactive",
|
|
@@ -117,7 +116,6 @@ async function parseArgs() {
|
|
|
117
116
|
for (let i = 0; i < args.length; i++) {
|
|
118
117
|
const arg = args[i];
|
|
119
118
|
|
|
120
|
-
// Handle long flags (--region, --help, etc.)
|
|
121
119
|
if (arg.startsWith("--")) {
|
|
122
120
|
const flag = arg.slice(2);
|
|
123
121
|
if (flag === "help") await showHelp();
|
|
@@ -135,11 +133,9 @@ async function parseArgs() {
|
|
|
135
133
|
continue;
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
// Handle short and multi-letter shorthand flags
|
|
139
136
|
if (arg.startsWith("-")) {
|
|
140
137
|
const short = arg.slice(1);
|
|
141
138
|
|
|
142
|
-
// Check if it's a multi-letter shorthand like -cs or -lr
|
|
143
139
|
if (shorthandMap[short]) {
|
|
144
140
|
const mappedFlag = shorthandMap[short];
|
|
145
141
|
if (mappedFlag === "help") showHelp();
|
|
@@ -155,7 +151,6 @@ async function parseArgs() {
|
|
|
155
151
|
continue;
|
|
156
152
|
}
|
|
157
153
|
|
|
158
|
-
// Fall back to single-letter flags like -r -l
|
|
159
154
|
for (const letter of short.split("")) {
|
|
160
155
|
const mappedFlag = shorthandMap[letter];
|
|
161
156
|
if (!mappedFlag) exitWithError(`Invalid flag: -${letter}`);
|
|
@@ -182,16 +177,15 @@ async function parseArgs() {
|
|
|
182
177
|
return { flags };
|
|
183
178
|
}
|
|
184
179
|
|
|
185
|
-
/**
|
|
186
|
-
* Fetch available regions from the API.
|
|
187
|
-
*/
|
|
188
180
|
export async function getRegions(returnJson = false) {
|
|
189
181
|
const url = `${CREATE_DB_WORKER_URL}/regions`;
|
|
190
182
|
const res = await fetch(url);
|
|
191
183
|
|
|
192
184
|
if (!res.ok) {
|
|
193
185
|
if (returnJson) {
|
|
194
|
-
throw new Error(
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Failed to fetch regions. Status: ${res.status} ${res.statusText}`
|
|
188
|
+
);
|
|
195
189
|
}
|
|
196
190
|
handleError(
|
|
197
191
|
`Failed to fetch regions. Status: ${res.status} ${res.statusText}`
|
|
@@ -210,16 +204,15 @@ export async function getRegions(returnJson = false) {
|
|
|
210
204
|
}
|
|
211
205
|
}
|
|
212
206
|
|
|
213
|
-
/**
|
|
214
|
-
* Validate the provided region against the available list.
|
|
215
|
-
*/
|
|
216
207
|
export async function validateRegion(region, returnJson = false) {
|
|
217
208
|
const regions = await getRegions(returnJson);
|
|
218
209
|
const regionIds = regions.map((r) => r.id);
|
|
219
210
|
|
|
220
211
|
if (!regionIds.includes(region)) {
|
|
221
212
|
if (returnJson) {
|
|
222
|
-
throw new Error(
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Invalid region: ${region}. Available regions: ${regionIds.join(", ")}`
|
|
215
|
+
);
|
|
223
216
|
}
|
|
224
217
|
handleError(
|
|
225
218
|
`Invalid region: ${chalk.yellow(region)}.\nAvailable regions: ${chalk.green(
|
|
@@ -231,9 +224,6 @@ export async function validateRegion(region, returnJson = false) {
|
|
|
231
224
|
return region;
|
|
232
225
|
}
|
|
233
226
|
|
|
234
|
-
/**
|
|
235
|
-
* Prettified error handler
|
|
236
|
-
*/
|
|
237
227
|
function handleError(message, extra = "") {
|
|
238
228
|
console.error(
|
|
239
229
|
"\n" +
|
|
@@ -249,8 +239,6 @@ function handleError(message, extra = "") {
|
|
|
249
239
|
process.exit(1);
|
|
250
240
|
}
|
|
251
241
|
|
|
252
|
-
// Get region from user input
|
|
253
|
-
|
|
254
242
|
async function promptForRegion(defaultRegion) {
|
|
255
243
|
let regions;
|
|
256
244
|
try {
|
|
@@ -275,23 +263,17 @@ async function promptForRegion(defaultRegion) {
|
|
|
275
263
|
process.exit(0);
|
|
276
264
|
}
|
|
277
265
|
|
|
278
|
-
// Track region selection event
|
|
279
266
|
try {
|
|
280
267
|
await analytics.capture("create_db:region_selected", {
|
|
281
268
|
command: CLI_NAME,
|
|
282
269
|
region: region,
|
|
283
|
-
"selection-method": "interactive"
|
|
270
|
+
"selection-method": "interactive",
|
|
284
271
|
});
|
|
285
|
-
} catch (error) {
|
|
286
|
-
// Silently fail analytics
|
|
287
|
-
}
|
|
272
|
+
} catch (error) {}
|
|
288
273
|
|
|
289
274
|
return region;
|
|
290
275
|
}
|
|
291
276
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
// Create a database
|
|
295
277
|
async function createDatabase(name, region, returnJson = false) {
|
|
296
278
|
let s;
|
|
297
279
|
if (!returnJson) {
|
|
@@ -305,23 +287,22 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
305
287
|
body: JSON.stringify({ region, name, utm_source: CLI_NAME }),
|
|
306
288
|
});
|
|
307
289
|
|
|
308
|
-
// Rate limit exceeded
|
|
309
290
|
if (resp.status === 429) {
|
|
310
291
|
if (returnJson) {
|
|
311
292
|
return {
|
|
312
293
|
error: "rate_limit_exceeded",
|
|
313
|
-
message:
|
|
314
|
-
|
|
294
|
+
message:
|
|
295
|
+
"We're experiencing a high volume of requests. Please try again later.",
|
|
296
|
+
status: 429,
|
|
315
297
|
};
|
|
316
298
|
}
|
|
317
|
-
|
|
299
|
+
|
|
318
300
|
if (s) {
|
|
319
301
|
s.stop(
|
|
320
302
|
"We're experiencing a high volume of requests. Please try again later."
|
|
321
303
|
);
|
|
322
304
|
}
|
|
323
|
-
|
|
324
|
-
// Track database creation failure
|
|
305
|
+
|
|
325
306
|
try {
|
|
326
307
|
await analytics.capture("create_db:database_creation_failed", {
|
|
327
308
|
command: CLI_NAME,
|
|
@@ -329,31 +310,62 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
329
310
|
"error-type": "rate_limit",
|
|
330
311
|
"status-code": 429,
|
|
331
312
|
});
|
|
332
|
-
} catch (error) {
|
|
333
|
-
|
|
334
|
-
}
|
|
335
|
-
|
|
313
|
+
} catch (error) {}
|
|
314
|
+
|
|
336
315
|
process.exit(1);
|
|
337
316
|
}
|
|
338
317
|
|
|
339
318
|
const result = await resp.json();
|
|
340
319
|
|
|
320
|
+
const database = result.data ? result.data.database : result.databases?.[0];
|
|
321
|
+
const projectId = result.data ? result.data.id : result.id;
|
|
322
|
+
const prismaConn = database?.connectionString;
|
|
323
|
+
|
|
324
|
+
const directConnDetails = result.data
|
|
325
|
+
? database?.apiKeys?.[0]?.directConnection
|
|
326
|
+
: result.databases?.[0]?.apiKeys?.[0]?.ppgDirectConnection;
|
|
327
|
+
const directUser = directConnDetails?.user
|
|
328
|
+
? encodeURIComponent(directConnDetails.user)
|
|
329
|
+
: "";
|
|
330
|
+
const directPass = directConnDetails?.pass
|
|
331
|
+
? encodeURIComponent(directConnDetails.pass)
|
|
332
|
+
: "";
|
|
333
|
+
const directHost = directConnDetails?.host;
|
|
334
|
+
const directConn =
|
|
335
|
+
directConnDetails && directHost
|
|
336
|
+
? `postgresql://${directUser}:${directPass}@${directHost}/postgres`
|
|
337
|
+
: null;
|
|
338
|
+
|
|
339
|
+
const claimUrl = `${CLAIM_DB_WORKER_URL}?projectID=${projectId}&utm_source=${CLI_NAME}&utm_medium=cli`;
|
|
340
|
+
const expiryDate = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
341
|
+
|
|
342
|
+
if (returnJson && !result.error) {
|
|
343
|
+
return {
|
|
344
|
+
connectionString: prismaConn,
|
|
345
|
+
directConnectionString: directConn,
|
|
346
|
+
claimUrl: claimUrl,
|
|
347
|
+
deletionDate: expiryDate.toISOString(),
|
|
348
|
+
region: database?.region?.id || region,
|
|
349
|
+
name: database?.name,
|
|
350
|
+
projectId: projectId,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
341
354
|
if (result.error) {
|
|
342
355
|
if (returnJson) {
|
|
343
356
|
return {
|
|
344
357
|
error: "api_error",
|
|
345
358
|
message: result.error.message || "Unknown error",
|
|
346
|
-
details: result.error
|
|
359
|
+
details: result.error,
|
|
347
360
|
};
|
|
348
361
|
}
|
|
349
|
-
|
|
362
|
+
|
|
350
363
|
if (s) {
|
|
351
364
|
s.stop(
|
|
352
365
|
`Error creating database: ${result.error.message || "Unknown error"}`
|
|
353
366
|
);
|
|
354
367
|
}
|
|
355
|
-
|
|
356
|
-
// Track database creation failure
|
|
368
|
+
|
|
357
369
|
try {
|
|
358
370
|
await analytics.capture("create_db:database_creation_failed", {
|
|
359
371
|
command: CLI_NAME,
|
|
@@ -361,37 +373,20 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
361
373
|
"error-type": "api_error",
|
|
362
374
|
"error-message": result.error.message,
|
|
363
375
|
});
|
|
364
|
-
} catch (error) {
|
|
365
|
-
// Silently fail analytics
|
|
366
|
-
}
|
|
376
|
+
} catch (error) {}
|
|
367
377
|
process.exit(1);
|
|
368
378
|
}
|
|
369
379
|
|
|
370
|
-
if (returnJson) {
|
|
371
|
-
return result;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
380
|
if (s) {
|
|
375
381
|
s.stop("Database created successfully!");
|
|
376
382
|
}
|
|
377
383
|
|
|
378
|
-
const expiryDate = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
379
384
|
const expiryFormatted = expiryDate.toLocaleString();
|
|
380
385
|
|
|
381
386
|
log.message("");
|
|
382
|
-
// Determine which connection string to display
|
|
383
|
-
const database = result.data ? result.data.database : result.databases?.[0];
|
|
384
|
-
const prismaConn = database?.connectionString;
|
|
385
|
-
const directConnDetails = result.data
|
|
386
|
-
? database?.apiKeys?.[0]?.directConnection
|
|
387
|
-
: result.databases?.[0]?.apiKeys?.[0]?.ppgDirectConnection;
|
|
388
|
-
const directConn = directConnDetails
|
|
389
|
-
? `postgresql://${directConnDetails.user}:${directConnDetails.pass}@${directConnDetails.host}/postgres`
|
|
390
|
-
: null;
|
|
391
387
|
|
|
392
388
|
log.info(chalk.bold("Connect to your database →"));
|
|
393
389
|
|
|
394
|
-
// Show Prisma Postgres connection string
|
|
395
390
|
if (prismaConn) {
|
|
396
391
|
log.message(
|
|
397
392
|
chalk.magenta(" Use this connection string optimized for Prisma ORM:")
|
|
@@ -400,7 +395,6 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
400
395
|
log.message("");
|
|
401
396
|
}
|
|
402
397
|
|
|
403
|
-
// Show Direct connection string (if available)
|
|
404
398
|
if (directConn) {
|
|
405
399
|
log.message(
|
|
406
400
|
chalk.cyan(" Use this connection string for everything else:")
|
|
@@ -415,9 +409,6 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
415
409
|
);
|
|
416
410
|
}
|
|
417
411
|
|
|
418
|
-
// Claim Database
|
|
419
|
-
const projectId = result.data ? result.data.id : result.id;
|
|
420
|
-
const claimUrl = `${CLAIM_DB_WORKER_URL}?projectID=${projectId}&utm_source=${CLI_NAME}&utm_medium=cli`;
|
|
421
412
|
const clickableUrl = terminalLink(claimUrl, claimUrl, { fallback: false });
|
|
422
413
|
log.success(`${chalk.bold("Claim your database →")}`);
|
|
423
414
|
log.message(
|
|
@@ -435,35 +426,32 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
435
426
|
);
|
|
436
427
|
}
|
|
437
428
|
|
|
438
|
-
// Main function
|
|
439
|
-
|
|
440
429
|
async function main() {
|
|
441
430
|
try {
|
|
442
431
|
const rawArgs = process.argv.slice(2);
|
|
443
432
|
try {
|
|
444
433
|
await analytics.capture("create_db:cli_command_ran", {
|
|
445
434
|
command: CLI_NAME,
|
|
446
|
-
"full-command": `${CLI_NAME} ${rawArgs.join(
|
|
447
|
-
"has-region-flag":
|
|
448
|
-
|
|
449
|
-
"has-
|
|
450
|
-
|
|
435
|
+
"full-command": `${CLI_NAME} ${rawArgs.join(" ")}`.trim(),
|
|
436
|
+
"has-region-flag":
|
|
437
|
+
rawArgs.includes("--region") || rawArgs.includes("-r"),
|
|
438
|
+
"has-interactive-flag":
|
|
439
|
+
rawArgs.includes("--interactive") || rawArgs.includes("-i"),
|
|
440
|
+
"has-help-flag": rawArgs.includes("--help") || rawArgs.includes("-h"),
|
|
441
|
+
"has-list-regions-flag": rawArgs.includes("--list-regions"),
|
|
442
|
+
"has-json-flag": rawArgs.includes("--json") || rawArgs.includes("-j"),
|
|
451
443
|
"node-version": process.version,
|
|
452
444
|
platform: process.platform,
|
|
453
|
-
arch: process.arch
|
|
445
|
+
arch: process.arch,
|
|
454
446
|
});
|
|
455
|
-
} catch (error) {
|
|
456
|
-
// Silently fail analytics
|
|
457
|
-
}
|
|
447
|
+
} catch (error) {}
|
|
458
448
|
|
|
459
|
-
// Parse command line arguments
|
|
460
449
|
const { flags } = await parseArgs();
|
|
461
450
|
|
|
462
451
|
if (!flags.help) {
|
|
463
452
|
await isOffline();
|
|
464
453
|
}
|
|
465
454
|
|
|
466
|
-
// Set default values
|
|
467
455
|
let name = new Date().toISOString();
|
|
468
456
|
let region = "us-east-1";
|
|
469
457
|
let chooseRegionPrompt = false;
|
|
@@ -477,35 +465,32 @@ async function main() {
|
|
|
477
465
|
process.exit(0);
|
|
478
466
|
}
|
|
479
467
|
|
|
480
|
-
if (flags.json) {
|
|
481
|
-
if (chooseRegionPrompt) {
|
|
482
|
-
region = await promptForRegion(region);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
const result = await createDatabase(name, region, true);
|
|
486
|
-
console.log(JSON.stringify(result, null, 2));
|
|
487
|
-
process.exit(0);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// Apply command line flags
|
|
491
468
|
if (flags.region) {
|
|
492
469
|
region = flags.region;
|
|
493
|
-
|
|
494
|
-
// Track region selection via flag
|
|
470
|
+
|
|
495
471
|
try {
|
|
496
472
|
await analytics.capture("create_db:region_selected", {
|
|
497
473
|
command: CLI_NAME,
|
|
498
474
|
region: region,
|
|
499
|
-
"selection-method": "flag"
|
|
475
|
+
"selection-method": "flag",
|
|
500
476
|
});
|
|
501
|
-
} catch (error) {
|
|
502
|
-
// Silently fail analytics
|
|
503
|
-
}
|
|
477
|
+
} catch (error) {}
|
|
504
478
|
}
|
|
479
|
+
|
|
505
480
|
if (flags.interactive) {
|
|
506
481
|
chooseRegionPrompt = true;
|
|
507
482
|
}
|
|
508
483
|
|
|
484
|
+
if (flags.json) {
|
|
485
|
+
if (chooseRegionPrompt) {
|
|
486
|
+
region = await promptForRegion(region);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const result = await createDatabase(name, region, true);
|
|
490
|
+
console.log(JSON.stringify(result, null, 2));
|
|
491
|
+
process.exit(0);
|
|
492
|
+
}
|
|
493
|
+
|
|
509
494
|
intro(chalk.cyan.bold("🚀 Creating a Prisma Postgres database"));
|
|
510
495
|
log.message(
|
|
511
496
|
chalk.white(`Provisioning a temporary database in ${region}...`)
|
|
@@ -515,16 +500,12 @@ async function main() {
|
|
|
515
500
|
`It will be automatically deleted in 24 hours, but you can claim it.`
|
|
516
501
|
)
|
|
517
502
|
);
|
|
518
|
-
// Interactive mode prompts
|
|
519
503
|
if (chooseRegionPrompt) {
|
|
520
|
-
// Prompt for region
|
|
521
504
|
region = await promptForRegion(region);
|
|
522
505
|
}
|
|
523
506
|
|
|
524
|
-
// Validate the region
|
|
525
507
|
region = await validateRegion(region);
|
|
526
508
|
|
|
527
|
-
// Create the database
|
|
528
509
|
await createDatabase(name, region);
|
|
529
510
|
|
|
530
511
|
outro("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-db",
|
|
3
|
-
"version": "1.0.1-pr43-DC-4828-json-flag-
|
|
3
|
+
"version": "1.0.1-pr43-DC-4828-json-flag-17106021047.0",
|
|
4
4
|
"description": "Instantly create a temporary Prisma Postgres database with one command, then claim and persist it in your Prisma Data Platform project when ready.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "",
|