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.
Files changed (2) hide show
  1. package/index.js +89 -108
  2. 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 = ["region", "help", "list-regions", "interactive", "json"];
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(`Failed to fetch regions. Status: ${res.status} ${res.statusText}`);
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(`Invalid region: ${region}. Available regions: ${regionIds.join(", ")}`);
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: "We're experiencing a high volume of requests. Please try again later.",
314
- status: 429
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
- // Silently fail analytics
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(' ')}`.trim(),
447
- "has-region-flag": rawArgs.includes('--region') || rawArgs.includes('-r'),
448
- "has-interactive-flag": rawArgs.includes('--interactive') || rawArgs.includes('-i'),
449
- "has-help-flag": rawArgs.includes('--help') || rawArgs.includes('-h'),
450
- "has-list-regions-flag": rawArgs.includes('--list-regions'),
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-17103676514.0",
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": "",