better-auth-studio 1.0.59-beta.9 → 1.0.60-beta.1
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/README.md +2 -2
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +192 -3
- package/dist/routes.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/main-BUaRlQuu.js +1140 -0
- package/public/assets/{main-Bbsm29F_.css → main-qMHo0OfS.css} +1 -1
- package/public/index.html +2 -2
- package/public/assets/main-fX0tKK6u.js +0 -1104
package/README.md
CHANGED
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAeA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAS9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA+D9C,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAeA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAS9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA+D9C,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAqLhG;AAeD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAuzLR"}
|
package/dist/routes.js
CHANGED
|
@@ -5122,14 +5122,11 @@ export const authClient = createAuthClient({
|
|
|
5122
5122
|
}
|
|
5123
5123
|
const envPath = join(process.cwd(), '.env');
|
|
5124
5124
|
const envLocalPath = join(process.cwd(), '.env.local');
|
|
5125
|
-
// Try .env.local first, then .env
|
|
5126
5125
|
const targetPath = existsSync(envLocalPath) ? envLocalPath : envPath;
|
|
5127
5126
|
const envContent = existsSync(targetPath) ? readFileSync(targetPath, 'utf-8') : '';
|
|
5128
|
-
// Generate environment variable names
|
|
5129
5127
|
const providerUpper = provider.toUpperCase();
|
|
5130
5128
|
const clientIdKey = `${providerUpper}_CLIENT_ID`;
|
|
5131
5129
|
const clientSecretKey = `${providerUpper}_CLIENT_SECRET`;
|
|
5132
|
-
// Parse existing .env file
|
|
5133
5130
|
const envLines = envContent.split('\n');
|
|
5134
5131
|
const existingCredentials = {};
|
|
5135
5132
|
envLines.forEach((line) => {
|
|
@@ -5291,6 +5288,198 @@ export const authClient = createAuthClient({
|
|
|
5291
5288
|
});
|
|
5292
5289
|
}
|
|
5293
5290
|
});
|
|
5291
|
+
router.post('/api/tools/apply-email-template', async (req, res) => {
|
|
5292
|
+
try {
|
|
5293
|
+
const { subject, html, templateId } = req.body || {};
|
|
5294
|
+
if (!subject || !html || !templateId) {
|
|
5295
|
+
return res
|
|
5296
|
+
.status(400)
|
|
5297
|
+
.json({ success: false, message: 'templateId, subject and html are required' });
|
|
5298
|
+
}
|
|
5299
|
+
const authPathFromConfig = configPath ? join(process.cwd(), configPath) : null;
|
|
5300
|
+
const authPath = authPathFromConfig || (await findAuthConfigPath());
|
|
5301
|
+
if (!authPath || !existsSync(authPath)) {
|
|
5302
|
+
return res.status(404).json({ success: false, message: 'auth.ts not found' });
|
|
5303
|
+
}
|
|
5304
|
+
let fileContent = readFileSync(authPath, 'utf-8');
|
|
5305
|
+
// Escape backticks and ${ for template literals
|
|
5306
|
+
// First escape backslashes, then escape backticks and ${ to avoid double-escaping
|
|
5307
|
+
const escapedSubject = subject.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\${/g, '\\${');
|
|
5308
|
+
const escapedHtml = html.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\${/g, '\\${');
|
|
5309
|
+
if (!fileContent.includes("from 'resend'")) {
|
|
5310
|
+
fileContent = `import { Resend } from 'resend';\n` + fileContent;
|
|
5311
|
+
}
|
|
5312
|
+
if (!fileContent.includes('const resend = new Resend(')) {
|
|
5313
|
+
const importBlockEnd = fileContent.indexOf('\n', fileContent.lastIndexOf('import'));
|
|
5314
|
+
if (importBlockEnd > -1) {
|
|
5315
|
+
fileContent =
|
|
5316
|
+
fileContent.slice(0, importBlockEnd + 1) +
|
|
5317
|
+
`const resend = new Resend(process.env.RESEND_API_KEY || '');\n` +
|
|
5318
|
+
fileContent.slice(importBlockEnd + 1);
|
|
5319
|
+
}
|
|
5320
|
+
else {
|
|
5321
|
+
fileContent =
|
|
5322
|
+
`const resend = new Resend(process.env.RESEND_API_KEY || '');\n` + fileContent;
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
const handlers = {
|
|
5326
|
+
'password-reset': {
|
|
5327
|
+
regex: /sendResetPassword\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
|
|
5328
|
+
sectionRegex: /emailAndPassword\s*:\s*\{\s*/,
|
|
5329
|
+
fn: `sendResetPassword: async ({ user, url, token }, request) => {
|
|
5330
|
+
const subject = \`${escapedSubject}\`
|
|
5331
|
+
.replace(/{{user.name}}/g, user?.name || '')
|
|
5332
|
+
.replace(/{{user.email}}/g, user?.email || '');
|
|
5333
|
+
|
|
5334
|
+
const html = \`${escapedHtml}\`
|
|
5335
|
+
.replace(/{{user.name}}/g, user?.name || '')
|
|
5336
|
+
.replace(/{{user.email}}/g, user?.email || '')
|
|
5337
|
+
.replace(/{{url}}/g, url || '')
|
|
5338
|
+
.replace(/{{token}}/g, token || '');
|
|
5339
|
+
|
|
5340
|
+
void sendEmail({
|
|
5341
|
+
to: user.email,
|
|
5342
|
+
subject,
|
|
5343
|
+
html,
|
|
5344
|
+
});
|
|
5345
|
+
}`,
|
|
5346
|
+
},
|
|
5347
|
+
'email-verification': {
|
|
5348
|
+
regex: /sendVerificationEmail\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
|
|
5349
|
+
sectionRegex: /emailVerification\s*:\s*\{\s*/,
|
|
5350
|
+
fn: `sendVerificationEmail: async ({ user, url, token }, request) => {
|
|
5351
|
+
const subject = \`${escapedSubject}\`
|
|
5352
|
+
.replace(/{{user.name}}/g, user?.name || '')
|
|
5353
|
+
.replace(/{{user.email}}/g, user?.email || '');
|
|
5354
|
+
|
|
5355
|
+
const html = \`${escapedHtml}\`
|
|
5356
|
+
.replace(/{{user.name}}/g, user?.name || '')
|
|
5357
|
+
.replace(/{{user.email}}/g, user?.email || '')
|
|
5358
|
+
.replace(/{{url}}/g, url || '')
|
|
5359
|
+
.replace(/{{token}}/g, token || '');
|
|
5360
|
+
|
|
5361
|
+
void sendEmail({
|
|
5362
|
+
to: user.email,
|
|
5363
|
+
subject,
|
|
5364
|
+
html,
|
|
5365
|
+
});
|
|
5366
|
+
}`,
|
|
5367
|
+
},
|
|
5368
|
+
'magic-link': {
|
|
5369
|
+
regex: /sendMagicLink\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
|
|
5370
|
+
sectionRegex: /magicLink\s*:\s*\{\s*/,
|
|
5371
|
+
fn: `sendMagicLink: async ({ email, token, url }, ctx) => {
|
|
5372
|
+
const subject = \`${escapedSubject}\`
|
|
5373
|
+
.replace(/{{user.email}}/g, email || '');
|
|
5374
|
+
|
|
5375
|
+
const html = \`${escapedHtml}\`
|
|
5376
|
+
.replace(/{{user.email}}/g, email || '')
|
|
5377
|
+
.replace(/{{url}}/g, url || '')
|
|
5378
|
+
.replace(/{{token}}/g, token || '');
|
|
5379
|
+
|
|
5380
|
+
void sendEmail({
|
|
5381
|
+
to: email,
|
|
5382
|
+
subject,
|
|
5383
|
+
html,
|
|
5384
|
+
});
|
|
5385
|
+
}`,
|
|
5386
|
+
},
|
|
5387
|
+
'org-invitation': {
|
|
5388
|
+
regex: /sendInvitationEmail\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
|
|
5389
|
+
fn: `sendInvitationEmail: async ({ data, request }: {
|
|
5390
|
+
data: {
|
|
5391
|
+
invitation: {
|
|
5392
|
+
id: string;
|
|
5393
|
+
organizationId: string;
|
|
5394
|
+
email: string;
|
|
5395
|
+
role: string;
|
|
5396
|
+
status: "pending" | "accepted" | "rejected" | "canceled";
|
|
5397
|
+
inviterId: string;
|
|
5398
|
+
expiresAt: Date;
|
|
5399
|
+
createdAt: Date;
|
|
5400
|
+
teamId?: string | null | undefined;
|
|
5401
|
+
};
|
|
5402
|
+
organization: { name?: string; slug?: string };
|
|
5403
|
+
inviter: { user: { name?: string; email?: string } };
|
|
5404
|
+
};
|
|
5405
|
+
request?: Request;
|
|
5406
|
+
}) => {
|
|
5407
|
+
const { invitation, organization, inviter } = data;
|
|
5408
|
+
const baseUrl = process.env.BETTER_AUTH_URL || 'http://localhost:3000';
|
|
5409
|
+
const url = \`\${baseUrl}/accept-invitation?id=\${invitation.id}\`;
|
|
5410
|
+
|
|
5411
|
+
const subject = \`${escapedSubject}\`
|
|
5412
|
+
.replace(/{{organization.name}}/g, organization?.name || '')
|
|
5413
|
+
.replace(/{{invitation.role}}/g, invitation.role || '')
|
|
5414
|
+
.replace(/{{inviter.user.name}}/g, inviter?.user?.name || '')
|
|
5415
|
+
.replace(/{{inviter.user.email}}/g, inviter?.user?.email || '')
|
|
5416
|
+
.replace(/{{invitation.email}}/g, invitation.email || '');
|
|
5417
|
+
|
|
5418
|
+
const html = \`${escapedHtml}\`
|
|
5419
|
+
.replace(/{{invitation.url}}/g, url)
|
|
5420
|
+
.replace(/{{invitation.role}}/g, invitation.role || '')
|
|
5421
|
+
.replace(/{{organization.name}}/g, organization?.name || '')
|
|
5422
|
+
.replace(/{{organization.slug}}/g, organization?.slug || '')
|
|
5423
|
+
.replace(/{{inviter.user.name}}/g, inviter?.user?.name || '')
|
|
5424
|
+
.replace(/{{inviter.user.email}}/g, inviter?.user?.email || '')
|
|
5425
|
+
.replace(/{{invitation.email}}/g, invitation.email || '')
|
|
5426
|
+
.replace(/{{invitation.expiresAt}}/g, invitation.expiresAt?.toLocaleString() || '')
|
|
5427
|
+
.replace(/{{expiresIn}}/g, invitation.expiresAt ? \`\${Math.ceil((invitation.expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24))} days\` : '');
|
|
5428
|
+
|
|
5429
|
+
void sendEmail({
|
|
5430
|
+
to: invitation.email,
|
|
5431
|
+
subject,
|
|
5432
|
+
html,
|
|
5433
|
+
});
|
|
5434
|
+
}`,
|
|
5435
|
+
},
|
|
5436
|
+
};
|
|
5437
|
+
const handler = handlers[templateId];
|
|
5438
|
+
if (!handler) {
|
|
5439
|
+
return res
|
|
5440
|
+
.status(400)
|
|
5441
|
+
.json({ success: false, message: 'Unsupported templateId for apply' });
|
|
5442
|
+
}
|
|
5443
|
+
if (!fileContent.includes('const sendEmail = async')) {
|
|
5444
|
+
const insertPoint = fileContent.indexOf('export const auth');
|
|
5445
|
+
fileContent =
|
|
5446
|
+
fileContent.slice(0, insertPoint) +
|
|
5447
|
+
`const sendEmail = async ({ to, subject, text, html }: { to: string; subject: string; text?: string; html?: string }) => {\n console.log(\`Sending email to \${to} | \${subject}\`);\n if (text) console.log('Text content:', text);\n if (html) console.log('HTML content:', html);\n};\n\n` +
|
|
5448
|
+
fileContent.slice(insertPoint);
|
|
5449
|
+
}
|
|
5450
|
+
if (handler.regex.test(fileContent)) {
|
|
5451
|
+
fileContent = fileContent.replace(handler.regex, `${handler.fn},`);
|
|
5452
|
+
}
|
|
5453
|
+
else if (templateId === 'org-invitation') {
|
|
5454
|
+
const orgPluginRegex = /organization\(\s*\{\s*/;
|
|
5455
|
+
if (!orgPluginRegex.test(fileContent)) {
|
|
5456
|
+
return res.status(400).json({
|
|
5457
|
+
success: false,
|
|
5458
|
+
message: 'organization plugin config not found in auth.ts',
|
|
5459
|
+
});
|
|
5460
|
+
}
|
|
5461
|
+
fileContent = fileContent.replace(orgPluginRegex, (m) => `${m}${handler.fn},\n `);
|
|
5462
|
+
}
|
|
5463
|
+
else {
|
|
5464
|
+
const sectionRegex = handler.sectionRegex || /emailAndPassword\s*:\s*\{\s*/;
|
|
5465
|
+
if (!sectionRegex.test(fileContent)) {
|
|
5466
|
+
return res.status(400).json({
|
|
5467
|
+
success: false,
|
|
5468
|
+
message: 'target email config section not found in auth.ts',
|
|
5469
|
+
});
|
|
5470
|
+
}
|
|
5471
|
+
fileContent = fileContent.replace(sectionRegex, (m) => `${m}${handler.fn},\n `);
|
|
5472
|
+
}
|
|
5473
|
+
writeFileSync(authPath, fileContent, 'utf-8');
|
|
5474
|
+
res.json({ success: true, path: authPath });
|
|
5475
|
+
}
|
|
5476
|
+
catch (error) {
|
|
5477
|
+
res.status(500).json({
|
|
5478
|
+
success: false,
|
|
5479
|
+
message: error?.message || 'Failed to apply invitation template',
|
|
5480
|
+
});
|
|
5481
|
+
}
|
|
5482
|
+
});
|
|
5294
5483
|
return router;
|
|
5295
5484
|
}
|
|
5296
5485
|
//# sourceMappingURL=routes.js.map
|