create-db 1.1.1-pr67-overhaul-19905444027.0 → 1.1.1-pr67-overhaul-20097603007.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/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as createDbCli } from "./src-CWxeHoyI.mjs";
2
+ import { n as createDbCli } from "./src-CFVkopQv.mjs";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createDbCli().run();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { a as isDatabaseError, i as RegionSchema, n as createDbCli, o as isDatabaseSuccess, r as regions, t as create } from "./src-CWxeHoyI.mjs";
2
+ import { a as isDatabaseError, i as RegionSchema, n as createDbCli, o as isDatabaseSuccess, r as regions, t as create } from "./src-CFVkopQv.mjs";
3
3
 
4
4
  export { RegionSchema, create, createDbCli, isDatabaseError, isDatabaseSuccess, regions };
@@ -4,11 +4,11 @@ import { createRouterClient, os } from "@orpc/server";
4
4
  import { randomUUID } from "crypto";
5
5
  import dotenv from "dotenv";
6
6
  import fs from "fs";
7
- import path from "path";
8
7
  import pc from "picocolors";
9
8
  import terminalLink from "terminal-link";
10
9
  import { createCli } from "trpc-cli";
11
10
  import z$1, { z } from "zod";
11
+ import path from "path";
12
12
 
13
13
  //#region src/types.ts
