create-db 1.0.4-pr45-DC-4829-source-flag-17239715470.0 → 1.0.4-pr48-DC-4894-posthog-fix-17271643844.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 (3) hide show
  1. package/index.js +93 -36
  2. package/package.json +1 -1
  3. package/analytics.js +0 -63
package/index.js CHANGED
@@ -9,13 +9,90 @@ dotenv.config();
9
9
  import { select, spinner, intro, outro, log, cancel } from "@clack/prompts";
10
10
  import chalk from "chalk";
11
11
  import terminalLink from "terminal-link";
12
- import { analytics } from "./analytics.js";
12
+
13
+ async function sendAnalyticsToWorker(eventName, properties = {}) {
14
+ try {
15
+ await fetch(`${CREATE_DB_WORKER_URL}/analytics`, {
16
+ method: "POST",
17
+ headers: { "Content-Type": "application/json" },
18
+ body: JSON.stringify({ eventName, properties }),
19
+ });
20
+ } catch (error) {}
21
+ }
13
22
 
14
23
  const CREATE_DB_WORKER_URL =
15
24
  process.env.CREATE_DB_WORKER_URL || "https://create-db-temp.prisma.io";
16
25
  const CLAIM_DB_WORKER_URL =
17
26
  process.env.CLAIM_DB_WORKER_URL || "https://create-db.prisma.io";
18
27
 
28
+ async function detectUserLocation() {
29
+ try {
30
+ const response = await fetch("https://ipapi.co/json/", {
31
+ method: "GET",
32
+ headers: {
33
+ "User-Agent": "create-db-cli/1.0",
34
+ },
35
+ });
36
+
37
+ if (!response.ok) {
38
+ throw new Error(`Failed to fetch location data: ${response.status}`);
39
+ }
40
+
41
+ const data = await response.json();
42
+ return {
43
+ country: data.country_code,
44
+ continent: data.continent_code,
45
+ city: data.city,
46
+ region: data.region,
47
+ latitude: data.latitude,
48
+ longitude: data.longitude,
49
+ };
50
+ } catch (error) {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ // Region coordinates (latitude, longitude)
56
+ const REGION_COORDINATES = {
57
+ "ap-southeast-1": { lat: 1.3521, lng: 103.8198 }, // Singapore
58
+ "ap-northeast-1": { lat: 35.6762, lng: 139.6503 }, // Tokyo
59
+ "eu-central-1": { lat: 50.1109, lng: 8.6821 }, // Frankfurt
60
+ "eu-west-3": { lat: 48.8566, lng: 2.3522 }, // Paris
61
+ "us-east-1": { lat: 38.9072, lng: -77.0369 }, // N. Virginia
62
+ "us-west-1": { lat: 37.7749, lng: -122.4194 }, // N. California
63
+ };
64
+
65
+ function getRegionClosestToLocation(userLocation) {
66
+ if (!userLocation) return null;
67
+
68
+ const userLat = parseFloat(userLocation.latitude);
69
+ const userLng = parseFloat(userLocation.longitude);
70
+
71
+ let closestRegion = null;
72
+ let minDistance = Infinity;
73
+
74
+ for (const [region, coordinates] of Object.entries(REGION_COORDINATES)) {
75
+ // Simple distance calculation using Haversine formula
76
+ const latDiff = ((userLat - coordinates.lat) * Math.PI) / 180;
77
+ const lngDiff = ((userLng - coordinates.lng) * Math.PI) / 180;
78
+ const a =
79
+ Math.sin(latDiff / 2) * Math.sin(latDiff / 2) +
80
+ Math.cos((userLat * Math.PI) / 180) *
81
+ Math.cos((coordinates.lat * Math.PI) / 180) *
82
+ Math.sin(lngDiff / 2) *
83
+ Math.sin(lngDiff / 2);
84
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
85
+ const distance = 6371 * c; // Earth radius in km
86
+
87
+ if (distance < minDistance) {
88
+ minDistance = distance;
89
+ closestRegion = region;
90
+ }
91
+ }
92
+
93
+ return closestRegion;
94
+ }
95
+
19
96
  async function listRegions() {
20
97
  try {
21
98
  const regions = await getRegions();
@@ -292,14 +369,12 @@ async function promptForRegion(defaultRegion, userAgent) {
292
369
  }
293
370
 
294
371
  try {
295
- const analyticsProps = {
372
+ await sendAnalyticsToWorker("create_db:region_selected", {
296
373
  command: CLI_NAME,
297
374
  region: region,
298
375
  "selection-method": "interactive",
299
376
  "user-agent": userAgent,
300
- };
301
-
302
- await analytics.capture("create_db:region_selected", analyticsProps);
377
+ });
303
378
  } catch (error) {}
304
379
 
305
380
  return region;
@@ -339,18 +414,13 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
339
414
  }
340
415
 
341
416
  try {
342
- const analyticsProps = {
417
+ await sendAnalyticsToWorker("create_db:database_creation_failed", {
343
418
  command: CLI_NAME,
344
419
  region: region,
345
420
  "error-type": "rate_limit",
346
421
  "status-code": 429,
347
422
  "user-agent": userAgent,
348
- };
349
-
350
- await analytics.capture(
351
- "create_db:database_creation_failed",
352
- analyticsProps
353
- );
423
+ });
354
424
  } catch (error) {}
355
425
 
356
426
  process.exit(1);
@@ -374,18 +444,13 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
374
444
  s.stop("Unexpected response from create service.");
375
445
  }
376
446
  try {
377
- const analyticsProps = {
447
+ await sendAnalyticsToWorker("create_db:database_creation_failed", {
378
448
  command: CLI_NAME,
379
449
  region,
380
450
  "error-type": "invalid_json",
381
451
  "status-code": resp.status,
382
452
  "user-agent": userAgent,
383
- };
384
-
385
- await analytics.capture(
386
- "create_db:database_creation_failed",
387
- analyticsProps
388
- );
453
+ });
389
454
  } catch (error) {}
390
455
  process.exit(1);
391
456
  }
@@ -410,7 +475,7 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
410
475
  const directDbName = directConnDetails?.database || "postgres";
411
476
  const directConn =
412
477
  directConnDetails && directHost
413
- ? `postgresql://${directUser}:${directPass}@${directHost}${directPort}/${directDbName}`
478
+ ? `postgresql://${directUser}:${directPass}@${directHost}${directPort}/${directDbName}?sslmode=require`
414
479
  : null;
415
480
 
416
481
  const claimUrl = `${CLAIM_DB_WORKER_URL}?projectID=${projectId}&utm_source=${userAgent}&utm_medium=cli`;
@@ -450,18 +515,13 @@ async function createDatabase(name, region, userAgent, returnJson = false) {
450
515
  }
451
516
 
452
517
  try {
453
- const analyticsProps = {
518
+ await sendAnalyticsToWorker("create_db:database_creation_failed", {
454
519
  command: CLI_NAME,
455
520
  region: region,
456
521
  "error-type": "api_error",
457
522
  "error-message": result.error.message,
458
523
  "user-agent": userAgent,
459
- };
460
-
461
- await analytics.capture(
462
- "create_db:database_creation_failed",
463
- analyticsProps
464
- );
524
+ });
465
525
  } catch (error) {}
466
526
  process.exit(1);
467
527
  }
