Reconnect the app to the API, and fix the session that was never injected
Four changes that together get a signed-in officer back to working data. The SSO validation in index.php and embed.php called the public hostname from inside the server. The Lands Commission's NAT rule blocks traffic that leaves the server and tries to come back in, so that curl stalled for its full 30-second timeout and then failed validation, bouncing the user back to the login. Both now call http://l4lmainbackend/sso/validate, overridable with LUPMIS_SSO_BASE. Measured from inside the spdrawing container: 25 ms with no redirect, against a 10-second timeout on the public name. API_ROOT is now the relative path /api. The PWA host already proxies it to the ApiEngine container — a deliberate route, not a catch-all: /api answers on pwa. and api. but not on permits., minio. or minioapi. Same-origin removes the mixed-content, CORS and CORP constraints that Cross-Origin-Embedder-Policy: require-corp imposes on a cross-origin call, and no API hostname is compiled into the bundle any more. The dev server proxies /api to the public host, which is right there because a developer's machine is outside the server and only callers inside it are blocked from the public name. A direct request for /index.html bypassed index.php, which is what injects window.LUPMIS_SESSION, so the app started with no session at all and said so in the menu. The LUSPA landing page links to exactly that URL, and the SPA fallback could not help because its RewriteCond !-f fails precisely when the file exists. .htaccess now routes it through index.php; index.php reads index.html from the filesystem, so there is no loop. This one is inert until AllowOverride is relaxed on the PWA container, where it is currently None. Service worker v29, and v28 before it, which carries the GIS Tools rename to devices that already have the app installed. The tile cache stays pinned at v24, so downloaded map areas survive both updates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e82f4cae60
commit
4952c92e42
8
dist/.htaccess
vendored
8
dist/.htaccess
vendored
@ -70,6 +70,14 @@ DirectoryIndex index.php index.html
|
||||
# index.php. Query strings (?mode=permit&...) pass through automatically.
|
||||
RewriteRule ^embed/?$ embed.php [L]
|
||||
|
||||
# A direct request for /index.html must still go through index.php, which
|
||||
# is what injects window.LUPMIS_SESSION. Without this rule the SPA fallback
|
||||
# below cannot help: its RewriteCond !-f fails precisely because index.html
|
||||
# IS a real file, so Apache serves it raw and the app starts with no
|
||||
# session — the "No session injected" warning. index.php reads index.html
|
||||
# from the filesystem (__DIR__), not over HTTP, so there is no loop.
|
||||
RewriteRule ^index\.html$ index.php [L]
|
||||
|
||||
# Common single-page-app behaviour: if a route doesn't map to a real file
|
||||
# or directory, send the request to index.php so the PWA can handle it
|
||||
# client-side. Comment out this block if hash-based routing is preferred.
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/assets/index-C6kuA4o8.js.map
vendored
1
dist/assets/index-C6kuA4o8.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dist/assets/index-ybgDODsx.js.map
vendored
Normal file
1
dist/assets/index-ybgDODsx.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
||||
import{d as f,z as d}from"./index-C6kuA4o8.js";import"./vite-helpers-BlTxHScW.js";import"./bootstrap-D1-uvFxm.js";import"./openlayers-D5-VSKzq.js";import"./ol-ext-DV70ljNY.js";function p(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g,"")}function h(e){let l="",o=e;for(;o>=0;)l=String.fromCharCode(o%26+65)+l,o=Math.floor(o/26)-1;return l}function x(e){return e&&!Array.isArray(e)&&Array.isArray(e.cells)?{cells:e.cells,bold:!!e.bold}:{cells:Array.isArray(e)?e:[e],bold:!1}}function u(e){const l=[];return e.forEach((o,n)=>{const{cells:t,bold:a}=x(o),r=a?' s="1"':"",i=t.map((s,c)=>{const m=`${h(c)}${n+1}`;return s==null||s===""?`<c r="${m}"${r}/>`:typeof s=="number"&&Number.isFinite(s)?`<c r="${m}"${r}><v>${s}</v></c>`:`<c r="${m}"${r} t="inlineStr"><is><t xml:space="preserve">${p(s)}</t></is></c>`}).join("");l.push(`<row r="${n+1}">${i}</row>`)}),`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
import{d as f,z as d}from"./index-ybgDODsx.js";import"./vite-helpers-BlTxHScW.js";import"./bootstrap-D1-uvFxm.js";import"./openlayers-D5-VSKzq.js";import"./ol-ext-DV70ljNY.js";function p(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g,"")}function h(e){let l="",o=e;for(;o>=0;)l=String.fromCharCode(o%26+65)+l,o=Math.floor(o/26)-1;return l}function x(e){return e&&!Array.isArray(e)&&Array.isArray(e.cells)?{cells:e.cells,bold:!!e.bold}:{cells:Array.isArray(e)?e:[e],bold:!1}}function u(e){const l=[];return e.forEach((o,n)=>{const{cells:t,bold:a}=x(o),r=a?' s="1"':"",i=t.map((s,c)=>{const m=`${h(c)}${n+1}`;return s==null||s===""?`<c r="${m}"${r}/>`:typeof s=="number"&&Number.isFinite(s)?`<c r="${m}"${r}><v>${s}</v></c>`:`<c r="${m}"${r} t="inlineStr"><is><t xml:space="preserve">${p(s)}</t></is></c>`}).join("");l.push(`<row r="${n+1}">${i}</row>`)}),`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>${l.join("")}</sheetData></worksheet>`}const y=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<fonts count="2"><font><sz val="11"/><name val="Calibri"/></font><font><b/><sz val="11"/><name val="Calibri"/></font></fonts>
|
||||
@ -27,4 +27,4 @@ ${n.map(t=>`<Relationship Id="rId${t.id}" Type="http://schemas.openxmlformats.or
|
||||
`)}
|
||||
<Relationship Id="rIdStyles" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
||||
</Relationships>`,o["xl/styles.xml"]=y,d(o,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")}function S(e,l){f(g(e),l)}export{g as buildXlsxBlob,S as exportXlsx};
|
||||
//# sourceMappingURL=xlsx-CYAxSxVe.js.map
|
||||
//# sourceMappingURL=xlsx-x-C7b9wf.js.map
|
||||
File diff suppressed because one or more lines are too long
12
dist/embed.php
vendored
12
dist/embed.php
vendored
@ -35,7 +35,17 @@ header_remove('X-Frame-Options');
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
if (!isset($_SESSION['user_id']) && isset($_COOKIE['sso_auth_token'])) {
|
||||
$plainToken = $_COOKIE['sso_auth_token'];
|
||||
$validate_url = 'https://lupmis4luspa.org/sso/validate?token=' . urlencode($plainToken);
|
||||
// The SSO service is reached by its container name on the internal Docker
|
||||
// network. The public hostname must NOT be used from inside the server:
|
||||
// the Lands Commission's NAT rule blocks traffic that leaves the server and
|
||||
// tries to come back in, so a call to https://lupmis4luspa.org/ from here
|
||||
// hangs until CURLOPT_TIMEOUT and then fails validation, bouncing the user
|
||||
// back to SSO. Measured from inside the spdrawing container on 2026-10-12:
|
||||
// http://l4lmainbackend/sso/validate answers in 25 ms with no redirect,
|
||||
// while the public name times out. Override with LUPMIS_SSO_BASE if the
|
||||
// container is renamed.
|
||||
$ssoBase = getenv('LUPMIS_SSO_BASE') ?: 'http://l4lmainbackend';
|
||||
$validate_url = rtrim($ssoBase, '/') . '/sso/validate?token=' . urlencode($plainToken);
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
|
||||
8
dist/index.html
vendored
8
dist/index.html
vendored
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#005eb8">
|
||||
<meta name="description" content="LUPMIS2 Drawing Tools">
|
||||
<meta name="description" content="LUPMIS2 GIS Tools">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="manifest.json">
|
||||
@ -61,7 +61,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>LUPMIS2 Drawing Tools</title>
|
||||
<title>LUPMIS2 GIS Tools</title>
|
||||
|
||||
<style>
|
||||
/* LUSPA Design System Tokens
|
||||
@ -2004,7 +2004,7 @@
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-C6kuA4o8.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-ybgDODsx.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/vite-helpers-BlTxHScW.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/bootstrap-D1-uvFxm.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/openlayers-D5-VSKzq.js">
|
||||
@ -2020,7 +2020,7 @@
|
||||
<nav class="navbar py-2">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand mb-0 h1">
|
||||
<span class="me-2">🌍</span><span class="brand-text">LUPMIS2 Drawing Tools</span>
|
||||
<span class="me-2">🌍</span><span class="brand-text">LUPMIS2 GIS Tools</span>
|
||||
</span>
|
||||
|
||||
<!-- Live GPS status: lon/lat, accuracy (precision) and satellites.
|
||||
|
||||
12
dist/index.php
vendored
12
dist/index.php
vendored
@ -69,7 +69,17 @@ if (isset($_GET['logout'])) {
|
||||
// cleared the SSO cookie, which left the stale district pinned).
|
||||
if (!isset($_SESSION['user_id']) && isset($_COOKIE['sso_auth_token'])) {
|
||||
$plainToken = $_COOKIE['sso_auth_token'];
|
||||
$validate_url = 'https://lupmis4luspa.org/sso/validate?token=' . urlencode($plainToken);
|
||||
// The SSO service is reached by its container name on the internal Docker
|
||||
// network. The public hostname must NOT be used from inside the server:
|
||||
// the Lands Commission's NAT rule blocks traffic that leaves the server and
|
||||
// tries to come back in, so a call to https://lupmis4luspa.org/ from here
|
||||
// hangs until CURLOPT_TIMEOUT and then fails validation, bouncing the user
|
||||
// back to SSO. Measured from inside the spdrawing container on 2026-10-12:
|
||||
// http://l4lmainbackend/sso/validate answers in 25 ms with no redirect,
|
||||
// while the public name times out. Override with LUPMIS_SSO_BASE if the
|
||||
// container is renamed.
|
||||
$ssoBase = getenv('LUPMIS_SSO_BASE') ?: 'http://l4lmainbackend';
|
||||
$validate_url = rtrim($ssoBase, '/') . '/sso/validate?token=' . urlencode($plainToken);
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
|
||||
2
dist/manifest.json
vendored
2
dist/manifest.json
vendored
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "LUPMIS2 Drawing Tools",
|
||||
"name": "LUPMIS2 GIS Tools",
|
||||
"short_name": "LUPMIS2",
|
||||
"description": "Map and GIS functions for Land Use Planning in Ghana",
|
||||
"start_url": "./",
|
||||
|
||||
18
dist/sw.js
vendored
18
dist/sw.js
vendored
@ -175,7 +175,16 @@
|
||||
// an error. The map, the tiles and the shell all worked, so the app
|
||||
// looked like it was working offline while nothing could be saved or
|
||||
// read. The skip now covers only the dev server's own paths.
|
||||
const CACHE_VERSION = 'v27';
|
||||
// v28: The module is named GIS Tools, not Drawing Tools. The change reaches
|
||||
// the installed app through manifest.json, so the shell has to be
|
||||
// re-precached for a device that already has it on its home screen.
|
||||
// v29: A direct request for /index.html bypassed index.php, so no session was
|
||||
// injected and the app reported "No session injected" even for a
|
||||
// signed-in officer. The LUSPA landing page links to exactly that URL.
|
||||
// .htaccess now routes it through index.php; the shell still precaches it,
|
||||
// since it is a real entry point and a navigation that misses the cache
|
||||
// throws rather than falling back. Re-precache on installed devices.
|
||||
const CACHE_VERSION = 'v29';
|
||||
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
||||
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
||||
const API_CACHE = `api-${CACHE_VERSION}`;
|
||||
@ -248,6 +257,13 @@ const AVG_TILE_BYTES = 30 * 1024;
|
||||
// ----------------------------------------------------------------------------
|
||||
// App shell assets — precached on install.
|
||||
// ----------------------------------------------------------------------------
|
||||
// Both '/' and '/index.html' are precached, because both are real entry
|
||||
// points: the installed app opens start_url './' while the LUSPA landing page
|
||||
// links to '/index.html'. Precaching both is only correct because .htaccess
|
||||
// routes /index.html through index.php — before that rule, fetching it here
|
||||
// stored a shell with no session injected. networkFirst() throws when a
|
||||
// navigation misses the cache, so an un-precached entry point means a cold
|
||||
// offline start at that URL fails outright.
|
||||
const SHELL_ASSETS = [
|
||||
'/',
|
||||
'/index.html',
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#005eb8">
|
||||
<meta name="description" content="LUPMIS2 Drawing Tools">
|
||||
<meta name="description" content="LUPMIS2 GIS Tools">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="manifest.json">
|
||||
@ -61,7 +61,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>LUPMIS2 Drawing Tools</title>
|
||||
<title>LUPMIS2 GIS Tools</title>
|
||||
|
||||
<style>
|
||||
/* LUSPA Design System Tokens
|
||||
@ -2011,7 +2011,7 @@
|
||||
<nav class="navbar py-2">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand mb-0 h1">
|
||||
<span class="me-2">🌍</span><span class="brand-text">LUPMIS2 Drawing Tools</span>
|
||||
<span class="me-2">🌍</span><span class="brand-text">LUPMIS2 GIS Tools</span>
|
||||
</span>
|
||||
|
||||
<!-- Live GPS status: lon/lat, accuracy (precision) and satellites.
|
||||
|
||||
@ -70,6 +70,14 @@ DirectoryIndex index.php index.html
|
||||
# index.php. Query strings (?mode=permit&...) pass through automatically.
|
||||
RewriteRule ^embed/?$ embed.php [L]
|
||||
|
||||
# A direct request for /index.html must still go through index.php, which
|
||||
# is what injects window.LUPMIS_SESSION. Without this rule the SPA fallback
|
||||
# below cannot help: its RewriteCond !-f fails precisely because index.html
|
||||
# IS a real file, so Apache serves it raw and the app starts with no
|
||||
# session — the "No session injected" warning. index.php reads index.html
|
||||
# from the filesystem (__DIR__), not over HTTP, so there is no loop.
|
||||
RewriteRule ^index\.html$ index.php [L]
|
||||
|
||||
# Common single-page-app behaviour: if a route doesn't map to a real file
|
||||
# or directory, send the request to index.php so the PWA can handle it
|
||||
# client-side. Comment out this block if hash-based routing is preferred.
|
||||
|
||||
@ -35,7 +35,17 @@ header_remove('X-Frame-Options');
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
if (!isset($_SESSION['user_id']) && isset($_COOKIE['sso_auth_token'])) {
|
||||
$plainToken = $_COOKIE['sso_auth_token'];
|
||||
$validate_url = 'https://lupmis4luspa.org/sso/validate?token=' . urlencode($plainToken);
|
||||
// The SSO service is reached by its container name on the internal Docker
|
||||
// network. The public hostname must NOT be used from inside the server:
|
||||
// the Lands Commission's NAT rule blocks traffic that leaves the server and
|
||||
// tries to come back in, so a call to https://lupmis4luspa.org/ from here
|
||||
// hangs until CURLOPT_TIMEOUT and then fails validation, bouncing the user
|
||||
// back to SSO. Measured from inside the spdrawing container on 2026-10-12:
|
||||
// http://l4lmainbackend/sso/validate answers in 25 ms with no redirect,
|
||||
// while the public name times out. Override with LUPMIS_SSO_BASE if the
|
||||
// container is renamed.
|
||||
$ssoBase = getenv('LUPMIS_SSO_BASE') ?: 'http://l4lmainbackend';
|
||||
$validate_url = rtrim($ssoBase, '/') . '/sso/validate?token=' . urlencode($plainToken);
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
|
||||
@ -69,7 +69,17 @@ if (isset($_GET['logout'])) {
|
||||
// cleared the SSO cookie, which left the stale district pinned).
|
||||
if (!isset($_SESSION['user_id']) && isset($_COOKIE['sso_auth_token'])) {
|
||||
$plainToken = $_COOKIE['sso_auth_token'];
|
||||
$validate_url = 'https://lupmis4luspa.org/sso/validate?token=' . urlencode($plainToken);
|
||||
// The SSO service is reached by its container name on the internal Docker
|
||||
// network. The public hostname must NOT be used from inside the server:
|
||||
// the Lands Commission's NAT rule blocks traffic that leaves the server and
|
||||
// tries to come back in, so a call to https://lupmis4luspa.org/ from here
|
||||
// hangs until CURLOPT_TIMEOUT and then fails validation, bouncing the user
|
||||
// back to SSO. Measured from inside the spdrawing container on 2026-10-12:
|
||||
// http://l4lmainbackend/sso/validate answers in 25 ms with no redirect,
|
||||
// while the public name times out. Override with LUPMIS_SSO_BASE if the
|
||||
// container is renamed.
|
||||
$ssoBase = getenv('LUPMIS_SSO_BASE') ?: 'http://l4lmainbackend';
|
||||
$validate_url = rtrim($ssoBase, '/') . '/sso/validate?token=' . urlencode($plainToken);
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "LUPMIS2 Drawing Tools",
|
||||
"name": "LUPMIS2 GIS Tools",
|
||||
"short_name": "LUPMIS2",
|
||||
"description": "Map and GIS functions for Land Use Planning in Ghana",
|
||||
"start_url": "./",
|
||||
|
||||
18
public/sw.js
18
public/sw.js
@ -175,7 +175,16 @@
|
||||
// an error. The map, the tiles and the shell all worked, so the app
|
||||
// looked like it was working offline while nothing could be saved or
|
||||
// read. The skip now covers only the dev server's own paths.
|
||||
const CACHE_VERSION = 'v27';
|
||||
// v28: The module is named GIS Tools, not Drawing Tools. The change reaches
|
||||
// the installed app through manifest.json, so the shell has to be
|
||||
// re-precached for a device that already has it on its home screen.
|
||||
// v29: A direct request for /index.html bypassed index.php, so no session was
|
||||
// injected and the app reported "No session injected" even for a
|
||||
// signed-in officer. The LUSPA landing page links to exactly that URL.
|
||||
// .htaccess now routes it through index.php; the shell still precaches it,
|
||||
// since it is a real entry point and a navigation that misses the cache
|
||||
// throws rather than falling back. Re-precache on installed devices.
|
||||
const CACHE_VERSION = 'v29';
|
||||
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
||||
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
||||
const API_CACHE = `api-${CACHE_VERSION}`;
|
||||
@ -248,6 +257,13 @@ const AVG_TILE_BYTES = 30 * 1024;
|
||||
// ----------------------------------------------------------------------------
|
||||
// App shell assets — precached on install.
|
||||
// ----------------------------------------------------------------------------
|
||||
// Both '/' and '/index.html' are precached, because both are real entry
|
||||
// points: the installed app opens start_url './' while the LUSPA landing page
|
||||
// links to '/index.html'. Precaching both is only correct because .htaccess
|
||||
// routes /index.html through index.php — before that rule, fetching it here
|
||||
// stored a shell with no session injected. networkFirst() throws when a
|
||||
// navigation misses the cache, so an un-precached entry point means a cold
|
||||
// offline start at that URL fails outright.
|
||||
const SHELL_ASSETS = [
|
||||
'/',
|
||||
'/index.html',
|
||||
|
||||
@ -17,7 +17,16 @@
|
||||
// Most endpoints live under the /spatial_planning module, but not all — the
|
||||
// contours endpoint sits in its own module. Endpoint names containing a slash
|
||||
// are resolved against API_ROOT instead (see resolveEndpoint below).
|
||||
const API_ROOT = 'https://api.lupmis4luspa.org/api';
|
||||
// Same-origin by default: the PWA host already proxies /api to the ApiEngine
|
||||
// container (verified 2026-10-12 — /api answers on pwa. and api. only, not on
|
||||
// the other subdomains, so it is a deliberate location, not a catch-all).
|
||||
// Same-origin matters here: the app runs cross-origin isolated under
|
||||
// Cross-Origin-Embedder-Policy: require-corp, and a relative path sidesteps
|
||||
// mixed content, CORS and CORP entirely. It also keeps the browser on the
|
||||
// outside-in path the Lands Commission NAT rule requires — the proxy makes the
|
||||
// internal hop to ApiEngine itself, so the bundle never names a host.
|
||||
// VITE_API_ROOT overrides it; the dev server proxies /api (see vite.config.js).
|
||||
const API_ROOT = import.meta.env.VITE_API_ROOT ?? '/api';
|
||||
const API_BASE = `${API_ROOT}/spatial_planning`;
|
||||
|
||||
/**
|
||||
|
||||
@ -16,6 +16,18 @@ export default defineConfig({
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
},
|
||||
// In production the PWA host proxies /api to the ApiEngine container, so
|
||||
// the app calls the API with a relative path. The dev server is not behind
|
||||
// that proxy, so it forwards /api to the public host — which is correct
|
||||
// here because a developer's machine is outside the server, and only
|
||||
// callers inside it are blocked from using the public name.
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'https://api.lupmis4luspa.org',
|
||||
changeOrigin: true,
|
||||
secure: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Preview server (npm run preview) configuration
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user