usetraceforge-cli 0.1.10 → 0.1.13

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 CHANGED
@@ -3,6 +3,9 @@ import { intro, outro, text, select, spinner } from "@clack/prompts";
3
3
  import chalk from "chalk";
4
4
  import { execa } from "execa";
5
5
  import { installNextJs } from "./installers/nextjs.js";
6
+ import { installExpress } from "./installers/express.js";
7
+ import { installReact } from "./installers/react.js";
8
+ import { installNode } from "./installers/node.js";
6
9
  async function main() {
7
10
  console.log();
8
11
  intro(chalk.bgBlue(chalk.white(" Welcome to TraceForge ")));
@@ -27,7 +30,9 @@ async function main() {
27
30
  message: "Which framework are you using?",
28
31
  options: [
29
32
  { value: "nextjs", label: "Next.js (Prebuilt)" },
30
- { value: "express", label: "Express.js (Prebuilt)" },
33
+ { value: "express", label: "Express.js (Auto Setup)" },
34
+ { value: "react", label: "React (Manual Setup)" },
35
+ { value: "node", label: "Raw Node.js (Manual Setup)" },
31
36
  ],
32
37
  });
33
38
  if (typeof framework !== "string") {
@@ -49,7 +54,13 @@ async function main() {
49
54
  await installNextJs(apiKey, endpoint);
50
55
  }
51
56
  else if (framework === "express") {
52
- console.log(chalk.yellow("Express auto-installation coming soon."));
57
+ await installExpress(apiKey, endpoint);
58
+ }
59
+ else if (framework === "react") {
60
+ await installReact(apiKey, endpoint);
61
+ }
62
+ else if (framework === "node") {
63
+ await installNode(apiKey, endpoint);
53
64
  }
54
65
  outro(chalk.green("✨ You're all set! TraceForge is now protecting your application."));
55
66
  }
