import { EmailError } from '../map-error.js' const COPY = Object.freeze({ en: { subject: 'Your VOKO invite', heading: 'Your VOKO invite is ready', intro: 'Use the link below to finish registration.', action: 'Finish registration', warning: 'This invite link expires and should not be shared.', }, zh: { subject: '您的 VOKO 邀请', heading: '您的 VOKO 邀请已准备就绪', intro: '请使用下方链接完成注册。', action: '完成注册', warning: '该邀请链接会过期,请勿分享给他人。', }, ja: { subject: 'VOKOへの招待', heading: 'VOKOへの招待の準備ができました', intro: '以下のリンクから登録を完了してください。', action: '登録を完了', warning: 'この招待リンクには有効期限があります。他の人と共有しないでください。', }, ko: { subject: 'VOKO 초대', heading: 'VOKO 초대가 준비되었습니다', intro: '아래 링크를 사용해 가입을 완료하세요.', action: '가입 완료', warning: '이 초대 링크는 만료되며 다른 사람과 공유하면 안 됩니다.', }, es: { subject: 'Tu invitación a VOKO', heading: 'Tu invitación a VOKO está lista', intro: 'Usa el siguiente enlace para completar el registro.', action: 'Completar registro', warning: 'Este enlace de invitación caduca y no debe compartirse.', }, pt: { subject: 'Seu convite para o VOKO', heading: 'Seu convite para o VOKO está pronto', intro: 'Use o link abaixo para concluir o cadastro.', action: 'Concluir cadastro', warning: 'Este link de convite expira e não deve ser compartilhado.', }, }) /** * @param {{ locale: string, inviteUrl: string }} data */ export function render(data) { if (!data || typeof data !== 'object') fail('data is required') const copy = COPY[data.locale] if (!copy) fail(`unsupported locale: ${String(data.locale)}`) const inviteUrl = requiredHttpsUrl(data.inviteUrl) const text = [copy.heading, '', copy.intro, inviteUrl, '', copy.warning].join('\n') const html = [ '
', `${escapeHtml(copy.intro)}
`, ``, `${escapeHtml(copy.warning)}
`, '', ].join('') return { subject: copy.subject, text, html } } function requiredHttpsUrl(value) { if (typeof value !== 'string' || value.trim() === '') fail('missing field "inviteUrl"') const url = value.trim() try { const parsed = new URL(url) // 本地开发的前端是 http://localhost,其余环境必须 https。 if (parsed.protocol === 'https:' || parsed.hostname === 'localhost') return url } catch (error) { fail(`inviteUrl is invalid: ${error instanceof Error ? error.message : String(error)}`) } fail('inviteUrl must use https') } function fail(message) { throw new EmailError({ provider: 'template', reason: 'badTemplate', retryable: false, message: `waitlist-invite: ${message}` }) } function escapeHtml(value) { return String(value) .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", ''') }