create-v0-sdk-app 0.2.1 → 3.0.0-canary.4360778

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-v0-sdk-app
2
2
 
3
- Create [v0 SDK](https://v0-sdk.dev)-powered apps with one command.
3
+ Create [v0 Platform API v2](https://v0.app/docs/api/v2) SDK apps with one command.
4
4
 
5
5
  ## Usage
6
6
 
@@ -24,7 +24,7 @@ bun create v0-sdk-app my-app
24
24
  ## Options
25
25
 
26
26
  - `--example <example-name>` - Specify which example to use
27
- - `--use-pnpm` - Use pnpm as the package manager (recommended)
27
+ - `--use-pnpm` - Use pnpm as the package manager
28
28
  - `--use-npm` - Use npm as the package manager
29
29
  - `--use-yarn` - Use Yarn as the package manager
30
30
  - `--use-bun` - Use Bun as the package manager
@@ -32,49 +32,31 @@ bun create v0-sdk-app my-app
32
32
 
33
33
  ## Available Examples
34
34
 
35
- ### v0-clone (Recommended)
35
+ ### simple-v0 (Recommended)
36
36
 
37
- Next.js app that replicates the v0.dev interface with modern React components and AI chat functionality. This is the recommended starting point for most projects.
37
+ Next.js app that uses the v2 SDK to generate, preview, manage, and deploy v0 chats.
38
38
 
39
39
  ```bash
40
- pnpm create v0-sdk-app my-app --example v0-clone
40
+ pnpm create v0-sdk-app my-app --example simple-v0
41
41
  ```
42
42
 
43
- ### classic-v0
43
+ ### basic
44
44
 
45
- Full-featured Next.js app similar to the original v0.dev with project management, chat interface, and code generation capabilities.
45
+ Minimal TypeScript scripts for creating v2 chats with synchronous and streaming SDK calls.
46
46
 
47
47
  ```bash
48
- pnpm create v0-sdk-app my-classic-app --example classic-v0
49
- ```
50
-
51
- ### v0-sdk-react-example
52
-
53
- Next.js example using `@v0-sdk/react` components with different UI themes (minimal, elegant, neobrutalism, terminal).
54
-
55
- ```bash
56
- pnpm create v0-sdk-app my-react-app --example v0-sdk-react-example
57
- ```
58
-
59
- ### ai-tools-example
60
-
61
- Node.js example using `@v0-sdk/ai-tools` with AI SDK. Perfect for building AI-powered command-line tools and scripts.
62
-
63
- ```bash
64
- pnpm create v0-sdk-app my-ai-app --example ai-tools-example
48
+ pnpm create v0-sdk-app my-basic-app --example basic
65
49
  ```
66
50
 
67
51
  ## Interactive Mode
68
52
 
69
- If you don't specify an example, the CLI will prompt you to choose one:
53
+ If you do not specify an example, the CLI prompts you to choose one:
70
54
 
71
55
  ```bash
72
56
  pnpm create v0-sdk-app my-app
73
- # ? Which example would you like to use? (Use arrow keys)
74
- # v0-clone - Next.js app that replicates the v0.dev interface (Recommended)
75
- # classic-v0 - Full-featured Next.js app similar to the original v0.dev
76
- # v0-sdk-react-example - Next.js example using @v0-sdk/react components
77
- # ai-tools-example - Node.js example using @v0-sdk/ai-tools with AI SDK
57
+ # ? Which example would you like to use?
58
+ # > simple-v0 - Next.js app for generating, previewing, managing, and deploying v0 chats (Recommended)
59
+ # basic - Minimal TypeScript scripts for sync and streaming v2 chat creation
78
60
  ```
79
61
 
80
62
  ## What's Included
@@ -82,24 +64,20 @@ pnpm create v0-sdk-app my-app
82
64
  Each example comes pre-configured with:
83
65
 
84
66
  - TypeScript support
85
- - Modern tooling and build setup
67
+ - v0 SDK v2 usage
86
68
  - Example code and documentation
87
- - Proper dependency management
88
- - Development and production scripts
69
+ - A v0 SDK agent skill at `.agents/skills/v0/SKILL.md`
70
+ - Published package dependencies for use outside this monorepo
89
71
 
90
72
  ## Development
91
73
 
92
74
  To work on this package:
93
75
 
94
76
  ```bash
95
- # Install dependencies
96
- pnpm install
97
-
98
- # Build the package
99
- pnpm build
100
-
101
- # Test locally
102
- pnpm dev --help
77
+ bun install
78
+ bun --filter create-v0-sdk-app build
79
+ bun --filter create-v0-sdk-app typecheck
80
+ bun --filter create-v0-sdk-app dev --help
103
81
  ```
104
82
 
105
83
  ## License
@@ -1,5 +1,5 @@
1
- import type { PackageManager } from './helpers/get-pkg-manager';
2
- export type ExampleType = 'ai-tools-example' | 'classic-v0' | 'simple-v0' | 'v0-clone' | 'v0-sdk-react-example';
1
+ import type { PackageManager } from './helpers/get-pkg-manager.js';
2
+ export type ExampleType = 'basic' | 'simple-v0';
3
3
  export declare function createApp({ appPath, packageManager, example, skipInstall, }: {
4
4
  appPath: string;
5
5
  packageManager: PackageManager;
@@ -1 +1 @@
1
- {"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAM/D,MAAM,MAAM,WAAW,GACnB,kBAAkB,GAClB,YAAY,GACZ,WAAW,GACX,UAAU,GACV,sBAAsB,CAAA;AAE1B,wBAAsB,SAAS,CAAC,EAC9B,OAAO,EACP,cAAc,EACd,OAAO,EACP,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,cAAc,CAAA;IAC9B,OAAO,EAAE,WAAW,CAAA;IACpB,WAAW,EAAE,OAAO,CAAA;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2HhB"}
1
+ {"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAMlE,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,WAAW,CAAA;AAwC/C,wBAAsB,SAAS,CAAC,EAC9B,OAAO,EACP,cAAc,EACd,OAAO,EACP,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,cAAc,CAAA;IAC9B,OAAO,EAAE,WAAW,CAAA;IACpB,WAAW,EAAE,OAAO,CAAA;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGhB"}
@@ -1,47 +1,59 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createApp = createApp;
4
- const node_path_1 = require("node:path");
5
- const node_fs_1 = require("node:fs");
6
- const picocolors_1 = require("picocolors");
7
- const copy_1 = require("./helpers/copy");
8
- const install_1 = require("./helpers/install");
9
- const is_folder_empty_1 = require("./helpers/is-folder-empty");
10
- const is_online_1 = require("./helpers/is-online");
11
- const download_1 = require("./helpers/download");
12
- async function createApp({ appPath, packageManager, example, skipInstall, }) {
13
- const appName = (0, node_path_1.basename)(appPath);
14
- if ((0, node_fs_1.existsSync)(appPath) && !(0, is_folder_empty_1.isFolderEmpty)(appPath, appName)) {
1
+ import { basename, dirname, join } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from 'node:fs';
4
+ import degit from 'degit';
5
+ import picocolors from 'picocolors';
6
+ import { install } from './helpers/install.js';
7
+ import { isFolderEmpty } from './helpers/is-folder-empty.js';
8
+ const { cyan, green, red } = picocolors;
9
+ const packageVersions = {
10
+ v0: 'canary',
11
+ '@v0-sdk/ai-tools': 'canary',
12
+ };
13
+ const scriptDescriptions = {
14
+ dev: 'Starts the development server.',
15
+ sync: 'Runs the synchronous chat creation example.',
16
+ stream: 'Runs the streaming chat creation example.',
17
+ build: 'Builds the app for production.',
18
+ start: 'Runs the built app in production mode.',
19
+ };
20
+ const scriptDisplayOrder = ['dev', 'sync', 'stream', 'build', 'start'];
21
+ const basicScripts = {
22
+ sync: 'tsx chats/sync.ts',
23
+ stream: 'tsx chats/stream.ts',
24
+ };
25
+ const basicDevDependencies = {
26
+ '@types/bun': 'latest',
27
+ '@types/node': '^22.0.0',
28
+ tsx: '^4.19.2',
29
+ typescript: '^6.0.3',
30
+ };
31
+ const lockfiles = ['bun.lock', 'bun.lockb', 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock'];
32
+ export async function createApp({ appPath, packageManager, example, skipInstall, }) {
33
+ const appName = basename(appPath);
34
+ if (existsSync(appPath) && !isFolderEmpty(appPath, appName)) {
15
35
  process.exit(1);
16
36
  }
17
- console.log(`Creating a new v0 SDK app in ${(0, picocolors_1.green)(appPath)}.`);
37
+ console.log(`Creating a new v0 SDK app in ${green(appPath)}.`);
18
38
  console.log();
19
- // Download example from GitHub repository
20
- const repoUrl = 'https://github.com/vercel/v0-sdk';
21
- const examplePath = `examples/${example}`;
22
- console.log(`Downloading files from ${(0, picocolors_1.cyan)(repoUrl)}. This might take a moment.`);
39
+ const template = `vercel/v0-sdk/examples/${example}#v2`;
40
+ console.log(`Downloading template ${cyan(template)}. This might take a moment.`);
23
41
  console.log();
24
42
  try {
25
- await (0, download_1.downloadAndExtractExample)(repoUrl, examplePath, appPath);
26
- // Rename gitignore file if it exists
27
- const gitignorePath = (0, node_path_1.join)(appPath, 'gitignore');
28
- const dotGitignorePath = (0, node_path_1.join)(appPath, '.gitignore');
29
- if ((0, node_fs_1.existsSync)(gitignorePath)) {
30
- await (0, copy_1.copy)(['gitignore'], appPath, {
31
- cwd: appPath,
32
- rename: () => '.gitignore',
33
- });
34
- }
43
+ await degit(template, { cache: false, force: true }).clone(appPath);
35
44
  }
36
45
  catch (error) {
37
- console.error(`Failed to download example ${(0, picocolors_1.red)(example)}:`, error);
38
- console.error(`Example ${(0, picocolors_1.red)(example)} does not exist or could not be downloaded.`);
46
+ console.error(`Failed to download example ${red(example)}:`, error);
47
+ console.error(`Example ${red(example)} does not exist or could not be downloaded.`);
39
48
  process.exit(1);
40
49
  }
50
+ installAgentSkill(appPath);
41
51
  // Update package.json to use published packages instead of workspace references
42
- const packageJsonPath = (0, node_path_1.join)(appPath, 'package.json');
43
- if ((0, node_fs_1.existsSync)(packageJsonPath)) {
44
- const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf8'));
52
+ const packageJsonPath = join(appPath, 'package.json');
53
+ let packageScripts;
54
+ if (existsSync(packageJsonPath)) {
55
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
56
+ updateTemplatePackage(packageJson, example);
45
57
  // Replace workspace dependencies with actual versions
46
58
  const replaceWorkspaceDeps = (deps) => {
47
59
  if (!deps)
@@ -49,11 +61,6 @@ async function createApp({ appPath, packageManager, example, skipInstall, }) {
49
61
  for (const [name, version] of Object.entries(deps)) {
50
62
  if (version === 'workspace:*') {
51
63
  // Map workspace packages to their published versions
52
- const packageVersions = {
53
- 'v0-sdk': '^0.11.0',
54
- '@v0-sdk/react': '^0.3.0',
55
- '@v0-sdk/ai-tools': '^0.1.0',
56
- };
57
64
  if (packageVersions[name]) {
58
65
  deps[name] = packageVersions[name];
59
66
  }
@@ -68,36 +75,68 @@ async function createApp({ appPath, packageManager, example, skipInstall, }) {
68
75
  replaceWorkspaceDeps(packageJson.devDependencies);
69
76
  // Update the package name to match the app name
70
77
  packageJson.name = appName;
71
- (0, node_fs_1.writeFileSync)(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
78
+ packageScripts = packageJson.scripts;
79
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
80
+ removeLockfiles(appPath);
72
81
  }
73
82
  process.chdir(appPath);
74
83
  if (!skipInstall) {
75
84
  console.log('Installing packages. This might take a couple of minutes.');
76
85
  console.log();
77
- const isOnline = await (0, is_online_1.getOnline)();
78
- await (0, install_1.install)(packageManager, isOnline);
86
+ await install(packageManager);
79
87
  console.log();
80
88
  }
81
- console.log(`${(0, picocolors_1.green)('Success!')} Created ${appName} at ${appPath}`);
82
- console.log('Inside that directory, you can run several commands:');
83
- console.log();
84
- console.log((0, picocolors_1.cyan)(` ${packageManager} ${packageManager === 'npm' ? 'run ' : ''}dev`));
85
- console.log(' Starts the development server.');
86
- console.log();
87
- console.log((0, picocolors_1.cyan)(` ${packageManager} ${packageManager === 'npm' ? 'run ' : ''}build`));
88
- console.log(' Builds the app for production.');
89
- console.log();
90
- if (example !== 'ai-tools-example') {
91
- console.log((0, picocolors_1.cyan)(` ${packageManager} ${packageManager === 'npm' ? 'run ' : ''}start`));
92
- console.log(' Runs the built app in production mode.');
89
+ console.log(`${green('Success!')} Created ${appName} at ${appPath}`);
90
+ const availableScripts = scriptDisplayOrder.filter((script) => packageScripts?.[script]);
91
+ if (availableScripts.length > 0) {
92
+ console.log('Inside that directory, you can run several commands:');
93
93
  console.log();
94
+ for (const script of availableScripts) {
95
+ console.log(cyan(` ${getRunCommand(packageManager, script)}`));
96
+ console.log(` ${scriptDescriptions[script]}`);
97
+ console.log();
98
+ }
94
99
  }
95
100
  console.log('We suggest that you begin by typing:');
96
101
  console.log();
97
- console.log((0, picocolors_1.cyan)(' cd'), appName);
102
+ console.log(cyan(' cd'), appName);
98
103
  if (skipInstall) {
99
- console.log((0, picocolors_1.cyan)(` ${packageManager} install`));
104
+ console.log(cyan(` ${packageManager} install`));
105
+ }
106
+ const firstScript = availableScripts[0];
107
+ if (firstScript) {
108
+ console.log(cyan(` ${getRunCommand(packageManager, firstScript)}`));
100
109
  }
101
- console.log((0, picocolors_1.cyan)(` ${packageManager} ${packageManager === 'npm' ? 'run ' : ''}dev`));
102
110
  console.log();
103
111
  }
112
+ function getRunCommand(packageManager, script) {
113
+ return `${packageManager} ${packageManager === 'npm' ? 'run ' : ''}${script}`;
114
+ }
115
+ function updateTemplatePackage(packageJson, example) {
116
+ if (example !== 'basic')
117
+ return;
118
+ packageJson.scripts = {
119
+ ...basicScripts,
120
+ ...packageJson.scripts,
121
+ };
122
+ packageJson.devDependencies = {
123
+ ...packageJson.devDependencies,
124
+ ...basicDevDependencies,
125
+ };
126
+ delete packageJson.module;
127
+ delete packageJson.peerDependencies;
128
+ }
129
+ function installAgentSkill(appPath) {
130
+ const source = join(dirname(fileURLToPath(import.meta.url)), '..', 'templates', 'v0', 'SKILL.md');
131
+ const destination = join(appPath, '.agents', 'skills', 'v0', 'SKILL.md');
132
+ mkdirSync(dirname(destination), { recursive: true });
133
+ copyFileSync(source, destination);
134
+ }
135
+ function removeLockfiles(appPath) {
136
+ for (const lockfile of lockfiles) {
137
+ const lockfilePath = join(appPath, lockfile);
138
+ if (existsSync(lockfilePath)) {
139
+ unlinkSync(lockfilePath);
140
+ }
141
+ }
142
+ }
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPkgManager = getPkgManager;
4
- const node_child_process_1 = require("node:child_process");
5
- function getPkgManager() {
1
+ import { execSync } from 'node:child_process';
2
+ export function getPkgManager() {
6
3
  const userAgent = process.env.npm_config_user_agent;
7
4
  if (userAgent) {
8
5
  if (userAgent.startsWith('yarn')) {
@@ -16,17 +13,17 @@ function getPkgManager() {
16
13
  }
17
14
  }
18
15
  try {
19
- (0, node_child_process_1.execSync)('pnpm --version', { stdio: 'ignore' });
16
+ execSync('pnpm --version', { stdio: 'ignore' });
20
17
  return 'pnpm';
21
18
  }
22
19
  catch {
23
20
  try {
24
- (0, node_child_process_1.execSync)('yarn --version', { stdio: 'ignore' });
21
+ execSync('yarn --version', { stdio: 'ignore' });
25
22
  return 'yarn';
26
23
  }
27
24
  catch {
28
25
  try {
29
- (0, node_child_process_1.execSync)('bun --version', { stdio: 'ignore' });
26
+ execSync('bun --version', { stdio: 'ignore' });
30
27
  return 'bun';
31
28
  }
32
29
  catch {
@@ -1,4 +1,4 @@
1
- import type { PackageManager } from './get-pkg-manager';
1
+ import type { PackageManager } from './get-pkg-manager.js';
2
2
  /**
3
3
  * Spawn a package manager installation based on user preference.
4
4
  *
@@ -6,7 +6,5 @@ import type { PackageManager } from './get-pkg-manager';
6
6
  */
7
7
  export declare function install(
8
8
  /** Indicate which package manager to use. */
9
- packageManager: PackageManager,
10
- /** Indicate whether there is an active Internet connection.*/
11
- isOnline: boolean): Promise<void>;
9
+ packageManager: PackageManager): Promise<void>;
12
10
  //# sourceMappingURL=install.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/helpers/install.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;GAIG;AACH,wBAAsB,OAAO;AAC3B,6CAA6C;AAC7C,cAAc,EAAE,cAAc;AAC9B,8DAA8D;AAC9D,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,IAAI,CAAC,CAkCf"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/helpers/install.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D;;;;GAIG;AACH,wBAAsB,OAAO;AAC3B,6CAA6C;AAC7C,cAAc,EAAE,cAAc,GAC7B,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
@@ -1,26 +1,13 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.install = install;
7
- const picocolors_1 = require("picocolors");
8
- const cross_spawn_1 = __importDefault(require("cross-spawn"));
1
+ import spawn from 'cross-spawn';
9
2
  /**
10
3
  * Spawn a package manager installation based on user preference.
11
4
  *
12
5
  * @returns A Promise that resolves once the installation is finished.
13
6
  */
14
- async function install(
7
+ export async function install(
15
8
  /** Indicate which package manager to use. */
16
- packageManager,
17
- /** Indicate whether there is an active Internet connection.*/
18
- isOnline) {
9
+ packageManager) {
19
10
  const args = ['install'];
20
- if (!isOnline) {
21
- console.log((0, picocolors_1.yellow)('You appear to be offline.\nFalling back to the local cache.'));
22
- args.push('--offline');
23
- }
24
11
  /**
25
12
  * Return a Promise that resolves once the installation is finished.
26
13
  */
@@ -28,7 +15,7 @@ isOnline) {
28
15
  /**
29
16
  * Spawn the installation process.
30
17
  */
31
- const child = (0, cross_spawn_1.default)(packageManager, args, {
18
+ const child = spawn(packageManager, args, {
32
19
  stdio: 'inherit',
33
20
  env: {
34
21
  ...process.env,
@@ -1 +1 @@
1
- {"version":3,"file":"is-folder-empty.d.ts","sourceRoot":"","sources":["../../src/helpers/is-folder-empty.ts"],"names":[],"mappings":"AAoBA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAyCjE"}
1
+ {"version":3,"file":"is-folder-empty.d.ts","sourceRoot":"","sources":["../../src/helpers/is-folder-empty.ts"],"names":[],"mappings":"AAuBA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAgCjE"}
@@ -1,15 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isFolderEmpty = isFolderEmpty;
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
- const picocolors_1 = require("picocolors");
1
+ import { readdirSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import picocolors from 'picocolors';
4
+ const { red } = picocolors;
7
5
  const VALID_FILES = [
8
6
  '.DS_Store',
9
7
  '.git',
10
8
  '.gitattributes',
11
9
  '.gitignore',
12
10
  '.gitlab-ci.yml',
11
+ '.idea',
13
12
  '.hg',
14
13
  '.hgcheck',
15
14
  '.hgignore',
@@ -19,23 +18,21 @@ const VALID_FILES = [
19
18
  'mkdocs.yml',
20
19
  'Thumbs.db',
21
20
  ];
22
- function isFolderEmpty(root, name) {
21
+ export function isFolderEmpty(root, name) {
23
22
  const validFiles = VALID_FILES;
24
23
  let conflicts = [];
25
24
  try {
26
- conflicts = (0, node_fs_1.readdirSync)(root).filter((file) => !validFiles.includes(file) &&
27
- // Support IntelliJ IDEA-based editors
28
- !file.startsWith('.idea'));
25
+ conflicts = readdirSync(root).filter((file) => !validFiles.includes(file));
29
26
  }
30
27
  catch {
31
28
  return true;
32
29
  }
33
30
  if (conflicts.length > 0) {
34
- console.log(`The directory ${(0, picocolors_1.red)(name)} contains files that could conflict:`);
31
+ console.log(`The directory ${red(name)} contains files that could conflict:`);
35
32
  console.log();
36
33
  for (const file of conflicts) {
37
34
  try {
38
- const stats = (0, node_fs_1.readdirSync)((0, node_path_1.resolve)(root, file));
35
+ const stats = readdirSync(resolve(root, file));
39
36
  if (stats.length > 0) {
40
37
  console.log(` ${file}/`);
41
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validate-pkg.d.ts","sourceRoot":"","sources":["../../src/helpers/validate-pkg.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG;IAC7C,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAaA"}
1
+ {"version":3,"file":"validate-pkg.d.ts","sourceRoot":"","sources":["../../src/helpers/validate-pkg.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG;IAC7C,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAUA"}
@@ -1,20 +1,11 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.validateNpmName = validateNpmName;
7
- const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
8
- function validateNpmName(name) {
9
- const nameValidation = (0, validate_npm_package_name_1.default)(name);
1
+ import validateNpmPackageName from 'validate-npm-package-name';
2
+ export function validateNpmName(name) {
3
+ const nameValidation = validateNpmPackageName(name);
10
4
  if (nameValidation.validForNewPackages) {
11
5
  return { valid: true, problems: [] };
12
6
  }
13
7
  return {
14
8
  valid: false,
15
- problems: [
16
- ...(nameValidation.errors || []),
17
- ...(nameValidation.warnings || []),
18
- ],
9
+ problems: [...(nameValidation.errors || []), ...(nameValidation.warnings || [])],
19
10
  };
20
11
  }
package/dist/index.js CHANGED
@@ -1,19 +1,15 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const commander_1 = require("commander");
8
- const node_fs_1 = require("node:fs");
9
- const node_path_1 = require("node:path");
10
- const picocolors_1 = require("picocolors");
11
- const prompts_1 = __importDefault(require("prompts"));
12
- const create_app_1 = require("./create-app");
13
- const get_pkg_manager_1 = require("./helpers/get-pkg-manager");
14
- const is_folder_empty_1 = require("./helpers/is-folder-empty");
15
- const validate_pkg_1 = require("./helpers/validate-pkg");
16
- const package_json_1 = __importDefault(require("../package.json"));
2
+ import { Command } from 'commander';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { basename, resolve } from 'node:path';
5
+ import picocolors from 'picocolors';
6
+ import prompts from 'prompts';
7
+ import { createApp } from './create-app.js';
8
+ import { getPkgManager } from './helpers/get-pkg-manager.js';
9
+ import { isFolderEmpty } from './helpers/is-folder-empty.js';
10
+ import { validateNpmName } from './helpers/validate-pkg.js';
11
+ const { bold, cyan, green, red } = picocolors;
12
+ const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
17
13
  let projectPath = '';
18
14
  const handleSigTerm = () => process.exit(0);
19
15
  process.on('SIGINT', handleSigTerm);
@@ -28,36 +24,24 @@ const onPromptState = (state) => {
28
24
  }
29
25
  };
30
26
  const examples = [
31
- {
32
- name: 'v0-clone',
33
- description: 'Next.js app that replicates the v0.dev interface (Recommended)',
34
- },
35
27
  {
36
28
  name: 'simple-v0',
37
- description: 'The simplest way to use v0 - just prompt and see your app',
38
- },
39
- {
40
- name: 'classic-v0',
41
- description: 'Full-featured Next.js app similar to the original v0.dev released in 2023',
42
- },
43
- {
44
- name: 'v0-sdk-react-example',
45
- description: 'Next.js example using @v0-sdk/react components',
29
+ description: 'Next.js app for generating, previewing, managing, and deploying v0 chats (Recommended)',
46
30
  },
47
31
  {
48
- name: 'ai-tools-example',
49
- description: 'Node.js example using @v0-sdk/ai-tools with AI SDK + AI Gateway',
32
+ name: 'basic',
33
+ description: 'Minimal TypeScript scripts for sync and streaming v2 chat creation',
50
34
  },
51
35
  ];
52
- const program = new commander_1.Command(package_json_1.default.name)
53
- .version(package_json_1.default.version, '-v, --version', 'Output the current version of create-v0-sdk-app.')
36
+ const program = new Command(packageJson.name)
37
+ .version(packageJson.version, '-v, --version', 'Output the current version of create-v0-sdk-app.')
54
38
  .argument('[directory]')
55
39
  .usage('[directory] [options]')
56
40
  .helpOption('-h, --help', 'Display this help message.')
57
41
  .option('-e, --example <example-name>', `
58
42
 
59
43
  An example to bootstrap the app with. Available examples:
60
- ${examples.map((ex) => ` ${ex.name}: ${ex.description}`).join('\n ')}
44
+ ${examples.map((ex) => ` - ${ex.name}: ${ex.description}`).join('\n ')}
61
45
  `)
62
46
  .option('--use-pnpm', 'Explicitly tell the CLI to bootstrap the application using pnpm (recommended).')
63
47
  .option('--use-npm', 'Explicitly tell the CLI to bootstrap the application using npm.')
@@ -72,28 +56,28 @@ const program = new commander_1.Command(package_json_1.default.name)
72
56
  .allowUnknownOption()
73
57
  .parse(process.argv);
74
58
  const opts = program.opts();
75
- const packageManager = !!opts.usePnpm
59
+ const packageManager = opts.usePnpm
76
60
  ? 'pnpm'
77
- : !!opts.useNpm
61
+ : opts.useNpm
78
62
  ? 'npm'
79
- : !!opts.useYarn
63
+ : opts.useYarn
80
64
  ? 'yarn'
81
- : !!opts.useBun
65
+ : opts.useBun
82
66
  ? 'bun'
83
- : (0, get_pkg_manager_1.getPkgManager)();
67
+ : getPkgManager();
84
68
  async function run() {
85
69
  if (typeof projectPath === 'string') {
86
70
  projectPath = projectPath.trim();
87
71
  }
88
72
  if (!projectPath) {
89
- const res = await (0, prompts_1.default)({
73
+ const res = await prompts({
90
74
  onState: onPromptState,
91
75
  type: 'text',
92
76
  name: 'path',
93
77
  message: 'What is your project named?',
94
78
  initial: 'my-v0-app',
95
79
  validate: (name) => {
96
- const validation = (0, validate_pkg_1.validateNpmName)((0, node_path_1.basename)((0, node_path_1.resolve)(name)));
80
+ const validation = validateNpmName(basename(resolve(name)));
97
81
  if (validation.valid) {
98
82
  return true;
99
83
  }
@@ -106,26 +90,26 @@ async function run() {
106
90
  }
107
91
  if (!projectPath) {
108
92
  console.log('\nPlease specify the project directory:\n' +
109
- ` ${(0, picocolors_1.cyan)(program.name())} ${(0, picocolors_1.green)('<project-directory>')}\n` +
93
+ ` ${cyan(program.name())} ${green('<project-directory>')}\n` +
110
94
  'For example:\n' +
111
- ` ${(0, picocolors_1.cyan)(program.name())} ${(0, picocolors_1.green)('my-v0-app')}\n\n` +
112
- `Run ${(0, picocolors_1.cyan)(`${program.name()} --help`)} to see all options.`);
95
+ ` ${cyan(program.name())} ${green('my-v0-app')}\n\n` +
96
+ `Run ${cyan(`${program.name()} --help`)} to see all options.`);
113
97
  process.exit(1);
114
98
  }
115
- const appPath = (0, node_path_1.resolve)(projectPath);
116
- const appName = (0, node_path_1.basename)(appPath);
117
- const validation = (0, validate_pkg_1.validateNpmName)(appName);
99
+ const appPath = resolve(projectPath);
100
+ const appName = basename(appPath);
101
+ const validation = validateNpmName(appName);
118
102
  if (!validation.valid) {
119
- console.error(`Could not create a project called ${(0, picocolors_1.red)(`"${appName}"`)} because of npm naming restrictions:`);
120
- validation.problems.forEach((p) => console.error(` ${(0, picocolors_1.red)((0, picocolors_1.bold)('*'))} ${p}`));
103
+ console.error(`Could not create a project called ${red(`"${appName}"`)} because of npm naming restrictions:`);
104
+ validation.problems.forEach((p) => console.error(` ${red(bold('*'))} ${p}`));
121
105
  process.exit(1);
122
106
  }
123
- if ((0, node_fs_1.existsSync)(appPath) && !(0, is_folder_empty_1.isFolderEmpty)(appPath, appName)) {
107
+ if (existsSync(appPath) && !isFolderEmpty(appPath, appName)) {
124
108
  process.exit(1);
125
109
  }
126
110
  let example = opts.example;
127
111
  if (!example) {
128
- const res = await (0, prompts_1.default)({
112
+ const res = await prompts({
129
113
  onState: onPromptState,
130
114
  type: 'select',
131
115
  name: 'example',
@@ -141,11 +125,11 @@ async function run() {
141
125
  }
142
126
  if (!example || !examples.some((ex) => ex.name === example)) {
143
127
  console.error(`Invalid example "${example}". Available examples are:\n` +
144
- examples.map((ex) => ` ${ex.name}`).join('\n'));
128
+ examples.map((ex) => ` - ${ex.name}`).join('\n'));
145
129
  process.exit(1);
146
130
  }
147
131
  try {
148
- await (0, create_app_1.createApp)({
132
+ await createApp({
149
133
  appPath,
150
134
  packageManager,
151
135
  example,
@@ -158,16 +142,16 @@ async function run() {
158
142
  typeof reason === 'object' &&
159
143
  'command' in reason &&
160
144
  typeof reason.command === 'string') {
161
- console.error(` ${(0, picocolors_1.cyan)(reason.command)} has failed.`);
145
+ console.error(` ${cyan(reason.command)} has failed.`);
162
146
  }
163
147
  else {
164
- console.error((0, picocolors_1.red)('Unexpected error. Please report it as a bug:'), reason);
148
+ console.error(red('Unexpected error. Please report it as a bug:'), reason);
165
149
  }
166
150
  process.exit(1);
167
151
  }
168
152
  }
169
153
  run().catch((reason) => {
170
154
  console.error('Aborting installation.');
171
- console.error((0, picocolors_1.red)('Unexpected error. Please report it as a bug:'), reason);
155
+ console.error(red('Unexpected error. Please report it as a bug:'), reason);
172
156
  process.exit(1);
173
157
  });
package/package.json CHANGED
@@ -1,35 +1,44 @@
1
1
  {
2
2
  "name": "create-v0-sdk-app",
3
- "version": "0.2.1",
3
+ "version": "3.0.0-canary.4360778",
4
+ "description": "Create v0 Platform API v2 SDK apps with one command",
4
5
  "keywords": [
5
- "v0",
6
- "v0-sdk",
7
6
  "ai",
7
+ "next.js",
8
8
  "react",
9
- "next.js"
9
+ "v0",
10
+ "v0-sdk"
10
11
  ],
11
- "description": "Create v0 SDK-powered apps with one command",
12
+ "license": "Apache-2.0",
13
+ "author": "Vercel Team <support@vercel.com>",
12
14
  "repository": {
13
15
  "type": "git",
14
16
  "url": "https://github.com/vercel/v0-sdk.git",
15
17
  "directory": "packages/create-v0-sdk-app"
16
18
  },
17
- "author": "Vercel Team <support@vercel.com>",
18
- "license": "Apache-2.0",
19
19
  "bin": {
20
20
  "create-v0-sdk-app": "./dist/index.js"
21
21
  },
22
22
  "files": [
23
- "dist"
23
+ "dist",
24
+ "templates"
24
25
  ],
26
+ "type": "module",
27
+ "scripts": {
28
+ "dev": "tsx src/index.ts",
29
+ "build": "bun run clean && tsc",
30
+ "clean": "rm -rf dist *.tsbuildinfo",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "echo 'No linting configured for create-v0-sdk-app package'",
33
+ "prepublishOnly": "bun run build"
34
+ },
25
35
  "dependencies": {
26
- "commander": "^12.1.0",
27
- "prompts": "^2.4.2",
36
+ "commander": "^14.0.3",
37
+ "cross-spawn": "^7.0.6",
38
+ "degit": "^3.6.1",
28
39
  "picocolors": "^1.0.0",
29
- "cross-spawn": "^7.0.3",
30
- "fast-glob": "^3.3.1",
31
- "validate-npm-package-name": "^5.0.1",
32
- "tar": "^7.4.3"
40
+ "prompts": "^2.4.2",
41
+ "validate-npm-package-name": "^5.0.1"
33
42
  },
34
43
  "devDependencies": {
35
44
  "@types/cross-spawn": "^6.0.0",
@@ -37,17 +46,10 @@
37
46
  "@types/prompts": "^2.4.2",
38
47
  "@types/validate-npm-package-name": "^4.0.2",
39
48
  "tsx": "^4.19.2",
40
- "typescript": "^5.7.3"
49
+ "typescript": "^6.0.3"
41
50
  },
42
51
  "engines": {
43
52
  "node": ">=22",
44
53
  "pnpm": ">=9"
45
- },
46
- "scripts": {
47
- "dev": "tsx src/index.ts",
48
- "build": "tsc",
49
- "clean": "rm -rf dist *.tsbuildinfo",
50
- "type-check": "tsc --noEmit",
51
- "lint": "echo 'No linting configured for create-v0-sdk-app package'"
52
54
  }
53
- }
55
+ }
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: v0
3
+ description: Build and modify applications that use the v0 TypeScript SDK and Platform API v2.
4
+ ---
5
+
6
+ # v0 TypeScript SDK
7
+
8
+ Use this guidance when building or modifying applications that use the v0 TypeScript SDK.
9
+
10
+ ## Setup
11
+
12
+ - Install the SDK from the `v0` package.
13
+ - Import the default client with `import { v0 } from 'v0'` for simple server-side usage.
14
+ - Use `createV0Client` when the application needs custom authentication, a custom base URL, or custom fetch options.
15
+ - Read `V0_API_KEY` on the server. Never expose it to client components or browser code.
16
+ - The v2 API is organized around chats, messages, files, previews, and deployments.
17
+
18
+ ## Create a chat
19
+
20
+ Use `v0.chats.create({ message })` when the caller can wait for completion. Non-streaming SDK methods return a result containing `data` or `error`:
21
+
22
+ ```ts
23
+ const response = await v0.chats.create({ message })
24
+ if (response.error) throw new Error(response.error.message)
25
+
26
+ const chat = response.data.chat
27
+ ```
28
+
29
+ Store `chat.id` so later requests can continue the same workspace. Chat metadata can be used for application grouping, customer IDs, or internal routing.
30
+
31
+ Use `v0.chats.createStream({ message })` for interactive interfaces that show progress.
32
+
33
+ ## Send follow-up messages
34
+
35
+ - Use `v0.messages.send({ chatId, message })` to continue an existing chat synchronously.
36
+ - Use `v0.messages.sendStream({ chatId, message })` to stream progress for an existing chat.
37
+ - Treat messages as the conversation history and agent trace. Render message `parts` when the UI needs to show thinking, file edits, tool calls, and final text.
38
+
39
+ ## Streaming
40
+
41
+ The SDK stream result can be returned directly from a server with `result.toResponse()`, or consumed with `for await (const update of result.stream)`.
42
+
43
+ On the client, use `readV0Stream(response)` when consuming the v0 wire format directly. Prefer streaming for chat-style interfaces so the UI can update while v0 thinks, edits files, and reports usage.
44
+
45
+ ## Show previews
46
+
47
+ Use `v0.chats.getPreview({ chatId })` after a chat exists. As with other non-streaming methods, check `response.error` and read the preview from `response.data`.
48
+
49
+ The preview data may be `null` while the VM is starting. Poll until it is available. Preview access uses a short-lived token. If embedding the preview in an iframe, proxy requests through a server route and forward the token as `x-v0-preview-token`. Never send `V0_API_KEY` to the preview URL or browser.
50
+
51
+ ## Documentation
52
+
53
+ Use the [v0 Platform API v2 documentation](https://v0.app/docs/api/v2) for endpoint details.
@@ -1,8 +0,0 @@
1
- interface CopyOption {
2
- cwd?: string;
3
- rename?: (basename: string) => string;
4
- parents?: boolean;
5
- }
6
- export declare const copy: (src: string | string[], dest: string, { cwd, rename, parents }?: CopyOption) => Promise<void[]>;
7
- export {};
8
- //# sourceMappingURL=copy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../src/helpers/copy.ts"],"names":[],"mappings":"AAIA,UAAU,UAAU;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAID,eAAO,MAAM,IAAI,QACV,MAAM,GAAG,MAAM,EAAE,QAChB,MAAM,6BACgC,UAAU,oBAiCvD,CAAA"}
@@ -1,32 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.copy = void 0;
4
- const node_path_1 = require("node:path");
5
- const promises_1 = require("node:fs/promises");
6
- const fast_glob_1 = require("fast-glob");
7
- const identity = (x) => x;
8
- const copy = async (src, dest, { cwd, rename = identity, parents = true } = {}) => {
9
- const source = typeof src === 'string' ? [src] : src;
10
- if (source.length === 0 || !dest) {
11
- throw new TypeError('`src` and `dest` are required');
12
- }
13
- const sourceFiles = await (0, fast_glob_1.async)(source, {
14
- cwd,
15
- dot: true,
16
- absolute: false,
17
- stats: false,
18
- });
19
- const destRelativeToCwd = cwd ? (0, node_path_1.resolve)(cwd, dest) : dest;
20
- return Promise.all(sourceFiles.map(async (p) => {
21
- const dirName = (0, node_path_1.dirname)(p);
22
- const baseName = rename((0, node_path_1.basename)(p));
23
- const from = cwd ? (0, node_path_1.resolve)(cwd, p) : p;
24
- const to = parents
25
- ? (0, node_path_1.join)(destRelativeToCwd, dirName, baseName)
26
- : (0, node_path_1.join)(destRelativeToCwd, baseName);
27
- // Ensure the destination directory exists
28
- await (0, promises_1.mkdir)((0, node_path_1.dirname)(to), { recursive: true });
29
- return (0, promises_1.copyFile)(from, to);
30
- }));
31
- };
32
- exports.copy = copy;
@@ -1,12 +0,0 @@
1
- export type RepoInfo = {
2
- username: string;
3
- name: string;
4
- branch: string;
5
- filePath: string;
6
- };
7
- export declare function isUrlOk(url: string): Promise<boolean>;
8
- export declare function getRepoInfo(url: URL, examplePath?: string): Promise<RepoInfo | undefined>;
9
- export declare function hasRepo({ username, name, branch, filePath, }: RepoInfo): Promise<boolean>;
10
- export declare function downloadAndExtractRepo(root: string, { username, name, branch, filePath }: RepoInfo): Promise<void>;
11
- export declare function downloadAndExtractExample(repoUrl: string, examplePath: string, appPath: string): Promise<void>;
12
- //# sourceMappingURL=download.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/helpers/download.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO3D;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,GAAG,EACR,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAoC/B;AAED,wBAAgB,OAAO,CAAC,EACtB,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,QAAQ,GACT,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAK7B;AAED,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,GAC7C,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -1,94 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUrlOk = isUrlOk;
4
- exports.getRepoInfo = getRepoInfo;
5
- exports.hasRepo = hasRepo;
6
- exports.downloadAndExtractRepo = downloadAndExtractRepo;
7
- exports.downloadAndExtractExample = downloadAndExtractExample;
8
- const node_stream_1 = require("node:stream");
9
- const promises_1 = require("node:stream/promises");
10
- const node_fs_1 = require("node:fs");
11
- const tar_1 = require("tar");
12
- async function isUrlOk(url) {
13
- try {
14
- const res = await fetch(url, { method: 'HEAD' });
15
- return res.status === 200;
16
- }
17
- catch {
18
- return false;
19
- }
20
- }
21
- async function getRepoInfo(url, examplePath) {
22
- const [, username, name, t, _branch, ...file] = url.pathname.split('/');
23
- const filePath = examplePath ? examplePath.replace(/^\//, '') : file.join('/');
24
- if (
25
- // Support repos whose entire purpose is to be a Next.js example, e.g.
26
- // https://github.com/:username/:my-cool-nextjs-example-repo-name.
27
- t === undefined ||
28
- // Support GitHub URL that ends with a trailing slash, e.g.
29
- // https://github.com/:username/:my-cool-nextjs-example-repo-name/
30
- // In this case "t" will be an empty string while the next part "_branch" will be undefined
31
- (t === '' && _branch === undefined)) {
32
- try {
33
- const infoResponse = await fetch(`https://api.github.com/repos/${username}/${name}`);
34
- if (infoResponse.status !== 200) {
35
- return;
36
- }
37
- const info = await infoResponse.json();
38
- return { username, name, branch: info['default_branch'], filePath };
39
- }
40
- catch {
41
- return;
42
- }
43
- }
44
- // Support GitHub URL that ends with a trailing slash, e.g.
45
- // https://github.com/:username/:my-cool-nextjs-example-repo-name/tree/my-cool-branch/
46
- // In this case "t" will be "tree" and "_branch" will be the branch name
47
- if (t === 'tree' && _branch) {
48
- return { username, name, branch: _branch, filePath };
49
- }
50
- return { username, name, branch: 'main', filePath };
51
- }
52
- function hasRepo({ username, name, branch, filePath, }) {
53
- const contentsUrl = `https://api.github.com/repos/${username}/${name}/contents`;
54
- const packagePath = `${filePath ? `/${filePath}` : ''}/package.json`;
55
- return isUrlOk(`${contentsUrl}${packagePath}?ref=${branch}`);
56
- }
57
- async function downloadAndExtractRepo(root, { username, name, branch, filePath }) {
58
- const tempFile = `https://codeload.github.com/${username}/${name}/tar.gz/${branch}`;
59
- // Ensure the target directory exists
60
- (0, node_fs_1.mkdirSync)(root, { recursive: true });
61
- const response = await fetch(tempFile);
62
- if (!response.body) {
63
- throw new Error('Failed to fetch repository');
64
- }
65
- return (0, promises_1.pipeline)(node_stream_1.Readable.fromWeb(response.body), (0, tar_1.x)({
66
- cwd: root,
67
- strip: filePath ? filePath.split('/').length + 1 : 1,
68
- filter: (path) => {
69
- const chunks = path.split('/');
70
- if (filePath) {
71
- const filePathChunks = filePath.split('/');
72
- if (chunks.length <= filePathChunks.length ||
73
- filePathChunks.some((chunk, i) => chunks[i + 1] !== chunk)) {
74
- return false;
75
- }
76
- }
77
- const [, ...fileChunks] = chunks;
78
- const target = fileChunks.join('/');
79
- return !target.startsWith('.git');
80
- },
81
- }));
82
- }
83
- async function downloadAndExtractExample(repoUrl, examplePath, appPath) {
84
- const url = new URL(repoUrl);
85
- const repoInfo = await getRepoInfo(url, examplePath);
86
- if (!repoInfo) {
87
- throw new Error(`Could not get repository info for ${repoUrl}`);
88
- }
89
- const hasExample = await hasRepo(repoInfo);
90
- if (!hasExample) {
91
- throw new Error(`Example "${examplePath}" not found in repository`);
92
- }
93
- await downloadAndExtractRepo(appPath, repoInfo);
94
- }
@@ -1,2 +0,0 @@
1
- export declare function getOnline(): Promise<boolean>;
2
- //# sourceMappingURL=is-online.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"is-online.d.ts","sourceRoot":"","sources":["../../src/helpers/is-online.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAS5C"}
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getOnline = getOnline;
4
- const node_child_process_1 = require("node:child_process");
5
- function getOnline() {
6
- return new Promise((resolve) => {
7
- try {
8
- (0, node_child_process_1.execSync)('ping -c 1 8.8.8.8', { stdio: 'ignore' });
9
- resolve(true);
10
- }
11
- catch {
12
- resolve(false);
13
- }
14
- });
15
- }