@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
JavaScript
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 };