14
14
  const RegionSchema = z$1.enum([
@@ -27,43 +27,14 @@ function isDatabaseSuccess(result) {
27
27
  }
28
28
 
29
29
  //#endregion
30
- //#region src/index.ts
31
- dotenv.config({ quiet: true });
32
- const CREATE_DB_WORKER_URL = process.env.CREATE_DB_WORKER_URL || "https://create-db-temp.prisma.io";
33
- const CLAIM_DB_WORKER_URL = process.env.CLAIM_DB_WORKER_URL || "https://create-db.prisma.io";
34
- const REGION_COORDINATES = {
35
- "ap-southeast-1": {
36
- lat: 1.3521,
37
- lng: 103.8198
38
- },
39
- "ap-northeast-1": {
40
- lat: 35.6762,
41
- lng: 139.6503
42
- },
43
- "eu-central-1": {
44
- lat: 50.1109,
45
- lng: 8.6821
46
- },
47
- "eu-west-3": {
48
- lat: 48.8566,
49
- lng: 2.3522
50
- },
51
- "us-east-1": {
52
- lat: 38.9072,
53
- lng: -77.0369
54
- },
55
- "us-west-1": {
56
- lat: 37.7749,
57
- lng: -122.4194
58
- }
59
- };
30
+ //#region src/analytics.ts
60
31
  const pendingAnalytics = [];
61
- async function sendAnalytics(eventName, properties, cliRunId) {
32
+ async function sendAnalytics(eventName, properties, cliRunId, workerUrl) {
62
33
  const controller = new AbortController();
63
34
  const timer = setTimeout(() => controller.abort(), 5e3);
64
35
  const promise = (async () => {
65
36
  try {
66
- await fetch(`${CREATE_DB_WORKER_URL}/analytics`, {
37
+ await fetch(`${workerUrl}/analytics`, {
67
38
  method: "POST",
68
39
  headers: { "Content-Type": "application/json" },
69
40
  body: JSON.stringify({
@@ -85,93 +56,19 @@ async function flushAnalytics(maxWaitMs = 500) {
85
56
  if (pendingAnalytics.length === 0) return;
86
57
  await Promise.race([Promise.all(pendingAnalytics), new Promise((resolve) => setTimeout(resolve, maxWaitMs))]);
87
58
  }
59
+
60
+ //#endregion
61
+ //#region src/database.ts
88
62
  function getCommandName() {
89
63
  const executable = process.argv[1] || "create-db";
90
64
  if (executable.includes("create-pg")) return "create-pg";
91
65
  if (executable.includes("create-postgres")) return "create-postgres";
92
66
  return "create-db";
93
67
  }
94
- async function detectUserLocation() {
95
- try {
96
- const response = await fetch("https://ipapi.co/json/", {
97
- method: "GET",
98
- headers: { "User-Agent": "create-db-cli/1.0" }
99
- });
100
- if (!response.ok) return null;
101
- const data = await response.json();
102
- return {
103
- country: data.country_code,
104
- continent: data.continent_code,
105
- city: data.city,
106
- region: data.region,
107
- latitude: data.latitude,
108
- longitude: data.longitude
109
- };
110
- } catch {
111
- return null;
112
- }
113
- }
114
- function getRegionClosestToLocation(userLocation) {
115
- if (!userLocation) return null;
116
- const userLat = parseFloat(String(userLocation.latitude));
117
- const userLng = parseFloat(String(userLocation.longitude));
118
- if (isNaN(userLat) || isNaN(userLng)) return null;
119
- let closestRegion = null;
120
- let minDistance = Infinity;
121
- for (const [region, coordinates] of Object.entries(REGION_COORDINATES)) {
122
- const latDiff = (userLat - coordinates.lat) * Math.PI / 180;
123
- const lngDiff = (userLng - coordinates.lng) * Math.PI / 180;
124
- const a = Math.sin(latDiff / 2) ** 2 + Math.cos(userLat * Math.PI / 180) * Math.cos(coordinates.lat * Math.PI / 180) * Math.sin(lngDiff / 2) ** 2;
125
- const distance = 6371 * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
126
- if (distance < minDistance) {
127
- minDistance = distance;
128
- closestRegion = region;
129
- }
130
- }
131
- return closestRegion;
132
- }
133
- function readUserEnvFile() {
134
- const envPath = path.join(process.cwd(), ".env");
135
- if (!fs.existsSync(envPath)) return {};
136
- const envContent = fs.readFileSync(envPath, "utf8");
137
- const envVars = {};
138
- for (const line of envContent.split("\n")) {
139
- const trimmed = line.trim();
140
- if (trimmed && !trimmed.startsWith("#")) {
141
- const [key, ...valueParts] = trimmed.split("=");
142
- if (key && valueParts.length > 0) {
143
- const value = valueParts.join("=").replace(/^["']|["']$/g, "");
144
- envVars[key.trim()] = value.trim();
145
- }
146
- }
147
- }
148
- return envVars;
149
- }
150
- async function checkOnline() {
151
- try {
152
- if (!(await fetch(`${CREATE_DB_WORKER_URL}/health`)).ok) throw new Error("API not available");
153
- } catch {
154
- console.error(pc.bold(pc.red("\n✖ Error: Cannot reach Prisma Postgres API server.\n")));
155
- console.error(pc.dim(`Check your internet connection or visit ${pc.green("https://www.prisma-status.com/")}\n`));
156
- await flushAnalytics();
157
- process.exit(1);
158
- }
159
- }
160
- async function getRegions() {
161
- const res = await fetch(`${CREATE_DB_WORKER_URL}/regions`);
162
- if (!res.ok) throw new Error(`Failed to fetch regions. Status: ${res.status} ${res.statusText}`);
163
- const data = await res.json();
164
- return (Array.isArray(data) ? data : data.data ?? []).filter((region) => region.status === "available");
165
- }
166
- async function validateRegion(region) {
167
- const regionIds = (await getRegions()).map((r) => r.id);
168
- if (!regionIds.includes(region)) throw new Error(`Invalid region: ${region}. Available regions: ${regionIds.join(", ")}`);
169
- return region;
170
- }
171
- async function createDatabaseCore(region, userAgent, cliRunId) {
68
+ async function createDatabaseCore(region, createDbWorkerUrl, claimDbWorkerUrl, userAgent, cliRunId) {
172
69
  const name = (/* @__PURE__ */ new Date()).toISOString();
173
70
  const runId = cliRunId ?? randomUUID();
174
- const resp = await fetch(`${CREATE_DB_WORKER_URL}/create`, {
71
+ const resp = await fetch(`${createDbWorkerUrl}/create`, {
175
72
  method: "POST",
176
73
  headers: { "Content-Type": "application/json" },
177
74
  body: JSON.stringify({
@@ -186,7 +83,7 @@ async function createDatabaseCore(region, userAgent, cliRunId) {
186
83
  region,
187
84
  "error-type": "rate_limit",
188
85
  "status-code": 429
189
- }, runId);
86
+ }, runId, createDbWorkerUrl);
190
87
  return {
191
88
  success: false,
192
89
  error: "rate_limit_exceeded",
@@ -204,7 +101,7 @@ async function createDatabaseCore(region, userAgent, cliRunId) {
204
101
  region,
205
102
  "error-type": "invalid_json",
206
103
  "status-code": resp.status
207
- }, runId);
104
+ }, runId, createDbWorkerUrl);
208
105
  return {
209
106
  success: false,
210
107
  error: "invalid_json",
@@ -218,7 +115,7 @@ async function createDatabaseCore(region, userAgent, cliRunId) {
218
115
  region,
219
116
  "error-type": "api_error",
220
117
  "error-message": result.error.message
221
- }, runId);
118
+ }, runId, createDbWorkerUrl);
222
119
  return {
223
120
  success: false,
224
121
  error: "api_error",
@@ -237,12 +134,12 @@ async function createDatabaseCore(region, userAgent, cliRunId) {
237
134
  const directPort = directConnDetails?.port ? `:${directConnDetails.port}` : "";
238
135
  const directDbName = directConnDetails?.database || "postgres";
239
136
  const connectionString = directConnDetails && directHost ? `postgresql://${directUser}:${directPass}@${directHost}${directPort}/${directDbName}?sslmode=require` : null;
240
- const claimUrl = `${CLAIM_DB_WORKER_URL}/claim?projectID=${projectId}&utm_source=${userAgent || getCommandName()}&utm_medium=cli`;
137
+ const claimUrl = `${claimDbWorkerUrl}/claim?projectID=${projectId}&utm_source=${userAgent || getCommandName()}&utm_medium=cli`;
241
138
  const expiryDate = new Date(Date.now() + 1440 * 60 * 1e3);
242
139
  sendAnalytics("create_db:database_created", {
243
140
  region,
244
141
  utm_source: getCommandName()
245
- }, runId);
142
+ }, runId, createDbWorkerUrl);
246
143
  return {
247
144
  success: true,
248
145
  connectionString,
@@ -254,6 +151,173 @@ async function createDatabaseCore(region, userAgent, cliRunId) {
254
151
  userAgent
255
152
  };
256
153
  }
154
+
155
+ //#endregion
156
+ //#region src/env-utils.ts
157
+ function readUserEnvFile() {
158
+ const envPath = path.join(process.cwd(), ".env");
159
+ if (!fs.existsSync(envPath)) return {};
160
+ const envContent = fs.readFileSync(envPath, "utf8");
161
+ const envVars = {};
162
+ for (const line of envContent.split("\n")) {
163
+ const trimmed = line.trim();
164
+ if (trimmed && !trimmed.startsWith("#")) {
165
+ const [key, ...valueParts] = trimmed.split("=");
166
+ if (key && valueParts.length > 0) {
167
+ const value = valueParts.join("=").replace(/^["']|["']$/g, "");
168
+ envVars[key.trim()] = value.trim();
169
+ }
170
+ }
171
+ }
172
+ return envVars;
173
+ }
174
+
175
+ //#endregion
176
+ //#region src/geolocation.ts
177
+ const TEST_LOCATION = null;
178
+ const REGION_COORDINATES = {
179
+ "ap-southeast-1": {
180
+ lat: 1.3521,
181
+ lng: 103.8198
182
+ },
183
+ "ap-northeast-1": {
184
+ lat: 35.6762,
185
+ lng: 139.6503
186
+ },
187
+ "eu-central-1": {
188
+ lat: 50.1109,
189
+ lng: 8.6821
190
+ },
191
+ "eu-west-3": {
192
+ lat: 48.8566,
193
+ lng: 2.3522
194
+ },
195
+ "us-east-1": {
196
+ lat: 38.9072,
197
+ lng: -77.0369
198
+ },
199
+ "us-west-1": {
200
+ lat: 37.7749,
201
+ lng: -122.4194
202
+ }
203
+ };
204
+ /**
205
+ * Calculate the great-circle distance between two points on Earth using the Haversine formula.
206
+ * @param lat1 Latitude of first point in degrees
207
+ * @param lng1 Longitude of first point in degrees
208
+ * @param lat2 Latitude of second point in degrees
209
+ * @param lng2 Longitude of second point in degrees
210
+ * @returns Distance in kilometers
211
+ */
212
+ function calculateHaversineDistance(lat1, lng1, lat2, lng2) {
213
+ const EARTH_RADIUS_KM = 6371;
214
+ const toRadians = (degrees) => degrees * Math.PI / 180;
215
+ const lat1Rad = toRadians(lat1);
216
+ const lat2Rad = toRadians(lat2);
217
+ const deltaLatRad = toRadians(lat2 - lat1);
218
+ const deltaLngRad = toRadians(lng2 - lng1);
219
+ const a = Math.sin(deltaLatRad / 2) ** 2 + Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(deltaLngRad / 2) ** 2;
220
+ return EARTH_RADIUS_KM * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)));
221
+ }
222
+ /**
223
+ * Detect user's location via IP geolocation API or test location override.
224
+ * Returns null if detection fails or times out.
225
+ */
226
+ async function detectUserLocation() {
227
+ if (TEST_LOCATION !== null) return {
228
+ country: "TEST",
229
+ continent: "TEST",
230
+ city: "Test City",
231
+ region: "Test Region",
232
+ latitude: TEST_LOCATION.latitude,
233
+ longitude: TEST_LOCATION.longitude
234
+ };
235
+ const controller = new AbortController();
236
+ const timeout = setTimeout(() => controller.abort(), 3e3);
237
+ try {
238
+ const response = await fetch("https://ipapi.co/json/", {
239
+ method: "GET",
240
+ headers: { "User-Agent": "create-db-cli/1.0" },
241
+ signal: controller.signal
242
+ });
243
+ if (!response.ok) return null;
244
+ const data = await response.json();
245
+ if (typeof data.latitude !== "number" || typeof data.longitude !== "number" || !Number.isFinite(data.latitude) || !Number.isFinite(data.longitude)) return null;
246
+ return {
247
+ country: data.country_code,
248
+ continent: data.continent_code,
249
+ city: data.city,
250
+ region: data.region,
251
+ latitude: data.latitude,
252
+ longitude: data.longitude
253
+ };
254
+ } catch {
255
+ return null;
256
+ } finally {
257
+ clearTimeout(timeout);
258
+ }
259
+ }
260
+ /**
261
+ * Find the closest AWS region to a given location using Haversine distance.
262
+ * Returns null if the location is invalid or missing coordinates.
263
+ */
264
+ function getRegionClosestToLocation(userLocation) {
265
+ if (!userLocation || userLocation.latitude == null || userLocation.longitude == null) return null;
266
+ const userLat = typeof userLocation.latitude === "number" ? userLocation.latitude : parseFloat(String(userLocation.latitude));
267
+ const userLng = typeof userLocation.longitude === "number" ? userLocation.longitude : parseFloat(String(userLocation.longitude));
268
+ if (!Number.isFinite(userLat) || !Number.isFinite(userLng)) return null;
269
+ let closestRegion = null;
270
+ let minDistance = Infinity;
271
+ for (const [regionId, coords] of Object.entries(REGION_COORDINATES)) {
272
+ const distance = calculateHaversineDistance(userLat, userLng, coords.lat, coords.lng);
273
+ if (distance < minDistance) {
274
+ minDistance = distance;
275
+ closestRegion = regionId;
276
+ }
277
+ }
278
+ return closestRegion;
279
+ }
280
+
281
+ //#endregion
282
+ //#region src/regions.ts
283
+ async function checkOnline(workerUrl) {
284
+ try {
285
+ if (!(await fetch(`${workerUrl}/health`)).ok) throw new Error("API not available");
286
+ } catch {
287
+ console.error(pc.bold(pc.red("\n✖ Error: Cannot reach Prisma Postgres API server.\n")));
288
+ console.error(pc.dim(`Check your internet connection or visit ${pc.green("https://www.prisma-status.com/")}\n`));
289
+ throw new Error("Cannot reach API server");
290
+ }
291
+ }
292
+ async function getRegions(workerUrl) {
293
+ const res = await fetch(`${workerUrl}/regions`);
294
+ if (!res.ok) throw new Error(`Failed to fetch regions. Status: ${res.status} ${res.statusText}`);
295
+ const data = await res.json();
296
+ return (Array.isArray(data) ? data : data.data ?? []).filter((region) => region.status === "available");
297
+ }
298
+ async function validateRegion(region, workerUrl) {
299
+ const regionIds = (await getRegions(workerUrl)).map((r) => r.id);
300
+ if (!regionIds.includes(region)) throw new Error(`Invalid region: ${region}. Available regions: ${regionIds.join(", ")}`);
301
+ return region;
302
+ }
303
+
304
+ //#endregion
305
+ //#region src/index.ts
306
+ dotenv.config({ quiet: true });
307
+ const CREATE_DB_WORKER_URL = process.env.CREATE_DB_WORKER_URL || "https://create-db-temp.prisma.io";
308
+ const CLAIM_DB_WORKER_URL = process.env.CLAIM_DB_WORKER_URL || "https://create-db.prisma.io";
309
+ const sendAnalyticsWithUrl = (eventName, properties, cliRunId) => sendAnalytics(eventName, properties, cliRunId, CREATE_DB_WORKER_URL);
310
+ const checkOnlineWithUrl = async () => {
311
+ try {
312
+ await checkOnline(CREATE_DB_WORKER_URL);
313
+ } catch {
314
+ await flushAnalytics();
315
+ process.exit(1);
316
+ }
317
+ };
318
+ const getRegionsWithUrl = () => getRegions(CREATE_DB_WORKER_URL);
319
+ const validateRegionWithUrl = (region) => validateRegion(region, CREATE_DB_WORKER_URL);
320
+ const createDatabaseCoreWithUrl = (region, userAgent, cliRunId) => createDatabaseCore(region, CREATE_DB_WORKER_URL, CLAIM_DB_WORKER_URL, userAgent, cliRunId);
257
321
  const router = os.router({
258
322
  create: os.meta({
259
323
  description: "Create a new Prisma Postgres database",
@@ -269,7 +333,7 @@ const router = os.router({
269
333
  let userAgent;
270
334
  const userEnvVars = readUserEnvFile();
271
335
  if (userEnvVars.PRISMA_ACTOR_NAME && userEnvVars.PRISMA_ACTOR_PROJECT) userAgent = `${userEnvVars.PRISMA_ACTOR_NAME}/${userEnvVars.PRISMA_ACTOR_PROJECT}`;
272
- sendAnalytics("create_db:cli_command_ran", {
336
+ sendAnalyticsWithUrl("create_db:cli_command_ran", {
273
337
  command: CLI_NAME,
274
338
  "has-region-flag": !!input.region,
275
339
  "has-interactive-flag": input.interactive,
@@ -286,8 +350,8 @@ const router = os.router({
286
350
  const envEnabled = typeof envPath === "string" && envPath.trim().length > 0;
287
351
  if (input.json || envEnabled) {
288
352
  if (input.interactive) {
289
- await checkOnline();
290
- const regions$1 = await getRegions();
353
+ await checkOnlineWithUrl();
354
+ const regions$1 = await getRegionsWithUrl();
291
355
  const selectedRegion = await select({
292
356
  message: "Choose a region:",
293
357
  options: regions$1.map((r) => ({
@@ -302,19 +366,19 @@ const router = os.router({
302
366
  process.exit(0);
303
367
  }
304
368
  region = selectedRegion;
305
- sendAnalytics("create_db:region_selected", {
369
+ sendAnalyticsWithUrl("create_db:region_selected", {
306
370
  region,
307
371
  "selection-method": "interactive"
308
372
  }, cliRunId);
309
373
  } else if (input.region) {
310
- await validateRegion(region);
311
- sendAnalytics("create_db:region_selected", {
374
+ await validateRegionWithUrl(region);
375
+ sendAnalyticsWithUrl("create_db:region_selected", {
312
376
  region,
313
377
  "selection-method": "flag"
314
378
  }, cliRunId);
315
379
  }
316
- await checkOnline();
317
- const result$1 = await createDatabaseCore(region, userAgent, cliRunId);
380
+ await checkOnlineWithUrl();
381
+ const result$1 = await createDatabaseCoreWithUrl(region, userAgent, cliRunId);
318
382
  await flushAnalytics();
319
383
  if (input.json) {
320
384
  console.log(JSON.stringify(result$1, null, 2));
@@ -344,10 +408,10 @@ const router = os.router({
344
408
  }
345
409
  return;
346
410
  }
347
- await checkOnline();
411
+ await checkOnlineWithUrl();
348
412
  intro(pc.bold(pc.cyan("🚀 Creating a Prisma Postgres database")));
349
413
  if (input.interactive) {
350
- const regions$1 = await getRegions();
414
+ const regions$1 = await getRegionsWithUrl();
351
415
  const selectedRegion = await select({
352
416
  message: "Choose a region:",
353
417
  options: regions$1.map((r) => ({
@@ -362,20 +426,20 @@ const router = os.router({
362
426
  process.exit(0);
363
427
  }
364
428
  region = selectedRegion;
365
- sendAnalytics("create_db:region_selected", {
429
+ sendAnalyticsWithUrl("create_db:region_selected", {
366
430
  region,
367
431
  "selection-method": "interactive"
368
432
  }, cliRunId);
369
433
  } else if (input.region) {
370
- await validateRegion(region);
371
- sendAnalytics("create_db:region_selected", {
434
+ await validateRegionWithUrl(region);
435
+ sendAnalyticsWithUrl("create_db:region_selected", {
372
436
  region,
373
437
  "selection-method": "flag"
374
438
  }, cliRunId);
375
439
  }
376
440
  const s = spinner();
377
441
  s.start(`Creating database in ${pc.cyan(region)}...`);
378
- const result = await createDatabaseCore(region, userAgent, cliRunId);
442
+ const result = await createDatabaseCoreWithUrl(region, userAgent, cliRunId);
379
443
  if (!result.success) {
380
444
  s.stop(pc.red(`Error: ${result.message}`));
381
445
  await flushAnalytics();
@@ -403,7 +467,7 @@ const router = os.router({
403
467
  await flushAnalytics();
404
468
  }),
405
469
  regions: os.meta({ description: "List available Prisma Postgres regions" }).handler(async () => {
406
- const regions$1 = await getRegions();
470
+ const regions$1 = await getRegionsWithUrl();
407
471
  log.message("");
408
472
  log.info(pc.bold(pc.cyan("Available Prisma Postgres regions:")));
409
473
  log.message("");
@@ -443,7 +507,7 @@ createRouterClient(router, { context: {} });
443
507
  * ```
444
508
  */
445
509
  async function create(options) {
446
- return createDatabaseCore(options?.region || "us-east-1", options?.userAgent);
510
+ return createDatabaseCoreWithUrl(options?.region || "us-east-1", options?.userAgent);
447
511
  }
448
512
  /**
449
513
  * List available Prisma Postgres regions programmatically.
@@ -457,7 +521,7 @@ async function create(options) {
457
521
  * ```
458
522
  */
459
523
  async function regions() {
460
- return getRegions();
524
+ return getRegionsWithUrl();
461
525
  }
462
526
 
463
527
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-db",
3
- "version": "1.1.1-pr67-overhaul-19905444027.0",
3
+ "version": "1.1.1-pr67-overhaul-20097603007.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
  "type": "module",
6
6
  "exports": {