create-db 1.0.3-pr48-DC-4894-posthog-fix-17269175017.0 → 1.0.3
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 +50 -0
- package/index.js +75 -38
- package/package.json +1 -1
package/analytics.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
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_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";
|
|
15
|
+
|
|
16
|
+
const payload = {
|
|
17
|
+
api_key: POSTHOG_KEY,
|
|
18
|
+
event: eventName,
|
|
19
|
+
distinct_id: randomUUID(),
|
|
20
|
+
properties: {
|
|
21
|
+
$process_person_profile: false,
|
|
22
|
+
...properties,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch(POSTHOG_CAPTURE_URL, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify(payload),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new EventCaptureError(eventName, response.statusText);
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Silently fail analytics to not disrupt user experience
|
|
40
|
+
if (process.env.NODE_ENV === "development") {
|
|
41
|
+
console.error("Analytics error:", error.message);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Create a singleton instance
|
|
48
|
+
const analytics = new PosthogEventCapture();
|
|
49
|
+
|
|
50
|
+
export { analytics, EventCaptureError };
|
package/index.js
CHANGED
|
@@ -6,32 +6,80 @@ dotenv.config();
|
|
|
6
6
|
import { select, spinner, intro, outro, log, cancel } from "@clack/prompts";
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import terminalLink from "terminal-link";
|
|
9
|
+
import { analytics } from "./analytics.js";
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
const CREATE_DB_WORKER_URL =
|
|
12
|
+
process.env.CREATE_DB_WORKER_URL || "https://create-db-temp.prisma.io";
|
|
13
|
+
const CLAIM_DB_WORKER_URL =
|
|
14
|
+
process.env.CLAIM_DB_WORKER_URL || "https://create-db.prisma.io";
|
|
15
|
+
|
|
16
|
+
async function detectUserLocation() {
|
|
11
17
|
try {
|
|
12
|
-
const response = await fetch(
|
|
13
|
-
method: "
|
|
14
|
-
headers: {
|
|
15
|
-
|
|
18
|
+
const response = await fetch("https://ipapi.co/json/", {
|
|
19
|
+
method: "GET",
|
|
20
|
+
headers: {
|
|
21
|
+
"User-Agent": "create-db-cli/1.0",
|
|
22
|
+
},
|
|
16
23
|
});
|
|
17
24
|
|
|
18
25
|
if (!response.ok) {
|
|
19
|
-
throw new Error(
|
|
20
|
-
`Analytics request failed: ${response.status} ${response.statusText}`
|
|
21
|
-
);
|
|
26
|
+
throw new Error(`Failed to fetch location data: ${response.status}`);
|
|
22
27
|
}
|
|
23
28
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
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
|
+
}
|
|
29
41
|
}
|
|
30
42
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
}
|
|
35
83
|
|
|
36
84
|
async function listRegions() {
|
|
37
85
|
try {
|
|
@@ -284,7 +332,7 @@ async function promptForRegion(defaultRegion) {
|
|
|
284
332
|
}
|
|
285
333
|
|
|
286
334
|
try {
|
|
287
|
-
await
|
|
335
|
+
await analytics.capture("create_db:region_selected", {
|
|
288
336
|
command: CLI_NAME,
|
|
289
337
|
region: region,
|
|
290
338
|
"selection-method": "interactive",
|
|
@@ -304,19 +352,7 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
304
352
|
const resp = await fetch(`${CREATE_DB_WORKER_URL}/create`, {
|
|
305
353
|
method: "POST",
|
|
306
354
|
headers: { "Content-Type": "application/json" },
|
|
307
|
-
body: JSON.stringify({
|
|
308
|
-
region,
|
|
309
|
-
name,
|
|
310
|
-
utm_source: CLI_NAME,
|
|
311
|
-
analytics: {
|
|
312
|
-
eventName: "create_db:database_created",
|
|
313
|
-
properties: {
|
|
314
|
-
command: CLI_NAME,
|
|
315
|
-
region: region,
|
|
316
|
-
utm_source: CLI_NAME,
|
|
317
|
-
},
|
|
318
|
-
},
|
|
319
|
-
}),
|
|
355
|
+
body: JSON.stringify({ region, name, utm_source: CLI_NAME }),
|
|
320
356
|
});
|
|
321
357
|
|
|
322
358
|
if (resp.status === 429) {
|
|
@@ -336,7 +372,7 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
336
372
|
}
|
|
337
373
|
|
|
338
374
|
try {
|
|
339
|
-
await
|
|
375
|
+
await analytics.capture("create_db:database_creation_failed", {
|
|
340
376
|
command: CLI_NAME,
|
|
341
377
|
region: region,
|
|
342
378
|
"error-type": "rate_limit",
|
|
@@ -365,13 +401,13 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
365
401
|
s.stop("Unexpected response from create service.");
|
|
366
402
|
}
|
|
367
403
|
try {
|
|
368
|
-
await
|
|
404
|
+
await analytics.capture("create_db:database_creation_failed", {
|
|
369
405
|
command: CLI_NAME,
|
|
370
406
|
region,
|
|
371
407
|
"error-type": "invalid_json",
|
|
372
408
|
"status-code": resp.status,
|
|
373
409
|
});
|
|
374
|
-
} catch
|
|
410
|
+
} catch {}
|
|
375
411
|
process.exit(1);
|
|
376
412
|
}
|
|
377
413
|
|
|
@@ -429,7 +465,7 @@ async function createDatabase(name, region, returnJson = false) {
|
|
|
429
465
|
}
|
|
430
466
|
|
|
431
467
|
try {
|
|
432
|
-
await
|
|
468
|
+
await analytics.capture("create_db:database_creation_failed", {
|
|
433
469
|
command: CLI_NAME,
|
|
434
470
|
region: region,
|
|
435
471
|
"error-type": "api_error",
|
|
@@ -492,7 +528,7 @@ async function main() {
|
|
|
492
528
|
try {
|
|
493
529
|
const rawArgs = process.argv.slice(2);
|
|
494
530
|
try {
|
|
495
|
-
await
|
|
531
|
+
await analytics.capture("create_db:cli_command_ran", {
|
|
496
532
|
command: CLI_NAME,
|
|
497
533
|
"full-command": `${CLI_NAME} ${rawArgs.join(" ")}`.trim(),
|
|
498
534
|
"has-region-flag":
|
|
@@ -515,7 +551,8 @@ async function main() {
|
|
|
515
551
|
}
|
|
516
552
|
|
|
517
553
|
let name = new Date().toISOString();
|
|
518
|
-
let
|
|
554
|
+
let userLocation = await detectUserLocation();
|
|
555
|
+
let region = getRegionClosestToLocation(userLocation) || "us-east-1";
|
|
519
556
|
let chooseRegionPrompt = false;
|
|
520
557
|
|
|
521
558
|
if (flags.help) {
|
|
@@ -531,7 +568,7 @@ async function main() {
|
|
|
531
568
|
region = flags.region;
|
|
532
569
|
|
|
533
570
|
try {
|
|
534
|
-
await
|
|
571
|
+
await analytics.capture("create_db:region_selected", {
|
|
535
572
|
command: CLI_NAME,
|
|
536
573
|
region: region,
|
|
537
574
|
"selection-method": "flag",
|
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",
|
|
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": "",
|