UNPKG

@shopify/app-bridge-core

Version:

**[Join our team and work on libraries like this one.](https://www.shopify.ca/careers)**

102 lines (99 loc) 3.85 kB
import { validate, composeSchemas, matchesObject, matchesString, makeOptional, matchesArray } from '../type-validate.js'; import { createActionValidator, relativePathSchema } from '../utils.js'; import { Action, isIframeModal, Size } from '../../actions/Modal/index.js'; import { Action as Action$1 } from '../../actions/Button/index.js'; import { isSafe } from '../safe-redirect.js'; import { validateAction as validateAction$1, buttonSchemaWithId } from './button.js'; function matchesSafeOrigin(value, localOrigin) { let hostName; try { hostName = new URL(localOrigin).hostname; } catch (error) { return [ { error: 'invalid_app_origin', value: localOrigin, message: `Provided value for app origin: \`${localOrigin}\` is invalid`, }, ]; } const isSafeSrc = isSafe(value, { requireAbsolute: true, requireSSL: true, allowInternalProtocol: true, allowedDomains: [hostName], }); if (!isSafeSrc) { return [ { error: 'not_matching_app_origin', value, message: `Provided URL origin does not match app origin \`${hostName}\``, }, ]; } } function matchesSize() { return (value) => { const values = [Size.Small, Size.Medium, Size.Large]; if (values.includes(value)) { return; } let message = `expected:${values.map((val) => `\`${val}\``).join(' or ')}`; if (value === Size.Full) { message += `. Size \`${value}\` is deprecated as of version 1.6.5 and will fall back to size \`medium\``; } if (value === Size.Auto) { message += `. Size \`${value}\` is deprecated as of version 1.12.x and will fall back to size \`medium\`. Use the \`setUpModalAutoSizing\` utility from \`app-bridge\` instead`; } return [ { error: 'invalid_enum_value', value, message, }, ]; }; } function getModalSchema(props = {}, localOrigin) { const baseModalSchema = matchesObject({ title: makeOptional(matchesString()), footer: makeOptional(matchesObject({ buttons: matchesObject({ primary: makeOptional(buttonSchemaWithId), secondary: makeOptional(matchesArray(buttonSchemaWithId)), }), })), size: makeOptional(matchesSize()), }); if (isIframeModal(props)) { if (props.url) { const urlSchema = matchesObject({ url: composeSchemas(matchesString(), (value) => localOrigin ? matchesSafeOrigin(value, localOrigin) : undefined), }); return composeSchemas(baseModalSchema, urlSchema); } return composeSchemas(baseModalSchema, relativePathSchema); } return composeSchemas(baseModalSchema, matchesObject({ message: matchesString() })); } function validateProps(props, localOrigin) { return validate(props, getModalSchema(props, localOrigin)); } function validateAction(action, localOrigin) { const schema = getModalSchema(action.payload, localOrigin); switch (action.type) { case Action.OPEN: case Action.UPDATE: return validate(action, createActionValidator(Action, schema, true, action.type === Action.UPDATE)); case Action.FOOTER_BUTTON_CLICK: return validateAction$1({ ...action, type: Action$1.CLICK }); case Action.FOOTER_BUTTON_UPDATE: return validateAction$1({ ...action, type: Action$1.UPDATE }); case Action.CLOSE: default: return validate(action, createActionValidator(Action)); } } export { Action, validateAction, validateProps };