@l4yercak3/cli 1.2.15 → 1.2.18
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/docs/INTEGRATION_PATHS_ARCHITECTURE.md +1543 -0
- package/package.json +1 -1
- package/src/commands/spread.js +101 -6
- package/src/detectors/database-detector.js +245 -0
- package/src/detectors/index.js +17 -4
- package/src/generators/api-only/client.js +683 -0
- package/src/generators/api-only/index.js +96 -0
- package/src/generators/api-only/types.js +618 -0
- package/src/generators/api-only/webhooks.js +377 -0
- package/src/generators/index.js +88 -2
- package/src/generators/mcp-guide-generator.js +256 -0
- package/src/generators/quickstart/components/index.js +1699 -0
- package/src/generators/quickstart/database/convex.js +1257 -0
- package/src/generators/quickstart/database/index.js +34 -0
- package/src/generators/quickstart/database/supabase.js +1132 -0
- package/src/generators/quickstart/hooks/index.js +1047 -0
- package/src/generators/quickstart/index.js +151 -0
- package/src/generators/quickstart/pages/index.js +1466 -0
- package/src/mcp/registry/domains/applications.js +4 -4
- package/src/mcp/registry/domains/benefits.js +798 -0
- package/src/mcp/registry/domains/crm.js +11 -11
- package/src/mcp/registry/domains/events.js +12 -12
- package/src/mcp/registry/domains/forms.js +12 -12
- package/src/mcp/registry/index.js +2 -0
- package/tests/database-detector.test.js +221 -0
- package/tests/generators-index.test.js +215 -3
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhooks Generator
|
|
3
|
+
* Generates webhook handling utilities for the L4YERCAK3 API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { ensureDir, writeFileWithBackup, checkFileOverwrite } = require('../../utils/file-utils');
|
|
9
|
+
|
|
10
|
+
class WebhooksGenerator {
|
|
11
|
+
/**
|
|
12
|
+
* Generate the webhooks utility file
|
|
13
|
+
* @param {Object} options - Generation options
|
|
14
|
+
* @returns {Promise<string|null>} - Path to generated file or null if skipped
|
|
15
|
+
*/
|
|
16
|
+
async generate(options) {
|
|
17
|
+
const { projectPath, isTypeScript } = options;
|
|
18
|
+
|
|
19
|
+
// Determine output directory
|
|
20
|
+
let outputDir;
|
|
21
|
+
if (fs.existsSync(path.join(projectPath, 'src'))) {
|
|
22
|
+
outputDir = path.join(projectPath, 'src', 'lib', 'l4yercak3');
|
|
23
|
+
} else {
|
|
24
|
+
outputDir = path.join(projectPath, 'lib', 'l4yercak3');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
ensureDir(outputDir);
|
|
28
|
+
|
|
29
|
+
const extension = isTypeScript ? 'ts' : 'js';
|
|
30
|
+
const outputPath = path.join(outputDir, `webhooks.${extension}`);
|
|
31
|
+
|
|
32
|
+
const action = await checkFileOverwrite(outputPath);
|
|
33
|
+
if (action === 'skip') {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const content = isTypeScript
|
|
38
|
+
? this.generateTypeScriptWebhooks()
|
|
39
|
+
: this.generateJavaScriptWebhooks();
|
|
40
|
+
|
|
41
|
+
return writeFileWithBackup(outputPath, content, action);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
generateTypeScriptWebhooks() {
|
|
45
|
+
return `/**
|
|
46
|
+
* L4YERCAK3 Webhook Utilities
|
|
47
|
+
* Auto-generated by @l4yercak3/cli
|
|
48
|
+
*
|
|
49
|
+
* Utilities for handling webhook events from L4YERCAK3.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
import { createHmac, timingSafeEqual } from 'crypto';
|
|
53
|
+
|
|
54
|
+
export interface WebhookEvent<T = Record<string, unknown>> {
|
|
55
|
+
id: string;
|
|
56
|
+
type: WebhookEventType;
|
|
57
|
+
timestamp: string;
|
|
58
|
+
data: T;
|
|
59
|
+
organizationId: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type WebhookEventType =
|
|
63
|
+
| 'contact.created'
|
|
64
|
+
| 'contact.updated'
|
|
65
|
+
| 'contact.deleted'
|
|
66
|
+
| 'organization.created'
|
|
67
|
+
| 'organization.updated'
|
|
68
|
+
| 'event.created'
|
|
69
|
+
| 'event.updated'
|
|
70
|
+
| 'event.published'
|
|
71
|
+
| 'event.cancelled'
|
|
72
|
+
| 'attendee.registered'
|
|
73
|
+
| 'attendee.checked_in'
|
|
74
|
+
| 'attendee.cancelled'
|
|
75
|
+
| 'form.submitted'
|
|
76
|
+
| 'order.created'
|
|
77
|
+
| 'order.paid'
|
|
78
|
+
| 'order.refunded'
|
|
79
|
+
| 'invoice.created'
|
|
80
|
+
| 'invoice.sent'
|
|
81
|
+
| 'invoice.paid'
|
|
82
|
+
| 'invoice.overdue'
|
|
83
|
+
| 'benefit_claim.submitted'
|
|
84
|
+
| 'benefit_claim.approved'
|
|
85
|
+
| 'benefit_claim.rejected'
|
|
86
|
+
| 'benefit_claim.paid'
|
|
87
|
+
| 'commission.calculated'
|
|
88
|
+
| 'commission.paid'
|
|
89
|
+
| 'certificate.issued';
|
|
90
|
+
|
|
91
|
+
export interface VerifyOptions {
|
|
92
|
+
/** The raw request body as a string or Buffer */
|
|
93
|
+
payload: string | Buffer;
|
|
94
|
+
/** The signature from the X-L4yercak3-Signature header */
|
|
95
|
+
signature: string;
|
|
96
|
+
/** Your webhook secret from the L4YERCAK3 dashboard */
|
|
97
|
+
secret: string;
|
|
98
|
+
/** Tolerance in seconds for timestamp validation (default: 300 = 5 minutes) */
|
|
99
|
+
tolerance?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class WebhookVerificationError extends Error {
|
|
103
|
+
constructor(message: string) {
|
|
104
|
+
super(message);
|
|
105
|
+
this.name = 'WebhookVerificationError';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Verify a webhook signature and parse the event
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* \`\`\`ts
|
|
114
|
+
* // In your Next.js API route
|
|
115
|
+
* import { verifyWebhookSignature, WebhookEvent } from '@/lib/l4yercak3';
|
|
116
|
+
*
|
|
117
|
+
* export async function POST(req: Request) {
|
|
118
|
+
* const payload = await req.text();
|
|
119
|
+
* const signature = req.headers.get('x-l4yercak3-signature') || '';
|
|
120
|
+
*
|
|
121
|
+
* try {
|
|
122
|
+
* const event = verifyWebhookSignature({
|
|
123
|
+
* payload,
|
|
124
|
+
* signature,
|
|
125
|
+
* secret: process.env.L4YERCAK3_WEBHOOK_SECRET!,
|
|
126
|
+
* });
|
|
127
|
+
*
|
|
128
|
+
* switch (event.type) {
|
|
129
|
+
* case 'contact.created':
|
|
130
|
+
* // Handle new contact
|
|
131
|
+
* break;
|
|
132
|
+
* case 'order.paid':
|
|
133
|
+
* // Handle paid order
|
|
134
|
+
* break;
|
|
135
|
+
* }
|
|
136
|
+
*
|
|
137
|
+
* return new Response('OK', { status: 200 });
|
|
138
|
+
* } catch (error) {
|
|
139
|
+
* console.error('Webhook error:', error);
|
|
140
|
+
* return new Response('Invalid signature', { status: 400 });
|
|
141
|
+
* }
|
|
142
|
+
* }
|
|
143
|
+
* \`\`\`
|
|
144
|
+
*/
|
|
145
|
+
export function verifyWebhookSignature<T = Record<string, unknown>>(
|
|
146
|
+
options: VerifyOptions
|
|
147
|
+
): WebhookEvent<T> {
|
|
148
|
+
const { payload, signature, secret, tolerance = 300 } = options;
|
|
149
|
+
|
|
150
|
+
if (!signature) {
|
|
151
|
+
throw new WebhookVerificationError('Missing signature header');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Parse the signature header (format: t=timestamp,v1=signature)
|
|
155
|
+
const parts = signature.split(',').reduce((acc, part) => {
|
|
156
|
+
const [key, value] = part.split('=');
|
|
157
|
+
acc[key] = value;
|
|
158
|
+
return acc;
|
|
159
|
+
}, {} as Record<string, string>);
|
|
160
|
+
|
|
161
|
+
const timestamp = parts['t'];
|
|
162
|
+
const signatureHash = parts['v1'];
|
|
163
|
+
|
|
164
|
+
if (!timestamp || !signatureHash) {
|
|
165
|
+
throw new WebhookVerificationError('Invalid signature format');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Check timestamp tolerance
|
|
169
|
+
const timestampNum = parseInt(timestamp, 10);
|
|
170
|
+
const now = Math.floor(Date.now() / 1000);
|
|
171
|
+
if (Math.abs(now - timestampNum) > tolerance) {
|
|
172
|
+
throw new WebhookVerificationError('Timestamp outside tolerance window');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Compute expected signature
|
|
176
|
+
const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');
|
|
177
|
+
const signedPayload = \`\${timestamp}.\${payloadStr}\`;
|
|
178
|
+
const expectedSignature = createHmac('sha256', secret)
|
|
179
|
+
.update(signedPayload)
|
|
180
|
+
.digest('hex');
|
|
181
|
+
|
|
182
|
+
// Constant-time comparison
|
|
183
|
+
const expectedBuffer = Buffer.from(expectedSignature);
|
|
184
|
+
const receivedBuffer = Buffer.from(signatureHash);
|
|
185
|
+
|
|
186
|
+
if (expectedBuffer.length !== receivedBuffer.length) {
|
|
187
|
+
throw new WebhookVerificationError('Invalid signature');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!timingSafeEqual(expectedBuffer, receivedBuffer)) {
|
|
191
|
+
throw new WebhookVerificationError('Invalid signature');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Parse and return the event
|
|
195
|
+
try {
|
|
196
|
+
return JSON.parse(payloadStr) as WebhookEvent<T>;
|
|
197
|
+
} catch {
|
|
198
|
+
throw new WebhookVerificationError('Invalid JSON payload');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Type guard helpers for specific webhook events
|
|
204
|
+
*/
|
|
205
|
+
export function isContactEvent(event: WebhookEvent): event is WebhookEvent<{ contact: unknown }> {
|
|
206
|
+
return event.type.startsWith('contact.');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function isEventEvent(event: WebhookEvent): event is WebhookEvent<{ event: unknown }> {
|
|
210
|
+
return event.type.startsWith('event.');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function isOrderEvent(event: WebhookEvent): event is WebhookEvent<{ order: unknown }> {
|
|
214
|
+
return event.type.startsWith('order.');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function isInvoiceEvent(event: WebhookEvent): event is WebhookEvent<{ invoice: unknown }> {
|
|
218
|
+
return event.type.startsWith('invoice.');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function isBenefitClaimEvent(event: WebhookEvent): event is WebhookEvent<{ claim: unknown }> {
|
|
222
|
+
return event.type.startsWith('benefit_claim.');
|
|
223
|
+
}
|
|
224
|
+
`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
generateJavaScriptWebhooks() {
|
|
228
|
+
return `/**
|
|
229
|
+
* L4YERCAK3 Webhook Utilities
|
|
230
|
+
* Auto-generated by @l4yercak3/cli
|
|
231
|
+
*
|
|
232
|
+
* Utilities for handling webhook events from L4YERCAK3.
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
const { createHmac, timingSafeEqual } = require('crypto');
|
|
236
|
+
|
|
237
|
+
class WebhookVerificationError extends Error {
|
|
238
|
+
constructor(message) {
|
|
239
|
+
super(message);
|
|
240
|
+
this.name = 'WebhookVerificationError';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Verify a webhook signature and parse the event
|
|
246
|
+
*
|
|
247
|
+
* @param {Object} options
|
|
248
|
+
* @param {string|Buffer} options.payload - The raw request body
|
|
249
|
+
* @param {string} options.signature - The signature from X-L4yercak3-Signature header
|
|
250
|
+
* @param {string} options.secret - Your webhook secret
|
|
251
|
+
* @param {number} [options.tolerance=300] - Timestamp tolerance in seconds
|
|
252
|
+
* @returns {Object} The verified webhook event
|
|
253
|
+
* @throws {WebhookVerificationError} If verification fails
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* // In your Next.js API route
|
|
257
|
+
* const { verifyWebhookSignature } = require('@/lib/l4yercak3');
|
|
258
|
+
*
|
|
259
|
+
* export default async function handler(req, res) {
|
|
260
|
+
* const payload = req.body;
|
|
261
|
+
* const signature = req.headers['x-l4yercak3-signature'];
|
|
262
|
+
*
|
|
263
|
+
* try {
|
|
264
|
+
* const event = verifyWebhookSignature({
|
|
265
|
+
* payload: JSON.stringify(payload),
|
|
266
|
+
* signature,
|
|
267
|
+
* secret: process.env.L4YERCAK3_WEBHOOK_SECRET,
|
|
268
|
+
* });
|
|
269
|
+
*
|
|
270
|
+
* switch (event.type) {
|
|
271
|
+
* case 'contact.created':
|
|
272
|
+
* // Handle new contact
|
|
273
|
+
* break;
|
|
274
|
+
* case 'order.paid':
|
|
275
|
+
* // Handle paid order
|
|
276
|
+
* break;
|
|
277
|
+
* }
|
|
278
|
+
*
|
|
279
|
+
* res.status(200).json({ received: true });
|
|
280
|
+
* } catch (error) {
|
|
281
|
+
* console.error('Webhook error:', error);
|
|
282
|
+
* res.status(400).json({ error: 'Invalid signature' });
|
|
283
|
+
* }
|
|
284
|
+
* }
|
|
285
|
+
*/
|
|
286
|
+
function verifyWebhookSignature(options) {
|
|
287
|
+
const { payload, signature, secret, tolerance = 300 } = options;
|
|
288
|
+
|
|
289
|
+
if (!signature) {
|
|
290
|
+
throw new WebhookVerificationError('Missing signature header');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Parse the signature header (format: t=timestamp,v1=signature)
|
|
294
|
+
const parts = signature.split(',').reduce((acc, part) => {
|
|
295
|
+
const [key, value] = part.split('=');
|
|
296
|
+
acc[key] = value;
|
|
297
|
+
return acc;
|
|
298
|
+
}, {});
|
|
299
|
+
|
|
300
|
+
const timestamp = parts['t'];
|
|
301
|
+
const signatureHash = parts['v1'];
|
|
302
|
+
|
|
303
|
+
if (!timestamp || !signatureHash) {
|
|
304
|
+
throw new WebhookVerificationError('Invalid signature format');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Check timestamp tolerance
|
|
308
|
+
const timestampNum = parseInt(timestamp, 10);
|
|
309
|
+
const now = Math.floor(Date.now() / 1000);
|
|
310
|
+
if (Math.abs(now - timestampNum) > tolerance) {
|
|
311
|
+
throw new WebhookVerificationError('Timestamp outside tolerance window');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Compute expected signature
|
|
315
|
+
const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');
|
|
316
|
+
const signedPayload = \`\${timestamp}.\${payloadStr}\`;
|
|
317
|
+
const expectedSignature = createHmac('sha256', secret)
|
|
318
|
+
.update(signedPayload)
|
|
319
|
+
.digest('hex');
|
|
320
|
+
|
|
321
|
+
// Constant-time comparison
|
|
322
|
+
const expectedBuffer = Buffer.from(expectedSignature);
|
|
323
|
+
const receivedBuffer = Buffer.from(signatureHash);
|
|
324
|
+
|
|
325
|
+
if (expectedBuffer.length !== receivedBuffer.length) {
|
|
326
|
+
throw new WebhookVerificationError('Invalid signature');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (!timingSafeEqual(expectedBuffer, receivedBuffer)) {
|
|
330
|
+
throw new WebhookVerificationError('Invalid signature');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Parse and return the event
|
|
334
|
+
try {
|
|
335
|
+
return JSON.parse(payloadStr);
|
|
336
|
+
} catch {
|
|
337
|
+
throw new WebhookVerificationError('Invalid JSON payload');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Type guard helpers for specific webhook events
|
|
343
|
+
*/
|
|
344
|
+
function isContactEvent(event) {
|
|
345
|
+
return event.type && event.type.startsWith('contact.');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function isEventEvent(event) {
|
|
349
|
+
return event.type && event.type.startsWith('event.');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function isOrderEvent(event) {
|
|
353
|
+
return event.type && event.type.startsWith('order.');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function isInvoiceEvent(event) {
|
|
357
|
+
return event.type && event.type.startsWith('invoice.');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function isBenefitClaimEvent(event) {
|
|
361
|
+
return event.type && event.type.startsWith('benefit_claim.');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
module.exports = {
|
|
365
|
+
verifyWebhookSignature,
|
|
366
|
+
WebhookVerificationError,
|
|
367
|
+
isContactEvent,
|
|
368
|
+
isEventEvent,
|
|
369
|
+
isOrderEvent,
|
|
370
|
+
isInvoiceEvent,
|
|
371
|
+
isBenefitClaimEvent,
|
|
372
|
+
};
|
|
373
|
+
`;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
module.exports = new WebhooksGenerator();
|
package/src/generators/index.js
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* Supports multiple frameworks:
|
|
6
6
|
* - nextjs: Next.js (App Router and Pages Router)
|
|
7
7
|
* - expo: Expo/React Native
|
|
8
|
+
*
|
|
9
|
+
* Supports multiple integration paths:
|
|
10
|
+
* - quickstart: Full-stack with UI components & database
|
|
11
|
+
* - api-only: Just the typed API client
|
|
12
|
+
* - mcp-assisted: AI-powered custom generation
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
const apiClientGenerator = require('./api-client-generator');
|
|
@@ -12,6 +17,9 @@ const envGenerator = require('./env-generator');
|
|
|
12
17
|
const nextauthGenerator = require('./nextauth-generator');
|
|
13
18
|
const oauthGuideGenerator = require('./oauth-guide-generator');
|
|
14
19
|
const gitignoreGenerator = require('./gitignore-generator');
|
|
20
|
+
const apiOnlyGenerator = require('./api-only');
|
|
21
|
+
const mcpGuideGenerator = require('./mcp-guide-generator');
|
|
22
|
+
const quickstartGenerator = require('./quickstart');
|
|
15
23
|
|
|
16
24
|
class FileGenerator {
|
|
17
25
|
/**
|
|
@@ -32,6 +40,86 @@ class FileGenerator {
|
|
|
32
40
|
* Generate all files based on configuration
|
|
33
41
|
*/
|
|
34
42
|
async generate(options) {
|
|
43
|
+
const integrationPath = options.integrationPath || 'api-only';
|
|
44
|
+
|
|
45
|
+
// Route to the appropriate generator based on integration path
|
|
46
|
+
switch (integrationPath) {
|
|
47
|
+
case 'api-only':
|
|
48
|
+
return this.generateApiOnly(options);
|
|
49
|
+
case 'mcp-assisted':
|
|
50
|
+
return this.generateMcpAssisted(options);
|
|
51
|
+
case 'quickstart':
|
|
52
|
+
return this.generateQuickStart(options);
|
|
53
|
+
default:
|
|
54
|
+
return this.generateLegacy(options);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* API-Only path: Generate typed API client and types
|
|
60
|
+
*/
|
|
61
|
+
async generateApiOnly(options) {
|
|
62
|
+
const results = {
|
|
63
|
+
apiClient: null,
|
|
64
|
+
types: null,
|
|
65
|
+
webhooks: null,
|
|
66
|
+
index: null,
|
|
67
|
+
envFile: null,
|
|
68
|
+
gitignore: null,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Generate the full typed API client package
|
|
72
|
+
const apiOnlyResults = await apiOnlyGenerator.generate(options);
|
|
73
|
+
results.apiClient = apiOnlyResults.client;
|
|
74
|
+
results.types = apiOnlyResults.types;
|
|
75
|
+
results.webhooks = apiOnlyResults.webhooks;
|
|
76
|
+
results.index = apiOnlyResults.index;
|
|
77
|
+
|
|
78
|
+
// Generate environment file
|
|
79
|
+
results.envFile = envGenerator.generate(options);
|
|
80
|
+
|
|
81
|
+
// Update .gitignore
|
|
82
|
+
results.gitignore = gitignoreGenerator.generate(options);
|
|
83
|
+
|
|
84
|
+
return results;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* MCP-Assisted path: Generate MCP config and guide
|
|
89
|
+
*/
|
|
90
|
+
async generateMcpAssisted(options) {
|
|
91
|
+
const results = {
|
|
92
|
+
mcpConfig: null,
|
|
93
|
+
mcpGuide: null,
|
|
94
|
+
envFile: null,
|
|
95
|
+
gitignore: null,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Generate MCP configuration and guide
|
|
99
|
+
const mcpResults = await mcpGuideGenerator.generate(options);
|
|
100
|
+
results.mcpConfig = mcpResults.config;
|
|
101
|
+
results.mcpGuide = mcpResults.guide;
|
|
102
|
+
|
|
103
|
+
// Generate environment file
|
|
104
|
+
results.envFile = envGenerator.generate(options);
|
|
105
|
+
|
|
106
|
+
// Update .gitignore
|
|
107
|
+
results.gitignore = gitignoreGenerator.generate(options);
|
|
108
|
+
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Quick Start path: Full-stack generation with database, hooks, and components
|
|
114
|
+
*/
|
|
115
|
+
async generateQuickStart(options) {
|
|
116
|
+
return quickstartGenerator.generate(options);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Legacy generation (backward compatibility)
|
|
121
|
+
*/
|
|
122
|
+
async generateLegacy(options) {
|
|
35
123
|
const results = {
|
|
36
124
|
apiClient: null,
|
|
37
125
|
envFile: null,
|
|
@@ -57,12 +145,10 @@ class FileGenerator {
|
|
|
57
145
|
if (isNextJs) {
|
|
58
146
|
results.nextauth = await nextauthGenerator.generate(options);
|
|
59
147
|
}
|
|
60
|
-
// For mobile, OAuth is handled differently (expo-auth-session, etc.)
|
|
61
148
|
}
|
|
62
149
|
|
|
63
150
|
// Generate OAuth guide if OAuth is enabled
|
|
64
151
|
if (options.features && options.features.includes('oauth') && options.oauthProviders) {
|
|
65
|
-
// Pass framework info so guide can be customized
|
|
66
152
|
results.oauthGuide = oauthGuideGenerator.generate({
|
|
67
153
|
...options,
|
|
68
154
|
isMobile,
|