@thepalaceproject/circulation-admin 0.0.0-post.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +59 -0
- package/.node-version +1 -0
- package/.nvmrc +1 -0
- package/.prettierrc.json +10 -0
- package/.sass-lint.yml +37 -0
- package/CHANGELOG.md +946 -0
- package/README.md +155 -0
- package/dist/060b2710bdbbe3dfe48b58d59bd5f1fb.svg +288 -0
- package/dist/0db1520f47986b6c755a.svg +1 -0
- package/dist/1e59d2330b4c6deb84b3.ttf +0 -0
- package/dist/20fd1704ea223900efa9.woff2 +0 -0
- package/dist/4692b9ec53fd5972caa2.ttf +0 -0
- package/dist/5be1347c682810f199c7.eot +0 -0
- package/dist/6563aa3790be8329e4f2.svg +1 -0
- package/dist/82b1212e45a2bc35dd73.woff +0 -0
- package/dist/8b43027f47b20503057d.eot +0 -0
- package/dist/PalaceCollectionManagerLogo.svg +122 -0
- package/dist/be810be3a3e14c682a25.woff2 +0 -0
- package/dist/c1e38fd9e0e74ba58f7a2b77ef29fdd3.svg +2671 -0
- package/dist/circulation-admin.css +6841 -0
- package/dist/circulation-admin.js +2 -0
- package/dist/circulation-admin.js.LICENSE.txt +153 -0
- package/dist/f691f37e57f04c152e23.woff +0 -0
- package/jest.config.js +15 -0
- package/jest.polyfills.js +12 -0
- package/nightwatch.json +58 -0
- package/package.json +155 -0
- package/pull_request_template.md +22 -0
- package/requirements-ci.txt +1 -0
- package/testReporter.js +31 -0
- package/tests/__data__/statisticsApiResponseData.ts +327 -0
- package/tests/__mocks__/fileMock.js +1 -0
- package/tests/__mocks__/styleMock.js +1 -0
- package/tests/browser/README.md +19 -0
- package/tests/browser/assertions/noError.js +38 -0
- package/tests/browser/commands/goHome.js +13 -0
- package/tests/browser/commands/signIn.js +18 -0
- package/tests/browser/globals.js.sample +5 -0
- package/tests/browser/navigate.js +294 -0
- package/tests/browser/pages/book.js +21 -0
- package/tests/browser/pages/catalog.js +24 -0
- package/tests/browser/pages/login.js +11 -0
- package/tests/browser/redirect.js +104 -0
- package/tests/browser/signInFailure.js +22 -0
- package/tests/jest/README.md +6 -0
- package/tests/jest/api/admin.test.ts +60 -0
- package/tests/jest/businessRules/roleBasedAccess.test.ts +250 -0
- package/tests/jest/components/AdvancedSearchBuilder.test.tsx +38 -0
- package/tests/jest/components/BookEditor.test.tsx +240 -0
- package/tests/jest/components/CirculationEventsDownload.test.tsx +65 -0
- package/tests/jest/components/CustomLists.test.tsx +203 -0
- package/tests/jest/components/EditableInput.test.tsx +64 -0
- package/tests/jest/components/IndividualAdminEditForm.test.tsx +128 -0
- package/tests/jest/components/InventoryReportRequestModal.test.tsx +652 -0
- package/tests/jest/components/Lane.test.tsx +78 -0
- package/tests/jest/components/LaneEditor.test.tsx +148 -0
- package/tests/jest/components/ProtocolFormField.test.tsx +37 -0
- package/tests/jest/components/QuicksightDashboard.test.tsx +67 -0
- package/tests/jest/components/Stats.test.tsx +699 -0
- package/tests/jest/context/AppContext.test.tsx +113 -0
- package/tests/jest/features/book.test.ts +396 -0
- package/tests/jest/jest-setup.ts +1 -0
- package/tests/jest/sample/sample.test.js +3 -0
- package/tests/jest/testUtils/renderWithContext.tsx +38 -0
- package/tests/jest/testUtils/withProviders.tsx +92 -0
- package/tests/jest/utils/NoCacheDataFetcher.test.ts +75 -0
- package/tsconfig.json +25 -0
- package/tslint.json +56 -0
- package/webpack.common.js +72 -0
- package/webpack.dev-server.config.js +215 -0
- package/webpack.dev.config.js +9 -0
- package/webpack.prod.config.js +8 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Need to manually mock DataFetcher before importing NoCacheDataFetcher
|
|
2
|
+
const mockSuperFetch = jest.fn();
|
|
3
|
+
|
|
4
|
+
// Mock the DataFetcher module
|
|
5
|
+
jest.mock("@thepalaceproject/web-opds-client/lib/DataFetcher", () => ({
|
|
6
|
+
__esModule: true,
|
|
7
|
+
default: class MockDataFetcher {
|
|
8
|
+
fetch(url: string, options?: any) {
|
|
9
|
+
return mockSuperFetch(url, options);
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
// Import after mocking
|
|
15
|
+
import NoCacheDataFetcher from "../../../src/utils/NoCacheDataFetcher";
|
|
16
|
+
|
|
17
|
+
const TEST_URL = "http://example.com";
|
|
18
|
+
|
|
19
|
+
describe("NoCacheDataFetcher", () => {
|
|
20
|
+
let fetcher: NoCacheDataFetcher;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
// Clear mocks between tests
|
|
24
|
+
mockSuperFetch.mockClear();
|
|
25
|
+
|
|
26
|
+
// Create instance of class under test
|
|
27
|
+
fetcher = new NoCacheDataFetcher();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("adds no-cache headers to fetch requests", async () => {
|
|
31
|
+
await fetcher.fetch(TEST_URL);
|
|
32
|
+
|
|
33
|
+
expect(mockSuperFetch).toHaveBeenCalledWith(
|
|
34
|
+
TEST_URL,
|
|
35
|
+
expect.objectContaining({
|
|
36
|
+
headers: { "Cache-Control": "no-cache" },
|
|
37
|
+
cache: "no-cache",
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("preserves existing headers when adding no-cache headers", async () => {
|
|
43
|
+
const options = {
|
|
44
|
+
headers: { "Content-Type": "application/json" },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
await fetcher.fetch(TEST_URL, options);
|
|
48
|
+
|
|
49
|
+
expect(mockSuperFetch).toHaveBeenCalledWith(
|
|
50
|
+
TEST_URL,
|
|
51
|
+
expect.objectContaining({
|
|
52
|
+
headers: {
|
|
53
|
+
"Cache-Control": "no-cache",
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
},
|
|
56
|
+
cache: "no-cache",
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("passes through other options to super.fetch", async () => {
|
|
62
|
+
await fetcher.fetch(TEST_URL, {
|
|
63
|
+
credentials: "include",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(mockSuperFetch).toHaveBeenCalledWith(
|
|
67
|
+
TEST_URL,
|
|
68
|
+
expect.objectContaining({
|
|
69
|
+
headers: { "Cache-Control": "no-cache" },
|
|
70
|
+
cache: "no-cache",
|
|
71
|
+
credentials: "include",
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.8.2",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"target": "es5",
|
|
6
|
+
"outDir": "lib",
|
|
7
|
+
"lib": ["es2023.array","es2019", "dom"],
|
|
8
|
+
"rootDir": ".",
|
|
9
|
+
// Mocha and jest are both used in this project. Certain globals are declared by both,
|
|
10
|
+
// such as describe, it, and test. Setting skipLibCheck to true prevents typescript from
|
|
11
|
+
// erroring when it sees duplicate variable declarations with different types.
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"types": ["mocha", "node", "jest", "@testing-library/jest-dom"],
|
|
14
|
+
"jsx": "react"
|
|
15
|
+
},
|
|
16
|
+
"exclude": [
|
|
17
|
+
"lib",
|
|
18
|
+
"node_modules",
|
|
19
|
+
"tests/browser"
|
|
20
|
+
],
|
|
21
|
+
"typedocOptions": {
|
|
22
|
+
"entryPointStrategy": "expand",
|
|
23
|
+
"out": "docs"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/tslint.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["tslint-react-a11y"],
|
|
3
|
+
"rules": {
|
|
4
|
+
"class-name": true,
|
|
5
|
+
"comment-format": [
|
|
6
|
+
true,
|
|
7
|
+
"check-space"
|
|
8
|
+
],
|
|
9
|
+
"indent": [
|
|
10
|
+
true,
|
|
11
|
+
"spaces"
|
|
12
|
+
],
|
|
13
|
+
"no-duplicate-variable": true,
|
|
14
|
+
"no-eval": true,
|
|
15
|
+
"no-internal-module": true,
|
|
16
|
+
"no-trailing-whitespace": true,
|
|
17
|
+
"no-var-keyword": true,
|
|
18
|
+
"one-line": [
|
|
19
|
+
true,
|
|
20
|
+
"check-open-brace",
|
|
21
|
+
"check-whitespace"
|
|
22
|
+
],
|
|
23
|
+
"quotemark": [
|
|
24
|
+
true,
|
|
25
|
+
"double",
|
|
26
|
+
"avoid-escape"
|
|
27
|
+
],
|
|
28
|
+
"semicolon": true,
|
|
29
|
+
"triple-equals": [
|
|
30
|
+
true,
|
|
31
|
+
"allow-null-check"
|
|
32
|
+
],
|
|
33
|
+
"typedef-whitespace": [
|
|
34
|
+
true,
|
|
35
|
+
{
|
|
36
|
+
"call-signature": "nospace",
|
|
37
|
+
"index-signature": "nospace",
|
|
38
|
+
"parameter": "nospace",
|
|
39
|
+
"property-declaration": "nospace",
|
|
40
|
+
"variable-declaration": "nospace"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"variable-name": [
|
|
44
|
+
true,
|
|
45
|
+
"ban-keywords"
|
|
46
|
+
],
|
|
47
|
+
"whitespace": [
|
|
48
|
+
true,
|
|
49
|
+
"check-branch",
|
|
50
|
+
"check-decl",
|
|
51
|
+
"check-operator",
|
|
52
|
+
"check-separator",
|
|
53
|
+
"check-type"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const CleanWebpackPlugin = require("clean-webpack-plugin");
|
|
4
|
+
const webpack = require("webpack");
|
|
5
|
+
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
|
6
|
+
const TerserPlugin = require("terser-webpack-plugin");
|
|
7
|
+
const CopyPlugin = require("copy-webpack-plugin");
|
|
8
|
+
/* eslint-enable @typescript-eslint/no-var-requires */
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
entry: {
|
|
12
|
+
app: ["./src/stylesheets/app.scss", "./src/index.tsx"],
|
|
13
|
+
},
|
|
14
|
+
output: {
|
|
15
|
+
path: path.resolve(__dirname, "./dist"),
|
|
16
|
+
filename: "circulation-admin.js",
|
|
17
|
+
library: "CirculationAdmin",
|
|
18
|
+
libraryTarget: "umd",
|
|
19
|
+
},
|
|
20
|
+
plugins: [
|
|
21
|
+
new CleanWebpackPlugin(),
|
|
22
|
+
// jsdom is needed for server rendering, but causes errors
|
|
23
|
+
// in the browser even if it is never used, so we ignore it:
|
|
24
|
+
new webpack.IgnorePlugin({ resourceRegExp: /jsdom$/ }),
|
|
25
|
+
// Extract separate css file.
|
|
26
|
+
new MiniCssExtractPlugin({ filename: "circulation-admin.css" }),
|
|
27
|
+
// Set a local global variable in the app that will be used only
|
|
28
|
+
// for testing AXE in development mode.
|
|
29
|
+
new webpack.DefinePlugin({
|
|
30
|
+
"process.env.TEST_AXE": JSON.stringify(process.env.TEST_AXE),
|
|
31
|
+
}),
|
|
32
|
+
// Publish the logo to dist.
|
|
33
|
+
new CopyPlugin({
|
|
34
|
+
patterns: ["src/images/PalaceCollectionManagerLogo.svg"],
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
optimization: {
|
|
38
|
+
minimizer: [new TerserPlugin({ terserOptions: { compress: false } })],
|
|
39
|
+
},
|
|
40
|
+
module: {
|
|
41
|
+
rules: [
|
|
42
|
+
{
|
|
43
|
+
test: /\.scss$/,
|
|
44
|
+
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
test: /\.tsx?$/,
|
|
48
|
+
exclude: [/node_modules/],
|
|
49
|
+
use: ["ts-loader"],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
test: /\.(ttf|woff|eot|woff2)(\?[\s\S]+)?$/,
|
|
53
|
+
type: "asset/resource",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
test: /\.(svg|png|gif|jpg)(\?[\s\S]+)?$/,
|
|
57
|
+
use: ["url-loader?limit=100000"],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
resolve: {
|
|
62
|
+
alias: {
|
|
63
|
+
react: path.resolve("./node_modules/react"),
|
|
64
|
+
},
|
|
65
|
+
extensions: [".ts", ".tsx", ".js", ".scss"],
|
|
66
|
+
fallback: {
|
|
67
|
+
stream: require.resolve("stream-browserify"),
|
|
68
|
+
timers: require.resolve("timers-browserify"),
|
|
69
|
+
url: require.resolve("url"),
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This webpack config establishes a proxy server to enable a local build of circulation-admin to
|
|
5
|
+
* connect to a remote Circulation Manager back-end. Requests for webpack assets are served from
|
|
6
|
+
* memory; other requests are proxied to the specified Circulation Manager.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npm run dev-server -- --env=backend=https://gorgon.tpp-qa.lyrasistechnology.org
|
|
10
|
+
* or
|
|
11
|
+
* npx webpack serve --config webpack.dev-server.config --env=backend=https://gorgon.tpp-qa.lyrasistechnology.org
|
|
12
|
+
*
|
|
13
|
+
* This makes the circulation-admin webapp available at http://localhost:8080/admin.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
createProxyMiddleware,
|
|
18
|
+
responseInterceptor,
|
|
19
|
+
} = require("http-proxy-middleware");
|
|
20
|
+
|
|
21
|
+
const { merge } = require("webpack-merge");
|
|
22
|
+
const { URL } = require("url");
|
|
23
|
+
const dev = require("./webpack.dev.config.js");
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The public path to local webpack assets. This is chosen to have low chance of collision with any
|
|
27
|
+
* path on the back-end (e.g., a library ID, or "/admin"). This should start and end with slashes.
|
|
28
|
+
*/
|
|
29
|
+
const devAssetsPublicPath = "/webpack-dev-assets/";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Build the webpack configuration.
|
|
33
|
+
* See https://webpack.js.org/configuration/configuration-types/#exporting-a-function
|
|
34
|
+
*
|
|
35
|
+
* @param {object} env The environment.
|
|
36
|
+
* @returns The webpack configuration.
|
|
37
|
+
*/
|
|
38
|
+
module.exports = (env) => {
|
|
39
|
+
const { backend } = env;
|
|
40
|
+
|
|
41
|
+
if (!backend) {
|
|
42
|
+
console.error("Please specify the URL of a Circulation Manager back-end.");
|
|
43
|
+
|
|
44
|
+
console.error(
|
|
45
|
+
"Example: npm run dev-server -- --env=backend=https://gorgon.tpp-qa.lyrasistechnology.org"
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
throw "No back-end URL was specified.";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.info(`Using Circulation Manager back-end: ${backend}`);
|
|
52
|
+
|
|
53
|
+
const backendUrl = new URL(backend);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Rewrite a location header (as received in a 3xx response). This changes back-end URLs to
|
|
57
|
+
* point to the local server instead. The CM may redirect to a URL that contains a "redirect"
|
|
58
|
+
* parameter that contains another URL. The "redirect" parameter is also rewritten.
|
|
59
|
+
*
|
|
60
|
+
* @param res The response.
|
|
61
|
+
* @param req The request.
|
|
62
|
+
*/
|
|
63
|
+
const rewriteLocationHeader = (res, req) => {
|
|
64
|
+
const location = res.getHeader("location");
|
|
65
|
+
|
|
66
|
+
if (!location) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const locationUrl = new URL(location, backendUrl);
|
|
71
|
+
|
|
72
|
+
if (locationUrl.host !== backendUrl.host) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const requestHost = req.headers.host;
|
|
77
|
+
|
|
78
|
+
if (!requestHost) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
locationUrl.protocol = "http";
|
|
83
|
+
locationUrl.host = requestHost;
|
|
84
|
+
|
|
85
|
+
const redirectParam = locationUrl.searchParams.get("redirect");
|
|
86
|
+
|
|
87
|
+
if (redirectParam) {
|
|
88
|
+
const redirectUrl = new URL(redirectParam);
|
|
89
|
+
|
|
90
|
+
if (redirectUrl.host == backendUrl.host) {
|
|
91
|
+
redirectUrl.protocol = "http";
|
|
92
|
+
redirectUrl.host = requestHost;
|
|
93
|
+
|
|
94
|
+
locationUrl.searchParams.set("redirect", redirectUrl.href);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
res.setHeader("location", locationUrl.href);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Rewrites an OpenSearch description response. This changes back-end URLs in the description to
|
|
103
|
+
* point to the local server instead. This is a simple find-and-replace.
|
|
104
|
+
*
|
|
105
|
+
* @param responseBuffer A buffer containing the response body.
|
|
106
|
+
* @param req The request.
|
|
107
|
+
* @returns
|
|
108
|
+
*/
|
|
109
|
+
const rewriteOpenSearch = (responseBuffer, req) => {
|
|
110
|
+
const requestHost = req.headers.host;
|
|
111
|
+
|
|
112
|
+
if (!requestHost) {
|
|
113
|
+
return responseBuffer;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const osd = responseBuffer.toString("utf8");
|
|
117
|
+
|
|
118
|
+
return osd.replace(
|
|
119
|
+
new RegExp(backendUrl.origin, "g"),
|
|
120
|
+
`http://${requestHost}`
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Rewrites an OPDS response. This changes back-end URLs in the feed to point to the local server
|
|
126
|
+
* instead. This is a simple find-and-replace.
|
|
127
|
+
*
|
|
128
|
+
* @param responseBuffer A buffer containing the response body.
|
|
129
|
+
* @param req The request.
|
|
130
|
+
* @returns
|
|
131
|
+
*/
|
|
132
|
+
const rewriteOPDS = (responseBuffer, req) => {
|
|
133
|
+
const requestHost = req.headers.host;
|
|
134
|
+
|
|
135
|
+
if (!requestHost) {
|
|
136
|
+
return responseBuffer;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const feed = responseBuffer.toString("utf8");
|
|
140
|
+
|
|
141
|
+
return feed.replace(
|
|
142
|
+
new RegExp(backendUrl.origin, "g"),
|
|
143
|
+
`http://${requestHost}`
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Rewrites an HTML response. This changes jsdelivr CDN URLs in the page to point to the webpack
|
|
149
|
+
* assets on the local server instead. This is a simple find-and-replace.
|
|
150
|
+
*
|
|
151
|
+
* @param responseBuffer A buffer containing the response body.
|
|
152
|
+
* @param req The request.
|
|
153
|
+
* @returns
|
|
154
|
+
*/
|
|
155
|
+
const rewriteHTML = (responseBuffer, req) => {
|
|
156
|
+
const requestHost = req.headers.host;
|
|
157
|
+
|
|
158
|
+
if (!requestHost) {
|
|
159
|
+
return responseBuffer;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const page = responseBuffer.toString("utf8");
|
|
163
|
+
const packageName = process.env.npm_package_name;
|
|
164
|
+
const cdnUrlPattern = `"https://cdn.jsdelivr.net/npm/${packageName}(@.*?)?/dist/(.*?)"`;
|
|
165
|
+
|
|
166
|
+
return page.replace(
|
|
167
|
+
new RegExp(cdnUrlPattern, "g"),
|
|
168
|
+
`"http://${requestHost}${devAssetsPublicPath}$2"`
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const proxyMiddleware = createProxyMiddleware({
|
|
173
|
+
changeOrigin: true,
|
|
174
|
+
onProxyRes: responseInterceptor(
|
|
175
|
+
async (responseBuffer, proxyRes, req, res) => {
|
|
176
|
+
rewriteLocationHeader(res, req);
|
|
177
|
+
|
|
178
|
+
const contentType = res.getHeader("content-type");
|
|
179
|
+
|
|
180
|
+
if (contentType.startsWith("application/atom+xml")) {
|
|
181
|
+
return rewriteOPDS(responseBuffer, req);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (contentType.startsWith("text/html")) {
|
|
185
|
+
return rewriteHTML(responseBuffer, req);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (contentType.startsWith("application/opensearchdescription+xml")) {
|
|
189
|
+
return rewriteOpenSearch(responseBuffer, req);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return responseBuffer;
|
|
193
|
+
}
|
|
194
|
+
),
|
|
195
|
+
proxyTimeout: 120000,
|
|
196
|
+
secure: false,
|
|
197
|
+
selfHandleResponse: true,
|
|
198
|
+
target: backend,
|
|
199
|
+
timeout: 120000,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const config = merge(dev, {
|
|
203
|
+
devServer: {
|
|
204
|
+
setupMiddlewares: (middlewares, _devServer) => {
|
|
205
|
+
middlewares.push(proxyMiddleware);
|
|
206
|
+
return middlewares;
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
output: {
|
|
210
|
+
publicPath: devAssetsPublicPath,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return config;
|
|
215
|
+
};
|