@witchcraft/nuxt-electron 0.2.2 → 0.2.3
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/dist/module.json
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Protocol } from "electron";
|
|
2
|
+
export declare const cache: Map<string, string | undefined>;
|
|
3
|
+
export declare const proxyCache: Map<string, string | undefined>;
|
|
2
4
|
export declare function createProxiedProtocolHandler(
|
|
3
5
|
/** `protocol` or `session.protocol` depending on if you're using paritions with your windows or not, regular `protocol` only registers the handler for the default parition. */
|
|
4
6
|
protocol: Protocol, protocolName: string | undefined, basePath: string,
|
|
@@ -7,14 +9,33 @@ protocol: Protocol, protocolName: string | undefined, basePath: string,
|
|
|
7
9
|
*
|
|
8
10
|
* At least `/api` should be added for a basic nuxt app to work correctly.
|
|
9
11
|
*
|
|
12
|
+
* The longest key matched will be used.
|
|
10
13
|
*
|
|
11
14
|
* ```ts
|
|
12
15
|
* routeProxies: {
|
|
13
|
-
* "/api": "http://localhost:3000/api
|
|
16
|
+
* "/api": "http://localhost:3000", // turns into http://localhost:3000/api
|
|
17
|
+
* // for more control, for example: to proxy /your/path to some other path while removing the /your/path part:
|
|
18
|
+
* "/your/path": {
|
|
19
|
+
* url: "http://some-site.com",
|
|
20
|
+
* convertPath: (proxyKey, url, requestPath) => url + requestPath.slice(proxyKey.length)
|
|
21
|
+
* }
|
|
22
|
+
* // to ignore a path
|
|
23
|
+
* "/ignore/some/path": {
|
|
24
|
+
* ignore: true
|
|
25
|
+
* }
|
|
14
26
|
* }
|
|
15
27
|
* ```
|
|
16
28
|
*/
|
|
17
|
-
routeProxies: Record<string, string
|
|
29
|
+
routeProxies: Record<string, string | {
|
|
30
|
+
url: string;
|
|
31
|
+
/** Override how the path is merged with the url. The default literally just concatenates url + path. */
|
|
32
|
+
convertPath?: (proxyKey: string, url: string, requestPath: string) => string;
|
|
33
|
+
ignore?: false;
|
|
34
|
+
} | {
|
|
35
|
+
url: never;
|
|
36
|
+
convertPath: never;
|
|
37
|
+
ignore: true;
|
|
38
|
+
}>, { logger, errorPage }?: {
|
|
18
39
|
/**
|
|
19
40
|
* Optional logger. It's suggested you not pass this unless you're traceging in dev mode as a lot of requests can be made.
|
|
20
41
|
*/
|
|
@@ -4,33 +4,41 @@ import { net } from "electron";
|
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
|
-
const cache = /* @__PURE__ */ new Map();
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (logger) {
|
|
12
|
-
logger.trace({
|
|
13
|
-
ns: "main:createProxiedProtocolHandler:cacheHit",
|
|
14
|
-
requestUrl: key,
|
|
15
|
-
result: cache.get(key)
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
return result;
|
|
19
|
-
}
|
|
7
|
+
export const cache = /* @__PURE__ */ new Map();
|
|
8
|
+
export const proxyCache = /* @__PURE__ */ new Map();
|
|
9
|
+
const proxiedProperties = ["headers", "destination", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive"];
|
|
10
|
+
async function getPathToServe(originalPath, pathWithIndexHtml, requestUrl, logger) {
|
|
20
11
|
const stats = await fs.stat(originalPath).catch(() => void 0);
|
|
21
12
|
if (logger) {
|
|
22
13
|
logger.trace({
|
|
23
14
|
ns: "main:createProxiedProtocolHandler:stats",
|
|
24
|
-
|
|
15
|
+
requestUrl,
|
|
25
16
|
exists: !!stats,
|
|
26
17
|
isFile: stats?.isFile(),
|
|
27
18
|
isDirectory: stats?.isDirectory()
|
|
28
19
|
});
|
|
29
20
|
}
|
|
30
21
|
const pathToServe = stats !== void 0 ? stats.isFile() ? originalPath : stats.isDirectory() ? (await fs.stat(pathWithIndexHtml).catch(() => void 0))?.isFile() ? pathWithIndexHtml : void 0 : void 0 : void 0;
|
|
31
|
-
cache.set(key, pathToServe);
|
|
32
22
|
return pathToServe;
|
|
33
23
|
}
|
|
24
|
+
async function getFromCacheOr(cache2, key, fn, logger) {
|
|
25
|
+
let result = cache2.get(key);
|
|
26
|
+
if (result) {
|
|
27
|
+
if (logger) {
|
|
28
|
+
logger.trace({
|
|
29
|
+
ns: "main:createProxiedProtocolHandler:cacheHit",
|
|
30
|
+
requestUrl: key,
|
|
31
|
+
result
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
result = await fn(key);
|
|
37
|
+
if (result) {
|
|
38
|
+
cache2.set(key, result);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
34
42
|
export function createProxiedProtocolHandler(protocol, protocolName = "app", basePath, routeProxies, {
|
|
35
43
|
logger,
|
|
36
44
|
errorPage = "404.html"
|
|
@@ -46,28 +54,44 @@ export function createProxiedProtocolHandler(protocol, protocolName = "app", bas
|
|
|
46
54
|
}
|
|
47
55
|
let errorPage404;
|
|
48
56
|
protocol.handle(protocolName, async (request) => {
|
|
49
|
-
errorPage404 ??= await getPathToServe(path.join(basePath, errorPage), "404.html",
|
|
57
|
+
errorPage404 ??= await getFromCacheOr(cache, "404.html", (key) => getPathToServe(path.join(basePath, errorPage), "404.html", key, logger), logger);
|
|
50
58
|
if (!errorPage404) {
|
|
51
59
|
throw new Error(`Error page ${path.join(basePath, errorPage)} does not exist. Did you override the routeRules for it?`);
|
|
52
60
|
}
|
|
53
61
|
const parsedUrl = new URL(request.url);
|
|
54
62
|
const requestPath = decodeURIComponent(parsedUrl.pathname);
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
const
|
|
63
|
+
const cachedProxyResult = await getFromCacheOr(proxyCache, requestPath, (_) => {
|
|
64
|
+
const matchedProxyKeys = routeProxyKeys.filter((key) => requestPath.startsWith(key));
|
|
65
|
+
const proxyKey = matchedProxyKeys.sort((a, b) => b.length - a.length)[0];
|
|
66
|
+
const proxyEntry = proxyKey && routeProxies[proxyKey];
|
|
67
|
+
if (proxyKey && proxyEntry && !(typeof proxyEntry === "object" && proxyEntry?.ignore)) {
|
|
68
|
+
const proxyUrl = typeof proxyEntry === "string" ? proxyEntry : proxyEntry?.url;
|
|
69
|
+
const finalPath2 = typeof proxyEntry === "object" && proxyEntry?.convertPath ? proxyEntry.convertPath(proxyKey, proxyUrl, requestPath) : proxyUrl + requestPath;
|
|
70
|
+
if (logger) {
|
|
71
|
+
logger.trace({
|
|
72
|
+
ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
|
|
73
|
+
requestUrl: request.url,
|
|
74
|
+
proxyKey,
|
|
75
|
+
route: proxyUrl,
|
|
76
|
+
requestPath,
|
|
77
|
+
finalPath: finalPath2
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return finalPath2;
|
|
81
|
+
}
|
|
82
|
+
return void 0;
|
|
83
|
+
});
|
|
84
|
+
if (cachedProxyResult) {
|
|
59
85
|
if (logger) {
|
|
60
86
|
logger.trace({
|
|
61
|
-
ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
|
|
87
|
+
ns: "main:createProxiedProtocolHandler:fetchingViaProxy(cached)",
|
|
62
88
|
requestUrl: request.url,
|
|
63
|
-
proxyKey,
|
|
64
|
-
route: proxyUrl,
|
|
65
89
|
requestPath,
|
|
66
|
-
finalPath:
|
|
90
|
+
finalPath: cachedProxyResult
|
|
67
91
|
});
|
|
68
92
|
}
|
|
69
|
-
return net.fetch(
|
|
70
|
-
...pick(request,
|
|
93
|
+
return net.fetch(cachedProxyResult, {
|
|
94
|
+
...pick(request, proxiedProperties)
|
|
71
95
|
});
|
|
72
96
|
}
|
|
73
97
|
const originalPath = path.join(basePath, requestPath);
|
|
@@ -107,7 +131,7 @@ export function createProxiedProtocolHandler(protocol, protocolName = "app", bas
|
|
|
107
131
|
status: 400
|
|
108
132
|
});
|
|
109
133
|
}
|
|
110
|
-
const pathToServe = await getPathToServe(originalPath, pathWithIndexHtml,
|
|
134
|
+
const pathToServe = await getFromCacheOr(cache, request.url, (key) => getPathToServe(originalPath, pathWithIndexHtml, key, logger), logger);
|
|
111
135
|
if (!pathToServe) {
|
|
112
136
|
if (logger) {
|
|
113
137
|
logger.error({
|
package/package.json
CHANGED
|
@@ -7,35 +7,24 @@ import path from "node:path"
|
|
|
7
7
|
import { pathToFileURL } from "node:url"
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
const cache = new Map<string, string | undefined>()
|
|
10
|
+
export const cache = new Map<string, string | undefined>()
|
|
11
|
+
export const proxyCache = new Map<string, string | undefined>()
|
|
12
|
+
const proxiedProperties: (keyof Request)[] = ["headers", "destination", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive"]
|
|
11
13
|
|
|
12
14
|
async function getPathToServe(
|
|
13
15
|
originalPath: string,
|
|
14
16
|
pathWithIndexHtml: string,
|
|
15
|
-
|
|
16
|
-
key: string,
|
|
17
|
+
requestUrl: string,
|
|
17
18
|
logger?: {
|
|
18
19
|
trace: (...args: any[]) => void
|
|
19
20
|
}
|
|
20
21
|
) {
|
|
21
|
-
if (cache.has(key)) {
|
|
22
|
-
const result = cache.get(key)
|
|
23
|
-
if (logger) {
|
|
24
|
-
logger.trace({
|
|
25
|
-
ns: "main:createProxiedProtocolHandler:cacheHit",
|
|
26
|
-
requestUrl: key,
|
|
27
|
-
result: cache.get(key)
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
return result
|
|
31
|
-
}
|
|
32
22
|
const stats = await fs.stat(originalPath).catch(() => undefined)
|
|
33
23
|
|
|
34
|
-
|
|
35
24
|
if (logger) {
|
|
36
25
|
logger.trace({
|
|
37
26
|
ns: "main:createProxiedProtocolHandler:stats",
|
|
38
|
-
|
|
27
|
+
requestUrl,
|
|
39
28
|
exists: !!stats,
|
|
40
29
|
isFile: stats?.isFile(),
|
|
41
30
|
isDirectory: stats?.isDirectory()
|
|
@@ -51,9 +40,28 @@ async function getPathToServe(
|
|
|
51
40
|
: undefined
|
|
52
41
|
: undefined
|
|
53
42
|
: undefined
|
|
54
|
-
cache.set(key, pathToServe)
|
|
55
43
|
return pathToServe
|
|
56
44
|
}
|
|
45
|
+
|
|
46
|
+
async function getFromCacheOr(cache: Map<string, string | undefined>, key: string, fn: (key: string) => Promise<string | undefined> | string | undefined, logger?: { trace: (...args: any[]) => void }): Promise<string | undefined> {
|
|
47
|
+
let result = cache.get(key)
|
|
48
|
+
if (result) {
|
|
49
|
+
if (logger) {
|
|
50
|
+
logger.trace({
|
|
51
|
+
ns: "main:createProxiedProtocolHandler:cacheHit",
|
|
52
|
+
requestUrl: key,
|
|
53
|
+
result
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
return result
|
|
57
|
+
}
|
|
58
|
+
result = await fn(key)
|
|
59
|
+
if (result) {
|
|
60
|
+
cache.set(key, result)
|
|
61
|
+
}
|
|
62
|
+
return result
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
export function createProxiedProtocolHandler(
|
|
58
66
|
/** `protocol` or `session.protocol` depending on if you're using paritions with your windows or not, regular `protocol` only registers the handler for the default parition. */
|
|
59
67
|
protocol: Protocol,
|
|
@@ -64,14 +72,38 @@ export function createProxiedProtocolHandler(
|
|
|
64
72
|
*
|
|
65
73
|
* At least `/api` should be added for a basic nuxt app to work correctly.
|
|
66
74
|
*
|
|
75
|
+
* The longest key matched will be used.
|
|
67
76
|
*
|
|
68
77
|
* ```ts
|
|
69
78
|
* routeProxies: {
|
|
70
|
-
* "/api": "http://localhost:3000/api
|
|
79
|
+
* "/api": "http://localhost:3000", // turns into http://localhost:3000/api
|
|
80
|
+
* // for more control, for example: to proxy /your/path to some other path while removing the /your/path part:
|
|
81
|
+
* "/your/path": {
|
|
82
|
+
* url: "http://some-site.com",
|
|
83
|
+
* convertPath: (proxyKey, url, requestPath) => url + requestPath.slice(proxyKey.length)
|
|
84
|
+
* }
|
|
85
|
+
* // to ignore a path
|
|
86
|
+
* "/ignore/some/path": {
|
|
87
|
+
* ignore: true
|
|
88
|
+
* }
|
|
71
89
|
* }
|
|
72
90
|
* ```
|
|
73
91
|
*/
|
|
74
|
-
routeProxies: Record<
|
|
92
|
+
routeProxies: Record<
|
|
93
|
+
string,
|
|
94
|
+
| string
|
|
95
|
+
| {
|
|
96
|
+
url: string
|
|
97
|
+
/** Override how the path is merged with the url. The default literally just concatenates url + path. */
|
|
98
|
+
convertPath?: (proxyKey: string, url: string, requestPath: string) => string
|
|
99
|
+
ignore?: false
|
|
100
|
+
}
|
|
101
|
+
| {
|
|
102
|
+
url: never
|
|
103
|
+
convertPath: never
|
|
104
|
+
ignore: true
|
|
105
|
+
}
|
|
106
|
+
>,
|
|
75
107
|
{
|
|
76
108
|
logger,
|
|
77
109
|
errorPage = "404.html"
|
|
@@ -108,7 +140,7 @@ export function createProxiedProtocolHandler(
|
|
|
108
140
|
// to check the user correctly registered it
|
|
109
141
|
// it's deprecated for some reason and also it doesn't work (so maybe because of that)!
|
|
110
142
|
protocol.handle(protocolName, async request => {
|
|
111
|
-
errorPage404 ??= await getPathToServe(path.join(basePath, errorPage), "404.html",
|
|
143
|
+
errorPage404 ??= await getFromCacheOr(cache, "404.html", key => getPathToServe(path.join(basePath, errorPage), "404.html", key, logger), logger)
|
|
112
144
|
|
|
113
145
|
if (!errorPage404) {
|
|
114
146
|
throw new Error(`Error page ${path.join(basePath, errorPage)} does not exist. Did you override the routeRules for it?`)
|
|
@@ -118,23 +150,45 @@ export function createProxiedProtocolHandler(
|
|
|
118
150
|
// we can ignore the host, as getPaths sets it to bundle (e.g. protocol://bundle/path/to/file)
|
|
119
151
|
const requestPath = decodeURIComponent(parsedUrl.pathname)
|
|
120
152
|
|
|
121
|
-
const proxyKey = routeProxyKeys.find(key => requestPath.startsWith(key))
|
|
122
153
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
154
|
+
// this must be on a seperate cache because the result and key are different since fetching is different
|
|
155
|
+
const cachedProxyResult = await getFromCacheOr(proxyCache, requestPath, _ /* requestPath */ => {
|
|
156
|
+
const matchedProxyKeys = routeProxyKeys.filter(key => requestPath.startsWith(key))
|
|
157
|
+
const proxyKey = matchedProxyKeys.sort((a, b) => b.length - a.length)[0]
|
|
158
|
+
|
|
159
|
+
const proxyEntry = proxyKey && routeProxies[proxyKey]
|
|
160
|
+
if (proxyKey && proxyEntry && !(typeof proxyEntry === "object" && proxyEntry?.ignore)) {
|
|
161
|
+
const proxyUrl = typeof proxyEntry === "string" ? proxyEntry : proxyEntry?.url
|
|
162
|
+
|
|
163
|
+
const finalPath = typeof proxyEntry === "object" && proxyEntry?.convertPath
|
|
164
|
+
? proxyEntry.convertPath(proxyKey, proxyUrl, requestPath)
|
|
165
|
+
: proxyUrl + requestPath
|
|
166
|
+
|
|
167
|
+
if (logger) {
|
|
168
|
+
logger.trace({
|
|
169
|
+
ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
|
|
170
|
+
requestUrl: request.url,
|
|
171
|
+
proxyKey,
|
|
172
|
+
route: proxyUrl,
|
|
173
|
+
requestPath,
|
|
174
|
+
finalPath
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
return finalPath
|
|
178
|
+
}
|
|
179
|
+
return undefined
|
|
180
|
+
})
|
|
181
|
+
if (cachedProxyResult) {
|
|
126
182
|
if (logger) {
|
|
127
183
|
logger.trace({
|
|
128
|
-
ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
|
|
184
|
+
ns: "main:createProxiedProtocolHandler:fetchingViaProxy(cached)",
|
|
129
185
|
requestUrl: request.url,
|
|
130
|
-
proxyKey,
|
|
131
|
-
route: proxyUrl,
|
|
132
186
|
requestPath,
|
|
133
|
-
finalPath
|
|
187
|
+
finalPath: cachedProxyResult
|
|
134
188
|
})
|
|
135
189
|
}
|
|
136
|
-
return net.fetch(
|
|
137
|
-
...pick(request,
|
|
190
|
+
return net.fetch(cachedProxyResult, {
|
|
191
|
+
...pick(request, proxiedProperties)
|
|
138
192
|
})
|
|
139
193
|
}
|
|
140
194
|
|
|
@@ -173,7 +227,7 @@ export function createProxiedProtocolHandler(
|
|
|
173
227
|
}
|
|
174
228
|
|
|
175
229
|
|
|
176
|
-
const pathToServe = await getPathToServe(originalPath, pathWithIndexHtml,
|
|
230
|
+
const pathToServe = await getFromCacheOr(cache, request.url, key => getPathToServe(originalPath, pathWithIndexHtml, key, logger), logger)
|
|
177
231
|
|
|
178
232
|
if (!pathToServe) {
|
|
179
233
|
if (logger) {
|