From 1bb14c16c67ea37ee3f680fe12d50fdb95cb4077 Mon Sep 17 00:00:00 2001 From: vitoUwu Date: Wed, 26 Feb 2025 07:37:03 -0400 Subject: [PATCH] feat: authentication api --- utils/safeParse.ts | 16 +++ .../actions/authentication/accessKeySignIn.ts | 100 ++++++++++++++++ vtex/actions/authentication/classicSignIn.ts | 103 ++++++++++++++++ vtex/actions/authentication/logout.ts | 33 ++++++ .../authentication/recoveryPassword.ts | 107 +++++++++++++++++ vtex/actions/authentication/resetPassword.ts | 110 ++++++++++++++++++ .../authentication/sendEmailVerification.ts | 84 +++++++++++++ .../authentication/startAuthentication.ts | 50 ++++++++ vtex/manifest.gen.ts | 110 ++++++++++-------- vtex/utils/client.ts | 30 +++++ vtex/utils/types.ts | 97 +++++++++++++++ 11 files changed, 792 insertions(+), 48 deletions(-) create mode 100644 utils/safeParse.ts create mode 100644 vtex/actions/authentication/accessKeySignIn.ts create mode 100644 vtex/actions/authentication/classicSignIn.ts create mode 100644 vtex/actions/authentication/logout.ts create mode 100644 vtex/actions/authentication/recoveryPassword.ts create mode 100644 vtex/actions/authentication/resetPassword.ts create mode 100644 vtex/actions/authentication/sendEmailVerification.ts create mode 100644 vtex/actions/authentication/startAuthentication.ts diff --git a/utils/safeParse.ts b/utils/safeParse.ts new file mode 100644 index 000000000..727a25fe9 --- /dev/null +++ b/utils/safeParse.ts @@ -0,0 +1,16 @@ +/** + * @description Safely parses a value to a JSON object. It doesn't validates the object, it just tries to parse it. + * @param value - The value to parse + * @returns The parsed value or null if the value is not a string + */ +export default function safeParse(value: string): T | null { + if (typeof value !== "string") { + return null; + } + + try { + return JSON.parse(value) as T; + } catch (_e) { + return null; + } +} diff --git a/vtex/actions/authentication/accessKeySignIn.ts b/vtex/actions/authentication/accessKeySignIn.ts new file mode 100644 index 000000000..fc11adf61 --- /dev/null +++ b/vtex/actions/authentication/accessKeySignIn.ts @@ -0,0 +1,100 @@ +import { getCookies } from "std/http/cookie.ts"; +import { setCookie } from "std/http/mod.ts"; +import safeParse from "../../../utils/safeParse.ts"; +import { AppContext } from "../../mod.ts"; +import { AuthResponse } from "../../utils/types.ts"; + +export interface Props { + email: string; + accessKey: string; +} + +/** + * @title VTEX Integration - Authenticate with Email and AcessKey + * @description Return authStatus that show if user is logged or something wrong happens. + */ +export default async function action( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const { vcsDeprecated } = ctx; + + if (!props.email || !props.accessKey) { + console.error("Email and/or password is missing:", props); + return null; + } + + try { + const cookies = getCookies(req.headers); + const VtexSessionToken = cookies?.["VtexSessionToken"] ?? null; + + if (!VtexSessionToken) { + console.error("VtexSessionToken cookie is missing", VtexSessionToken); + return null; + } + + const body = new URLSearchParams(); + body.append("login", props.email); + body.append("accessKey", props.accessKey); + body.append("authenticationToken", VtexSessionToken); + + const response = await vcsDeprecated + ["POST /api/vtexid/pub/authentication/accesskey/validate"]( + {}, + { + body, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json", + }, + }, + ); + + if (!response.ok) { + console.error( + "Authentication request failed", + response.status, + response.statusText, + ); + return null; + } + + const data: AuthResponse = await response.json(); + if (data.authStatus === "Success") { + const VTEXID_EXPIRES = data.expiresIn; + + if (data.authCookie) { + setCookie(ctx.response.headers, { + name: data.authCookie.Name, + value: data.authCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + + if (data.accountAuthCookie) { + setCookie(ctx.response.headers, { + name: data.accountAuthCookie.Name, + value: data.accountAuthCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + } + + await ctx.invoke.vtex.actions.session.editSession({}); + + return data; + } catch (error) { + console.error("Unexpected error during authentication", error); + if (error instanceof Error) { + return safeParse(error.message); + } + return null; + } +} diff --git a/vtex/actions/authentication/classicSignIn.ts b/vtex/actions/authentication/classicSignIn.ts new file mode 100644 index 000000000..d6f9503b3 --- /dev/null +++ b/vtex/actions/authentication/classicSignIn.ts @@ -0,0 +1,103 @@ +import { setCookie } from "std/http/mod.ts"; +import safeParse from "../../../utils/safeParse.ts"; +import { AppContext } from "../../mod.ts"; +import { AuthResponse } from "../../utils/types.ts"; + +export interface Props { + email: string; + password: string; +} + +/** + * @title VTEX Integration - Authenticate with Email and Password + * @description This function authenticates a user using their email and password. + */ +export default async function action( + props: Props, + _req: Request, + ctx: AppContext, +): Promise { + const { vcsDeprecated } = ctx; + + if (!props.email || !props.password) { + console.error("Email and/or password is missing:", props); + return null; + } + + try { + const startAuthentication = await ctx.invoke.vtex.actions.authentication + .startAuthentication({}); + + if (!startAuthentication?.authenticationToken) { + console.error( + "No authentication token returned from startAuthentication.", + ); + return null; + } + + const authenticationToken = startAuthentication.authenticationToken; + + const urlencoded = new URLSearchParams(); + urlencoded.append("email", props.email); + urlencoded.append("password", props.password); + urlencoded.append("authenticationToken", authenticationToken); + + const response = await vcsDeprecated + ["POST /api/vtexid/pub/authentication/classic/validate"]( + {}, + { + body: urlencoded, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json", + }, + }, + ); + + if (!response.ok) { + console.error( + "Authentication request failed", + response.status, + response.statusText, + ); + return null; + } + + const data: AuthResponse = await response.json(); + if (data.authStatus === "Success") { + const VTEXID_EXPIRES = data.expiresIn; + + if (data.authCookie) { + setCookie(ctx.response.headers, { + name: data.authCookie.Name, + value: data.authCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + + if (data.accountAuthCookie) { + setCookie(ctx.response.headers, { + name: data.accountAuthCookie.Name, + value: data.accountAuthCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + } + + await ctx.invoke.vtex.actions.session.editSession({}); + + return data; + } catch (error) { + console.error("Unexpected error during authentication", error); + if (error instanceof Error) { + return safeParse(error.message); + } + return null; + } +} diff --git a/vtex/actions/authentication/logout.ts b/vtex/actions/authentication/logout.ts new file mode 100644 index 000000000..37034cbc4 --- /dev/null +++ b/vtex/actions/authentication/logout.ts @@ -0,0 +1,33 @@ +import { getCookies, setCookie } from "std/http/mod.ts"; +import { AppContext } from "../../mod.ts"; +import { parseCookie } from "../../utils/vtexId.ts"; + +export default async function logout( + _: unknown, + req: Request, + ctx: AppContext, +) { + const cookies = getCookies(req.headers); + const { payload } = parseCookie(req.headers, ctx.account); + + for (const cookieName in cookies) { + if (cookieName.startsWith("VtexIdclientAutCookie")) { + setCookie(ctx.response.headers, { + name: cookieName, + value: "", + expires: new Date(0), + path: "/", + }); + } + } + + try { + if (payload?.sess) { + await ctx.invoke.vtex.actions.session.deleteSession({ + sessionId: payload?.sess, + }); + } + } catch (error) { + console.error("Error deleting session", error); + } +} diff --git a/vtex/actions/authentication/recoveryPassword.ts b/vtex/actions/authentication/recoveryPassword.ts new file mode 100644 index 000000000..e02ab493d --- /dev/null +++ b/vtex/actions/authentication/recoveryPassword.ts @@ -0,0 +1,107 @@ +import { getCookies } from "std/http/cookie.ts"; +import { setCookie } from "std/http/mod.ts"; +import safeParse from "../../../utils/safeParse.ts"; +import { AppContext } from "../../mod.ts"; +import { getSegmentFromBag } from "../../utils/segment.ts"; +import { AuthResponse } from "../../utils/types.ts"; + +export interface Props { + email: string; + newPassword: string; + accessKey: string; +} + +/** + * @title VTEX Integration - Recovery password + * @description + */ +export default async function action( + props: Props, + req: Request, + ctx: AppContext, +): Promise { + const { vcsDeprecated, account } = ctx; + const segment = getSegmentFromBag(ctx); + + if (!props.email || !props.accessKey || !props.newPassword) { + console.error("Email, accessKey and/or newPassword is missing:", props); + return null; + } + + try { + const cookies = getCookies(req.headers); + const VtexSessionToken = cookies?.["VtexSessionToken"] ?? null; + + if (!VtexSessionToken) { + console.error("VtexSessionToken is missing"); + return null; + } + + const urlencoded = new URLSearchParams(); + urlencoded.append("login", props.email); + urlencoded.append("accessKey", props.accessKey); + urlencoded.append("newPassword", props.newPassword); + urlencoded.append("authenticationToken", VtexSessionToken); + + const response = await vcsDeprecated + ["POST /api/vtexid/pub/authentication/classic/setpassword"]( + { + locale: segment?.payload.cultureInfo || "pt-BR", + scope: account, + }, + { + body: urlencoded, + headers: { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + }, + ); + + if (!response.ok) { + console.error( + "Authentication request failed", + response.status, + response.statusText, + ); + return null; + } + + const data: AuthResponse = await response.json(); + if (data.authStatus === "Success") { + const VTEXID_EXPIRES = data.expiresIn; + + if (data.authCookie) { + setCookie(ctx.response.headers, { + name: data.authCookie.Name, + value: data.authCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + + if (data.accountAuthCookie) { + setCookie(ctx.response.headers, { + name: data.accountAuthCookie.Name, + value: data.accountAuthCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + } + + await ctx.invoke.vtex.actions.session.editSession({}); + + return data; + } catch (error) { + console.error("Unexpected error during authentication", error); + if (error instanceof Error) { + return safeParse(error.message); + } + return null; + } +} diff --git a/vtex/actions/authentication/resetPassword.ts b/vtex/actions/authentication/resetPassword.ts new file mode 100644 index 000000000..16b10178d --- /dev/null +++ b/vtex/actions/authentication/resetPassword.ts @@ -0,0 +1,110 @@ +import { setCookie } from "std/http/mod.ts"; +import safeParse from "../../../utils/safeParse.ts"; +import { AppContext } from "../../mod.ts"; +import { getSegmentFromBag } from "../../utils/segment.ts"; +import { AuthResponse } from "../../utils/types.ts"; + +export interface Props { + email: string; + currentPassword: string; + newPassword: string; +} + +/** + * @title VTEX Integration - Redefine password + * @description + */ +export default async function action( + props: Props, + _req: Request, + ctx: AppContext, +): Promise { + const { vcsDeprecated, account } = ctx; + const segment = getSegmentFromBag(ctx); + + if (!props.email || !props.currentPassword || !props.newPassword) { + console.error("Email and/or password is missing:", props); + return null; + } + + try { + const startAuthentication = await ctx.invoke.vtex.actions.authentication + .startAuthentication({}); + + if (!startAuthentication?.authenticationToken) { + console.error( + "No authentication token returned from startAuthentication.", + ); + return null; + } + + const authenticationToken = startAuthentication.authenticationToken; + + const urlencoded = new URLSearchParams(); + urlencoded.append("login", props.email); + urlencoded.append("currentPassword", props.currentPassword); + urlencoded.append("newPassword", props.newPassword); + urlencoded.append("authenticationToken", authenticationToken); + + const response = await vcsDeprecated + ["POST /api/vtexid/pub/authentication/classic/setpassword"]( + { + locale: segment?.payload.cultureInfo || "pt-BR", + scope: account, + }, + { + body: urlencoded, + headers: { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + }, + ); + + if (!response.ok) { + console.error( + "Authentication request failed", + response.status, + response.statusText, + ); + return null; + } + + const data: AuthResponse = await response.json(); + if (data.authStatus === "Success") { + const VTEXID_EXPIRES = data.expiresIn; + + if (data.authCookie) { + setCookie(ctx.response.headers, { + name: data.authCookie.Name, + value: data.authCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + + if (data.accountAuthCookie) { + setCookie(ctx.response.headers, { + name: data.accountAuthCookie.Name, + value: data.accountAuthCookie.Value, + httpOnly: true, + maxAge: VTEXID_EXPIRES, + path: "/", + secure: true, + }); + } + } + + await ctx.invoke.vtex.actions.session.editSession({}); + + return data; + } catch (error) { + console.error("Unexpected error during authentication", error); + if (error instanceof Error) { + return safeParse(error.message); + } + return null; + } +} diff --git a/vtex/actions/authentication/sendEmailVerification.ts b/vtex/actions/authentication/sendEmailVerification.ts new file mode 100644 index 000000000..5481ca9d5 --- /dev/null +++ b/vtex/actions/authentication/sendEmailVerification.ts @@ -0,0 +1,84 @@ +import { setCookie } from "std/http/mod.ts"; +import type { AppContext } from "../../mod.ts"; + +export interface Props { + email: string; +} + +export type SendEmailVerificationResult = boolean; + +/** + * @title VTEX Integration - Send Email Verification + * @description Sends an email verification request via VTEX API + */ +export default async function action( + props: Props, + _req: Request, + ctx: AppContext, +): Promise { + const { vcsDeprecated } = ctx; + + if (!props.email) { + throw new Error("Email is missing"); + } + + try { + const startAuthentication = await ctx.invoke.vtex.actions.authentication + .startAuthentication({}); + + if (!startAuthentication?.authenticationToken) { + console.error( + "No authentication token returned from startAuthentication.", + ); + return false; + } + + const authenticationToken = startAuthentication.authenticationToken; + + const formData = new FormData(); + formData.append("authenticationToken", authenticationToken); + formData.append("email", props.email); + + const response = await vcsDeprecated[ + "POST /api/vtexid/pub/authentication/accesskey/send" + ]({ + deliveryMethod: "email", + }, { + body: formData, + headers: { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + }, + }); + + if (!response.ok) { + console.error( + "Authentication request failed", + response.status, + response.statusText, + ); + return false; + } + + const data = await response.json(); + if (data?.authStatus === "InvalidToken") { + return false; + } + + // VtexSessionToken is valid for 10 minutes + const SESSION_TOKEN_EXPIRES = 600; + setCookie(ctx.response.headers, { + name: "VtexSessionToken", + value: authenticationToken, + httpOnly: true, + maxAge: SESSION_TOKEN_EXPIRES, + path: "/", + secure: true, + }); + + return true; + } catch (error) { + console.error("Unexpected error during authentication", error); + return false; + } +} diff --git a/vtex/actions/authentication/startAuthentication.ts b/vtex/actions/authentication/startAuthentication.ts new file mode 100644 index 000000000..67c914ab5 --- /dev/null +++ b/vtex/actions/authentication/startAuthentication.ts @@ -0,0 +1,50 @@ +import { AppContext } from "../../mod.ts"; +import { StartAuthentication } from "../../utils/types.ts"; +import { getSegmentFromBag } from "../../utils/segment.ts"; + +export interface Props { + callbackUrl?: string; + returnUrl?: string; + appStart?: boolean; +} + +/** + * @title VTEX Integration - Start Authentication + * @description Initiates the authentication process with VTEX. + */ +export default async function loader( + { + callbackUrl = "/", + returnUrl = "/", + appStart = true, + }: Props, + _req: Request, + ctx: AppContext, +): Promise { + const { vcsDeprecated, account } = ctx; + const segment = getSegmentFromBag(ctx); + + try { + const response = await vcsDeprecated + ["GET /api/vtexid/pub/authentication/start"]({ + locale: segment?.payload.cultureInfo ?? "pt-BR", + scope: account, + appStart, + callbackUrl, + returnUrl, + }); + + if (!response.ok) { + console.error( + `Failed to start authentication. HTTP status=${response.status}`, + ); + return null; + } + + const data = await response.json(); + return data; + } catch (error) { + console.error("Error during authentication:", error); + return null; + } +} diff --git a/vtex/manifest.gen.ts b/vtex/manifest.gen.ts index 921f1446c..75ad7e4ce 100644 --- a/vtex/manifest.gen.ts +++ b/vtex/manifest.gen.ts @@ -3,30 +3,37 @@ // This file is automatically updated during development when running `dev.ts`. import * as $$$$$$$$$0 from "./actions/analytics/sendEvent.ts"; -import * as $$$$$$$$$1 from "./actions/cart/addItems.ts"; -import * as $$$$$$$$$2 from "./actions/cart/addOfferings.ts"; -import * as $$$$$$$$$3 from "./actions/cart/clearOrderformMessages.ts"; -import * as $$$$$$$$$4 from "./actions/cart/getInstallment.ts"; -import * as $$$$$$$$$5 from "./actions/cart/removeItemAttachment.ts"; -import * as $$$$$$$$$6 from "./actions/cart/removeItems.ts"; -import * as $$$$$$$$$7 from "./actions/cart/removeOffering.ts"; -import * as $$$$$$$$$8 from "./actions/cart/simulation.ts"; -import * as $$$$$$$$$9 from "./actions/cart/updateAttachment.ts"; -import * as $$$$$$$$$10 from "./actions/cart/updateCoupons.ts"; -import * as $$$$$$$$$11 from "./actions/cart/updateGifts.ts"; -import * as $$$$$$$$$12 from "./actions/cart/updateItemAttachment.ts"; -import * as $$$$$$$$$13 from "./actions/cart/updateItemPrice.ts"; -import * as $$$$$$$$$14 from "./actions/cart/updateItems.ts"; -import * as $$$$$$$$$15 from "./actions/cart/updateProfile.ts"; -import * as $$$$$$$$$16 from "./actions/cart/updateUser.ts"; -import * as $$$$$$$$$17 from "./actions/masterdata/createDocument.ts"; -import * as $$$$$$$$$18 from "./actions/masterdata/updateDocument.ts"; -import * as $$$$$$$$$19 from "./actions/newsletter/subscribe.ts"; -import * as $$$$$$$$$20 from "./actions/notifyme.ts"; -import * as $$$$$$$$$21 from "./actions/review/submit.ts"; -import * as $$$$$$$$$22 from "./actions/trigger.ts"; -import * as $$$$$$$$$23 from "./actions/wishlist/addItem.ts"; -import * as $$$$$$$$$24 from "./actions/wishlist/removeItem.ts"; +import * as $$$$$$$$$1 from "./actions/authentication/accessKeySignIn.ts"; +import * as $$$$$$$$$2 from "./actions/authentication/classicSignIn.ts"; +import * as $$$$$$$$$3 from "./actions/authentication/logout.ts"; +import * as $$$$$$$$$4 from "./actions/authentication/recoveryPassword.ts"; +import * as $$$$$$$$$5 from "./actions/authentication/resetPassword.ts"; +import * as $$$$$$$$$6 from "./actions/authentication/sendEmailVerification.ts"; +import * as $$$$$$$$$7 from "./actions/authentication/startAuthentication.ts"; +import * as $$$$$$$$$8 from "./actions/cart/addItems.ts"; +import * as $$$$$$$$$9 from "./actions/cart/addOfferings.ts"; +import * as $$$$$$$$$10 from "./actions/cart/clearOrderformMessages.ts"; +import * as $$$$$$$$$11 from "./actions/cart/getInstallment.ts"; +import * as $$$$$$$$$12 from "./actions/cart/removeItemAttachment.ts"; +import * as $$$$$$$$$13 from "./actions/cart/removeItems.ts"; +import * as $$$$$$$$$14 from "./actions/cart/removeOffering.ts"; +import * as $$$$$$$$$15 from "./actions/cart/simulation.ts"; +import * as $$$$$$$$$16 from "./actions/cart/updateAttachment.ts"; +import * as $$$$$$$$$17 from "./actions/cart/updateCoupons.ts"; +import * as $$$$$$$$$18 from "./actions/cart/updateGifts.ts"; +import * as $$$$$$$$$19 from "./actions/cart/updateItemAttachment.ts"; +import * as $$$$$$$$$20 from "./actions/cart/updateItemPrice.ts"; +import * as $$$$$$$$$21 from "./actions/cart/updateItems.ts"; +import * as $$$$$$$$$22 from "./actions/cart/updateProfile.ts"; +import * as $$$$$$$$$23 from "./actions/cart/updateUser.ts"; +import * as $$$$$$$$$24 from "./actions/masterdata/createDocument.ts"; +import * as $$$$$$$$$25 from "./actions/masterdata/updateDocument.ts"; +import * as $$$$$$$$$26 from "./actions/newsletter/subscribe.ts"; +import * as $$$$$$$$$27 from "./actions/notifyme.ts"; +import * as $$$$$$$$$28 from "./actions/review/submit.ts"; +import * as $$$$$$$$$29 from "./actions/trigger.ts"; +import * as $$$$$$$$$30 from "./actions/wishlist/addItem.ts"; +import * as $$$$$$$$$31 from "./actions/wishlist/removeItem.ts"; import * as $$$$0 from "./handlers/sitemap.ts"; import * as $$$0 from "./loaders/cart.ts"; import * as $$$1 from "./loaders/categories/tree.ts"; @@ -123,30 +130,37 @@ const manifest = { }, "actions": { "vtex/actions/analytics/sendEvent.ts": $$$$$$$$$0, - "vtex/actions/cart/addItems.ts": $$$$$$$$$1, - "vtex/actions/cart/addOfferings.ts": $$$$$$$$$2, - "vtex/actions/cart/clearOrderformMessages.ts": $$$$$$$$$3, - "vtex/actions/cart/getInstallment.ts": $$$$$$$$$4, - "vtex/actions/cart/removeItemAttachment.ts": $$$$$$$$$5, - "vtex/actions/cart/removeItems.ts": $$$$$$$$$6, - "vtex/actions/cart/removeOffering.ts": $$$$$$$$$7, - "vtex/actions/cart/simulation.ts": $$$$$$$$$8, - "vtex/actions/cart/updateAttachment.ts": $$$$$$$$$9, - "vtex/actions/cart/updateCoupons.ts": $$$$$$$$$10, - "vtex/actions/cart/updateGifts.ts": $$$$$$$$$11, - "vtex/actions/cart/updateItemAttachment.ts": $$$$$$$$$12, - "vtex/actions/cart/updateItemPrice.ts": $$$$$$$$$13, - "vtex/actions/cart/updateItems.ts": $$$$$$$$$14, - "vtex/actions/cart/updateProfile.ts": $$$$$$$$$15, - "vtex/actions/cart/updateUser.ts": $$$$$$$$$16, - "vtex/actions/masterdata/createDocument.ts": $$$$$$$$$17, - "vtex/actions/masterdata/updateDocument.ts": $$$$$$$$$18, - "vtex/actions/newsletter/subscribe.ts": $$$$$$$$$19, - "vtex/actions/notifyme.ts": $$$$$$$$$20, - "vtex/actions/review/submit.ts": $$$$$$$$$21, - "vtex/actions/trigger.ts": $$$$$$$$$22, - "vtex/actions/wishlist/addItem.ts": $$$$$$$$$23, - "vtex/actions/wishlist/removeItem.ts": $$$$$$$$$24, + "vtex/actions/authentication/accessKeySignIn.ts": $$$$$$$$$1, + "vtex/actions/authentication/classicSignIn.ts": $$$$$$$$$2, + "vtex/actions/authentication/logout.ts": $$$$$$$$$3, + "vtex/actions/authentication/recoveryPassword.ts": $$$$$$$$$4, + "vtex/actions/authentication/resetPassword.ts": $$$$$$$$$5, + "vtex/actions/authentication/sendEmailVerification.ts": $$$$$$$$$6, + "vtex/actions/authentication/startAuthentication.ts": $$$$$$$$$7, + "vtex/actions/cart/addItems.ts": $$$$$$$$$8, + "vtex/actions/cart/addOfferings.ts": $$$$$$$$$9, + "vtex/actions/cart/clearOrderformMessages.ts": $$$$$$$$$10, + "vtex/actions/cart/getInstallment.ts": $$$$$$$$$11, + "vtex/actions/cart/removeItemAttachment.ts": $$$$$$$$$12, + "vtex/actions/cart/removeItems.ts": $$$$$$$$$13, + "vtex/actions/cart/removeOffering.ts": $$$$$$$$$14, + "vtex/actions/cart/simulation.ts": $$$$$$$$$15, + "vtex/actions/cart/updateAttachment.ts": $$$$$$$$$16, + "vtex/actions/cart/updateCoupons.ts": $$$$$$$$$17, + "vtex/actions/cart/updateGifts.ts": $$$$$$$$$18, + "vtex/actions/cart/updateItemAttachment.ts": $$$$$$$$$19, + "vtex/actions/cart/updateItemPrice.ts": $$$$$$$$$20, + "vtex/actions/cart/updateItems.ts": $$$$$$$$$21, + "vtex/actions/cart/updateProfile.ts": $$$$$$$$$22, + "vtex/actions/cart/updateUser.ts": $$$$$$$$$23, + "vtex/actions/masterdata/createDocument.ts": $$$$$$$$$24, + "vtex/actions/masterdata/updateDocument.ts": $$$$$$$$$25, + "vtex/actions/newsletter/subscribe.ts": $$$$$$$$$26, + "vtex/actions/notifyme.ts": $$$$$$$$$27, + "vtex/actions/review/submit.ts": $$$$$$$$$28, + "vtex/actions/trigger.ts": $$$$$$$$$29, + "vtex/actions/wishlist/addItem.ts": $$$$$$$$$30, + "vtex/actions/wishlist/removeItem.ts": $$$$$$$$$31, }, "workflows": { "vtex/workflows/events.ts": $$$$$$$$$$0, diff --git a/vtex/utils/client.ts b/vtex/utils/client.ts index 7fb63b193..fb0754e25 100644 --- a/vtex/utils/client.ts +++ b/vtex/utils/client.ts @@ -1,5 +1,6 @@ import { Userorderslist } from "./openapi/vcs.openapi.gen.ts"; import { + AuthResponse, Brand, Category, CreateNewDocument, @@ -16,10 +17,39 @@ import { SimulationItem, SimulationOrderForm, SPEvent, + StartAuthentication, Suggestion, } from "./types.ts"; export interface VTEXCommerceStable { + "GET /api/vtexid/pub/authentication/start": { + searchParams: { + scope?: string; + locale?: string; + appStart: boolean; + callbackUrl?: string; + returnUrl?: string; + }; + response: StartAuthentication; + }; + "POST /api/vtexid/pub/authentication/classic/validate": { + body: URLSearchParams; + response: AuthResponse; + }; + "POST /api/vtexid/pub/authentication/accesskey/validate": { + body: URLSearchParams; + response: AuthResponse; + }; + "POST /api/vtexid/pub/authentication/classic/setpassword": { + searchParams: { scope?: string; locale?: string }; + body: URLSearchParams; + response: AuthResponse; + }; + "POST /api/vtexid/pub/authentication/accesskey/send": { + searchParams: { deliveryMethod: "email" }; + body: FormData; + response: Record; + }; "POST /api/checkout/pub/orderForm/:orderFormId/messages/clear": { // deno-lint-ignore no-explicit-any body: Record; diff --git a/vtex/utils/types.ts b/vtex/utils/types.ts index 89b86ec21..6f69150a4 100644 --- a/vtex/utils/types.ts +++ b/vtex/utils/types.ts @@ -1526,3 +1526,100 @@ export interface AdvancedLoaderConfig { } export type Maybe = T | null | undefined; + +export enum DeviceType { + Mobile = "MOBILE", + Tablet = "TABLET", + Desktop = "DESKTOP", +} + +export interface LoginSession { + id: string; + cacheId: string; + deviceType: DeviceType; + city?: Maybe; + lastAccess: string; + browser?: Maybe; + os?: Maybe; + ip?: Maybe; + fullAddress?: Maybe; + firstAccess: string; +} + +export interface LoginSessionsInfo { + currentLoginSessionId?: Maybe; + loginSessions?: Maybe; +} + +export interface Session { + id: string; + namespaces?: { + profile: SessionProfile; + impersonate: SessionImpersonate; + authentication: Record; + public: SessionPublic; + }; +} + +export interface SessionProfile { + id?: { value: string }; + email?: { value: string }; + firstName?: { value: string }; + lastName?: { value: string }; + phone?: { value: string }; + isAuthenticated?: { value: string }; + priceTables?: { value: string }; +} + +export interface SessionImpersonate { + storeUserEmail?: { value: string }; + storeUserId?: { value: string }; +} + +export interface SessionPublic { + orderFormId?: { value: string }; + utm_source?: { value: string }; + utm_medium?: { value: string }; + utm_campaign?: { value: string }; + utm_term?: { value: string }; + utm_content?: { value: string }; + utmi_cp?: { value: string }; + utmi_pc?: { value: string }; + utmi_p?: { value: string }; +} + +export interface AuthResponse { + authStatus: string | "WrongCredentials" | "BlockedUser" | "Success"; + promptMFA: boolean; + clientToken: string | null; + authCookie: { + Name: string; + Value: string; + } | null; + accountAuthCookie: { + Name: string; + Value: string; + } | null; + expiresIn: number; + userId: string | null; + phoneNumber: string | null; + scope: string | null; +} + +export interface AuthProvider { + providerName: string; + className: string; + expectedContext: unknown[]; +} + +export interface StartAuthentication { + authenticationToken: string | null; + oauthProviders: AuthProvider[]; + showClassicAuthentication: boolean; + showAccessKeyAuthentication: boolean; + showPasskeyAuthentication: boolean; + authCookie: string | null; + isAuthenticated: boolean; + selectedProvider: string | null; + samlProviders: unknown[]; +}