@nextsparkjs/core 0.1.0-beta.149 → 0.1.0-beta.150
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/dist/components/dashboard/block-editor/block-picker.d.ts +6 -1
- package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/block-picker.js +34 -12
- package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts +2 -1
- package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/block-preview-canvas.js +5 -0
- package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/builder-editor-view.js +41 -13
- package/dist/components/dashboard/block-editor/floating-block-toolbar.d.ts +2 -1
- package/dist/components/dashboard/block-editor/floating-block-toolbar.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/floating-block-toolbar.js +17 -1
- package/dist/components/dashboard/block-editor/tree-view-node.d.ts +4 -1
- package/dist/components/dashboard/block-editor/tree-view-node.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/tree-view-node.js +52 -1
- package/dist/components/dashboard/block-editor/tree-view.d.ts +4 -1
- package/dist/components/dashboard/block-editor/tree-view.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/tree-view.js +6 -0
- package/dist/components/entities/EntityTable.d.ts +1 -1
- package/dist/components/entities/EntityTable.d.ts.map +1 -1
- package/dist/components/entities/EntityTable.js +14 -1
- package/dist/components/entities/entity-table.types.d.ts +2 -0
- package/dist/components/entities/entity-table.types.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityListWrapper.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityListWrapper.js +19 -1
- package/dist/emails/otp-verification.d.ts +9 -0
- package/dist/emails/otp-verification.d.ts.map +1 -0
- package/dist/emails/otp-verification.js +72 -0
- package/dist/emails/reset-password.d.ts +9 -0
- package/dist/emails/reset-password.d.ts.map +1 -0
- package/dist/emails/reset-password.js +95 -0
- package/dist/emails/team-invitation.d.ts +9 -0
- package/dist/emails/team-invitation.d.ts.map +1 -0
- package/dist/emails/team-invitation.js +93 -0
- package/dist/emails/verify-email.d.ts +13 -0
- package/dist/emails/verify-email.d.ts.map +1 -0
- package/dist/emails/verify-email.js +84 -0
- package/dist/lib/api/entities.d.ts +6 -1
- package/dist/lib/api/entities.d.ts.map +1 -1
- package/dist/lib/api/entities.js +23 -2
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +12 -7
- package/dist/lib/blocks/clipboard.d.ts +11 -0
- package/dist/lib/blocks/clipboard.d.ts.map +1 -0
- package/dist/lib/blocks/clipboard.js +30 -0
- package/dist/lib/email/index.d.ts +1 -0
- package/dist/lib/email/index.d.ts.map +1 -1
- package/dist/lib/email/index.js +12 -0
- package/dist/lib/email/send.d.ts +15 -0
- package/dist/lib/email/send.d.ts.map +1 -0
- package/dist/lib/email/send.js +11 -0
- package/dist/lib/email/templates.d.ts +42 -29
- package/dist/lib/email/templates.d.ts.map +1 -1
- package/dist/lib/email/templates.js +8 -303
- package/dist/lib/email/types.d.ts +32 -0
- package/dist/lib/email/types.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.d.ts +2 -2
- package/dist/lib/services/subscription.service.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.js +6 -6
- package/dist/messages/de/email.json +58 -0
- package/dist/messages/en/admin.json +6 -2
- package/dist/messages/en/email.json +58 -0
- package/dist/messages/en/index.d.ts +4 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/es/admin.json +6 -2
- package/dist/messages/es/email.json +58 -0
- package/dist/messages/es/index.d.ts +4 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/fr/email.json +58 -0
- package/dist/messages/it/email.json +58 -0
- package/dist/messages/pt/email.json +58 -0
- package/dist/styles/classes.json +3 -2
- package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +9 -7
- package/dist/templates/contents/themes/starter/emails/_README.md +69 -0
- package/dist/templates/contents/themes/starter/emails/verify-email.ts +34 -0
- package/package.json +6 -2
- package/scripts/build/registry/discovery/emails.mjs +146 -0
- package/scripts/build/registry/generators/email-registry.mjs +94 -0
- package/scripts/build/registry.mjs +8 -4
- package/templates/app/api/v1/teams/[teamId]/members/route.ts +9 -7
- package/templates/contents/themes/starter/emails/_README.md +69 -0
- package/templates/contents/themes/starter/emails/verify-email.ts +34 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/email-registry.ts +41 -0
- package/tests/jest/__mocks__/next-intl-server.js +55 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/email/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/email/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,QAAQ,CAAC"}
|
package/dist/lib/email/index.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export * from "./factory.js";
|
|
3
3
|
export * from "./templates.js";
|
|
4
|
+
import {
|
|
5
|
+
sendVerifyEmail,
|
|
6
|
+
sendResetPasswordEmail,
|
|
7
|
+
sendOtpVerificationEmail,
|
|
8
|
+
sendTeamInvitationEmail
|
|
9
|
+
} from "./send.js";
|
|
10
|
+
export {
|
|
11
|
+
sendOtpVerificationEmail,
|
|
12
|
+
sendResetPasswordEmail,
|
|
13
|
+
sendTeamInvitationEmail,
|
|
14
|
+
sendVerifyEmail
|
|
15
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed convenience helpers around `EMAIL_REGISTRY`.
|
|
3
|
+
*
|
|
4
|
+
* These wrap the four core slugs so call sites can stay readable and keep
|
|
5
|
+
* full type safety on the data argument. For consumer-defined slugs (e.g. a
|
|
6
|
+
* theme's own `purchase-confirmation.ts`), call `EMAIL_REGISTRY['<slug>']`
|
|
7
|
+
* directly — TypeScript infers the data type from each registered function's
|
|
8
|
+
* signature thanks to the `as const` emission in the generated registry.
|
|
9
|
+
*/
|
|
10
|
+
import type { EmailContent, VerificationEmailData, PasswordResetEmailData, OtpVerificationEmailData, TeamInvitationEmailData } from './types';
|
|
11
|
+
export declare const sendVerifyEmail: (data: VerificationEmailData, locale?: string) => EmailContent | Promise<EmailContent>;
|
|
12
|
+
export declare const sendResetPasswordEmail: (data: PasswordResetEmailData, locale?: string) => EmailContent | Promise<EmailContent>;
|
|
13
|
+
export declare const sendOtpVerificationEmail: (data: OtpVerificationEmailData, locale?: string) => EmailContent | Promise<EmailContent>;
|
|
14
|
+
export declare const sendTeamInvitationEmail: (data: TeamInvitationEmailData, locale?: string) => EmailContent | Promise<EmailContent>;
|
|
15
|
+
//# sourceMappingURL=send.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../../src/lib/email/send.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,eAAe,GAC1B,MAAM,qBAAqB,EAC3B,SAAS,MAAM,KACd,YAAY,GAAG,OAAO,CAAC,YAAY,CACQ,CAAC;AAE/C,eAAO,MAAM,sBAAsB,GACjC,MAAM,sBAAsB,EAC5B,SAAS,MAAM,KACd,YAAY,GAAG,OAAO,CAAC,YAAY,CACU,CAAC;AAEjD,eAAO,MAAM,wBAAwB,GACnC,MAAM,wBAAwB,EAC9B,SAAS,MAAM,KACd,YAAY,GAAG,OAAO,CAAC,YAAY,CACY,CAAC;AAEnD,eAAO,MAAM,uBAAuB,GAClC,MAAM,uBAAuB,EAC7B,SAAS,MAAM,KACd,YAAY,GAAG,OAAO,CAAC,YAAY,CACW,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EMAIL_REGISTRY } from "@nextsparkjs/registries/email-registry";
|
|
2
|
+
const sendVerifyEmail = (data, locale) => EMAIL_REGISTRY["verify-email"](data, locale);
|
|
3
|
+
const sendResetPasswordEmail = (data, locale) => EMAIL_REGISTRY["reset-password"](data, locale);
|
|
4
|
+
const sendOtpVerificationEmail = (data, locale) => EMAIL_REGISTRY["otp-verification"](data, locale);
|
|
5
|
+
const sendTeamInvitationEmail = (data, locale) => EMAIL_REGISTRY["team-invitation"](data, locale);
|
|
6
|
+
export {
|
|
7
|
+
sendOtpVerificationEmail,
|
|
8
|
+
sendResetPasswordEmail,
|
|
9
|
+
sendTeamInvitationEmail,
|
|
10
|
+
sendVerifyEmail
|
|
11
|
+
};
|
|
@@ -1,32 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Deprecated email-templates surface.
|
|
3
|
+
*
|
|
4
|
+
* Prior to the email-registry refactor (0.1.0-beta.150) this file shipped four
|
|
5
|
+
* monolithic English-only templates accessed via `emailTemplates.<slug>(data)`.
|
|
6
|
+
* That made it impossible for themes to brand or translate transactional
|
|
7
|
+
* emails without forking core.
|
|
8
|
+
*
|
|
9
|
+
* The replacement is the build-time `EMAIL_REGISTRY` in
|
|
10
|
+
* `@nextsparkjs/registries/email-registry`, with theme overrides at
|
|
11
|
+
* `themes/<active-theme>/emails/<slug>.ts`. Typed convenience helpers live in
|
|
12
|
+
* `@nextsparkjs/core/lib/email/send` (`sendVerifyEmail`, `sendResetPasswordEmail`,
|
|
13
|
+
* `sendOtpVerificationEmail`, `sendTeamInvitationEmail`).
|
|
14
|
+
*
|
|
15
|
+
* The exports below are kept as thin async adapters so out-of-tree consumers
|
|
16
|
+
* keep working for one release cycle. They will be removed in a future release.
|
|
17
|
+
*/
|
|
18
|
+
import type { VerificationEmailData, PasswordResetEmailData, TeamInvitationEmailData, OtpVerificationEmailData, EmailContent } from './types';
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated Use the typed helpers from `@nextsparkjs/core/lib/email/send`
|
|
21
|
+
* (e.g. `sendVerifyEmail`) or `EMAIL_REGISTRY['<slug>']` directly. This object
|
|
22
|
+
* is kept for one release cycle to avoid breaking out-of-tree consumers.
|
|
23
|
+
*/
|
|
2
24
|
export declare const emailTemplates: {
|
|
3
|
-
verifyEmail: (data: VerificationEmailData) =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
resetPassword: (data: PasswordResetEmailData) => {
|
|
8
|
-
subject: string;
|
|
9
|
-
html: string;
|
|
10
|
-
};
|
|
11
|
-
otpVerification: (data: OtpVerificationEmailData) => {
|
|
12
|
-
subject: string;
|
|
13
|
-
html: string;
|
|
14
|
-
};
|
|
15
|
-
teamInvitation: (data: TeamInvitationEmailData) => {
|
|
16
|
-
subject: string;
|
|
17
|
-
html: string;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
export declare const createVerificationEmail: (name: string | undefined, verifyUrl: string) => {
|
|
21
|
-
subject: string;
|
|
22
|
-
html: string;
|
|
23
|
-
};
|
|
24
|
-
export declare const createPasswordResetEmail: (name: string | undefined, resetUrl: string) => {
|
|
25
|
-
subject: string;
|
|
26
|
-
html: string;
|
|
27
|
-
};
|
|
28
|
-
export declare const createTeamInvitationEmail: (inviteeEmail: string, inviterName: string, teamName: string, role: string, acceptUrl: string, expiresIn?: string) => {
|
|
29
|
-
subject: string;
|
|
30
|
-
html: string;
|
|
25
|
+
verifyEmail: (data: VerificationEmailData) => Promise<EmailContent>;
|
|
26
|
+
resetPassword: (data: PasswordResetEmailData) => Promise<EmailContent>;
|
|
27
|
+
otpVerification: (data: OtpVerificationEmailData) => Promise<EmailContent>;
|
|
28
|
+
teamInvitation: (data: TeamInvitationEmailData) => Promise<EmailContent>;
|
|
31
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* @deprecated Use `sendVerifyEmail({ userName, verificationUrl, appName })`
|
|
32
|
+
* from `@nextsparkjs/core/lib/email/send`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const createVerificationEmail: (name: string | undefined, verifyUrl: string) => any;
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use `sendResetPasswordEmail({ userName, resetUrl, appName })`
|
|
37
|
+
* from `@nextsparkjs/core/lib/email/send`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const createPasswordResetEmail: (name: string | undefined, resetUrl: string) => any;
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated Use `sendTeamInvitationEmail({ inviteeEmail, inviterName, teamName, role, acceptUrl, expiresIn, appName })`
|
|
42
|
+
* from `@nextsparkjs/core/lib/email/send`.
|
|
43
|
+
*/
|
|
44
|
+
export declare const createTeamInvitationEmail: (inviteeEmail: string, inviterName: string, teamName: string, role: string, acceptUrl: string, expiresIn?: string) => any;
|
|
32
45
|
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/lib/email/templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/lib/email/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,YAAY,EACb,MAAM,SAAS,CAAC;AAIjB;;;;GAIG;AACH,eAAO,MAAM,cAAc;wBACL,qBAAqB,KAAG,OAAO,CAAC,YAAY,CAAC;0BAE3C,sBAAsB,KAAG,OAAO,CAAC,YAAY,CAAC;4BAE5C,wBAAwB,KAAG,OAAO,CAAC,YAAY,CAAC;2BAEjD,uBAAuB,KAAG,OAAO,CAAC,YAAY,CAAC;CAEvE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,GAAG,SAAS,EAAE,WAAW,MAAM,QAK/E,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM,MAAM,GAAG,SAAS,EAAE,UAAU,MAAM,QAK/E,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GACpC,cAAc,MAAM,EACpB,aAAa,MAAM,EACnB,UAAU,MAAM,EAChB,MAAM,MAAM,EACZ,WAAW,MAAM,EACjB,YAAW,MAAiB,QAU1B,CAAC"}
|
|
@@ -1,317 +1,22 @@
|
|
|
1
|
+
import { EMAIL_REGISTRY } from "@nextsparkjs/registries/email-registry";
|
|
1
2
|
const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME || "Your App";
|
|
2
3
|
const emailTemplates = {
|
|
3
|
-
verifyEmail: (data) => (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<html>
|
|
8
|
-
<head>
|
|
9
|
-
<meta charset="utf-8">
|
|
10
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
-
</head>
|
|
12
|
-
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f4f4f4;">
|
|
13
|
-
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
14
|
-
<tr>
|
|
15
|
-
<td align="center" style="padding: 40px 0;">
|
|
16
|
-
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style="background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
17
|
-
<!-- Header -->
|
|
18
|
-
<tr>
|
|
19
|
-
<td style="padding: 40px 40px 20px 40px; text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px 8px 0 0;">
|
|
20
|
-
<h1 style="color: #ffffff; font-size: 28px; margin: 0; font-weight: 600;">${data.appName || APP_NAME}</h1>
|
|
21
|
-
<p style="color: #ffffff; font-size: 16px; margin: 10px 0 0 0; opacity: 0.95;">Welcome to Your Account</p>
|
|
22
|
-
</td>
|
|
23
|
-
</tr>
|
|
24
|
-
|
|
25
|
-
<!-- Content -->
|
|
26
|
-
<tr>
|
|
27
|
-
<td style="padding: 40px;">
|
|
28
|
-
<h2 style="color: #333333; font-size: 24px; margin: 0 0 20px 0; font-weight: 600;">Verify Your Email Address</h2>
|
|
29
|
-
|
|
30
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 20px 0;">
|
|
31
|
-
Hi${data.userName ? ` ${data.userName}` : ""},
|
|
32
|
-
</p>
|
|
33
|
-
|
|
34
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 30px 0;">
|
|
35
|
-
Thank you for signing up! We're excited to have you on board. Please verify your email address to activate your account and get started.
|
|
36
|
-
</p>
|
|
37
|
-
|
|
38
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: 0 auto;">
|
|
39
|
-
<tr>
|
|
40
|
-
<td style="border-radius: 6px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
|
41
|
-
<a href="${data.verificationUrl}" target="_blank" style="display: inline-block; padding: 14px 32px; font-size: 16px; font-weight: 600; color: #ffffff; text-decoration: none; border-radius: 6px;">
|
|
42
|
-
Verify Email Address
|
|
43
|
-
</a>
|
|
44
|
-
</td>
|
|
45
|
-
</tr>
|
|
46
|
-
</table>
|
|
47
|
-
|
|
48
|
-
<p style="color: #999999; font-size: 14px; line-height: 1.6; margin: 30px 0 0 0; padding: 20px; background-color: #f8f8f8; border-radius: 6px;">
|
|
49
|
-
<strong>Can't click the button?</strong><br>
|
|
50
|
-
Copy and paste this link into your browser:<br>
|
|
51
|
-
<span style="color: #667eea; word-break: break-all; font-size: 12px;">${data.verificationUrl}</span>
|
|
52
|
-
</p>
|
|
53
|
-
</td>
|
|
54
|
-
</tr>
|
|
55
|
-
|
|
56
|
-
<!-- Footer -->
|
|
57
|
-
<tr>
|
|
58
|
-
<td style="padding: 30px 40px; background-color: #f8f8f8; border-radius: 0 0 8px 8px; text-align: center;">
|
|
59
|
-
<p style="color: #999999; font-size: 14px; margin: 0 0 10px 0;">
|
|
60
|
-
\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${data.appName || APP_NAME}. All rights reserved.
|
|
61
|
-
</p>
|
|
62
|
-
<p style="color: #999999; font-size: 12px; margin: 0;">
|
|
63
|
-
This email was sent to you because you signed up for ${data.appName || APP_NAME}.
|
|
64
|
-
<br>If you didn't request this, please ignore this email.
|
|
65
|
-
</p>
|
|
66
|
-
</td>
|
|
67
|
-
</tr>
|
|
68
|
-
</table>
|
|
69
|
-
</td>
|
|
70
|
-
</tr>
|
|
71
|
-
</table>
|
|
72
|
-
</body>
|
|
73
|
-
</html>
|
|
74
|
-
`
|
|
75
|
-
}),
|
|
76
|
-
resetPassword: (data) => ({
|
|
77
|
-
subject: `Reset Your Password - ${data.appName || APP_NAME}`,
|
|
78
|
-
html: `
|
|
79
|
-
<!DOCTYPE html>
|
|
80
|
-
<html>
|
|
81
|
-
<head>
|
|
82
|
-
<meta charset="utf-8">
|
|
83
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
84
|
-
</head>
|
|
85
|
-
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f4f4f4;">
|
|
86
|
-
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
87
|
-
<tr>
|
|
88
|
-
<td align="center" style="padding: 40px 0;">
|
|
89
|
-
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style="background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
90
|
-
<!-- Header -->
|
|
91
|
-
<tr>
|
|
92
|
-
<td style="padding: 40px 40px 20px 40px; text-align: center; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border-radius: 8px 8px 0 0;">
|
|
93
|
-
<h1 style="color: #ffffff; font-size: 28px; margin: 0; font-weight: 600;">${data.appName || APP_NAME}</h1>
|
|
94
|
-
<p style="color: #ffffff; font-size: 16px; margin: 10px 0 0 0; opacity: 0.95;">Password Reset Request</p>
|
|
95
|
-
</td>
|
|
96
|
-
</tr>
|
|
97
|
-
|
|
98
|
-
<!-- Content -->
|
|
99
|
-
<tr>
|
|
100
|
-
<td style="padding: 40px;">
|
|
101
|
-
<h2 style="color: #333333; font-size: 24px; margin: 0 0 20px 0; font-weight: 600;">Reset Your Password</h2>
|
|
102
|
-
|
|
103
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 20px 0;">
|
|
104
|
-
Hi${data.userName ? ` ${data.userName}` : ""},
|
|
105
|
-
</p>
|
|
106
|
-
|
|
107
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 30px 0;">
|
|
108
|
-
We received a request to reset your password for your account. Click the button below to create a new password:
|
|
109
|
-
</p>
|
|
110
|
-
|
|
111
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: 0 auto;">
|
|
112
|
-
<tr>
|
|
113
|
-
<td style="border-radius: 6px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
|
|
114
|
-
<a href="${data.resetUrl}" target="_blank" style="display: inline-block; padding: 14px 32px; font-size: 16px; font-weight: 600; color: #ffffff; text-decoration: none; border-radius: 6px;">
|
|
115
|
-
Reset Password
|
|
116
|
-
</a>
|
|
117
|
-
</td>
|
|
118
|
-
</tr>
|
|
119
|
-
</table>
|
|
120
|
-
|
|
121
|
-
<div style="margin: 30px 0; padding: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;">
|
|
122
|
-
<p style="color: #856404; font-size: 14px; margin: 0; font-weight: 600;">
|
|
123
|
-
\u26A0\uFE0F Important Security Information
|
|
124
|
-
</p>
|
|
125
|
-
<p style="color: #856404; font-size: 14px; margin: 10px 0 0 0; line-height: 1.5;">
|
|
126
|
-
This link will expire in <strong>${data.expiresIn || "1 hour"}</strong> for your security.<br>
|
|
127
|
-
If you didn't request this password reset, please ignore this email and your password will remain unchanged.
|
|
128
|
-
</p>
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
<p style="color: #999999; font-size: 14px; line-height: 1.6; margin: 20px 0 0 0; padding: 20px; background-color: #f8f8f8; border-radius: 6px;">
|
|
132
|
-
<strong>Can't click the button?</strong><br>
|
|
133
|
-
Copy and paste this link into your browser:<br>
|
|
134
|
-
<span style="color: #f5576c; word-break: break-all; font-size: 12px;">${data.resetUrl}</span>
|
|
135
|
-
</p>
|
|
136
|
-
</td>
|
|
137
|
-
</tr>
|
|
138
|
-
|
|
139
|
-
<!-- Footer -->
|
|
140
|
-
<tr>
|
|
141
|
-
<td style="padding: 30px 40px; background-color: #f8f8f8; border-radius: 0 0 8px 8px; text-align: center;">
|
|
142
|
-
<p style="color: #999999; font-size: 14px; margin: 0 0 10px 0;">
|
|
143
|
-
\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${data.appName || APP_NAME}. All rights reserved.
|
|
144
|
-
</p>
|
|
145
|
-
<p style="color: #999999; font-size: 12px; margin: 0;">
|
|
146
|
-
This is an automated security email from ${data.appName || APP_NAME}.
|
|
147
|
-
<br>For security reasons, we never ask for your password via email.
|
|
148
|
-
</p>
|
|
149
|
-
</td>
|
|
150
|
-
</tr>
|
|
151
|
-
</table>
|
|
152
|
-
</td>
|
|
153
|
-
</tr>
|
|
154
|
-
</table>
|
|
155
|
-
</body>
|
|
156
|
-
</html>
|
|
157
|
-
`
|
|
158
|
-
}),
|
|
159
|
-
otpVerification: (data) => ({
|
|
160
|
-
subject: `${data.otp} is your verification code - ${data.appName || APP_NAME}`,
|
|
161
|
-
html: `
|
|
162
|
-
<!DOCTYPE html>
|
|
163
|
-
<html>
|
|
164
|
-
<head>
|
|
165
|
-
<meta charset="utf-8">
|
|
166
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
167
|
-
</head>
|
|
168
|
-
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f4f4f4;">
|
|
169
|
-
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
170
|
-
<tr>
|
|
171
|
-
<td align="center" style="padding: 40px 0;">
|
|
172
|
-
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style="background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
173
|
-
<!-- Header -->
|
|
174
|
-
<tr>
|
|
175
|
-
<td style="padding: 40px 40px 20px 40px; text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px 8px 0 0;">
|
|
176
|
-
<h1 style="color: #ffffff; font-size: 28px; margin: 0; font-weight: 600;">${data.appName || APP_NAME}</h1>
|
|
177
|
-
<p style="color: #ffffff; font-size: 16px; margin: 10px 0 0 0; opacity: 0.95;">Verification Code</p>
|
|
178
|
-
</td>
|
|
179
|
-
</tr>
|
|
180
|
-
|
|
181
|
-
<!-- Content -->
|
|
182
|
-
<tr>
|
|
183
|
-
<td style="padding: 40px; text-align: center;">
|
|
184
|
-
<h2 style="color: #333333; font-size: 24px; margin: 0 0 20px 0; font-weight: 600;">Your verification code</h2>
|
|
185
|
-
|
|
186
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 30px 0;">
|
|
187
|
-
Enter this code to verify your identity:
|
|
188
|
-
</p>
|
|
189
|
-
|
|
190
|
-
<div style="margin: 0 auto 30px; padding: 20px 40px; background-color: #f8f8f8; border-radius: 8px; display: inline-block;">
|
|
191
|
-
<span style="font-size: 36px; font-weight: 700; letter-spacing: 8px; color: #333333; font-family: monospace;">${data.otp}</span>
|
|
192
|
-
</div>
|
|
193
|
-
|
|
194
|
-
<p style="color: #999999; font-size: 14px; line-height: 1.6; margin: 0;">
|
|
195
|
-
This code expires in <strong>5 minutes</strong>.<br>
|
|
196
|
-
If you didn't request this code, you can safely ignore this email.
|
|
197
|
-
</p>
|
|
198
|
-
</td>
|
|
199
|
-
</tr>
|
|
200
|
-
|
|
201
|
-
<!-- Footer -->
|
|
202
|
-
<tr>
|
|
203
|
-
<td style="padding: 30px 40px; background-color: #f8f8f8; border-radius: 0 0 8px 8px; text-align: center;">
|
|
204
|
-
<p style="color: #999999; font-size: 14px; margin: 0 0 10px 0;">
|
|
205
|
-
© ${(/* @__PURE__ */ new Date()).getFullYear()} ${data.appName || APP_NAME}. All rights reserved.
|
|
206
|
-
</p>
|
|
207
|
-
<p style="color: #999999; font-size: 12px; margin: 0;">
|
|
208
|
-
This is an automated email from ${data.appName || APP_NAME}.
|
|
209
|
-
</p>
|
|
210
|
-
</td>
|
|
211
|
-
</tr>
|
|
212
|
-
</table>
|
|
213
|
-
</td>
|
|
214
|
-
</tr>
|
|
215
|
-
</table>
|
|
216
|
-
</body>
|
|
217
|
-
</html>
|
|
218
|
-
`
|
|
219
|
-
}),
|
|
220
|
-
teamInvitation: (data) => ({
|
|
221
|
-
subject: `You've been invited to join ${data.teamName} on ${data.appName || APP_NAME}`,
|
|
222
|
-
html: `
|
|
223
|
-
<!DOCTYPE html>
|
|
224
|
-
<html>
|
|
225
|
-
<head>
|
|
226
|
-
<meta charset="utf-8">
|
|
227
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
228
|
-
</head>
|
|
229
|
-
<body style="margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f4f4f4;">
|
|
230
|
-
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
231
|
-
<tr>
|
|
232
|
-
<td align="center" style="padding: 40px 0;">
|
|
233
|
-
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0" style="background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
234
|
-
<!-- Header -->
|
|
235
|
-
<tr>
|
|
236
|
-
<td style="padding: 40px 40px 20px 40px; text-align: center; background: linear-gradient(135deg, #4F46E5 0%, #7C3AED 100%); border-radius: 8px 8px 0 0;">
|
|
237
|
-
<h1 style="color: #ffffff; font-size: 28px; margin: 0; font-weight: 600;">${data.appName || APP_NAME}</h1>
|
|
238
|
-
<p style="color: #ffffff; font-size: 16px; margin: 10px 0 0 0; opacity: 0.95;">Team Invitation</p>
|
|
239
|
-
</td>
|
|
240
|
-
</tr>
|
|
241
|
-
|
|
242
|
-
<!-- Content -->
|
|
243
|
-
<tr>
|
|
244
|
-
<td style="padding: 40px;">
|
|
245
|
-
<h2 style="color: #333333; font-size: 24px; margin: 0 0 20px 0; font-weight: 600;">You're Invited!</h2>
|
|
246
|
-
|
|
247
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 20px 0;">
|
|
248
|
-
<strong>${data.inviterName}</strong> has invited you to join the team <strong>${data.teamName}</strong> as a <strong>${data.role}</strong>.
|
|
249
|
-
</p>
|
|
250
|
-
|
|
251
|
-
<p style="color: #666666; font-size: 16px; line-height: 1.6; margin: 0 0 30px 0;">
|
|
252
|
-
Click the button below to accept the invitation and join the team:
|
|
253
|
-
</p>
|
|
254
|
-
|
|
255
|
-
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: 0 auto;">
|
|
256
|
-
<tr>
|
|
257
|
-
<td style="border-radius: 6px; background: linear-gradient(135deg, #4F46E5 0%, #7C3AED 100%);">
|
|
258
|
-
<a href="${data.acceptUrl}" target="_blank" style="display: inline-block; padding: 14px 32px; font-size: 16px; font-weight: 600; color: #ffffff; text-decoration: none; border-radius: 6px;">
|
|
259
|
-
Accept Invitation
|
|
260
|
-
</a>
|
|
261
|
-
</td>
|
|
262
|
-
</tr>
|
|
263
|
-
</table>
|
|
264
|
-
|
|
265
|
-
<div style="margin: 30px 0; padding: 20px; background-color: #f0f9ff; border-left: 4px solid #4F46E5; border-radius: 4px;">
|
|
266
|
-
<p style="color: #1e40af; font-size: 14px; margin: 0; font-weight: 600;">
|
|
267
|
-
\u23F0 Invitation Details
|
|
268
|
-
</p>
|
|
269
|
-
<p style="color: #1e40af; font-size: 14px; margin: 10px 0 0 0; line-height: 1.5;">
|
|
270
|
-
This invitation will expire in <strong>${data.expiresIn}</strong>.<br>
|
|
271
|
-
If you don't have an account yet, you'll be able to create one when you accept.
|
|
272
|
-
</p>
|
|
273
|
-
</div>
|
|
274
|
-
|
|
275
|
-
<p style="color: #999999; font-size: 14px; line-height: 1.6; margin: 20px 0 0 0; padding: 20px; background-color: #f8f8f8; border-radius: 6px;">
|
|
276
|
-
<strong>Can't click the button?</strong><br>
|
|
277
|
-
Copy and paste this link into your browser:<br>
|
|
278
|
-
<span style="color: #4F46E5; word-break: break-all; font-size: 12px;">${data.acceptUrl}</span>
|
|
279
|
-
</p>
|
|
280
|
-
</td>
|
|
281
|
-
</tr>
|
|
282
|
-
|
|
283
|
-
<!-- Footer -->
|
|
284
|
-
<tr>
|
|
285
|
-
<td style="padding: 30px 40px; background-color: #f8f8f8; border-radius: 0 0 8px 8px; text-align: center;">
|
|
286
|
-
<p style="color: #999999; font-size: 14px; margin: 0 0 10px 0;">
|
|
287
|
-
\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${data.appName || APP_NAME}. All rights reserved.
|
|
288
|
-
</p>
|
|
289
|
-
<p style="color: #999999; font-size: 12px; margin: 0;">
|
|
290
|
-
This invitation was sent to ${data.inviteeEmail}.<br>
|
|
291
|
-
If you didn't expect this invitation, you can safely ignore this email.
|
|
292
|
-
</p>
|
|
293
|
-
</td>
|
|
294
|
-
</tr>
|
|
295
|
-
</table>
|
|
296
|
-
</td>
|
|
297
|
-
</tr>
|
|
298
|
-
</table>
|
|
299
|
-
</body>
|
|
300
|
-
</html>
|
|
301
|
-
`
|
|
302
|
-
})
|
|
4
|
+
verifyEmail: (data) => Promise.resolve(EMAIL_REGISTRY["verify-email"](data)),
|
|
5
|
+
resetPassword: (data) => Promise.resolve(EMAIL_REGISTRY["reset-password"](data)),
|
|
6
|
+
otpVerification: (data) => Promise.resolve(EMAIL_REGISTRY["otp-verification"](data)),
|
|
7
|
+
teamInvitation: (data) => Promise.resolve(EMAIL_REGISTRY["team-invitation"](data))
|
|
303
8
|
};
|
|
304
|
-
const createVerificationEmail = (name, verifyUrl) =>
|
|
9
|
+
const createVerificationEmail = (name, verifyUrl) => EMAIL_REGISTRY["verify-email"]({
|
|
305
10
|
userName: name || "",
|
|
306
11
|
verificationUrl: verifyUrl,
|
|
307
12
|
appName: APP_NAME
|
|
308
13
|
});
|
|
309
|
-
const createPasswordResetEmail = (name, resetUrl) =>
|
|
14
|
+
const createPasswordResetEmail = (name, resetUrl) => EMAIL_REGISTRY["reset-password"]({
|
|
310
15
|
userName: name || "",
|
|
311
16
|
resetUrl,
|
|
312
17
|
appName: APP_NAME
|
|
313
18
|
});
|
|
314
|
-
const createTeamInvitationEmail = (inviteeEmail, inviterName, teamName, role, acceptUrl, expiresIn = "7 days") =>
|
|
19
|
+
const createTeamInvitationEmail = (inviteeEmail, inviterName, teamName, role, acceptUrl, expiresIn = "7 days") => EMAIL_REGISTRY["team-invitation"]({
|
|
315
20
|
inviteeEmail,
|
|
316
21
|
inviterName,
|
|
317
22
|
teamName,
|
|
@@ -27,6 +27,30 @@ export interface EmailProvider {
|
|
|
27
27
|
export interface EmailTemplateData {
|
|
28
28
|
[key: string]: string | number | boolean | undefined;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Output shape every email template function returns.
|
|
32
|
+
*
|
|
33
|
+
* The shipping `EmailFactory` consumes `subject` and `html` directly when
|
|
34
|
+
* dispatching via Resend or the console provider. `text` is reserved for
|
|
35
|
+
* future plain-text fallback support and is currently optional.
|
|
36
|
+
*/
|
|
37
|
+
export interface EmailContent {
|
|
38
|
+
subject: string;
|
|
39
|
+
html: string;
|
|
40
|
+
text?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Contract every email template file (core default or theme override) must
|
|
44
|
+
* export as its default export.
|
|
45
|
+
*
|
|
46
|
+
* - `data`: template-specific input shape (e.g. `VerificationEmailData`).
|
|
47
|
+
* - `locale`: optional BCP47 code; templates that integrate i18n use it to
|
|
48
|
+
* fetch translated copy via `getTranslations({ locale, namespace })`.
|
|
49
|
+
*
|
|
50
|
+
* Returning a `Promise` is fully supported so locale-aware templates can
|
|
51
|
+
* `await getTranslations(...)`.
|
|
52
|
+
*/
|
|
53
|
+
export type EmailTemplateFn<TData extends EmailTemplateData> = (data: TData, locale?: string) => EmailContent | Promise<EmailContent>;
|
|
30
54
|
export interface VerificationEmailData extends EmailTemplateData {
|
|
31
55
|
userName: string;
|
|
32
56
|
verificationUrl: string;
|
|
@@ -38,6 +62,14 @@ export interface PasswordResetEmailData extends EmailTemplateData {
|
|
|
38
62
|
appName: string;
|
|
39
63
|
expiresIn?: string;
|
|
40
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* @deprecated Orphaned type — no template implementation in core or any
|
|
67
|
+
* theme as of 0.1.0-beta.149. Either implement a `welcome-email` template
|
|
68
|
+
* (drop a file at `packages/core/src/emails/welcome-email.ts` exporting
|
|
69
|
+
* `EmailTemplateFn<WelcomeEmailData>`) or remove this interface in a
|
|
70
|
+
* follow-up cleanup. Kept exported for now to avoid breaking any
|
|
71
|
+
* out-of-tree consumer that imports the type.
|
|
72
|
+
*/
|
|
41
73
|
export interface WelcomeEmailData extends EmailTemplateData {
|
|
42
74
|
userName: string;
|
|
43
75
|
appName: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/email/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACtD;AAED,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/email/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACtD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,iBAAiB,IAAI,CAC7D,IAAI,EAAE,KAAK,EACX,MAAM,CAAC,EAAE,MAAM,KACZ,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAE1C,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -220,7 +220,7 @@ export declare class SubscriptionService {
|
|
|
220
220
|
* @example
|
|
221
221
|
* const hasAnalytics = await SubscriptionService.hasFeature('team-123', 'advanced_analytics')
|
|
222
222
|
*/
|
|
223
|
-
static hasFeature(teamId: string, featureSlug: string): Promise<boolean>;
|
|
223
|
+
static hasFeature(teamId: string, featureSlug: string, userId?: string): Promise<boolean>;
|
|
224
224
|
/**
|
|
225
225
|
* Check quota for a specific limit
|
|
226
226
|
*
|
|
@@ -234,7 +234,7 @@ export declare class SubscriptionService {
|
|
|
234
234
|
* console.log('Quota exceeded:', quota.current, '/', quota.max)
|
|
235
235
|
* }
|
|
236
236
|
*/
|
|
237
|
-
static checkQuota(teamId: string, limitSlug: string): Promise<QuotaInfo>;
|
|
237
|
+
static checkQuota(teamId: string, limitSlug: string, userId?: string): Promise<QuotaInfo>;
|
|
238
238
|
/**
|
|
239
239
|
* Check if action is allowed (RBAC + feature + quota)
|
|
240
240
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/subscription.service.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"subscription.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/subscription.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -664,11 +664,11 @@ class SubscriptionService {
|
|
|
664
664
|
* @example
|
|
665
665
|
* const hasAnalytics = await SubscriptionService.hasFeature('team-123', 'advanced_analytics')
|
|
666
666
|
*/
|
|
667
|
-
static async hasFeature(teamId, featureSlug) {
|
|
667
|
+
static async hasFeature(teamId, featureSlug, userId) {
|
|
668
668
|
if (!teamId || !featureSlug) {
|
|
669
669
|
return false;
|
|
670
670
|
}
|
|
671
|
-
const subscription = await this.getActive(teamId);
|
|
671
|
+
const subscription = await this.getActive(teamId, userId);
|
|
672
672
|
if (!subscription || !isSubscriptionActive(subscription.status)) {
|
|
673
673
|
return false;
|
|
674
674
|
}
|
|
@@ -689,7 +689,7 @@ class SubscriptionService {
|
|
|
689
689
|
* console.log('Quota exceeded:', quota.current, '/', quota.max)
|
|
690
690
|
* }
|
|
691
691
|
*/
|
|
692
|
-
static async checkQuota(teamId, limitSlug) {
|
|
692
|
+
static async checkQuota(teamId, limitSlug, userId) {
|
|
693
693
|
if (!teamId || !limitSlug) {
|
|
694
694
|
return {
|
|
695
695
|
allowed: false,
|
|
@@ -699,7 +699,7 @@ class SubscriptionService {
|
|
|
699
699
|
percentUsed: 0
|
|
700
700
|
};
|
|
701
701
|
}
|
|
702
|
-
const subscription = await this.getActive(teamId);
|
|
702
|
+
const subscription = await this.getActive(teamId, userId);
|
|
703
703
|
if (!subscription || !isSubscriptionActive(subscription.status)) {
|
|
704
704
|
return {
|
|
705
705
|
allowed: false,
|
|
@@ -811,14 +811,14 @@ class SubscriptionService {
|
|
|
811
811
|
}
|
|
812
812
|
const requiredFeature = BILLING_REGISTRY.actionMappings.features[action];
|
|
813
813
|
if (requiredFeature) {
|
|
814
|
-
const hasFeatureAccess = await this.hasFeature(teamId, requiredFeature);
|
|
814
|
+
const hasFeatureAccess = await this.hasFeature(teamId, requiredFeature, userId);
|
|
815
815
|
if (!hasFeatureAccess) {
|
|
816
816
|
return { allowed: false, reason: "feature_not_in_plan" };
|
|
817
817
|
}
|
|
818
818
|
}
|
|
819
819
|
const consumedLimit = BILLING_REGISTRY.actionMappings.limits[action];
|
|
820
820
|
if (consumedLimit) {
|
|
821
|
-
const quota = await this.checkQuota(teamId, consumedLimit);
|
|
821
|
+
const quota = await this.checkQuota(teamId, consumedLimit, userId);
|
|
822
822
|
if (!quota.allowed) {
|
|
823
823
|
return { allowed: false, reason: "quota_exceeded", quota };
|
|
824
824
|
}
|