elm-pages 2.1.11 → 3.0.0-beta.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/codegen/elm-pages-codegen.js +38507 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/{template/public/style.css → dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/lock} +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +6795 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25651 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +110 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +187 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/package.json +1 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/src/Reporter.elm +26 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/src/Runner.elm +62 -0
- package/generator/dead-code-review/elm.json +35 -0
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +181 -0
- package/generator/dead-code-review/src/ReviewConfig.elm +9 -0
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +455 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/lock +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +6795 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +27617 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +110 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +187 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/package.json +1 -0
- package/generator/review/elm-stuff/tests-0.19.1/src/Reporter.elm +26 -0
- package/generator/review/elm-stuff/tests-0.19.1/src/Runner.elm +62 -0
- package/generator/review/elm.json +13 -4
- package/{src → generator/review/src}/Pages/Review/NoContractViolations.elm +148 -148
- package/generator/review/tests/Pages/Review/NoContractViolationsTest.elm +331 -0
- package/generator/src/RouteBuilder.elm +420 -0
- package/generator/src/SharedTemplate.elm +4 -5
- package/generator/src/SiteConfig.elm +3 -9
- package/generator/src/build.js +308 -95
- package/generator/src/cli.js +103 -8
- package/generator/src/codegen.js +192 -35
- package/generator/src/compile-elm.js +183 -31
- package/generator/src/dev-server.js +353 -96
- package/generator/src/elm-application.json +3 -1
- package/generator/src/elm-codegen.js +34 -0
- package/generator/src/elm-file-constants.js +2 -0
- package/generator/src/error-formatter.js +20 -1
- package/generator/src/generate-template-module-connector.js +125 -927
- package/generator/src/hello.ts +5 -0
- package/generator/src/pre-render-html.js +58 -104
- package/generator/src/render-worker.js +27 -13
- package/generator/src/render.js +252 -197
- package/generator/src/request-cache-fs.js +18 -0
- package/generator/src/request-cache.js +128 -56
- package/generator/src/rewrite-client-elm-json.js +49 -0
- package/generator/src/route-codegen-helpers.js +62 -1
- package/generator/static-code/dev-style.css +22 -0
- package/generator/static-code/elm-pages.js +43 -39
- package/generator/static-code/hmr.js +98 -88
- package/generator/template/app/Api.elm +25 -0
- package/generator/template/app/ErrorPage.elm +38 -0
- package/generator/template/app/Route/Index.elm +87 -0
- package/generator/template/{src → app}/Shared.elm +34 -13
- package/generator/template/app/Site.elm +19 -0
- package/generator/template/{src → app}/View.elm +0 -0
- package/generator/template/elm-pages.config.mjs +5 -0
- package/generator/template/elm.json +1 -0
- package/generator/template/{public/index.js → index.ts} +7 -3
- package/generator/template/package.json +4 -4
- package/generator/template/public/favicon.ico +0 -0
- package/generator/template/public/images/icon-png.png +0 -0
- package/generator/template/src/.gitkeep +0 -0
- package/generator/template/style.css +4 -0
- package/package.json +33 -23
- package/src/ApiRoute.elm +176 -43
- package/src/BuildError.elm +10 -1
- package/src/CookieParser.elm +84 -0
- package/src/DataSource/Env.elm +38 -0
- package/src/DataSource/File.elm +27 -16
- package/src/DataSource/Glob.elm +126 -80
- package/src/DataSource/Http.elm +283 -304
- package/src/DataSource/Internal/Glob.elm +5 -21
- package/src/DataSource/Internal/Request.elm +25 -0
- package/src/DataSource/Port.elm +17 -14
- package/src/DataSource.elm +55 -318
- package/src/Form/Field.elm +717 -0
- package/src/Form/FieldStatus.elm +36 -0
- package/src/Form/FieldView.elm +417 -0
- package/src/Form/FormData.elm +22 -0
- package/src/Form/Validation.elm +391 -0
- package/src/Form/Value.elm +118 -0
- package/src/Form.elm +1683 -0
- package/src/FormData.elm +58 -0
- package/src/FormDecoder.elm +102 -0
- package/src/Head/Seo.elm +12 -4
- package/src/Head.elm +12 -2
- package/src/HtmlPrinter.elm +1 -1
- package/src/Internal/ApiRoute.elm +17 -4
- package/src/Internal/Request.elm +7 -0
- package/src/PageServerResponse.elm +68 -0
- package/src/Pages/ContentCache.elm +1 -229
- package/src/Pages/Fetcher.elm +58 -0
- package/src/Pages/FormState.elm +256 -0
- package/src/Pages/Generate.elm +800 -0
- package/src/Pages/Internal/Form.elm +17 -0
- package/src/Pages/Internal/NotFoundReason.elm +3 -55
- package/src/Pages/Internal/Platform/Cli.elm +777 -579
- package/src/Pages/Internal/Platform/Effect.elm +5 -5
- package/src/Pages/Internal/Platform/StaticResponses.elm +178 -394
- package/src/Pages/Internal/Platform/ToJsPayload.elm +24 -23
- package/src/Pages/Internal/Platform.elm +1244 -504
- package/src/Pages/Internal/ResponseSketch.elm +19 -0
- package/src/Pages/Internal/RoutePattern.elm +596 -45
- package/src/Pages/Manifest.elm +26 -0
- package/src/Pages/Msg.elm +79 -0
- package/src/Pages/ProgramConfig.elm +67 -14
- package/src/Pages/SiteConfig.elm +3 -6
- package/src/Pages/StaticHttp/Request.elm +4 -2
- package/src/Pages/StaticHttpRequest.elm +50 -215
- package/src/Pages/Transition.elm +70 -0
- package/src/Path.elm +1 -0
- package/src/Pattern.elm +98 -0
- package/src/RenderRequest.elm +2 -2
- package/src/RequestsAndPending.elm +111 -9
- package/src/Server/Request.elm +1253 -0
- package/src/Server/Response.elm +292 -0
- package/src/Server/Session.elm +316 -0
- package/src/Server/SetCookie.elm +169 -0
- package/src/TerminalText.elm +1 -1
- package/src/Test/Html/Internal/ElmHtml/Markdown.elm +0 -1
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +1 -1
- package/generator/src/Page.elm +0 -359
- package/generator/src/codegen-template-module.js +0 -183
- package/generator/src/elm-pages-js-minified.js +0 -1
- package/generator/template/src/Api.elm +0 -14
- package/generator/template/src/Page/Index.elm +0 -69
- package/generator/template/src/Site.elm +0 -41
- package/src/DataSource/ServerRequest.elm +0 -60
- package/src/Internal/OptimizedDecoder.elm +0 -18
- package/src/KeepOrDiscard.elm +0 -6
- package/src/OptimizedDecoder/Pipeline.elm +0 -335
- package/src/OptimizedDecoder.elm +0 -818
- package/src/Pages/Internal/ApplicationType.elm +0 -6
- package/src/Pages/Secrets.elm +0 -83
- package/src/Secrets.elm +0 -111
- package/src/SecretsDict.elm +0 -45
package/generator/src/render.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
const path = require("path");
|
|
4
|
+
const mm = require("micromatch");
|
|
4
5
|
const matter = require("gray-matter");
|
|
5
6
|
const globby = require("globby");
|
|
6
7
|
const fsPromises = require("fs").promises;
|
|
7
8
|
const preRenderHtml = require("./pre-render-html.js");
|
|
8
9
|
const { lookupOrPerform } = require("./request-cache.js");
|
|
9
10
|
const kleur = require("kleur");
|
|
11
|
+
const cookie = require("cookie-signature");
|
|
10
12
|
kleur.enabled = true;
|
|
11
13
|
|
|
12
14
|
process.on("unhandledRejection", (error) => {
|
|
@@ -22,31 +24,41 @@ module.exports =
|
|
|
22
24
|
* @param {string} basePath
|
|
23
25
|
* @param {Object} elmModule
|
|
24
26
|
* @param {string} path
|
|
25
|
-
* @param {
|
|
27
|
+
* @param {{ method: string; hostname: string; query: Record<string, string | undefined>; headers: Record<string, string>; host: string; pathname: string; port: number | null; protocol: string; rawUrl: string; }} request
|
|
26
28
|
* @param {(pattern: string) => void} addDataSourceWatcher
|
|
29
|
+
* @param {boolean} hasFsAccess
|
|
27
30
|
* @returns
|
|
28
31
|
*/
|
|
29
32
|
async function run(
|
|
33
|
+
portsFile,
|
|
30
34
|
basePath,
|
|
31
35
|
elmModule,
|
|
32
36
|
mode,
|
|
33
37
|
path,
|
|
34
38
|
request,
|
|
35
|
-
addDataSourceWatcher
|
|
39
|
+
addDataSourceWatcher,
|
|
40
|
+
hasFsAccess
|
|
36
41
|
) {
|
|
42
|
+
const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(
|
|
43
|
+
hasFsAccess
|
|
44
|
+
);
|
|
45
|
+
resetInMemoryFs();
|
|
37
46
|
foundErrors = false;
|
|
38
47
|
pendingDataSourceResponses = [];
|
|
39
48
|
pendingDataSourceCount = 0;
|
|
40
|
-
// since init/update are never called in pre-renders, and DataSource.Http is called using
|
|
49
|
+
// since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
|
|
41
50
|
// we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
|
|
42
51
|
XMLHttpRequest = {};
|
|
43
52
|
const result = await runElmApp(
|
|
53
|
+
portsFile,
|
|
44
54
|
basePath,
|
|
45
55
|
elmModule,
|
|
46
56
|
mode,
|
|
47
57
|
path,
|
|
48
58
|
request,
|
|
49
|
-
addDataSourceWatcher
|
|
59
|
+
addDataSourceWatcher,
|
|
60
|
+
fs,
|
|
61
|
+
hasFsAccess
|
|
50
62
|
);
|
|
51
63
|
return result;
|
|
52
64
|
};
|
|
@@ -56,49 +68,61 @@ module.exports =
|
|
|
56
68
|
* @param {Object} elmModule
|
|
57
69
|
* @param {string} pagePath
|
|
58
70
|
* @param {string} mode
|
|
59
|
-
* @param {
|
|
71
|
+
* @param {{ method: string; hostname: string; query: string; headers: Object; host: string; pathname: string; port: string; protocol: string; rawUrl: string; }} request
|
|
60
72
|
* @param {(pattern: string) => void} addDataSourceWatcher
|
|
61
73
|
* @returns {Promise<({is404: boolean} & ( { kind: 'json'; contentJson: string} | { kind: 'html'; htmlString: string } | { kind: 'api-response'; body: string; }) )>}
|
|
62
74
|
*/
|
|
63
75
|
function runElmApp(
|
|
76
|
+
portsFile,
|
|
64
77
|
basePath,
|
|
65
78
|
elmModule,
|
|
66
79
|
mode,
|
|
67
80
|
pagePath,
|
|
68
81
|
request,
|
|
69
|
-
addDataSourceWatcher
|
|
82
|
+
addDataSourceWatcher,
|
|
83
|
+
fs,
|
|
84
|
+
hasFsAccess
|
|
70
85
|
) {
|
|
71
86
|
const isDevServer = mode !== "build";
|
|
72
87
|
let patternsToWatch = new Set();
|
|
73
88
|
let app = null;
|
|
74
89
|
let killApp;
|
|
75
90
|
return new Promise((resolve, reject) => {
|
|
76
|
-
const
|
|
77
|
-
const route = pagePath
|
|
91
|
+
const isBytes = pagePath.match(/content\.dat\/?$/);
|
|
92
|
+
const route = pagePath
|
|
93
|
+
.replace(/content\.json\/?$/, "")
|
|
94
|
+
.replace(/content\.dat\/?$/, "");
|
|
78
95
|
|
|
79
96
|
const modifiedRequest = { ...request, path: route };
|
|
80
97
|
// console.log("StaticHttp cache keys", Object.keys(global.staticHttpCache));
|
|
81
|
-
app = elmModule.Elm.
|
|
98
|
+
app = elmModule.Elm.Main.init({
|
|
82
99
|
flags: {
|
|
83
|
-
secrets: process.env,
|
|
84
|
-
staticHttpCache: global.staticHttpCache || {},
|
|
85
100
|
mode,
|
|
86
101
|
request: {
|
|
87
102
|
payload: modifiedRequest,
|
|
88
103
|
kind: "single-page",
|
|
89
|
-
jsonOnly: !!
|
|
104
|
+
jsonOnly: !!isBytes,
|
|
90
105
|
},
|
|
91
106
|
},
|
|
92
107
|
});
|
|
93
108
|
|
|
94
109
|
killApp = () => {
|
|
95
110
|
app.ports.toJsPort.unsubscribe(portHandler);
|
|
111
|
+
app.ports.sendPageData.unsubscribe(portHandler);
|
|
96
112
|
app.die();
|
|
97
113
|
app = null;
|
|
98
114
|
// delete require.cache[require.resolve(compiledElmPath)];
|
|
99
115
|
};
|
|
100
116
|
|
|
101
|
-
async function portHandler(/** @type { FromElm } */
|
|
117
|
+
async function portHandler(/** @type { FromElm } */ newThing) {
|
|
118
|
+
let fromElm;
|
|
119
|
+
let contentDatPayload;
|
|
120
|
+
if ("oldThing" in newThing) {
|
|
121
|
+
fromElm = newThing.oldThing;
|
|
122
|
+
contentDatPayload = newThing.binaryPageData;
|
|
123
|
+
} else {
|
|
124
|
+
fromElm = newThing;
|
|
125
|
+
}
|
|
102
126
|
if (fromElm.command === "log") {
|
|
103
127
|
console.log(fromElm.value);
|
|
104
128
|
} else if (fromElm.tag === "ApiResponse") {
|
|
@@ -119,51 +143,63 @@ function runElmApp(
|
|
|
119
143
|
global.staticHttpCache = args.staticHttpCache;
|
|
120
144
|
}
|
|
121
145
|
|
|
122
|
-
if (
|
|
146
|
+
if (isBytes) {
|
|
123
147
|
resolve({
|
|
124
|
-
kind: "
|
|
125
|
-
is404:
|
|
148
|
+
kind: "bytes",
|
|
149
|
+
is404: false,
|
|
126
150
|
contentJson: JSON.stringify({
|
|
127
151
|
staticData: args.contentJson,
|
|
128
|
-
is404:
|
|
152
|
+
is404: false,
|
|
129
153
|
}),
|
|
154
|
+
statusCode: args.statusCode,
|
|
155
|
+
headers: args.headers,
|
|
156
|
+
contentDatPayload,
|
|
130
157
|
});
|
|
131
158
|
} else {
|
|
132
|
-
resolve(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const filePath = fromElm.args[0];
|
|
136
|
-
try {
|
|
137
|
-
patternsToWatch.add(filePath);
|
|
138
|
-
|
|
139
|
-
runJob(app, filePath);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
sendError(app, {
|
|
142
|
-
title: "DataSource.File Error",
|
|
143
|
-
message: `A DataSource.File read failed because I couldn't find this file: ${kleur.yellow(
|
|
144
|
-
filePath
|
|
145
|
-
)}`,
|
|
146
|
-
});
|
|
159
|
+
resolve(
|
|
160
|
+
outputString(basePath, fromElm, isDevServer, contentDatPayload)
|
|
161
|
+
);
|
|
147
162
|
}
|
|
148
163
|
} else if (fromElm.tag === "DoHttp") {
|
|
149
164
|
const requestToPerform = fromElm.args[0];
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
165
|
+
if (
|
|
166
|
+
requestToPerform.url !== "elm-pages-internal://port" &&
|
|
167
|
+
requestToPerform.url.startsWith("elm-pages-internal://")
|
|
168
|
+
) {
|
|
169
|
+
runInternalJob(
|
|
170
|
+
app,
|
|
171
|
+
mode,
|
|
172
|
+
requestToPerform,
|
|
173
|
+
fs,
|
|
174
|
+
hasFsAccess,
|
|
175
|
+
patternsToWatch
|
|
176
|
+
);
|
|
177
|
+
} else {
|
|
178
|
+
runHttpJob(
|
|
179
|
+
portsFile,
|
|
180
|
+
app,
|
|
181
|
+
mode,
|
|
182
|
+
requestToPerform,
|
|
183
|
+
fs,
|
|
184
|
+
hasFsAccess,
|
|
185
|
+
fromElm.args[1]
|
|
186
|
+
);
|
|
187
|
+
}
|
|
155
188
|
} else if (fromElm.tag === "Errors") {
|
|
156
189
|
foundErrors = true;
|
|
157
|
-
reject(fromElm.args[0]);
|
|
190
|
+
reject(fromElm.args[0].errorsJson);
|
|
158
191
|
} else {
|
|
159
192
|
console.log(fromElm);
|
|
160
193
|
}
|
|
161
194
|
}
|
|
162
195
|
app.ports.toJsPort.subscribe(portHandler);
|
|
196
|
+
app.ports.sendPageData.subscribe(portHandler);
|
|
163
197
|
}).finally(() => {
|
|
164
198
|
addDataSourceWatcher(patternsToWatch);
|
|
165
|
-
|
|
166
|
-
|
|
199
|
+
try {
|
|
200
|
+
killApp();
|
|
201
|
+
killApp = null;
|
|
202
|
+
} catch (error) {}
|
|
167
203
|
});
|
|
168
204
|
}
|
|
169
205
|
/**
|
|
@@ -174,21 +210,27 @@ function runElmApp(
|
|
|
174
210
|
async function outputString(
|
|
175
211
|
basePath,
|
|
176
212
|
/** @type { PageProgress } */ fromElm,
|
|
177
|
-
isDevServer
|
|
213
|
+
isDevServer,
|
|
214
|
+
contentDatPayload
|
|
178
215
|
) {
|
|
179
216
|
const args = fromElm.args[0];
|
|
180
217
|
let contentJson = {};
|
|
181
218
|
contentJson["staticData"] = args.contentJson;
|
|
182
219
|
contentJson["is404"] = args.is404;
|
|
183
220
|
contentJson["path"] = args.route;
|
|
221
|
+
contentJson["statusCode"] = args.statusCode;
|
|
222
|
+
contentJson["headers"] = args.headers;
|
|
184
223
|
const normalizedRoute = args.route.replace(/index$/, "");
|
|
185
224
|
|
|
186
225
|
return {
|
|
187
226
|
is404: args.is404,
|
|
188
227
|
route: normalizedRoute,
|
|
189
|
-
htmlString: preRenderHtml(basePath, args,
|
|
228
|
+
htmlString: preRenderHtml.wrapHtml(basePath, args, contentDatPayload),
|
|
190
229
|
contentJson: args.contentJson,
|
|
230
|
+
statusCode: args.statusCode,
|
|
231
|
+
headers: args.headers,
|
|
191
232
|
kind: "html",
|
|
233
|
+
contentDatPayload,
|
|
192
234
|
};
|
|
193
235
|
}
|
|
194
236
|
|
|
@@ -201,73 +243,30 @@ async function outputString(
|
|
|
201
243
|
|
|
202
244
|
/** @typedef { { head: any[]; errors: any[]; contentJson: any[]; html: string; route: string; title: string; } } Arg */
|
|
203
245
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async function runJob(app, filePath) {
|
|
216
|
-
pendingDataSourceCount += 1;
|
|
217
|
-
try {
|
|
218
|
-
const fileContents = (
|
|
219
|
-
await fsPromises.readFile(path.join(process.cwd(), filePath))
|
|
220
|
-
).toString();
|
|
221
|
-
const parsedFile = matter(fileContents);
|
|
222
|
-
|
|
223
|
-
pendingDataSourceResponses.push({
|
|
224
|
-
request: {
|
|
225
|
-
masked: {
|
|
226
|
-
url: `file://${filePath}`,
|
|
227
|
-
method: "GET",
|
|
228
|
-
headers: [],
|
|
229
|
-
body: { tag: "EmptyBody", args: [] },
|
|
230
|
-
},
|
|
231
|
-
unmasked: {
|
|
232
|
-
url: `file://${filePath}`,
|
|
233
|
-
method: "GET",
|
|
234
|
-
headers: [],
|
|
235
|
-
body: { tag: "EmptyBody", args: [] },
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
response: JSON.stringify({
|
|
239
|
-
parsedFrontmatter: parsedFile.data,
|
|
240
|
-
withoutFrontmatter: parsedFile.content,
|
|
241
|
-
rawFile: fileContents,
|
|
242
|
-
jsonFile: jsonOrNull(fileContents),
|
|
243
|
-
}),
|
|
244
|
-
});
|
|
245
|
-
} catch (e) {
|
|
246
|
-
sendError(app, {
|
|
247
|
-
title: "Error reading file",
|
|
248
|
-
message: `A DataSource.File read failed because I couldn't find this file: ${kleur.yellow(
|
|
249
|
-
filePath
|
|
250
|
-
)}`,
|
|
251
|
-
});
|
|
252
|
-
} finally {
|
|
253
|
-
pendingDataSourceCount -= 1;
|
|
254
|
-
flushIfDone(app);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
async function runHttpJob(app, mode, requestToPerform) {
|
|
246
|
+
async function runHttpJob(
|
|
247
|
+
portsFile,
|
|
248
|
+
app,
|
|
249
|
+
mode,
|
|
250
|
+
requestToPerform,
|
|
251
|
+
fs,
|
|
252
|
+
hasFsAccess,
|
|
253
|
+
useCache
|
|
254
|
+
) {
|
|
259
255
|
pendingDataSourceCount += 1;
|
|
260
256
|
try {
|
|
261
257
|
const responseFilePath = await lookupOrPerform(
|
|
258
|
+
portsFile,
|
|
262
259
|
mode,
|
|
263
|
-
requestToPerform
|
|
260
|
+
requestToPerform,
|
|
261
|
+
hasFsAccess,
|
|
262
|
+
useCache
|
|
264
263
|
);
|
|
265
264
|
|
|
266
265
|
pendingDataSourceResponses.push({
|
|
267
266
|
request: requestToPerform,
|
|
268
|
-
response: (
|
|
269
|
-
await
|
|
270
|
-
)
|
|
267
|
+
response: JSON.parse(
|
|
268
|
+
(await fs.promises.readFile(responseFilePath, "utf8")).toString()
|
|
269
|
+
),
|
|
271
270
|
});
|
|
272
271
|
} catch (error) {
|
|
273
272
|
sendError(app, error);
|
|
@@ -277,129 +276,173 @@ async function runHttpJob(app, mode, requestToPerform) {
|
|
|
277
276
|
}
|
|
278
277
|
}
|
|
279
278
|
|
|
280
|
-
|
|
279
|
+
function stringResponse(request, string) {
|
|
280
|
+
return {
|
|
281
|
+
request,
|
|
282
|
+
response: { bodyKind: "string", body: string },
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function jsonResponse(request, json) {
|
|
286
|
+
return {
|
|
287
|
+
request,
|
|
288
|
+
response: { bodyKind: "json", body: json },
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function runInternalJob(
|
|
293
|
+
app,
|
|
294
|
+
mode,
|
|
295
|
+
requestToPerform,
|
|
296
|
+
fs,
|
|
297
|
+
hasFsAccess,
|
|
298
|
+
patternsToWatch
|
|
299
|
+
) {
|
|
281
300
|
try {
|
|
282
|
-
// if (pendingDataSourceCount > 0) {
|
|
283
|
-
// console.log(`Waiting for ${pendingDataSourceCount} pending data sources`);
|
|
284
|
-
// }
|
|
285
301
|
pendingDataSourceCount += 1;
|
|
286
302
|
|
|
287
|
-
|
|
303
|
+
if (requestToPerform.url === "elm-pages-internal://read-file") {
|
|
304
|
+
pendingDataSourceResponses.push(
|
|
305
|
+
await readFileJobNew(requestToPerform, patternsToWatch)
|
|
306
|
+
);
|
|
307
|
+
} else if (requestToPerform.url === "elm-pages-internal://glob") {
|
|
308
|
+
pendingDataSourceResponses.push(
|
|
309
|
+
await runGlobNew(requestToPerform, patternsToWatch)
|
|
310
|
+
);
|
|
311
|
+
} else if (requestToPerform.url === "elm-pages-internal://env") {
|
|
312
|
+
pendingDataSourceResponses.push(
|
|
313
|
+
await runEnvJob(requestToPerform, patternsToWatch)
|
|
314
|
+
);
|
|
315
|
+
} else if (requestToPerform.url === "elm-pages-internal://encrypt") {
|
|
316
|
+
pendingDataSourceResponses.push(
|
|
317
|
+
await runEncryptJob(requestToPerform, patternsToWatch)
|
|
318
|
+
);
|
|
319
|
+
} else if (requestToPerform.url === "elm-pages-internal://decrypt") {
|
|
320
|
+
pendingDataSourceResponses.push(
|
|
321
|
+
await runDecryptJob(requestToPerform, patternsToWatch)
|
|
322
|
+
);
|
|
323
|
+
} else {
|
|
324
|
+
throw `Unexpected internal DataSource request format: ${kleur.yellow(
|
|
325
|
+
JSON.stringify(2, null, requestToPerform)
|
|
326
|
+
)}`;
|
|
327
|
+
}
|
|
288
328
|
} catch (error) {
|
|
289
|
-
|
|
290
|
-
throw error;
|
|
329
|
+
sendError(app, error);
|
|
291
330
|
} finally {
|
|
292
331
|
pendingDataSourceCount -= 1;
|
|
293
332
|
flushIfDone(app);
|
|
294
333
|
}
|
|
295
334
|
}
|
|
296
335
|
|
|
297
|
-
function
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
// console.log(
|
|
302
|
-
// `Flushing ${pendingDataSourceResponses.length} items in ${timeUntilThreshold}ms`
|
|
303
|
-
// );
|
|
336
|
+
async function readFileJobNew(req, patternsToWatch) {
|
|
337
|
+
const filePath = req.body.args[1];
|
|
338
|
+
try {
|
|
339
|
+
patternsToWatch.add(filePath);
|
|
304
340
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
341
|
+
const fileContents = // TODO can I remove this hack?
|
|
342
|
+
(
|
|
343
|
+
await fsPromises.readFile(
|
|
344
|
+
path.join(process.env.LAMBDA_TASK_ROOT || process.cwd(), filePath)
|
|
345
|
+
)
|
|
346
|
+
).toString();
|
|
347
|
+
const parsedFile = matter(fileContents);
|
|
308
348
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
349
|
+
return jsonResponse(req, {
|
|
350
|
+
parsedFrontmatter: parsedFile.data,
|
|
351
|
+
withoutFrontmatter: parsedFile.content,
|
|
352
|
+
rawFile: fileContents,
|
|
353
|
+
});
|
|
354
|
+
} catch (error) {
|
|
355
|
+
throw {
|
|
356
|
+
title: "DataSource.File Error",
|
|
357
|
+
message: `A DataSource.File read failed because I couldn't find this file: ${kleur.yellow(
|
|
358
|
+
filePath
|
|
359
|
+
)}\n${kleur.red(error.toString())}`,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
317
362
|
}
|
|
318
363
|
|
|
319
|
-
|
|
320
|
-
* @param {string} filePath
|
|
321
|
-
* @returns {Promise<Object>}
|
|
322
|
-
*/
|
|
323
|
-
async function readFileTask(app, filePath) {
|
|
324
|
-
// console.log(`Read file ${filePath}`);
|
|
364
|
+
async function runGlobNew(req, patternsToWatch) {
|
|
325
365
|
try {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
// console.log(`DONE reading file ${filePath}`);
|
|
330
|
-
const parsedFile = matter(fileContents);
|
|
366
|
+
const { pattern, options } = req.body.args[0];
|
|
367
|
+
const matchedPaths = await globby(pattern, options);
|
|
368
|
+
patternsToWatch.add(pattern);
|
|
331
369
|
|
|
332
|
-
return
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
url: `file://${filePath}`,
|
|
342
|
-
method: "GET",
|
|
343
|
-
headers: [],
|
|
344
|
-
body: { tag: "EmptyBody", args: [] },
|
|
345
|
-
},
|
|
346
|
-
},
|
|
347
|
-
response: JSON.stringify({
|
|
348
|
-
parsedFrontmatter: parsedFile.data,
|
|
349
|
-
withoutFrontmatter: parsedFile.content,
|
|
350
|
-
rawFile: fileContents,
|
|
351
|
-
jsonFile: jsonOrNull(fileContents),
|
|
352
|
-
}),
|
|
353
|
-
};
|
|
370
|
+
return jsonResponse(
|
|
371
|
+
req,
|
|
372
|
+
matchedPaths.map((fullPath) => {
|
|
373
|
+
return {
|
|
374
|
+
fullPath,
|
|
375
|
+
captures: mm.capture(pattern, fullPath),
|
|
376
|
+
};
|
|
377
|
+
})
|
|
378
|
+
);
|
|
354
379
|
} catch (e) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
message: `A DataSource.File read failed because I couldn't find this file: ${kleur.yellow(
|
|
358
|
-
filePath
|
|
359
|
-
)}`,
|
|
360
|
-
});
|
|
380
|
+
console.log(`Error performing glob '${JSON.stringify(req.body)}'`);
|
|
381
|
+
throw e;
|
|
361
382
|
}
|
|
362
383
|
}
|
|
363
384
|
|
|
364
|
-
|
|
365
|
-
* @param {string} globPattern
|
|
366
|
-
* @returns {Promise<Object>}
|
|
367
|
-
*/
|
|
368
|
-
async function globTask(globPattern) {
|
|
385
|
+
async function runEnvJob(req, patternsToWatch) {
|
|
369
386
|
try {
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return {
|
|
374
|
-
request: {
|
|
375
|
-
masked: {
|
|
376
|
-
url: `glob://${globPattern}`,
|
|
377
|
-
method: "GET",
|
|
378
|
-
headers: [],
|
|
379
|
-
body: { tag: "EmptyBody", args: [] },
|
|
380
|
-
},
|
|
381
|
-
unmasked: {
|
|
382
|
-
url: `glob://${globPattern}`,
|
|
383
|
-
method: "GET",
|
|
384
|
-
headers: [],
|
|
385
|
-
body: { tag: "EmptyBody", args: [] },
|
|
386
|
-
},
|
|
387
|
-
},
|
|
388
|
-
response: JSON.stringify(matchedPaths),
|
|
389
|
-
};
|
|
387
|
+
const expectedEnv = req.body.args[0];
|
|
388
|
+
return jsonResponse(req, process.env[expectedEnv] || null);
|
|
390
389
|
} catch (e) {
|
|
391
|
-
console.log(`Error performing
|
|
390
|
+
console.log(`Error performing env '${JSON.stringify(req.body)}'`);
|
|
392
391
|
throw e;
|
|
393
392
|
}
|
|
394
393
|
}
|
|
394
|
+
async function runEncryptJob(req, patternsToWatch) {
|
|
395
|
+
try {
|
|
396
|
+
return jsonResponse(
|
|
397
|
+
req,
|
|
398
|
+
cookie.sign(
|
|
399
|
+
JSON.stringify(req.body.args[0].values, null, 0),
|
|
400
|
+
req.body.args[0].secret
|
|
401
|
+
)
|
|
402
|
+
);
|
|
403
|
+
} catch (e) {
|
|
404
|
+
throw {
|
|
405
|
+
title: "DataSource Encrypt Error",
|
|
406
|
+
message:
|
|
407
|
+
e.toString() + e.stack + "\n\n" + JSON.stringify(rawRequest, null, 2),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
async function runDecryptJob(req, patternsToWatch) {
|
|
412
|
+
try {
|
|
413
|
+
// TODO if unsign returns `false`, need to have an `Err` in Elm because decryption failed
|
|
414
|
+
const signed = tryDecodeCookie(
|
|
415
|
+
req.body.args[0].input,
|
|
416
|
+
req.body.args[0].secrets
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
return jsonResponse(req, JSON.parse(signed || "null"));
|
|
420
|
+
} catch (e) {
|
|
421
|
+
throw {
|
|
422
|
+
title: "DataSource Decrypt Error",
|
|
423
|
+
message:
|
|
424
|
+
e.toString() + e.stack + "\n\n" + JSON.stringify(rawRequest, null, 2),
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function flushIfDone(app) {
|
|
430
|
+
if (foundErrors) {
|
|
431
|
+
pendingDataSourceResponses = [];
|
|
432
|
+
} else if (pendingDataSourceCount === 0) {
|
|
433
|
+
// console.log(
|
|
434
|
+
// `Flushing ${pendingDataSourceResponses.length} items in ${timeUntilThreshold}ms`
|
|
435
|
+
// );
|
|
395
436
|
|
|
396
|
-
|
|
397
|
-
if (mode === "dev-server") {
|
|
398
|
-
// for the build command, we can skip clearing the cache because it won't change while the build is running
|
|
399
|
-
// in the dev server, we want to clear the cache to get a the latest code each time it runs
|
|
400
|
-
delete require.cache[require.resolve(filePath)];
|
|
437
|
+
flushQueue(app);
|
|
401
438
|
}
|
|
402
|
-
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function flushQueue(app) {
|
|
442
|
+
const temp = pendingDataSourceResponses;
|
|
443
|
+
pendingDataSourceResponses = [];
|
|
444
|
+
// console.log("@@@ FLUSHING", temp.length);
|
|
445
|
+
app.ports.gotBatchSub.send(temp);
|
|
403
446
|
}
|
|
404
447
|
|
|
405
448
|
/**
|
|
@@ -414,3 +457,15 @@ function sendError(app, error) {
|
|
|
414
457
|
data: error,
|
|
415
458
|
});
|
|
416
459
|
}
|
|
460
|
+
function tryDecodeCookie(input, secrets) {
|
|
461
|
+
if (secrets.length > 0) {
|
|
462
|
+
const signed = cookie.unsign(input, secrets[0]);
|
|
463
|
+
if (signed) {
|
|
464
|
+
return signed;
|
|
465
|
+
} else {
|
|
466
|
+
return tryDecodeCookie(input, secrets.slice(1));
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module.exports = function (/** @type {boolean} */ hasFsAccess) {
|
|
2
|
+
if (hasFsAccess) {
|
|
3
|
+
return {
|
|
4
|
+
fs: require("fs"),
|
|
5
|
+
resetInMemoryFs: () => {},
|
|
6
|
+
};
|
|
7
|
+
} else {
|
|
8
|
+
const { vol, fs, Volume } = require("memfs");
|
|
9
|
+
vol.fromJSON({});
|
|
10
|
+
// vol.reset();
|
|
11
|
+
return {
|
|
12
|
+
fs: fs,
|
|
13
|
+
resetInMemoryFs: () => {
|
|
14
|
+
vol.reset();
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|