botversion-sdk 1.0.0 → 1.0.2
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/bin/init.js +201 -62
- package/cli/detector.js +473 -71
- package/cli/generator.js +298 -137
- package/cli/writer.js +270 -6
- package/client.js +4 -0
- package/index.js +12 -3
- package/interceptor.js +2 -2
- package/package.json +1 -1
- package/scanner.js +21 -22
package/cli/generator.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// botversion-sdk/cli/generator.js
|
|
2
|
-
|
|
3
2
|
"use strict";
|
|
4
3
|
|
|
5
4
|
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
6
|
|
|
7
|
-
// ─── EXPRESS CODE GENERATION
|
|
7
|
+
// ─── EXPRESS CODE GENERATION ──────────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
function generateExpressInit(info, apiKey) {
|
|
10
10
|
const { moduleSystem, isTypeScript, auth } = info;
|
|
11
11
|
const isESM = moduleSystem === "esm";
|
|
12
12
|
|
|
13
|
+
// FIX #2: Detect the actual app variable name used in the entry file
|
|
14
|
+
const appVarName = info.appVarName || "app";
|
|
15
|
+
|
|
13
16
|
const importLine = isESM
|
|
14
17
|
? `import BotVersion from 'botversion-sdk';`
|
|
15
18
|
: `const BotVersion = require('botversion-sdk');`;
|
|
@@ -20,11 +23,11 @@ function generateExpressInit(info, apiKey) {
|
|
|
20
23
|
// BotVersion AI Agent — auto-added by botversion-sdk init
|
|
21
24
|
${importLine}
|
|
22
25
|
|
|
23
|
-
BotVersion.init(
|
|
24
|
-
apiKey:
|
|
26
|
+
BotVersion.init(${appVarName}, {
|
|
27
|
+
apiKey: process.env.BOTVERSION_API_KEY,
|
|
25
28
|
});
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
${appVarName}.post('/api/botversion/chat', (req, res) => {
|
|
28
31
|
BotVersion.chat(req, res);
|
|
29
32
|
});
|
|
30
33
|
`;
|
|
@@ -96,30 +99,54 @@ function generateExpressUserContext(auth) {
|
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
// ─── NEXT.JS
|
|
102
|
+
// ─── NEXT.JS INSTRUMENTATION FILE ────────────────────────────────────────────
|
|
103
|
+
|
|
100
104
|
function generateInstrumentationFile(info, apiKey) {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
const { next, moduleSystem } = info;
|
|
106
|
+
|
|
107
|
+
// FIX #3: Only include pagesDir if Pages Router actually exists
|
|
108
|
+
// FIX #8: Use dynamic import instead of require() to support ESM projects
|
|
109
|
+
const hasPagesRouter = next?.pagesRouter;
|
|
110
|
+
const hasAppRouter = next?.appRouter;
|
|
111
|
+
|
|
112
|
+
const pagesDirLine = hasPagesRouter
|
|
113
|
+
? next?.srcDir
|
|
114
|
+
? `path.join(process.cwd(), 'src', 'pages')`
|
|
115
|
+
: `path.join(process.cwd(), 'pages')`
|
|
116
|
+
: null;
|
|
117
|
+
|
|
118
|
+
const appDirLine = hasAppRouter
|
|
119
|
+
? next?.srcDir
|
|
120
|
+
? `path.join(process.cwd(), 'src', 'app')`
|
|
121
|
+
: `path.join(process.cwd(), 'app')`
|
|
122
|
+
: null;
|
|
123
|
+
|
|
124
|
+
// Build pagesDir option only if Pages Router exists
|
|
125
|
+
const pagesDirOption = pagesDirLine
|
|
126
|
+
? `\n pagesDir: ${pagesDirLine},`
|
|
127
|
+
: "";
|
|
128
|
+
|
|
129
|
+
// Build appDir option only if App Router exists (for future scanner support)
|
|
130
|
+
const appDirOption = appDirLine ? `\n appDir: ${appDirLine},` : "";
|
|
104
131
|
|
|
105
132
|
return `export async function register() {
|
|
106
133
|
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
107
|
-
|
|
108
|
-
const
|
|
134
|
+
// FIX: Use dynamic import to support both CJS and ESM projects
|
|
135
|
+
const { default: BotVersion } = await import('botversion-sdk');
|
|
136
|
+
const { default: path } = await import('path');
|
|
137
|
+
|
|
109
138
|
BotVersion.init({
|
|
110
|
-
apiKey: process.env.BOTVERSION_API_KEY
|
|
111
|
-
pagesDir: ${pagesDir},
|
|
139
|
+
apiKey: process.env.BOTVERSION_API_KEY,${pagesDirOption}${appDirOption}
|
|
112
140
|
});
|
|
113
141
|
}
|
|
114
142
|
}
|
|
115
143
|
`;
|
|
116
144
|
}
|
|
117
145
|
|
|
118
|
-
// ─── NEXT.JS CHAT ROUTE — PAGES ROUTER
|
|
146
|
+
// ─── NEXT.JS CHAT ROUTE — PAGES ROUTER ───────────────────────────────────────
|
|
119
147
|
|
|
120
148
|
function generateNextPagesChatRoute(info) {
|
|
121
|
-
const { auth
|
|
122
|
-
const isESM = moduleSystem === "esm";
|
|
149
|
+
const { auth } = info;
|
|
123
150
|
|
|
124
151
|
switch (auth.name) {
|
|
125
152
|
case "next-auth":
|
|
@@ -137,18 +164,10 @@ function generateNextAuthPagesRoute(info) {
|
|
|
137
164
|
const { nextAuthConfig, auth, next, generateTs } = info;
|
|
138
165
|
const isV5 = auth.version === "v5";
|
|
139
166
|
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
const chatFileDir = path.join(
|
|
143
|
-
next.baseDir, // handles src/ automatically
|
|
144
|
-
"pages",
|
|
145
|
-
"api",
|
|
146
|
-
"botversion",
|
|
147
|
-
);
|
|
167
|
+
// Compute correct relative import path for authOptions
|
|
168
|
+
const chatFileDir = path.join(next.baseDir, "pages", "api", "botversion");
|
|
148
169
|
|
|
149
|
-
// Determine the import path for authOptions
|
|
150
170
|
let authImportPath = "../auth/[...nextauth]";
|
|
151
|
-
|
|
152
171
|
if (nextAuthConfig) {
|
|
153
172
|
const rel = path
|
|
154
173
|
.relative(chatFileDir, nextAuthConfig.path)
|
|
@@ -168,8 +187,7 @@ export default BotVersion.nextHandler({
|
|
|
168
187
|
`;
|
|
169
188
|
}
|
|
170
189
|
|
|
171
|
-
|
|
172
|
-
if (info.generateTs) {
|
|
190
|
+
if (generateTs) {
|
|
173
191
|
return `import BotVersion from 'botversion-sdk';
|
|
174
192
|
import { getServerSession } from 'next-auth';
|
|
175
193
|
import { authOptions } from '${authImportPath}';
|
|
@@ -184,7 +202,6 @@ export default BotVersion.nextHandler({
|
|
|
184
202
|
`;
|
|
185
203
|
}
|
|
186
204
|
|
|
187
|
-
// Plain JS — works for all standard Next.js projects
|
|
188
205
|
return `import BotVersion from 'botversion-sdk';
|
|
189
206
|
import { getServerSession } from 'next-auth';
|
|
190
207
|
import { authOptions } from '${authImportPath}';
|
|
@@ -233,9 +250,7 @@ function generateAuthlessPagesRoute(info) {
|
|
|
233
250
|
|
|
234
251
|
const comment =
|
|
235
252
|
auth.name && !auth.supported
|
|
236
|
-
? `// TODO: We detected ${auth.name} but don't have automatic support yet.
|
|
237
|
-
// Add your own getSession below to pass user context to the agent.
|
|
238
|
-
// See: https://docs.botversion.com/auth\n`
|
|
253
|
+
? `// TODO: We detected ${auth.name} but don't have automatic support yet.\n// Add your own getSession below to pass user context to the agent.\n// See: https://docs.botversion.com/auth\n`
|
|
239
254
|
: "";
|
|
240
255
|
|
|
241
256
|
if (isTypeScript) {
|
|
@@ -269,7 +284,7 @@ export default BotVersion.nextHandler({
|
|
|
269
284
|
// ─── NEXT.JS CHAT ROUTE — APP ROUTER ─────────────────────────────────────────
|
|
270
285
|
|
|
271
286
|
function generateNextAppChatRoute(info) {
|
|
272
|
-
const { auth
|
|
287
|
+
const { auth } = info;
|
|
273
288
|
|
|
274
289
|
switch (auth.name) {
|
|
275
290
|
case "next-auth":
|
|
@@ -284,118 +299,293 @@ function generateNextAppChatRoute(info) {
|
|
|
284
299
|
}
|
|
285
300
|
|
|
286
301
|
function generateNextAuthAppRoute(info) {
|
|
287
|
-
const { auth, isTypeScript } = info;
|
|
302
|
+
const { auth, isTypeScript, next, nextAuthConfig } = info;
|
|
288
303
|
const isV5 = auth.version === "v5";
|
|
289
304
|
|
|
305
|
+
// FIX #5: Compute the correct relative import path instead of hardcoding @/lib/auth
|
|
306
|
+
const chatFileDir = path.join(
|
|
307
|
+
next.baseDir,
|
|
308
|
+
"app",
|
|
309
|
+
"api",
|
|
310
|
+
"botversion",
|
|
311
|
+
"chat",
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
let authImportPath = "@/lib/auth"; // fallback alias
|
|
315
|
+
if (nextAuthConfig) {
|
|
316
|
+
const rel = path
|
|
317
|
+
.relative(chatFileDir, nextAuthConfig.path)
|
|
318
|
+
.replace(/\\/g, "/")
|
|
319
|
+
.replace(/\.(js|ts)$/, "");
|
|
320
|
+
authImportPath = rel.startsWith(".") ? rel : "./" + rel;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const typeAnnotation = isTypeScript ? ": NextRequest" : "";
|
|
324
|
+
const nextRequestImport = isTypeScript
|
|
325
|
+
? `import { NextRequest, NextResponse } from 'next/server';\n`
|
|
326
|
+
: `import { NextResponse } from 'next/server';\n`;
|
|
327
|
+
|
|
290
328
|
if (isV5) {
|
|
291
329
|
return `import BotVersion from 'botversion-sdk';
|
|
292
|
-
import { auth } from '
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
330
|
+
import { auth } from '${authImportPath}';
|
|
331
|
+
${nextRequestImport}
|
|
332
|
+
// FIX #1: appRouterHandler is implemented here directly since App Router
|
|
333
|
+
// does not support the nextHandler() Pages pattern
|
|
334
|
+
export async function POST(req${typeAnnotation}) {
|
|
335
|
+
try {
|
|
336
|
+
const session = await auth();
|
|
337
|
+
const body = await req.json();
|
|
338
|
+
|
|
339
|
+
const result = await BotVersion.nextHandler({
|
|
340
|
+
apiKey: process.env.BOTVERSION_API_KEY,
|
|
341
|
+
getSession: async () => session,
|
|
342
|
+
})({ ...req, body }, { json: (d) => d, status: () => ({ json: (d) => d }) });
|
|
298
343
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
name: session?.user?.name,
|
|
305
|
-
},
|
|
306
|
-
});
|
|
344
|
+
return NextResponse.json(result);
|
|
345
|
+
} catch (err) {
|
|
346
|
+
console.error('[BotVersion] App Router handler error:', err);
|
|
347
|
+
return NextResponse.json({ error: 'Agent error' }, { status: 500 });
|
|
348
|
+
}
|
|
307
349
|
}
|
|
308
350
|
`;
|
|
309
351
|
}
|
|
310
352
|
|
|
311
353
|
return `import BotVersion from 'botversion-sdk';
|
|
312
354
|
import { getServerSession } from 'next-auth';
|
|
313
|
-
import { authOptions } from '
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
355
|
+
import { authOptions } from '${authImportPath}';
|
|
356
|
+
${nextRequestImport}
|
|
357
|
+
export async function POST(req${typeAnnotation}) {
|
|
358
|
+
try {
|
|
359
|
+
const session = await getServerSession(authOptions);
|
|
360
|
+
const body = await req.json();
|
|
319
361
|
|
|
320
|
-
|
|
321
|
-
body,
|
|
322
|
-
userContext: {
|
|
362
|
+
const userContext = {
|
|
323
363
|
userId: session?.user?.id,
|
|
324
364
|
email: session?.user?.email,
|
|
325
365
|
name: session?.user?.name,
|
|
326
|
-
}
|
|
327
|
-
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// Forward to BotVersion platform directly
|
|
369
|
+
const response = await fetch(\`\${process.env.BOTVERSION_PLATFORM_URL || 'http://localhost:3000'}/api/chatbot/widget-chat\`, {
|
|
370
|
+
method: 'POST',
|
|
371
|
+
headers: { 'Content-Type': 'application/json' },
|
|
372
|
+
body: JSON.stringify({
|
|
373
|
+
chatbotId: body.chatbotId,
|
|
374
|
+
publicKey: body.publicKey,
|
|
375
|
+
query: body.message,
|
|
376
|
+
previousChats: body.conversationHistory || [],
|
|
377
|
+
pageContext: body.pageContext || {},
|
|
378
|
+
userContext,
|
|
379
|
+
}),
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
const data = await response.json();
|
|
383
|
+
return NextResponse.json(data);
|
|
384
|
+
} catch (err) {
|
|
385
|
+
console.error('[BotVersion] App Router handler error:', err);
|
|
386
|
+
return NextResponse.json({ error: 'Agent error' }, { status: 500 });
|
|
387
|
+
}
|
|
328
388
|
}
|
|
329
389
|
`;
|
|
330
390
|
}
|
|
331
391
|
|
|
332
392
|
function generateClerkAppRoute(info) {
|
|
333
|
-
const {
|
|
393
|
+
const { isTypeScript } = info;
|
|
394
|
+
const typeAnnotation = isTypeScript ? ": NextRequest" : "";
|
|
395
|
+
const nextRequestImport = isTypeScript
|
|
396
|
+
? `import { NextRequest, NextResponse } from 'next/server';\n`
|
|
397
|
+
: `import { NextResponse } from 'next/server';\n`;
|
|
334
398
|
|
|
335
399
|
return `import BotVersion from 'botversion-sdk';
|
|
336
400
|
import { auth } from '@clerk/nextjs/server';
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
401
|
+
${nextRequestImport}
|
|
402
|
+
export async function POST(req${typeAnnotation}) {
|
|
403
|
+
try {
|
|
404
|
+
// FIX #6: auth() is async in Clerk v5+ — must be awaited
|
|
405
|
+
const { userId } = await auth();
|
|
406
|
+
const body = await req.json();
|
|
407
|
+
|
|
408
|
+
const response = await fetch(\`\${process.env.BOTVERSION_PLATFORM_URL || 'http://localhost:3000'}/api/chatbot/widget-chat\`, {
|
|
409
|
+
method: 'POST',
|
|
410
|
+
headers: { 'Content-Type': 'application/json' },
|
|
411
|
+
body: JSON.stringify({
|
|
412
|
+
chatbotId: body.chatbotId,
|
|
413
|
+
publicKey: body.publicKey,
|
|
414
|
+
query: body.message,
|
|
415
|
+
previousChats: body.conversationHistory || [],
|
|
416
|
+
pageContext: body.pageContext || {},
|
|
417
|
+
userContext: { userId },
|
|
418
|
+
}),
|
|
419
|
+
});
|
|
342
420
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
421
|
+
const data = await response.json();
|
|
422
|
+
return NextResponse.json(data);
|
|
423
|
+
} catch (err) {
|
|
424
|
+
console.error('[BotVersion] App Router handler error:', err);
|
|
425
|
+
return NextResponse.json({ error: 'Agent error' }, { status: 500 });
|
|
426
|
+
}
|
|
347
427
|
}
|
|
348
428
|
`;
|
|
349
429
|
}
|
|
350
430
|
|
|
351
431
|
function generateSupabaseAppRoute(info) {
|
|
352
432
|
const { isTypeScript } = info;
|
|
433
|
+
const typeAnnotation = isTypeScript ? ": NextRequest" : "";
|
|
434
|
+
const nextRequestImport = isTypeScript
|
|
435
|
+
? `import { NextRequest, NextResponse } from 'next/server';\n`
|
|
436
|
+
: `import { NextResponse } from 'next/server';\n`;
|
|
353
437
|
|
|
354
|
-
return `import
|
|
355
|
-
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
|
|
438
|
+
return `import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
|
|
356
439
|
import { cookies } from 'next/headers';
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
440
|
+
${nextRequestImport}
|
|
441
|
+
export async function POST(req${typeAnnotation}) {
|
|
442
|
+
try {
|
|
443
|
+
const supabase = createRouteHandlerClient({ cookies });
|
|
444
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
445
|
+
const body = await req.json();
|
|
446
|
+
|
|
447
|
+
const response = await fetch(\`\${process.env.BOTVERSION_PLATFORM_URL || 'http://localhost:3000'}/api/chatbot/widget-chat\`, {
|
|
448
|
+
method: 'POST',
|
|
449
|
+
headers: { 'Content-Type': 'application/json' },
|
|
450
|
+
body: JSON.stringify({
|
|
451
|
+
chatbotId: body.chatbotId,
|
|
452
|
+
publicKey: body.publicKey,
|
|
453
|
+
query: body.message,
|
|
454
|
+
previousChats: body.conversationHistory || [],
|
|
455
|
+
pageContext: body.pageContext || {},
|
|
456
|
+
userContext: {
|
|
457
|
+
userId: session?.user?.id,
|
|
458
|
+
email: session?.user?.email,
|
|
459
|
+
},
|
|
460
|
+
}),
|
|
461
|
+
});
|
|
363
462
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
});
|
|
463
|
+
const data = await response.json();
|
|
464
|
+
return NextResponse.json(data);
|
|
465
|
+
} catch (err) {
|
|
466
|
+
console.error('[BotVersion] App Router handler error:', err);
|
|
467
|
+
return NextResponse.json({ error: 'Agent error' }, { status: 500 });
|
|
468
|
+
}
|
|
371
469
|
}
|
|
372
470
|
`;
|
|
373
471
|
}
|
|
374
472
|
|
|
375
473
|
function generateAuthlessAppRoute(info) {
|
|
376
474
|
const { auth, isTypeScript } = info;
|
|
475
|
+
const typeAnnotation = isTypeScript ? ": NextRequest" : "";
|
|
476
|
+
const nextRequestImport = isTypeScript
|
|
477
|
+
? `import { NextRequest, NextResponse } from 'next/server';\n`
|
|
478
|
+
: `import { NextResponse } from 'next/server';\n`;
|
|
377
479
|
|
|
378
480
|
const comment =
|
|
379
481
|
auth.name && !auth.supported
|
|
380
|
-
? `// TODO: We detected ${auth.name} but don't have automatic support yet.
|
|
381
|
-
// Add your own user context below.
|
|
382
|
-
// See: https://docs.botversion.com/auth\n\n`
|
|
482
|
+
? `// TODO: We detected ${auth.name} but don't have automatic support yet.\n// Add your own user context below.\n// See: https://docs.botversion.com/auth\n\n`
|
|
383
483
|
: "";
|
|
384
484
|
|
|
385
|
-
return `${comment}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
485
|
+
return `${comment}${nextRequestImport}
|
|
486
|
+
export async function POST(req${typeAnnotation}) {
|
|
487
|
+
try {
|
|
488
|
+
const body = await req.json();
|
|
489
|
+
|
|
490
|
+
// No auth detected — agent works without user context
|
|
491
|
+
// Add userContext here if needed:
|
|
492
|
+
// const userContext = { userId: '...', email: '...' };
|
|
493
|
+
|
|
494
|
+
const response = await fetch(\`\${process.env.BOTVERSION_PLATFORM_URL || 'http://localhost:3000'}/api/chatbot/widget-chat\`, {
|
|
495
|
+
method: 'POST',
|
|
496
|
+
headers: { 'Content-Type': 'application/json' },
|
|
497
|
+
body: JSON.stringify({
|
|
498
|
+
chatbotId: body.chatbotId,
|
|
499
|
+
publicKey: body.publicKey,
|
|
500
|
+
query: body.message,
|
|
501
|
+
previousChats: body.conversationHistory || [],
|
|
502
|
+
pageContext: body.pageContext || {},
|
|
503
|
+
userContext: {},
|
|
504
|
+
}),
|
|
505
|
+
});
|
|
390
506
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
507
|
+
const data = await response.json();
|
|
508
|
+
return NextResponse.json(data);
|
|
509
|
+
} catch (err) {
|
|
510
|
+
console.error('[BotVersion] App Router handler error:', err);
|
|
511
|
+
return NextResponse.json({ error: 'Agent error' }, { status: 500 });
|
|
512
|
+
}
|
|
394
513
|
}
|
|
395
514
|
`;
|
|
396
515
|
}
|
|
397
516
|
|
|
398
|
-
// ───
|
|
517
|
+
// ─── NEXT.JS CONFIG PATCH ─────────────────────────────────────────────────────
|
|
518
|
+
|
|
519
|
+
function generateNextConfigPatch(cwd, nextVersion) {
|
|
520
|
+
const candidates = ["next.config.js", "next.config.mjs", "next.config.ts"];
|
|
521
|
+
|
|
522
|
+
let configPath = null;
|
|
523
|
+
let configContent = null;
|
|
524
|
+
|
|
525
|
+
for (const candidate of candidates) {
|
|
526
|
+
const fullPath = path.join(cwd, candidate);
|
|
527
|
+
if (fs.existsSync(fullPath)) {
|
|
528
|
+
configPath = fullPath;
|
|
529
|
+
configContent = fs.readFileSync(fullPath, "utf8");
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (!configPath) return null;
|
|
535
|
+
|
|
536
|
+
// Skip instrumentationHook for Next.js 14.1+ (enabled by default)
|
|
537
|
+
if (nextVersion && nextVersion.major >= 14) {
|
|
538
|
+
// Check minor version too
|
|
539
|
+
const rawVersion = nextVersion.raw || "";
|
|
540
|
+
const match = rawVersion.match(/(\d+)\.(\d+)/);
|
|
541
|
+
const minor = match ? parseInt(match[2], 10) : 0;
|
|
542
|
+
if (nextVersion.major > 14 || (nextVersion.major === 14 && minor >= 1)) {
|
|
543
|
+
return { path: configPath, alreadyPatched: true };
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (configContent.includes("instrumentationHook")) {
|
|
548
|
+
return { path: configPath, alreadyPatched: true };
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
let patched = configContent;
|
|
552
|
+
|
|
553
|
+
// Add to existing experimental block
|
|
554
|
+
if (configContent.includes("experimental")) {
|
|
555
|
+
patched = configContent.replace(
|
|
556
|
+
/experimental\s*:\s*\{/,
|
|
557
|
+
"experimental: {\n instrumentationHook: true,",
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
// FIX #7: Handle next.config.mjs style — export default { ... }
|
|
561
|
+
} else if (/export\s+default\s+\{/.test(configContent)) {
|
|
562
|
+
patched = configContent.replace(
|
|
563
|
+
/export\s+default\s+\{/,
|
|
564
|
+
"export default {\n experimental: {\n instrumentationHook: true,\n },",
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
// Handle const nextConfig = { ... } style (next.config.js)
|
|
568
|
+
} else if (/const\s+nextConfig\s*=\s*\{/.test(configContent)) {
|
|
569
|
+
patched = configContent.replace(
|
|
570
|
+
/const\s+nextConfig\s*=\s*\{/,
|
|
571
|
+
"const nextConfig = {\n experimental: {\n instrumentationHook: true,\n },",
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
// Handle module.exports = { ... } style
|
|
575
|
+
} else if (/module\.exports\s*=\s*\{/.test(configContent)) {
|
|
576
|
+
patched = configContent.replace(
|
|
577
|
+
/module\.exports\s*=\s*\{/,
|
|
578
|
+
"module.exports = {\n experimental: {\n instrumentationHook: true,\n },",
|
|
579
|
+
);
|
|
580
|
+
} else {
|
|
581
|
+
// Cannot safely patch — return null so caller prompts manual step
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return { path: configPath, content: patched, alreadyPatched: false };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// ─── MANUAL INSTRUCTIONS FOR UNSUPPORTED FRAMEWORKS ──────────────────────────
|
|
399
589
|
|
|
400
590
|
function generateManualInstructions(framework, apiKey) {
|
|
401
591
|
const instructions = {
|
|
@@ -431,47 +621,17 @@ Visit https://docs.botversion.com for manual setup instructions.
|
|
|
431
621
|
);
|
|
432
622
|
}
|
|
433
623
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (fs.existsSync(fullPath)) {
|
|
446
|
-
configPath = fullPath;
|
|
447
|
-
configContent = fs.readFileSync(fullPath, "utf8");
|
|
448
|
-
break;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (!configPath) return null;
|
|
453
|
-
|
|
454
|
-
// Already has instrumentationHook
|
|
455
|
-
if (configContent.includes("instrumentationHook")) {
|
|
456
|
-
return { path: configPath, alreadyPatched: true };
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// Add instrumentationHook: true to experimental block if exists
|
|
460
|
-
if (configContent.includes("experimental")) {
|
|
461
|
-
const patched = configContent.replace(
|
|
462
|
-
/experimental\s*:\s*\{/,
|
|
463
|
-
"experimental: {\n instrumentationHook: true,",
|
|
464
|
-
);
|
|
465
|
-
return { path: configPath, content: patched, alreadyPatched: false };
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// Add experimental block before the closing of config object
|
|
469
|
-
const patched = configContent.replace(
|
|
470
|
-
/const nextConfig\s*=\s*\{/,
|
|
471
|
-
"const nextConfig = {\n experimental: {\n instrumentationHook: true,\n },",
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
return { path: configPath, content: patched, alreadyPatched: false };
|
|
624
|
+
// ─── SCRIPT TAG GENERATION ────────────────────────────────────────────────────
|
|
625
|
+
|
|
626
|
+
function generateScriptTag(projectInfo) {
|
|
627
|
+
return `<script
|
|
628
|
+
id="botversion-loader"
|
|
629
|
+
src="${projectInfo.cdnUrl}"
|
|
630
|
+
data-api-url="${projectInfo.apiUrl}"
|
|
631
|
+
data-project-id="${projectInfo.projectId}"
|
|
632
|
+
data-public-key="${projectInfo.publicKey}"
|
|
633
|
+
data-proxy-url="/api/botversion/chat"
|
|
634
|
+
></script>`;
|
|
475
635
|
}
|
|
476
636
|
|
|
477
637
|
module.exports = {
|
|
@@ -481,4 +641,5 @@ module.exports = {
|
|
|
481
641
|
generateNextAppChatRoute,
|
|
482
642
|
generateManualInstructions,
|
|
483
643
|
generateNextConfigPatch,
|
|
644
|
+
generateScriptTag,
|
|
484
645
|
};
|