feat(proxy-server): add local fs middleware and make it the default (#3217)
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { applyDefaults, detectProxyServer } from '../config';
|
||||
import { applyDefaults, detectProxyServer, handleLocalBackend } from '../config';
|
||||
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
@ -185,38 +185,46 @@ describe('config', () => {
|
||||
delete window.location;
|
||||
});
|
||||
|
||||
it('should return undefined when not on localhost', async () => {
|
||||
it('should return empty object when not on localhost', async () => {
|
||||
window.location = { hostname: 'www.netlify.com' };
|
||||
global.fetch = jest.fn();
|
||||
await expect(detectProxyServer()).resolves.toBeUndefined();
|
||||
await expect(detectProxyServer()).resolves.toEqual({});
|
||||
|
||||
expect(global.fetch).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('should return undefined when fetch returns an error', async () => {
|
||||
it('should return empty object when fetch returns an error', async () => {
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest.fn().mockRejectedValue(new Error());
|
||||
await expect(detectProxyServer(true)).resolves.toBeUndefined();
|
||||
await expect(detectProxyServer(true)).resolves.toEqual({});
|
||||
|
||||
assetFetchCalled();
|
||||
});
|
||||
|
||||
it('should return undefined when fetch returns an invalid response', async () => {
|
||||
it('should return empty object when fetch returns an invalid response', async () => {
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest
|
||||
.fn()
|
||||
.mockResolvedValue({ json: jest.fn().mockResolvedValue({ repo: [] }) });
|
||||
await expect(detectProxyServer(true)).resolves.toBeUndefined();
|
||||
await expect(detectProxyServer(true)).resolves.toEqual({});
|
||||
|
||||
assetFetchCalled();
|
||||
});
|
||||
|
||||
it('should return proxyUrl when fetch returns a valid response', async () => {
|
||||
it('should return result object when fetch returns a valid response', async () => {
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest
|
||||
.fn()
|
||||
.mockResolvedValue({ json: jest.fn().mockResolvedValue({ repo: 'test-repo' }) });
|
||||
await expect(detectProxyServer(true)).resolves.toBe('http://localhost:8081/api/v1');
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
json: jest.fn().mockResolvedValue({
|
||||
repo: 'test-repo',
|
||||
publish_modes: ['simple', 'editorial_workflow'],
|
||||
type: 'local_git',
|
||||
}),
|
||||
});
|
||||
await expect(detectProxyServer(true)).resolves.toEqual({
|
||||
proxyUrl: 'http://localhost:8081/api/v1',
|
||||
publish_modes: ['simple', 'editorial_workflow'],
|
||||
type: 'local_git',
|
||||
});
|
||||
|
||||
assetFetchCalled();
|
||||
});
|
||||
@ -224,12 +232,83 @@ describe('config', () => {
|
||||
it('should use local_backend url', async () => {
|
||||
const url = 'http://localhost:8082/api/v1';
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest
|
||||
.fn()
|
||||
.mockResolvedValue({ json: jest.fn().mockResolvedValue({ repo: 'test-repo' }) });
|
||||
await expect(detectProxyServer({ url })).resolves.toBe(url);
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
json: jest.fn().mockResolvedValue({
|
||||
repo: 'test-repo',
|
||||
publish_modes: ['simple', 'editorial_workflow'],
|
||||
type: 'local_git',
|
||||
}),
|
||||
});
|
||||
await expect(detectProxyServer({ url })).resolves.toEqual({
|
||||
proxyUrl: url,
|
||||
publish_modes: ['simple', 'editorial_workflow'],
|
||||
type: 'local_git',
|
||||
});
|
||||
|
||||
assetFetchCalled(url);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleLocalBackend', () => {
|
||||
beforeEach(() => {
|
||||
delete window.location;
|
||||
});
|
||||
|
||||
it('should not replace backend config when proxy is not detected', async () => {
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest.fn().mockRejectedValue(new Error());
|
||||
|
||||
const config = fromJS({ local_backend: true, backend: { name: 'github' } });
|
||||
const actual = await handleLocalBackend(config);
|
||||
|
||||
expect(actual).toEqual(config);
|
||||
});
|
||||
|
||||
it('should replace backend config when proxy is detected', async () => {
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
json: jest.fn().mockResolvedValue({
|
||||
repo: 'test-repo',
|
||||
publish_modes: ['simple', 'editorial_workflow'],
|
||||
type: 'local_git',
|
||||
}),
|
||||
});
|
||||
|
||||
const config = fromJS({ local_backend: true, backend: { name: 'github' } });
|
||||
const actual = await handleLocalBackend(config);
|
||||
|
||||
expect(actual).toEqual(
|
||||
fromJS({
|
||||
local_backend: true,
|
||||
backend: { name: 'proxy', proxy_url: 'http://localhost:8081/api/v1' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should replace publish mode when not supported by proxy', async () => {
|
||||
window.location = { hostname: 'localhost' };
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
json: jest.fn().mockResolvedValue({
|
||||
repo: 'test-repo',
|
||||
publish_modes: ['simple'],
|
||||
type: 'local_fs',
|
||||
}),
|
||||
});
|
||||
|
||||
const config = fromJS({
|
||||
local_backend: true,
|
||||
publish_mode: 'editorial_workflow',
|
||||
backend: { name: 'github' },
|
||||
});
|
||||
const actual = await handleLocalBackend(config);
|
||||
|
||||
expect(actual).toEqual(
|
||||
fromJS({
|
||||
local_backend: true,
|
||||
publish_mode: 'simple',
|
||||
backend: { name: 'proxy', proxy_url: 'http://localhost:8081/api/v1' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -155,19 +155,48 @@ export async function detectProxyServer(localBackend) {
|
||||
}
|
||||
try {
|
||||
console.log(`Looking for Netlify CMS Proxy Server at '${proxyUrl}'`);
|
||||
const { repo } = await fetch(`${proxyUrl}`, {
|
||||
const { repo, publish_modes, type } = await fetch(`${proxyUrl}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action: 'info' }),
|
||||
}).then(res => res.json());
|
||||
if (typeof repo === 'string') {
|
||||
if (typeof repo === 'string' && Array.isArray(publish_modes) && typeof type === 'string') {
|
||||
console.log(`Detected Netlify CMS Proxy Server at '${proxyUrl}' with repo: '${repo}'`);
|
||||
return proxyUrl;
|
||||
return { proxyUrl, publish_modes, type };
|
||||
}
|
||||
} catch {
|
||||
console.log(`Netlify CMS Proxy Server not detected at '${proxyUrl}'`);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
export async function handleLocalBackend(mergedConfig) {
|
||||
if (mergedConfig.has('local_backend')) {
|
||||
const { proxyUrl, publish_modes, type } = await detectProxyServer(
|
||||
mergedConfig.toJS().local_backend,
|
||||
);
|
||||
if (proxyUrl) {
|
||||
mergedConfig = mergePreloadedConfig(mergedConfig, {
|
||||
backend: { name: 'proxy', proxy_url: proxyUrl },
|
||||
});
|
||||
if (
|
||||
mergedConfig.has('publish_mode') &&
|
||||
!publish_modes.includes(mergedConfig.get('publish_mode'))
|
||||
) {
|
||||
const newPublishMode = publish_modes[0];
|
||||
console.log(
|
||||
`'${mergedConfig.get(
|
||||
'publish_mode',
|
||||
)}' is not supported by '${type}' backend, switching to '${newPublishMode}'`,
|
||||
);
|
||||
mergedConfig = mergePreloadedConfig(mergedConfig, {
|
||||
publish_mode: newPublishMode,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return mergedConfig;
|
||||
}
|
||||
|
||||
export function loadConfig() {
|
||||
@ -193,15 +222,7 @@ export function loadConfig() {
|
||||
|
||||
validateConfig(mergedConfig.toJS());
|
||||
|
||||
// detect running Netlify CMS proxy
|
||||
if (mergedConfig.has('local_backend')) {
|
||||
const proxyUrl = await detectProxyServer(mergedConfig.toJS().local_backend);
|
||||
if (proxyUrl) {
|
||||
mergedConfig = mergePreloadedConfig(mergedConfig, {
|
||||
backend: { name: 'proxy', proxy_url: proxyUrl },
|
||||
});
|
||||
}
|
||||
}
|
||||
mergedConfig = await handleLocalBackend(mergedConfig);
|
||||
|
||||
const config = applyDefaults(mergedConfig);
|
||||
|
||||
|
Reference in New Issue
Block a user