elm-pages 3.0.23 → 3.0.25

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/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  - [elm-pages Docs Site](https://elm-pages.com/docs)
13
13
  - [elm-pages site showcase](https://elm-pages.com/showcase/)
14
- - [elm-pages Elm API Docs](https://package.elm-lang.org/packages/dillonkearns/elm-pages/10.2.1/)
14
+ - [elm-pages Elm API Docs](https://package.elm-lang.org/packages/dillonkearns/elm-pages/10.2.2/)
15
15
  - [Quick start repo](https://github.com/dillonkearns/elm-pages-starter) [(live site hosted here)](https://elm-pages-starter.netlify.com)
16
16
  - [Introducing `elm-pages` blog post](https://elm-pages.com/blog/introducing-elm-pages)
17
17
  - [`examples` folder](https://github.com/dillonkearns/elm-pages/blob/master/examples/) (includes https://elm-pages.com site source) Use `git clone --recurse-submodules https://github.com/dillonkearns/elm-pages.git` so that there aren't missing files when you try to build the examples.
@@ -741,7 +741,9 @@ async function runAdapter(adaptFn, processedIndexTemplate) {
741
741
  * @param {string} file
742
742
  */
743
743
  function defaultPreloadForFile(file) {
744
- if (file.endsWith(".js")) {
744
+ if (/\/elm\.[a-f0-9]+\.js$/.test(file)) {
745
+ return `<link rel="preload" as="script" href="${file}">`;
746
+ } else if (file.endsWith(".js")) {
745
747
  return `<link rel="modulepreload" crossorigin href="${file}">`;
746
748
  } else if (file.endsWith(".css")) {
747
749
  return `<link rel="preload" href="${file}" as="style">`;
@@ -162,8 +162,7 @@ async function main() {
162
162
  moduleName
163
163
  );
164
164
  } catch (error) {
165
- console.trace(error);
166
- console.log(restoreColorSafe(error));
165
+ printCaughtError(error);
167
166
  process.exit(1);
168
167
  }
169
168
  });
@@ -283,7 +282,7 @@ await(async()=>{let{dirname:e}=await import("path"),{fileURLToPath:i}=await impo
283
282
  });
284
283
  // await runTerser(path.resolve(cwd, options.output));
285
284
  } catch (error) {
286
- console.log(restoreColorSafe(error));
285
+ printCaughtError(error);
287
286
  process.exit(1);
288
287
  }
289
288
  });
@@ -327,6 +326,17 @@ function safeSubscribe(program, portName, subscribeFunction) {
327
326
  program.ports[portName].subscribe(subscribeFunction);
328
327
  }
329
328
 
329
+ /**
330
+ * @param {Error|string|any[]} error - Thing that was thrown and caught.
331
+ */
332
+ function printCaughtError(error) {
333
+ if (typeof error === "string" || Array.isArray(error)) {
334
+ console.log(restoreColorSafe(error));
335
+ } else {
336
+ console.trace(error);
337
+ }
338
+ }
339
+
330
340
  /**
331
341
  * @param {string} rawPagePath
332
342
  */
@@ -404,7 +414,13 @@ async function compileElmForScript(elmModulePath) {
404
414
  // await codegen.generate("");
405
415
  ensureDirSync(path.join(process.cwd(), ".elm-pages", "http-response-cache"));
406
416
  if (fs.existsSync("./codegen/") && process.env.SKIP_ELM_CODEGEN !== "true") {
407
- await runElmCodegenInstall();
417
+ const result = await runElmCodegenInstall();
418
+ if (!result.success) {
419
+ console.error(`Warning: ${result.message}. This may cause stale generated code or missing module errors.\n`);
420
+ if (result.error) {
421
+ console.error(result.error);
422
+ }
423
+ }
408
424
  }
409
425
 
410
426
  ensureDirSync(`${projectDirectory}/elm-stuff`);
@@ -1,3 +1,3 @@
1
1
  export const compatibilityKey = 22;
2
2
 
3
- export const packageVersion = "3.0.23";
3
+ export const packageVersion = "3.0.25";
@@ -1,35 +1,39 @@
1
1
  import { spawn as spawnCallback } from "cross-spawn";
2
+ import which from "which";
2
3
 
3
- export function runElmCodegenInstall() {
4
- return new Promise(async (resolve, reject) => {
5
- const subprocess = spawnCallback(`elm-codegen`, ["install"], {
6
- // ignore stdout
7
- // stdio: ["inherit", "ignore", "inherit"],
8
- // cwd: cwd,
9
- });
10
- // if (await fsHelpers.fileExists(outputPath)) {
11
- // await fsPromises.unlink(outputPath, {
12
- // force: true /* ignore errors if file doesn't exist */,
13
- // });
14
- // }
15
- let commandOutput = "";
4
+ /**
5
+ * @returns {Promise<{ success: true } | { success: false; message: string; error?: Error }>}
6
+ */
7
+ export async function runElmCodegenInstall() {
8
+ try {
9
+ await which("elm-codegen");
10
+ } catch (error) {
11
+ return { success: false, message: "Unable to find elm-codegen on the PATH" };
12
+ }
16
13
 
14
+ return new Promise((resolve) => {
15
+ const subprocess = spawnCallback("elm-codegen", ["install"]);
16
+
17
+ let commandOutput = "";
17
18
  subprocess.stderr.on("data", function (data) {
18
19
  commandOutput += data;
19
20
  });
20
21
  subprocess.stdout.on("data", function (data) {
21
22
  commandOutput += data;
22
23
  });
23
- subprocess.on("error", function () {
24
- reject(commandOutput);
24
+ subprocess.on("error", function (error) {
25
+ resolve({ success: false, message: "Failed to run elm-codegen", error });
25
26
  });
26
27
 
27
- subprocess.on("close", async (code) => {
28
- if (code == 0) {
29
- resolve();
30
- } else {
31
- reject(commandOutput);
28
+ subprocess.on("close", (code) => {
29
+ if (code === 0) {
30
+ return resolve({ success: true });
32
31
  }
32
+ resolve({
33
+ success: false,
34
+ message: `elm-codegen exited with code ${code}`,
35
+ error: commandOutput.length > 0 ? new Error(commandOutput) : undefined
36
+ });
33
37
  });
34
38
  });
35
39
  }
@@ -107,7 +107,7 @@ export const restoreColor = (error) => {
107
107
  };
108
108
 
109
109
  /**
110
- * @param {string} error
110
+ * @param {string|RootObject[]} error
111
111
  * @returns {string}
112
112
  */
113
113
  export function restoreColorSafe(error) {
@@ -65,8 +65,7 @@ export async function render(
65
65
  mode,
66
66
  path,
67
67
  request,
68
- addBackendTaskWatcher,
69
- hasFsAccess
68
+ addBackendTaskWatcher
70
69
  );
71
70
  return result;
72
71
  }
@@ -102,7 +101,6 @@ export async function runGenerator(
102
101
  scriptModuleName,
103
102
  "production",
104
103
  "",
105
- true,
106
104
  versionMessage
107
105
  );
108
106
  return result;
@@ -120,7 +118,6 @@ export async function runGenerator(
120
118
  * @param {string[]} cliOptions
121
119
  * @param {any} portsFile
122
120
  * @param {typeof import("fs") | import("memfs").IFs} fs
123
- * @param {boolean} hasFsAccess
124
121
  * @param {string} scriptModuleName
125
122
  * @param {string} versionMessage
126
123
  */
@@ -132,7 +129,6 @@ function runGeneratorAppHelp(
132
129
  scriptModuleName,
133
130
  mode,
134
131
  pagePath,
135
- hasFsAccess,
136
132
  versionMessage
137
133
  ) {
138
134
  const isDevServer = mode !== "build";
@@ -155,7 +151,7 @@ function runGeneratorAppHelp(
155
151
  flags: {
156
152
  compatibilityKey,
157
153
  argv: ["", `elm-pages run ${scriptModuleName}`, ...cliOptions],
158
- versionMessage,
154
+ versionMessage: versionMessage || "",
159
155
  },
160
156
  });
161
157
 
@@ -208,9 +204,7 @@ function runGeneratorAppHelp(
208
204
  return runInternalJob(
209
205
  requestHash,
210
206
  app,
211
- mode,
212
207
  requestToPerform,
213
- hasFsAccess,
214
208
  patternsToWatch,
215
209
  portsFile
216
210
  );
@@ -218,10 +212,7 @@ function runGeneratorAppHelp(
218
212
  return runHttpJob(
219
213
  requestHash,
220
214
  portsFile,
221
- app,
222
215
  mode,
223
- requestToPerform,
224
- hasFsAccess,
225
216
  requestToPerform
226
217
  );
227
218
  }
@@ -262,8 +253,7 @@ function runElmApp(
262
253
  mode,
263
254
  pagePath,
264
255
  request,
265
- addBackendTaskWatcher,
266
- hasFsAccess
256
+ addBackendTaskWatcher
267
257
  ) {
268
258
  const isDevServer = mode !== "build";
269
259
  let patternsToWatch = new Set();
@@ -347,9 +337,7 @@ function runElmApp(
347
337
  return runInternalJob(
348
338
  requestHash,
349
339
  app,
350
- mode,
351
340
  requestToPerform,
352
- hasFsAccess,
353
341
  patternsToWatch,
354
342
  portsFile
355
343
  );
@@ -357,10 +345,7 @@ function runElmApp(
357
345
  return runHttpJob(
358
346
  requestHash,
359
347
  portsFile,
360
- app,
361
348
  mode,
362
- requestToPerform,
363
- hasFsAccess,
364
349
  requestToPerform
365
350
  );
366
351
  }
@@ -430,19 +415,14 @@ async function outputString(
430
415
  async function runHttpJob(
431
416
  requestHash,
432
417
  portsFile,
433
- app,
434
418
  mode,
435
419
  requestToPerform,
436
- hasFsAccess,
437
- useCache
438
420
  ) {
439
421
  try {
440
422
  const lookupResponse = await lookupOrPerform(
441
423
  portsFile,
442
424
  mode,
443
- requestToPerform,
444
- hasFsAccess,
445
- useCache
425
+ requestToPerform
446
426
  );
447
427
 
448
428
  if (lookupResponse.kind === "cache-response-path") {
@@ -485,13 +465,27 @@ function jsonResponse(request, json) {
485
465
  response: { bodyKind: "json", body: json },
486
466
  };
487
467
  }
468
+ /**
469
+ * @param {any} request
470
+ * @param {WithImplicitCoercion<ArrayBuffer | SharedArrayBuffer>} buffer
471
+ */
472
+ function bytesResponse(request, buffer) {
473
+ return {
474
+ request,
475
+ response: {
476
+ bodyKind: "bytes",
477
+ body: Buffer.from(buffer).toString("base64"),
478
+ },
479
+ };
480
+ }
488
481
 
482
+ /**
483
+ * @param {{ url: string; body: { args: any[] } }} requestToPerform
484
+ */
489
485
  async function runInternalJob(
490
486
  requestHash,
491
487
  app,
492
- mode,
493
488
  requestToPerform,
494
- hasFsAccess,
495
489
  patternsToWatch,
496
490
  portsFile
497
491
  ) {
@@ -509,6 +503,11 @@ async function runInternalJob(
509
503
  requestHash,
510
504
  await readFileJobNew(requestToPerform, patternsToWatch, context),
511
505
  ];
506
+ case "elm-pages-internal://read-file-binary":
507
+ return [
508
+ requestHash,
509
+ await readFileBinaryJobNew(requestToPerform, patternsToWatch),
510
+ ];
512
511
  case "elm-pages-internal://glob":
513
512
  return [
514
513
  requestHash,
@@ -590,6 +589,34 @@ async function readFileJobNew(req, patternsToWatch, { cwd }) {
590
589
  }
591
590
  }
592
591
 
592
+ /**
593
+ * @param {{ url: string; body: { args: any[] } }} req
594
+ * @param {{ add: (arg0: string) => void; }} patternsToWatch
595
+ */
596
+ async function readFileBinaryJobNew(req, patternsToWatch) {
597
+ const filePath = req.body.args[1];
598
+ try {
599
+ patternsToWatch.add(filePath);
600
+
601
+ const fileContents = await fsPromises.readFile(filePath);
602
+ // It's safe to use allocUnsafe here because we're going to overwrite it immediately anyway
603
+ const buffer = new Uint8Array(4 + fileContents.length);
604
+ const view = new DataView(
605
+ buffer.buffer,
606
+ buffer.byteOffset,
607
+ buffer.byteLength
608
+ );
609
+ view.setInt32(0, fileContents.length);
610
+ fileContents.copy(buffer, 4);
611
+
612
+ return bytesResponse(req, buffer);
613
+ } catch (error) {
614
+ const buffer = new Int32Array(1);
615
+ buffer[0] = -1;
616
+ return bytesResponse(req, buffer);
617
+ }
618
+ }
619
+
593
620
  function runSleep(req) {
594
621
  const { milliseconds } = req.body.args[0];
595
622
  return new Promise((resolve) => {
@@ -11,15 +11,12 @@ const defaultHttpCachePath = "./.elm-pages/http-cache";
11
11
  * @param {string} mode
12
12
  * @param {{url: string;headers: {[x: string]: string;};method: string;body: Body; }} rawRequest
13
13
  * @param {Record<string, unknown>} portsFile
14
- * @param {boolean} hasFsAccess
15
14
  * @returns {Promise<Response>}
16
15
  */
17
16
  export function lookupOrPerform(
18
17
  portsFile,
19
18
  mode,
20
- rawRequest,
21
- hasFsAccess,
22
- useCache
19
+ rawRequest
23
20
  ) {
24
21
  const uniqueTimeId =
25
22
  Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
@@ -14,7 +14,7 @@
14
14
  "dillonkearns/elm-bcp47-language-tag": "2.0.0",
15
15
  "dillonkearns/elm-form": "3.0.1",
16
16
  "dillonkearns/elm-markdown": "7.0.1",
17
- "dillonkearns/elm-pages": "10.2.1",
17
+ "dillonkearns/elm-pages": "10.2.2",
18
18
  "elm/browser": "1.0.2",
19
19
  "elm/bytes": "1.0.8",
20
20
  "elm/core": "1.0.5",
@@ -9,7 +9,7 @@
9
9
  "devDependencies": {
10
10
  "elm-codegen": "^0.6.1",
11
11
  "elm-optimize-level-2": "^0.3.5",
12
- "elm-pages": "3.0.23",
12
+ "elm-pages": "3.0.24",
13
13
  "elm-review": "^2.12.0",
14
14
  "elm-tooling": "^1.15.1",
15
15
  "lamdera": "^0.19.1-1.3.2",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elm-pages",
3
3
  "type": "module",
4
- "version": "3.0.23",
4
+ "version": "3.0.25",
5
5
  "homepage": "https://elm-pages.com",
6
6
  "moduleResolution": "node",
7
7
  "description": "Hybrid Elm framework with full-stack and static routes.",
@@ -126,6 +126,7 @@ import Date
126
126
  import FatalError exposing (FatalError)
127
127
  import Json.Decode as Decode exposing (Decoder)
128
128
  import Json.Encode as Encode
129
+ import Pages.StaticHttpRequest
129
130
  import TerminalText
130
131
  import Time
131
132
 
@@ -331,7 +332,6 @@ request :
331
332
  }
332
333
  -> BackendTask { fatal : FatalError, recoverable : Error } a
333
334
  request { body, expect } =
334
- -- elm-review: known-unoptimized-recursion
335
335
  BackendTask.Http.request
336
336
  { url = "elm-pages-internal://port"
337
337
  , method = "GET"
@@ -343,8 +343,6 @@ request { body, expect } =
343
343
  expect
344
344
  |> BackendTask.onError
345
345
  (\error ->
346
- -- TODO avoid crash here, this should be handled as an internal error
347
- --request params
348
346
  case error.recoverable of
349
347
  BackendTask.Http.BadBody (Just jsonError) _ ->
350
348
  { recoverable = DecodeError jsonError
@@ -353,8 +351,5 @@ request { body, expect } =
353
351
  |> BackendTask.fail
354
352
 
355
353
  _ ->
356
- { recoverable = Error
357
- , fatal = error.fatal
358
- }
359
- |> BackendTask.fail
354
+ Pages.StaticHttpRequest.InternalError error.fatal
360
355
  )
@@ -1,6 +1,6 @@
1
1
  module BackendTask.File exposing
2
2
  ( bodyWithFrontmatter, bodyWithoutFrontmatter, onlyFrontmatter
3
- , jsonFile, rawFile
3
+ , jsonFile, rawFile, binaryFile
4
4
  , FileReadError(..)
5
5
  )
6
6
 
@@ -40,7 +40,7 @@ plain old JSON in Elm.
40
40
 
41
41
  ## Reading Files Without Frontmatter
42
42
 
43
- @docs jsonFile, rawFile
43
+ @docs jsonFile, rawFile, binaryFile
44
44
 
45
45
 
46
46
  ## FatalErrors
@@ -52,6 +52,8 @@ plain old JSON in Elm.
52
52
  import BackendTask exposing (BackendTask)
53
53
  import BackendTask.Http
54
54
  import BackendTask.Internal.Request
55
+ import Bytes exposing (Bytes)
56
+ import Bytes.Decode
55
57
  import FatalError exposing (FatalError)
56
58
  import Json.Decode as Decode exposing (Decoder)
57
59
  import TerminalText
@@ -337,6 +339,39 @@ rawFile filePath =
337
339
  read filePath (Decode.field "rawFile" Decode.string)
338
340
 
339
341
 
342
+ {-| Get the raw file content as `Bytes`.
343
+
344
+ You could read a file called `hello.jpg` in your root project directory like this:
345
+
346
+ import BackendTask exposing (BackendTask)
347
+ import BackendTask.File as File
348
+ import Bytes exposing (Bytes)
349
+
350
+ elmBinaryFile : BackendTask Bytes
351
+ elmBinaryFile =
352
+ File.binaryFile "hello.jpg"
353
+
354
+ -}
355
+ binaryFile : String -> BackendTask { fatal : FatalError, recoverable : FileReadError decoderError } Bytes
356
+ binaryFile filePath =
357
+ BackendTask.Internal.Request.request
358
+ { name = "read-file-binary"
359
+ , body = BackendTask.Http.stringBody "" filePath
360
+ , expect =
361
+ Bytes.Decode.signedInt32 Bytes.BE
362
+ |> Bytes.Decode.andThen
363
+ (\length ->
364
+ if length < 0 then
365
+ Bytes.Decode.fail
366
+
367
+ else
368
+ Bytes.Decode.bytes length
369
+ )
370
+ |> BackendTask.Http.expectBytes
371
+ }
372
+ |> BackendTask.mapError (\_ -> fileNotFound filePath)
373
+
374
+
340
375
  {-| Read a file as JSON.
341
376
 
342
377
  The Decode will strip off any unused JSON data.
@@ -410,23 +445,25 @@ read filePath decoder =
410
445
  |> BackendTask.andThen BackendTask.fromResult
411
446
 
412
447
 
413
- errorDecoder :
448
+ errorDecoder : String -> Decoder { fatal : FatalError, recoverable : FileReadError decoding }
449
+ errorDecoder filePath =
450
+ Decode.succeed (fileNotFound filePath)
451
+
452
+
453
+ fileNotFound :
414
454
  String
415
455
  ->
416
- Decoder
417
- { fatal : FatalError
418
- , recoverable : FileReadError decoding
419
- }
420
- errorDecoder filePath =
421
- Decode.succeed
422
- (FatalError.recoverable
423
- { title = "File Doesn't Exist"
424
- , body =
425
- [ TerminalText.text "Couldn't find file at path `"
426
- , TerminalText.yellow filePath
427
- , TerminalText.text "`"
428
- ]
429
- |> TerminalText.toString
430
- }
431
- FileDoesntExist
432
- )
456
+ { fatal : FatalError
457
+ , recoverable : FileReadError decoding
458
+ }
459
+ fileNotFound filePath =
460
+ FatalError.recoverable
461
+ { title = "File Doesn't Exist"
462
+ , body =
463
+ [ TerminalText.text "Couldn't find file at path `"
464
+ , TerminalText.yellow filePath
465
+ , TerminalText.text "`"
466
+ ]
467
+ |> TerminalText.toString
468
+ }
469
+ FileDoesntExist
@@ -4,6 +4,7 @@ import BackendTask exposing (BackendTask)
4
4
  import BackendTask.Http exposing (Body, Expect)
5
5
  import Json.Decode exposing (Decoder)
6
6
  import Json.Encode as Encode
7
+ import Pages.StaticHttpRequest
7
8
 
8
9
 
9
10
  request :
@@ -12,8 +13,7 @@ request :
12
13
  , expect : Expect a
13
14
  }
14
15
  -> BackendTask error a
15
- request ({ name, body, expect } as params) =
16
- -- elm-review: known-unoptimized-recursion
16
+ request { name, body, expect } =
17
17
  BackendTask.Http.request
18
18
  { url = "elm-pages-internal://" ++ name
19
19
  , method = "GET"
@@ -24,9 +24,8 @@ request ({ name, body, expect } as params) =
24
24
  }
25
25
  expect
26
26
  |> BackendTask.onError
27
- (\_ ->
28
- -- TODO avoid crash here, this should be handled as an internal error
29
- request params
27
+ (\err ->
28
+ Pages.StaticHttpRequest.InternalError err.fatal
30
29
  )
31
30
 
32
31
 
@@ -143,6 +143,9 @@ but mapping allows you to change the resulting values by applying functions to t
143
143
  map : (a -> b) -> BackendTask error a -> BackendTask error b
144
144
  map fn requestInfo =
145
145
  case requestInfo of
146
+ InternalError err ->
147
+ InternalError err
148
+
146
149
  ApiRoute value ->
147
150
  ApiRoute (Result.map fn value)
148
151
 
@@ -221,6 +224,9 @@ inDir dir backendTask =
221
224
  -- elm-review: known-unoptimized-recursion
222
225
  -- TODO try to find a way to optimize tail-call recursion here
223
226
  case backendTask of
227
+ InternalError _ ->
228
+ backendTask
229
+
224
230
  ApiRoute _ ->
225
231
  backendTask
226
232
 
@@ -243,6 +249,9 @@ quiet backendTask =
243
249
  -- elm-review: known-unoptimized-recursion
244
250
  -- TODO try to find a way to optimize tail-call recursion here
245
251
  case backendTask of
252
+ InternalError _ ->
253
+ backendTask
254
+
246
255
  ApiRoute _ ->
247
256
  backendTask
248
257
 
@@ -260,6 +269,9 @@ withEnv key value backendTask =
260
269
  -- elm-review: known-unoptimized-recursion
261
270
  -- TODO try to find a way to optimize tail-call recursion here
262
271
  case backendTask of
272
+ InternalError _ ->
273
+ backendTask
274
+
263
275
  ApiRoute _ ->
264
276
  backendTask
265
277
 
@@ -422,6 +434,12 @@ map2 fn request1 request2 =
422
434
  -- elm-review: known-unoptimized-recursion
423
435
  -- TODO try to find a way to optimize tail-call recursion here
424
436
  case ( request1, request2 ) of
437
+ ( InternalError err1, _ ) ->
438
+ InternalError err1
439
+
440
+ ( _, InternalError err2 ) ->
441
+ InternalError err2
442
+
425
443
  ( ApiRoute value1, ApiRoute value2 ) ->
426
444
  ApiRoute (Result.map2 fn value1 value2)
427
445
 
@@ -478,6 +496,9 @@ andThen fn requestInfo =
478
496
  -- elm-review: known-unoptimized-recursion
479
497
  -- TODO try to find a way to optimize recursion here
480
498
  case requestInfo of
499
+ InternalError errA ->
500
+ InternalError errA
501
+
481
502
  ApiRoute a ->
482
503
  case a of
483
504
  Ok okA ->
@@ -503,6 +524,9 @@ onError : (error -> BackendTask mappedError value) -> BackendTask error value ->
503
524
  onError fromError backendTask =
504
525
  -- elm-review: known-unoptimized-recursion
505
526
  case backendTask of
527
+ InternalError err ->
528
+ InternalError err
529
+
506
530
  ApiRoute a ->
507
531
  case a of
508
532
  Ok okA ->
@@ -569,6 +593,9 @@ fromResult result =
569
593
  mapError : (error -> errorMapped) -> BackendTask error value -> BackendTask errorMapped value
570
594
  mapError mapFn requestInfo =
571
595
  case requestInfo of
596
+ InternalError internal ->
597
+ InternalError internal
598
+
572
599
  ApiRoute value ->
573
600
  ApiRoute (Result.mapError mapFn value)
574
601
 
@@ -84,7 +84,15 @@ mainView config model =
84
84
  { path = ContentCache.pathForUrl urls |> UrlPath.join
85
85
  , route = config.urlToRoute { currentUrl | path = model.currentPath }
86
86
  }
87
- Nothing
87
+ (Just
88
+ { protocol = currentUrl.protocol
89
+ , host = currentUrl.host
90
+ , port_ = currentUrl.port_
91
+ , path = ContentCache.pathForUrl urls
92
+ , query = currentUrl.query |> Maybe.map QueryParams.fromString |> Maybe.withDefault Dict.empty
93
+ , fragment = currentUrl.fragment
94
+ }
95
+ )
88
96
  pageData.sharedData
89
97
  pageData.pageData
90
98
  pageData.actionData
@@ -1,7 +1,9 @@
1
1
  module Pages.StaticHttpRequest exposing (Error(..), MockResolver, RawRequest(..), Status(..), cacheRequestResolution, mockResolve, toBuildError)
2
2
 
3
3
  import BuildError exposing (BuildError)
4
+ import FatalError exposing (FatalError)
4
5
  import Json.Encode
6
+ import Pages.Internal.FatalError
5
7
  import Pages.StaticHttp.Request
6
8
  import RequestsAndPending exposing (RequestsAndPending)
7
9
  import TerminalText as Terminal
@@ -15,11 +17,13 @@ type alias MockResolver =
15
17
  type RawRequest error value
16
18
  = Request (List Pages.StaticHttp.Request.Request) (Maybe MockResolver -> RequestsAndPending -> RawRequest error value)
17
19
  | ApiRoute (Result error value)
20
+ | InternalError FatalError
18
21
 
19
22
 
20
23
  type Error
21
24
  = DecoderError String
22
25
  | UserCalledStaticHttpFail String
26
+ | InternalFailure FatalError
23
27
 
24
28
 
25
29
  toBuildError : String -> Error -> BuildError
@@ -43,18 +47,36 @@ toBuildError path error =
43
47
  , fatal = True
44
48
  }
45
49
 
50
+ InternalFailure (Pages.Internal.FatalError.FatalError buildError) ->
51
+ { title = "Internal error"
52
+ , message =
53
+ [ Terminal.text <| "Please report this error!"
54
+ , Terminal.text ""
55
+ , Terminal.text ""
56
+ , Terminal.text buildError.body
57
+ ]
58
+ , path = path
59
+ , fatal = True
60
+ }
61
+
46
62
 
47
- mockResolve : RawRequest error value -> MockResolver -> Result error value
48
- mockResolve request mockResolver =
63
+ mockResolve : (FatalError -> error) -> RawRequest error value -> MockResolver -> Result error value
64
+ mockResolve onInternalError request mockResolver =
49
65
  case request of
50
66
  Request _ lookupFn ->
51
- case lookupFn (Just mockResolver) (Json.Encode.object []) of
52
- nextRequest ->
53
- mockResolve nextRequest mockResolver
67
+ let
68
+ nextRequest : RawRequest error value
69
+ nextRequest =
70
+ lookupFn (Just mockResolver) (Json.Encode.object [])
71
+ in
72
+ mockResolve onInternalError nextRequest mockResolver
54
73
 
55
74
  ApiRoute value ->
56
75
  value
57
76
 
77
+ InternalError err ->
78
+ Err (onInternalError err)
79
+
58
80
 
59
81
  cacheRequestResolution :
60
82
  RawRequest error value
@@ -72,6 +94,9 @@ cacheRequestResolution request rawResponses =
72
94
  ApiRoute value ->
73
95
  Complete value
74
96
 
97
+ InternalError err ->
98
+ HasPermanentError (InternalFailure err)
99
+
75
100
 
76
101
  type Status error value
77
102
  = Incomplete (List Pages.StaticHttp.Request.Request) (RawRequest error value)
@@ -36,10 +36,12 @@ bodyDecoder =
36
36
  Decode.string
37
37
  |> Decode.andThen
38
38
  (\base64String ->
39
- base64String
40
- |> Base64.toBytes
41
- |> Maybe.map (BytesBody >> Decode.succeed)
42
- |> Maybe.withDefault (Decode.fail "Couldn't parse base64 string into Bytes.")
39
+ case Base64.toBytes base64String of
40
+ Just bytes ->
41
+ Decode.succeed (BytesBody bytes)
42
+
43
+ Nothing ->
44
+ Decode.fail "Couldn't parse base64 string into Bytes."
43
45
  )
44
46
 
45
47
  "string" ->