elm-pages 3.0.0-beta.8 → 3.0.0

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.
Files changed (164) hide show
  1. package/README.md +11 -2
  2. package/adapter/netlify.js +207 -0
  3. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2730 -2938
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1527 -422
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +16840 -13653
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  14. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +2 -2
  15. package/generator/dead-code-review/elm.json +9 -7
  16. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
  17. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
  21. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
  22. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  23. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  24. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  25. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  26. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1527 -422
  27. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25118 -21832
  28. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  29. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +2 -2
  30. package/generator/review/elm.json +10 -10
  31. package/generator/src/RouteBuilder.elm +93 -128
  32. package/generator/src/SharedTemplate.elm +8 -7
  33. package/generator/src/SiteConfig.elm +3 -2
  34. package/generator/src/basepath-middleware.js +3 -3
  35. package/generator/src/build.js +147 -63
  36. package/generator/src/cli.js +292 -88
  37. package/generator/src/codegen.js +29 -27
  38. package/generator/src/compatibility-key.js +3 -0
  39. package/generator/src/compile-elm.js +43 -26
  40. package/generator/src/config.js +2 -4
  41. package/generator/src/copy-dir.js +2 -2
  42. package/generator/src/dev-server.js +159 -92
  43. package/generator/src/dir-helpers.js +9 -26
  44. package/generator/src/elm-codegen.js +5 -4
  45. package/generator/src/elm-file-constants.js +2 -3
  46. package/generator/src/error-formatter.js +12 -11
  47. package/generator/src/file-helpers.js +3 -4
  48. package/generator/src/generate-template-module-connector.js +23 -23
  49. package/generator/src/init.js +9 -8
  50. package/generator/src/pre-render-html.js +10 -13
  51. package/generator/src/render-test.js +109 -0
  52. package/generator/src/render-worker.js +25 -28
  53. package/generator/src/render.js +321 -142
  54. package/generator/src/request-cache.js +265 -162
  55. package/generator/src/resolve-elm-module.js +64 -0
  56. package/generator/src/rewrite-client-elm-json.js +6 -5
  57. package/generator/src/rewrite-elm-json-help.js +56 -0
  58. package/generator/src/rewrite-elm-json.js +17 -7
  59. package/generator/src/route-codegen-helpers.js +16 -31
  60. package/generator/src/seo-renderer.js +12 -7
  61. package/generator/src/vite-utils.js +1 -2
  62. package/generator/static-code/elm-pages.js +10 -0
  63. package/generator/static-code/hmr.js +79 -13
  64. package/generator/template/app/Api.elm +3 -2
  65. package/generator/template/app/Effect.elm +155 -0
  66. package/generator/template/app/ErrorPage.elm +49 -6
  67. package/generator/template/app/Route/Blog/Slug_.elm +86 -0
  68. package/generator/template/app/Route/Greet.elm +107 -0
  69. package/generator/template/app/Route/Hello.elm +119 -0
  70. package/generator/template/app/Route/Index.elm +26 -25
  71. package/generator/template/app/Shared.elm +38 -39
  72. package/generator/template/app/Site.elm +4 -7
  73. package/generator/template/app/View.elm +9 -8
  74. package/generator/template/codegen/elm.codegen.json +18 -0
  75. package/generator/template/custom-backend-task.ts +3 -0
  76. package/generator/template/elm-pages.config.mjs +13 -0
  77. package/generator/template/elm-tooling.json +0 -3
  78. package/generator/template/elm.json +25 -20
  79. package/generator/template/index.ts +1 -2
  80. package/generator/template/netlify.toml +4 -1
  81. package/generator/template/package.json +10 -4
  82. package/generator/template/script/.elm-pages/compiled-ports/custom-backend-task.mjs +7 -0
  83. package/generator/template/script/custom-backend-task.ts +3 -0
  84. package/generator/template/script/elm.json +61 -0
  85. package/generator/template/script/src/AddRoute.elm +312 -0
  86. package/generator/template/script/src/Stars.elm +42 -0
  87. package/package.json +30 -27
  88. package/src/ApiRoute.elm +249 -85
  89. package/src/BackendTask/Custom.elm +325 -0
  90. package/src/BackendTask/Env.elm +90 -0
  91. package/src/{DataSource → BackendTask}/File.elm +171 -56
  92. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  93. package/src/BackendTask/Http.elm +679 -0
  94. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  95. package/src/BackendTask/Internal/Request.elm +69 -0
  96. package/src/BackendTask/Random.elm +79 -0
  97. package/src/BackendTask/Time.elm +47 -0
  98. package/src/BackendTask.elm +531 -0
  99. package/src/FatalError.elm +90 -0
  100. package/src/FormData.elm +21 -18
  101. package/src/Head/Seo.elm +4 -4
  102. package/src/Head.elm +237 -7
  103. package/src/Internal/ApiRoute.elm +7 -5
  104. package/src/Internal/Request.elm +84 -4
  105. package/src/PageServerResponse.elm +6 -1
  106. package/src/Pages/ConcurrentSubmission.elm +127 -0
  107. package/src/Pages/Form.elm +340 -0
  108. package/src/Pages/FormData.elm +19 -0
  109. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  110. package/src/Pages/Internal/FatalError.elm +5 -0
  111. package/src/Pages/Internal/Msg.elm +93 -0
  112. package/src/Pages/Internal/NotFoundReason.elm +4 -4
  113. package/src/Pages/Internal/Platform/Cli.elm +629 -767
  114. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  115. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  116. package/src/Pages/Internal/Platform/GeneratorApplication.elm +379 -0
  117. package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
  118. package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
  119. package/src/Pages/Internal/Platform.elm +330 -203
  120. package/src/Pages/Internal/ResponseSketch.elm +2 -2
  121. package/src/Pages/Internal/Script.elm +17 -0
  122. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  123. package/src/Pages/Manifest.elm +52 -11
  124. package/src/Pages/Navigation.elm +85 -0
  125. package/src/Pages/PageUrl.elm +26 -12
  126. package/src/Pages/ProgramConfig.elm +32 -22
  127. package/src/Pages/Script.elm +166 -0
  128. package/src/Pages/SiteConfig.elm +3 -2
  129. package/src/Pages/StaticHttp/Request.elm +2 -2
  130. package/src/Pages/StaticHttpRequest.elm +23 -99
  131. package/src/Pages/Url.elm +3 -3
  132. package/src/PagesMsg.elm +88 -0
  133. package/src/QueryParams.elm +21 -172
  134. package/src/RenderRequest.elm +7 -7
  135. package/src/RequestsAndPending.elm +37 -20
  136. package/src/Result/Extra.elm +26 -0
  137. package/src/Scaffold/Form.elm +569 -0
  138. package/src/Scaffold/Route.elm +1431 -0
  139. package/src/Server/Request.elm +476 -1001
  140. package/src/Server/Response.elm +130 -36
  141. package/src/Server/Session.elm +181 -111
  142. package/src/Server/SetCookie.elm +80 -32
  143. package/src/Stub.elm +53 -0
  144. package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
  145. package/src/{Path.elm → UrlPath.elm} +33 -36
  146. package/generator/template/public/images/icon-png.png +0 -0
  147. package/src/DataSource/Env.elm +0 -38
  148. package/src/DataSource/Http.elm +0 -446
  149. package/src/DataSource/Internal/Request.elm +0 -20
  150. package/src/DataSource/Port.elm +0 -90
  151. package/src/DataSource.elm +0 -538
  152. package/src/Form/Field.elm +0 -717
  153. package/src/Form/FieldStatus.elm +0 -36
  154. package/src/Form/FieldView.elm +0 -417
  155. package/src/Form/FormData.elm +0 -22
  156. package/src/Form/Validation.elm +0 -391
  157. package/src/Form/Value.elm +0 -118
  158. package/src/Form.elm +0 -1683
  159. package/src/FormDecoder.elm +0 -102
  160. package/src/Pages/FormState.elm +0 -256
  161. package/src/Pages/Generate.elm +0 -1151
  162. package/src/Pages/Internal/Form.elm +0 -17
  163. package/src/Pages/Msg.elm +0 -79
  164. package/src/Pages/Transition.elm +0 -70
