@olenbetong/appframe-vite 3.1.17 → 4.0.0-rc.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/lib/build.js +10 -0
- package/lib/devServer.d.ts +8 -6
- package/lib/devServer.js +86 -176
- package/lib/index.d.ts +2 -3
- package/lib/index.js +73 -7
- package/lib/proxy.d.ts +5 -15
- package/lib/proxy.js +15 -34
- package/package.json +5 -2
package/lib/build.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { exists } from "fs-extra";
|
|
2
|
+
import { resolve } from "node:path";
|
|
1
3
|
import { visualizer } from "rollup-plugin-visualizer";
|
|
2
4
|
import { viteExternalsPlugin } from "vite-plugin-externals";
|
|
3
5
|
import { importJson } from "./importJson.js";
|
|
@@ -17,7 +19,15 @@ export async function addAppframeBuildConfig(config) {
|
|
|
17
19
|
"react-dom": "ReactDOM",
|
|
18
20
|
}));
|
|
19
21
|
}
|
|
22
|
+
let entry = resolve(process.cwd(), "./src/index.tsx");
|
|
23
|
+
if (!(await exists(resolve(entry)))) {
|
|
24
|
+
entry = resolve(process.cwd(), "./src/index.ts");
|
|
25
|
+
}
|
|
26
|
+
if (!(await exists(resolve(entry)))) {
|
|
27
|
+
entry = resolve(process.cwd(), "./src/index.js");
|
|
28
|
+
}
|
|
20
29
|
config.build.rollupOptions = {
|
|
30
|
+
input: entry,
|
|
21
31
|
plugins: [visualizer({ filename: "./dist/stats.html", gzipSize: true })],
|
|
22
32
|
output: {
|
|
23
33
|
globals: appframe.build.externals !== false
|
package/lib/devServer.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Connect, ViteDevServer } from "vite";
|
|
2
|
+
export declare function getLoginInfo(): Promise<{
|
|
3
|
+
hostname: any;
|
|
4
|
+
username: string;
|
|
5
|
+
password: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function getProxyRoutes(): string[];
|
|
8
|
+
export declare function createDevMiddleware(vite: ViteDevServer): Connect.NextHandleFunction;
|
package/lib/devServer.js
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
import { Client } from "@olenbetong/appframe-data";
|
|
2
|
-
import { watch } from "chokidar";
|
|
3
2
|
import dotenv from "dotenv";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import open from "open";
|
|
8
|
-
import tcpPortUsed from "tcp-port-used";
|
|
3
|
+
import { exists } from "fs-extra";
|
|
4
|
+
import { JSDOM } from "jsdom";
|
|
5
|
+
import { resolve } from "node:path";
|
|
9
6
|
import { importJson } from "./importJson.js";
|
|
10
|
-
import { createAppframeProxy } from "./proxy.js";
|
|
11
7
|
dotenv.config();
|
|
12
8
|
let appPkg = await importJson("./package.json", true);
|
|
13
9
|
let { appframe } = appPkg;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (userSession) {
|
|
17
|
-
return userSession;
|
|
18
|
-
}
|
|
19
|
-
let { hostname, username, password } = await getLoginInfo();
|
|
20
|
-
let client = new Client(hostname);
|
|
21
|
-
await client.login(username, password);
|
|
22
|
-
let userResult = await client.afFetch("/api/system/usersession", {
|
|
23
|
-
timeout: 5000,
|
|
24
|
-
});
|
|
25
|
-
userSession = await userResult.json();
|
|
26
|
-
return userSession;
|
|
27
|
-
}
|
|
28
|
-
function getLoginInfo() {
|
|
10
|
+
export async function getLoginInfo() {
|
|
11
|
+
let { appframe } = await importJson("./package.json", true);
|
|
29
12
|
const hostname = appframe.proxy?.hostname ?? appframe.deploy?.hostname ?? "dev.obet.no";
|
|
30
13
|
const { APPFRAME_LOGIN: username, APPFRAME_PWD: password } = process.env;
|
|
31
14
|
if (!username || !password) {
|
|
@@ -33,173 +16,100 @@ function getLoginInfo() {
|
|
|
33
16
|
}
|
|
34
17
|
return { hostname, username, password };
|
|
35
18
|
}
|
|
36
|
-
export function
|
|
37
|
-
let { hostname, username, password } = getLoginInfo();
|
|
38
|
-
const proxy = createAppframeProxy({ hostname, username, password });
|
|
39
|
-
try {
|
|
40
|
-
let appPkgUrl = `file://${process.cwd()}/package.json`;
|
|
41
|
-
watch(appPkgUrl).on("all", async () => {
|
|
42
|
-
appPkg = await importJson("./package.json", true);
|
|
43
|
-
appframe = appPkg.appframe;
|
|
44
|
-
let { hostname } = getLoginInfo();
|
|
45
|
-
proxy.setHostname(hostname);
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
console.log(`Failed to watch package.json: ${error.message}`);
|
|
50
|
-
}
|
|
19
|
+
export function getProxyRoutes() {
|
|
51
20
|
const proxyRoutes = [
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"/
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
21
|
+
"^/api/.*",
|
|
22
|
+
"^/file/.*",
|
|
23
|
+
"^/filestore/.*",
|
|
24
|
+
"^/static/dbimages/.*",
|
|
25
|
+
"^/static/images/.*",
|
|
26
|
+
"^/static/graphics/.*",
|
|
27
|
+
"^/destroy/.*",
|
|
28
|
+
"^/create/.*",
|
|
29
|
+
"^/update/.*",
|
|
30
|
+
"^/retrieve/.*",
|
|
31
|
+
"^/exec/.*",
|
|
32
|
+
"^/report/.*",
|
|
33
|
+
"^/rowcount/.*",
|
|
34
|
+
"^/lib/.*",
|
|
35
|
+
"^/login",
|
|
36
|
+
"^/logout",
|
|
65
37
|
];
|
|
66
38
|
if (appframe.proxy?.routes) {
|
|
67
39
|
proxyRoutes.push(...appframe.proxy.routes);
|
|
68
40
|
}
|
|
69
|
-
|
|
70
|
-
proxyRoutes.forEach((route) => {
|
|
71
|
-
router.use(route, proxy);
|
|
72
|
-
});
|
|
73
|
-
return router;
|
|
41
|
+
return proxyRoutes;
|
|
74
42
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<template id="PromptBeforeReloadDialog">
|
|
83
|
-
<dialog class="do-prompt">
|
|
84
|
-
<form method="dialog">
|
|
85
|
-
<article>
|
|
86
|
-
<p>There are unsaved changes. Would you like to save before reloading data?
|
|
87
|
-
</article>
|
|
88
|
-
<footer>
|
|
89
|
-
<menu>
|
|
90
|
-
<li><button value="cancel">Cancel reloading</button></li>
|
|
91
|
-
<li><button value="reload">Reload without saving</button></li>
|
|
92
|
-
<li><button class="primary" value="save-and-reload">Save and reload</button></li>
|
|
93
|
-
</menu>
|
|
94
|
-
</footer>
|
|
95
|
-
</form>
|
|
96
|
-
</dialog>
|
|
97
|
-
</template>
|
|
98
|
-
|
|
99
|
-
<script type="text/javascript">
|
|
100
|
-
function waitForDialog(dialog) {
|
|
101
|
-
return new Promise((resolve) => {
|
|
102
|
-
dialog.addEventListener("close", resolve, { once: true });
|
|
43
|
+
async function getArticleHtml() {
|
|
44
|
+
let { hostname, username, password } = await getLoginInfo();
|
|
45
|
+
let article = appframe.article?.id;
|
|
46
|
+
let client = new Client(hostname);
|
|
47
|
+
await client.login(username, password);
|
|
48
|
+
let response = await client.afFetch(`/${article}`, {
|
|
49
|
+
timeout: 30000,
|
|
103
50
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
headingLevelLabel: l('Heading level'),
|
|
146
|
-
mainLabel: l('main'),
|
|
147
|
-
searchLabel: l('search'),
|
|
148
|
-
navLabel: l('navigation'),
|
|
149
|
-
asideLabel: l('aside'),
|
|
150
|
-
footerLabel: l('footer'),
|
|
151
|
-
headerLabel: l('header'),
|
|
152
|
-
formLabel: l('form'),
|
|
153
|
-
msgNoLandmarksFound: l('No landmarks to skip to'),
|
|
154
|
-
msgNoHeadingsFound: l('No main headings to skip to')
|
|
51
|
+
if (response.ok) {
|
|
52
|
+
let html = await response.text();
|
|
53
|
+
let entry;
|
|
54
|
+
if (await exists(resolve(process.cwd(), "./src/index.tsx"))) {
|
|
55
|
+
entry = "/src/index.tsx";
|
|
56
|
+
}
|
|
57
|
+
else if (await exists(resolve(process.cwd(), "./src/index.ts"))) {
|
|
58
|
+
entry = "/src/index.ts";
|
|
59
|
+
}
|
|
60
|
+
else if (await exists(resolve(process.cwd(), "./src/index.js"))) {
|
|
61
|
+
entry = "/src/index.js";
|
|
62
|
+
}
|
|
63
|
+
let dom = new JSDOM(html);
|
|
64
|
+
let nodesToRemove = [];
|
|
65
|
+
dom.window.document.querySelectorAll("script").forEach((script) => {
|
|
66
|
+
if (script.src?.startsWith(`/file/article/script/${article}/main`)) {
|
|
67
|
+
let mainScript = dom.window.document.createElement("script");
|
|
68
|
+
mainScript.type = "module";
|
|
69
|
+
mainScript.src = entry;
|
|
70
|
+
script.insertAdjacentElement("beforebegin", mainScript);
|
|
71
|
+
nodesToRemove.push(script);
|
|
72
|
+
}
|
|
73
|
+
else if (script.src?.includes("bugsnag")) {
|
|
74
|
+
nodesToRemove.push(script);
|
|
75
|
+
}
|
|
76
|
+
else if (script.textContent?.includes("bugsnagOptions") ||
|
|
77
|
+
script.textContent?.includes("web-vitals") ||
|
|
78
|
+
script.textContent?.includes("serviceWorker.register")) {
|
|
79
|
+
nodesToRemove.push(script);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
dom.window.document.querySelectorAll("link").forEach((link) => {
|
|
83
|
+
if (link.rel === "stylesheet" && link.href?.startsWith(`/file/article/style/${article}`)) {
|
|
84
|
+
nodesToRemove.push(link);
|
|
85
|
+
}
|
|
86
|
+
else if (link.rel === "prefetch" && link.href?.startsWith(`/file/article`)) {
|
|
87
|
+
nodesToRemove.push(link);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
nodesToRemove.forEach((node) => node.remove());
|
|
91
|
+
return dom.serialize();
|
|
155
92
|
}
|
|
156
|
-
|
|
157
|
-
};
|
|
158
|
-
</script>
|
|
159
|
-
<script src="/lib/paypal-skipto/downloads/js/skipto.min.js" async></script>`)
|
|
160
|
-
.replace(`<!-- {Theme} -->`, isPartner
|
|
161
|
-
? `
|
|
162
|
-
<link rel="stylesheet" href="/file/site/style/ob.application.min.css" />
|
|
163
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.base.less" />
|
|
164
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.betongost.less" />
|
|
165
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.olenbetong.less" />
|
|
166
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.ribe.less" />
|
|
167
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.sjb.less" />
|
|
168
|
-
`
|
|
169
|
-
: `
|
|
170
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.base.less" />
|
|
171
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.betongost.less" />
|
|
172
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.forsand.less" />
|
|
173
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.olenbetong.less" />
|
|
174
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.ribe.less" />
|
|
175
|
-
<link rel="stylesheet" href="/file/site/style/ob.theme.sjb.less" />
|
|
176
|
-
<link rel="stylesheet" href="/file/site/style/ob.es.application.min.css" />`);
|
|
177
|
-
};
|
|
93
|
+
throw Error(`Failed to get article '${article}' from '${hostname}': ${response.status} ${response.statusText}`);
|
|
178
94
|
}
|
|
179
95
|
export function createDevMiddleware(vite) {
|
|
180
96
|
return async (req, res, next) => {
|
|
181
|
-
let transformer = createHtmlTransformer();
|
|
182
97
|
const url = req.originalUrl;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
98
|
+
if (url === "/" || url?.startsWith("/" + appPkg.appframe.article.id)) {
|
|
99
|
+
try {
|
|
100
|
+
let html = await getArticleHtml();
|
|
101
|
+
html = await vite.transformIndexHtml(url ?? "", html);
|
|
102
|
+
res.statusCode = 200;
|
|
103
|
+
res.setHeader("Content-Type", "text/html");
|
|
104
|
+
res.end(html);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
vite.ssrFixStacktrace(error);
|
|
108
|
+
next(error);
|
|
109
|
+
}
|
|
188
110
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
next(error);
|
|
111
|
+
else {
|
|
112
|
+
next();
|
|
192
113
|
}
|
|
193
114
|
};
|
|
194
115
|
}
|
|
195
|
-
export async function startDevServer(app) {
|
|
196
|
-
let port = 3000;
|
|
197
|
-
let used = true;
|
|
198
|
-
do {
|
|
199
|
-
used = await tcpPortUsed.check(port);
|
|
200
|
-
if (used)
|
|
201
|
-
port++;
|
|
202
|
-
} while (used);
|
|
203
|
-
app.listen(port);
|
|
204
|
-
open(`http://localhost:${port}/${appframe.article.id}`);
|
|
205
|
-
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Plugin } from "vite";
|
|
2
2
|
import { addAppframeBuildConfig } from "./build.js";
|
|
3
|
-
import { createDevMiddleware
|
|
3
|
+
import { createDevMiddleware } from "./devServer.js";
|
|
4
4
|
export default function appframe(): Plugin;
|
|
5
|
-
export { addAppframeBuildConfig };
|
|
6
|
-
export { createDevMiddleware, createProxyMiddleware, startDevServer };
|
|
5
|
+
export { addAppframeBuildConfig, createDevMiddleware };
|
package/lib/index.js
CHANGED
|
@@ -1,15 +1,45 @@
|
|
|
1
|
+
import { watch } from "chokidar";
|
|
1
2
|
import { addAppframeBuildConfig } from "./build.js";
|
|
2
|
-
import { createDevMiddleware,
|
|
3
|
+
import { createDevMiddleware, getLoginInfo, getProxyRoutes } from "./devServer.js";
|
|
4
|
+
import { importJson } from "./importJson.js";
|
|
5
|
+
import { getLastSession, login } from "./proxy.js";
|
|
6
|
+
let interval;
|
|
7
|
+
let server;
|
|
8
|
+
let lastHostname;
|
|
9
|
+
try {
|
|
10
|
+
let appPkgUrl = `file://${process.cwd()}/package.json`;
|
|
11
|
+
watch(appPkgUrl).on("all", async () => {
|
|
12
|
+
if (server) {
|
|
13
|
+
let appPkg = await importJson("./package.json", true);
|
|
14
|
+
let config = appPkg.appframe;
|
|
15
|
+
let { hostname } = await getLoginInfo();
|
|
16
|
+
if (lastHostname !== hostname) {
|
|
17
|
+
server.restart(false);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.log(`Failed to watch package.json: ${error.message}`);
|
|
24
|
+
}
|
|
3
25
|
export default function appframe() {
|
|
4
|
-
let transformIndexHtml = createHtmlTransformer();
|
|
5
26
|
return {
|
|
6
27
|
name: "appframe",
|
|
28
|
+
resolveId(source) {
|
|
29
|
+
if (source.startsWith("/file/") || source.startsWith("/lib/")) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
},
|
|
7
34
|
async config(currentConfig, env) {
|
|
8
35
|
const { command } = env;
|
|
9
36
|
let config = {
|
|
37
|
+
...currentConfig,
|
|
10
38
|
build: {
|
|
39
|
+
...currentConfig.build,
|
|
11
40
|
target: currentConfig.build?.target ?? ["chrome90", "safari14"],
|
|
12
41
|
rollupOptions: {
|
|
42
|
+
...currentConfig.build?.rollupOptions,
|
|
13
43
|
output: {
|
|
14
44
|
assetFileNames: (assetInfo) => {
|
|
15
45
|
if (assetInfo.name === "style.css")
|
|
@@ -20,23 +50,59 @@ export default function appframe() {
|
|
|
20
50
|
},
|
|
21
51
|
},
|
|
22
52
|
resolve: {
|
|
53
|
+
...currentConfig.resolve,
|
|
23
54
|
alias: [{ find: "~/", replacement: "/src/" }],
|
|
24
55
|
},
|
|
25
56
|
};
|
|
26
57
|
if (command === "build") {
|
|
27
58
|
await addAppframeBuildConfig(config);
|
|
28
59
|
}
|
|
60
|
+
let proxy = config.server?.proxy ?? {};
|
|
61
|
+
let routes = getProxyRoutes();
|
|
62
|
+
let { hostname, username, password } = await getLoginInfo();
|
|
63
|
+
lastHostname = hostname;
|
|
64
|
+
await login(hostname, username, password);
|
|
65
|
+
if (interval)
|
|
66
|
+
clearInterval(interval);
|
|
67
|
+
// After changing the plugin to use the Vite proxy instead of a custom
|
|
68
|
+
// express server with node-http-proxy, we can no longer ensure the requests
|
|
69
|
+
// have a valid login. To reduce the amount of problems we get with expired
|
|
70
|
+
// sessions, we run the login procedure every 5 minutes to renew the session.
|
|
71
|
+
interval = setInterval(async () => {
|
|
72
|
+
await login(hostname, username, password);
|
|
73
|
+
}, 1000 * 60 * 5);
|
|
74
|
+
for (let route of routes) {
|
|
75
|
+
proxy[route] = {
|
|
76
|
+
target: `https://${hostname}`,
|
|
77
|
+
changeOrigin: true,
|
|
78
|
+
configure(proxy, options) {
|
|
79
|
+
proxy.on("proxyReq", (proxyReq, req, res, options) => {
|
|
80
|
+
let authCookies = getLastSession(hostname)?.authCookies;
|
|
81
|
+
if (authCookies) {
|
|
82
|
+
let cookies = [];
|
|
83
|
+
cookies.push(`AppframeWebAuth=${authCookies["AppframeWebAuth"]}`);
|
|
84
|
+
cookies.push(`AppframeWebSession=${authCookies["AppframeWebSession"]}`);
|
|
85
|
+
proxyReq.setHeader("cookie", cookies.join(";"));
|
|
86
|
+
// If left unchanged, the origin will be the local IP address, which makes Appframe
|
|
87
|
+
// return 403 errors
|
|
88
|
+
proxyReq.setHeader("origin", `https://${hostname}`);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
config.server = {
|
|
95
|
+
...config.server,
|
|
96
|
+
proxy,
|
|
97
|
+
};
|
|
29
98
|
return config;
|
|
30
99
|
},
|
|
31
100
|
async configureServer(_server) {
|
|
32
|
-
|
|
33
|
-
_server.middlewares.use(proxyMiddleware);
|
|
101
|
+
server = _server;
|
|
34
102
|
return () => {
|
|
35
103
|
_server.middlewares.use(createDevMiddleware(_server));
|
|
36
104
|
};
|
|
37
105
|
},
|
|
38
|
-
transformIndexHtml,
|
|
39
106
|
};
|
|
40
107
|
}
|
|
41
|
-
export { addAppframeBuildConfig };
|
|
42
|
-
export { createDevMiddleware, createProxyMiddleware, startDevServer };
|
|
108
|
+
export { addAppframeBuildConfig, createDevMiddleware };
|
package/lib/proxy.d.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
import e from "express";
|
|
2
1
|
type CookieObject = Record<string, string>;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* If true, will wait for the first login request to complete before returning.
|
|
7
|
-
*/
|
|
8
|
-
autoLogin?: boolean;
|
|
9
|
-
hostname: string;
|
|
10
|
-
username: string;
|
|
11
|
-
password: string;
|
|
12
|
-
protocol?: "http" | "https";
|
|
13
|
-
};
|
|
14
|
-
export type AppframeProxy = e.RequestHandler & {
|
|
15
|
-
setHostname: (hostname: string) => Promise<void>;
|
|
2
|
+
type LoginCacheEntry = {
|
|
3
|
+
timestamp: number;
|
|
4
|
+
authCookies: CookieObject;
|
|
16
5
|
};
|
|
17
|
-
export declare function
|
|
6
|
+
export declare function getLastSession(hostname: any): LoginCacheEntry | undefined;
|
|
7
|
+
export declare function login(hostname: string, username: string, password: string): Promise<CookieObject>;
|
|
18
8
|
export {};
|
package/lib/proxy.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import chalk from "chalk";
|
|
2
2
|
import https from "node:https";
|
|
3
3
|
const lastLogin = new Map();
|
|
4
4
|
let currentLogin = null;
|
|
5
|
+
export function getLastSession(hostname) {
|
|
6
|
+
return lastLogin.get(hostname);
|
|
7
|
+
}
|
|
5
8
|
export async function login(hostname, username, password) {
|
|
6
9
|
if (currentLogin) {
|
|
7
10
|
await currentLogin;
|
|
@@ -14,7 +17,7 @@ export async function login(hostname, username, password) {
|
|
|
14
17
|
return;
|
|
15
18
|
}
|
|
16
19
|
else {
|
|
17
|
-
|
|
20
|
+
process.stdout.write(`${chalk.bgBlueBright(hostname)}: Renewing authentication cookies...`);
|
|
18
21
|
lastLogin.delete(hostname);
|
|
19
22
|
}
|
|
20
23
|
}
|
|
@@ -30,8 +33,14 @@ export async function login(hostname, username, password) {
|
|
|
30
33
|
"Content-Length": data.length,
|
|
31
34
|
},
|
|
32
35
|
};
|
|
33
|
-
|
|
36
|
+
process.stdout.clearLine(0);
|
|
37
|
+
process.stdout.write(`\r${chalk.bgBlueBright(hostname)}: Authenticating`);
|
|
38
|
+
let start = performance.now();
|
|
39
|
+
let interval = setInterval(() => {
|
|
40
|
+
process.stdout.write(`.`);
|
|
41
|
+
}, 100);
|
|
34
42
|
let request = https.request(options, (response) => {
|
|
43
|
+
clearInterval(interval);
|
|
35
44
|
let status = response.statusCode ?? 600;
|
|
36
45
|
if (status < 400) {
|
|
37
46
|
let cookies = response.headers["set-cookie"] ?? [];
|
|
@@ -43,7 +52,8 @@ export async function login(hostname, username, password) {
|
|
|
43
52
|
cookieObj[key] = value;
|
|
44
53
|
}
|
|
45
54
|
}
|
|
46
|
-
|
|
55
|
+
process.stdout.clearLine(0);
|
|
56
|
+
process.stdout.write(`\r${chalk.bgBlueBright(hostname)}: Authenticated (${Math.floor(performance.now() - start)}ms)\n`);
|
|
47
57
|
lastLogin.set(hostname, {
|
|
48
58
|
timestamp: Date.now(),
|
|
49
59
|
authCookies: cookieObj,
|
|
@@ -51,7 +61,7 @@ export async function login(hostname, username, password) {
|
|
|
51
61
|
resolve(cookieObj);
|
|
52
62
|
}
|
|
53
63
|
else {
|
|
54
|
-
reject(Error(
|
|
64
|
+
reject(Error(`${chalk.bgBlueBright(hostname)}: Authentication failed: ${response.statusCode} ${response.statusMessage}`));
|
|
55
65
|
}
|
|
56
66
|
});
|
|
57
67
|
request.write(data);
|
|
@@ -71,32 +81,3 @@ export async function login(hostname, username, password) {
|
|
|
71
81
|
throw error;
|
|
72
82
|
}
|
|
73
83
|
}
|
|
74
|
-
export function createAppframeProxy(options) {
|
|
75
|
-
let { hostname, password, protocol = "https", username } = options;
|
|
76
|
-
// @ts-ignore
|
|
77
|
-
const proxy = expressProxy(() => `${protocol}://${hostname}`, {
|
|
78
|
-
memoizeHost: false,
|
|
79
|
-
proxyReqOptDecorator: async function (proxyReqOpts) {
|
|
80
|
-
if (!proxyReqOpts.path?.startsWith("/login")) {
|
|
81
|
-
let authCookies = await login(hostname, username, password);
|
|
82
|
-
let cookies = [];
|
|
83
|
-
cookies.push(`AppframeWebAuth=${authCookies["AppframeWebAuth"]}`);
|
|
84
|
-
cookies.push(`AppframeWebSession=${authCookies["AppframeWebSession"]}`);
|
|
85
|
-
proxyReqOpts.headers = proxyReqOpts.headers ?? {};
|
|
86
|
-
proxyReqOpts.headers["cookie"] = cookies.join(";");
|
|
87
|
-
}
|
|
88
|
-
return proxyReqOpts;
|
|
89
|
-
},
|
|
90
|
-
proxyReqPathResolver: function (req) {
|
|
91
|
-
return req.originalUrl;
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
proxy.setHostname = async (newHostname) => {
|
|
95
|
-
if (hostname !== newHostname) {
|
|
96
|
-
hostname = newHostname;
|
|
97
|
-
console.log(`Changing proxy host to '${newHostname}'...`);
|
|
98
|
-
await login(hostname, username, password);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
return proxy;
|
|
102
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-vite",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-rc.1",
|
|
4
4
|
"description": "Tools to use and deploy Vite applications to Appframe",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -20,12 +20,15 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@olenbetong/appframe-data": "^0.8.10",
|
|
23
|
+
"chalk": "^5.3.0",
|
|
23
24
|
"chokidar": "^3.5.3",
|
|
24
25
|
"dotenv": "^16.3.1",
|
|
26
|
+
"jsdom": "^22.1.0",
|
|
25
27
|
"rollup-plugin-visualizer": "^5.9.2",
|
|
26
28
|
"vite-plugin-externals": "^0.6.2"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
31
|
+
"@types/jsdom": "^21.1.2",
|
|
29
32
|
"typescript": "^5.1.6"
|
|
30
33
|
},
|
|
31
34
|
"peerDependencies": {
|
|
@@ -40,5 +43,5 @@
|
|
|
40
43
|
"open": "^9.1.0",
|
|
41
44
|
"tcp-port-used": "^1.0.2"
|
|
42
45
|
},
|
|
43
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "2e06c4e76d3a0e56aec830b06f9dc5491e5291df"
|
|
44
47
|
}
|