diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..a706a465e9 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ + +# Formats the code +.PHONY: format +format: node_modules + npm exec -- prettier --write 'contrib/**/*{.ts,.js}' + +node_modules: package-lock.json + npm ci + touch node_modules diff --git a/contrib/fetch/src/continueWith.ts b/contrib/fetch/src/continueWith.ts index d011c9c100..8c0020ea74 100644 --- a/contrib/fetch/src/continueWith.ts +++ b/contrib/fetch/src/continueWith.ts @@ -8,9 +8,9 @@ import { ContinueWithSettingsUi, ContinueWithVerificationUi, ContinueWithRedirectBrowserTo, -} from "../"; +} from "../" -export type OnRedirectHandler = (url: string, external: boolean) => void; +export type OnRedirectHandler = (url: string, external: boolean) => void // The order in which the actions are defined here is the order in which they are expected to be executed. const continueWithPriority = [ @@ -19,46 +19,46 @@ const continueWithPriority = [ "show_verification_ui", "redirect_browser_to", "set_ory_session_token", -]; +] export function handleContinueWith( continueWith: ContinueWith[] | undefined, - { onRedirect }: { onRedirect: OnRedirectHandler } + { onRedirect }: { onRedirect: OnRedirectHandler }, ): boolean { if (!continueWith || continueWith.length === 0) { - return false; + return false } - const action = pickBestContinueWith(continueWith); + const action = pickBestContinueWith(continueWith) if (!action) { - return false; + return false } const redirectFlow = (id: string, flow: string, url?: string) => { if (url) { - onRedirect(url, true); - return true; + onRedirect(url, true) + return true } - onRedirect("/" + flow + "?flow=" + id, false); - return true; - }; + onRedirect("/" + flow + "?flow=" + id, false) + return true + } if (isSetOrySessionToken(action)) { - throw new Error("Ory Elements does not support API flows yet."); + throw new Error("Ory Elements does not support API flows yet.") } else if (isRedirectBrowserTo(action) && action.redirect_browser_to) { // console.log("Redirecting to", action.redirect_browser_to) - onRedirect(action.redirect_browser_to, true); - return true; + onRedirect(action.redirect_browser_to, true) + return true } else if (isShowVerificationUi(action)) { - return redirectFlow(action.flow.id, "verification", action.flow.url); + return redirectFlow(action.flow.id, "verification", action.flow.url) } else if (isShowRecoveryUi(action)) { - return redirectFlow(action.flow.id, "recovery", action.flow.url); + return redirectFlow(action.flow.id, "recovery", action.flow.url) } else if (isShowSettingsUi(action)) { // TODO: re-add url - return redirectFlow(action.flow.id, "settings", action.flow.url); + return redirectFlow(action.flow.id, "settings", action.flow.url) } else { - throw new Error("Unknown action: " + JSON.stringify(action)); + throw new Error("Unknown action: " + JSON.stringify(action)) } } @@ -69,15 +69,15 @@ export function handleContinueWith( */ export function pickBestContinueWith(continueWith: ContinueWith[]) { if (!continueWith || continueWith.length === 0) { - return; + return } const sorted = continueWith.sort( (a, b) => continueWithPriority.indexOf(a.action) - - continueWithPriority.indexOf(b.action) - ); - return sorted[0]; + continueWithPriority.indexOf(b.action), + ) + return sorted[0] } /** @@ -86,11 +86,11 @@ export function pickBestContinueWith(continueWith: ContinueWith[]) { * @param continueWith - The continue with action. */ export function isSetOrySessionToken( - continueWith: ContinueWith + continueWith: ContinueWith, ): continueWith is ContinueWithSetOrySessionToken & { - action: "set_ory_session_token"; + action: "set_ory_session_token" } { - return continueWith.action === "set_ory_session_token"; + return continueWith.action === "set_ory_session_token" } /** @@ -99,11 +99,11 @@ export function isSetOrySessionToken( * @param continueWith - The continue with action. */ export function isRedirectBrowserTo( - continueWith: ContinueWith + continueWith: ContinueWith, ): continueWith is ContinueWithRedirectBrowserTo & { - action: "redirect_browser_to"; + action: "redirect_browser_to" } { - return continueWith.action === "redirect_browser_to"; + return continueWith.action === "redirect_browser_to" } /** @@ -112,11 +112,11 @@ export function isRedirectBrowserTo( * @param continueWith - The continue with action. */ export function isShowRecoveryUi( - continueWith: ContinueWith + continueWith: ContinueWith, ): continueWith is ContinueWithRecoveryUi & { - action: "show_recovery_ui"; + action: "show_recovery_ui" } { - return continueWith.action === "show_recovery_ui"; + return continueWith.action === "show_recovery_ui" } /** @@ -125,11 +125,11 @@ export function isShowRecoveryUi( * @param continueWith - The continue with action. */ export function isShowSettingsUi( - continueWith: ContinueWith + continueWith: ContinueWith, ): continueWith is ContinueWithSettingsUi & { - action: "show_settings_ui"; + action: "show_settings_ui" } { - return continueWith.action === "show_settings_ui"; + return continueWith.action === "show_settings_ui" } /** @@ -138,9 +138,9 @@ export function isShowSettingsUi( * @param continueWith - The continue with action. */ export function isShowVerificationUi( - continueWith: ContinueWith + continueWith: ContinueWith, ): continueWith is ContinueWithVerificationUi & { - action: "show_verification_ui"; + action: "show_verification_ui" } { - return continueWith.action === "show_verification_ui"; + return continueWith.action === "show_verification_ui" } diff --git a/contrib/fetch/src/error.ts b/contrib/fetch/src/error.ts index 31b50b1de8..4dc5d95f1a 100644 --- a/contrib/fetch/src/error.ts +++ b/contrib/fetch/src/error.ts @@ -8,10 +8,10 @@ import { NeedsPrivilegedSessionError, ResponseError, SelfServiceFlowExpiredError, -} from "../"; +} from "../" export function isGenericErrorResponse( - response: unknown + response: unknown, ): response is { error: GenericError } { return ( typeof response === "object" && @@ -20,7 +20,7 @@ export function isGenericErrorResponse( typeof response.error === "object" && !!response.error && "id" in response.error - ); + ) } /** @@ -30,12 +30,12 @@ export function isGenericErrorResponse( * @param response - The response to check. */ export function isNeedsPrivilegedSessionError( - response: unknown + response: unknown, ): response is NeedsPrivilegedSessionError { return ( isGenericErrorResponse(response) && response.error.id === "session_refresh_required" - ); + ) } /**1 @@ -44,12 +44,12 @@ export function isNeedsPrivilegedSessionError( * @param response - The response to check. */ export function isSelfServiceFlowExpiredError( - response: unknown + response: unknown, ): response is SelfServiceFlowExpiredError { return ( isGenericErrorResponse(response) && response.error.id === "self_service_flow_expired" - ); + ) } /** @@ -58,13 +58,13 @@ export function isSelfServiceFlowExpiredError( * @param response - The response to check. */ export function isSelfServiceFlowDisabled( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && isGenericErrorResponse(response) && response.error.id === "self_service_flow_disabled" - ); + ) } /** @@ -72,13 +72,13 @@ export function isSelfServiceFlowDisabled( * @param response - The response to check. */ export function isBrowserLocationChangeRequired( - response: unknown + response: unknown, ): response is ErrorBrowserLocationChangeRequired { return ( isGenericErrorResponse(response) && isGenericErrorResponse(response) && response.error.id === "browser_location_change_required" - ); + ) } /** @@ -86,12 +86,12 @@ export function isBrowserLocationChangeRequired( * @param response - The response to check. */ export function isSelfServiceFlowReplaced( - response: unknown + response: unknown, ): response is ErrorFlowReplaced { return ( isGenericErrorResponse(response) && response.error.id === "self_service_flow_replaced" - ); + ) } /** @@ -99,12 +99,12 @@ export function isSelfServiceFlowReplaced( * @param response - The response to check. */ export function isSessionAlreadyAvailable( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "session_already_available" - ); + ) } /** @@ -113,12 +113,12 @@ export function isSessionAlreadyAvailable( * @param response - The response to check. */ export function isAddressNotVerified( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "session_verified_address_required" - ); + ) } /** @@ -127,12 +127,12 @@ export function isAddressNotVerified( * @param response - The response to check. */ export function isAalAlreadyFulfilled( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "session_aal_already_fulfilled" - ); + ) } /** @@ -141,12 +141,12 @@ export function isAalAlreadyFulfilled( * @param response - The response to check. */ export function isSessionAal1Required( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "session_aal1_required" - ); + ) } /** @@ -155,12 +155,12 @@ export function isSessionAal1Required( * @param response - The response to check. */ export function isSessionAal2Required( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "session_aal2_required" - ); + ) } /** @@ -171,7 +171,7 @@ export function isSessionAal2Required( export function isNoActiveSession(response: unknown): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "session_inactive" - ); + ) } /** * Checks if the response is a GenericError due to a CSRF violation. @@ -182,7 +182,7 @@ export function isCsrfError(response: unknown): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "security_csrf_violation" - ); + ) } /** @@ -191,12 +191,12 @@ export function isCsrfError(response: unknown): response is GenericError { * @param response - The response to check. */ export function isRedirectUrlNotAllowed( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "self_service_flow_return_to_forbidden" - ); + ) } /** @@ -205,17 +205,17 @@ export function isRedirectUrlNotAllowed( * @param response - The response to check. */ export function isSecurityIdentityMismatch( - response: unknown + response: unknown, ): response is GenericError { return ( isGenericErrorResponse(response) && response.error.id === "security_identity_mismatch" - ); + ) } export const isResponseError = (err: unknown): err is ResponseError => { if (err instanceof ResponseError) { - return true; + return true } return ( @@ -223,5 +223,5 @@ export const isResponseError = (err: unknown): err is ResponseError => { !!err && "name" in err && err.name === "ResponseError" - ); -}; + ) +} diff --git a/contrib/fetch/src/index.ts b/contrib/fetch/src/index.ts index df941e1b60..958ecf6bb4 100644 --- a/contrib/fetch/src/index.ts +++ b/contrib/fetch/src/index.ts @@ -1,9 +1,9 @@ // Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 -export * from "./error"; -export * from "./urlHelpers"; -export * from "./flowTypes"; -export * from "./utils"; -export * from "./continueWith"; -export * from "./ui"; +export * from "./error" +export * from "./urlHelpers" +export * from "./flowTypes" +export * from "./utils" +export * from "./continueWith" +export * from "./ui" diff --git a/contrib/fetch/src/ui.ts b/contrib/fetch/src/ui.ts index 096a5bc891..41b74fa614 100644 --- a/contrib/fetch/src/ui.ts +++ b/contrib/fetch/src/ui.ts @@ -9,7 +9,7 @@ import { UiNodeScriptAttributes, UiNodeTextAttributes, UiText, -} from "../"; +} from "../" /** * Returns the node's label. @@ -18,27 +18,27 @@ import { * @returns label of the node */ export const getNodeLabel = (node: UiNode): UiText | undefined => { - const attributes = node.attributes; + const attributes = node.attributes if (isUiNodeAnchorAttributes(attributes)) { - return attributes.title; + return attributes.title } if (isUiNodeImageAttributes(attributes)) { - return node.meta.label; + return node.meta.label } if (isUiNodeInputAttributes(attributes)) { if (attributes.label) { - return attributes.label; + return attributes.label } } - return node.meta.label; -}; + return node.meta.label +} type ObjWithNodeType = { - node_type: string; -}; + node_type: string +} /** * A TypeScript type guard for nodes of the type @@ -46,9 +46,9 @@ type ObjWithNodeType = { * @param attrs - the attributes of the node */ export function isUiNodeAnchorAttributes( - attrs: ObjWithNodeType + attrs: ObjWithNodeType, ): attrs is UiNodeAnchorAttributes { - return attrs.node_type === "a"; + return attrs.node_type === "a" } /** @@ -57,9 +57,9 @@ export function isUiNodeAnchorAttributes( * @param attrs - the attributes of the node */ export function isUiNodeImageAttributes( - attrs: ObjWithNodeType + attrs: ObjWithNodeType, ): attrs is UiNodeImageAttributes { - return attrs.node_type === "img"; + return attrs.node_type === "img" } /** @@ -68,9 +68,9 @@ export function isUiNodeImageAttributes( * @param attrs - the attributes of the node */ export function isUiNodeInputAttributes( - attrs: ObjWithNodeType + attrs: ObjWithNodeType, ): attrs is UiNodeInputAttributes { - return attrs.node_type === "input"; + return attrs.node_type === "input" } /** @@ -79,9 +79,9 @@ export function isUiNodeInputAttributes( * @param attrs - the attributes of the node */ export function isUiNodeTextAttributes( - attrs: ObjWithNodeType + attrs: ObjWithNodeType, ): attrs is UiNodeTextAttributes { - return attrs.node_type === "text"; + return attrs.node_type === "text" } /** @@ -90,9 +90,9 @@ export function isUiNodeTextAttributes( * @param attrs - the attributes of the node */ export function isUiNodeScriptAttributes( - attrs: ObjWithNodeType + attrs: ObjWithNodeType, ): attrs is UiNodeScriptAttributes { - return attrs.node_type === "script"; + return attrs.node_type === "script" } /** @@ -102,9 +102,9 @@ export function isUiNodeScriptAttributes( */ export function getNodeId({ attributes }: UiNode) { if (isUiNodeInputAttributes(attributes)) { - return attributes.name; + return attributes.name } else { - return attributes.id; + return attributes.id } } @@ -117,4 +117,4 @@ export function getNodeId({ attributes }: UiNode) { * @returns type of node */ export const getNodeInputType = (attr: object): string => - "type" in attr && typeof attr?.type == "string" ? attr.type : ""; + "type" in attr && typeof attr?.type == "string" ? attr.type : "" diff --git a/contrib/fetch/src/urlHelpers.ts b/contrib/fetch/src/urlHelpers.ts index 7d8c08df5b..7d0066c5f7 100644 --- a/contrib/fetch/src/urlHelpers.ts +++ b/contrib/fetch/src/urlHelpers.ts @@ -2,16 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 export const registrationUrl = (config: { sdk: { url: string } }) => - config.sdk.url + "/self-service/registration/browser"; + config.sdk.url + "/self-service/registration/browser" export const loginUrl = (config: { sdk: { url: string } }) => - config.sdk.url + "/self-service/login/browser"; + config.sdk.url + "/self-service/login/browser" export const settingsUrl = (config: { sdk: { url: string } }) => - config.sdk.url + "/self-service/settings/browser"; + config.sdk.url + "/self-service/settings/browser" export const recoveryUrl = (config: { sdk: { url: string } }) => - config.sdk.url + "/self-service/recovery/browser"; + config.sdk.url + "/self-service/recovery/browser" export const verificationUrl = (config: { sdk: { url: string } }) => - config.sdk.url + "/self-service/verification/browser"; + config.sdk.url + "/self-service/verification/browser" diff --git a/contrib/fetch/src/utils.ts b/contrib/fetch/src/utils.ts index d85664e1bb..75892e2e8f 100644 --- a/contrib/fetch/src/utils.ts +++ b/contrib/fetch/src/utils.ts @@ -1,17 +1,17 @@ // Copyright © 2024 Ory Corp // SPDX-License-Identifier: Apache-2.0 -import { FetchError, RequiredError, ResponseError } from "../"; -import { OnRedirectHandler } from "./continueWith"; +import { FetchError, RequiredError, ResponseError } from "../" +import { OnRedirectHandler } from "./continueWith" import { isBrowserLocationChangeRequired, isCsrfError, isNeedsPrivilegedSessionError, isResponseError, isSelfServiceFlowExpiredError, -} from "./error"; +} from "./error" -export type ValidationErrorHandler = (body: T) => void; +export type ValidationErrorHandler = (body: T) => void type FlowErrorHandlerProps = { /** @@ -19,7 +19,7 @@ type FlowErrorHandlerProps = { * * @param useFlowId - If provided, the SDK should use this flow ID to not lose context of the flow. */ - onRestartFlow: (useFlowId?: string) => void; + onRestartFlow: (useFlowId?: string) => void /** * When the SDK returns a validation error, this function is called. The result should be used to update the @@ -29,13 +29,13 @@ type FlowErrorHandlerProps = { * * @param body - The body of the response. */ - onValidationError: ValidationErrorHandler; + onValidationError: ValidationErrorHandler /** * This method is used to redirect the user to a different page. */ - onRedirect: OnRedirectHandler; -}; + onRedirect: OnRedirectHandler +} /** * Use this as the catch handler for all flow-related SDK calls, such as creating a login or submitting a login. @@ -44,80 +44,80 @@ type FlowErrorHandlerProps = { * @param opts - The configuration object. */ export const handleFlowError = - (opts: FlowErrorHandlerProps) => - async (err: unknown): Promise => { - if (isResponseError(err)) { - switch (err.response.status) { - case 404: // Does not exist - opts.onRestartFlow(); - return; - case 410: // Expired - const body = await toBody(err.response); - if (isSelfServiceFlowExpiredError(body)) { - opts.onRestartFlow(body.use_flow_id); - return; - } - // Re-initialize the flow - opts.onRestartFlow(); - return; - case 400: - return opts.onValidationError( - // TODO: maybe we can do actual type checking here? - (await err.response.json()) as unknown as T - ); - case 403: // This typically happens with CSRF violations. - case 422: { - const body = await toBody(err.response); - if ( - isBrowserLocationChangeRequired(body) && - body.redirect_browser_to - ) { - opts.onRedirect(body.redirect_browser_to, true); - return; - } else if (isSelfServiceFlowExpiredError(body)) { - opts.onRestartFlow(body.use_flow_id); - return; - } else if (isNeedsPrivilegedSessionError(body)) { - opts.onRedirect(body.redirect_browser_to, true); - return; - } else if (isCsrfError(body)) { - opts.onRestartFlow(); - return; - } + (opts: FlowErrorHandlerProps) => + async (err: unknown): Promise => { + if (isResponseError(err)) { + switch (err.response.status) { + case 404: // Does not exist + opts.onRestartFlow() + return + case 410: // Expired + const body = await toBody(err.response) + if (isSelfServiceFlowExpiredError(body)) { + opts.onRestartFlow(body.use_flow_id) + return + } + // Re-initialize the flow + opts.onRestartFlow() + return + case 400: + return opts.onValidationError( + // TODO: maybe we can do actual type checking here? + (await err.response.json()) as unknown as T, + ) + case 403: // This typically happens with CSRF violations. + case 422: { + const body = await toBody(err.response) + if ( + isBrowserLocationChangeRequired(body) && + body.redirect_browser_to + ) { + opts.onRedirect(body.redirect_browser_to, true) + return + } else if (isSelfServiceFlowExpiredError(body)) { + opts.onRestartFlow(body.use_flow_id) + return + } else if (isNeedsPrivilegedSessionError(body)) { + opts.onRedirect(body.redirect_browser_to, true) + return + } else if (isCsrfError(body)) { + opts.onRestartFlow() + return + } - throw new ResponseError( - err.response, - "The Ory API endpoint returned a response code the SDK does not know how to handle. Please check the network tab for more information:" + - JSON.stringify(body) - ); - } + throw new ResponseError( + err.response, + "The Ory API endpoint returned a response code the SDK does not know how to handle. Please check the network tab for more information:" + + JSON.stringify(body), + ) + } - default: - throw new ResponseError( - err.response, - "The Ory API endpoint returned a response code the SDK does not know how to handle. Please check the network tab for more information." - ); - } - } else if (err instanceof FetchError) { - throw new FetchError( - err, - "Unable to call the API endpoint. Ensure that CORS is set up correctly and that you have provided a valid SDK URL to Ory Elements." - ); - } else if (err instanceof RequiredError) { - // TODO (@aeneasr) Happens on submit usually. Not sure how to handle yet. - } + default: + throw new ResponseError( + err.response, + "The Ory API endpoint returned a response code the SDK does not know how to handle. Please check the network tab for more information.", + ) + } + } else if (err instanceof FetchError) { + throw new FetchError( + err, + "Unable to call the API endpoint. Ensure that CORS is set up correctly and that you have provided a valid SDK URL to Ory Elements.", + ) + } else if (err instanceof RequiredError) { + // TODO (@aeneasr) Happens on submit usually. Not sure how to handle yet. + } - throw err; - }; + throw err + } export async function toBody(response: Response): Promise { try { - return (await response.clone().json()) as unknown; + return (await response.clone().json()) as unknown } catch (e) { throw new ResponseError( - response, - "The Ory API endpoint returned a response the SDK does not know how to handle:" + - (await response.text()) - ); + response, + "The Ory API endpoint returned a response the SDK does not know how to handle:" + + (await response.text()), + ) } } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..2b7ea69cee --- /dev/null +++ b/package-lock.json @@ -0,0 +1,35 @@ +{ + "name": "sdk", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "ory-prettier-styles": "1.3.0", + "prettier": "2.7.1" + } + }, + "node_modules/ory-prettier-styles": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ory-prettier-styles/-/ory-prettier-styles-1.3.0.tgz", + "integrity": "sha512-Vfn0G6CyLaadwcCamwe1SQCf37ZQfBDgMrhRI70dE/2fbE3Q43/xu7K5c32I5FGt/EliroWty5yBjmdkj0eWug==", + "dev": true + }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..1504e306e1 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "private": true, + "scripts": { + "format": "prettier --write 'contrib/**/*{.ts,.js}'" + }, + "prettier": "ory-prettier-styles", + "devDependencies": { + "ory-prettier-styles": "1.3.0", + "prettier": "2.7.1" + } +}