@@ -1,67 +1,221 @@
1
1
  // @ts-check
2
2
 
3
- const path = require("path");
4
- const mm = require("micromatch");
5
- const matter = require("gray-matter");
6
- const globby = require("globby");
7
- const fsPromises = require("fs").promises;
8
- const preRenderHtml = require("./pre-render-html.js");
9
- const { lookupOrPerform } = require("./request-cache.js");
10
- const kleur = require("kleur");
11
- const cookie = require("cookie-signature");
12
- kleur.enabled = true;
3
+ import * as path from "node:path";
4
+ import { default as mm } from "micromatch";
5
+ import { default as matter } from "gray-matter";
6
+ import * as globby from "globby";
7
+ import * as fsPromises from "node:fs/promises";
8
+ import * as preRenderHtml from "./pre-render-html.js";
9
+ import { lookupOrPerform } from "./request-cache.js";
10
+ import * as kleur from "kleur/colors";
11
+ import * as cookie from "cookie-signature";
12
+ import { compatibilityKey } from "./compatibility-key.js";
13
+ import * as fs from "node:fs";
14
+ import * as crypto from "node:crypto";
15
+ import { restoreColorSafe } from "./error-formatter.js";
13
16
 
14
17
  process.on("unhandledRejection", (error) => {
15
18
  console.error(error);
16
19
  });
