create-v0-sdk-app 0.2.0 → 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 +19 -41
- package/dist/create-app.d.ts +2 -2
- package/dist/create-app.d.ts.map +1 -1
- package/dist/create-app.js +96 -57
- package/dist/helpers/get-pkg-manager.js +5 -8
- package/dist/helpers/install.d.ts +2 -4
- package/dist/helpers/install.d.ts.map +1 -1
- package/dist/helpers/install.js +4 -17
- package/dist/helpers/is-folder-empty.d.ts.map +1 -1
- package/dist/helpers/is-folder-empty.js +9 -12
- package/dist/helpers/validate-pkg.d.ts.map +1 -1
- package/dist/helpers/validate-pkg.js +4 -13
- package/dist/index.js +39 -55
- package/package.json +25 -23
- package/templates/v0/SKILL.md +53 -0
- package/dist/helpers/copy.d.ts +0 -8
- package/dist/helpers/copy.d.ts.map +0 -1
- package/dist/helpers/copy.js +0 -32
- package/dist/helpers/download.d.ts +0 -12
- package/dist/helpers/download.d.ts.map +0 -1
- package/dist/helpers/download.js +0 -94
- package/dist/helpers/is-online.d.ts +0 -2
- package/dist/helpers/is-online.d.ts.map +0 -1
- package/dist/helpers/is-online.js +0 -15
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-v0-sdk-app
|
|
2
2
|
|
|
3
|
-
Create [v0
|
|
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
|
|
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
|
|
35
|
+
### simple-v0 (Recommended)
|
|
36
36
|
|
|
37
|
-
Next.js app that
|
|
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
|
|
40
|
+
pnpm create v0-sdk-app my-app --example simple-v0
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
###
|
|
43
|
+
### basic
|
|
44
44
|
|
|
45
|
-
|
|
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-
|
|
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
|
|
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?
|
|
74
|
-
#
|
|
75
|
-
#
|
|
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
|
-
-
|
|
67
|
+
- v0 SDK v2 usage
|
|
86
68
|
- Example code and documentation
|
|
87
|
-
-
|
|
88
|
-
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
package/dist/create-app.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PackageManager } from './helpers/get-pkg-manager';
|
|
2
|
-
export type ExampleType = '
|
|
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;
|
package/dist/create-app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-app.d.ts","sourceRoot":"","sources":["../src/create-app.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/create-app.js
CHANGED
|
@@ -1,47 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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 ${
|
|
37
|
+
console.log(`Creating a new v0 SDK app in ${green(appPath)}.`);
|
|
18
38
|
console.log();
|
|
19
|
-
|
|
20
|
-
|
|
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 (
|
|
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 ${
|
|
38
|
-
console.error(`Example ${
|
|
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 =
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
await (0, install_1.install)(packageManager, isOnline);
|
|
86
|
+
await install(packageManager);
|
|
79
87
|
console.log();
|
|
80
88
|
}
|
|
81
|
-
console.log(`${
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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(
|
|
102
|
+
console.log(cyan(' cd'), appName);
|
|
98
103
|
if (skipInstall) {
|
|
99
|
-
console.log(
|
|
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
|
-
|
|
2
|
-
|
|
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
|
-
|
|
16
|
+
execSync('pnpm --version', { stdio: 'ignore' });
|
|
20
17
|
return 'pnpm';
|
|
21
18
|
}
|
|
22
19
|
catch {
|
|
23
20
|
try {
|
|
24
|
-
|
|
21
|
+
execSync('yarn --version', { stdio: 'ignore' });
|
|
25
22
|
return 'yarn';
|
|
26
23
|
}
|
|
27
24
|
catch {
|
|
28
25
|
try {
|
|
29
|
-
|
|
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":"
|
|
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"}
|
package/dist/helpers/install.js
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
|
-
|
|
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 = (
|
|
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":"
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
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 =
|
|
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 ${
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
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: '
|
|
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: '
|
|
49
|
-
description: '
|
|
32
|
+
name: 'basic',
|
|
33
|
+
description: 'Minimal TypeScript scripts for sync and streaming v2 chat creation',
|
|
50
34
|
},
|
|
51
35
|
];
|
|
52
|
-
const program = new
|
|
53
|
-
.version(
|
|
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) => `
|
|
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 =
|
|
59
|
+
const packageManager = opts.usePnpm
|
|
76
60
|
? 'pnpm'
|
|
77
|
-
:
|
|
61
|
+
: opts.useNpm
|
|
78
62
|
? 'npm'
|
|
79
|
-
:
|
|
63
|
+
: opts.useYarn
|
|
80
64
|
? 'yarn'
|
|
81
|
-
:
|
|
65
|
+
: opts.useBun
|
|
82
66
|
? 'bun'
|
|
83
|
-
:
|
|
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 (
|
|
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 =
|
|
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
|
-
` ${
|
|
93
|
+
` ${cyan(program.name())} ${green('<project-directory>')}\n` +
|
|
110
94
|
'For example:\n' +
|
|
111
|
-
` ${
|
|
112
|
-
`Run ${
|
|
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 =
|
|
116
|
-
const appName =
|
|
117
|
-
const validation =
|
|
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 ${
|
|
120
|
-
validation.problems.forEach((p) => console.error(` ${
|
|
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 (
|
|
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 (
|
|
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) => `
|
|
128
|
+
examples.map((ex) => ` - ${ex.name}`).join('\n'));
|
|
145
129
|
process.exit(1);
|
|
146
130
|
}
|
|
147
131
|
try {
|
|
148
|
-
await
|
|
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(` ${
|
|
145
|
+
console.error(` ${cyan(reason.command)} has failed.`);
|
|
162
146
|
}
|
|
163
147
|
else {
|
|
164
|
-
console.error(
|
|
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(
|
|
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.
|
|
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
|
-
"
|
|
9
|
+
"v0",
|
|
10
|
+
"v0-sdk"
|
|
10
11
|
],
|
|
11
|
-
"
|
|
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": "^
|
|
27
|
-
"
|
|
36
|
+
"commander": "^14.0.3",
|
|
37
|
+
"cross-spawn": "^7.0.6",
|
|
38
|
+
"degit": "^3.6.1",
|
|
28
39
|
"picocolors": "^1.0.0",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
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": "^
|
|
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.
|
package/dist/helpers/copy.d.ts
DELETED
|
@@ -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"}
|
package/dist/helpers/copy.js
DELETED
|
@@ -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"}
|
package/dist/helpers/download.js
DELETED
|
@@ -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 +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
|
-
}
|