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.
@@ -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,SAwGZ,CAAC"}
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"}
@@ -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 ${config.token}`,
60
- "X-Machine-ID": config.machineId, // <-- ADD THIS LINE
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
- fs.writeFileSync(filePath, file.content);
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 { Section } from "@/${config.componentsPath}/${componentName}/Section"`));
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."));
@@ -1,4 +1,5 @@
1
1
  export declare function saveToken(token: string, machineId: string): void;
2
2
  export declare function getToken(): string | null;
3
+ export declare function getMachineId(): string | null;
3
4
  export declare function deleteToken(): void;
4
5
  //# sourceMappingURL=config.d.ts.map
@@ -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"}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ds-01",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Make your site best with DS01",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 ${config.token}`,
87
- "X-Machine-ID": config.machineId, // <-- ADD THIS LINE
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
- fs.writeFileSync(filePath, file.content);
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 { Section } from "@/${config.componentsPath}/${componentName}/Section"`,
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
+ });
@@ -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);