better-auth-studio 1.0.59-beta.11 → 1.0.59-beta.12

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.
@@ -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,CA4mLR"}
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,CA4wLR"}
package/dist/routes.js CHANGED
@@ -5291,6 +5291,152 @@ export const authClient = createAuthClient({
5291
5291
  });
5292
5292
  }
5293
5293
  });
5294
+ // Apply org invitation email template into examples auth.ts
5295
+ router.post('/api/tools/apply-email-template', async (req, res) => {
5296
+ try {
5297
+ const { subject, html, templateId } = req.body || {};
5298
+ if (!subject || !html || !templateId) {
5299
+ return res
5300
+ .status(400)
5301
+ .json({ success: false, message: 'templateId, subject and html are required' });
5302
+ }
5303
+ const authPath = join(process.cwd(), 'examples/nextjs/prisma/lib/auth.ts');
5304
+ if (!existsSync(authPath)) {
5305
+ return res.status(404).json({ success: false, message: 'auth.ts not found' });
5306
+ }
5307
+ let fileContent = readFileSync(authPath, 'utf-8');
5308
+ const escapedSubject = subject.replace(/`/g, '\\`').replace(/\${/g, '\\${');
5309
+ const escapedHtml = html.replace(/`/g, '\\`').replace(/\${/g, '\\${');
5310
+ // Ensure Resend import
5311
+ if (!fileContent.includes("from 'resend'")) {
5312
+ fileContent = `import { Resend } from 'resend';\n` + fileContent;
5313
+ }
5314
+ // Ensure resend instance
5315
+ if (!fileContent.includes('const resend = new Resend(')) {
5316
+ // place after imports
5317
+ const importBlockEnd = fileContent.indexOf('\n', fileContent.lastIndexOf('import'));
5318
+ if (importBlockEnd > -1) {
5319
+ fileContent =
5320
+ fileContent.slice(0, importBlockEnd + 1) +
5321
+ `const resend = new Resend(process.env.RESEND_API_KEY || '');\n` +
5322
+ fileContent.slice(importBlockEnd + 1);
5323
+ }
5324
+ else {
5325
+ fileContent = `const resend = new Resend(process.env.RESEND_API_KEY || '');\n` + fileContent;
5326
+ }
5327
+ }
5328
+ const handlers = {
5329
+ 'password-reset': {
5330
+ regex: /sendResetPassword\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
5331
+ fn: `sendResetPassword: async ({ user, url, token }, request) => {
5332
+ void sendEmail({
5333
+ to: user.email,
5334
+ subject: "Reset your password",
5335
+ text: \\\`Click the link to reset your password: \\\${url}\\\`,
5336
+ });
5337
+ }`,
5338
+ },
5339
+ 'email-verification': {
5340
+ regex: /sendVerificationEmail\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
5341
+ fn: `sendVerificationEmail: async ({ user, url, token }, request) => {
5342
+ void sendEmail({
5343
+ to: user.email,
5344
+ subject: "Verify your email address",
5345
+ text: \\\`Click the link to verify your email: \\\${url}\\\`,
5346
+ });
5347
+ }`,
5348
+ },
5349
+ 'magic-link': {
5350
+ regex: /sendMagicLink\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
5351
+ fn: `sendMagicLink: async ({ email, token, url }, ctx) => {
5352
+ void sendEmail({
5353
+ to: email,
5354
+ subject: "Sign in to your account",
5355
+ text: \\\`Click the link to sign in: \\\${url}\\\`,
5356
+ });
5357
+ }`,
5358
+ },
5359
+ 'org-invitation': {
5360
+ regex: /sendInvitationEmail\s*:\s*async\s*\([^)]*\)\s*=>\s*\{[\s\S]*?\},?/,
5361
+ fn: `sendInvitationEmail: async ({ data, request }) => {
5362
+ const { invitation, organization, inviter } = data;
5363
+ const url =
5364
+ (invitation as any)?.url ||
5365
+ (invitation as any)?.link ||
5366
+ request?.url ||
5367
+ invitation.id;
5368
+
5369
+ const subject = \\\`${escapedSubject}\\\`
5370
+ .replace(/{{organization.name}}/g, organization?.name || '')
5371
+ .replace(/{{invitation.role}}/g, invitation.role || '')
5372
+ .replace(/{{inviter.user.name}}/g, inviter?.user?.name || '')
5373
+ .replace(/{{inviter.user.email}}/g, inviter?.user?.email || '');
5374
+
5375
+ const html = \\\`${escapedHtml}\\\`
5376
+ .replace(/{{invitation.url}}/g, url)
5377
+ .replace(/{{invitation.role}}/g, invitation.role || '')
5378
+ .replace(/{{organization.name}}/g, organization?.name || '')
5379
+ .replace(/{{inviter.user.name}}/g, inviter?.user?.name || '')
5380
+ .replace(/{{inviter.user.email}}/g, inviter?.user?.email || '');
5381
+
5382
+ await sendEmail({
5383
+ to: invitation.email,
5384
+ subject,
5385
+ text: url,
5386
+ });
5387
+ }`,
5388
+ },
5389
+ };
5390
+ const handler = handlers[templateId];
5391
+ if (!handler) {
5392
+ return res
5393
+ .status(400)
5394
+ .json({ success: false, message: 'Unsupported templateId for apply' });
5395
+ }
5396
+ // ensure sendEmail helper exists
5397
+ if (!fileContent.includes('const sendEmail = async')) {
5398
+ const insertPoint = fileContent.indexOf('export const auth');
5399
+ fileContent =
5400
+ fileContent.slice(0, insertPoint) +
5401
+ `const sendEmail = async ({ to, subject, text }: { to: string; subject: string; text: string }) => {\n console.log(\`Sending email to \${to} | \${subject} | \${text}\`);\n};\n\n` +
5402
+ fileContent.slice(insertPoint);
5403
+ }
5404
+ if (handler.regex.test(fileContent)) {
5405
+ fileContent = fileContent.replace(handler.regex, `${handler.fn},`);
5406
+ }
5407
+ else {
5408
+ // try to inject into emailAndPassword or organization plugin based on template
5409
+ if (templateId === 'org-invitation') {
5410
+ const orgPluginRegex = /organization\(\s*\{\s*/;
5411
+ if (!orgPluginRegex.test(fileContent)) {
5412
+ return res.status(400).json({
5413
+ success: false,
5414
+ message: 'organization plugin config not found in auth.ts',
5415
+ });
5416
+ }
5417
+ fileContent = fileContent.replace(orgPluginRegex, (m) => `${m}${handler.fn},\n `);
5418
+ }
5419
+ else {
5420
+ const emailAndPasswordRegex = /emailAndPassword\s*:\s*\{\s*/;
5421
+ if (!emailAndPasswordRegex.test(fileContent)) {
5422
+ return res.status(400).json({
5423
+ success: false,
5424
+ message: 'emailAndPassword config not found in auth.ts',
5425
+ });
5426
+ }
5427
+ fileContent = fileContent.replace(emailAndPasswordRegex, (m) => `${m}${handler.fn},\n `);
5428
+ }
5429
+ }
5430
+ writeFileSync(authPath, fileContent, 'utf-8');
5431
+ res.json({ success: true, path: authPath });
5432
+ }
5433
+ catch (error) {
5434
+ res.status(500).json({
5435
+ success: false,
5436
+ message: error?.message || 'Failed to apply invitation template',
5437
+ });
5438
+ }
5439
+ });
5294
5440
  return router;
5295
5441
  }
5296
5442
  //# sourceMappingURL=routes.js.map