serve api on same origin at /api
This commit is contained in:
+1
-2
@@ -12,10 +12,9 @@ RUN npm run build
|
|||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
WORKDIR /usr/share/nginx/html
|
WORKDIR /usr/share/nginx/html
|
||||||
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
COPY --from=build /app/dist ./
|
COPY --from=build /app/dist ./
|
||||||
|
|
||||||
ENV API_BASE_URL=""
|
ENV API_PROXY_PASS=""
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||||
RUN chmod +x /docker-entrypoint.sh
|
RUN chmod +x /docker-entrypoint.sh
|
||||||
|
|||||||
@@ -1,11 +1,37 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
API_BASE_URL_TRIMMED="${API_BASE_URL:-}"
|
API_PROXY_PASS_TRIMMED="${API_PROXY_PASS:-}"
|
||||||
API_BASE_URL_TRIMMED="${API_BASE_URL_TRIMMED%%/}"
|
API_PROXY_PASS_TRIMMED="${API_PROXY_PASS_TRIMMED%%/}"
|
||||||
|
|
||||||
cat <<CONFIG > /usr/share/nginx/html/config.js
|
cat <<'BASE' > /etc/nginx/conf.d/default.conf
|
||||||
window.__PAPERCRATE_API_BASE_URL = "${API_BASE_URL_TRIMMED}";
|
server {
|
||||||
CONFIG
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri /index.html;
|
||||||
|
}
|
||||||
|
BASE
|
||||||
|
|
||||||
|
if [ -n "$API_PROXY_PASS_TRIMMED" ]; then
|
||||||
|
cat <<PROXY >> /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass ${API_PROXY_PASS_TRIMMED};
|
||||||
|
proxy_set_header Host \$host;
|
||||||
|
proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||||
|
}
|
||||||
|
PROXY
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<'ENDCFG' >> /etc/nginx/conf.d/default.conf
|
||||||
|
}
|
||||||
|
ENDCFG
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri /index.html;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
window.__PAPERCRATE_API_BASE_URL = window.__PAPERCRATE_API_BASE_URL || '';
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
<title>Papercrate</title>
|
<title>Papercrate</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="/config.js"></script>
|
|
||||||
<main id="app"></main>
|
<main id="app"></main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+24
-19
@@ -36,33 +36,28 @@ import { createPreviewSurface } from './preview/PreviewWorkspace';
|
|||||||
import { createDesktopSurface } from './DesktopWorkspace';
|
import { createDesktopSurface } from './DesktopWorkspace';
|
||||||
import { AppShellContext, useAppShell } from './appShellContext';
|
import { AppShellContext, useAppShell } from './appShellContext';
|
||||||
|
|
||||||
const runtimeApiBase =
|
|
||||||
typeof window !== 'undefined' && window.__PAPERCRATE_API_BASE_URL
|
|
||||||
? window.__PAPERCRATE_API_BASE_URL
|
|
||||||
: '';
|
|
||||||
|
|
||||||
const DEFAULT_DEV_API = 'http://127.0.0.1:3000';
|
|
||||||
const ASSET_PRESIGN_TTL_MS = 240 * 1000; // backend issues 5 min tokens; refresh slightly early
|
const ASSET_PRESIGN_TTL_MS = 240 * 1000; // backend issues 5 min tokens; refresh slightly early
|
||||||
const TAG_MIME_TYPES = ['application/x-papercrate-tag', 'text/papercrate-tag'];
|
const TAG_MIME_TYPES = ['application/x-papercrate-tag', 'text/papercrate-tag'];
|
||||||
|
|
||||||
const API_ROOT = (runtimeApiBase || process.env.API_BASE_URL || DEFAULT_DEV_API).replace(/\/$/, '');
|
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: API_ROOT ? `${API_ROOT}/api` : '/api',
|
baseURL: '/api',
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const STORED_TOKEN = window.localStorage.getItem('papercrate_token') || '';
|
const storage = typeof window !== 'undefined' ? window.sessionStorage : undefined;
|
||||||
|
const STORED_TOKEN = storage?.getItem('papercrate_token') || '';
|
||||||
let STORED_TENANT = null;
|
let STORED_TENANT = null;
|
||||||
try {
|
if (storage) {
|
||||||
const rawTenant = window.localStorage.getItem('papercrate_tenant');
|
try {
|
||||||
|
const rawTenant = storage.getItem('papercrate_tenant');
|
||||||
if (rawTenant) {
|
if (rawTenant) {
|
||||||
STORED_TENANT = JSON.parse(rawTenant);
|
STORED_TENANT = JSON.parse(rawTenant);
|
||||||
}
|
}
|
||||||
} catch (
|
} catch (
|
||||||
// eslint-disable-next-line no-empty
|
// eslint-disable-next-line no-empty
|
||||||
error
|
error
|
||||||
) {}
|
) {}
|
||||||
|
}
|
||||||
if (STORED_TOKEN) {
|
if (STORED_TOKEN) {
|
||||||
api.defaults.headers.common.Authorization = `Bearer ${STORED_TOKEN}`;
|
api.defaults.headers.common.Authorization = `Bearer ${STORED_TOKEN}`;
|
||||||
}
|
}
|
||||||
@@ -191,22 +186,22 @@ const AppStateProvider = ({ children }) => {
|
|||||||
const token = state.token || '';
|
const token = state.token || '';
|
||||||
if (token) {
|
if (token) {
|
||||||
api.defaults.headers.common.Authorization = `Bearer ${token}`;
|
api.defaults.headers.common.Authorization = `Bearer ${token}`;
|
||||||
window.localStorage.setItem('papercrate_token', token);
|
storage?.setItem('papercrate_token', token);
|
||||||
} else {
|
} else {
|
||||||
delete api.defaults.headers.common.Authorization;
|
delete api.defaults.headers.common.Authorization;
|
||||||
window.localStorage.removeItem('papercrate_token');
|
storage?.removeItem('papercrate_token');
|
||||||
}
|
}
|
||||||
}, [state.token]);
|
}, [state.token]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.tenant) {
|
if (state.tenant) {
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem('papercrate_tenant', JSON.stringify(state.tenant));
|
storage?.setItem('papercrate_tenant', JSON.stringify(state.tenant));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Failed to persist tenant info', error);
|
console.warn('Failed to persist tenant info', error);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window.localStorage.removeItem('papercrate_tenant');
|
storage?.removeItem('papercrate_tenant');
|
||||||
}
|
}
|
||||||
}, [state.tenant]);
|
}, [state.tenant]);
|
||||||
|
|
||||||
@@ -270,7 +265,7 @@ const ROW_KEY_SEPARATOR = ':';
|
|||||||
const DOCUMENT_ROW_PREFIX = 'document';
|
const DOCUMENT_ROW_PREFIX = 'document';
|
||||||
const FOLDER_ROW_PREFIX = 'folder';
|
const FOLDER_ROW_PREFIX = 'folder';
|
||||||
|
|
||||||
const resolveApiPath = (path = '') => (API_ROOT ? `${API_ROOT}${path}` : path);
|
const resolveApiPath = (path = '') => path;
|
||||||
|
|
||||||
const makeRowKey = (type, id) =>
|
const makeRowKey = (type, id) =>
|
||||||
id ? `${type}${ROW_KEY_SEPARATOR}${id}` : `${type}${ROW_KEY_SEPARATOR}`;
|
id ? `${type}${ROW_KEY_SEPARATOR}${id}` : `${type}${ROW_KEY_SEPARATOR}`;
|
||||||
@@ -571,6 +566,16 @@ const AppLayout = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const initialRefreshAttemptedRef = useRef(Boolean(token));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!token && !initialRefreshAttemptedRef.current && appStatus === 'logged-out') {
|
||||||
|
initialRefreshAttemptedRef.current = true;
|
||||||
|
console.log('[Auth] Attempting refresh at startup');
|
||||||
|
refreshAccessToken().catch(() => {});
|
||||||
|
}
|
||||||
|
}, [token, appStatus, refreshAccessToken]);
|
||||||
|
|
||||||
const clearFilters = useCallback(() => {
|
const clearFilters = useCallback(() => {
|
||||||
setSearchQuery('');
|
setSearchQuery('');
|
||||||
setActiveTagFilters([]);
|
setActiveTagFilters([]);
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const webpack = require('webpack');
|
|
||||||
const dotenv = require('dotenv');
|
|
||||||
|
|
||||||
const env = dotenv.config({ path: path.resolve(__dirname, '.env.local') }).parsed || {};
|
|
||||||
|
|
||||||
const DEFAULT_DEV_API = 'http://127.0.0.1:3000';
|
|
||||||
|
|
||||||
const API_BASE_URL = env.API_BASE_URL || process.env.API_BASE_URL || DEFAULT_DEV_API;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/index.jsx',
|
entry: './src/index.jsx',
|
||||||
output: {
|
output: {
|
||||||
@@ -46,9 +37,6 @@ module.exports = {
|
|||||||
template: path.resolve(__dirname, 'src/index.html'),
|
template: path.resolve(__dirname, 'src/index.html'),
|
||||||
favicon: false,
|
favicon: false,
|
||||||
}),
|
}),
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.API_BASE_URL': JSON.stringify(API_BASE_URL),
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
devServer: {
|
devServer: {
|
||||||
static: {
|
static: {
|
||||||
@@ -58,6 +46,14 @@ module.exports = {
|
|||||||
port: 5173,
|
port: 5173,
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
open: true,
|
open: true,
|
||||||
|
proxy: [
|
||||||
|
{
|
||||||
|
context: ['/api'],
|
||||||
|
target: 'http://127.0.0.1:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ spec:
|
|||||||
containerPort: {{ .Values.frontend.service.port }}
|
containerPort: {{ .Values.frontend.service.port }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
env:
|
env:
|
||||||
|
- name: API_PROXY_PASS
|
||||||
|
value: {{ printf "http://%s-backend:%d" (include "papercrate.fullname" . ) (int (.Values.backend.service.port)) | quote }}
|
||||||
{{- range .Values.frontend.env.extra }}
|
{{- range .Values.frontend.env.extra }}
|
||||||
- name: {{ .name }}
|
- name: {{ .name }}
|
||||||
value: {{ .value | quote }}
|
value: {{ .value | quote }}
|
||||||
|
|||||||
Reference in New Issue
Block a user