botversion-sdk 1.1.7 → 2.1.0

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/cli/generator.js DELETED
@@ -1,187 +0,0 @@
1
- // botversion-sdk/cli/generator.js
2
- "use strict";
3
-
4
- const path = require("path");
5
- const fs = require("fs");
6
-
7
- // ─── EXPRESS CODE GENERATION ──────────────────────────────────────────────────
8
-
9
- function generateExpressInit(info, apiKey) {
10
- const { moduleSystem, isTypeScript } = info;
11
- const isESM = moduleSystem === "esm";
12
-
13
- const appVarName = info.appVarName || "app";
14
-
15
- const importLine = isESM
16
- ? `import BotVersion from 'botversion-sdk';`
17
- : `const BotVersion = require('botversion-sdk');`;
18
-
19
- const apiKeyValue = `process.env.BOTVERSION_API_KEY`;
20
-
21
- const initBlock = `
22
- // BotVersion AI Agent — auto-added by botversion-sdk init
23
- ${importLine}
24
-
25
- BotVersion.init(${appVarName}, {
26
- apiKey: ${apiKeyValue},
27
- cwd: __dirname,
28
- });
29
- `;
30
-
31
- return {
32
- initBlock: initBlock.trim(),
33
- };
34
- }
35
-
36
- // ─── NEXT.JS INSTRUMENTATION FILE ────────────────────────────────────────────
37
- function generateInstrumentationFile(info, apiKey) {
38
- const { next, moduleSystem } = info;
39
- const isESM = moduleSystem === "esm";
40
-
41
- const hasPagesRouter = next?.pagesRouter;
42
- const hasAppRouter = next?.appRouter;
43
-
44
- // Both App Router and Pages Router use pagesDir option
45
- const pagesDirOption = "";
46
-
47
- // ESM version
48
- if (isESM) {
49
- return `export async function register() {
50
- if (process.env.NEXT_RUNTIME === 'nodejs') {
51
- const { default: BotVersion } = await import('botversion-sdk');
52
-
53
- BotVersion.init({
54
- apiKey: process.env.BOTVERSION_API_KEY,
55
- });
56
- }
57
- }
58
- `;
59
- }
60
-
61
- // CommonJS version
62
- return `async function register() {
63
- if (process.env.NEXT_RUNTIME === 'nodejs') {
64
- const BotVersion = require('botversion-sdk');
65
-
66
- BotVersion.init({
67
- apiKey: process.env.BOTVERSION_API_KEY,
68
- });
69
- }
70
- }
71
-
72
- module.exports = { register };
73
- `;
74
- }
75
-
76
- // ─── NEXT.JS CONFIG PATCH ─────────────────────────────────────────────────────
77
-
78
- function generateNextConfigPatch(cwd, nextVersion) {
79
- const candidates = ["next.config.js", "next.config.mjs", "next.config.ts"];
80
-
81
- let configPath = null;
82
- let configContent = null;
83
-
84
- for (const candidate of candidates) {
85
- const fullPath = path.join(cwd, candidate);
86
- if (fs.existsSync(fullPath)) {
87
- configPath = fullPath;
88
- configContent = fs.readFileSync(fullPath, "utf8");
89
- break;
90
- }
91
- }
92
-
93
- if (!configPath) return null;
94
-
95
- // Skip instrumentationHook for Next.js 14.1+ (enabled by default)
96
- if (nextVersion && nextVersion.major >= 14) {
97
- const rawVersion = nextVersion.raw || "";
98
- const match = rawVersion.match(/(\d+)\.(\d+)/);
99
- const minor = match ? parseInt(match[2], 10) : 0;
100
- if (nextVersion.major > 14 || (nextVersion.major === 14 && minor >= 1)) {
101
- return { path: configPath, alreadyPatched: true };
102
- }
103
- }
104
-
105
- if (configContent.includes("instrumentationHook")) {
106
- return { path: configPath, alreadyPatched: true };
107
- }
108
-
109
- let patched = configContent;
110
-
111
- if (configContent.includes("experimental")) {
112
- patched = configContent.replace(
113
- /experimental\s*:\s*\{/,
114
- "experimental: {\n instrumentationHook: true,",
115
- );
116
- } else if (/export\s+default\s+\{/.test(configContent)) {
117
- patched = configContent.replace(
118
- /export\s+default\s+\{/,
119
- "export default {\n experimental: {\n instrumentationHook: true,\n },",
120
- );
121
- } else if (/const\s+nextConfig\s*=\s*\{/.test(configContent)) {
122
- patched = configContent.replace(
123
- /const\s+nextConfig\s*=\s*\{/,
124
- "const nextConfig = {\n experimental: {\n instrumentationHook: true,\n },",
125
- );
126
- } else if (/module\.exports\s*=\s*\{/.test(configContent)) {
127
- patched = configContent.replace(
128
- /module\.exports\s*=\s*\{/,
129
- "module.exports = {\n experimental: {\n instrumentationHook: true,\n },",
130
- );
131
- } else {
132
- return null;
133
- }
134
-
135
- return { path: configPath, content: patched, alreadyPatched: false };
136
- }
137
-
138
- // ─── MANUAL INSTRUCTIONS FOR UNSUPPORTED FRAMEWORKS ──────────────────────────
139
-
140
- function generateManualInstructions(framework, apiKey) {
141
- const instructions = {
142
- fastify: `
143
- Fastify support is coming soon. For now, add this manually:
144
-
145
- const BotVersion = require('botversion-sdk');
146
-
147
- // After registering all your routes:
148
- BotVersion.init({ apiKey: process.env.BOTVERSION_API_KEY });
149
- `,
150
- koa: `
151
- Koa support is coming soon. For now, add this manually:
152
- See: https://botversion.com/docs
153
- `,
154
- "@nestjs/core": `
155
- NestJS support is coming soon. For now, add this manually:
156
- See: https://botversion.com/docs
157
- `,
158
- };
159
-
160
- return (
161
- instructions[framework] ||
162
- `
163
- This framework is not yet supported automatically.
164
- Visit https://botversion.com/docs for manual setup instructions.
165
- `
166
- );
167
- }
168
-
169
- // ─── SCRIPT TAG GENERATION ────────────────────────────────────────────────────
170
-
171
- function generateScriptTag(projectInfo) {
172
- return `<script
173
- id="botversion-loader"
174
- src="${projectInfo.cdnUrl}"
175
- data-api-url="${projectInfo.apiUrl}"
176
- data-project-id="${projectInfo.projectId}"
177
- data-public-key="${projectInfo.publicKey}"
178
- ></script>`;
179
- }
180
-
181
- module.exports = {
182
- generateExpressInit,
183
- generateInstrumentationFile,
184
- generateManualInstructions,
185
- generateNextConfigPatch,
186
- generateScriptTag,
187
- };
package/cli/prompts.js DELETED
@@ -1,163 +0,0 @@
1
- // botversion-sdk/cli/prompts.js
2
-
3
- "use strict";
4
-
5
- const readline = require("readline");
6
-
7
- // ─── BASE PROMPT HELPER ───────────────────────────────────────────────────────
8
-
9
- function ask(question) {
10
- const rl = readline.createInterface({
11
- input: process.stdin,
12
- output: process.stdout,
13
- });
14
-
15
- return new Promise((resolve) => {
16
- rl.question(question, (answer) => {
17
- rl.close();
18
- resolve(answer.trim());
19
- });
20
- });
21
- }
22
-
23
- function askChoice(question, choices) {
24
- const rl = readline.createInterface({
25
- input: process.stdin,
26
- output: process.stdout,
27
- });
28
-
29
- return new Promise((resolve) => {
30
- console.log("\n" + question);
31
- choices.forEach((choice, i) => {
32
- console.log(` ${i + 1}. ${choice.label}`);
33
- });
34
- console.log("");
35
-
36
- const prompt = () => {
37
- rl.question(`Enter number (1-${choices.length}): `, (answer) => {
38
- const num = parseInt(answer.trim(), 10);
39
- if (num >= 1 && num <= choices.length) {
40
- rl.close();
41
- resolve(choices[num - 1]);
42
- } else {
43
- console.log(
44
- ` Please enter a number between 1 and ${choices.length}`,
45
- );
46
- prompt();
47
- }
48
- });
49
- };
50
-
51
- prompt();
52
- });
53
- }
54
-
55
- function confirm(question, defaultYes) {
56
- const hint = defaultYes ? "[Y/n]" : "[y/N]";
57
- return ask(`${question} ${hint}: `).then((answer) => {
58
- if (!answer) return defaultYes;
59
- return answer.toLowerCase().startsWith("y");
60
- });
61
- }
62
-
63
- // ─── SPECIFIC PROMPTS ─────────────────────────────────────────────────────────
64
-
65
- async function promptMonorepoPackage(packages, cwd) {
66
- const path = require("path");
67
- const choices = packages.map((p) => ({
68
- label: path.relative(cwd, p),
69
- value: p,
70
- }));
71
-
72
- choices.push({ label: "This directory (root)", value: cwd });
73
-
74
- const choice = await askChoice(
75
- "We found multiple packages (monorepo). Which is your backend?",
76
- choices,
77
- );
78
-
79
- return choice.value;
80
- }
81
-
82
- async function promptEntryPoint() {
83
- console.log(
84
- "\n ⚠️ We couldn't find your server entry point automatically.",
85
- );
86
- const filePath = await ask(
87
- " Enter the path to your main server file (e.g. src/server.js): ",
88
- );
89
- return filePath;
90
- }
91
-
92
- async function promptForce(conflictFile) {
93
- console.log(`\n ⚠️ File already exists: ${conflictFile}`);
94
- return confirm(" Overwrite it? (a backup will be created)", false);
95
- }
96
-
97
- const CONFIG_FILES = [
98
- "next.config.js",
99
- "next.config.ts",
100
- "vite.config.js",
101
- "vite.config.ts",
102
- "webpack.config.js",
103
- "webpack.config.ts",
104
- "nuxt.config.js",
105
- "nuxt.config.ts",
106
- ];
107
-
108
- async function promptMissingListenCall(entryPoint) {
109
- const path = require("path");
110
- const entryFileName = path.basename(entryPoint || "");
111
- const isConfigFile = CONFIG_FILES.includes(entryFileName);
112
-
113
- console.log(`\n ⚠️ We couldn't find app.listen() in ${entryPoint}`);
114
-
115
- if (isConfigFile) {
116
- console.log(
117
- `\n ❌ "${entryFileName}" is a config file, not a server file.`,
118
- );
119
- console.log(" Appending server code here would break your project.");
120
- console.log(" Options:");
121
-
122
- const choices = [
123
- {
124
- label: "Enter the correct server file path manually",
125
- value: "manual_path",
126
- },
127
- { label: "Skip — I'll add it manually", value: "skip" },
128
- ];
129
-
130
- const choice = await askChoice("How would you like to proceed?", choices);
131
- if (choice.value === "manual_path") {
132
- const filePath = await ask(" Enter file path: ");
133
- return { action: "manual_path", filePath };
134
- }
135
- return { action: choice.value };
136
- }
137
-
138
- // Normal flow — entry point is not a config file
139
- console.log(" Options:");
140
- const choices = [
141
- { label: "Append to end of file", value: "append" },
142
- { label: "Enter the correct file path manually", value: "manual_path" },
143
- { label: "Skip — I'll add it manually", value: "skip" },
144
- ];
145
-
146
- const choice = await askChoice("How would you like to proceed?", choices);
147
- if (choice.value === "manual_path") {
148
- const filePath = await ask(" Enter file path: ");
149
- return { action: "manual_path", filePath };
150
- }
151
-
152
- return { action: choice.value };
153
- }
154
-
155
- module.exports = {
156
- ask,
157
- askChoice,
158
- confirm,
159
- promptMonorepoPackage,
160
- promptEntryPoint,
161
- promptForce,
162
- promptMissingListenCall,
163
- };