@embeddable.com/init 0.0.4 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +201 -1
- package/package.json +9 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,204 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import degit from "degit";
|
|
9
|
+
import prompts from "prompts";
|
|
10
|
+
import terminalLink from "terminal-link";
|
|
11
|
+
var REPO_URL = "embeddable-hq/remarkable-pro-boilerplate";
|
|
12
|
+
var DEFAULT_FOLDER = "embeddable-repo";
|
|
13
|
+
var WORKSPACE_URLS = {
|
|
14
|
+
US: "https://app.us.embeddable.com",
|
|
15
|
+
EU: "https://app.eu.embeddable.com"
|
|
16
|
+
};
|
|
17
|
+
var INVALID_FOLDER_CHARS = /[<>:"/\\|?*\x00-\x1f]/;
|
|
18
|
+
function exit(message) {
|
|
19
|
+
if (message) console.log(message);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
function validateFolderName(value, cwd) {
|
|
23
|
+
const trimmed = value.trim();
|
|
24
|
+
if (!trimmed) return "Folder name is required";
|
|
25
|
+
if (INVALID_FOLDER_CHARS.test(trimmed)) {
|
|
26
|
+
return "Folder name contains invalid characters";
|
|
27
|
+
}
|
|
28
|
+
if (trimmed.startsWith(".") || trimmed.startsWith("-")) {
|
|
29
|
+
return "Folder name should not start with . or -";
|
|
30
|
+
}
|
|
31
|
+
if (fs.existsSync(path.join(cwd, trimmed))) {
|
|
32
|
+
return `Folder "${trimmed}" already exists`;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
function isValidUuid(value) {
|
|
37
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
38
|
+
return uuidRegex.test(value.trim());
|
|
39
|
+
}
|
|
40
|
+
async function main() {
|
|
41
|
+
const onCancel = () => exit("\nSetup cancelled.\n");
|
|
42
|
+
console.log(chalk.bold("\nWelcome to Embeddable!\n"));
|
|
43
|
+
console.log(`Embeddable stores your ${chalk.bold("charting components")}, ${chalk.bold("data models")} and ${chalk.bold("themes")} in code, so you have full control over the look-and-feel and the data powering your dashboards.
|
|
44
|
+
`);
|
|
45
|
+
console.log("This tool helps you get set up to create your first Embeddable dashboard.\n");
|
|
46
|
+
const cwd = process.cwd();
|
|
47
|
+
const { confirmDir } = await prompts(
|
|
48
|
+
{
|
|
49
|
+
type: "confirm",
|
|
50
|
+
name: "confirmDir",
|
|
51
|
+
message: `Ok to create a new Project subfolder in your current directory ${chalk.cyan(cwd)}?`,
|
|
52
|
+
initial: true
|
|
53
|
+
},
|
|
54
|
+
{ onCancel }
|
|
55
|
+
);
|
|
56
|
+
if (!confirmDir) {
|
|
57
|
+
exit("\nRun this command from the directory where you'd like to create your project.\n");
|
|
58
|
+
}
|
|
59
|
+
const { folderName } = await prompts(
|
|
60
|
+
{
|
|
61
|
+
type: "text",
|
|
62
|
+
name: "folderName",
|
|
63
|
+
message: "Project folder name:",
|
|
64
|
+
initial: DEFAULT_FOLDER,
|
|
65
|
+
validate: (value) => validateFolderName(value, cwd)
|
|
66
|
+
},
|
|
67
|
+
{ onCancel }
|
|
68
|
+
);
|
|
69
|
+
if (!folderName) {
|
|
70
|
+
exit("\nSetup cancelled.\n");
|
|
71
|
+
}
|
|
72
|
+
const projectPath = path.join(cwd, folderName);
|
|
73
|
+
console.log(chalk.dim("\nDownloading boilerplate..."));
|
|
74
|
+
try {
|
|
75
|
+
const emitter = degit(REPO_URL, { cache: false, force: true });
|
|
76
|
+
await emitter.clone(projectPath);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (fs.existsSync(projectPath)) {
|
|
79
|
+
fs.rmSync(projectPath, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
82
|
+
console.error(chalk.red(`
|
|
83
|
+
Failed to download boilerplate: ${message}
|
|
84
|
+
`));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
execSync("git init", { cwd: projectPath, stdio: "ignore" });
|
|
89
|
+
} catch {
|
|
90
|
+
console.log(
|
|
91
|
+
chalk.yellow("\nWarning: Could not initialize git repository. Is git installed?")
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
console.log(chalk.dim("Installing dependencies...\n"));
|
|
95
|
+
try {
|
|
96
|
+
execSync("npm install", { cwd: projectPath, stdio: "inherit" });
|
|
97
|
+
} catch {
|
|
98
|
+
console.log(
|
|
99
|
+
chalk.yellow("\nWarning: npm install failed. You can run it manually.")
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
const { apiKey } = await prompts(
|
|
103
|
+
{
|
|
104
|
+
type: "password",
|
|
105
|
+
name: "apiKey",
|
|
106
|
+
message: `
|
|
107
|
+
Grab your API key (to create an account, head to ${chalk.cyan("https://embeddable.com/select-region")}) and paste it here:`,
|
|
108
|
+
validate: (value) => {
|
|
109
|
+
const trimmed = value.trim();
|
|
110
|
+
if (!trimmed) return "API key is required";
|
|
111
|
+
if (!isValidUuid(trimmed)) return "API key must be a valid UUID";
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{ onCancel }
|
|
116
|
+
);
|
|
117
|
+
if (!apiKey) {
|
|
118
|
+
exit("\nSetup cancelled.\n");
|
|
119
|
+
}
|
|
120
|
+
const embeddableDir = path.join(projectPath, ".embeddable");
|
|
121
|
+
fs.mkdirSync(embeddableDir, { recursive: true });
|
|
122
|
+
fs.writeFileSync(path.join(embeddableDir, ".api-key"), apiKey.trim());
|
|
123
|
+
const regionResponse = await prompts(
|
|
124
|
+
{
|
|
125
|
+
type: "select",
|
|
126
|
+
name: "region",
|
|
127
|
+
message: "Confirm your workspace region:",
|
|
128
|
+
choices: [
|
|
129
|
+
{ title: "US", value: "US" },
|
|
130
|
+
{ title: "EU", value: "EU" }
|
|
131
|
+
],
|
|
132
|
+
initial: 0
|
|
133
|
+
},
|
|
134
|
+
{ onCancel }
|
|
135
|
+
);
|
|
136
|
+
const region = regionResponse.region;
|
|
137
|
+
if (!region) {
|
|
138
|
+
exit("\nSetup cancelled.\n");
|
|
139
|
+
}
|
|
140
|
+
if (region === "EU") {
|
|
141
|
+
const configPath = path.join(projectPath, "embeddable.config.ts");
|
|
142
|
+
try {
|
|
143
|
+
const configContent = fs.readFileSync(configPath, "utf-8");
|
|
144
|
+
let updatedContent = configContent.replace(
|
|
145
|
+
/^(\s*)region:\s*["']US["'],?/m,
|
|
146
|
+
"$1// region: 'US',"
|
|
147
|
+
);
|
|
148
|
+
updatedContent = updatedContent.replace(
|
|
149
|
+
/^(\s*)\/\/\s*region:\s*["']EU["'],?/m,
|
|
150
|
+
"$1region: 'EU',"
|
|
151
|
+
);
|
|
152
|
+
if (updatedContent === configContent) {
|
|
153
|
+
console.log(
|
|
154
|
+
chalk.yellow("\nWarning: Could not update region in config file. Please set it manually.")
|
|
155
|
+
);
|
|
156
|
+
} else {
|
|
157
|
+
fs.writeFileSync(configPath, updatedContent);
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
console.log(
|
|
161
|
+
chalk.yellow("\nWarning: Could not find embeddable.config.ts to set region.")
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
console.log(chalk.dim("\nBuilding bundle...\n"));
|
|
166
|
+
try {
|
|
167
|
+
execSync("npm run embeddable:build", { cwd: projectPath, stdio: "inherit" });
|
|
168
|
+
} catch {
|
|
169
|
+
console.log(
|
|
170
|
+
chalk.yellow("\nWarning: embeddable:build failed. You can run it manually.")
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
console.log(chalk.dim("\nPushing to workspace...\n"));
|
|
174
|
+
try {
|
|
175
|
+
execSync(
|
|
176
|
+
`npm run embeddable:push -- --api-key ${apiKey.trim()} --email "no-reply@embeddable.com" --message "npx @embeddable.com/init"`,
|
|
177
|
+
{ cwd: projectPath, stdio: "inherit" }
|
|
178
|
+
);
|
|
179
|
+
} catch {
|
|
180
|
+
console.log(
|
|
181
|
+
chalk.yellow("\nWarning: embeddable:push failed. You can run it manually.")
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
const workspaceUrl = WORKSPACE_URLS[region];
|
|
185
|
+
const workspaceLink = terminalLink(workspaceUrl, workspaceUrl, {
|
|
186
|
+
fallback: (text) => text
|
|
187
|
+
});
|
|
188
|
+
const docsUrl = "https://docs.embeddable.com/getting-started/first-embeddable";
|
|
189
|
+
const docsLink = terminalLink(docsUrl, docsUrl, {
|
|
190
|
+
fallback: (text) => text
|
|
191
|
+
});
|
|
192
|
+
console.log(chalk.green(`
|
|
193
|
+
Success!
|
|
194
|
+
`));
|
|
195
|
+
console.log(`You have pushed your ${chalk.bold("components")} and ${chalk.bold("data models")} to workspace.`);
|
|
196
|
+
console.log(`Head there now to build your first Embeddable: ${chalk.cyan(workspaceLink)}
|
|
197
|
+
`);
|
|
198
|
+
console.log(`Follow the guide here to create your first Embeddable dashboard: ${chalk.cyan(docsLink)}
|
|
199
|
+
`);
|
|
200
|
+
}
|
|
201
|
+
main().catch((error) => {
|
|
202
|
+
console.error(chalk.red("An unexpected error occurred:"), error);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embeddable.com/init",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "CLI tool for Embeddable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,15 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^5.3.0",
|
|
27
|
+
"degit": "^2.8.4",
|
|
28
|
+
"prompts": "^2.4.2",
|
|
29
|
+
"terminal-link": "^5.0.0"
|
|
30
|
+
},
|
|
25
31
|
"devDependencies": {
|
|
32
|
+
"@types/degit": "^2.8.6",
|
|
33
|
+
"@types/prompts": "^2.4.9",
|
|
26
34
|
"tsup": "^8.0.0",
|
|
27
35
|
"typescript": "^5.0.0"
|
|
28
36
|
}
|