elm-pages 3.0.0-beta.4 → 3.0.0-beta.41

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 (148) hide show
  1. package/README.md +10 -1
  2. package/adapter/netlify.js +207 -0
  3. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2828 -2933
  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 +1447 -342
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +17004 -13817
  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 +4 -4
  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 +1447 -342
  27. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25025 -21739
  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 +4 -4
  30. package/generator/review/elm.json +10 -10
  31. package/generator/src/RouteBuilder.elm +121 -114
  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 +209 -92
  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 +39 -0
  41. package/generator/src/copy-dir.js +2 -2
  42. package/generator/src/dev-server.js +176 -138
  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 +39 -28
  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 +77 -0
  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 +6 -5
  65. package/generator/template/app/Effect.elm +123 -0
  66. package/generator/template/app/ErrorPage.elm +37 -6
  67. package/generator/template/app/Route/Index.elm +17 -10
  68. package/generator/template/app/Shared.elm +24 -47
  69. package/generator/template/app/Site.elm +19 -6
  70. package/generator/template/app/View.elm +1 -8
  71. package/generator/template/elm-tooling.json +0 -3
  72. package/generator/template/elm.json +32 -24
  73. package/generator/template/package.json +10 -4
  74. package/package.json +30 -27
  75. package/src/ApiRoute.elm +199 -61
  76. package/src/BackendTask/Custom.elm +325 -0
  77. package/src/BackendTask/Env.elm +90 -0
  78. package/src/{DataSource → BackendTask}/File.elm +171 -56
  79. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  80. package/src/BackendTask/Http.elm +679 -0
  81. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  82. package/src/BackendTask/Internal/Request.elm +69 -0
  83. package/src/BackendTask/Random.elm +79 -0
  84. package/src/BackendTask/Time.elm +47 -0
  85. package/src/BackendTask.elm +531 -0
  86. package/src/FatalError.elm +90 -0
  87. package/src/Head/Seo.elm +4 -4
  88. package/src/Head.elm +237 -7
  89. package/src/HtmlPrinter.elm +7 -3
  90. package/src/Internal/ApiRoute.elm +7 -5
  91. package/src/PageServerResponse.elm +6 -1
  92. package/src/Pages/ConcurrentSubmission.elm +127 -0
  93. package/src/Pages/Form.elm +340 -0
  94. package/src/Pages/FormData.elm +18 -0
  95. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  96. package/src/Pages/Internal/FatalError.elm +5 -0
  97. package/src/Pages/Internal/Msg.elm +93 -0
  98. package/src/Pages/Internal/NotFoundReason.elm +4 -4
  99. package/src/Pages/Internal/Platform/Cli.elm +617 -768
  100. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  101. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  102. package/src/Pages/Internal/Platform/GeneratorApplication.elm +379 -0
  103. package/src/Pages/Internal/Platform/StaticResponses.elm +65 -276
  104. package/src/Pages/Internal/Platform/ToJsPayload.elm +6 -9
  105. package/src/Pages/Internal/Platform.elm +359 -225
  106. package/src/Pages/Internal/ResponseSketch.elm +2 -2
  107. package/src/Pages/Internal/Script.elm +17 -0
  108. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  109. package/src/Pages/Manifest.elm +52 -11
  110. package/src/Pages/Navigation.elm +87 -0
  111. package/src/Pages/PageUrl.elm +26 -12
  112. package/src/Pages/ProgramConfig.elm +35 -23
  113. package/src/Pages/Script.elm +166 -0
  114. package/src/Pages/SiteConfig.elm +3 -2
  115. package/src/Pages/StaticHttp/Request.elm +2 -2
  116. package/src/Pages/StaticHttpRequest.elm +23 -99
  117. package/src/Pages/Url.elm +3 -3
  118. package/src/PagesMsg.elm +88 -0
  119. package/src/QueryParams.elm +21 -172
  120. package/src/RenderRequest.elm +7 -7
  121. package/src/RequestsAndPending.elm +37 -20
  122. package/src/Result/Extra.elm +26 -0
  123. package/src/Scaffold/Form.elm +569 -0
  124. package/src/Scaffold/Route.elm +1411 -0
  125. package/src/Server/Request.elm +74 -72
  126. package/src/Server/Session.elm +62 -42
  127. package/src/Server/SetCookie.elm +80 -32
  128. package/src/Stub.elm +53 -0
  129. package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
  130. package/src/{Path.elm → UrlPath.elm} +33 -36
  131. package/src/DataSource/Env.elm +0 -38
  132. package/src/DataSource/Http.elm +0 -446
  133. package/src/DataSource/Internal/Request.elm +0 -20
  134. package/src/DataSource/Port.elm +0 -90
  135. package/src/DataSource.elm +0 -538
  136. package/src/Form/Field.elm +0 -717
  137. package/src/Form/FieldStatus.elm +0 -36
  138. package/src/Form/FieldView.elm +0 -417
  139. package/src/Form/FormData.elm +0 -22
  140. package/src/Form/Validation.elm +0 -391
  141. package/src/Form/Value.elm +0 -118
  142. package/src/Form.elm +0 -1683
  143. package/src/FormDecoder.elm +0 -102
  144. package/src/Pages/FormState.elm +0 -256
  145. package/src/Pages/Generate.elm +0 -800
  146. package/src/Pages/Internal/Form.elm +0 -17
  147. package/src/Pages/Msg.elm +0 -79
  148. package/src/Pages/Transition.elm +0 -70
