ds-01 1.0.2 → 1.0.4
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/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +26 -5
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +13 -0
- package/package.json +1 -1
- package/src/commands/add.ts +49 -20
- package/src/utils/config.ts +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDpC,eAAO,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDpC,eAAO,MAAM,GAAG,SAqIZ,CAAC"}
|
package/dist/commands/add.js
CHANGED
|
@@ -4,7 +4,7 @@ import pc from "picocolors";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
import { getToken } from "../utils/config.js";
|
|
7
|
+
import { getToken, getMachineId } from "../utils/config.js";
|
|
8
8
|
const API_BASE_URL = process.env.DS01_API_URL || "https://ds-01.vercel.app";
|
|
9
9
|
// Helper to verify Tailwind exists before doing anything
|
|
10
10
|
function checkTailwindInstallation() {
|
|
@@ -49,15 +49,21 @@ export const add = new Command()
|
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
51
|
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
52
|
+
// Read the GLOBAL credentials, not the local project config
|
|
52
53
|
const token = getToken();
|
|
54
|
+
const machineId = getMachineId();
|
|
55
|
+
if (!token || !machineId) {
|
|
56
|
+
cancel(pc.red("You are not authenticated. Run 'npx ds-01 login' first."));
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
53
59
|
const s = spinner();
|
|
54
60
|
s.start(`Fetching ${pc.cyan(`<${componentName} />`)} from registry...`);
|
|
55
61
|
try {
|
|
56
62
|
// 3. Fetch component from your API
|
|
57
63
|
const response = await fetch(`${API_BASE_URL}/api/registry/${componentName}`, {
|
|
58
64
|
headers: {
|
|
59
|
-
Authorization: `Bearer ${
|
|
60
|
-
"X-Machine-ID":
|
|
65
|
+
Authorization: `Bearer ${token}`,
|
|
66
|
+
"X-Machine-ID": machineId, // <-- TypeScript error fixed here
|
|
61
67
|
},
|
|
62
68
|
});
|
|
63
69
|
if (!response.ok) {
|
|
@@ -71,10 +77,23 @@ export const add = new Command()
|
|
|
71
77
|
if (!fs.existsSync(targetDir)) {
|
|
72
78
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
73
79
|
}
|
|
80
|
+
// 🛠️ EXTRACT NAMES FOR SMART REWRITING (e.g., ["PremiumHero", "Section", "AnimatedText"])
|
|
81
|
+
// We strip the extension (.tsx, .ts) to get the raw component name for import matching
|
|
82
|
+
const bundledFileNames = componentData.files.map((file) => file.name.replace(/\.[^/.]+$/, ""));
|
|
74
83
|
// 5. Inject the pure code files
|
|
75
84
|
for (const file of componentData.files) {
|
|
85
|
+
// Because the server sends just the basename (e.g., PremiumHero.tsx),
|
|
86
|
+
// path.join inherently flattens all files into the single targetDir folder.
|
|
76
87
|
const filePath = path.join(targetDir, file.name);
|
|
77
|
-
|
|
88
|
+
let content = file.content;
|
|
89
|
+
// 🛠️ DYNAMIC IMPORT REWRITER
|
|
90
|
+
bundledFileNames.forEach((fileName) => {
|
|
91
|
+
// Finds any relative import pointing to a bundled file (e.g., "../Section", "../../Section")
|
|
92
|
+
// and rewrites it strictly to a sibling import (e.g., "./Section")
|
|
93
|
+
const regex = new RegExp(`from\\s+["']\\.[^"']*?\\/${fileName}["']`, "g");
|
|
94
|
+
content = content.replace(regex, `from "./${fileName}"`);
|
|
95
|
+
});
|
|
96
|
+
fs.writeFileSync(filePath, content);
|
|
78
97
|
}
|
|
79
98
|
s.stop(pc.green(`Downloaded ${componentData.files.length} files into ${pc.white(`/${config.componentsPath}/${componentName}`)}`));
|
|
80
99
|
// 6. Auto-install Missing Component Dependencies (e.g., framer-motion)
|
|
@@ -92,9 +111,11 @@ export const add = new Command()
|
|
|
92
111
|
}
|
|
93
112
|
}
|
|
94
113
|
// 7. Clean Success Outro
|
|
114
|
+
// Find the main file to import (prioritize the one that matches the component name or use the first one)
|
|
115
|
+
const mainFile = bundledFileNames.find((name) => name.toLowerCase() === componentName.toLowerCase()) || bundledFileNames[0];
|
|
95
116
|
outro(`${pc.white("✔")} ${pc.bold(`Component <${componentName} /> is ready!`)}\n` +
|
|
96
117
|
pc.gray(`Import it: `) +
|
|
97
|
-
pc.cyan(`import {
|
|
118
|
+
pc.cyan(`import { ${mainFile} } from "@/${config.componentsPath}/${componentName}/${mainFile}"`));
|
|
98
119
|
}
|
|
99
120
|
catch (error) {
|
|
100
121
|
s.stop(pc.red("An error occurred during injection."));
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAQA,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAczD;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAWxC;AAED,wBAAgB,WAAW,SAI1B"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAQA,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAczD;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAWxC;AAED,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAW5C;AAED,wBAAgB,WAAW,SAI1B"}
|
package/dist/utils/config.js
CHANGED
|
@@ -30,6 +30,19 @@ export function getToken() {
|
|
|
30
30
|
}
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
|
+
export function getMachineId() {
|
|
34
|
+
if (fs.existsSync(credentialsPath)) {
|
|
35
|
+
try {
|
|
36
|
+
const data = fs.readFileSync(credentialsPath, "utf-8");
|
|
37
|
+
const parsed = JSON.parse(data);
|
|
38
|
+
return parsed.machineId || null;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
33
46
|
export function deleteToken() {
|
|
34
47
|
if (fs.existsSync(credentialsPath)) {
|
|
35
48
|
fs.unlinkSync(credentialsPath);
|
package/package.json
CHANGED
package/src/commands/add.ts
CHANGED
|
@@ -4,7 +4,7 @@ import pc from "picocolors";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
import { getToken } from "../utils/config.js";
|
|
7
|
+
import { getToken, getMachineId } from "../utils/config.js";
|
|
8
8
|
|
|
9
9
|
const API_BASE_URL = process.env.DS01_API_URL || "https://ds-01.vercel.app";
|
|
10
10
|
|
|
@@ -17,8 +17,8 @@ function checkTailwindInstallation() {
|
|
|
17
17
|
if (!fs.existsSync(pkgJsonPath)) {
|
|
18
18
|
cancel(
|
|
19
19
|
pc.red(
|
|
20
|
-
"No package.json found. Please run this command inside a Node.js project."
|
|
21
|
-
)
|
|
20
|
+
"No package.json found. Please run this command inside a Node.js project."
|
|
21
|
+
)
|
|
22
22
|
);
|
|
23
23
|
process.exit(1);
|
|
24
24
|
}
|
|
@@ -35,14 +35,14 @@ function checkTailwindInstallation() {
|
|
|
35
35
|
cancel(
|
|
36
36
|
pc.red("Tailwind CSS is missing from your project dependencies.\n") +
|
|
37
37
|
pc.gray(
|
|
38
|
-
"DS01 components rely strictly on Tailwind CSS for styling.\n\n"
|
|
38
|
+
"DS01 components rely strictly on Tailwind CSS for styling.\n\n"
|
|
39
39
|
) +
|
|
40
40
|
pc.white(
|
|
41
|
-
"Kindly install it and configure your project, then retry:\n"
|
|
41
|
+
"Kindly install it and configure your project, then retry:\n"
|
|
42
42
|
) +
|
|
43
43
|
pc.cyan(" npm install tailwindcss @tailwindcss/postcss postcss\n\n") +
|
|
44
44
|
pc.gray("Official Setup Guide: ") +
|
|
45
|
-
pc.underline("https://tailwindcss.com/docs/installation")
|
|
45
|
+
pc.underline("https://tailwindcss.com/docs/installation")
|
|
46
46
|
);
|
|
47
47
|
process.exit(1);
|
|
48
48
|
}
|
|
@@ -57,7 +57,7 @@ export const add = new Command()
|
|
|
57
57
|
|
|
58
58
|
// 1. Premium Header
|
|
59
59
|
intro(
|
|
60
|
-
`${pc.bgWhite(pc.black(pc.bold(" DS01 ")))} ${pc.gray("Adding Component")}
|
|
60
|
+
`${pc.bgWhite(pc.black(pc.bold(" DS01 ")))} ${pc.gray("Adding Component")}`
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
// 2. Run Pre-Flight Tailwind Check
|
|
@@ -72,7 +72,15 @@ export const add = new Command()
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
75
|
+
|
|
76
|
+
// Read the GLOBAL credentials, not the local project config
|
|
75
77
|
const token = getToken();
|
|
78
|
+
const machineId = getMachineId();
|
|
79
|
+
|
|
80
|
+
if (!token || !machineId) {
|
|
81
|
+
cancel(pc.red("You are not authenticated. Run 'npx ds-01 login' first."));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
76
84
|
|
|
77
85
|
const s = spinner();
|
|
78
86
|
s.start(`Fetching ${pc.cyan(`<${componentName} />`)} from registry...`);
|
|
@@ -83,10 +91,10 @@ export const add = new Command()
|
|
|
83
91
|
`${API_BASE_URL}/api/registry/${componentName}`,
|
|
84
92
|
{
|
|
85
93
|
headers: {
|
|
86
|
-
Authorization: `Bearer ${
|
|
87
|
-
"X-Machine-ID":
|
|
94
|
+
Authorization: `Bearer ${token}`,
|
|
95
|
+
"X-Machine-ID": machineId as string, // <-- TypeScript error fixed here
|
|
88
96
|
},
|
|
89
|
-
}
|
|
97
|
+
}
|
|
90
98
|
);
|
|
91
99
|
|
|
92
100
|
if (!response.ok) {
|
|
@@ -103,23 +111,41 @@ export const add = new Command()
|
|
|
103
111
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
104
112
|
}
|
|
105
113
|
|
|
114
|
+
// 🛠️ EXTRACT NAMES FOR SMART REWRITING (e.g., ["PremiumHero", "Section", "AnimatedText"])
|
|
115
|
+
// We strip the extension (.tsx, .ts) to get the raw component name for import matching
|
|
116
|
+
const bundledFileNames = componentData.files.map((file: any) =>
|
|
117
|
+
file.name.replace(/\.[^/.]+$/, "")
|
|
118
|
+
);
|
|
119
|
+
|
|
106
120
|
// 5. Inject the pure code files
|
|
107
121
|
for (const file of componentData.files) {
|
|
122
|
+
// Because the server sends just the basename (e.g., PremiumHero.tsx),
|
|
123
|
+
// path.join inherently flattens all files into the single targetDir folder.
|
|
108
124
|
const filePath = path.join(targetDir, file.name);
|
|
109
|
-
|
|
125
|
+
let content = file.content;
|
|
126
|
+
|
|
127
|
+
// 🛠️ DYNAMIC IMPORT REWRITER
|
|
128
|
+
bundledFileNames.forEach((fileName: string) => {
|
|
129
|
+
// Finds any relative import pointing to a bundled file (e.g., "../Section", "../../Section")
|
|
130
|
+
// and rewrites it strictly to a sibling import (e.g., "./Section")
|
|
131
|
+
const regex = new RegExp(`from\\s+["']\\.[^"']*?\\/${fileName}["']`, "g");
|
|
132
|
+
content = content.replace(regex, `from "./${fileName}"`);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
fs.writeFileSync(filePath, content);
|
|
110
136
|
}
|
|
111
137
|
|
|
112
138
|
s.stop(
|
|
113
139
|
pc.green(
|
|
114
|
-
`Downloaded ${componentData.files.length} files into ${pc.white(`/${config.componentsPath}/${componentName}`)}
|
|
115
|
-
)
|
|
140
|
+
`Downloaded ${componentData.files.length} files into ${pc.white(`/${config.componentsPath}/${componentName}`)}`
|
|
141
|
+
)
|
|
116
142
|
);
|
|
117
143
|
|
|
118
144
|
// 6. Auto-install Missing Component Dependencies (e.g., framer-motion)
|
|
119
145
|
if (componentData.dependencies && componentData.dependencies.length > 0) {
|
|
120
146
|
const depsToInstall = componentData.dependencies.join(" ");
|
|
121
147
|
s.start(
|
|
122
|
-
`Installing missing dependencies: ${pc.cyan(depsToInstall)}
|
|
148
|
+
`Installing missing dependencies: ${pc.cyan(depsToInstall)}...`
|
|
123
149
|
);
|
|
124
150
|
|
|
125
151
|
try {
|
|
@@ -127,29 +153,32 @@ export const add = new Command()
|
|
|
127
153
|
execSync(`npm install ${depsToInstall}`, { stdio: "ignore" });
|
|
128
154
|
s.stop(
|
|
129
155
|
pc.green(
|
|
130
|
-
`Dependencies installed successfully: ${pc.gray(depsToInstall)}
|
|
131
|
-
)
|
|
156
|
+
`Dependencies installed successfully: ${pc.gray(depsToInstall)}`
|
|
157
|
+
)
|
|
132
158
|
);
|
|
133
159
|
} catch (error) {
|
|
134
160
|
s.stop(pc.red("Failed to auto-install dependencies."));
|
|
135
161
|
note(
|
|
136
162
|
`Please run: ${pc.cyan(`npm install ${depsToInstall}`)} manually.`,
|
|
137
|
-
"Manual Action Required"
|
|
163
|
+
"Manual Action Required"
|
|
138
164
|
);
|
|
139
165
|
}
|
|
140
166
|
}
|
|
141
167
|
|
|
142
168
|
// 7. Clean Success Outro
|
|
169
|
+
// Find the main file to import (prioritize the one that matches the component name or use the first one)
|
|
170
|
+
const mainFile = bundledFileNames.find((name: string) => name.toLowerCase() === componentName.toLowerCase()) || bundledFileNames[0];
|
|
171
|
+
|
|
143
172
|
outro(
|
|
144
173
|
`${pc.white("✔")} ${pc.bold(`Component <${componentName} /> is ready!`)}\n` +
|
|
145
174
|
pc.gray(`Import it: `) +
|
|
146
175
|
pc.cyan(
|
|
147
|
-
`import {
|
|
148
|
-
)
|
|
176
|
+
`import { ${mainFile} } from "@/${config.componentsPath}/${componentName}/${mainFile}"`
|
|
177
|
+
)
|
|
149
178
|
);
|
|
150
179
|
} catch (error: any) {
|
|
151
180
|
s.stop(pc.red("An error occurred during injection."));
|
|
152
181
|
cancel(pc.gray(error.message || "Unknown CLI Error"));
|
|
153
182
|
process.exit(1);
|
|
154
183
|
}
|
|
155
|
-
});
|
|
184
|
+
});
|
package/src/utils/config.ts
CHANGED
|
@@ -35,6 +35,19 @@ export function getToken(): string | null {
|
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export function getMachineId(): string | null {
|
|
39
|
+
if (fs.existsSync(credentialsPath)) {
|
|
40
|
+
try {
|
|
41
|
+
const data = fs.readFileSync(credentialsPath, "utf-8");
|
|
42
|
+
const parsed = JSON.parse(data);
|
|
43
|
+
return parsed.machineId || null;
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
export function deleteToken() {
|
|
39
52
|
if (fs.existsSync(credentialsPath)) {
|
|
40
53
|
fs.unlinkSync(credentialsPath);
|