-
Notifications
You must be signed in to change notification settings - Fork 498
resend api key config #851
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
772f7ec
83fd955
060335c
2a08ae7
8bab612
0f1c9a3
7461754
e654986
e5eb478
d5fa738
773d5e5
3e4262d
83cf1c4
e48d423
0e6ecc6
fa0ee35
33f8d6d
c7985ff
8fc939d
b9e0630
76c45cf
856c0c5
fa1bc34
3c34140
88a10cf
9594392
c7ebb00
615fd72
0b57f9e
795c404
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,18 +10,19 @@ import { strictEmailSchema } from "@stackframe/stack-shared/dist/schema-fields"; | |||||||||||||||||||||||||||||||
| import { throwErr } from "@stackframe/stack-shared/dist/utils/errors"; | ||||||||||||||||||||||||||||||||
| import { deepPlainEquals } from "@stackframe/stack-shared/dist/utils/objects"; | ||||||||||||||||||||||||||||||||
| import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises"; | ||||||||||||||||||||||||||||||||
| import { ActionDialog, Alert, Button, DataTable, SimpleTooltip, Typography, useToast, Input, Textarea, TooltipProvider, TooltipTrigger, TooltipContent, Tooltip, AlertDescription, AlertTitle } from "@stackframe/stack-ui"; | ||||||||||||||||||||||||||||||||
| import { ActionDialog, Alert, Button, DataTable, SimpleTooltip, Typography, useToast, TooltipProvider, TooltipTrigger, TooltipContent, Tooltip, AlertDescription, AlertTitle } from "@stackframe/stack-ui"; | ||||||||||||||||||||||||||||||||
| import { ColumnDef } from "@tanstack/react-table"; | ||||||||||||||||||||||||||||||||
| import { AlertCircle, X } from "lucide-react"; | ||||||||||||||||||||||||||||||||
| import { useEffect, useMemo, useState } from "react"; | ||||||||||||||||||||||||||||||||
| import * as yup from "yup"; | ||||||||||||||||||||||||||||||||
| import { PageLayout } from "../page-layout"; | ||||||||||||||||||||||||||||||||
| import { useAdminApp } from "../use-admin-app"; | ||||||||||||||||||||||||||||||||
| import { CompleteConfig } from "@stackframe/stack-shared/dist/config/schema"; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| export default function PageClient() { | ||||||||||||||||||||||||||||||||
| const stackAdminApp = useAdminApp(); | ||||||||||||||||||||||||||||||||
| const project = stackAdminApp.useProject(); | ||||||||||||||||||||||||||||||||
| const emailConfig = project.config.emailConfig; | ||||||||||||||||||||||||||||||||
| const emailConfig = project.useConfig().emails.server; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||
| <PageLayout | ||||||||||||||||||||||||||||||||
|
|
@@ -30,7 +31,7 @@ export default function PageClient() { | |||||||||||||||||||||||||||||||
| actions={ | ||||||||||||||||||||||||||||||||
| <SendEmailDialog | ||||||||||||||||||||||||||||||||
| trigger={<Button>Send Email</Button>} | ||||||||||||||||||||||||||||||||
| emailConfigType={emailConfig?.type} | ||||||||||||||||||||||||||||||||
| emailConfig={emailConfig} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
|
|
@@ -51,21 +52,21 @@ export default function PageClient() { | |||||||||||||||||||||||||||||||
| description="Configure the email server and sender address for outgoing emails" | ||||||||||||||||||||||||||||||||
| actions={ | ||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-2"> | ||||||||||||||||||||||||||||||||
| {emailConfig?.type === 'standard' && <TestSendingDialog trigger={<Button variant='secondary' className="w-full">Send Test Email</Button>} />} | ||||||||||||||||||||||||||||||||
| {!emailConfig.isShared && <TestSendingDialog trigger={<Button variant='secondary' className="w-full">Send Test Email</Button>} />} | ||||||||||||||||||||||||||||||||
| <EditEmailServerDialog trigger={<Button variant='secondary' className="w-full">Configure</Button>} /> | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||
| <SettingText label="Server"> | ||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-2"> | ||||||||||||||||||||||||||||||||
| {emailConfig?.type === 'standard' ? | ||||||||||||||||||||||||||||||||
| 'Custom SMTP server' : | ||||||||||||||||||||||||||||||||
| {emailConfig.isShared ? | ||||||||||||||||||||||||||||||||
| <>Shared <SimpleTooltip tooltip="When you use the shared email server, all the emails are sent from Stack's email address" type='info' /></> | ||||||||||||||||||||||||||||||||
| : (emailConfig.provider === 'resend' ? "Resend" : "Custom SMTP server") | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||
| </SettingText> | ||||||||||||||||||||||||||||||||
| <SettingText label="Sender Email"> | ||||||||||||||||||||||||||||||||
| {emailConfig?.type === 'standard' ? emailConfig.senderEmail : '[email protected]'} | ||||||||||||||||||||||||||||||||
| {emailConfig.isShared ? '[email protected]' : emailConfig.senderEmail} | ||||||||||||||||||||||||||||||||
| </SettingText> | ||||||||||||||||||||||||||||||||
| </SettingCard> | ||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||
|
|
@@ -76,19 +77,26 @@ export default function PageClient() { | |||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| function definedWhenNotShared<S extends yup.AnyObject>(schema: S, message: string): S { | ||||||||||||||||||||||||||||||||
| function definedWhenTypeIsOneOf<S extends yup.AnyObject>(schema: S, types: string[], message: string): S { | ||||||||||||||||||||||||||||||||
| return schema.when('type', { | ||||||||||||||||||||||||||||||||
| is: 'standard', | ||||||||||||||||||||||||||||||||
| is: (t: string) => types.includes(t), | ||||||||||||||||||||||||||||||||
| then: (schema: S) => schema.defined(message), | ||||||||||||||||||||||||||||||||
| otherwise: (schema: S) => schema.optional() | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Comment on lines
+80
to
86
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix Biome “noThenProperty” lint error and broaden generic. Use the functional -function definedWhenTypeIsOneOf<S extends yup.AnyObject>(schema: S, types: string[], message: string): S {
- return schema.when('type', {
- is: (t: string) => types.includes(t),
- then: (schema: S) => schema.defined(message),
- otherwise: (schema: S) => schema.optional()
- });
-}
+function definedWhenTypeIsOneOf<S extends yup.AnySchema>(schema: S, types: string[], message: string): S {
+ // Avoid "then" property (thenable) objects per lint rule.
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return (schema as any).when('type', (val: unknown, s: S) =>
+ types.includes(String(val)) ? s.defined(message) : s.optional()
+ );
+}📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (2.1.2)[error] 83-83: Do not add then to an object. (lint/suspicious/noThenProperty) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const getDefaultValues = (emailConfig: AdminEmailConfig | undefined, project: AdminProject) => { | ||||||||||||||||||||||||||||||||
| const getDefaultValues = (emailConfig: CompleteConfig['emails']['server'] | undefined, project: AdminProject) => { | ||||||||||||||||||||||||||||||||
| if (!emailConfig) { | ||||||||||||||||||||||||||||||||
| return { type: 'shared', senderName: project.displayName } as const; | ||||||||||||||||||||||||||||||||
| } else if (emailConfig.type === 'shared') { | ||||||||||||||||||||||||||||||||
| } else if (emailConfig.isShared) { | ||||||||||||||||||||||||||||||||
| return { type: 'shared' } as const; | ||||||||||||||||||||||||||||||||
| } else if (emailConfig.provider === 'resend') { | ||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||
| type: 'resend', | ||||||||||||||||||||||||||||||||
| senderEmail: emailConfig.senderEmail, | ||||||||||||||||||||||||||||||||
| senderName: emailConfig.senderName, | ||||||||||||||||||||||||||||||||
| password: emailConfig.password, | ||||||||||||||||||||||||||||||||
| } as const; | ||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||
| type: 'standard', | ||||||||||||||||||||||||||||||||
|
|
@@ -103,25 +111,59 @@ const getDefaultValues = (emailConfig: AdminEmailConfig | undefined, project: Ad | |||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const emailServerSchema = yup.object({ | ||||||||||||||||||||||||||||||||
| type: yup.string().oneOf(['shared', 'standard']).defined(), | ||||||||||||||||||||||||||||||||
| host: definedWhenNotShared(yup.string(), "Host is required"), | ||||||||||||||||||||||||||||||||
| port: definedWhenNotShared(yup.number().min(0, "Port must be a number between 0 and 65535").max(65535, "Port must be a number between 0 and 65535"), "Port is required"), | ||||||||||||||||||||||||||||||||
| username: definedWhenNotShared(yup.string(), "Username is required"), | ||||||||||||||||||||||||||||||||
| password: definedWhenNotShared(yup.string(), "Password is required"), | ||||||||||||||||||||||||||||||||
| senderEmail: definedWhenNotShared(strictEmailSchema("Sender email must be a valid email"), "Sender email is required"), | ||||||||||||||||||||||||||||||||
| senderName: definedWhenNotShared(yup.string(), "Email sender name is required"), | ||||||||||||||||||||||||||||||||
| type: yup.string().oneOf(['shared', 'standard', 'resend']).defined(), | ||||||||||||||||||||||||||||||||
| host: definedWhenTypeIsOneOf(yup.string(), ["standard"], "Host is required"), | ||||||||||||||||||||||||||||||||
| port: definedWhenTypeIsOneOf(yup.number().min(0, "Port must be a number between 0 and 65535").max(65535, "Port must be a number between 0 and 65535"), ["standard"], "Port is required"), | ||||||||||||||||||||||||||||||||
| username: definedWhenTypeIsOneOf(yup.string(), ["standard"], "Username is required"), | ||||||||||||||||||||||||||||||||
| password: definedWhenTypeIsOneOf(yup.string(), ["standard", "resend"], "Password is required"), | ||||||||||||||||||||||||||||||||
| senderEmail: definedWhenTypeIsOneOf(strictEmailSchema("Sender email must be a valid email"), ["standard", "resend"], "Sender email is required"), | ||||||||||||||||||||||||||||||||
| senderName: definedWhenTypeIsOneOf(yup.string(), ["standard", "resend"], "Email sender name is required"), | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| function EditEmailServerDialog(props: { | ||||||||||||||||||||||||||||||||
| trigger: React.ReactNode, | ||||||||||||||||||||||||||||||||
| }) { | ||||||||||||||||||||||||||||||||
| const stackAdminApp = useAdminApp(); | ||||||||||||||||||||||||||||||||
| const project = stackAdminApp.useProject(); | ||||||||||||||||||||||||||||||||
| const config = project.useConfig(); | ||||||||||||||||||||||||||||||||
| const [error, setError] = useState<string | null>(null); | ||||||||||||||||||||||||||||||||
| const [formValues, setFormValues] = useState<any>(null); | ||||||||||||||||||||||||||||||||
| const defaultValues = useMemo(() => getDefaultValues(project.config.emailConfig, project), [project]); | ||||||||||||||||||||||||||||||||
| const defaultValues = useMemo(() => getDefaultValues(config.emails.server, project), [config, project]); | ||||||||||||||||||||||||||||||||
| const { toast } = useToast(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| async function testEmailAndUpdateConfig(emailConfig: AdminEmailConfig & { type: "standard" | "resend" }) { | ||||||||||||||||||||||||||||||||
| const testResult = await stackAdminApp.sendTestEmail({ | ||||||||||||||||||||||||||||||||
| recipientEmail: '[email protected]', | ||||||||||||||||||||||||||||||||
| emailConfig, | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (testResult.status === 'error') { | ||||||||||||||||||||||||||||||||
| setError(testResult.error.errorMessage); | ||||||||||||||||||||||||||||||||
| return 'prevent-close-and-prevent-reset'; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| setError(null); | ||||||||||||||||||||||||||||||||
| await project.updateConfig({ | ||||||||||||||||||||||||||||||||
| emails: { | ||||||||||||||||||||||||||||||||
| server: { | ||||||||||||||||||||||||||||||||
| isShared: false, | ||||||||||||||||||||||||||||||||
| host: emailConfig.host, | ||||||||||||||||||||||||||||||||
| port: emailConfig.port, | ||||||||||||||||||||||||||||||||
| username: emailConfig.username, | ||||||||||||||||||||||||||||||||
| password: emailConfig.password, | ||||||||||||||||||||||||||||||||
| senderEmail: emailConfig.senderEmail, | ||||||||||||||||||||||||||||||||
| senderName: emailConfig.senderName, | ||||||||||||||||||||||||||||||||
| provider: emailConfig.type === 'resend' ? 'resend' : 'smtp', | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| toast({ | ||||||||||||||||||||||||||||||||
| title: "Email server updated", | ||||||||||||||||||||||||||||||||
| description: "The email server has been updated. You can now send test emails to verify the configuration.", | ||||||||||||||||||||||||||||||||
| variant: 'success', | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return <FormDialog | ||||||||||||||||||||||||||||||||
| trigger={props.trigger} | ||||||||||||||||||||||||||||||||
| title="Edit Email Server" | ||||||||||||||||||||||||||||||||
|
|
@@ -135,45 +177,31 @@ function EditEmailServerDialog(props: { | |||||||||||||||||||||||||||||||
| emailConfig: { type: 'shared' } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
| } else if (values.type === 'resend') { | ||||||||||||||||||||||||||||||||
| if (!values.password || !values.senderEmail || !values.senderName) { | ||||||||||||||||||||||||||||||||
| throwErr("Missing email server config for Resend"); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| return await testEmailAndUpdateConfig({ | ||||||||||||||||||||||||||||||||
| type: 'resend', | ||||||||||||||||||||||||||||||||
| host: 'smtp.resend.com', | ||||||||||||||||||||||||||||||||
| port: 465, | ||||||||||||||||||||||||||||||||
| username: 'resend', | ||||||||||||||||||||||||||||||||
| password: values.password, | ||||||||||||||||||||||||||||||||
| senderEmail: values.senderEmail, | ||||||||||||||||||||||||||||||||
| senderName: values.senderName, | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||
| if (!values.host || !values.port || !values.username || !values.password || !values.senderEmail || !values.senderName) { | ||||||||||||||||||||||||||||||||
| throwErr("Missing email server config for custom SMTP server"); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const emailConfig = { | ||||||||||||||||||||||||||||||||
| return await testEmailAndUpdateConfig({ | ||||||||||||||||||||||||||||||||
| type: 'standard', | ||||||||||||||||||||||||||||||||
| host: values.host, | ||||||||||||||||||||||||||||||||
| port: values.port, | ||||||||||||||||||||||||||||||||
| username: values.username, | ||||||||||||||||||||||||||||||||
| password: values.password, | ||||||||||||||||||||||||||||||||
| senderEmail: values.senderEmail, | ||||||||||||||||||||||||||||||||
| senderName: values.senderName, | ||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const testResult = await stackAdminApp.sendTestEmail({ | ||||||||||||||||||||||||||||||||
| recipientEmail: '[email protected]', | ||||||||||||||||||||||||||||||||
| emailConfig: emailConfig, | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (testResult.status === 'error') { | ||||||||||||||||||||||||||||||||
| setError(testResult.error.errorMessage); | ||||||||||||||||||||||||||||||||
| return 'prevent-close-and-prevent-reset'; | ||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||
| setError(null); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| await project.update({ | ||||||||||||||||||||||||||||||||
| config: { | ||||||||||||||||||||||||||||||||
| emailConfig: { | ||||||||||||||||||||||||||||||||
| type: 'standard', | ||||||||||||||||||||||||||||||||
| ...emailConfig, | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| toast({ | ||||||||||||||||||||||||||||||||
| title: "Email server updated", | ||||||||||||||||||||||||||||||||
| description: "The email server has been updated. You can now send test emails to verify the configuration.", | ||||||||||||||||||||||||||||||||
| variant: 'success', | ||||||||||||||||||||||||||||||||
| senderName: values.senderName | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||
|
|
@@ -193,9 +221,26 @@ function EditEmailServerDialog(props: { | |||||||||||||||||||||||||||||||
| control={form.control} | ||||||||||||||||||||||||||||||||
| options={[ | ||||||||||||||||||||||||||||||||
| { label: "Shared ([email protected])", value: 'shared' }, | ||||||||||||||||||||||||||||||||
| { label: "Resend (your own email address)", value: 'resend' }, | ||||||||||||||||||||||||||||||||
| { label: "Custom SMTP server (your own email address)", value: 'standard' }, | ||||||||||||||||||||||||||||||||
| ]} | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| {form.watch('type') === 'resend' && <> | ||||||||||||||||||||||||||||||||
| {([ | ||||||||||||||||||||||||||||||||
| { label: "Resend API Key", name: "password", type: 'password' }, | ||||||||||||||||||||||||||||||||
| { label: "Sender Email", name: "senderEmail", type: 'email' }, | ||||||||||||||||||||||||||||||||
| { label: "Sender Name", name: "senderName", type: 'text' }, | ||||||||||||||||||||||||||||||||
| ] as const).map((field) => ( | ||||||||||||||||||||||||||||||||
| <InputField | ||||||||||||||||||||||||||||||||
| key={field.name} | ||||||||||||||||||||||||||||||||
| label={field.label} | ||||||||||||||||||||||||||||||||
| name={field.name} | ||||||||||||||||||||||||||||||||
| control={form.control} | ||||||||||||||||||||||||||||||||
| type={field.type} | ||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||
| </>} | ||||||||||||||||||||||||||||||||
| {form.watch('type') === 'standard' && <> | ||||||||||||||||||||||||||||||||
| {([ | ||||||||||||||||||||||||||||||||
| { label: "Host", name: "host", type: 'text' }, | ||||||||||||||||||||||||||||||||
|
|
@@ -327,7 +372,7 @@ function EmailSendDataTable() { | |||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| function SendEmailDialog(props: { | ||||||||||||||||||||||||||||||||
| trigger: React.ReactNode, | ||||||||||||||||||||||||||||||||
| emailConfigType?: AdminEmailConfig['type'], | ||||||||||||||||||||||||||||||||
| emailConfig: CompleteConfig['emails']['server'], | ||||||||||||||||||||||||||||||||
| }) { | ||||||||||||||||||||||||||||||||
| const stackAdminApp = useAdminApp(); | ||||||||||||||||||||||||||||||||
| const { toast } = useToast(); | ||||||||||||||||||||||||||||||||
|
|
@@ -420,7 +465,7 @@ function SendEmailDialog(props: { | |||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||
| onClick={() => { | ||||||||||||||||||||||||||||||||
| if (props.emailConfigType === 'standard') { | ||||||||||||||||||||||||||||||||
| if (!props.emailConfig.isShared) { | ||||||||||||||||||||||||||||||||
| setOpen(true); | ||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||
| setSharedSmtpDialogOpen(true); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,7 +39,7 @@ export type AdminProjectConfig = { | |
|
|
||
| export type AdminEmailConfig = ( | ||
| { | ||
| type: "standard", | ||
| type: "standard" | "resend", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Adding 'resend' to the type union but requiring SMTP fields (host, port, username, password) creates a configuration mismatch since Resend uses API keys, not SMTP credentials
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea shouldn't this be another union option? |
||
| senderName: string, | ||
| senderEmail: string, | ||
| host: string, | ||
|
|
@@ -60,15 +60,15 @@ export type AdminDomainConfig = { | |
| export type AdminOAuthProviderConfig = { | ||
| id: string, | ||
| } & ( | ||
| | { type: 'shared' } | ||
| | { | ||
| type: 'standard', | ||
| clientId: string, | ||
| clientSecret: string, | ||
| facebookConfigId?: string, | ||
| microsoftTenantId?: string, | ||
| } | ||
| ) & OAuthProviderConfig; | ||
| | { type: 'shared' } | ||
| | { | ||
| type: 'standard', | ||
| clientId: string, | ||
| clientSecret: string, | ||
| facebookConfigId?: string, | ||
| microsoftTenantId?: string, | ||
| } | ||
| ) & OAuthProviderConfig; | ||
|
|
||
| export type AdminProjectConfigUpdateOptions = { | ||
| domains?: { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.