17
20
  let foundErrors;
18
- let pendingDataSourceResponses;
19
- let pendingDataSourceCount;
20
21
 
21
- module.exports =
22
- /**
23
- *
24
- * @param {string} basePath
25
- * @param {Object} elmModule
26
- * @param {string} path
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
28
- * @param {(pattern: string) => void} addDataSourceWatcher
29
- * @param {boolean} hasFsAccess
30
- * @returns
31
- */
32
- async function run(
22
+ /**
23
+ *
24
+ * @param {string} basePath
25
+ * @param {Object} elmModule
26
+ * @param {string} path
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
28
+ * @param {(pattern: string) => void} addBackendTaskWatcher
29
+ * @param {boolean} hasFsAccess
30
+ * @returns
31
+ */
32
+ export async function render(
33
+ portsFile,
34
+ basePath,
35
+ elmModule,
36
+ mode,
37
+ path,
38
+ request,
39
+ addBackendTaskWatcher,
40
+ hasFsAccess
41
+ ) {
42
+ // const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(hasFsAccess);
43
+ // resetInMemoryFs();
44
+ foundErrors = false;
45
+ // since init/update are never called in pre-renders, and BackendTask.Http is called using pure NodeJS HTTP fetching
46
+ // we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
47
+ global.XMLHttpRequest = {};
48
+ const result = await runElmApp(
33
49
  portsFile,
34
50
  basePath,
35
51
  elmModule,
36
52
  mode,
37
53
  path,
38
54
  request,
39
- addDataSourceWatcher,
55
+ addBackendTaskWatcher,
40
56
  hasFsAccess
41
- ) {
42
- const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(
43
- hasFsAccess
44
- );
45
- resetInMemoryFs();
46
- foundErrors = false;
47
- pendingDataSourceResponses = [];
48
- pendingDataSourceCount = 0;
49
- // since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
50
- // we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
51
- XMLHttpRequest = {};
52
- const result = await runElmApp(
57
+ );
58
+ return result;
59
+ }
60
+
61
+ /**
62
+ * @param {Object} elmModule
63
+ * @returns
64
+ * @param {string[]} cliOptions
65
+ * @param {any} portsFile
66
+ * @param {string} scriptModuleName
67
+ */
68
+ export async function runGenerator(
69
+ cliOptions,
70
+ portsFile,
71
+ elmModule,
72
+ scriptModuleName
73
+ ) {
74
+ global.isRunningGenerator = true;
75
+ // const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(true);
76
+ // resetInMemoryFs();
77
+ foundErrors = false;
78
+ // since init/update are never called in pre-renders, and BackendTask.Http is called using pure NodeJS HTTP fetching
79
+ // we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
80
+ global.XMLHttpRequest = {};
81
+ try {
82
+ const result = await runGeneratorAppHelp(
83
+ cliOptions,
53
84
  portsFile,
54
- basePath,
85
+ "",
55
86
  elmModule,
56
- mode,
57
- path,
58
- request,
59
- addDataSourceWatcher,
60
- fs,
61
- hasFsAccess
87
+ scriptModuleName,
88
+ "production",
89
+ "",
90
+ true
62
91
  );
63
92
  return result;
64
- };
93
+ } catch (error) {
94
+ process.exitCode = 1;
95
+ console.log(restoreColorSafe(error));
96
+ }
97
+ }
98
+ /**
99
+ * @param {string} basePath
100
+ * @param {Object} elmModule
101
+ * @param {string} pagePath
102
+ * @param {string} mode
103
+ * @returns {Promise<({is404: boolean;} & ({kind: 'json';contentJson: string;} | {kind: 'html';htmlString: string;} | {kind: 'api-response';body: string;}))>}
104
+ * @param {string[]} cliOptions
105
+ * @param {any} portsFile
106
+ * @param {typeof import("fs") | import("memfs").IFs} fs
107
+ * @param {boolean} hasFsAccess
108
+ * @param {string} scriptModuleName
109
+ */
110
+ function runGeneratorAppHelp(
111
+ cliOptions,
112
+ portsFile,
113
+ basePath,
114
+ elmModule,
115
+ scriptModuleName,
116
+ mode,
117
+ pagePath,
118
+ hasFsAccess
119
+ ) {
120
+ const isDevServer = mode !== "build";
121
+ let patternsToWatch = new Set();
122
+ let app = null;
123
+ let killApp;
124
+ return new Promise((resolve, reject) => {
125
+ const isBytes = pagePath.match(/content\.dat\/?$/);
126
+
127
+ app = elmModule.Elm.Main.init({
128
+ flags: {
129
+ compatibilityKey,
130
+ argv: ["", `elm-pages run ${scriptModuleName}`, ...cliOptions],
131
+ versionMessage: "1.2.3",
132
+ },
133
+ });
134
+
135
+ killApp = () => {
136
+ app.ports.toJsPort.unsubscribe(portHandler);
137
+ app.die();
138
+ app = null;
139
+ // delete require.cache[require.resolve(compiledElmPath)];
140
+ };
141
+
142
+ async function portHandler(/** @type { FromElm } */ newThing) {
143
+ let fromElm;
144
+ let contentDatPayload;
145
+
146
+ fromElm = newThing;
147
+ if (fromElm.command === "log") {
148
+ console.log(fromElm.value);
149
+ } else if (fromElm.tag === "ApiResponse") {
150
+ // Finished successfully
151
+ process.exit(0);
152
+ } else if (fromElm.tag === "PageProgress") {
153
+ const args = fromElm.args[0];
154
+
155
+ if (isBytes) {
156
+ resolve({
157
+ kind: "bytes",
158
+ is404: false,
159
+ contentJson: JSON.stringify({
160
+ staticData: args.contentJson,
161
+ is404: false,
162
+ }),
163
+ statusCode: args.statusCode,
164
+ headers: args.headers,
165
+ contentDatPayload,
166
+ });
167
+ } else {
168
+ resolve(
169
+ outputString(basePath, fromElm, isDevServer, contentDatPayload)
170
+ );
171
+ }
172
+ } else if (fromElm.tag === "DoHttp") {
173
+ app.ports.gotBatchSub.send(
174
+ Object.fromEntries(
175
+ await Promise.all(
176
+ fromElm.args[0].map(([requestHash, requestToPerform]) => {
177
+ if (
178
+ requestToPerform.url !== "elm-pages-internal://port" &&
179
+ requestToPerform.url.startsWith("elm-pages-internal://")
180
+ ) {
181
+ return runInternalJob(
182
+ requestHash,
183
+ app,
184
+ mode,
185
+ requestToPerform,
186
+ hasFsAccess,
187
+ patternsToWatch
188
+ );
189
+ } else {
190
+ return runHttpJob(
191
+ requestHash,
192
+ portsFile,
193
+ app,
194
+ mode,
195
+ requestToPerform,
196
+ hasFsAccess,
197
+ requestToPerform
198
+ );
199
+ }
200
+ })
201
+ )
202
+ )
203
+ );
204
+ } else if (fromElm.tag === "Errors") {
205
+ foundErrors = true;
206
+ reject(fromElm.args[0].errorsJson);
207
+ } else {
208
+ console.log(fromElm);
209
+ }
210
+ }
211
+ app.ports.toJsPort.subscribe(portHandler);
212
+ }).finally(() => {
213
+ try {
214
+ killApp();
215
+ killApp = null;
216
+ } catch (error) {}
217
+ });
218
+ }
65
219
 
66
220
  /**
67
221
  * @param {string} basePath
@@ -69,7 +223,7 @@ module.exports =
69
223
  * @param {string} pagePath
70
224
  * @param {string} mode
71
225
  * @param {{ method: string; hostname: string; query: string; headers: Object; host: string; pathname: string; port: string; protocol: string; rawUrl: string; }} request
72
- * @param {(pattern: string) => void} addDataSourceWatcher
226
+ * @param {(pattern: string) => void} addBackendTaskWatcher
73
227
  * @returns {Promise<({is404: boolean} & ( { kind: 'json'; contentJson: string} | { kind: 'html'; htmlString: string } | { kind: 'api-response'; body: string; }) )>}
74
228
  */
75
229
  function runElmApp(
@@ -79,8 +233,7 @@ function runElmApp(
79
233
  mode,
80
234
  pagePath,
81
235
  request,
82
- addDataSourceWatcher,
83
- fs,
236
+ addBackendTaskWatcher,
84
237
  hasFsAccess
85
238
  ) {
86
239
  const isDevServer = mode !== "build";
@@ -94,10 +247,10 @@ function runElmApp(
94
247
  .replace(/content\.dat\/?$/, "");
95
248
 
96
249
  const modifiedRequest = { ...request, path: route };
97
- // console.log("StaticHttp cache keys", Object.keys(global.staticHttpCache));
98
250
  app = elmModule.Elm.Main.init({
99
251
  flags: {
100
252
  mode,
253
+ compatibilityKey,
101
254
  request: {
102
255
  payload: modifiedRequest,
103
256
  kind: "single-page",
@@ -127,9 +280,6 @@ function runElmApp(
127
280
  console.log(fromElm.value);
128
281
  } else if (fromElm.tag === "ApiResponse") {
129
282
  const args = fromElm.args[0];
130
- if (mode === "build") {
131
- global.staticHttpCache = args.staticHttpCache;
132
- }
133
283
 
134
284
  resolve({
135
285
  kind: "api-response",
@@ -139,10 +289,6 @@ function runElmApp(
139
289
  });
140
290
  } else if (fromElm.tag === "PageProgress") {
141
291
  const args = fromElm.args[0];
142
- if (mode === "build") {
143
- global.staticHttpCache = args.staticHttpCache;
144
- }
145
-
146
292
  if (isBytes) {
147
293
  resolve({
148
294
  kind: "bytes",
@@ -161,30 +307,37 @@ function runElmApp(
161
307
  );
162
308
  }
163
309
  } else if (fromElm.tag === "DoHttp") {
164
- const requestToPerform = fromElm.args[0];
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
- }
310
+ app.ports.gotBatchSub.send(
311
+ Object.fromEntries(
312
+ await Promise.all(
313
+ fromElm.args[0].map(([requestHash, requestToPerform]) => {
314
+ if (
315
+ requestToPerform.url !== "elm-pages-internal://port" &&
316
+ requestToPerform.url.startsWith("elm-pages-internal://")
317
+ ) {
318
+ return runInternalJob(
319
+ requestHash,
320
+ app,
321
+ mode,
322
+ requestToPerform,
323
+ hasFsAccess,
324
+ patternsToWatch
325
+ );
326
+ } else {
327
+ return runHttpJob(
328
+ requestHash,
329
+ portsFile,
330
+ app,
331
+ mode,
332
+ requestToPerform,
333
+ hasFsAccess,
334
+ requestToPerform
335
+ );
336
+ }
337
+ })
338
+ )
339
+ )
340
+ );
188
341
  } else if (fromElm.tag === "Errors") {
189
342
  foundErrors = true;
190
343
  reject(fromElm.args[0].errorsJson);
@@ -195,7 +348,7 @@ function runElmApp(
195
348
  app.ports.toJsPort.subscribe(portHandler);
196
349
  app.ports.sendPageData.subscribe(portHandler);
197
350
  }).finally(() => {
198
- addDataSourceWatcher(patternsToWatch);
351
+ addBackendTaskWatcher(patternsToWatch);
199
352
  try {
200
353
  killApp();
201
354
  killApp = null;
@@ -244,17 +397,16 @@ async function outputString(
244
397
  /** @typedef { { head: any[]; errors: any[]; contentJson: any[]; html: string; route: string; title: string; } } Arg */
245
398
 
246
399
  async function runHttpJob(
400
+ requestHash,
247
401
  portsFile,
248
402
  app,
249
403
  mode,
250
404
  requestToPerform,
251
- fs,
252
405
  hasFsAccess,
253
406
  useCache
254
407
  ) {
255
- pendingDataSourceCount += 1;
256
408
  try {
257
- const responseFilePath = await lookupOrPerform(
409
+ const lookupResponse = await lookupOrPerform(
258
410
  portsFile,
259
411
  mode,
260
412
  requestToPerform,
@@ -262,17 +414,31 @@ async function runHttpJob(
262
414
  useCache
263
415
  );
264
416
 
265
- pendingDataSourceResponses.push({
266
- request: requestToPerform,
267
- response: JSON.parse(
268
- (await fs.promises.readFile(responseFilePath, "utf8")).toString()
269
- ),
270
- });
417
+ if (lookupResponse.kind === "cache-response-path") {
418
+ const responseFilePath = lookupResponse.value;
419
+ return [
420
+ requestHash,
421
+ {
422
+ request: requestToPerform,
423
+ response: JSON.parse(
424
+ (await fs.promises.readFile(responseFilePath, "utf8")).toString()
425
+ ),
426
+ },
427
+ ];
428
+ } else if (lookupResponse.kind === "response-json") {
429
+ return [
430
+ requestHash,
431
+ {
432
+ request: requestToPerform,
433
+ response: lookupResponse.value,
434
+ },
435
+ ];
436
+ } else {
437
+ throw `Unexpected kind ${lookupResponse}`;
438
+ }
271
439
  } catch (error) {
272
- sendError(app, error);
273
- } finally {
274
- pendingDataSourceCount -= 1;
275
- flushIfDone(app);
440
+ console.log("@@@ERROR", error);
441
+ // sendError(app, error);
276
442
  }
277
443
  }
278
444
 
@@ -290,46 +456,54 @@ function jsonResponse(request, json) {
290
456
  }
291
457
 
292
458
  async function runInternalJob(
459
+ requestHash,
293
460
  app,
294
461
  mode,
295
462
  requestToPerform,
296
- fs,
297
463
  hasFsAccess,
298
464
  patternsToWatch
299
465
  ) {
300
466
  try {
301
- pendingDataSourceCount += 1;
302
-
303
- if (requestToPerform.url === "elm-pages-internal://read-file") {
304
- pendingDataSourceResponses.push(
305
- await readFileJobNew(requestToPerform, patternsToWatch)
306
- );
467
+ if (requestToPerform.url === "elm-pages-internal://log") {
468
+ return [requestHash, await runLogJob(requestToPerform)];
469
+ } else if (requestToPerform.url === "elm-pages-internal://read-file") {
470
+ return [
471
+ requestHash,
472
+ await readFileJobNew(requestToPerform, patternsToWatch),
473
+ ];
307
474
  } else if (requestToPerform.url === "elm-pages-internal://glob") {
308
- pendingDataSourceResponses.push(
309
- await runGlobNew(requestToPerform, patternsToWatch)
310
- );
475
+ return [requestHash, await runGlobNew(requestToPerform, patternsToWatch)];
476
+ } else if (requestToPerform.url === "elm-pages-internal://randomSeed") {
477
+ return [
478
+ requestHash,
479
+ jsonResponse(
480
+ requestToPerform,
481
+ crypto.getRandomValues(new Uint32Array(1))[0]
482
+ ),
483
+ ];
484
+ } else if (requestToPerform.url === "elm-pages-internal://now") {
485
+ return [requestHash, jsonResponse(requestToPerform, Date.now())];
311
486
  } else if (requestToPerform.url === "elm-pages-internal://env") {
312
- pendingDataSourceResponses.push(
313
- await runEnvJob(requestToPerform, patternsToWatch)
314
- );
487
+ return [requestHash, await runEnvJob(requestToPerform, patternsToWatch)];
315
488
  } else if (requestToPerform.url === "elm-pages-internal://encrypt") {
316
- pendingDataSourceResponses.push(
317
- await runEncryptJob(requestToPerform, patternsToWatch)
318
- );
489
+ return [
490
+ requestHash,
491
+ await runEncryptJob(requestToPerform, patternsToWatch),
492
+ ];
319
493
  } else if (requestToPerform.url === "elm-pages-internal://decrypt") {
320
- pendingDataSourceResponses.push(
321
- await runDecryptJob(requestToPerform, patternsToWatch)
322
- );
494
+ return [
495
+ requestHash,
496
+ await runDecryptJob(requestToPerform, patternsToWatch),
497
+ ];
498
+ } else if (requestToPerform.url === "elm-pages-internal://write-file") {
499
+ return [requestHash, await runWriteFileJob(requestToPerform)];
323
500
  } else {
324
- throw `Unexpected internal DataSource request format: ${kleur.yellow(
501
+ throw `Unexpected internal BackendTask request format: ${kleur.yellow(
325
502
  JSON.stringify(2, null, requestToPerform)
326
503
  )}`;
327
504
  }
328
505
  } catch (error) {
329
506
  sendError(app, error);
330
- } finally {
331
- pendingDataSourceCount -= 1;
332
- flushIfDone(app);
333
507
  }
334
508
  }
335
509
 
@@ -344,6 +518,7 @@ async function readFileJobNew(req, patternsToWatch) {
344
518
  path.join(process.env.LAMBDA_TASK_ROOT || process.cwd(), filePath)
345
519
  )
346
520
  ).toString();
521
+ // TODO does this throw an error if there is invalid frontmatter?
347
522
  const parsedFile = matter(fileContents);
348
523
 
349
524
  return jsonResponse(req, {
@@ -352,10 +527,24 @@ async function readFileJobNew(req, patternsToWatch) {
352
527
  rawFile: fileContents,
353
528
  });
354
529
  } catch (error) {
530
+ return jsonResponse(req, {
531
+ errorCode: error.code,
532
+ });
533
+ }
534
+ }
535
+ async function runWriteFileJob(req) {
536
+ const data = req.body.args[0];
537
+ try {
538
+ const fullPathToWrite = path.join(process.cwd(), data.path);
539
+ await fsPromises.mkdir(path.dirname(fullPathToWrite), { recursive: true });
540
+ await fsPromises.writeFile(fullPathToWrite, data.body);
541
+ return jsonResponse(req, null);
542
+ } catch (error) {
543
+ console.trace(error);
355
544
  throw {
356
- title: "DataSource.File Error",
357
- message: `A DataSource.File read failed because I couldn't find this file: ${kleur.yellow(
358
- filePath
545
+ title: "BackendTask Error",
546
+ message: `BackendTask.Generator.writeFile failed for file path: ${kleur.yellow(
547
+ data.path
359
548
  )}\n${kleur.red(error.toString())}`,
360
549
  };
361
550
  }
@@ -364,7 +553,7 @@ async function readFileJobNew(req, patternsToWatch) {
364
553
  async function runGlobNew(req, patternsToWatch) {
365
554
  try {
366
555
  const { pattern, options } = req.body.args[0];
367
- const matchedPaths = await globby(pattern, options);
556
+ const matchedPaths = await globby.globby(pattern, options);
368
557
  patternsToWatch.add(pattern);
369
558
 
370
559
  return jsonResponse(
@@ -382,6 +571,15 @@ async function runGlobNew(req, patternsToWatch) {
382
571
  }
383
572
  }
384
573
 
574
+ async function runLogJob(req) {
575
+ try {
576
+ console.log(req.body.args[0].message);
577
+ return jsonResponse(req, null);
578
+ } catch (e) {
579
+ console.log(`Error performing env '${JSON.stringify(req.body)}'`);
580
+ throw e;
581
+ }
582
+ }
385
583
  async function runEnvJob(req, patternsToWatch) {
386
584
  try {
387
585
  const expectedEnv = req.body.args[0];
@@ -402,7 +600,7 @@ async function runEncryptJob(req, patternsToWatch) {
402
600
  );
403
601
  } catch (e) {
404
602
  throw {
405
- title: "DataSource Encrypt Error",
603
+ title: "BackendTask Encrypt Error",
406
604
  message:
407
605
  e.toString() + e.stack + "\n\n" + JSON.stringify(rawRequest, null, 2),
408
606
  };
@@ -419,32 +617,13 @@ async function runDecryptJob(req, patternsToWatch) {
419
617
  return jsonResponse(req, JSON.parse(signed || "null"));
420
618
  } catch (e) {
421
619
  throw {
422
- title: "DataSource Decrypt Error",
620
+ title: "BackendTask Decrypt Error",
423
621
  message:
424
622
  e.toString() + e.stack + "\n\n" + JSON.stringify(rawRequest, null, 2),
425
623
  };
426
624
  }
427
625
  }
428
626
 
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
- // );
436
-
437
- flushQueue(app);
438
- }
439
- }
440
-
441
- function flushQueue(app) {
442
- const temp = pendingDataSourceResponses;
443
- pendingDataSourceResponses = [];
444
- // console.log("@@@ FLUSHING", temp.length);
445
- app.ports.gotBatchSub.send(temp);
446
- }
447
-
448
627
  /**
449
628
  * @param {{ ports: { fromJsPort: { send: (arg0: { tag: string; data: any; }) => void; }; }; }} app
450
629
  * @param {{ message: string; title: string; }} error