@@ -0,0 +1,119 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { spinner } from "@clack/prompts";
4
+ import chalk from "chalk";
5
+ import { Project, SyntaxKind } from "ts-morph";
6
+ function printManualInstructions() {
7
+ console.log(chalk.cyan(`\n=================================================`));
8
+ console.log(chalk.bold.white(`🚀 Express.js Manual Setup Instructions`));
9
+ console.log(chalk.cyan(`=================================================\n`));
10
+ console.log(`Add this at the ${chalk.bold('TOP')} of your main file (e.g. app.js or server.js):`);
11
+ console.log(chalk.yellow(`
12
+ import TraceForge from "usetraceforge";
13
+ import { expressErrorHandler } from "usetraceforge/express";
14
+
15
+ TraceForge.init({
16
+ apiKey: process.env.TRACEFORGE_API_KEY,
17
+ endpoint: process.env.TRACEFORGE_INGEST_URL
18
+ });
19
+ `));
20
+ console.log(`Then, add the middleware at the ${chalk.bold('VERY END')} of your routes:`);
21
+ console.log(chalk.yellow(`
22
+ // ... all your other app.use() and app.get() routes ...
23
+
24
+ app.use(expressErrorHandler());
25
+
26
+ // ... your custom error handlers (if any) ...
27
+ app.listen(3000);
28
+ `));
29
+ }
30
+ export async function installExpress(apiKey, endpoint) {
31
+ const s = spinner();
32
+ s.start("Agent: Configuring Express.js environment...");
33
+ try {
34
+ const envPath = path.resolve(process.cwd(), ".env");
35
+ const envVar = `\nTRACEFORGE_API_KEY="${apiKey}"\nTRACEFORGE_INGEST_URL="${endpoint}"\n`;
36
+ if (fs.existsSync(envPath)) {
37
+ let content = fs.readFileSync(envPath, "utf-8");
38
+ if (content.includes("TRACEFORGE_API_KEY")) {
39
+ content = content.replace(/TRACEFORGE_API_KEY=.*/g, `TRACEFORGE_API_KEY="${apiKey}"`);
40
+ content = content.replace(/TRACEFORGE_INGEST_URL=.*/g, `TRACEFORGE_INGEST_URL="${endpoint}"`);
41
+ fs.writeFileSync(envPath, content);
42
+ }
43
+ else {
44
+ fs.appendFileSync(envPath, envVar);
45
+ }
46
+ }
47
+ else {
48
+ fs.writeFileSync(envPath, envVar);
49
+ }
50
+ s.stop(chalk.green("Agent: .env configured successfully!"));
51
+ const project = new Project();
52
+ const possiblePaths = [
53
+ "app.ts", "app.js",
54
+ "server.ts", "server.js",
55
+ "index.ts", "index.js",
56
+ "src/app.ts", "src/app.js",
57
+ "src/server.ts", "src/server.js",
58
+ "src/index.ts", "src/index.js",
59
+ "bin/www", "bin/www.js"
60
+ ];
61
+ let targetFile = null;
62
+ for (const p of possiblePaths) {
63
+ const fullPath = path.resolve(process.cwd(), p);
64
+ if (fs.existsSync(fullPath)) {
65
+ targetFile = fullPath;
66
+ break; // First match wins
67
+ }
68
+ }
69
+ if (!targetFile) {
70
+ console.log(chalk.yellow("\nAgent: Could not find your Express entrypoint file automatically."));
71
+ printManualInstructions();
72
+ return;
73
+ }
74
+ const sourceFile = project.addSourceFileAtPath(targetFile);
75
+ let astSuccess = false;
76
+ const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
77
+ let listenCall = null;
78
+ let appVariableName = null;
79
+ for (const callExpr of callExpressions) {
80
+ const expression = callExpr.getExpression();
81
+ if (expression.getKind() === SyntaxKind.PropertyAccessExpression) {
82
+ const propAccess = expression.asKindOrThrow(SyntaxKind.PropertyAccessExpression);
83
+ if (propAccess.getName() === "listen") {
84
+ listenCall = callExpr;
85
+ appVariableName = propAccess.getExpression().getText();
86
+ break;
87
+ }
88
+ }
89
+ }
90
+ if (listenCall && appVariableName) {
91
+ const listenStatement = listenCall.getFirstAncestorByKind(SyntaxKind.ExpressionStatement);
92
+ if (listenStatement) {
93
+ if (!sourceFile.getFullText().includes("TraceForge.init")) {
94
+ // Inject imports and init at the top
95
+ sourceFile.insertStatements(0, `import TraceForge from "usetraceforge";\nimport { expressErrorHandler } from "usetraceforge/express";\n\nTraceForge.init({\n apiKey: process.env.TRACEFORGE_API_KEY as string,\n endpoint: process.env.TRACEFORGE_INGEST_URL\n});\n`);
96
+ // Inject middleware right before app.listen()
97
+ const listenIndex = listenStatement.getChildIndex();
98
+ sourceFile.insertStatements(listenIndex, `\n// TraceForge must be the last middleware before listen\n${appVariableName}.use(expressErrorHandler());\n`);
99
+ sourceFile.saveSync();
100
+ console.log(chalk.green(`\nAgent: Auto-injected TraceForge into ${targetFile.replace(process.cwd(), "")}!`));
101
+ astSuccess = true;
102
+ }
103
+ else {
104
+ console.log(chalk.blue(`\nAgent: TraceForge is already configured in ${targetFile.replace(process.cwd(), "")}`));
105
+ astSuccess = true;
106
+ }
107
+ }
108
+ }
109
+ if (!astSuccess) {
110
+ console.log(chalk.yellow(`\nAgent: Found ${targetFile.replace(process.cwd(), "")} but could not auto-inject safely.`));
111
+ printManualInstructions();
112
+ }
113
+ }
114
+ catch (error) {
115
+ s.stop(chalk.red("Agent: An error occurred during Express configuration."));
116
+ console.error(error);
117
+ printManualInstructions();
118
+ }
119
+ }
@@ -11,8 +11,13 @@ export async function installNextJs(apiKey, endpoint) {
11
11
  const envPath = path.resolve(process.cwd(), ".env.local");
12
12
  const envVar = `\nNEXT_PUBLIC_TRACEFORGE_API_KEY="${apiKey}"\nNEXT_PUBLIC_TRACEFORGE_INGEST_URL="${endpoint}"\n`;
13
13
  if (fs.existsSync(envPath)) {
14
- const content = fs.readFileSync(envPath, "utf-8");
15
- if (!content.includes("NEXT_PUBLIC_TRACEFORGE_API_KEY")) {
14
+ let content = fs.readFileSync(envPath, "utf-8");
15
+ if (content.includes("NEXT_PUBLIC_TRACEFORGE_API_KEY")) {
16
+ content = content.replace(/NEXT_PUBLIC_TRACEFORGE_API_KEY=.*/g, `NEXT_PUBLIC_TRACEFORGE_API_KEY="${apiKey}"`);
17
+ content = content.replace(/NEXT_PUBLIC_TRACEFORGE_INGEST_URL=.*/g, `NEXT_PUBLIC_TRACEFORGE_INGEST_URL="${endpoint}"`);
18
+ fs.writeFileSync(envPath, content);
19
+ }
20
+ else {
16
21
  fs.appendFileSync(envPath, envVar);
17
22
  }
18
23
  }
@@ -0,0 +1,51 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { spinner } from "@clack/prompts";
4
+ import chalk from "chalk";
5
+ export async function installNode(apiKey, endpoint) {
6
+ const s = spinner();
7
+ s.start("Agent: Configuring Node.js environment...");
8
+ try {
9
+ const envPath = path.resolve(process.cwd(), ".env");
10
+ const envVar = `\nTRACEFORGE_API_KEY="${apiKey}"\nTRACEFORGE_INGEST_URL="${endpoint}"\n`;
11
+ if (fs.existsSync(envPath)) {
12
+ let content = fs.readFileSync(envPath, "utf-8");
13
+ if (content.includes("TRACEFORGE_API_KEY")) {
14
+ content = content.replace(/TRACEFORGE_API_KEY=.*/g, `TRACEFORGE_API_KEY="${apiKey}"`);
15
+ content = content.replace(/TRACEFORGE_INGEST_URL=.*/g, `TRACEFORGE_INGEST_URL="${endpoint}"`);
16
+ fs.writeFileSync(envPath, content);
17
+ }
18
+ else {
19
+ fs.appendFileSync(envPath, envVar);
20
+ }
21
+ }
22
+ else {
23
+ fs.writeFileSync(envPath, envVar);
24
+ }
25
+ s.stop(chalk.green("Agent: .env configured successfully!"));
26
+ console.log(chalk.cyan(`\n=================================================`));
27
+ console.log(chalk.bold.white(`🚀 Node.js Manual Setup Instructions`));
28
+ console.log(chalk.cyan(`=================================================\n`));
29
+ console.log(`Add this to your entrypoint file:`);
30
+ console.log(chalk.yellow(`
31
+ import TraceForge from "usetraceforge";
32
+
33
+ TraceForge.init({
34
+ apiKey: process.env.TRACEFORGE_API_KEY,
35
+ endpoint: process.env.TRACEFORGE_INGEST_URL
36
+ });
37
+ `));
38
+ console.log(`Then, manually capture errors like this:`);
39
+ console.log(chalk.yellow(`
40
+ try {
41
+ // your code
42
+ } catch (error) {
43
+ TraceForge.captureException(error);
44
+ }
45
+ `));
46
+ }
47
+ catch (error) {
48
+ s.stop(chalk.red("Agent: An error occurred."));
49
+ console.error(error);
50
+ }
51
+ }
@@ -0,0 +1,57 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { spinner } from "@clack/prompts";
4
+ import chalk from "chalk";
5
+ export async function installReact(apiKey, endpoint) {
6
+ const s = spinner();
7
+ s.start("Agent: Configuring React environment...");
8
+ try {
9
+ // For React, usually Vite uses VITE_ prefix, CRA uses REACT_APP_
10
+ // Let's create a generic .env but also print the keys
11
+ const envPath = path.resolve(process.cwd(), ".env");
12
+ const envVar = `\nVITE_TRACEFORGE_API_KEY="${apiKey}"\nVITE_TRACEFORGE_INGEST_URL="${endpoint}"\nREACT_APP_TRACEFORGE_API_KEY="${apiKey}"\nREACT_APP_TRACEFORGE_INGEST_URL="${endpoint}"\n`;
13
+ if (fs.existsSync(envPath)) {
14
+ let content = fs.readFileSync(envPath, "utf-8");
15
+ if (content.includes("TRACEFORGE_API_KEY")) {
16
+ content = content.replace(/VITE_TRACEFORGE_API_KEY=.*/g, `VITE_TRACEFORGE_API_KEY="${apiKey}"`);
17
+ content = content.replace(/VITE_TRACEFORGE_INGEST_URL=.*/g, `VITE_TRACEFORGE_INGEST_URL="${endpoint}"`);
18
+ content = content.replace(/REACT_APP_TRACEFORGE_API_KEY=.*/g, `REACT_APP_TRACEFORGE_API_KEY="${apiKey}"`);
19
+ content = content.replace(/REACT_APP_TRACEFORGE_INGEST_URL=.*/g, `REACT_APP_TRACEFORGE_INGEST_URL="${endpoint}"`);
20
+ fs.writeFileSync(envPath, content);
21
+ }
22
+ else {
23
+ fs.appendFileSync(envPath, envVar);
24
+ }
25
+ }
26
+ else {
27
+ fs.writeFileSync(envPath, envVar);
28
+ }
29
+ s.stop(chalk.green("Agent: .env configured successfully!"));
30
+ console.log(chalk.cyan(`\n=================================================`));
31
+ console.log(chalk.bold.white(`🚀 React Manual Setup Instructions`));
32
+ console.log(chalk.cyan(`=================================================\n`));
33
+ console.log(`Open your main file (e.g. App.tsx or main.tsx) and wrap your app:`);
34
+ console.log(chalk.yellow(`
35
+ import TraceForge from "usetraceforge";
36
+ import { TraceForgeProvider } from "usetraceforge/react";
37
+
38
+ // For Vite use import.meta.env, for CRA use process.env
39
+ TraceForge.init({
40
+ apiKey: import.meta.env.VITE_TRACEFORGE_API_KEY,
41
+ endpoint: import.meta.env.VITE_TRACEFORGE_INGEST_URL
42
+ });
43
+
44
+ export default function App() {
45
+ return (
46
+ <TraceForgeProvider>
47
+ <YourComponents />
48
+ </TraceForgeProvider>
49
+ );
50
+ }
51
+ `));
52
+ }
53
+ catch (error) {
54
+ s.stop(chalk.red("Agent: An error occurred."));
55
+ console.error(error);
56
+ }
57
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usetraceforge-cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.13",
4
4
  "description": "TraceForge CLI Wizard for 2-click installations",
5
5
  "bin": {
6
6
  "traceforge": "./dist/index.js"