zuro-cli 0.0.2-beta.15 → 0.0.2-beta.16

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/index.mjs CHANGED
@@ -1332,27 +1332,15 @@ var UPLOAD_PRESETS = {
1332
1332
  mimeTypes: ["video/mp4", "video/quicktime", "video/webm"],
1333
1333
  maxFileSize: 100 * 1024 * 1024,
1334
1334
  maxFiles: 1
1335
- },
1336
- mixed: {
1337
- mimeTypes: [
1338
- "image/jpeg",
1339
- "image/png",
1340
- "image/webp",
1341
- "application/pdf",
1342
- "text/plain",
1343
- "video/mp4"
1344
- ],
1345
- maxFileSize: 25 * 1024 * 1024,
1346
- maxFiles: 5
1347
1335
  }
1348
1336
  };
1349
1337
  function getUploadEnvSchemaFields(provider) {
1350
1338
  const shared = [
1351
1339
  { name: "UPLOAD_PROVIDER", schema: `z.enum(["s3", "r2", "cloudinary"])` },
1352
1340
  { name: "UPLOAD_MODE", schema: `z.enum(["proxy", "direct", "large"])` },
1353
- { name: "UPLOAD_AUTH_MODE", schema: `z.enum(["required", "optional", "none"])` },
1341
+ { name: "UPLOAD_AUTH_MODE", schema: `z.enum(["required", "none"])` },
1354
1342
  { name: "UPLOAD_FILE_ACCESS", schema: `z.enum(["private", "public"])` },
1355
- { name: "UPLOAD_FILE_PRESET", schema: `z.enum(["image", "document", "video", "mixed"])` },
1343
+ { name: "UPLOAD_FILE_PRESET", schema: `z.enum(["image", "document", "video"])` },
1356
1344
  { name: "UPLOAD_KEY_PREFIX", schema: "z.string().min(1)" },
1357
1345
  { name: "UPLOAD_ALLOWED_MIME", schema: "z.string().min(1)" },
1358
1346
  { name: "UPLOAD_MAX_FILE_SIZE", schema: "z.coerce.number().positive()" },
@@ -1387,103 +1375,24 @@ async function isAuthInstalled(projectRoot, srcDir) {
1387
1375
  function hasDrizzleDatabase(config) {
1388
1376
  return config?.database?.orm === "drizzle";
1389
1377
  }
1390
- async function promptCredentials(provider) {
1391
- console.log(chalk6.dim(" Tip: Leave fields blank to use placeholders and configure later.\n"));
1378
+ function getProviderEnvDefaults(provider) {
1392
1379
  if (provider === "cloudinary") {
1393
- const response2 = await prompts4([
1394
- {
1395
- type: "text",
1396
- name: "cloudName",
1397
- message: "Cloudinary cloud name",
1398
- initial: ""
1399
- },
1400
- {
1401
- type: "text",
1402
- name: "apiKey",
1403
- message: "Cloudinary API key",
1404
- initial: ""
1405
- },
1406
- {
1407
- type: "password",
1408
- name: "apiSecret",
1409
- message: "Cloudinary API secret"
1410
- },
1411
- {
1412
- type: "text",
1413
- name: "folder",
1414
- message: "Cloudinary folder",
1415
- initial: "uploads"
1416
- },
1417
- {
1418
- type: "text",
1419
- name: "uploadPreset",
1420
- message: "Cloudinary upload preset (optional)",
1421
- initial: ""
1422
- }
1423
- ]);
1424
- if (response2.cloudName === void 0) {
1425
- console.log(chalk6.yellow("Operation cancelled."));
1426
- return null;
1427
- }
1428
- const values2 = {
1429
- CLOUDINARY_CLOUD_NAME: response2.cloudName?.trim() || "your-cloud-name",
1430
- CLOUDINARY_API_KEY: response2.apiKey?.trim() || "your-api-key",
1431
- CLOUDINARY_API_SECRET: response2.apiSecret?.trim() || "your-api-secret",
1432
- CLOUDINARY_FOLDER: response2.folder?.trim() || "uploads",
1433
- CLOUDINARY_UPLOAD_PRESET: response2.uploadPreset?.trim() || ""
1380
+ return {
1381
+ CLOUDINARY_CLOUD_NAME: "your-cloud-name",
1382
+ CLOUDINARY_API_KEY: "your-api-key",
1383
+ CLOUDINARY_API_SECRET: "your-api-secret",
1384
+ CLOUDINARY_FOLDER: "uploads",
1385
+ CLOUDINARY_UPLOAD_PRESET: ""
1434
1386
  };
1435
- return values2;
1436
1387
  }
1437
- const response = await prompts4([
1438
- {
1439
- type: "text",
1440
- name: "bucket",
1441
- message: `${provider.toUpperCase()} bucket name`,
1442
- initial: ""
1443
- },
1444
- {
1445
- type: "text",
1446
- name: "region",
1447
- message: `${provider.toUpperCase()} region`,
1448
- initial: provider === "r2" ? "auto" : "us-east-1"
1449
- },
1450
- {
1451
- type: "text",
1452
- name: "endpoint",
1453
- message: provider === "r2" ? "R2 S3 endpoint" : "Custom S3 endpoint (optional)",
1454
- initial: provider === "r2" ? "https://<account-id>.r2.cloudflarestorage.com" : ""
1455
- },
1456
- {
1457
- type: "text",
1458
- name: "accessKeyId",
1459
- message: "Access key ID",
1460
- initial: ""
1461
- },
1462
- {
1463
- type: "password",
1464
- name: "secretAccessKey",
1465
- message: "Secret access key"
1466
- },
1467
- {
1468
- type: "text",
1469
- name: "publicBaseUrl",
1470
- message: "Public base URL (optional)",
1471
- initial: ""
1472
- }
1473
- ]);
1474
- if (response.bucket === void 0) {
1475
- console.log(chalk6.yellow("Operation cancelled."));
1476
- return null;
1477
- }
1478
- const values = {
1479
- UPLOAD_BUCKET: response.bucket?.trim() || `your-${provider}-bucket`,
1480
- UPLOAD_REGION: response.region?.trim() || (provider === "r2" ? "auto" : "us-east-1"),
1481
- UPLOAD_ENDPOINT: response.endpoint?.trim() || (provider === "r2" ? "https://<account-id>.r2.cloudflarestorage.com" : ""),
1482
- UPLOAD_ACCESS_KEY_ID: response.accessKeyId?.trim() || "your-access-key-id",
1483
- UPLOAD_SECRET_ACCESS_KEY: response.secretAccessKey?.trim() || "your-secret-access-key",
1484
- UPLOAD_PUBLIC_BASE_URL: response.publicBaseUrl?.trim() || ""
1388
+ return {
1389
+ UPLOAD_BUCKET: `your-${provider}-bucket`,
1390
+ UPLOAD_REGION: provider === "r2" ? "auto" : "us-east-1",
1391
+ UPLOAD_ENDPOINT: provider === "r2" ? "https://<account-id>.r2.cloudflarestorage.com" : "",
1392
+ UPLOAD_ACCESS_KEY_ID: "your-access-key-id",
1393
+ UPLOAD_SECRET_ACCESS_KEY: "your-secret-access-key",
1394
+ UPLOAD_PUBLIC_BASE_URL: ""
1485
1395
  };
1486
- return values;
1487
1396
  }
1488
1397
  function buildSharedEnvVars(provider, mode, authMode, access, preset, maxFileSize, maxFiles) {
1489
1398
  return {
@@ -1534,10 +1443,9 @@ async function promptUploadsConfig(projectRoot, srcDir) {
1534
1443
  message: "Who can upload?",
1535
1444
  choices: [
1536
1445
  { title: "Authenticated only", value: "required" },
1537
- { title: "Optional auth", value: "optional" },
1538
1446
  { title: "Public", value: "none" }
1539
1447
  ],
1540
- initial: authInstalled ? 0 : 2
1448
+ initial: authInstalled ? 0 : 1
1541
1449
  },
1542
1450
  {
1543
1451
  type: "select",
@@ -1556,16 +1464,9 @@ async function promptUploadsConfig(projectRoot, srcDir) {
1556
1464
  choices: [
1557
1465
  { title: "Image", value: "image" },
1558
1466
  { title: "Document", value: "document" },
1559
- { title: "Video", value: "video" },
1560
- { title: "Mixed", value: "mixed" }
1467
+ { title: "Video", value: "video" }
1561
1468
  ],
1562
1469
  initial: 0
1563
- },
1564
- {
1565
- type: "confirm",
1566
- name: "useDefaults",
1567
- message: "Use recommended upload limits for this preset?",
1568
- initial: true
1569
1470
  }
1570
1471
  ]);
1571
1472
  if (initial.provider === void 0) {
@@ -1582,7 +1483,7 @@ async function promptUploadsConfig(projectRoot, srcDir) {
1582
1483
  console.log(chalk6.yellow("Use S3 or R2 for large uploads, or pick Proxy/Direct for Cloudinary.\n"));
1583
1484
  return null;
1584
1485
  }
1585
- if (provider === "cloudinary" && (preset === "document" || preset === "mixed")) {
1486
+ if (provider === "cloudinary" && preset === "document") {
1586
1487
  const warning = await prompts4({
1587
1488
  type: "confirm",
1588
1489
  name: "continue",
@@ -1595,50 +1496,19 @@ async function promptUploadsConfig(projectRoot, srcDir) {
1595
1496
  }
1596
1497
  }
1597
1498
  const presetDefaults = UPLOAD_PRESETS[preset];
1598
- let maxFileSize = presetDefaults.maxFileSize;
1599
- let maxFiles = presetDefaults.maxFiles;
1600
- if (!initial.useDefaults) {
1601
- const custom = await prompts4([
1602
- {
1603
- type: "number",
1604
- name: "maxFileSizeMb",
1605
- message: "Max file size (MB)",
1606
- initial: Math.max(1, Math.round(presetDefaults.maxFileSize / (1024 * 1024))),
1607
- min: 1
1608
- },
1609
- {
1610
- type: "number",
1611
- name: "maxFiles",
1612
- message: "Max files per request",
1613
- initial: presetDefaults.maxFiles,
1614
- min: 1,
1615
- max: 20
1616
- }
1617
- ]);
1618
- if (custom.maxFileSizeMb === void 0) {
1619
- console.log(chalk6.yellow("Operation cancelled."));
1620
- return null;
1621
- }
1622
- maxFileSize = Number(custom.maxFileSizeMb) * 1024 * 1024;
1623
- maxFiles = Number(custom.maxFiles);
1624
- }
1625
1499
  let useDatabaseMetadata = false;
1626
1500
  let shouldInstallDatabase = false;
1627
1501
  const metadataPrompt = await prompts4({
1628
- type: "select",
1502
+ type: "confirm",
1629
1503
  name: "metadata",
1630
- message: "Upload metadata storage?",
1631
- choices: [
1632
- { title: drizzleInstalled ? "Database" : "Install database + track uploads", value: "db" },
1633
- { title: "No metadata", value: "none" }
1634
- ],
1635
- initial: 0
1504
+ message: drizzleInstalled ? "Store upload metadata in your database?" : "Install database and store upload metadata?",
1505
+ initial: true
1636
1506
  });
1637
1507
  if (metadataPrompt.metadata === void 0) {
1638
1508
  console.log(chalk6.yellow("Operation cancelled."));
1639
1509
  return null;
1640
1510
  }
1641
- if (metadataPrompt.metadata === "db") {
1511
+ if (metadataPrompt.metadata === true) {
1642
1512
  useDatabaseMetadata = true;
1643
1513
  if (!projectConfig?.database) {
1644
1514
  shouldInstallDatabase = true;
@@ -1674,10 +1544,6 @@ async function promptUploadsConfig(projectRoot, srcDir) {
1674
1544
  }
1675
1545
  shouldInstallAuth = true;
1676
1546
  }
1677
- const providerEnv = await promptCredentials(provider);
1678
- if (!providerEnv) {
1679
- return null;
1680
- }
1681
1547
  return {
1682
1548
  provider,
1683
1549
  mode,
@@ -1688,8 +1554,8 @@ async function promptUploadsConfig(projectRoot, srcDir) {
1688
1554
  shouldInstallAuth,
1689
1555
  shouldInstallDatabase,
1690
1556
  envVars: {
1691
- ...buildSharedEnvVars(provider, mode, authMode, access, preset, maxFileSize, maxFiles),
1692
- ...providerEnv
1557
+ ...buildSharedEnvVars(provider, mode, authMode, access, preset, presetDefaults.maxFileSize, presetDefaults.maxFiles),
1558
+ ...getProviderEnvDefaults(provider)
1693
1559
  }
1694
1560
  };
1695
1561
  }
@@ -1925,6 +1791,7 @@ ${moduleDocsEndMarker}`);
1925
1791
  function printUploadHints(result) {
1926
1792
  console.log(chalk6.yellow("\u2139 Upload routes are mounted at: /api/uploads"));
1927
1793
  console.log(chalk6.yellow(`\u2139 Provider: ${result.provider} \xB7 Mode: ${result.mode} \xB7 Access: ${result.access}`));
1794
+ console.log(chalk6.yellow("\u2139 Fill the generated upload env vars in .env before testing uploads."));
1928
1795
  if (result.mode === "proxy") {
1929
1796
  console.log(chalk6.yellow("\u2139 Reuse uploadSingle()/uploadArray() from src/lib/uploads/proxy.ts in your own form + file routes."));
1930
1797
  }
@@ -2047,6 +1914,11 @@ var add = async (moduleName, options = {}) => {
2047
1914
  currentStep = "module dependency resolution";
2048
1915
  await resolveDependencies(moduleDeps, projectRoot);
2049
1916
  if (resolvedModuleName === "uploads" && uploadConfig) {
1917
+ const errorHandlerInstalled = fs10.existsSync(path11.join(projectRoot, srcDir, "lib", "errors.ts"));
1918
+ if (!errorHandlerInstalled) {
1919
+ console.log(chalk7.blue("\n\u2139 Uploads needs the error-handler module. Installing error-handler..."));
1920
+ await add("error-handler");
1921
+ }
2050
1922
  if (uploadConfig.shouldInstallDatabase) {
2051
1923
  console.log(chalk7.blue("\n\u2139 Upload metadata needs a Drizzle database. Installing database module..."));
2052
1924
  await add("database");