create-db 1.0.3-pr45-DC-4829-source-flag-17164819065.0 → 1.0.3-pr47-DC-4759-set-region-to-be-near-user-17250359916.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/analytics.js +4 -11
- package/index.js +93 -112
- package/package.json +1 -1
package/analytics.js
CHANGED
|
@@ -8,17 +8,10 @@ class EventCaptureError extends Error {
|
|
|
8
8
|
|
|
9
9
|
class PosthogEventCapture {
|
|
10
10
|
async capture(eventName, properties = {}) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
console.warn(
|
|
16
|
-
"Analytics disabled: missing POSTHOG_API_HOST or POSTHOG_API_KEY."
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const POSTHOG_CAPTURE_URL = `${POSTHOG_API_HOST.replace(/\/+$/, "")}/capture`;
|
|
11
|
+
const POSTHOG_CAPTURE_URL = process.env.POSTHOG_API_HOST
|
|
12
|
+
? process.env.POSTHOG_API_HOST + "/capture"
|
|
13
|
+
: "https://proxyhog.prisma-data.net/capture";
|
|
14
|
+
const POSTHOG_KEY = process.env.POSTHOG_API_KEY || "phc_cmc85avbWyuJ2JyKdGPdv7dxXli8xLdWDBPbvIXWJfs";
|
|
22
15
|
|
|
23
16
|
const payload = {
|
|
24
17
|
api_key: POSTHOG_KEY,
|
package/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import dotenv from "dotenv";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import path from "path";
|
|
6
4
|
dotenv.config();
|
|
7
5
|
|
|
8
6
|
import { select, spinner, intro, outro, log, cancel } from "@clack/prompts";
|
|
@@ -15,6 +13,74 @@ const CREATE_DB_WORKER_URL =
|
|
|
15
13
|
const CLAIM_DB_WORKER_URL =
|
|
16
14
|
process.env.CLAIM_DB_WORKER_URL || "https://create-db.prisma.io";
|
|
17
15
|
|
|
16
|
+
async function detectUserLocation() {
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetch("https://ipapi.co/json/", {
|
|
19
|
+
method: "GET",
|
|
20
|
+
headers: {
|
|
21
|
+
"User-Agent": "create-db-cli/1.0",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch location data: ${response.status}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
return {
|
|
31
|
+
country: data.country_code,
|
|
32
|
+
continent: data.continent_code,
|
|
33
|
+
city: data.city,
|
|
34
|
+
region: data.region,
|
|
35
|
+
latitude: data.latitude,
|
|
36
|
+
longitude: data.longitude,
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Region coordinates (latitude, longitude)
|
|
44
|
+
const REGION_COORDINATES = {
|
|
45
|
+
"ap-southeast-1": { lat: 1.3521, lng: 103.8198 }, // Singapore
|
|
46
|
+
"ap-northeast-1": { lat: 35.6762, lng: 139.6503 }, // Tokyo
|
|
47
|
+
"eu-central-1": { lat: 50.1109, lng: 8.6821 }, // Frankfurt
|
|
48
|
+
"eu-west-3": { lat: 48.8566, lng: 2.3522 }, // Paris
|
|
49
|
+
"us-east-1": { lat: 38.9072, lng: -77.0369 }, // N. Virginia
|
|
50
|
+
"us-west-1": { lat: 37.7749, lng: -122.4194 }, // N. California
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function getRegionClosestToLocation(userLocation) {
|
|
54
|
+
if (!userLocation) return null;
|
|
55
|
+
|
|
56
|
+
const userLat = parseFloat(userLocation.latitude);
|
|
57
|
+
const userLng = parseFloat(userLocation.longitude);
|
|
58
|
+
|
|
59
|
+
let closestRegion = null;
|
|
60
|
+
let minDistance = Infinity;
|
|
61
|
+
|
|
62
|
+
for (const [region, coordinates] of Object.entries(REGION_COORDINATES)) {
|
|
63
|
+
// Simple distance calculation using Haversine formula
|
|
64
|
+
const latDiff = ((userLat - coordinates.lat) * Math.PI) / 180;
|
|
65
|
+
const lngDiff = ((userLng - coordinates.lng) * Math.PI) / 180;
|
|
66
|
+
const a =
|
|
67
|
+
Math.sin(latDiff / 2) * Math.sin(latDiff / 2) +
|
|
68
|
+
Math.cos((userLat * Math.PI) / 180) *
|
|
69
|
+
Math.cos((coordinates.lat * Math.PI) / 180) *
|
|
70
|
+
Math.sin(lngDiff / 2) *
|
|
71
|
+
Math.sin(lngDiff / 2);
|
|
72
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
73
|
+
const distance = 6371 * c; // Earth radius in km
|
|
74
|
+
|
|
75
|
+
if (distance < minDistance) {
|
|
76
|
+
minDistance = distance;
|
|
77
|
+
closestRegion = region;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return closestRegion;
|
|
82
|
+
}
|
|
83
|
+
|
|
18
84
|
async function listRegions() {
|
|
19
85
|
try {
|
|
20
86
|
const regions = await getRegions();
|
|
@@ -59,31 +125,6 @@ function getCommandName() {
|
|
|
59
125
|
|
|
60
126
|
const CLI_NAME = getCommandName();
|
|
61
127
|
|
|
62
|
-
function readUserEnvFile() {
|
|
63
|
-
const userCwd = process.cwd();
|
|
64
|
-
const envPath = path.join(userCwd, ".env");
|
|
65
|
-
|
|
66
|
-
if (!fs.existsSync(envPath)) {
|
|
67
|
-
return {};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const envContent = fs.readFileSync(envPath, "utf8");
|
|
71
|
-
const envVars = {};
|
|
72
|
-
|
|
73
|
-
envContent.split("\n").forEach((line) => {
|
|
74
|
-
const trimmed = line.trim();
|
|
75
|
-
if (trimmed && !trimmed.startsWith("#")) {
|
|
76
|
-
const [key, ...valueParts] = trimmed.split("=");
|
|
77
|
-
if (key && valueParts.length > 0) {
|
|
78
|
-
const value = valueParts.join("=").replace(/^["']|["']$/g, "");
|
|
79
|
-
envVars[key.trim()] = value.trim();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
return envVars;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
128
|
async function showHelp() {
|
|
88
129
|
let regionExamples = "us-east-1, eu-west-1";
|
|
89
130
|
try {
|
|
@@ -266,7 +307,7 @@ function handleError(message, extra = "") {
|
|
|
266
307
|
process.exit(1);
|
|
267
308
|
}
|
|
268
309
|
|
|
269
|
-
async function promptForRegion(defaultRegion
|
|
310
|
+
async function promptForRegion(defaultRegion) {
|
|
270
311
|
let regions;
|
|
271
312
|
try {
|
|
272
313
|
regions = await getRegions();
|
|
@@ -291,23 +332,17 @@ async function promptForRegion(defaultRegion, userAgent) {
|
|
|
291
332
|
}
|
|
292
333
|
|
|
293
334
|
try {
|
|
294
|
-
|
|
335
|
+
await analytics.capture("create_db:region_selected", {
|
|
295
336
|
command: CLI_NAME,
|
|
296
337
|
region: region,
|
|
297
338
|
"selection-method": "interactive",
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
if (userAgent) {
|
|
301
|
-
analyticsProps["user-agent"] = userAgent;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
await analytics.capture("create_db:region_selected", analyticsProps);
|
|
339
|
+
});
|
|
305
340
|
} catch (error) {}
|
|
306
341
|
|
|
307
342
|
return region;
|
|
308
343
|
}
|
|
309
344
|
|
|
310
|
-
async function createDatabase(name, region,
|
|
345
|
+
async function createDatabase(name, region, returnJson = false) {
|
|
311
346
|
let s;
|
|
312
347
|
if (!returnJson) {
|
|
313
348
|
s = spinner();
|
|
@@ -317,7 +352,7 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
317
352
|
const resp = await fetch(`${CREATE_DB_WORKER_URL}/create`, {
|
|
318
353
|
method: "POST",
|
|
319
354
|
headers: { "Content-Type": "application/json" },
|
|
320
|
-
body: JSON.stringify({ region, name, utm_source:
|
|
355
|
+
body: JSON.stringify({ region, name, utm_source: CLI_NAME }),
|
|
321
356
|
});
|
|
322
357
|
|
|
323
358
|
if (resp.status === 429) {
|
|
@@ -337,21 +372,12 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
337
372
|
}
|
|
338
373
|
|
|
339
374
|
try {
|
|
340
|
-
|
|
375
|
+
await analytics.capture("create_db:database_creation_failed", {
|
|
341
376
|
command: CLI_NAME,
|
|
342
377
|
region: region,
|
|
343
378
|
"error-type": "rate_limit",
|
|
344
379
|
"status-code": 429,
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
if (userAgent) {
|
|
348
|
-
analyticsProps["user-agent"] = userAgent;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
await analytics.capture(
|
|
352
|
-
"create_db:database_creation_failed",
|
|
353
|
-
analyticsProps
|
|
354
|
-
);
|
|
380
|
+
});
|
|
355
381
|
} catch (error) {}
|
|
356
382
|
|
|
357
383
|
process.exit(1);
|
|
@@ -375,21 +401,12 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
375
401
|
s.stop("Unexpected response from create service.");
|
|
376
402
|
}
|
|
377
403
|
try {
|
|
378
|
-
|
|
404
|
+
await analytics.capture("create_db:database_creation_failed", {
|
|
379
405
|
command: CLI_NAME,
|
|
380
406
|
region,
|
|
381
407
|
"error-type": "invalid_json",
|
|
382
408
|
"status-code": resp.status,
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
if (userAgent) {
|
|
386
|
-
analyticsProps["user-agent"] = userAgent;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
await analytics.capture(
|
|
390
|
-
"create_db:database_creation_failed",
|
|
391
|
-
analyticsProps
|
|
392
|
-
);
|
|
409
|
+
});
|
|
393
410
|
} catch {}
|
|
394
411
|
process.exit(1);
|
|
395
412
|
}
|
|
@@ -417,11 +434,11 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
417
434
|
? `postgresql://${directUser}:${directPass}@${directHost}${directPort}/${directDbName}`
|
|
418
435
|
: null;
|
|
419
436
|
|
|
420
|
-
const claimUrl = `${CLAIM_DB_WORKER_URL}?projectID=${projectId}&utm_source=${
|
|
437
|
+
const claimUrl = `${CLAIM_DB_WORKER_URL}?projectID=${projectId}&utm_source=${CLI_NAME}&utm_medium=cli`;
|
|
421
438
|
const expiryDate = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
422
439
|
|
|
423
440
|
if (returnJson && !result.error) {
|
|
424
|
-
|
|
441
|
+
return {
|
|
425
442
|
connectionString: prismaConn,
|
|
426
443
|
directConnectionString: directConn,
|
|
427
444
|
claimUrl: claimUrl,
|
|
@@ -430,12 +447,6 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
430
447
|
name: database?.name,
|
|
431
448
|
projectId: projectId,
|
|
432
449
|
};
|
|
433
|
-
|
|
434
|
-
if (userAgent) {
|
|
435
|
-
jsonResponse.source = userAgent;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return jsonResponse;
|
|
439
450
|
}
|
|
440
451
|
|
|
441
452
|
if (result.error) {
|
|
@@ -454,21 +465,12 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
454
465
|
}
|
|
455
466
|
|
|
456
467
|
try {
|
|
457
|
-
|
|
468
|
+
await analytics.capture("create_db:database_creation_failed", {
|
|
458
469
|
command: CLI_NAME,
|
|
459
470
|
region: region,
|
|
460
471
|
"error-type": "api_error",
|
|
461
472
|
"error-message": result.error.message,
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
if (userAgent) {
|
|
465
|
-
analyticsProps["user-agent"] = userAgent;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
await analytics.capture(
|
|
469
|
-
"create_db:database_creation_failed",
|
|
470
|
-
analyticsProps
|
|
471
|
-
);
|
|
473
|
+
});
|
|
472
474
|
} catch (error) {}
|
|
473
475
|
process.exit(1);
|
|
474
476
|
}
|
|
@@ -525,17 +527,8 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
|
|
|
525
527
|
async function main() {
|
|
526
528
|
try {
|
|
527
529
|
const rawArgs = process.argv.slice(2);
|
|
528
|
-
|
|
529
|
-
const { flags } = await parseArgs();
|
|
530
|
-
|
|
531
|
-
let userAgent;
|
|
532
|
-
const userEnvVars = readUserEnvFile();
|
|
533
|
-
if (userEnvVars.PRISMA_ACTOR_NAME && userEnvVars.PRISMA_ACTOR_PROJECT) {
|
|
534
|
-
userAgent = `${userEnvVars.PRISMA_ACTOR_NAME}/${userEnvVars.PRISMA_ACTOR_PROJECT}`;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
530
|
try {
|
|
538
|
-
|
|
531
|
+
await analytics.capture("create_db:cli_command_ran", {
|
|
539
532
|
command: CLI_NAME,
|
|
540
533
|
"full-command": `${CLI_NAME} ${rawArgs.join(" ")}`.trim(),
|
|
541
534
|
"has-region-flag":
|
|
@@ -545,27 +538,21 @@ async function main() {
|
|
|
545
538
|
"has-help-flag": rawArgs.includes("--help") || rawArgs.includes("-h"),
|
|
546
539
|
"has-list-regions-flag": rawArgs.includes("--list-regions"),
|
|
547
540
|
"has-json-flag": rawArgs.includes("--json") || rawArgs.includes("-j"),
|
|
548
|
-
"has-source-from-env": !!userAgent,
|
|
549
541
|
"node-version": process.version,
|
|
550
542
|
platform: process.platform,
|
|
551
543
|
arch: process.arch,
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
if (userAgent) {
|
|
555
|
-
analyticsProps["user-agent"] = userAgent;
|
|
556
|
-
}
|
|
544
|
+
});
|
|
545
|
+
} catch (error) {}
|
|
557
546
|
|
|
558
|
-
|
|
559
|
-
} catch (error) {
|
|
560
|
-
console.error("Error:", error.message);
|
|
561
|
-
}
|
|
547
|
+
const { flags } = await parseArgs();
|
|
562
548
|
|
|
563
549
|
if (!flags.help && !flags.json) {
|
|
564
550
|
await isOffline();
|
|
565
551
|
}
|
|
566
552
|
|
|
567
553
|
let name = new Date().toISOString();
|
|
568
|
-
let
|
|
554
|
+
let userLocation = await detectUserLocation();
|
|
555
|
+
let region = getRegionClosestToLocation(userLocation) || "us-east-1";
|
|
569
556
|
let chooseRegionPrompt = false;
|
|
570
557
|
|
|
571
558
|
if (flags.help) {
|
|
@@ -581,17 +568,11 @@ async function main() {
|
|
|
581
568
|
region = flags.region;
|
|
582
569
|
|
|
583
570
|
try {
|
|
584
|
-
|
|
571
|
+
await analytics.capture("create_db:region_selected", {
|
|
585
572
|
command: CLI_NAME,
|
|
586
573
|
region: region,
|
|
587
574
|
"selection-method": "flag",
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
if (userAgent) {
|
|
591
|
-
analyticsProps["user-agent"] = userAgent;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
await analytics.capture("create_db:region_selected", analyticsProps);
|
|
575
|
+
});
|
|
595
576
|
} catch (error) {}
|
|
596
577
|
}
|
|
597
578
|
|
|
@@ -602,11 +583,11 @@ async function main() {
|
|
|
602
583
|
if (flags.json) {
|
|
603
584
|
try {
|
|
604
585
|
if (chooseRegionPrompt) {
|
|
605
|
-
region = await promptForRegion(region
|
|
586
|
+
region = await promptForRegion(region);
|
|
606
587
|
} else {
|
|
607
588
|
await validateRegion(region, true);
|
|
608
589
|
}
|
|
609
|
-
const result = await createDatabase(name, region,
|
|
590
|
+
const result = await createDatabase(name, region, true);
|
|
610
591
|
console.log(JSON.stringify(result, null, 2));
|
|
611
592
|
process.exit(0);
|
|
612
593
|
} catch (e) {
|
|
@@ -631,12 +612,12 @@ async function main() {
|
|
|
631
612
|
)
|
|
632
613
|
);
|
|
633
614
|
if (chooseRegionPrompt) {
|
|
634
|
-
region = await promptForRegion(region
|
|
615
|
+
region = await promptForRegion(region);
|
|
635
616
|
}
|
|
636
617
|
|
|
637
618
|
region = await validateRegion(region);
|
|
638
619
|
|
|
639
|
-
await createDatabase(name, region
|
|
620
|
+
await createDatabase(name, region);
|
|
640
621
|
|
|
641
622
|
outro("");
|
|
642
623
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-db",
|
|
3
|
-
"version": "1.0.3-
|
|
3
|
+
"version": "1.0.3-pr47-DC-4759-set-region-to-be-near-user-17250359916.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": "",
|