Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composition: Verify refs in node #12085

Merged
merged 10 commits into from
Aug 20, 2020
19 changes: 5 additions & 14 deletions lib/api/src/modules/refs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface ComposedRef {
id: string;
title?: string;
url: string;
type?: 'auto-inject' | 'unknown' | 'lazy';
type?: 'auto-inject' | 'unknown' | 'lazy' | 'server-checked';
ndelangen marked this conversation as resolved.
Show resolved Hide resolved
stories: StoriesHash;
versions?: Versions;
loginUrl?: string;
Expand All @@ -46,7 +46,7 @@ export interface ComposedRef {
}
export interface ComposedRefUpdate {
title?: string;
type?: 'auto-inject' | 'unknown' | 'lazy';
type?: 'auto-inject' | 'unknown' | 'lazy' | 'server-checked';
ndelangen marked this conversation as resolved.
Show resolved Hide resolved
stories?: StoriesHash;
versions?: Versions;
loginUrl?: string;
Expand Down Expand Up @@ -135,12 +135,12 @@ export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true }
});
},
checkRef: async (ref) => {
const { id, url, version } = ref;
const { id, url, version, type } = ref;

const loadedData: { error?: Error; stories?: StoriesRaw; loginUrl?: string } = {};
const query = version ? `?version=${version}` : '';

const [included, omitted, iframe] = await allSettled([
const [included, omitted] = await allSettled([
fetch(`${url}/stories.json${query}`, {
headers: {
Accept: 'application/json',
Expand All @@ -153,10 +153,6 @@ export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true }
},
credentials: 'omit',
}),
fetch(`${url}/iframe.html${query}`, {
mode: 'no-cors',
credentials: 'omit',
}),
]);

const handle = async (request: Response | false): Promise<SetRefData> => {
Expand All @@ -168,7 +164,7 @@ export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true }
return {};
};

if (!included && !omitted && !iframe) {
if (!included && !omitted && type !== 'server-checked') {
ndelangen marked this conversation as resolved.
Show resolved Hide resolved
loadedData.error = {
message: dedent`
Error: Loading of ref failed
Expand Down Expand Up @@ -244,11 +240,6 @@ export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true }

const initialState: SubState['refs'] = refs;

Object.values(refs).forEach((r) => {
// eslint-disable-next-line no-param-reassign
r.type = 'unknown';
});

if (runCheck) {
Object.entries(refs).forEach(([k, v]) => {
api.checkRef(v as SetRefData);
Expand Down
12 changes: 12 additions & 0 deletions lib/core/src/server/manager/manager-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from 'path';
import fs from 'fs-extra';
import findUp from 'find-up';
import resolveFrom from 'resolve-from';
import fetch from 'node-fetch';

import { logger } from '@storybook/node-logger';

Expand Down Expand Up @@ -91,6 +92,17 @@ async function getManagerWebpackConfig(options, presets) {
}
if (autoRefs || definedRefs) {
entries.push(path.resolve(path.join(options.configDir, `generated-refs.js`)));

// verify the refs are publicly reachable, if they are not we'll require stories.json at runtime, otherwise the ref won't work
await Promise.all(
Object.entries(refs).map(async ([k, value]) => {
const { ok } = await fetch(`${value.url}/iframe.html`).catch((e) => ({
ok: false,
}));
ndelangen marked this conversation as resolved.
Show resolved Hide resolved

refs[k] = { ...value, type: ok ? 'server-checked' : 'unknown' };
})
);
}

return presets.apply('managerWebpack', {}, { ...options, babelOptions, entries, refs });
Expand Down