@supertokens-plugins/rownd-nodejs 0.3.0-beta.0 → 0.3.0-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 +13 -0
- package/dist/index.d.mts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +150 -1
- package/dist/index.mjs +148 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,19 @@ RowndMigrationPlugin.init({
|
|
|
64
64
|
});
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
### Mobile Deep Links
|
|
68
|
+
|
|
69
|
+
Set `mobileDeepLinkBaseUrl` to rewrite mobile-context account links to a native deep link target. The value must be an absolute URL base, such as a custom scheme or HTTPS universal/app link domain.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
RowndMigrationPlugin.init({
|
|
73
|
+
rowndAppKey: process.env.ROWND_APP_KEY,
|
|
74
|
+
rowndAppSecret: process.env.ROWND_APP_SECRET,
|
|
75
|
+
mobileDeepLinkBaseUrl: "customDomain://",
|
|
76
|
+
// or: mobileDeepLinkBaseUrl: "https://links.example.com",
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
67
80
|
## API Endpoint
|
|
68
81
|
|
|
69
82
|
The plugin exposes a single endpoint:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as SuperTokens from 'supertokens-node';
|
|
2
2
|
import { JSONObject, SuperTokensPlugin } from 'supertokens-node/types';
|
|
3
|
+
import { TypePasswordlessEmailDeliveryInput } from 'supertokens-node/recipe/passwordless/types';
|
|
4
|
+
import { TypeEmailVerificationEmailDeliveryInput } from 'supertokens-node/recipe/emailverification/types';
|
|
3
5
|
|
|
4
6
|
type RowndSignInMethod = {
|
|
5
7
|
/**
|
|
@@ -660,6 +662,7 @@ interface RowndPluginConfig {
|
|
|
660
662
|
rowndAppKey: string;
|
|
661
663
|
rowndAppSecret: string;
|
|
662
664
|
enableDebugLogs?: boolean;
|
|
665
|
+
mobileDeepLinkBaseUrl?: string;
|
|
663
666
|
telemetry?: RowndTelemetryConfig;
|
|
664
667
|
schema?: RowndSchema;
|
|
665
668
|
appConfig?: RowndAppConfigInput;
|
|
@@ -736,6 +739,7 @@ interface RowndPluginNormalisedConfig {
|
|
|
736
739
|
rowndAppKey: string;
|
|
737
740
|
rowndAppSecret: string;
|
|
738
741
|
enableDebugLogs?: boolean;
|
|
742
|
+
mobileDeepLinkBaseUrl?: string;
|
|
739
743
|
telemetry?: RowndTelemetryConfig;
|
|
740
744
|
schema?: RowndSchema;
|
|
741
745
|
appConfig?: RowndAppConfigInput;
|
|
@@ -816,6 +820,19 @@ declare class RowndPluginError extends Error {
|
|
|
816
820
|
constructor(type: RowndPluginErrorType);
|
|
817
821
|
}
|
|
818
822
|
|
|
823
|
+
type RowndEmailContentResult = {
|
|
824
|
+
body: string;
|
|
825
|
+
isHtml: boolean;
|
|
826
|
+
subject: string;
|
|
827
|
+
toEmail: string;
|
|
828
|
+
};
|
|
829
|
+
declare function getRowndPasswordlessEmailContent(input: TypePasswordlessEmailDeliveryInput & {
|
|
830
|
+
userContext?: Record<string, unknown>;
|
|
831
|
+
}, originalContent: RowndEmailContentResult): Promise<RowndEmailContentResult>;
|
|
832
|
+
declare function getRowndEmailVerificationContent(input: TypeEmailVerificationEmailDeliveryInput & {
|
|
833
|
+
userContext?: Record<string, unknown>;
|
|
834
|
+
}, originalContent: RowndEmailContentResult): Promise<RowndEmailContentResult>;
|
|
835
|
+
|
|
819
836
|
declare function setRowndClient(client: IRowndClient): void;
|
|
820
837
|
declare function getRowndClient(): IRowndClient;
|
|
821
838
|
|
|
@@ -823,4 +840,4 @@ declare const _default: {
|
|
|
823
840
|
init: (config: RowndPluginConfig) => SuperTokens.SuperTokensPlugin;
|
|
824
841
|
};
|
|
825
842
|
|
|
826
|
-
export { ANONYMOUS_AUTH_METHOD_ID, DEFAULT_ROWND_SCHEMA, GUEST_AUTH_METHOD_ID, HANDLE_BASE_PATH, type IRowndClient, type MigrationResponse, PLUGIN_ID, PLUGIN_SDK_VERSION, PUBLIC_TENANT_ID, ROWND_JWT_CLAIMS, ROWND_PLUGIN_ERROR_MESSAGES, type RowndAppConfigInput, type RowndAuthConfig, type RowndBranding, type RowndCustomContent, type RowndLegal, type RowndPluginConfig, RowndPluginError, type RowndPluginErrorType, type RowndPluginNormalisedConfig, type RowndProfileConfig, type RowndSchema, type RowndSchemaField, type RowndSignInMethod, type RowndSubBrandConfigInput, type RowndTelemetryClient, type RowndTelemetryConfig, type RowndTelemetryEvent, type RowndUser, type RowndUserMetadata, type SuperTokensUserImport, _default as default, getRowndClient, init, setRowndClient };
|
|
843
|
+
export { ANONYMOUS_AUTH_METHOD_ID, DEFAULT_ROWND_SCHEMA, GUEST_AUTH_METHOD_ID, HANDLE_BASE_PATH, type IRowndClient, type MigrationResponse, PLUGIN_ID, PLUGIN_SDK_VERSION, PUBLIC_TENANT_ID, ROWND_JWT_CLAIMS, ROWND_PLUGIN_ERROR_MESSAGES, type RowndAppConfigInput, type RowndAuthConfig, type RowndBranding, type RowndCustomContent, type RowndEmailContentResult, type RowndLegal, type RowndPluginConfig, RowndPluginError, type RowndPluginErrorType, type RowndPluginNormalisedConfig, type RowndProfileConfig, type RowndSchema, type RowndSchemaField, type RowndSignInMethod, type RowndSubBrandConfigInput, type RowndTelemetryClient, type RowndTelemetryConfig, type RowndTelemetryEvent, type RowndUser, type RowndUserMetadata, type SuperTokensUserImport, _default as default, getRowndClient, getRowndEmailVerificationContent, getRowndPasswordlessEmailContent, init, setRowndClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as SuperTokens from 'supertokens-node';
|
|
2
2
|
import { JSONObject, SuperTokensPlugin } from 'supertokens-node/types';
|
|
3
|
+
import { TypePasswordlessEmailDeliveryInput } from 'supertokens-node/recipe/passwordless/types';
|
|
4
|
+
import { TypeEmailVerificationEmailDeliveryInput } from 'supertokens-node/recipe/emailverification/types';
|
|
3
5
|
|
|
4
6
|
type RowndSignInMethod = {
|
|
5
7
|
/**
|
|
@@ -660,6 +662,7 @@ interface RowndPluginConfig {
|
|
|
660
662
|
rowndAppKey: string;
|
|
661
663
|
rowndAppSecret: string;
|
|
662
664
|
enableDebugLogs?: boolean;
|
|
665
|
+
mobileDeepLinkBaseUrl?: string;
|
|
663
666
|
telemetry?: RowndTelemetryConfig;
|
|
664
667
|
schema?: RowndSchema;
|
|
665
668
|
appConfig?: RowndAppConfigInput;
|
|
@@ -736,6 +739,7 @@ interface RowndPluginNormalisedConfig {
|
|
|
736
739
|
rowndAppKey: string;
|
|
737
740
|
rowndAppSecret: string;
|
|
738
741
|
enableDebugLogs?: boolean;
|
|
742
|
+
mobileDeepLinkBaseUrl?: string;
|
|
739
743
|
telemetry?: RowndTelemetryConfig;
|
|
740
744
|
schema?: RowndSchema;
|
|
741
745
|
appConfig?: RowndAppConfigInput;
|
|
@@ -816,6 +820,19 @@ declare class RowndPluginError extends Error {
|
|
|
816
820
|
constructor(type: RowndPluginErrorType);
|
|
817
821
|
}
|
|
818
822
|
|
|
823
|
+
type RowndEmailContentResult = {
|
|
824
|
+
body: string;
|
|
825
|
+
isHtml: boolean;
|
|
826
|
+
subject: string;
|
|
827
|
+
toEmail: string;
|
|
828
|
+
};
|
|
829
|
+
declare function getRowndPasswordlessEmailContent(input: TypePasswordlessEmailDeliveryInput & {
|
|
830
|
+
userContext?: Record<string, unknown>;
|
|
831
|
+
}, originalContent: RowndEmailContentResult): Promise<RowndEmailContentResult>;
|
|
832
|
+
declare function getRowndEmailVerificationContent(input: TypeEmailVerificationEmailDeliveryInput & {
|
|
833
|
+
userContext?: Record<string, unknown>;
|
|
834
|
+
}, originalContent: RowndEmailContentResult): Promise<RowndEmailContentResult>;
|
|
835
|
+
|
|
819
836
|
declare function setRowndClient(client: IRowndClient): void;
|
|
820
837
|
declare function getRowndClient(): IRowndClient;
|
|
821
838
|
|
|
@@ -823,4 +840,4 @@ declare const _default: {
|
|
|
823
840
|
init: (config: RowndPluginConfig) => SuperTokens.SuperTokensPlugin;
|
|
824
841
|
};
|
|
825
842
|
|
|
826
|
-
export { ANONYMOUS_AUTH_METHOD_ID, DEFAULT_ROWND_SCHEMA, GUEST_AUTH_METHOD_ID, HANDLE_BASE_PATH, type IRowndClient, type MigrationResponse, PLUGIN_ID, PLUGIN_SDK_VERSION, PUBLIC_TENANT_ID, ROWND_JWT_CLAIMS, ROWND_PLUGIN_ERROR_MESSAGES, type RowndAppConfigInput, type RowndAuthConfig, type RowndBranding, type RowndCustomContent, type RowndLegal, type RowndPluginConfig, RowndPluginError, type RowndPluginErrorType, type RowndPluginNormalisedConfig, type RowndProfileConfig, type RowndSchema, type RowndSchemaField, type RowndSignInMethod, type RowndSubBrandConfigInput, type RowndTelemetryClient, type RowndTelemetryConfig, type RowndTelemetryEvent, type RowndUser, type RowndUserMetadata, type SuperTokensUserImport, _default as default, getRowndClient, init, setRowndClient };
|
|
843
|
+
export { ANONYMOUS_AUTH_METHOD_ID, DEFAULT_ROWND_SCHEMA, GUEST_AUTH_METHOD_ID, HANDLE_BASE_PATH, type IRowndClient, type MigrationResponse, PLUGIN_ID, PLUGIN_SDK_VERSION, PUBLIC_TENANT_ID, ROWND_JWT_CLAIMS, ROWND_PLUGIN_ERROR_MESSAGES, type RowndAppConfigInput, type RowndAuthConfig, type RowndBranding, type RowndCustomContent, type RowndEmailContentResult, type RowndLegal, type RowndPluginConfig, RowndPluginError, type RowndPluginErrorType, type RowndPluginNormalisedConfig, type RowndProfileConfig, type RowndSchema, type RowndSchemaField, type RowndSignInMethod, type RowndSubBrandConfigInput, type RowndTelemetryClient, type RowndTelemetryConfig, type RowndTelemetryEvent, type RowndUser, type RowndUserMetadata, type SuperTokensUserImport, _default as default, getRowndClient, getRowndEmailVerificationContent, getRowndPasswordlessEmailContent, init, setRowndClient };
|
package/dist/index.js
CHANGED
|
@@ -279,6 +279,8 @@ __export(index_exports, {
|
|
|
279
279
|
RowndPluginError: () => RowndPluginError,
|
|
280
280
|
default: () => index_default,
|
|
281
281
|
getRowndClient: () => getRowndClient,
|
|
282
|
+
getRowndEmailVerificationContent: () => getRowndEmailVerificationContent,
|
|
283
|
+
getRowndPasswordlessEmailContent: () => getRowndPasswordlessEmailContent,
|
|
282
284
|
init: () => init,
|
|
283
285
|
setRowndClient: () => setRowndClient
|
|
284
286
|
});
|
|
@@ -881,6 +883,26 @@ function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
|
881
883
|
return queryString ? `${path}?${queryString}` : path;
|
|
882
884
|
}
|
|
883
885
|
}
|
|
886
|
+
function rewriteLinkToMobileDeepLink(inputUrl, targetPath, baseUrl, searchParams) {
|
|
887
|
+
const normalizedBaseUrl = baseUrl.endsWith("://") ? baseUrl : baseUrl.replace(/\/+$/, "") + "/";
|
|
888
|
+
const targetUrl = new URL(
|
|
889
|
+
`${normalizedBaseUrl}${targetPath.replace(/^\//, "")}`
|
|
890
|
+
);
|
|
891
|
+
try {
|
|
892
|
+
const sourceUrl = new URL(inputUrl);
|
|
893
|
+
targetUrl.search = sourceUrl.search;
|
|
894
|
+
targetUrl.hash = sourceUrl.hash;
|
|
895
|
+
} catch {
|
|
896
|
+
const [, query = ""] = inputUrl.split("?");
|
|
897
|
+
targetUrl.search = query ? `?${query.split("#")[0]}` : "";
|
|
898
|
+
const hash = inputUrl.split("#")[1];
|
|
899
|
+
targetUrl.hash = hash ? `#${hash}` : "";
|
|
900
|
+
}
|
|
901
|
+
for (const [key, value] of Object.entries(searchParams ?? {})) {
|
|
902
|
+
targetUrl.searchParams.set(key, value);
|
|
903
|
+
}
|
|
904
|
+
return targetUrl.toString();
|
|
905
|
+
}
|
|
884
906
|
var rowndClient;
|
|
885
907
|
var pluginConfig;
|
|
886
908
|
function setRowndClient(client) {
|
|
@@ -895,6 +917,9 @@ function getRowndClient() {
|
|
|
895
917
|
function setPluginConfig(config2) {
|
|
896
918
|
pluginConfig = config2;
|
|
897
919
|
}
|
|
920
|
+
function getPluginConfig() {
|
|
921
|
+
return pluginConfig;
|
|
922
|
+
}
|
|
898
923
|
async function parseRequest(req) {
|
|
899
924
|
const authHeader = req.getHeaderValue("authorization");
|
|
900
925
|
if (!authHeader) {
|
|
@@ -2355,9 +2380,15 @@ var init = createPluginInitFunction(
|
|
|
2355
2380
|
...typeof displayContext === "string" ? { displayContext } : {},
|
|
2356
2381
|
...typeof redirectToPath === "string" ? { redirectToPath } : {}
|
|
2357
2382
|
};
|
|
2383
|
+
const rewrittenLink = input[linkKey] ? displayContext === "mobile_app" && pluginConfig2.mobileDeepLinkBaseUrl ? rewriteLinkToMobileDeepLink(
|
|
2384
|
+
input[linkKey],
|
|
2385
|
+
targetPath,
|
|
2386
|
+
pluginConfig2.mobileDeepLinkBaseUrl,
|
|
2387
|
+
bootstrapParams
|
|
2388
|
+
) : rewriteLinkPath(input[linkKey], targetPath, bootstrapParams) : input[linkKey];
|
|
2358
2389
|
return {
|
|
2359
2390
|
...input,
|
|
2360
|
-
[linkKey]:
|
|
2391
|
+
[linkKey]: rewrittenLink
|
|
2361
2392
|
};
|
|
2362
2393
|
};
|
|
2363
2394
|
setRowndClient(rowndClient2);
|
|
@@ -2720,10 +2751,21 @@ var init = createPluginInitFunction(
|
|
|
2720
2751
|
);
|
|
2721
2752
|
}
|
|
2722
2753
|
}
|
|
2754
|
+
if (config2.mobileDeepLinkBaseUrl !== void 0) {
|
|
2755
|
+
try {
|
|
2756
|
+
if (!/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(config2.mobileDeepLinkBaseUrl)) {
|
|
2757
|
+
throw new Error();
|
|
2758
|
+
}
|
|
2759
|
+
new URL(config2.mobileDeepLinkBaseUrl);
|
|
2760
|
+
} catch {
|
|
2761
|
+
throw new Error("Invalid mobileDeepLinkBaseUrl in plugin config");
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2723
2764
|
return {
|
|
2724
2765
|
rowndAppKey: config2.rowndAppKey,
|
|
2725
2766
|
rowndAppSecret: config2.rowndAppSecret,
|
|
2726
2767
|
enableDebugLogs: config2.enableDebugLogs,
|
|
2768
|
+
mobileDeepLinkBaseUrl: config2.mobileDeepLinkBaseUrl,
|
|
2727
2769
|
telemetry: config2.telemetry,
|
|
2728
2770
|
schema: config2.schema,
|
|
2729
2771
|
appConfig: config2.appConfig,
|
|
@@ -2732,6 +2774,111 @@ var init = createPluginInitFunction(
|
|
|
2732
2774
|
}
|
|
2733
2775
|
);
|
|
2734
2776
|
|
|
2777
|
+
// src/emailContent.ts
|
|
2778
|
+
function getActiveAppConfig(userContext) {
|
|
2779
|
+
const config2 = getPluginConfig();
|
|
2780
|
+
const baseApp = config2?.appConfig;
|
|
2781
|
+
const appVariantId = userContext?.rowndAppVariantId;
|
|
2782
|
+
if (typeof appVariantId === "string" && config2?.subBrands?.[appVariantId]) {
|
|
2783
|
+
return deepMerge(baseApp ?? {}, config2.subBrands[appVariantId]);
|
|
2784
|
+
}
|
|
2785
|
+
return baseApp;
|
|
2786
|
+
}
|
|
2787
|
+
function deepMerge(base, overlay) {
|
|
2788
|
+
const result = { ...base };
|
|
2789
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
2790
|
+
if (value === void 0) {
|
|
2791
|
+
continue;
|
|
2792
|
+
}
|
|
2793
|
+
const existingValue = result[key];
|
|
2794
|
+
if (isRecord2(existingValue) && isRecord2(value)) {
|
|
2795
|
+
result[key] = deepMerge(existingValue, value);
|
|
2796
|
+
} else {
|
|
2797
|
+
result[key] = value;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
return result;
|
|
2801
|
+
}
|
|
2802
|
+
function isRecord2(value) {
|
|
2803
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2804
|
+
}
|
|
2805
|
+
function getEmailConfig(userContext) {
|
|
2806
|
+
return getActiveAppConfig(userContext)?.auth?.email;
|
|
2807
|
+
}
|
|
2808
|
+
function getEmailLink(input) {
|
|
2809
|
+
if (hasOwn2(input, "urlWithLinkCode")) {
|
|
2810
|
+
return input.urlWithLinkCode;
|
|
2811
|
+
}
|
|
2812
|
+
return hasOwn2(input, "emailVerifyLink") ? input.emailVerifyLink : void 0;
|
|
2813
|
+
}
|
|
2814
|
+
function getEmailAddress(input) {
|
|
2815
|
+
if (hasOwn2(input, "email")) {
|
|
2816
|
+
return input.email;
|
|
2817
|
+
}
|
|
2818
|
+
return input.user.email;
|
|
2819
|
+
}
|
|
2820
|
+
function hasOwn2(value, key) {
|
|
2821
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
2822
|
+
}
|
|
2823
|
+
function buildRowndEmailContent(input, originalContent, emailConfig) {
|
|
2824
|
+
if (!emailConfig) {
|
|
2825
|
+
return originalContent;
|
|
2826
|
+
}
|
|
2827
|
+
const appConfig = getActiveAppConfig(input.userContext) ?? {};
|
|
2828
|
+
const link = getEmailLink(input);
|
|
2829
|
+
const callToActionText = emailConfig.callToActionText ?? "Verify your email";
|
|
2830
|
+
if (!link) {
|
|
2831
|
+
return {
|
|
2832
|
+
...originalContent,
|
|
2833
|
+
subject: emailConfig.subject ?? originalContent.subject
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
return {
|
|
2837
|
+
...originalContent,
|
|
2838
|
+
toEmail: getEmailAddress(input),
|
|
2839
|
+
subject: emailConfig.subject ?? originalContent.subject,
|
|
2840
|
+
isHtml: true,
|
|
2841
|
+
body: renderEmailHtml({
|
|
2842
|
+
appConfig,
|
|
2843
|
+
emailConfig,
|
|
2844
|
+
link,
|
|
2845
|
+
callToActionText,
|
|
2846
|
+
originalBody: originalContent.body
|
|
2847
|
+
})
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2850
|
+
function renderEmailHtml(input) {
|
|
2851
|
+
const primaryColor = input.appConfig.branding?.primaryColor ?? DEFAULT_PRIMARY_COLOR;
|
|
2852
|
+
const image = input.emailConfig.image || input.appConfig.branding?.logo || input.appConfig.icon;
|
|
2853
|
+
const appName = input.appConfig.name ?? "Application";
|
|
2854
|
+
const content = input.emailConfig.customContent ?? input.originalBody;
|
|
2855
|
+
return `<!doctype html>
|
|
2856
|
+
<html>
|
|
2857
|
+
<body style="font-family: Arial, sans-serif; color: #1f2937; margin: 0; padding: 32px; background: #f9fafb;">
|
|
2858
|
+
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="max-width: 560px; margin: 0 auto; background: #ffffff; border-radius: 16px; padding: 32px;">
|
|
2859
|
+
<tr>
|
|
2860
|
+
<td style="text-align: center;">
|
|
2861
|
+
${image ? `<img src="${escapeHtml(image)}" alt="${escapeHtml(appName)}" style="max-width: 96px; max-height: 96px; margin-bottom: 24px;" />` : ""}
|
|
2862
|
+
<div style="font-size: 18px; font-weight: 600; margin-bottom: 16px;">${escapeHtml(appName)}</div>
|
|
2863
|
+
<div style="font-size: 15px; line-height: 1.6; margin-bottom: 24px;">${content}</div>
|
|
2864
|
+
<a href="${escapeHtml(input.link)}" style="display: inline-block; background: ${escapeHtml(primaryColor)}; color: #ffffff; text-decoration: none; padding: 12px 20px; border-radius: 10px; font-weight: 600;">${escapeHtml(input.callToActionText)}</a>
|
|
2865
|
+
${input.emailConfig.customClosingContent ? `<div style="font-size: 14px; line-height: 1.6; margin-top: 24px;">${input.emailConfig.customClosingContent}</div>` : ""}
|
|
2866
|
+
</td>
|
|
2867
|
+
</tr>
|
|
2868
|
+
</table>
|
|
2869
|
+
</body>
|
|
2870
|
+
</html>`;
|
|
2871
|
+
}
|
|
2872
|
+
function escapeHtml(value) {
|
|
2873
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2874
|
+
}
|
|
2875
|
+
async function getRowndPasswordlessEmailContent(input, originalContent) {
|
|
2876
|
+
return buildRowndEmailContent(input, originalContent, getEmailConfig(input.userContext));
|
|
2877
|
+
}
|
|
2878
|
+
async function getRowndEmailVerificationContent(input, originalContent) {
|
|
2879
|
+
return buildRowndEmailContent(input, originalContent, getEmailConfig(input.userContext));
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2735
2882
|
// src/index.ts
|
|
2736
2883
|
var index_default = { init };
|
|
2737
2884
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -2747,6 +2894,8 @@ var index_default = { init };
|
|
|
2747
2894
|
ROWND_PLUGIN_ERROR_MESSAGES,
|
|
2748
2895
|
RowndPluginError,
|
|
2749
2896
|
getRowndClient,
|
|
2897
|
+
getRowndEmailVerificationContent,
|
|
2898
|
+
getRowndPasswordlessEmailContent,
|
|
2750
2899
|
init,
|
|
2751
2900
|
setRowndClient
|
|
2752
2901
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -861,6 +861,26 @@ function rewriteLinkPath(inputUrl, targetPath, searchParams) {
|
|
|
861
861
|
return queryString ? `${path}?${queryString}` : path;
|
|
862
862
|
}
|
|
863
863
|
}
|
|
864
|
+
function rewriteLinkToMobileDeepLink(inputUrl, targetPath, baseUrl, searchParams) {
|
|
865
|
+
const normalizedBaseUrl = baseUrl.endsWith("://") ? baseUrl : baseUrl.replace(/\/+$/, "") + "/";
|
|
866
|
+
const targetUrl = new URL(
|
|
867
|
+
`${normalizedBaseUrl}${targetPath.replace(/^\//, "")}`
|
|
868
|
+
);
|
|
869
|
+
try {
|
|
870
|
+
const sourceUrl = new URL(inputUrl);
|
|
871
|
+
targetUrl.search = sourceUrl.search;
|
|
872
|
+
targetUrl.hash = sourceUrl.hash;
|
|
873
|
+
} catch {
|
|
874
|
+
const [, query = ""] = inputUrl.split("?");
|
|
875
|
+
targetUrl.search = query ? `?${query.split("#")[0]}` : "";
|
|
876
|
+
const hash = inputUrl.split("#")[1];
|
|
877
|
+
targetUrl.hash = hash ? `#${hash}` : "";
|
|
878
|
+
}
|
|
879
|
+
for (const [key, value] of Object.entries(searchParams ?? {})) {
|
|
880
|
+
targetUrl.searchParams.set(key, value);
|
|
881
|
+
}
|
|
882
|
+
return targetUrl.toString();
|
|
883
|
+
}
|
|
864
884
|
var rowndClient;
|
|
865
885
|
var pluginConfig;
|
|
866
886
|
function setRowndClient(client) {
|
|
@@ -875,6 +895,9 @@ function getRowndClient() {
|
|
|
875
895
|
function setPluginConfig(config2) {
|
|
876
896
|
pluginConfig = config2;
|
|
877
897
|
}
|
|
898
|
+
function getPluginConfig() {
|
|
899
|
+
return pluginConfig;
|
|
900
|
+
}
|
|
878
901
|
async function parseRequest(req) {
|
|
879
902
|
const authHeader = req.getHeaderValue("authorization");
|
|
880
903
|
if (!authHeader) {
|
|
@@ -2335,9 +2358,15 @@ var init = createPluginInitFunction(
|
|
|
2335
2358
|
...typeof displayContext === "string" ? { displayContext } : {},
|
|
2336
2359
|
...typeof redirectToPath === "string" ? { redirectToPath } : {}
|
|
2337
2360
|
};
|
|
2361
|
+
const rewrittenLink = input[linkKey] ? displayContext === "mobile_app" && pluginConfig2.mobileDeepLinkBaseUrl ? rewriteLinkToMobileDeepLink(
|
|
2362
|
+
input[linkKey],
|
|
2363
|
+
targetPath,
|
|
2364
|
+
pluginConfig2.mobileDeepLinkBaseUrl,
|
|
2365
|
+
bootstrapParams
|
|
2366
|
+
) : rewriteLinkPath(input[linkKey], targetPath, bootstrapParams) : input[linkKey];
|
|
2338
2367
|
return {
|
|
2339
2368
|
...input,
|
|
2340
|
-
[linkKey]:
|
|
2369
|
+
[linkKey]: rewrittenLink
|
|
2341
2370
|
};
|
|
2342
2371
|
};
|
|
2343
2372
|
setRowndClient(rowndClient2);
|
|
@@ -2700,10 +2729,21 @@ var init = createPluginInitFunction(
|
|
|
2700
2729
|
);
|
|
2701
2730
|
}
|
|
2702
2731
|
}
|
|
2732
|
+
if (config2.mobileDeepLinkBaseUrl !== void 0) {
|
|
2733
|
+
try {
|
|
2734
|
+
if (!/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(config2.mobileDeepLinkBaseUrl)) {
|
|
2735
|
+
throw new Error();
|
|
2736
|
+
}
|
|
2737
|
+
new URL(config2.mobileDeepLinkBaseUrl);
|
|
2738
|
+
} catch {
|
|
2739
|
+
throw new Error("Invalid mobileDeepLinkBaseUrl in plugin config");
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2703
2742
|
return {
|
|
2704
2743
|
rowndAppKey: config2.rowndAppKey,
|
|
2705
2744
|
rowndAppSecret: config2.rowndAppSecret,
|
|
2706
2745
|
enableDebugLogs: config2.enableDebugLogs,
|
|
2746
|
+
mobileDeepLinkBaseUrl: config2.mobileDeepLinkBaseUrl,
|
|
2707
2747
|
telemetry: config2.telemetry,
|
|
2708
2748
|
schema: config2.schema,
|
|
2709
2749
|
appConfig: config2.appConfig,
|
|
@@ -2712,6 +2752,111 @@ var init = createPluginInitFunction(
|
|
|
2712
2752
|
}
|
|
2713
2753
|
);
|
|
2714
2754
|
|
|
2755
|
+
// src/emailContent.ts
|
|
2756
|
+
function getActiveAppConfig(userContext) {
|
|
2757
|
+
const config2 = getPluginConfig();
|
|
2758
|
+
const baseApp = config2?.appConfig;
|
|
2759
|
+
const appVariantId = userContext?.rowndAppVariantId;
|
|
2760
|
+
if (typeof appVariantId === "string" && config2?.subBrands?.[appVariantId]) {
|
|
2761
|
+
return deepMerge(baseApp ?? {}, config2.subBrands[appVariantId]);
|
|
2762
|
+
}
|
|
2763
|
+
return baseApp;
|
|
2764
|
+
}
|
|
2765
|
+
function deepMerge(base, overlay) {
|
|
2766
|
+
const result = { ...base };
|
|
2767
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
2768
|
+
if (value === void 0) {
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
const existingValue = result[key];
|
|
2772
|
+
if (isRecord2(existingValue) && isRecord2(value)) {
|
|
2773
|
+
result[key] = deepMerge(existingValue, value);
|
|
2774
|
+
} else {
|
|
2775
|
+
result[key] = value;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
return result;
|
|
2779
|
+
}
|
|
2780
|
+
function isRecord2(value) {
|
|
2781
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2782
|
+
}
|
|
2783
|
+
function getEmailConfig(userContext) {
|
|
2784
|
+
return getActiveAppConfig(userContext)?.auth?.email;
|
|
2785
|
+
}
|
|
2786
|
+
function getEmailLink(input) {
|
|
2787
|
+
if (hasOwn2(input, "urlWithLinkCode")) {
|
|
2788
|
+
return input.urlWithLinkCode;
|
|
2789
|
+
}
|
|
2790
|
+
return hasOwn2(input, "emailVerifyLink") ? input.emailVerifyLink : void 0;
|
|
2791
|
+
}
|
|
2792
|
+
function getEmailAddress(input) {
|
|
2793
|
+
if (hasOwn2(input, "email")) {
|
|
2794
|
+
return input.email;
|
|
2795
|
+
}
|
|
2796
|
+
return input.user.email;
|
|
2797
|
+
}
|
|
2798
|
+
function hasOwn2(value, key) {
|
|
2799
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
2800
|
+
}
|
|
2801
|
+
function buildRowndEmailContent(input, originalContent, emailConfig) {
|
|
2802
|
+
if (!emailConfig) {
|
|
2803
|
+
return originalContent;
|
|
2804
|
+
}
|
|
2805
|
+
const appConfig = getActiveAppConfig(input.userContext) ?? {};
|
|
2806
|
+
const link = getEmailLink(input);
|
|
2807
|
+
const callToActionText = emailConfig.callToActionText ?? "Verify your email";
|
|
2808
|
+
if (!link) {
|
|
2809
|
+
return {
|
|
2810
|
+
...originalContent,
|
|
2811
|
+
subject: emailConfig.subject ?? originalContent.subject
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
return {
|
|
2815
|
+
...originalContent,
|
|
2816
|
+
toEmail: getEmailAddress(input),
|
|
2817
|
+
subject: emailConfig.subject ?? originalContent.subject,
|
|
2818
|
+
isHtml: true,
|
|
2819
|
+
body: renderEmailHtml({
|
|
2820
|
+
appConfig,
|
|
2821
|
+
emailConfig,
|
|
2822
|
+
link,
|
|
2823
|
+
callToActionText,
|
|
2824
|
+
originalBody: originalContent.body
|
|
2825
|
+
})
|
|
2826
|
+
};
|
|
2827
|
+
}
|
|
2828
|
+
function renderEmailHtml(input) {
|
|
2829
|
+
const primaryColor = input.appConfig.branding?.primaryColor ?? DEFAULT_PRIMARY_COLOR;
|
|
2830
|
+
const image = input.emailConfig.image || input.appConfig.branding?.logo || input.appConfig.icon;
|
|
2831
|
+
const appName = input.appConfig.name ?? "Application";
|
|
2832
|
+
const content = input.emailConfig.customContent ?? input.originalBody;
|
|
2833
|
+
return `<!doctype html>
|
|
2834
|
+
<html>
|
|
2835
|
+
<body style="font-family: Arial, sans-serif; color: #1f2937; margin: 0; padding: 32px; background: #f9fafb;">
|
|
2836
|
+
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="max-width: 560px; margin: 0 auto; background: #ffffff; border-radius: 16px; padding: 32px;">
|
|
2837
|
+
<tr>
|
|
2838
|
+
<td style="text-align: center;">
|
|
2839
|
+
${image ? `<img src="${escapeHtml(image)}" alt="${escapeHtml(appName)}" style="max-width: 96px; max-height: 96px; margin-bottom: 24px;" />` : ""}
|
|
2840
|
+
<div style="font-size: 18px; font-weight: 600; margin-bottom: 16px;">${escapeHtml(appName)}</div>
|
|
2841
|
+
<div style="font-size: 15px; line-height: 1.6; margin-bottom: 24px;">${content}</div>
|
|
2842
|
+
<a href="${escapeHtml(input.link)}" style="display: inline-block; background: ${escapeHtml(primaryColor)}; color: #ffffff; text-decoration: none; padding: 12px 20px; border-radius: 10px; font-weight: 600;">${escapeHtml(input.callToActionText)}</a>
|
|
2843
|
+
${input.emailConfig.customClosingContent ? `<div style="font-size: 14px; line-height: 1.6; margin-top: 24px;">${input.emailConfig.customClosingContent}</div>` : ""}
|
|
2844
|
+
</td>
|
|
2845
|
+
</tr>
|
|
2846
|
+
</table>
|
|
2847
|
+
</body>
|
|
2848
|
+
</html>`;
|
|
2849
|
+
}
|
|
2850
|
+
function escapeHtml(value) {
|
|
2851
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2852
|
+
}
|
|
2853
|
+
async function getRowndPasswordlessEmailContent(input, originalContent) {
|
|
2854
|
+
return buildRowndEmailContent(input, originalContent, getEmailConfig(input.userContext));
|
|
2855
|
+
}
|
|
2856
|
+
async function getRowndEmailVerificationContent(input, originalContent) {
|
|
2857
|
+
return buildRowndEmailContent(input, originalContent, getEmailConfig(input.userContext));
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2715
2860
|
// src/index.ts
|
|
2716
2861
|
var index_default = { init };
|
|
2717
2862
|
export {
|
|
@@ -2727,6 +2872,8 @@ export {
|
|
|
2727
2872
|
RowndPluginError,
|
|
2728
2873
|
index_default as default,
|
|
2729
2874
|
getRowndClient,
|
|
2875
|
+
getRowndEmailVerificationContent,
|
|
2876
|
+
getRowndPasswordlessEmailContent,
|
|
2730
2877
|
init,
|
|
2731
2878
|
setRowndClient
|
|
2732
2879
|
};
|