From 08b68b111f0a700825529ad072da0fb96ca35fb4 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 19 Jan 2026 14:13:37 +0530 Subject: [PATCH 1/4] fix: state limits. --- src/lib/helpers/oauth.ts | 98 +++++++++++++++++++ .../(public)/(guest)/login/+page.svelte | 22 ++--- .../(public)/auth/preview/access/+page.svelte | 21 ++-- 3 files changed, 117 insertions(+), 24 deletions(-) create mode 100644 src/lib/helpers/oauth.ts diff --git a/src/lib/helpers/oauth.ts b/src/lib/helpers/oauth.ts new file mode 100644 index 0000000000..b02805d1a1 --- /dev/null +++ b/src/lib/helpers/oauth.ts @@ -0,0 +1,98 @@ +type BuildOAuthSuccessUrlParams = { + pageUrl: URL; + basePath: string; + origin: string; + isStudio: boolean; +}; + +const STUDIO_PROMPT_KEY = 'studioPrompt'; +const ABSOLUTE_URL = /^[a-zA-Z][a-zA-Z\d+.-]*:/; + +function isAbsoluteUrl(value: string): boolean { + return ABSOLUTE_URL.test(value) || value.startsWith('//'); +} + +function stashStudioPrompt(prompt: string, isStudio: boolean): void { + if (!isStudio || !prompt) { + return; + } + + try { + sessionStorage.setItem(STUDIO_PROMPT_KEY, prompt); + } catch { + // ignore + } +} + +function formatUrl(url: URL, original: string): string { + if (isAbsoluteUrl(original)) { + return url.toString(); + } + + return `${url.pathname}${url.search}${url.hash}`; +} + +function stripPromptFromTarget(target: string, isStudio: boolean): string { + if (!isStudio) { + return target; + } + + try { + const url = new URL(target, window.location.origin); + const prompt = url.searchParams.get('prompt'); + + if (prompt) { + stashStudioPrompt(prompt, isStudio); + url.searchParams.delete('prompt'); + } + + return formatUrl(url, target); + } catch { + return target; + } +} + +function appendQuery(target: string, params: URLSearchParams): string { + const query = params.toString(); + if (!query) { + return target; + } + + const hashIndex = target.indexOf('#'); + const hash = hashIndex >= 0 ? target.slice(hashIndex) : ''; + const base = hashIndex >= 0 ? target.slice(0, hashIndex) : target; + const separator = base.includes('?') ? '&' : '?'; + + return `${base}${separator}${query}${hash}`; +} + +export function buildOAuthSuccessUrl({ + pageUrl, + basePath, + origin, + isStudio +}: BuildOAuthSuccessUrlParams): string { + const params = new URLSearchParams(pageUrl.search); + const redirect = params.get('redirect'); + + if (redirect) { + params.delete('redirect'); + } + + if (isStudio) { + const prompt = params.get('prompt'); + if (prompt) { + stashStudioPrompt(prompt, isStudio); + params.delete('prompt'); + } + } + + let target = redirect ? stripPromptFromTarget(redirect, isStudio) : basePath; + target = appendQuery(target, params); + + if (isAbsoluteUrl(target)) { + return target; + } + + return origin + target; +} diff --git a/src/routes/(public)/(guest)/login/+page.svelte b/src/routes/(public)/(guest)/login/+page.svelte index 9766f0e4db..7f61186550 100644 --- a/src/routes/(public)/(guest)/login/+page.svelte +++ b/src/routes/(public)/(guest)/login/+page.svelte @@ -4,13 +4,14 @@ import { Button, Form, InputEmail, InputPassword } from '$lib/elements/forms'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; + import { buildOAuthSuccessUrl } from '$lib/helpers/oauth'; import { Dependencies } from '$lib/constants'; import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; import { page } from '$app/state'; import { redirectTo } from '$routes/store'; import { user } from '$lib/stores/user'; import { Layout } from '@appwrite.io/pink-svelte'; - import { Logins, resolvedProfile } from '$lib/profiles/index.svelte'; + import { Logins, ProfileMode, resolvedProfile } from '$lib/profiles/index.svelte'; import type { OAuthProvider } from '@appwrite.io/console'; import type { PageProps } from './$types.js'; @@ -71,20 +72,17 @@ function onOauthLogin(config: { provider: OAuthProvider; scopes: string[] }) { clearAuthToken(); - let url = window.location.origin; - if (page.url.searchParams) { - const redirect = page.url.searchParams.get('redirect'); - page.url.searchParams.delete('redirect'); - if (redirect) { - url = `${redirect}${page.url.search}`; - } else { - url = `${base}${page.url.search ?? ''}`; - } - } + const successUrl = buildOAuthSuccessUrl({ + pageUrl: page.url, + basePath: base, + origin: window.location.origin, + isStudio: resolvedProfile.id === ProfileMode.STUDIO + }); + sdk.forConsole.account.createOAuth2Session({ provider: config.provider, - success: window.location.origin + url, + success: successUrl, failure: window.location.origin, scopes: config.scopes }); diff --git a/src/routes/(public)/auth/preview/access/+page.svelte b/src/routes/(public)/auth/preview/access/+page.svelte index 128774104a..6fed47089f 100644 --- a/src/routes/(public)/auth/preview/access/+page.svelte +++ b/src/routes/(public)/auth/preview/access/+page.svelte @@ -17,6 +17,7 @@ } from '$lib/elements/forms'; import { logout } from '$lib/helpers/logout'; import { sdk } from '$lib/stores/sdk'; + import { buildOAuthSuccessUrl } from '$lib/helpers/oauth'; import { isCloud } from '$lib/system'; import { ID, OAuthProvider } from '@appwrite.io/console'; import { Layout, Typography } from '@appwrite.io/pink-svelte'; @@ -24,7 +25,7 @@ import BGDark from './bg_dark.jpg'; import BGLight from './bg_light.jpg'; import { app } from '$lib/stores/app.js'; - import { resolvedProfile } from '$lib/profiles/index.svelte'; + import { ProfileMode, resolvedProfile } from '$lib/profiles/index.svelte'; export let data; @@ -88,20 +89,16 @@ } function onGithubAuth() { - let url = window.location.origin; + const success = buildOAuthSuccessUrl({ + pageUrl: page.url, + basePath: base, + origin: window.location.origin, + isStudio: resolvedProfile.id === ProfileMode.STUDIO + }); - if (page.url.searchParams) { - const redirect = page.url.searchParams.get('redirect'); - page.url.searchParams.delete('redirect'); - if (redirect) { - url = `${redirect}${page.url.search}`; - } else { - url = `${base}${page.url.search ?? ''}`; - } - } sdk.forConsole.account.createOAuth2Session({ provider: OAuthProvider.Github, - success: window.location.origin + url, + success, failure: window.location.origin, scopes: ['read:user', 'user:email'] }); From 9854790b862fb343aa11d46f5e3082e952c40db8 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 19 Jan 2026 14:17:33 +0530 Subject: [PATCH 2/4] use: const. bump: package. --- package.json | 2 +- pnpm-lock.yaml | 33 +++++++++++++++++++++------------ src/lib/helpers/oauth.ts | 2 +- src/routes/+layout.svelte | 7 ++++--- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 8ffeb7ddd2..f1d566fb06 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@melt-ui/svelte": "^0.86.6", "@playwright/test": "^1.56.0", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.46.2", + "@sveltejs/kit": "^2.49.5", "@sveltejs/vite-plugin-svelte": "^5.1.1", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddbd3a850c..2aad8c4dd6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 2.11.8 '@sentry/sveltekit': specifier: ^10.25.0 - version: 10.29.0(@sveltejs/kit@2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) + version: 10.29.0(@sveltejs/kit@2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) '@stripe/stripe-js': specifier: ^3.5.0 version: 3.5.0 @@ -122,10 +122,10 @@ importers: version: 1.57.0 '@sveltejs/adapter-static': specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))) + version: 3.0.10(@sveltejs/kit@2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))) '@sveltejs/kit': - specifier: ^2.46.2 - version: 2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) + specifier: ^2.49.5 + version: 2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) '@sveltejs/vite-plugin-svelte': specifier: ^5.1.1 version: 5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) @@ -1272,18 +1272,21 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.49.1': - resolution: {integrity: sha512-vByReCTTdlNM80vva8alAQC80HcOiHLkd8XAxIiKghKSHcqeNfyhp3VsYAV8VSiPKu4Jc8wWCfsZNAIvd1uCqA==} + '@sveltejs/kit@2.50.0': + resolution: {integrity: sha512-Hj8sR8O27p2zshFEIJzsvfhLzxga/hWw6tRLnBjMYw70m1aS9BSYCqAUtzDBjRREtX1EvLMYgaC0mYE3Hz4KWA==} engines: {node: '>=18.13'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.0.0 '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: ^5.3.3 vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 peerDependenciesMeta: '@opentelemetry/api': optional: true + typescript: + optional: true '@sveltejs/vite-plugin-svelte-inspector@4.0.1': resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} @@ -2014,6 +2017,9 @@ packages: devalue@5.5.0: resolution: {integrity: sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==} + devalue@5.6.2: + resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -4641,7 +4647,7 @@ snapshots: magic-string: 0.30.7 svelte: 5.45.6 - '@sentry/sveltekit@10.29.0(@sveltejs/kit@2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))': + '@sentry/sveltekit@10.29.0(@sveltejs/kit@2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))': dependencies: '@babel/parser': 7.26.9 '@sentry/cloudflare': 10.29.0 @@ -4649,7 +4655,7 @@ snapshots: '@sentry/node': 10.29.0 '@sentry/svelte': 10.29.0(svelte@5.45.6) '@sentry/vite-plugin': 4.6.1 - '@sveltejs/kit': 2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) + '@sveltejs/kit': 2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) magic-string: 0.30.7 recast: 0.23.11 sorcery: 1.0.0 @@ -4712,11 +4718,11 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))': dependencies: - '@sveltejs/kit': 2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) + '@sveltejs/kit': 2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)) - '@sveltejs/kit@2.49.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))': + '@sveltejs/kit@2.50.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(typescript@5.9.3)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) @@ -4724,7 +4730,7 @@ snapshots: '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 - devalue: 5.5.0 + devalue: 5.6.2 esm-env: 1.2.2 kleur: 4.1.5 magic-string: 0.30.21 @@ -4736,6 +4742,7 @@ snapshots: vite: 7.2.7(@types/node@24.10.1)(sass@1.94.2) optionalDependencies: '@opentelemetry/api': 1.9.0 + typescript: 5.9.3 '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2)))(svelte@5.45.6)(vite@7.2.7(@types/node@24.10.1)(sass@1.94.2))': dependencies: @@ -5588,6 +5595,8 @@ snapshots: devalue@5.5.0: {} + devalue@5.6.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 diff --git a/src/lib/helpers/oauth.ts b/src/lib/helpers/oauth.ts index b02805d1a1..00c43271a2 100644 --- a/src/lib/helpers/oauth.ts +++ b/src/lib/helpers/oauth.ts @@ -5,7 +5,7 @@ type BuildOAuthSuccessUrlParams = { isStudio: boolean; }; -const STUDIO_PROMPT_KEY = 'studioPrompt'; +export const STUDIO_PROMPT_KEY = 'studioPrompt'; const ABSOLUTE_URL = /^[a-zA-Z][a-zA-Z\d+.-]*:/; function isAbsoluteUrl(value: string): boolean { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index fa96bf8e5a..e89bcc8268 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -26,6 +26,7 @@ import { feedback } from '$lib/stores/feedback'; import { ProfileMode, resolvedProfile } from '$lib/profiles/index.svelte'; import { CDN_CSS_URL, CDN_URL } from '$lib/studio/studio-widget'; + import { STUDIO_PROMPT_KEY } from '$lib/helpers/oauth'; function resolveTheme(theme: AppStore['themeInUse']) { switch (theme) { @@ -45,16 +46,16 @@ const promptParam = currentUrl.searchParams.get('prompt'); if (promptParam) { - sessionStorage.setItem('studioPrompt', promptParam); + sessionStorage.setItem(STUDIO_PROMPT_KEY, promptParam); return; } - const storedPrompt = sessionStorage.getItem('studioPrompt'); + const storedPrompt = sessionStorage.getItem(STUDIO_PROMPT_KEY); if (!storedPrompt) return; currentUrl.searchParams.set('prompt', storedPrompt); await goto(currentUrl.toString(), { replaceState: true, noScroll: true }); - sessionStorage.removeItem('studioPrompt'); + sessionStorage.removeItem(STUDIO_PROMPT_KEY); } onMount(async () => { From b7876d07915cd4d84116ab21aac15a3c5854c9f6 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 19 Jan 2026 14:18:18 +0530 Subject: [PATCH 3/4] bump: package. --- package.json | 2 +- pnpm-lock.yaml | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index f1d566fb06..7003ec5c87 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "prettier": "^3.6.2", "prettier-plugin-svelte": "^3.4.0", "sass": "^1.93.2", - "svelte": "^5.45.5", + "svelte": "^5.6.2", "svelte-check": "^4.3.2", "svelte-preprocess": "^6.0.3", "svelte-sequential-preprocessor": "^2.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2aad8c4dd6..c81c1fb82c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -190,7 +190,7 @@ importers: specifier: ^1.93.2 version: 1.94.2 svelte: - specifier: ^5.45.5 + specifier: ^5.6.2 version: 5.45.6 svelte-check: specifier: ^4.3.2 @@ -2014,9 +2014,6 @@ packages: engines: {node: '>=0.10'} hasBin: true - devalue@5.5.0: - resolution: {integrity: sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==} - devalue@5.6.2: resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} @@ -5593,8 +5590,6 @@ snapshots: detect-libc@1.0.3: optional: true - devalue@5.5.0: {} - devalue@5.6.2: {} devlop@1.1.0: @@ -6819,7 +6814,7 @@ snapshots: aria-query: 5.3.2 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.5.0 + devalue: 5.6.2 esm-env: 1.2.2 esrap: 2.2.1 is-reference: 3.0.3 From 3514c8b78d2f17960ad1db9de56dbf88ed0d5cb8 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 19 Jan 2026 14:19:58 +0530 Subject: [PATCH 4/4] var name. --- src/routes/(public)/auth/preview/access/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/(public)/auth/preview/access/+page.svelte b/src/routes/(public)/auth/preview/access/+page.svelte index 6fed47089f..d57a4321a9 100644 --- a/src/routes/(public)/auth/preview/access/+page.svelte +++ b/src/routes/(public)/auth/preview/access/+page.svelte @@ -89,7 +89,7 @@ } function onGithubAuth() { - const success = buildOAuthSuccessUrl({ + const successUrl = buildOAuthSuccessUrl({ pageUrl: page.url, basePath: base, origin: window.location.origin, @@ -98,7 +98,7 @@ sdk.forConsole.account.createOAuth2Session({ provider: OAuthProvider.Github, - success, + success: successUrl, failure: window.location.origin, scopes: ['read:user', 'user:email'] });