@l4yercak3/cli 1.2.16 → 1.2.19
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/.claude/settings.local.json +3 -1
- package/docs/CRM-PIPELINES-SEQUENCES-SPEC.md +429 -0
- package/docs/INTEGRATION_PATHS_ARCHITECTURE.md +1543 -0
- package/package.json +1 -1
- package/src/commands/login.js +26 -7
- package/src/commands/spread.js +251 -10
- package/src/detectors/database-detector.js +245 -0
- package/src/detectors/expo-detector.js +4 -4
- 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/env-generator.js +23 -8
- package/src/generators/expo-auth-generator.js +1009 -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/components-mobile/index.js +1440 -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 +1065 -0
- package/src/generators/quickstart/index.js +177 -0
- package/src/generators/quickstart/pages/index.js +1466 -0
- package/src/generators/quickstart/screens/index.js +1498 -0
- package/src/mcp/registry/domains/benefits.js +798 -0
- package/src/mcp/registry/index.js +2 -0
- package/tests/database-detector.test.js +221 -0
- package/tests/expo-detector.test.js +3 -4
- 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();
|
|
@@ -18,8 +18,12 @@ class EnvGenerator {
|
|
|
18
18
|
organizationId,
|
|
19
19
|
features,
|
|
20
20
|
oauthProviders,
|
|
21
|
+
isMobile,
|
|
21
22
|
} = options;
|
|
22
23
|
|
|
24
|
+
// Use EXPO_PUBLIC_ for Expo, NEXT_PUBLIC_ for Next.js
|
|
25
|
+
const publicPrefix = isMobile ? 'EXPO_PUBLIC_' : 'NEXT_PUBLIC_';
|
|
26
|
+
|
|
23
27
|
const envPath = path.join(projectPath, '.env.local');
|
|
24
28
|
const existingEnv = this.readExistingEnv(envPath);
|
|
25
29
|
|
|
@@ -31,9 +35,11 @@ class EnvGenerator {
|
|
|
31
35
|
L4YERCAK3_API_KEY: apiKey || existingEnv.L4YERCAK3_API_KEY || 'your_api_key_here',
|
|
32
36
|
L4YERCAK3_BACKEND_URL: backendUrl,
|
|
33
37
|
L4YERCAK3_ORGANIZATION_ID: organizationId,
|
|
34
|
-
NEXT_PUBLIC_L4YERCAK3_BACKEND_URL: backendUrl,
|
|
35
38
|
};
|
|
36
39
|
|
|
40
|
+
// Add public backend URL with appropriate prefix
|
|
41
|
+
envVars[`${publicPrefix}L4YERCAK3_BACKEND_URL`] = backendUrl;
|
|
42
|
+
|
|
37
43
|
// Add OAuth variables if OAuth is enabled
|
|
38
44
|
if (features.includes('oauth') && oauthProviders) {
|
|
39
45
|
if (oauthProviders.includes('google')) {
|
|
@@ -55,11 +61,15 @@ class EnvGenerator {
|
|
|
55
61
|
|
|
56
62
|
// Add Stripe variables if Stripe is enabled
|
|
57
63
|
if (features.includes('stripe')) {
|
|
58
|
-
|
|
64
|
+
const stripePublicKey = `${publicPrefix}STRIPE_PUBLISHABLE_KEY`;
|
|
65
|
+
envVars[stripePublicKey] = existingEnv[stripePublicKey] || existingEnv.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY || 'your_stripe_publishable_key_here';
|
|
59
66
|
envVars.STRIPE_SECRET_KEY = existingEnv.STRIPE_SECRET_KEY || 'your_stripe_secret_key_here';
|
|
60
67
|
envVars.STRIPE_WEBHOOK_SECRET = existingEnv.STRIPE_WEBHOOK_SECRET || 'your_stripe_webhook_secret_here';
|
|
61
68
|
}
|
|
62
69
|
|
|
70
|
+
// Store isMobile for formatting
|
|
71
|
+
envVars._isMobile = isMobile;
|
|
72
|
+
|
|
63
73
|
// Write env file
|
|
64
74
|
const envContent = this.formatEnvFile(envVars);
|
|
65
75
|
fs.writeFileSync(envPath, envContent, 'utf8');
|
|
@@ -103,19 +113,23 @@ class EnvGenerator {
|
|
|
103
113
|
* Format environment variables as .env file
|
|
104
114
|
*/
|
|
105
115
|
formatEnvFile(envVars) {
|
|
116
|
+
const isMobile = envVars._isMobile;
|
|
117
|
+
const publicPrefix = isMobile ? 'EXPO_PUBLIC_' : 'NEXT_PUBLIC_';
|
|
118
|
+
const platformName = isMobile ? 'Expo/React Native' : 'Next.js';
|
|
119
|
+
const deploymentPlatforms = isMobile ? 'EAS Build, Expo Go' : 'Vercel, Netlify, etc.';
|
|
120
|
+
|
|
106
121
|
let content = `# L4YERCAK3 Configuration
|
|
107
122
|
# Auto-generated by @l4yercak3/cli
|
|
108
123
|
# DO NOT commit this file to git - it contains sensitive credentials
|
|
109
124
|
#
|
|
110
|
-
# This file is for LOCAL DEVELOPMENT.
|
|
111
|
-
#
|
|
112
|
-
# - NEXTAUTH_URL should be your production domain
|
|
125
|
+
# This file is for LOCAL DEVELOPMENT (${platformName}).
|
|
126
|
+
# For production, set these variables in your deployment platform (${deploymentPlatforms}).
|
|
113
127
|
|
|
114
128
|
# Core API Configuration
|
|
115
129
|
L4YERCAK3_API_KEY=${envVars.L4YERCAK3_API_KEY}
|
|
116
130
|
L4YERCAK3_BACKEND_URL=${envVars.L4YERCAK3_BACKEND_URL}
|
|
117
131
|
L4YERCAK3_ORGANIZATION_ID=${envVars.L4YERCAK3_ORGANIZATION_ID}
|
|
118
|
-
|
|
132
|
+
${publicPrefix}L4YERCAK3_BACKEND_URL=${envVars[`${publicPrefix}L4YERCAK3_BACKEND_URL`]}
|
|
119
133
|
|
|
120
134
|
`;
|
|
121
135
|
|
|
@@ -160,9 +174,10 @@ NEXTAUTH_SECRET=${envVars.NEXTAUTH_SECRET}
|
|
|
160
174
|
}
|
|
161
175
|
|
|
162
176
|
// Add Stripe section if present
|
|
163
|
-
|
|
177
|
+
const stripePublicKey = envVars[`${publicPrefix}STRIPE_PUBLISHABLE_KEY`];
|
|
178
|
+
if (stripePublicKey) {
|
|
164
179
|
content += `# Stripe Configuration
|
|
165
|
-
|
|
180
|
+
${publicPrefix}STRIPE_PUBLISHABLE_KEY=${stripePublicKey}
|
|
166
181
|
STRIPE_SECRET_KEY=${envVars.STRIPE_SECRET_KEY}
|
|
167
182
|
STRIPE_WEBHOOK_SECRET=${envVars.STRIPE_WEBHOOK_SECRET}
|
|
168
183
|
|