elm-pages 3.0.0-beta.14 → 3.0.0-beta.15
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 +1 -1
- package/codegen/elm-pages-codegen.js +4 -7
- 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/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- 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/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/compatibility-key.js +1 -1
- package/generator/src/error-formatter.js +7 -3
- package/generator/src/render.js +8 -17
- package/generator/src/request-cache.js +34 -4
- package/generator/static-code/hmr.js +16 -2
- package/package.json +1 -1
- package/src/ApiRoute.elm +1 -4
- package/src/BackendTask/Env.elm +10 -8
- package/src/BackendTask/File.elm +10 -10
- package/src/BackendTask/Glob.elm +2 -2
- package/src/BackendTask/Http.elm +49 -13
- package/src/BackendTask/Port.elm +50 -46
- package/src/BackendTask.elm +5 -5
- package/src/Exception.elm +70 -12
- package/src/Form.elm +3 -2
- package/src/Pages/Generate.elm +299 -102
- package/src/Pages/Internal/Platform/Cli.elm +17 -37
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +17 -41
- package/src/Pages/Internal/Platform/StaticResponses.elm +11 -25
- package/src/Pages/Script.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +1 -23
- package/src/Server/Request.elm +3 -2
- package/src/MultiDict.elm +0 -49
- package/src/PairingHeap.elm +0 -137
- package/src/Parser/Extra/String.elm +0 -33
- package/src/Parser/Extra.elm +0 -69
- package/src/ProgramTest/ComplexQuery.elm +0 -360
- package/src/ProgramTest/EffectSimulation.elm +0 -122
- package/src/ProgramTest/Failure.elm +0 -367
- package/src/ProgramTest/HtmlHighlighter.elm +0 -116
- package/src/ProgramTest/HtmlParserHacks.elm +0 -58
- package/src/ProgramTest/HtmlRenderer.elm +0 -73
- package/src/ProgramTest/Program.elm +0 -30
- package/src/ProgramTest/StringLines.elm +0 -26
- package/src/ProgramTest/TestHtmlHacks.elm +0 -132
- package/src/ProgramTest/TestHtmlParser.elm +0 -201
- package/src/ProgramTest.elm +0 -2339
- package/src/Query/Extra.elm +0 -55
- package/src/SimulatedEffect/Cmd.elm +0 -69
- package/src/SimulatedEffect/Http.elm +0 -330
- package/src/SimulatedEffect/Navigation.elm +0 -69
- package/src/SimulatedEffect/Ports.elm +0 -62
- package/src/SimulatedEffect/Process.elm +0 -24
- package/src/SimulatedEffect/Sub.elm +0 -48
- package/src/SimulatedEffect/Task.elm +0 -252
- package/src/SimulatedEffect/Time.elm +0 -25
- package/src/SimulatedEffect.elm +0 -42
- package/src/String/Extra.elm +0 -6
- package/src/Test/Http.elm +0 -145
- package/src/TestResult.elm +0 -35
- package/src/TestState.elm +0 -305
- package/src/Url/Extra.elm +0 -100
- package/src/Vendored/Diff.elm +0 -321
- package/src/Vendored/Failure.elm +0 -217
- package/src/Vendored/FormatMonochrome.elm +0 -44
- package/src/Vendored/Highlightable.elm +0 -53
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ https://github.com/dillonkearns/elm-pages/projects
|
|
|
81
81
|
You will see an error if the NPM and Elm package do not have a matching Compatibility Key. Usually it's best to upgrade to the latest version of both the Elm and NPM
|
|
82
82
|
packages when you upgrade. However, in case you want to install versions that are behind the latest, the Compatibility Key is included here for reference.
|
|
83
83
|
|
|
84
|
-
Current Compatibility Key:
|
|
84
|
+
Current Compatibility Key: 5.
|
|
85
85
|
|
|
86
86
|
## Contributors ✨
|
|
87
87
|
|
|
@@ -26209,9 +26209,6 @@ var $author$project$Gen$Pages$Internal$Platform$Cli$annotation_ = {
|
|
|
26209
26209
|
$author$project$Elm$Annotation$list(
|
|
26210
26210
|
A3($author$project$Elm$Annotation$namedWith, _List_Nil, 'BuildError', _List_Nil))),
|
|
26211
26211
|
_Utils_Tuple2(
|
|
26212
|
-
'allRawResponses',
|
|
26213
|
-
A3($author$project$Elm$Annotation$namedWith, _List_Nil, 'RequestsAndPending', _List_Nil)),
|
|
26214
|
-
_Utils_Tuple2(
|
|
26215
26212
|
'maybeRequestJson',
|
|
26216
26213
|
A3(
|
|
26217
26214
|
$author$project$Elm$Annotation$namedWith,
|
|
@@ -27113,7 +27110,7 @@ var $author$project$Gen$BackendTask$call_ = {
|
|
|
27113
27110
|
A3(
|
|
27114
27111
|
$author$project$Elm$Annotation$namedWith,
|
|
27115
27112
|
_List_Nil,
|
|
27116
|
-
'
|
|
27113
|
+
'Exception',
|
|
27117
27114
|
_List_fromArray(
|
|
27118
27115
|
[
|
|
27119
27116
|
$author$project$Elm$Annotation$var('error')
|
|
@@ -28201,7 +28198,7 @@ var $author$project$Gen$BackendTask$call_ = {
|
|
|
28201
28198
|
A3(
|
|
28202
28199
|
$author$project$Elm$Annotation$namedWith,
|
|
28203
28200
|
_List_Nil,
|
|
28204
|
-
'
|
|
28201
|
+
'Exception',
|
|
28205
28202
|
_List_fromArray(
|
|
28206
28203
|
[
|
|
28207
28204
|
$author$project$Elm$Annotation$var('error')
|
|
@@ -28244,7 +28241,7 @@ var $author$project$Gen$BackendTask$call_ = {
|
|
|
28244
28241
|
A3(
|
|
28245
28242
|
$author$project$Elm$Annotation$namedWith,
|
|
28246
28243
|
_List_Nil,
|
|
28247
|
-
'
|
|
28244
|
+
'Exception',
|
|
28248
28245
|
_List_fromArray(
|
|
28249
28246
|
[
|
|
28250
28247
|
$author$project$Elm$Annotation$var('error')
|
|
@@ -33792,7 +33789,7 @@ var $author$project$Gen$ApiRoute$values_ = {
|
|
|
33792
33789
|
'BackendTask',
|
|
33793
33790
|
_List_fromArray(
|
|
33794
33791
|
[
|
|
33795
|
-
A3($author$project$Elm$Annotation$namedWith, _List_Nil, '
|
|
33792
|
+
A3($author$project$Elm$Annotation$namedWith, _List_Nil, 'Throwable', _List_Nil),
|
|
33796
33793
|
A3(
|
|
33797
33794
|
$author$project$Elm$Annotation$namedWith,
|
|
33798
33795
|
_List_fromArray(
|
|
Binary file
|
|
@@ -75,7 +75,7 @@ console.elmlog = (str) => logs.push(str + "\n");
|
|
|
75
75
|
const { Elm } = require("./Runner.elm.js");
|
|
76
76
|
|
|
77
77
|
// Start the Elm app
|
|
78
|
-
const flags = { initialSeed:
|
|
78
|
+
const flags = { initialSeed: 4021965449, fuzzRuns: 100, filter: null };
|
|
79
79
|
const app = Elm.Runner.init({ flags: flags });
|
|
80
80
|
|
|
81
81
|
// Record the timing at which we received the last "runTest" message
|
|
Binary file
|
|
@@ -75,7 +75,7 @@ console.elmlog = (str) => logs.push(str + "\n");
|
|
|
75
75
|
const { Elm } = require("./Runner.elm.js");
|
|
76
76
|
|
|
77
77
|
// Start the Elm app
|
|
78
|
-
const flags = { initialSeed:
|
|
78
|
+
const flags = { initialSeed: 1951305281, fuzzRuns: 100, filter: null };
|
|
79
79
|
const app = Elm.Runner.init({ flags: flags });
|
|
80
80
|
|
|
81
81
|
// Record the timing at which we received the last "runTest" message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = { compatibilityKey:
|
|
1
|
+
module.exports = { compatibilityKey: 5 };
|
|
@@ -13,11 +13,12 @@ const kleur = require("kleur");
|
|
|
13
13
|
* @param {string} rule
|
|
14
14
|
* @param {string} path
|
|
15
15
|
* */
|
|
16
|
-
|
|
17
|
-
kleur.cyan(
|
|
18
|
-
`-- ${rule.replace("-", " ")} --------------- ${path || ""}
|
|
16
|
+
function parseHeader(rule, path) {
|
|
17
|
+
return kleur.cyan(
|
|
18
|
+
`-- ${(rule || "").replace("-", " ")} --------------- ${path || ""}
|
|
19
19
|
`
|
|
20
20
|
);
|
|
21
|
+
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* parseMsg :: String|Object -> String
|
|
@@ -137,7 +138,10 @@ const restoreProblem =
|
|
|
137
138
|
parseHeader(info.rule, path),
|
|
138
139
|
...info.formatted.map(parseMsg),
|
|
139
140
|
].join("");
|
|
141
|
+
} else if (typeof info.message === "string") {
|
|
142
|
+
return info.message;
|
|
140
143
|
} else {
|
|
144
|
+
// console.log("info.message", info.message);
|
|
141
145
|
return [
|
|
142
146
|
parseHeader(info.title, path),
|
|
143
147
|
...info.message.map(parseMsg),
|
package/generator/src/render.js
CHANGED
|
@@ -143,22 +143,10 @@ function runGeneratorAppHelp(
|
|
|
143
143
|
if (fromElm.command === "log") {
|
|
144
144
|
console.log(fromElm.value);
|
|
145
145
|
} else if (fromElm.tag === "ApiResponse") {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
global.staticHttpCache = args.staticHttpCache;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
resolve({
|
|
152
|
-
kind: "api-response",
|
|
153
|
-
is404: args.is404,
|
|
154
|
-
statusCode: args.statusCode,
|
|
155
|
-
body: args.body,
|
|
156
|
-
});
|
|
146
|
+
// Finished successfully
|
|
147
|
+
process.exit(0);
|
|
157
148
|
} else if (fromElm.tag === "PageProgress") {
|
|
158
149
|
const args = fromElm.args[0];
|
|
159
|
-
if (mode === "build") {
|
|
160
|
-
global.staticHttpCache = args.staticHttpCache;
|
|
161
|
-
}
|
|
162
150
|
|
|
163
151
|
if (isBytes) {
|
|
164
152
|
resolve({
|
|
@@ -653,9 +641,12 @@ function flushIfDone(app) {
|
|
|
653
641
|
}
|
|
654
642
|
|
|
655
643
|
function flushQueue(app) {
|
|
656
|
-
|
|
657
|
-
pendingBackendTaskResponses
|
|
658
|
-
|
|
644
|
+
// TODO - could the case where flush is called with size 0 be avoided on the Elm side?
|
|
645
|
+
if (pendingBackendTaskResponses.size > 0) {
|
|
646
|
+
// console.log("@@@ FLUSHING", pendingBackendTaskResponses.size);
|
|
647
|
+
app.ports.gotBatchSub.send(Object.fromEntries(pendingBackendTaskResponses));
|
|
648
|
+
pendingBackendTaskResponses = new Map();
|
|
649
|
+
}
|
|
659
650
|
}
|
|
660
651
|
|
|
661
652
|
/**
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const kleur = require("kleur");
|
|
3
|
+
const fsPromises = require("fs/promises");
|
|
4
|
+
|
|
5
|
+
const defaultHttpCachePath = "./.elm-pages/http-cache";
|
|
3
6
|
|
|
4
7
|
/** @typedef {{kind: 'cache-response-path', value: string} | {kind: 'response-json', value: JSON}} Response */
|
|
5
8
|
|
|
@@ -11,8 +14,7 @@ const kleur = require("kleur");
|
|
|
11
14
|
* @returns {Promise<Response>}
|
|
12
15
|
*/
|
|
13
16
|
function lookupOrPerform(portsFile, mode, rawRequest, hasFsAccess, useCache) {
|
|
14
|
-
const
|
|
15
|
-
cachePath: "./.elm-pages/http-cache",
|
|
17
|
+
const makeFetchHappen = require("make-fetch-happen").defaults({
|
|
16
18
|
cache: mode === "build" ? "no-cache" : "default",
|
|
17
19
|
});
|
|
18
20
|
return new Promise(async (resolve, reject) => {
|
|
@@ -81,7 +83,7 @@ function lookupOrPerform(portsFile, mode, rawRequest, hasFsAccess, useCache) {
|
|
|
81
83
|
resolve({
|
|
82
84
|
kind: "response-json",
|
|
83
85
|
value: jsonResponse({
|
|
84
|
-
"elm-pages-internal-error": "
|
|
86
|
+
"elm-pages-internal-error": "PortCallException",
|
|
85
87
|
error: portCallError,
|
|
86
88
|
}),
|
|
87
89
|
});
|
|
@@ -97,7 +99,7 @@ function lookupOrPerform(portsFile, mode, rawRequest, hasFsAccess, useCache) {
|
|
|
97
99
|
} else {
|
|
98
100
|
try {
|
|
99
101
|
console.time(`fetch ${request.url}`);
|
|
100
|
-
const response = await
|
|
102
|
+
const response = await safeFetch(makeFetchHappen, request.url, {
|
|
101
103
|
method: request.method,
|
|
102
104
|
body: request.body,
|
|
103
105
|
headers: {
|
|
@@ -241,4 +243,32 @@ function jsonResponse(json) {
|
|
|
241
243
|
return { bodyKind: "json", body: json };
|
|
242
244
|
}
|
|
243
245
|
|
|
246
|
+
async function safeFetch(makeFetchHappen, url, options) {
|
|
247
|
+
const { cachePath, ...optionsWithoutCachePath } = options;
|
|
248
|
+
const cachePathWithDefault = cachePath || defaultHttpCachePath;
|
|
249
|
+
if (await canAccess(cachePathWithDefault)) {
|
|
250
|
+
return await makeFetchHappen(url, {
|
|
251
|
+
cachePath: cachePathWithDefault,
|
|
252
|
+
...options,
|
|
253
|
+
});
|
|
254
|
+
} else {
|
|
255
|
+
return await makeFetchHappen(url, {
|
|
256
|
+
cache: "no-store",
|
|
257
|
+
...optionsWithoutCachePath,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function canAccess(filePath) {
|
|
263
|
+
try {
|
|
264
|
+
await fsPromises.access(
|
|
265
|
+
filePath,
|
|
266
|
+
fsPromises.constants.R_OK | fsPromises.constants.W_OK
|
|
267
|
+
);
|
|
268
|
+
return true;
|
|
269
|
+
} catch {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
244
274
|
module.exports = { lookupOrPerform };
|
|
@@ -224,8 +224,11 @@ function htmlSanitize(str, type) {
|
|
|
224
224
|
);
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
`-- ${title.replace("-", " ")} --------------- ${
|
|
227
|
+
function parseHeader(title, path) {
|
|
228
|
+
return `-- ${(title || "ERROR").replace("-", " ")} --------------- ${
|
|
229
|
+
path || ""
|
|
230
|
+
}`;
|
|
231
|
+
}
|
|
229
232
|
|
|
230
233
|
/*
|
|
231
234
|
|-------------------------------------------------------------------------------
|
|
@@ -253,6 +256,14 @@ const parseConsoleErrors =
|
|
|
253
256
|
* */
|
|
254
257
|
(info) => {
|
|
255
258
|
if (info.rule) {
|
|
259
|
+
if (info.details) {
|
|
260
|
+
return joinMessage(
|
|
261
|
+
info.details.reduce(consoleMsg, {
|
|
262
|
+
error: [consoleHeader(info.rule, path)],
|
|
263
|
+
style: [styleColor("blue")],
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
}
|
|
256
267
|
return joinMessage(
|
|
257
268
|
info.formatted.reduce(consoleMsg, {
|
|
258
269
|
error: [consoleHeader(info.rule, path)],
|
|
@@ -313,6 +324,9 @@ const parseHtmlErrors = (path) => (info) => {
|
|
|
313
324
|
if (info.rule) {
|
|
314
325
|
return info.formatted.reduce(htmlMsg, htmlHeader(info.rule, path));
|
|
315
326
|
} else {
|
|
327
|
+
if (info.details) {
|
|
328
|
+
return info.details.reduce(htmlMsg, htmlHeader(info.title, path));
|
|
329
|
+
}
|
|
316
330
|
return info.message.reduce(htmlMsg, htmlHeader(info.title, path));
|
|
317
331
|
}
|
|
318
332
|
};
|
package/package.json
CHANGED
package/src/ApiRoute.elm
CHANGED
|
@@ -199,7 +199,7 @@ single handler =
|
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
{-| -}
|
|
202
|
-
serverRender : ApiRouteBuilder (Server.Request.Parser (BackendTask
|
|
202
|
+
serverRender : ApiRouteBuilder (Server.Request.Parser (BackendTask Throwable (Server.Response.Response Never Never))) constructor -> ApiRoute Response
|
|
203
203
|
serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
204
204
|
ApiRoute
|
|
205
205
|
{ regex = Regex.fromString ("^" ++ pattern ++ "$") |> Maybe.withDefault Regex.never
|
|
@@ -225,7 +225,6 @@ serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
|
225
225
|
case rendered of
|
|
226
226
|
Just (Ok okRendered) ->
|
|
227
227
|
okRendered
|
|
228
|
-
|> BackendTask.onError never
|
|
229
228
|
|
|
230
229
|
Just (Err errors) ->
|
|
231
230
|
errors
|
|
@@ -233,13 +232,11 @@ serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
|
233
232
|
|> Server.Response.plainText
|
|
234
233
|
|> Server.Response.withStatusCode 400
|
|
235
234
|
|> BackendTask.succeed
|
|
236
|
-
|> BackendTask.onError never
|
|
237
235
|
|
|
238
236
|
Nothing ->
|
|
239
237
|
Server.Response.plainText "No matching request handler"
|
|
240
238
|
|> Server.Response.withStatusCode 400
|
|
241
239
|
|> BackendTask.succeed
|
|
242
|
-
|> BackendTask.onError never
|
|
243
240
|
)
|
|
244
241
|
)
|
|
245
242
|
|> Maybe.map (BackendTask.map (Server.Response.toJson >> Just))
|
package/src/BackendTask/Env.elm
CHANGED
|
@@ -8,22 +8,23 @@ down into the final `Data` value, it won't end up in the client!
|
|
|
8
8
|
|
|
9
9
|
import BackendTask exposing (BackendTask)
|
|
10
10
|
import BackendTask.Env
|
|
11
|
+
import Exception exposing (Throwable)
|
|
11
12
|
|
|
12
13
|
type alias EnvVariables =
|
|
13
14
|
{ sendGridKey : String
|
|
14
15
|
, siteUrl : String
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
sendEmail : Email -> BackendTask ()
|
|
18
|
+
sendEmail : Email -> BackendTask Throwable ()
|
|
18
19
|
sendEmail email =
|
|
19
20
|
BackendTask.map2 EnvVariables
|
|
20
|
-
(BackendTask.Env.expect "SEND_GRID_KEY")
|
|
21
|
+
(BackendTask.Env.expect "SEND_GRID_KEY" |> BackendTask.throw)
|
|
21
22
|
(BackendTask.Env.get "BASE_URL"
|
|
22
23
|
|> BackendTask.map (Maybe.withDefault "http://localhost:1234")
|
|
23
24
|
)
|
|
24
25
|
|> BackendTask.andThen (sendEmailBackendTask email)
|
|
25
26
|
|
|
26
|
-
sendEmailBackendTask : Email -> EnvVariables -> BackendTask ()
|
|
27
|
+
sendEmailBackendTask : Email -> EnvVariables -> BackendTask Throwable ()
|
|
27
28
|
sendEmailBackendTask email envVariables =
|
|
28
29
|
Debug.todo "Not defined here"
|
|
29
30
|
|
|
@@ -39,7 +40,7 @@ down into the final `Data` value, it won't end up in the client!
|
|
|
39
40
|
import BackendTask exposing (BackendTask)
|
|
40
41
|
import BackendTask.Http
|
|
41
42
|
import BackendTask.Internal.Request
|
|
42
|
-
import Exception exposing (
|
|
43
|
+
import Exception exposing (Exception)
|
|
43
44
|
import Json.Decode as Decode
|
|
44
45
|
import Json.Encode as Encode
|
|
45
46
|
import TerminalText
|
|
@@ -50,7 +51,8 @@ type Error
|
|
|
50
51
|
= MissingEnvVariable String
|
|
51
52
|
|
|
52
53
|
|
|
53
|
-
{-| Get an environment variable, or Nothing if there is no environment variable matching that name.
|
|
54
|
+
{-| Get an environment variable, or Nothing if there is no environment variable matching that name. This `BackendTask`
|
|
55
|
+
will never fail, but instead will return `Nothing` if the environment variable is missing.
|
|
54
56
|
-}
|
|
55
57
|
get : String -> BackendTask error (Maybe String)
|
|
56
58
|
get envVariableName =
|
|
@@ -63,9 +65,9 @@ get envVariableName =
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
|
|
66
|
-
{-| Get an environment variable, or a BackendTask
|
|
68
|
+
{-| Get an environment variable, or a BackendTask Exception if there is no environment variable matching that name.
|
|
67
69
|
-}
|
|
68
|
-
expect : String -> BackendTask (
|
|
70
|
+
expect : String -> BackendTask (Exception Error) String
|
|
69
71
|
expect envVariableName =
|
|
70
72
|
envVariableName
|
|
71
73
|
|> get
|
|
@@ -73,7 +75,7 @@ expect envVariableName =
|
|
|
73
75
|
(\maybeValue ->
|
|
74
76
|
maybeValue
|
|
75
77
|
|> Result.fromMaybe
|
|
76
|
-
(Exception.
|
|
78
|
+
(Exception.Exception (MissingEnvVariable envVariableName)
|
|
77
79
|
{ title = "Missing Env Variable"
|
|
78
80
|
, body =
|
|
79
81
|
[ TerminalText.text "BackendTask.Env.expect was expecting a variable `"
|
package/src/BackendTask/File.elm
CHANGED
|
@@ -51,7 +51,7 @@ plain old JSON in Elm.
|
|
|
51
51
|
import BackendTask exposing (BackendTask)
|
|
52
52
|
import BackendTask.Http
|
|
53
53
|
import BackendTask.Internal.Request
|
|
54
|
-
import Exception exposing (
|
|
54
|
+
import Exception exposing (Exception)
|
|
55
55
|
import Json.Decode as Decode exposing (Decoder)
|
|
56
56
|
import TerminalText
|
|
57
57
|
|
|
@@ -141,7 +141,7 @@ It's common to parse the body with a markdown parser or other format.
|
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
-}
|
|
144
|
-
bodyWithFrontmatter : (String -> Decoder frontmatter) -> String -> BackendTask (
|
|
144
|
+
bodyWithFrontmatter : (String -> Decoder frontmatter) -> String -> BackendTask (Exception (FileReadError Decode.Error)) frontmatter
|
|
145
145
|
bodyWithFrontmatter frontmatterDecoder filePath =
|
|
146
146
|
read filePath
|
|
147
147
|
(body
|
|
@@ -213,7 +213,7 @@ the [`BackendTask`](BackendTask) API along with [`BackendTask.Glob`](BackendTask
|
|
|
213
213
|
|> BackendTask.resolve
|
|
214
214
|
|
|
215
215
|
-}
|
|
216
|
-
onlyFrontmatter : Decoder frontmatter -> String -> BackendTask (
|
|
216
|
+
onlyFrontmatter : Decoder frontmatter -> String -> BackendTask (Exception (FileReadError Decode.Error)) frontmatter
|
|
217
217
|
onlyFrontmatter frontmatterDecoder filePath =
|
|
218
218
|
read filePath
|
|
219
219
|
(frontmatter frontmatterDecoder)
|
|
@@ -240,7 +240,7 @@ Hey there! This is my first post :)
|
|
|
240
240
|
Then data will yield the value `"Hey there! This is my first post :)"`.
|
|
241
241
|
|
|
242
242
|
-}
|
|
243
|
-
bodyWithoutFrontmatter : String -> BackendTask (
|
|
243
|
+
bodyWithoutFrontmatter : String -> BackendTask (Exception (FileReadError decoderError)) String
|
|
244
244
|
bodyWithoutFrontmatter filePath =
|
|
245
245
|
read filePath
|
|
246
246
|
body
|
|
@@ -264,7 +264,7 @@ You could read a file called `hello.txt` in your root project directory like thi
|
|
|
264
264
|
File.rawFile "hello.txt"
|
|
265
265
|
|
|
266
266
|
-}
|
|
267
|
-
rawFile : String -> BackendTask (
|
|
267
|
+
rawFile : String -> BackendTask (Exception (FileReadError decoderError)) String
|
|
268
268
|
rawFile filePath =
|
|
269
269
|
read filePath (Decode.field "rawFile" Decode.string)
|
|
270
270
|
|
|
@@ -286,7 +286,7 @@ The Decode will strip off any unused JSON data.
|
|
|
286
286
|
"elm.json"
|
|
287
287
|
|
|
288
288
|
-}
|
|
289
|
-
jsonFile : Decoder a -> String -> BackendTask (
|
|
289
|
+
jsonFile : Decoder a -> String -> BackendTask (Exception (FileReadError Decode.Error)) a
|
|
290
290
|
jsonFile jsonFileDecoder filePath =
|
|
291
291
|
rawFile filePath
|
|
292
292
|
|> BackendTask.andThen
|
|
@@ -295,7 +295,7 @@ jsonFile jsonFileDecoder filePath =
|
|
|
295
295
|
|> Decode.decodeString jsonFileDecoder
|
|
296
296
|
|> Result.mapError
|
|
297
297
|
(\jsonDecodeError ->
|
|
298
|
-
Exception.
|
|
298
|
+
Exception.Exception (DecodingError jsonDecodeError)
|
|
299
299
|
{ title = "JSON Decoding Error"
|
|
300
300
|
, body =
|
|
301
301
|
[ TerminalText.text (Decode.errorToString jsonDecodeError)
|
|
@@ -314,7 +314,7 @@ body =
|
|
|
314
314
|
Decode.field "withoutFrontmatter" Decode.string
|
|
315
315
|
|
|
316
316
|
|
|
317
|
-
read : String -> Decoder a -> BackendTask (
|
|
317
|
+
read : String -> Decoder a -> BackendTask (Exception (FileReadError error)) a
|
|
318
318
|
read filePath decoder =
|
|
319
319
|
BackendTask.Internal.Request.request
|
|
320
320
|
{ name = "read-file"
|
|
@@ -330,10 +330,10 @@ read filePath decoder =
|
|
|
330
330
|
|> BackendTask.andThen BackendTask.fromResult
|
|
331
331
|
|
|
332
332
|
|
|
333
|
-
errorDecoder : String -> Decoder (
|
|
333
|
+
errorDecoder : String -> Decoder (Exception (FileReadError decoding))
|
|
334
334
|
errorDecoder filePath =
|
|
335
335
|
Decode.succeed
|
|
336
|
-
(Exception.
|
|
336
|
+
(Exception.Exception FileDoesntExist
|
|
337
337
|
{ title = "File Doesn't Exist"
|
|
338
338
|
, body =
|
|
339
339
|
[ TerminalText.text "Couldn't find file at path `"
|
package/src/BackendTask/Glob.elm
CHANGED
|
@@ -229,7 +229,7 @@ import BackendTask exposing (BackendTask)
|
|
|
229
229
|
import BackendTask.Http
|
|
230
230
|
import BackendTask.Internal.Glob exposing (Glob(..))
|
|
231
231
|
import BackendTask.Internal.Request
|
|
232
|
-
import Exception exposing (
|
|
232
|
+
import Exception exposing (Exception, Throwable)
|
|
233
233
|
import Json.Decode as Decode
|
|
234
234
|
import Json.Encode as Encode
|
|
235
235
|
import List.Extra
|
|
@@ -1054,7 +1054,7 @@ so it's ideal to make this kind of assertion rather than having fallback behavio
|
|
|
1054
1054
|
issues (like if we had instead ignored the case where there are two or more matching blog post files).
|
|
1055
1055
|
|
|
1056
1056
|
-}
|
|
1057
|
-
expectUniqueMatch : Glob a -> BackendTask (
|
|
1057
|
+
expectUniqueMatch : Glob a -> BackendTask (Exception String) a
|
|
1058
1058
|
expectUniqueMatch glob =
|
|
1059
1059
|
glob
|
|
1060
1060
|
|> toBackendTask
|
package/src/BackendTask/Http.elm
CHANGED
|
@@ -71,7 +71,22 @@ and describe your use case!
|
|
|
71
71
|
|
|
72
72
|
## Caching Options
|
|
73
73
|
|
|
74
|
-
`elm-pages` performs GET requests using a local HTTP cache by default.
|
|
74
|
+
`elm-pages` performs GET requests using a local HTTP cache by default. These requests are not performed using Elm's `elm/http`,
|
|
75
|
+
but rather are performed in NodeJS. Under the hood it uses [the NPM package `make-fetch-happen`](https://github.com/npm/make-fetch-happen).
|
|
76
|
+
Only GET requests made with `get`, `getJson`, or `getWithOptions` use local caching. Requests made with [`BackendTask.Http.request`](#request)
|
|
77
|
+
are not cached, even if the method is set to `GET`.
|
|
78
|
+
|
|
79
|
+
In dev mode, assets are cached more aggressively by default, whereas for a production build assets use a default to revalidate each cached response's freshness before using it (the `ForceRevalidate` [`CacheStrategy`](#CacheStrategy)).
|
|
80
|
+
|
|
81
|
+
The default caching behavior for GET requests is to use a local cache in `.elm-pages/http-cache`. This uses the same caching behavior
|
|
82
|
+
that browsers use to avoid re-downloading content when it hasn't changed. Servers can set HTTP response headers to explicitly control
|
|
83
|
+
this caching behavior.
|
|
84
|
+
|
|
85
|
+
- [`cache-control` HTTP response headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) let you set a length of time before considering an asset stale. This could mean that the server considers it acceptable for an asset to be somewhat outdated, or this could mean that the asset is guaranteed to be up-to-date until it is stale - those semantics are up to the server.
|
|
86
|
+
- `Last-Modified` and `ETag` HTTP response headers can be returned by the server allow [Conditional Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests). Conditional Requests let us send back the `Last-Modified` timestamp or `etag` hash for assets that are in our local cache to the server to check if the asset is fresh, and skip re-downloading it if it is unchanged (or download a fresh one otherwise).
|
|
87
|
+
|
|
88
|
+
It's important to note that depending on how the server sets these HTTP response headers, we may have outdated data - either because the server explicitly allows assets to become outdated with their cache-control headers, OR because cache-control headers are not set. When these headers aren't explicitly set, [clients are allowed to cache assets for 10% of the amount of time since it was last modified](https://httpwg.org/specs/rfc7234.html#heuristic.freshness).
|
|
89
|
+
For production builds, the default caching will ignore both the implicit and explicit information about an asset's freshness and _always_ revalidate it before using a locally cached response.
|
|
75
90
|
|
|
76
91
|
@docs getWithOptions
|
|
77
92
|
|
|
@@ -89,7 +104,7 @@ import Base64
|
|
|
89
104
|
import Bytes exposing (Bytes)
|
|
90
105
|
import Bytes.Decode
|
|
91
106
|
import Dict exposing (Dict)
|
|
92
|
-
import Exception exposing (
|
|
107
|
+
import Exception exposing (Exception)
|
|
93
108
|
import Json.Decode
|
|
94
109
|
import Json.Encode as Encode
|
|
95
110
|
import Pages.Internal.StaticHttpBody as Body
|
|
@@ -138,15 +153,16 @@ type alias Body =
|
|
|
138
153
|
Body.Body
|
|
139
154
|
|
|
140
155
|
|
|
141
|
-
{-| A simplified helper around [`BackendTask.Http.
|
|
156
|
+
{-| A simplified helper around [`BackendTask.Http.get`](#get), which builds up a BackendTask.Http GET request with `expectJson`.
|
|
142
157
|
|
|
143
158
|
import BackendTask
|
|
144
159
|
import BackendTask.Http
|
|
160
|
+
import Exception exposing (Exception)
|
|
145
161
|
import Json.Decode as Decode exposing (Decoder)
|
|
146
162
|
|
|
147
|
-
getRequest : BackendTask Int
|
|
163
|
+
getRequest : BackendTask (Exception Error) Int
|
|
148
164
|
getRequest =
|
|
149
|
-
BackendTask.Http.
|
|
165
|
+
BackendTask.Http.getJson
|
|
150
166
|
"https://api.github.com/repos/dillonkearns/elm-pages"
|
|
151
167
|
(Decode.field "stargazers_count" Decode.int)
|
|
152
168
|
|
|
@@ -154,7 +170,7 @@ type alias Body =
|
|
|
154
170
|
getJson :
|
|
155
171
|
String
|
|
156
172
|
-> Json.Decode.Decoder a
|
|
157
|
-
-> BackendTask (
|
|
173
|
+
-> BackendTask (Exception Error) a
|
|
158
174
|
getJson url decoder =
|
|
159
175
|
getWithOptions
|
|
160
176
|
{ url = url
|
|
@@ -167,11 +183,25 @@ getJson url decoder =
|
|
|
167
183
|
}
|
|
168
184
|
|
|
169
185
|
|
|
170
|
-
{-|
|
|
186
|
+
{-| A simplified helper around [`BackendTask.Http.getWithOptions`](#getWithOptions), which builds up a GET request with
|
|
187
|
+
the default retries, timeout, and HTTP caching options. If you need to configure those options or include HTTP request headers,
|
|
188
|
+
use the more flexible `getWithOptions`.
|
|
189
|
+
|
|
190
|
+
import BackendTask
|
|
191
|
+
import BackendTask.Http
|
|
192
|
+
import Exception exposing (Exception)
|
|
193
|
+
|
|
194
|
+
getRequest : BackendTask (Exception Error) String
|
|
195
|
+
getRequest =
|
|
196
|
+
BackendTask.Http.get
|
|
197
|
+
"https://api.github.com/repos/dillonkearns/elm-pages"
|
|
198
|
+
BackendTask.Http.expectString
|
|
199
|
+
|
|
200
|
+
-}
|
|
171
201
|
get :
|
|
172
202
|
String
|
|
173
203
|
-> Expect a
|
|
174
|
-
-> BackendTask (
|
|
204
|
+
-> BackendTask (Exception Error) a
|
|
175
205
|
get url expect =
|
|
176
206
|
getWithOptions
|
|
177
207
|
{ url = url
|
|
@@ -185,6 +215,12 @@ get url expect =
|
|
|
185
215
|
|
|
186
216
|
|
|
187
217
|
{-| Perform a GET request, with some additional options for the HTTP request, including options for caching behavior.
|
|
218
|
+
|
|
219
|
+
- `retries` - Default is 0. Will try performing request again if set to a number greater than 0.
|
|
220
|
+
- `timeoutInMs` - Default is no timeout.
|
|
221
|
+
- `cacheStrategy` - The [caching options are passed to the NPM package `make-fetch-happen`](https://github.com/npm/make-fetch-happen#opts-cache)
|
|
222
|
+
- `cachePath` - override the default directory for the local HTTP cache. This can be helpful if you want more granular control to clear some HTTP caches more or less frequently than others. Or you may want to preserve the local cache for some requests in your build server, but not store the cache for other requests.
|
|
223
|
+
|
|
188
224
|
-}
|
|
189
225
|
getWithOptions :
|
|
190
226
|
{ url : String
|
|
@@ -195,7 +231,7 @@ getWithOptions :
|
|
|
195
231
|
, timeoutInMs : Maybe Int
|
|
196
232
|
, cachePath : Maybe String
|
|
197
233
|
}
|
|
198
|
-
-> BackendTask (
|
|
234
|
+
-> BackendTask (Exception Error) a
|
|
199
235
|
getWithOptions request__ =
|
|
200
236
|
let
|
|
201
237
|
request_ : HashRequest.Request
|
|
@@ -222,7 +258,7 @@ post :
|
|
|
222
258
|
String
|
|
223
259
|
-> Body
|
|
224
260
|
-> Expect a
|
|
225
|
-
-> BackendTask (
|
|
261
|
+
-> BackendTask (Exception Error) a
|
|
226
262
|
post url body expect =
|
|
227
263
|
request
|
|
228
264
|
{ url = url
|
|
@@ -361,7 +397,7 @@ request :
|
|
|
361
397
|
, timeoutInMs : Maybe Int
|
|
362
398
|
}
|
|
363
399
|
-> Expect a
|
|
364
|
-
-> BackendTask (
|
|
400
|
+
-> BackendTask (Exception Error) a
|
|
365
401
|
request request__ expect =
|
|
366
402
|
let
|
|
367
403
|
request_ : HashRequest.Request
|
|
@@ -439,7 +475,7 @@ with this as a low-level detail, or you can use functions like [BackendTask.Http
|
|
|
439
475
|
requestRaw :
|
|
440
476
|
HashRequest.Request
|
|
441
477
|
-> Expect a
|
|
442
|
-
-> BackendTask (
|
|
478
|
+
-> BackendTask (Exception Error) a
|
|
443
479
|
requestRaw request__ expect =
|
|
444
480
|
let
|
|
445
481
|
request_ : HashRequest.Request
|
|
@@ -537,7 +573,7 @@ requestRaw request__ expect =
|
|
|
537
573
|
|> BackendTask.fromResult
|
|
538
574
|
|> BackendTask.mapError
|
|
539
575
|
(\error ->
|
|
540
|
-
Exception.
|
|
576
|
+
Exception.Exception error (errorToString error)
|
|
541
577
|
)
|
|
542
578
|
)
|
|
543
579
|
|