create-cloudinary-react 1.0.0-beta.21 β†’ 1.0.0-beta.22

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/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # [1.0.0-beta.22](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2026-04-08)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add comments ([5dd6f00](https://github.com/cloudinary-devs/create-cloudinary-react/commit/5dd6f002d514d5e488eb1fcf8e9f003fa09fc22c))
7
+ * comment and render secure url after upload ([4061546](https://github.com/cloudinary-devs/create-cloudinary-react/commit/40615464f260693a1f9a5f6b7ceca3c10456bbe6))
8
+ * detect invoking package manager ([8e3547c](https://github.com/cloudinary-devs/create-cloudinary-react/commit/8e3547c9b97b1c806dacf853a0764d5fe9e36b9e))
9
+ * version in readme ([0325e1b](https://github.com/cloudinary-devs/create-cloudinary-react/commit/0325e1be42db7e042710a6249f72ca4a6738bd4d))
10
+
1
11
  # [1.0.0-beta.21](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.20...v1.0.0-beta.21) (2026-02-25)
2
12
 
3
13
 
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  Scaffold a modern, production-ready Cloudinary application with React 19, Vite 6, and TypeScript 5. Features interactive setup, automatic environment configuration, and built-in AI coding assistance.
10
10
 
11
- - Node.js 18+ installed
11
+ - **Node.js** β€” use a [current LTS](https://nodejs.org/) release. The generated app lists supported versions under `engines` in its `package.json`.
12
12
  - A Cloudinary account (free tier available)
13
13
  - [Sign up for free](https://cld.media/reactregister)
14
14
  - Your cloud name is in your [dashboard](https://console.cloudinary.com/app/home/dashboard)
@@ -36,7 +36,7 @@ Part of the [Cloudinary Developers](https://github.com/cloudinary-devs) organiza
36
36
 
37
37
  ## πŸš€ Quick Start
38
38
 
39
- Ensure you have Node.js 18+ installed.
39
+ Use a current **Node.js LTS** release. If installs fail, match the `engines` range in the generated project’s `package.json`.
40
40
 
41
41
  ```bash
42
42
  npx create-cloudinary-react
@@ -80,7 +80,7 @@ During setup, select your AI tool to generate **Context Rules**. These rules tea
80
80
 
81
81
  ## πŸ“‹ Prerequisites
82
82
 
83
- - **Node.js 18+**
83
+ - **Node.js** β€” LTS recommended; exact ranges for the scaffolded app are in `package.json` β†’ `engines`.
84
84
  - **Cloudinary Account**: [Sign up for free](https://cloudinary.com/users/register/free) if you haven't already.
85
85
 
86
86
  ## 🀝 Contributing
package/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join } from 'path';
5
5
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
6
- import { execSync } from 'child_process';
6
+ import { spawnSync } from 'child_process';
7
7
  import inquirer from 'inquirer';
8
8
  import chalk from 'chalk';
9
9
  import fs from 'fs-extra';
@@ -14,6 +14,64 @@ const __dirname = dirname(__filename);
14
14
 
15
15
  const TEMPLATES_DIR = join(__dirname, 'templates');
16
16
 
17
+ /** Package managers we know how to drive for install / dev scripts */
18
+ const SUPPORTED_PACKAGE_MANAGERS = new Set(['npm', 'pnpm', 'yarn', 'bun']);
19
+
20
+ /**
21
+ * Parse npm_config_user_agent (set by npm, pnpm, yarn, bun when they run a package).
22
+ * Same approach as create-vite: first space-separated segment is "name/version".
23
+ */
24
+ function pkgFromUserAgent(userAgent) {
25
+ if (!userAgent) return undefined;
26
+ const pkgSpec = userAgent.split(' ')[0];
27
+ const [name, version = ''] = pkgSpec.split('/');
28
+ if (!name) return undefined;
29
+ return { name, version };
30
+ }
31
+
32
+ /**
33
+ * Resolve which client to run for install / dev.
34
+ * Only npm, pnpm, yarn, and bun have explicit command mappings below; anything else
35
+ * (missing env, exotic clients, parse quirks) falls back to npm as the safe default that
36
+ * ships with Node and matches the install instructions most users expect.
37
+ */
38
+ function detectPackageManager() {
39
+ const pkg = pkgFromUserAgent(process.env.npm_config_user_agent);
40
+ if (pkg && SUPPORTED_PACKAGE_MANAGERS.has(pkg.name)) {
41
+ return pkg.name;
42
+ }
43
+ return 'npm';
44
+ }
45
+
46
+ function getInstallCommand(packageManager) {
47
+ if (packageManager === 'yarn') {
48
+ return ['yarn'];
49
+ }
50
+ return [packageManager, 'install'];
51
+ }
52
+
53
+ function getRunDevCommand(packageManager) {
54
+ switch (packageManager) {
55
+ case 'yarn':
56
+ case 'pnpm':
57
+ case 'bun':
58
+ return [packageManager, 'dev'];
59
+ default:
60
+ return ['npm', 'run', 'dev'];
61
+ }
62
+ }
63
+
64
+ function runPackageManagerCommand(args, cwd) {
65
+ const [command, ...cmdArgs] = args;
66
+ const result = spawnSync(command, cmdArgs, { stdio: 'inherit', cwd, shell: false });
67
+ if (result.error) {
68
+ throw result.error;
69
+ }
70
+ if (result.status !== 0) {
71
+ throw new Error(`Command failed: ${args.join(' ')}`);
72
+ }
73
+ }
74
+
17
75
  // Validate cloud name format
18
76
  function isValidCloudName(name) {
19
77
  return /^[a-z0-9_-]+$/.test(name) && name.length > 0;
@@ -61,8 +119,12 @@ async function main() {
61
119
  startDev: {
62
120
  type: 'boolean',
63
121
  default: false
64
- }
65
- }
122
+ },
123
+ packageManager: {
124
+ type: 'string',
125
+ },
126
+ },
127
+ allowPositionals: true,
66
128
  });
67
129
 
68
130
  Object.assign(answers, values);
@@ -166,6 +228,17 @@ async function main() {
166
228
 
167
229
  const { projectName, cloudName, uploadPreset, aiTools, installDeps, startDev } = answers;
168
230
 
231
+ let packageManager = answers.packageManager;
232
+ if (packageManager && !SUPPORTED_PACKAGE_MANAGERS.has(packageManager)) {
233
+ console.warn(
234
+ chalk.yellow(
235
+ `Unknown package manager "${packageManager}". Use npm, pnpm, yarn, or bun. Ignoring --packageManager; using npm_config_user_agent when it names a supported client, otherwise npm.`
236
+ )
237
+ );
238
+ packageManager = undefined;
239
+ }
240
+ packageManager = packageManager || detectPackageManager();
241
+
169
242
  console.log(chalk.blue('\nπŸ“¦ Creating project...\n'));
170
243
 
171
244
  // Create project directory
@@ -311,34 +384,38 @@ async function main() {
311
384
  console.log(chalk.cyan(' 5. Save the file and restart the dev server so it loads correctly\n'));
312
385
  }
313
386
 
387
+ const installCmd = getInstallCommand(packageManager);
388
+ const devCmd = getRunDevCommand(packageManager);
389
+ const installCmdStr = installCmd.join(' ');
390
+ const devCmdStr = devCmd.join(' ');
391
+
314
392
  if (installDeps) {
315
- console.log(chalk.blue('πŸ“¦ Installing dependencies...\n'));
393
+ console.log(chalk.blue(`πŸ“¦ Installing dependencies with ${packageManager}...\n`));
316
394
  try {
317
- process.chdir(projectPath);
318
- execSync('npm install', { stdio: 'inherit' });
395
+ runPackageManagerCommand(installCmd, projectPath);
319
396
  console.log(chalk.green('\nβœ… Dependencies installed!\n'));
320
397
 
321
398
  if (startDev) {
322
399
  console.log(chalk.blue('πŸš€ Starting development server...\n'));
323
- execSync('npm run dev', { stdio: 'inherit' });
400
+ runPackageManagerCommand(devCmd, projectPath);
324
401
  } else {
325
402
  console.log(chalk.cyan(`\nπŸ“ Project created at: ${projectPath}`));
326
403
  console.log(chalk.cyan(`\nNext steps:`));
327
404
  console.log(chalk.cyan(` cd ${projectName}`));
328
- console.log(chalk.cyan(` npm run dev\n`));
405
+ console.log(chalk.cyan(` ${devCmdStr}\n`));
329
406
  }
330
407
  } catch (error) {
331
408
  console.error(chalk.red('\n❌ Error installing dependencies:'), error.message);
332
409
  console.log(chalk.cyan(`\nYou can install manually:`));
333
410
  console.log(chalk.cyan(` cd ${projectName}`));
334
- console.log(chalk.cyan(` npm install\n`));
411
+ console.log(chalk.cyan(` ${installCmdStr}\n`));
335
412
  }
336
413
  } else {
337
414
  console.log(chalk.cyan(`\nπŸ“ Project created at: ${projectPath}`));
338
415
  console.log(chalk.cyan(`\nNext steps:`));
339
416
  console.log(chalk.cyan(` cd ${projectName}`));
340
- console.log(chalk.cyan(` npm install`));
341
- console.log(chalk.cyan(` npm run dev\n`));
417
+ console.log(chalk.cyan(` ${installCmdStr}`));
418
+ console.log(chalk.cyan(` ${devCmdStr}\n`));
342
419
  }
343
420
  }
344
421
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-cloudinary-react",
3
- "version": "1.0.0-beta.21",
3
+ "version": "1.0.0-beta.22",
4
4
  "description": "Scaffold a Cloudinary React + Vite + TypeScript project with interactive setup",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,6 +2,10 @@
2
2
 
3
3
  A Cloudinary React + Vite + TypeScript project scaffolded with [create-cloudinary-react](https://github.com/cloudinary-devs/create-cloudinary-react).
4
4
 
5
+ ## Prerequisites
6
+
7
+ - **Node.js** β€” use a current LTS release. Supported ranges are listed under `engines` in this `package.json`.
8
+
5
9
  ## Quick Start
6
10
 
7
11
  ```bash
@@ -3,6 +3,9 @@
3
3
  "private": true,
4
4
  "version": "0.0.0",
5
5
  "type": "module",
6
+ "engines": {
7
+ "node": "^20.19.0 || >=22.12.0"
8
+ },
6
9
  "scripts": {
7
10
  "dev": "vite",
8
11
  "build": "tsc -b && vite build",
@@ -25,11 +25,21 @@ const PROMPTS_WITHOUT_UPLOAD = [
25
25
 
26
26
  function App() {
27
27
  const [uploadedImageId, setUploadedImageId] = useState<string | null>(null);
28
+ const [uploadedUrl, setUploadedUrl] = useState<string | null>(null);
28
29
  const [clickedIds, setClickedIds] = useState(new Set<number>());
29
30
 
30
31
  const handleUploadSuccess = (result: CloudinaryUploadResult) => {
31
32
  console.log('Upload successful:', result);
33
+ // result contains everything you need to work with the uploaded asset:
34
+ // result.public_id β€” Cloudinary asset ID (use with cld.image() for transformations)
35
+ // result.secure_url β€” direct HTTPS URL to the original file
36
+ // result.url β€” HTTP URL (prefer secure_url)
37
+ // result.width / result.height β€” image dimensions
38
+ // result.format β€” file format (e.g. 'jpg', 'png', 'webp')
39
+ // result.bytes β€” file size in bytes
40
+ // result.resource_type β€” 'image', 'video', or 'raw'
32
41
  setUploadedImageId(result.public_id);
42
+ setUploadedUrl(result.secure_url); // store the URL to use anywhere in your app
33
43
  };
34
44
 
35
45
  const handleUploadError = (error: Error) => {
@@ -85,6 +95,14 @@ function App() {
85
95
  {uploadedImageId && (
86
96
  <p className="image-info">Public ID: {uploadedImageId}</p>
87
97
  )}
98
+ {uploadedUrl && (
99
+ <p className="image-info">
100
+ URL:{' '}
101
+ <a href={uploadedUrl} target="_blank" rel="noopener noreferrer">
102
+ {uploadedUrl}
103
+ </a>
104
+ </p>
105
+ )}
88
106
  </div>
89
107
 
90
108
  <div className="ai-prompts-section">