@@ -528,7 +588,7 @@ async function main() {
528
588
  }
529
589
 
530
590
  try {
531
- const analyticsProps = {
591
+ await sendAnalyticsToWorker("create_db:cli_command_ran", {
532
592
  command: CLI_NAME,
533
593
  "full-command": `${CLI_NAME} ${rawArgs.join(" ")}`.trim(),
534
594
  "has-region-flag":
@@ -543,9 +603,7 @@ async function main() {
543
603
  platform: process.platform,
544
604
  arch: process.arch,
545
605
  "user-agent": userAgent,
546
- };
547
-
548
- await analytics.capture("create_db:cli_command_ran", analyticsProps);
606
+ });
549
607
  } catch (error) {
550
608
  console.error("Error:", error.message);
551
609
  }
@@ -555,7 +613,8 @@ async function main() {
555
613
  }
556
614
 
557
615
  let name = new Date().toISOString();
558
- let region = "us-east-1";
616
+ let userLocation = await detectUserLocation();
617
+ let region = getRegionClosestToLocation(userLocation) || "us-east-1";
559
618
  let chooseRegionPrompt = false;
560
619
 
561
620
  if (flags.help) {
@@ -571,14 +630,12 @@ async function main() {
571
630
  region = flags.region;
572
631
 
573
632
  try {
574
- const analyticsProps = {
633
+ await sendAnalyticsToWorker("create_db:region_selected", {
575
634
  command: CLI_NAME,
576
635
  region: region,
577
636
  "selection-method": "flag",
578
637
  "user-agent": userAgent,
579
- };
580
-
581
- await analytics.capture("create_db:region_selected", analyticsProps);
638
+ });
582
639
  } catch (error) {}
583
640
  }
584
641
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-db",
3
- "version": "1.0.4-pr45-DC-4829-source-flag-17239715470.0",
3
+ "version": "1.0.4-pr48-DC-4894-posthog-fix-17271643844.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": "",
package/analytics.js DELETED
@@ -1,63 +0,0 @@
1
- import { randomUUID } from "crypto";
2
-
3
- class EventCaptureError extends Error {
4
- constructor(event, status) {
5
- super(`Failed to submit PostHog event '${event}': ${status}`);
6
- }
7
- }
8
-
9
- class PosthogEventCapture {
10
- async capture(eventName, properties = {}) {
11
- const POSTHOG_API_HOST = process.env.POSTHOG_API_HOST;
12
- const POSTHOG_KEY = process.env.POSTHOG_API_KEY;
13
-
14
- if (
15
- !POSTHOG_API_HOST ||
16
- !POSTHOG_KEY ||
17
- POSTHOG_API_HOST.trim() === "" ||
18
- POSTHOG_KEY.trim() === ""
19
- ) {
20
- if (process.env.NODE_ENV === "development") {
21
- console.warn(
22
- "Analytics disabled: missing POSTHOG_API_HOST or POSTHOG_API_KEY."
23
- );
24
- }
25
- return;
26
- }
27
-
28
- const POSTHOG_CAPTURE_URL = `${POSTHOG_API_HOST.replace(/\/+$/, "")}/capture`;
29
-
30
- const payload = {
31
- api_key: POSTHOG_KEY,
32
- event: eventName,
33
- distinct_id: randomUUID(),
34
- properties: {
35
- $process_person_profile: false,
36
- ...properties,
37
- },
38
- };
39
-
40
- try {
41
- const response = await fetch(POSTHOG_CAPTURE_URL, {
42
- method: "POST",
43
- headers: {
44
- "Content-Type": "application/json",
45
- },
46
- body: JSON.stringify(payload),
47
- });
48
-
49
- if (!response.ok) {
50
- throw new EventCaptureError(eventName, response.statusText);
51
- }
52
- } catch (error) {
53
- if (process.env.NODE_ENV === "development") {
54
- console.error("Analytics error:", error.message);
55
- }
56
- }
57
- }
58
- }
59
-
60
- // Create a singleton instance
61
- const analytics = new PosthogEventCapture();
62
-
63
- export { analytics, EventCaptureError };