@@ -0,0 +1,679 @@
1
+ module BackendTask.Http exposing
2
+ ( get, getJson
3
+ , post
4
+ , Expect, expectString, expectJson, expectBytes, expectWhatever
5
+ , Error(..)
6
+ , request
7
+ , Body, emptyBody, stringBody, jsonBody, bytesBody
8
+ , getWithOptions
9
+ , CacheStrategy(..)
10
+ , withMetadata, Metadata
11
+ )
12
+
13
+ {-| `BackendTask.Http` requests are an alternative to doing Elm HTTP requests the traditional way using the `elm/http` package.
14
+
15
+ The key differences are:
16
+
17
+ - `BackendTask.Http.Request`s are performed once at build time (`Http.Request`s are performed at runtime, at whenever point you perform them)
18
+ - `BackendTask.Http.Request`s have a built-in `BackendTask.andThen` that allows you to perform follow-up requests without using tasks
19
+
20
+
21
+ ## Scenarios where BackendTask.Http is a good fit
22
+
23
+ If you need data that is refreshed often you may want to do a traditional HTTP request with the `elm/http` package.
24
+ The kinds of situations that are served well by static HTTP are with data that updates moderately frequently or infrequently (or never).
25
+ A common pattern is to trigger a new build when data changes. Many JAMstack services
26
+ allow you to send a WebHook to your host (for example, Netlify is a good static file host that supports triggering builds with webhooks). So
27
+ you may want to have your site rebuild everytime your calendar feed has an event added, or whenever a page or article is added
28
+ or updated on a CMS service like Contentful.
29
+
30
+ In scenarios like this, you can serve data that is just as up-to-date as it would be using `elm/http`, but you get the performance
31
+ gains of using `BackendTask.Http.Request`s as well as the simplicity and robustness that comes with it. Read more about these benefits
32
+ in [this article introducing BackendTask.Http requests and some concepts around it](https://elm-pages.com/blog/static-http).
33
+
34
+
35
+ ## Scenarios where BackendTask.Http is not a good fit
36
+
37
+ - Data that is specific to the logged-in user
38
+ - Data that needs to be the very latest and changes often (for example, sports scores)
39
+
40
+
41
+ ## Making a Request
42
+
43
+ @docs get, getJson
44
+
45
+ @docs post
46
+
47
+
48
+ ## Decoding Request Body
49
+
50
+ @docs Expect, expectString, expectJson, expectBytes, expectWhatever
51
+
52
+
53
+ ## Error Handling
54
+
55
+ @docs Error
56
+
57
+
58
+ ## General Requests
59
+
60
+ @docs request
61
+
62
+
63
+ ## Building a BackendTask.Http Request Body
64
+
65
+ The way you build a body is analogous to the `elm/http` package. Currently, only `emptyBody` and
66
+ `stringBody` are supported. If you have a use case that calls for a different body type, please open a Github issue
67
+ and describe your use case!
68
+
69
+ @docs Body, emptyBody, stringBody, jsonBody, bytesBody
70
+
71
+
72
+ ## Caching Options
73
+
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.
90
+
91
+ @docs getWithOptions
92
+
93
+ @docs CacheStrategy
94
+
95
+
96
+ ## Including HTTP Metadata
97
+
98
+ @docs withMetadata, Metadata
99
+
100
+ -}
101
+
102
+ import BackendTask exposing (BackendTask)
103
+ import Base64
104
+ import Bytes exposing (Bytes)
105
+ import Bytes.Decode
106
+ import Dict exposing (Dict)
107
+ import FatalError exposing (FatalError)
108
+ import Json.Decode
109
+ import Json.Encode as Encode
110
+ import Pages.Internal.StaticHttpBody as Body
111
+ import Pages.StaticHttp.Request as HashRequest
112
+ import Pages.StaticHttpRequest exposing (RawRequest(..))
113
+ import RequestsAndPending
114
+ import TerminalText
115
+
116
+
117
+ {-| Build an empty body for a BackendTask.Http request. See [elm/http's `Http.emptyBody`](https://package.elm-lang.org/packages/elm/http/latest/Http#emptyBody).
118
+ -}
119
+ emptyBody : Body
120
+ emptyBody =
121
+ Body.EmptyBody
122
+
123
+
124
+ {-| Build a body from `Bytes` for a BackendTask.Http request. See [elm/http's `Http.bytesBody`](https://package.elm-lang.org/packages/elm/http/latest/Http#bytesBody).
125
+ -}
126
+ bytesBody : String -> Bytes -> Body
127
+ bytesBody =
128
+ Body.BytesBody
129
+
130
+
131
+ {-| Builds a string body for a BackendTask.Http request. See [elm/http's `Http.stringBody`](https://package.elm-lang.org/packages/elm/http/latest/Http#stringBody).
132
+
133
+ Note from the `elm/http` docs:
134
+
135
+ > The first argument is a [MIME type](https://en.wikipedia.org/wiki/Media_type) of the body. Some servers are strict about this!
136
+
137
+ -}
138
+ stringBody : String -> String -> Body
139
+ stringBody contentType content =
140
+ Body.StringBody contentType content
141
+
142
+
143
+ {-| Builds a JSON body for a BackendTask.Http request. See [elm/http's `Http.jsonBody`](https://package.elm-lang.org/packages/elm/http/latest/Http#jsonBody).
144
+ -}
145
+ jsonBody : Encode.Value -> Body
146
+ jsonBody content =
147
+ Body.JsonBody content
148
+
149
+
150
+ {-| A body for a BackendTask.Http request.
151
+ -}
152
+ type alias Body =
153
+ Body.Body
154
+
155
+
156
+ {-| A simplified helper around [`BackendTask.Http.get`](#get), which builds up a BackendTask.Http GET request with `expectJson`.
157
+
158
+ import BackendTask
159
+ import BackendTask.Http
160
+ import FatalError exposing (FatalError)
161
+ import Json.Decode as Decode exposing (Decoder)
162
+
163
+ getRequest : BackendTask (FatalError Error) Int
164
+ getRequest =
165
+ BackendTask.Http.getJson
166
+ "https://api.github.com/repos/dillonkearns/elm-pages"
167
+ (Decode.field "stargazers_count" Decode.int)
168
+
169
+ -}
170
+ getJson :
171
+ String
172
+ -> Json.Decode.Decoder a
173
+ -> BackendTask { fatal : FatalError, recoverable : Error } a
174
+ getJson url decoder =
175
+ getWithOptions
176
+ { url = url
177
+ , expect = expectJson decoder
178
+ , headers = []
179
+ , timeoutInMs = Nothing
180
+ , retries = Nothing
181
+ , cacheStrategy = Nothing
182
+ , cachePath = Nothing
183
+ }
184
+
185
+
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 FatalError exposing (FatalError)
193
+
194
+ getRequest : BackendTask (FatalError Error) String
195
+ getRequest =
196
+ BackendTask.Http.get
197
+ "https://api.github.com/repos/dillonkearns/elm-pages"
198
+ BackendTask.Http.expectString
199
+
200
+ -}
201
+ get :
202
+ String
203
+ -> Expect a
204
+ -> BackendTask { fatal : FatalError, recoverable : Error } a
205
+ get url expect =
206
+ getWithOptions
207
+ { url = url
208
+ , expect = expect
209
+ , headers = []
210
+ , timeoutInMs = Nothing
211
+ , retries = Nothing
212
+ , cacheStrategy = Nothing
213
+ , cachePath = Nothing
214
+ }
215
+
216
+
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
+
224
+ -}
225
+ getWithOptions :
226
+ { url : String
227
+ , expect : Expect a
228
+ , headers : List ( String, String )
229
+ , cacheStrategy : Maybe CacheStrategy
230
+ , retries : Maybe Int
231
+ , timeoutInMs : Maybe Int
232
+ , cachePath : Maybe String
233
+ }
234
+ -> BackendTask { fatal : FatalError, recoverable : Error } a
235
+ getWithOptions request__ =
236
+ let
237
+ request_ : HashRequest.Request
238
+ request_ =
239
+ { url = request__.url
240
+ , headers = request__.headers
241
+ , body = emptyBody
242
+ , method = "GET"
243
+ , cacheOptions =
244
+ { cacheStrategy = request__.cacheStrategy
245
+ , retries = request__.retries
246
+ , timeoutInMs = request__.timeoutInMs
247
+ , cachePath = request__.cachePath
248
+ }
249
+ |> encodeOptions
250
+ |> Just
251
+ }
252
+ in
253
+ requestRaw request_ request__.expect
254
+
255
+
256
+ {-| -}
257
+ post :
258
+ String
259
+ -> Body
260
+ -> Expect a
261
+ -> BackendTask { fatal : FatalError, recoverable : Error } a
262
+ post url body expect =
263
+ request
264
+ { url = url
265
+ , method = "POST"
266
+ , headers = []
267
+ , body = body
268
+ , retries = Nothing
269
+ , timeoutInMs = Nothing
270
+ }
271
+ expect
272
+
273
+
274
+ {-| Analogous to the `Expect` type in the `elm/http` package. This represents how you will process the data that comes
275
+ back in your BackendTask.Http request.
276
+
277
+ You can derive `ExpectJson` from `ExpectString`. Or you could build your own helper to process the String
278
+ as XML, for example, or give an `elm-pages` build error if the response can't be parsed as XML.
279
+
280
+ -}
281
+ type Expect value
282
+ = ExpectJson (Json.Decode.Decoder value)
283
+ | ExpectString (String -> value)
284
+ | ExpectBytes (Bytes.Decode.Decoder value)
285
+ | ExpectWhatever value
286
+ | ExpectMetadata (Metadata -> Expect value)
287
+
288
+
289
+ {-| Gives the HTTP response body as a raw String.
290
+
291
+ import BackendTask exposing (BackendTask)
292
+ import BackendTask.Http
293
+
294
+ request : BackendTask String
295
+ request =
296
+ BackendTask.Http.request
297
+ { url = "https://example.com/file.txt"
298
+ , method = "GET"
299
+ , headers = []
300
+ , body = BackendTask.Http.emptyBody
301
+ }
302
+ BackendTask.Http.expectString
303
+
304
+ -}
305
+ expectString : Expect String
306
+ expectString =
307
+ ExpectString identity
308
+
309
+
310
+ {-| Handle the incoming response as JSON and don't optimize the asset and strip out unused values.
311
+ Be sure to use the `BackendTask.Http.request` function if you want an optimized request that
312
+ strips out unused JSON to optimize your asset size. This function makes sense to use for things like a GraphQL request
313
+ where the JSON payload is already trimmed down to the data you explicitly requested.
314
+
315
+ If the function you pass to `expectString` yields an `Err`, then you will get a build error that will
316
+ fail your `elm-pages` build and print out the String from the `Err`.
317
+
318
+ -}
319
+ expectJson : Json.Decode.Decoder value -> Expect value
320
+ expectJson =
321
+ ExpectJson
322
+
323
+
324
+ {-| -}
325
+ withMetadata : (Metadata -> value -> combined) -> Expect value -> Expect combined
326
+ withMetadata combineFn originalExpect =
327
+ -- known-unoptimized-recursion
328
+ case originalExpect of
329
+ ExpectJson jsonDecoder ->
330
+ ExpectMetadata (\metadata -> ExpectJson (jsonDecoder |> Json.Decode.map (combineFn metadata)))
331
+
332
+ ExpectString stringToValue ->
333
+ ExpectMetadata
334
+ (\metadata ->
335
+ ExpectString (\string -> string |> stringToValue |> combineFn metadata)
336
+ )
337
+
338
+ ExpectBytes bytesDecoder ->
339
+ ExpectMetadata (\metadata -> ExpectBytes (bytesDecoder |> Bytes.Decode.map (combineFn metadata)))
340
+
341
+ ExpectWhatever value ->
342
+ ExpectMetadata (\metadata -> ExpectWhatever (combineFn metadata value))
343
+
344
+ ExpectMetadata metadataToExpect ->
345
+ ExpectMetadata (\metadata -> withMetadata combineFn (metadataToExpect metadata))
346
+
347
+
348
+ {-| -}
349
+ expectBytes : Bytes.Decode.Decoder value -> Expect value
350
+ expectBytes =
351
+ ExpectBytes
352
+
353
+
354
+ {-| -}
355
+ expectWhatever : value -> Expect value
356
+ expectWhatever =
357
+ ExpectWhatever
358
+
359
+
360
+ expectToString : Expect a -> String
361
+ expectToString expect =
362
+ -- known-unoptimized-recursion
363
+ case expect of
364
+ ExpectJson _ ->
365
+ "ExpectJson"
366
+
367
+ ExpectString _ ->
368
+ "ExpectString"
369
+
370
+ ExpectBytes _ ->
371
+ "ExpectBytes"
372
+
373
+ ExpectWhatever _ ->
374
+ "ExpectWhatever"
375
+
376
+ ExpectMetadata toExpect ->
377
+ -- It's safe to call this with fake metadata to get the kind of Expect because the exposed
378
+ -- API, `withMetadata`, will never change the type of Expect it returns based on the metadata, it simply
379
+ -- wraps the Expect with the additional Metadata.
380
+ -- It's important not to expose the raw `ExpectMetadata` constructor however because that would break that guarantee.
381
+ toExpect
382
+ { url = ""
383
+ , statusCode = 123
384
+ , statusText = ""
385
+ , headers = Dict.empty
386
+ }
387
+ |> expectToString
388
+
389
+
390
+ {-| -}
391
+ request :
392
+ { url : String
393
+ , method : String
394
+ , headers : List ( String, String )
395
+ , body : Body
396
+ , retries : Maybe Int
397
+ , timeoutInMs : Maybe Int
398
+ }
399
+ -> Expect a
400
+ -> BackendTask { fatal : FatalError, recoverable : Error } a
401
+ request request__ expect =
402
+ let
403
+ request_ : HashRequest.Request
404
+ request_ =
405
+ { url = request__.url
406
+ , headers = request__.headers
407
+ , method = request__.method
408
+ , body = request__.body
409
+ , cacheOptions =
410
+ { cacheStrategy = Nothing -- cache strategy only applies to GET and HEAD, need to use getWithOptions to customize
411
+ , cachePath = Nothing
412
+ , retries = request__.retries
413
+ , timeoutInMs = request__.timeoutInMs
414
+ }
415
+ |> encodeOptions
416
+ |> Just
417
+ }
418
+ in
419
+ requestRaw request_ expect
420
+
421
+
422
+ {-| -}
423
+ type CacheStrategy
424
+ = IgnoreCache -- 'no-store'
425
+ | ForceRevalidate -- 'no-cache'
426
+ | ForceReload -- 'reload'
427
+ | ForceCache -- 'force-cache'
428
+ | ErrorUnlessCached -- 'only-if-cached'
429
+
430
+
431
+ encodeOptions :
432
+ { cacheStrategy : Maybe CacheStrategy
433
+ , cachePath : Maybe String
434
+ , retries : Maybe Int
435
+ , timeoutInMs : Maybe Int
436
+ }
437
+ -> Encode.Value
438
+ encodeOptions options =
439
+ Encode.object
440
+ ([ ( "cache"
441
+ , options.cacheStrategy
442
+ |> Maybe.map
443
+ (\cacheStrategy ->
444
+ case cacheStrategy of
445
+ IgnoreCache ->
446
+ "no-store"
447
+
448
+ ForceRevalidate ->
449
+ "no-cache"
450
+
451
+ ForceReload ->
452
+ "reload"
453
+
454
+ ForceCache ->
455
+ "force-cache"
456
+
457
+ ErrorUnlessCached ->
458
+ "only-if-cached"
459
+ )
460
+ |> Maybe.map Encode.string
461
+ )
462
+ , ( "retry", options.retries |> Maybe.map Encode.int )
463
+ , ( "timeout", options.timeoutInMs |> Maybe.map Encode.int )
464
+ , ( "cachePath", options.cachePath |> Maybe.map Encode.string )
465
+ ]
466
+ |> List.filterMap
467
+ (\( a, b ) -> b |> Maybe.map (Tuple.pair a))
468
+ )
469
+
470
+
471
+ {-| Build a `BackendTask.Http` request (analogous to [Http.request](https://package.elm-lang.org/packages/elm/http/latest/Http#request)).
472
+ This function takes in all the details to build a `BackendTask.Http` request, but you can build your own simplified helper functions
473
+ with this as a low-level detail, or you can use functions like [BackendTask.Http.get](#get).
474
+ -}
475
+ requestRaw :
476
+ HashRequest.Request
477
+ -> Expect a
478
+ -> BackendTask { fatal : FatalError, recoverable : Error } a
479
+ requestRaw request__ expect =
480
+ let
481
+ request_ : HashRequest.Request
482
+ request_ =
483
+ { url = request__.url
484
+ , headers =
485
+ ( "elm-pages-internal", expectToString expect )
486
+ :: request__.headers
487
+ , method = request__.method
488
+ , body = request__.body
489
+ , cacheOptions = request__.cacheOptions
490
+ }
491
+ in
492
+ Request
493
+ [ request_ ]
494
+ (\maybeMockResolver rawResponseDict ->
495
+ (case maybeMockResolver of
496
+ Just mockResolver ->
497
+ mockResolver request_ |> Maybe.map Ok
498
+
499
+ Nothing ->
500
+ rawResponseDict |> RequestsAndPending.get (request_ |> HashRequest.hash)
501
+ )
502
+ |> (\maybeResponse ->
503
+ case maybeResponse of
504
+ Just (Ok rawResponse) ->
505
+ Ok rawResponse
506
+
507
+ Nothing ->
508
+ --Err (Pages.StaticHttpRequest.UserCalledStaticHttpFail ("INTERNAL ERROR - expected request" ++ request_.url))
509
+ Err (BadBody Nothing ("INTERNAL ERROR - expected request" ++ request_.url))
510
+
511
+ Just (Err RequestsAndPending.NetworkError) ->
512
+ Err NetworkError
513
+
514
+ Just (Err RequestsAndPending.Timeout) ->
515
+ Err Timeout
516
+ )
517
+ |> Result.andThen
518
+ (\(RequestsAndPending.Response maybeResponse body) ->
519
+ let
520
+ maybeBadResponse : Maybe Error
521
+ maybeBadResponse =
522
+ case maybeResponse of
523
+ Just response ->
524
+ if not (response.statusCode >= 200 && response.statusCode < 300) then
525
+ case body of
526
+ RequestsAndPending.StringBody s ->
527
+ BadStatus
528
+ { url = response.url
529
+ , statusCode = response.statusCode
530
+ , statusText = response.statusText
531
+ , headers = response.headers
532
+ }
533
+ s
534
+ |> Just
535
+
536
+ RequestsAndPending.BytesBody bytes ->
537
+ BadStatus
538
+ { url = response.url
539
+ , statusCode = response.statusCode
540
+ , statusText = response.statusText
541
+ , headers = response.headers
542
+ }
543
+ (Base64.fromBytes bytes |> Maybe.withDefault "")
544
+ |> Just
545
+
546
+ RequestsAndPending.JsonBody value ->
547
+ BadStatus
548
+ { url = response.url
549
+ , statusCode = response.statusCode
550
+ , statusText = response.statusText
551
+ , headers = response.headers
552
+ }
553
+ (Encode.encode 0 value)
554
+ |> Just
555
+
556
+ RequestsAndPending.WhateverBody ->
557
+ BadStatus
558
+ { url = response.url
559
+ , statusCode = response.statusCode
560
+ , statusText = response.statusText
561
+ , headers = response.headers
562
+ }
563
+ ""
564
+ |> Just
565
+
566
+ else
567
+ Nothing
568
+
569
+ Nothing ->
570
+ Nothing
571
+ in
572
+ case maybeBadResponse of
573
+ Just badResponse ->
574
+ Err badResponse
575
+
576
+ Nothing ->
577
+ toResultThing ( expect, body, maybeResponse )
578
+ )
579
+ |> BackendTask.fromResult
580
+ |> BackendTask.mapError
581
+ (\error ->
582
+ FatalError.recoverable (errorToString error) error
583
+ )
584
+ )
585
+
586
+
587
+ toResultThing :
588
+ ( Expect value
589
+ , RequestsAndPending.ResponseBody
590
+ , Maybe RequestsAndPending.RawResponse
591
+ )
592
+ -> Result Error value
593
+ toResultThing ( expect, body, maybeResponse ) =
594
+ case ( expect, body, maybeResponse ) of
595
+ ( ExpectMetadata toExpect, _, Just rawResponse ) ->
596
+ let
597
+ asMetadata : Metadata
598
+ asMetadata =
599
+ { url = rawResponse.url
600
+ , statusCode = rawResponse.statusCode
601
+ , statusText = rawResponse.statusText
602
+ , headers = rawResponse.headers
603
+ }
604
+ in
605
+ toResultThing ( toExpect asMetadata, body, maybeResponse )
606
+
607
+ ( ExpectJson decoder, RequestsAndPending.JsonBody json, _ ) ->
608
+ json
609
+ |> Json.Decode.decodeValue decoder
610
+ |> Result.mapError
611
+ (\error ->
612
+ error
613
+ |> Json.Decode.errorToString
614
+ |> BadBody (Just error)
615
+ )
616
+
617
+ ( ExpectString mapStringFn, RequestsAndPending.StringBody string, _ ) ->
618
+ string
619
+ |> mapStringFn
620
+ |> Ok
621
+
622
+ ( ExpectBytes bytesDecoder, RequestsAndPending.BytesBody rawBytes, _ ) ->
623
+ rawBytes
624
+ |> Bytes.Decode.decode bytesDecoder
625
+ |> Result.fromMaybe
626
+ (BadBody Nothing "Bytes decoding failed.")
627
+
628
+ ( ExpectWhatever whateverValue, RequestsAndPending.WhateverBody, _ ) ->
629
+ Ok whateverValue
630
+
631
+ _ ->
632
+ Err (BadBody Nothing "Unexpected combination, internal error")
633
+
634
+
635
+ errorToString : Error -> { title : String, body : String }
636
+ errorToString error =
637
+ { title = "HTTP Error"
638
+ , body =
639
+ (case error of
640
+ BadUrl string ->
641
+ [ TerminalText.text ("BadUrl " ++ string)
642
+ ]
643
+
644
+ Timeout ->
645
+ [ TerminalText.text "Timeout"
646
+ ]
647
+
648
+ NetworkError ->
649
+ [ TerminalText.text "NetworkError"
650
+ ]
651
+
652
+ BadStatus _ string ->
653
+ [ TerminalText.text ("BadStatus: " ++ string)
654
+ ]
655
+
656
+ BadBody _ string ->
657
+ [ TerminalText.text ("BadBody: " ++ string)
658
+ ]
659
+ )
660
+ |> TerminalText.toString
661
+ }
662
+
663
+
664
+ {-| -}
665
+ type alias Metadata =
666
+ { url : String
667
+ , statusCode : Int
668
+ , statusText : String
669
+ , headers : Dict String String
670
+ }
671
+
672
+
673
+ {-| -}
674
+ type Error
675
+ = BadUrl String
676
+ | Timeout
677
+ | NetworkError
678
+ | BadStatus Metadata String
679
+ | BadBody (Maybe Json.Decode.Error) String
@@ -1,4 +1,4 @@
1
- module DataSource.Internal.Glob exposing
1
+ module BackendTask.Internal.Glob exposing
2
2
  ( Glob(..)
3
3
  , extractMatches
4
4
  , run