elm-pages 3.0.0-beta.2 → 3.0.0-beta.20
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 +10 -1
- package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2420 -1592
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15215 -13007
- 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/dead-code-review/elm.json +8 -6
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +189 -17
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +255 -21
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14620 -12636
- 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/review/elm.json +8 -8
- package/generator/src/RouteBuilder.elm +66 -52
- package/generator/src/SharedTemplate.elm +3 -2
- package/generator/src/SiteConfig.elm +3 -2
- package/generator/src/basepath-middleware.js +3 -3
- package/generator/src/build.js +122 -86
- package/generator/src/cli.js +247 -51
- package/generator/src/codegen.js +29 -27
- package/generator/src/compatibility-key.js +1 -0
- package/generator/src/compile-elm.js +20 -22
- package/generator/src/config.js +39 -0
- package/generator/src/copy-dir.js +2 -2
- package/generator/src/dev-server.js +119 -110
- package/generator/src/dir-helpers.js +9 -26
- package/generator/src/elm-codegen.js +5 -4
- package/generator/src/elm-file-constants.js +2 -3
- package/generator/src/error-formatter.js +12 -11
- package/generator/src/file-helpers.js +3 -4
- package/generator/src/generate-template-module-connector.js +14 -21
- package/generator/src/init.js +8 -7
- package/generator/src/pre-render-html.js +41 -28
- package/generator/src/render-test.js +109 -0
- package/generator/src/render-worker.js +26 -28
- package/generator/src/render.js +322 -142
- package/generator/src/request-cache.js +200 -162
- package/generator/src/rewrite-client-elm-json.js +5 -5
- package/generator/src/rewrite-elm-json.js +7 -7
- package/generator/src/route-codegen-helpers.js +16 -31
- package/generator/src/seo-renderer.js +12 -7
- package/generator/src/vite-utils.js +77 -0
- package/generator/static-code/hmr.js +16 -2
- package/generator/template/app/Api.elm +3 -3
- package/generator/template/app/Route/Index.elm +3 -3
- package/generator/template/app/Shared.elm +3 -3
- package/generator/template/app/Site.elm +9 -4
- package/package.json +21 -21
- package/src/ApiRoute.elm +199 -61
- package/src/BackendTask/Custom.elm +214 -0
- package/src/BackendTask/Env.elm +90 -0
- package/src/{DataSource → BackendTask}/File.elm +128 -43
- package/src/{DataSource → BackendTask}/Glob.elm +136 -125
- package/src/BackendTask/Http.elm +673 -0
- package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
- package/src/BackendTask/Internal/Request.elm +28 -0
- package/src/BackendTask/Random.elm +79 -0
- package/src/BackendTask/Time.elm +47 -0
- package/src/BackendTask.elm +537 -0
- package/src/FatalError.elm +89 -0
- package/src/Form/Field.elm +1 -1
- package/src/Form.elm +72 -92
- package/src/Head/Seo.elm +4 -4
- package/src/Head.elm +237 -7
- package/src/HtmlPrinter.elm +7 -3
- package/src/Internal/ApiRoute.elm +7 -5
- package/src/PageServerResponse.elm +6 -1
- package/src/Pages/Generate.elm +775 -132
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Form.elm +21 -1
- package/src/Pages/Internal/Platform/Cli.elm +479 -747
- package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
- package/src/Pages/Internal/Platform/Effect.elm +1 -2
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +373 -0
- package/src/Pages/Internal/Platform/StaticResponses.elm +73 -270
- package/src/Pages/Internal/Platform/ToJsPayload.elm +4 -7
- package/src/Pages/Internal/Platform.elm +54 -53
- package/src/Pages/Internal/Script.elm +17 -0
- package/src/Pages/Internal/StaticHttpBody.elm +35 -1
- package/src/Pages/Manifest.elm +29 -4
- package/src/Pages/ProgramConfig.elm +12 -8
- package/src/Pages/Script.elm +109 -0
- package/src/Pages/SiteConfig.elm +3 -2
- package/src/Pages/StaticHttp/Request.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +23 -98
- package/src/RequestsAndPending.elm +8 -19
- package/src/Result/Extra.elm +21 -0
- package/src/Server/Request.elm +43 -34
- package/src/Server/Session.elm +166 -100
- package/src/Server/SetCookie.elm +89 -31
- package/src/DataSource/Env.elm +0 -38
- package/src/DataSource/Http.elm +0 -446
- package/src/DataSource/Internal/Request.elm +0 -20
- package/src/DataSource/Port.elm +0 -90
- package/src/DataSource.elm +0 -538
|
@@ -45,11 +45,6 @@ import Time
|
|
|
45
45
|
import Url exposing (Url)
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
type Transition
|
|
49
|
-
= Loading Int Path
|
|
50
|
-
| Submitting FormData
|
|
51
|
-
|
|
52
|
-
|
|
53
48
|
{-| -}
|
|
54
49
|
type alias Program userModel userMsg pageData actionData sharedData errorPage =
|
|
55
50
|
Platform.Program Flags (Model userModel pageData actionData sharedData) (Msg userMsg pageData actionData sharedData errorPage)
|
|
@@ -423,16 +418,14 @@ update config appMsg model =
|
|
|
423
418
|
)
|
|
424
419
|
|
|
425
420
|
else
|
|
426
|
-
(
|
|
427
|
-
| url = url
|
|
428
|
-
}
|
|
421
|
+
( model
|
|
429
422
|
, NoEffect
|
|
430
423
|
)
|
|
431
424
|
-- TODO is it reasonable to always re-fetch route data if you re-navigate to the current route? Might be a good
|
|
432
425
|
-- parallel to the browser behavior
|
|
433
426
|
|> startNewGetLoad url (UpdateCacheAndUrlNew True url Nothing)
|
|
434
427
|
|
|
435
|
-
FetcherComplete
|
|
428
|
+
FetcherComplete _ fetcherKey _ userMsgResult ->
|
|
436
429
|
case userMsgResult of
|
|
437
430
|
Ok ( userMsg, maybeFetcherDoneActionData ) ->
|
|
438
431
|
( { model
|
|
@@ -605,27 +598,32 @@ update config appMsg model =
|
|
|
605
598
|
, actionData = newActionData
|
|
606
599
|
}
|
|
607
600
|
|
|
608
|
-
( userModel,
|
|
601
|
+
( userModel, userEffect ) =
|
|
609
602
|
-- TODO if urlWithoutRedirectResolution is different from the url with redirect resolution, then
|
|
610
603
|
-- instead of calling update, call pushUrl (I think?)
|
|
611
604
|
-- TODO include user Cmd
|
|
612
|
-
|
|
613
|
-
(
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
605
|
+
if stayingOnSamePath then
|
|
606
|
+
( previousPageData.userModel, NoEffect )
|
|
607
|
+
|
|
608
|
+
else
|
|
609
|
+
config.update model.pageFormState
|
|
610
|
+
(model.inFlightFetchers |> toFetcherState)
|
|
611
|
+
(model.transition |> Maybe.map Tuple.second)
|
|
612
|
+
newSharedData
|
|
613
|
+
newPageData
|
|
614
|
+
model.key
|
|
615
|
+
(config.onPageChange
|
|
616
|
+
{ protocol = model.url.protocol
|
|
617
|
+
, host = model.url.host
|
|
618
|
+
, port_ = model.url.port_
|
|
619
|
+
, path = urlPathToPath urlWithoutRedirectResolution
|
|
620
|
+
, query = urlWithoutRedirectResolution.query
|
|
621
|
+
, fragment = urlWithoutRedirectResolution.fragment
|
|
622
|
+
, metadata = config.urlToRoute urlWithoutRedirectResolution
|
|
623
|
+
}
|
|
624
|
+
)
|
|
625
|
+
previousPageData.userModel
|
|
626
|
+
|> Tuple.mapSecond UserCmd
|
|
629
627
|
|
|
630
628
|
updatedModel : Model userModel pageData actionData sharedData
|
|
631
629
|
updatedModel =
|
|
@@ -656,10 +654,13 @@ update config appMsg model =
|
|
|
656
654
|
, currentPath = newUrl.path
|
|
657
655
|
}
|
|
658
656
|
, if not stayingOnSamePath && scrollToTopWhenDone then
|
|
659
|
-
|
|
657
|
+
Batch
|
|
658
|
+
[ ScrollToTop
|
|
659
|
+
, userEffect
|
|
660
|
+
]
|
|
660
661
|
|
|
661
662
|
else
|
|
662
|
-
|
|
663
|
+
userEffect
|
|
663
664
|
)
|
|
664
665
|
|> (case maybeUserMsg of
|
|
665
666
|
Just userMsg ->
|
|
@@ -679,10 +680,10 @@ update config appMsg model =
|
|
|
679
680
|
Err _ ->
|
|
680
681
|
{-
|
|
681
682
|
When there is an error loading the content.dat, we are either
|
|
682
|
-
1) in the dev server, and should show the relevant
|
|
683
|
+
1) in the dev server, and should show the relevant BackendTask error for the page
|
|
683
684
|
we're navigating to. This could be done more cleanly, but it's simplest to just
|
|
684
685
|
do a fresh page load and use the code path for presenting an error for a fresh page.
|
|
685
|
-
2) In a production app. That means we had a successful build, so there were no
|
|
686
|
+
2) In a production app. That means we had a successful build, so there were no BackendTask failures,
|
|
686
687
|
so the app must be stale (unless it's in some unexpected state from a bug). In the future,
|
|
687
688
|
it probably makes sense to include some sort of hash of the app version we are fetching, match
|
|
688
689
|
it with the current version that's running, and perform this logic when we see there is a mismatch.
|
|
@@ -766,7 +767,7 @@ update config appMsg model =
|
|
|
766
767
|
toFetcherState : Dict String ( Int, Pages.Transition.FetcherState actionData ) -> Dict String (Pages.Transition.FetcherState actionData)
|
|
767
768
|
toFetcherState inFlightFetchers =
|
|
768
769
|
inFlightFetchers
|
|
769
|
-
|> Dict.map (\_ (
|
|
770
|
+
|> Dict.map (\_ ( _, fetcherState ) -> fetcherState)
|
|
770
771
|
|
|
771
772
|
|
|
772
773
|
performUserMsg :
|
|
@@ -828,7 +829,7 @@ perform config model effect =
|
|
|
828
829
|
|> Maybe.withDefault Cmd.none
|
|
829
830
|
|
|
830
831
|
FetchPageData transitionKey maybeRequestInfo url toMsg ->
|
|
831
|
-
fetchRouteData
|
|
832
|
+
fetchRouteData transitionKey toMsg config url maybeRequestInfo
|
|
832
833
|
|
|
833
834
|
Submit fields ->
|
|
834
835
|
if fields.method == Get then
|
|
@@ -843,7 +844,7 @@ perform config model effect =
|
|
|
843
844
|
-- TODO add optional path parameter to Submit variant to allow submitting to other routes
|
|
844
845
|
model.url
|
|
845
846
|
in
|
|
846
|
-
fetchRouteData
|
|
847
|
+
fetchRouteData -1 (UpdateCacheAndUrlNew False model.url Nothing) config urlToSubmitTo (Just fields)
|
|
847
848
|
|
|
848
849
|
SubmitFetcher fetcherKey transitionId formData ->
|
|
849
850
|
startFetcher2 config False fetcherKey transitionId formData model
|
|
@@ -863,7 +864,7 @@ perform config model effect =
|
|
|
863
864
|
|> config.perform
|
|
864
865
|
{ fetchRouteData =
|
|
865
866
|
\fetchInfo ->
|
|
866
|
-
fetchRouteData
|
|
867
|
+
fetchRouteData
|
|
867
868
|
-1
|
|
868
869
|
(prepare fetchInfo.toMsg)
|
|
869
870
|
config
|
|
@@ -873,7 +874,7 @@ perform config model effect =
|
|
|
873
874
|
---- TODO map the Msg with the wrapper type (like in the PR branch)
|
|
874
875
|
, submit =
|
|
875
876
|
\fetchInfo ->
|
|
876
|
-
fetchRouteData
|
|
877
|
+
fetchRouteData -1 (prepare fetchInfo.toMsg) config (fetchInfo.values.action |> Url.fromString |> Maybe.withDefault model.url) (Just fetchInfo.values)
|
|
877
878
|
, runFetcher =
|
|
878
879
|
\(Pages.Fetcher.Fetcher options) ->
|
|
879
880
|
-- TODO need to get the fetcherId here
|
|
@@ -927,7 +928,7 @@ startFetcher fetcherKey transitionId options model =
|
|
|
927
928
|
Http.expectBytesResponse (FetcherComplete False fetcherKey model.nextTransitionKey)
|
|
928
929
|
(\bytes ->
|
|
929
930
|
case bytes of
|
|
930
|
-
Http.GoodStatus_
|
|
931
|
+
Http.GoodStatus_ _ bytesBody ->
|
|
931
932
|
( options.decoder (Ok bytesBody)
|
|
932
933
|
|> Just
|
|
933
934
|
, Nothing
|
|
@@ -943,7 +944,7 @@ startFetcher fetcherKey transitionId options model =
|
|
|
943
944
|
Http.NetworkError_ ->
|
|
944
945
|
Err <| Http.NetworkError
|
|
945
946
|
|
|
946
|
-
Http.BadStatus_ metadata
|
|
947
|
+
Http.BadStatus_ metadata _ ->
|
|
947
948
|
Err <| Http.BadStatus metadata.statusCode
|
|
948
949
|
)
|
|
949
950
|
, tracker = Nothing
|
|
@@ -974,7 +975,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
974
975
|
Cmd.batch
|
|
975
976
|
[ cancelStaleFetchers model
|
|
976
977
|
, case Dict.get fetcherKey model.inFlightFetchers of
|
|
977
|
-
Just ( inFlightId,
|
|
978
|
+
Just ( inFlightId, _ ) ->
|
|
978
979
|
Http.cancel (String.fromInt inFlightId)
|
|
979
980
|
|
|
980
981
|
Nothing ->
|
|
@@ -985,7 +986,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
985
986
|
Http.expectBytesResponse (FetcherComplete fromPageReload fetcherKey model.nextTransitionKey)
|
|
986
987
|
(\bytes ->
|
|
987
988
|
case bytes of
|
|
988
|
-
Http.GoodStatus_
|
|
989
|
+
Http.GoodStatus_ _ bytesBody ->
|
|
989
990
|
let
|
|
990
991
|
decodedAction : Maybe actionData
|
|
991
992
|
decodedAction =
|
|
@@ -993,10 +994,10 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
993
994
|
Just (ResponseSketch.RenderPage _ maybeAction) ->
|
|
994
995
|
maybeAction
|
|
995
996
|
|
|
996
|
-
Just (ResponseSketch.HotUpdate
|
|
997
|
+
Just (ResponseSketch.HotUpdate _ _ maybeAction) ->
|
|
997
998
|
maybeAction
|
|
998
999
|
|
|
999
|
-
Just (ResponseSketch.NotFound
|
|
1000
|
+
Just (ResponseSketch.NotFound _) ->
|
|
1000
1001
|
Nothing
|
|
1001
1002
|
|
|
1002
1003
|
_ ->
|
|
@@ -1014,7 +1015,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
1014
1015
|
Http.NetworkError_ ->
|
|
1015
1016
|
Err <| Http.NetworkError
|
|
1016
1017
|
|
|
1017
|
-
Http.BadStatus_ metadata
|
|
1018
|
+
Http.BadStatus_ metadata _ ->
|
|
1018
1019
|
Err <| Http.BadStatus metadata.statusCode
|
|
1019
1020
|
)
|
|
1020
1021
|
, tracker = Just (String.fromInt transitionId)
|
|
@@ -1036,7 +1037,7 @@ cancelStaleFetchers model =
|
|
|
1036
1037
|
model.inFlightFetchers
|
|
1037
1038
|
|> Dict.toList
|
|
1038
1039
|
|> List.filterMap
|
|
1039
|
-
(\(
|
|
1040
|
+
(\( _, ( id, fetcher ) ) ->
|
|
1040
1041
|
case fetcher.status of
|
|
1041
1042
|
Pages.Transition.FetcherReloading _ ->
|
|
1042
1043
|
Http.cancel (String.fromInt id)
|
|
@@ -1157,14 +1158,13 @@ urlPathToPath urls =
|
|
|
1157
1158
|
|
|
1158
1159
|
|
|
1159
1160
|
fetchRouteData :
|
|
1160
|
-
|
|
1161
|
-
-> Int
|
|
1161
|
+
Int
|
|
1162
1162
|
-> (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
|
|
1163
1163
|
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
|
|
1164
1164
|
-> Url
|
|
1165
1165
|
-> Maybe FormData
|
|
1166
1166
|
-> Cmd (Msg userMsg pageData actionData sharedData errorPage)
|
|
1167
|
-
fetchRouteData
|
|
1167
|
+
fetchRouteData transitionKey toMsg config url details =
|
|
1168
1168
|
{-
|
|
1169
1169
|
TODO:
|
|
1170
1170
|
- [X] `toMsg` needs a parameter for the callback Msg so it can pass it on if there is a Redirect response
|
|
@@ -1251,7 +1251,7 @@ fetchRouteData forPageDataReload transitionKey toMsg config url details =
|
|
|
1251
1251
|
Http.NetworkError_ ->
|
|
1252
1252
|
Err Http.NetworkError
|
|
1253
1253
|
|
|
1254
|
-
Http.BadStatus_
|
|
1254
|
+
Http.BadStatus_ _ body ->
|
|
1255
1255
|
body
|
|
1256
1256
|
|> Bytes.Decode.decode config.decodeResponse
|
|
1257
1257
|
|> Result.fromMaybe "Decoding error"
|
|
@@ -1303,7 +1303,7 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1303
1303
|
cancelIfStale : Effect userMsg pageData actionData sharedData userEffect errorPage
|
|
1304
1304
|
cancelIfStale =
|
|
1305
1305
|
case model.transition of
|
|
1306
|
-
Just ( transitionKey, Pages.Transition.Loading
|
|
1306
|
+
Just ( transitionKey, Pages.Transition.Loading _ _ ) ->
|
|
1307
1307
|
CancelRequest transitionKey
|
|
1308
1308
|
|
|
1309
1309
|
_ ->
|
|
@@ -1314,13 +1314,13 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1314
1314
|
, transition =
|
|
1315
1315
|
( model.nextTransitionKey
|
|
1316
1316
|
, case model.transition of
|
|
1317
|
-
Just (
|
|
1317
|
+
Just ( _, Pages.Transition.LoadAfterSubmit submitData _ _ ) ->
|
|
1318
1318
|
Pages.Transition.LoadAfterSubmit
|
|
1319
1319
|
submitData
|
|
1320
1320
|
(urlToGet.path |> Path.fromString)
|
|
1321
1321
|
Pages.Transition.Load
|
|
1322
1322
|
|
|
1323
|
-
Just (
|
|
1323
|
+
Just ( _, Pages.Transition.Submitting submitData ) ->
|
|
1324
1324
|
Pages.Transition.LoadAfterSubmit
|
|
1325
1325
|
submitData
|
|
1326
1326
|
(urlToGet.path |> Path.fromString)
|
|
@@ -1392,6 +1392,7 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
|
|
|
1392
1392
|
, actionData = newActionData
|
|
1393
1393
|
}
|
|
1394
1394
|
|
|
1395
|
+
-- TODO use userEffect here?
|
|
1395
1396
|
( userModel, _ ) =
|
|
1396
1397
|
-- TODO if urlWithoutRedirectResolution is different from the url with redirect resolution, then
|
|
1397
1398
|
-- instead of calling update, call pushUrl (I think?)
|
|
@@ -1467,10 +1468,10 @@ loadDataAndUpdateUrl ( newPageData, newSharedData, newActionData ) maybeUserMsg
|
|
|
1467
1468
|
Err _ ->
|
|
1468
1469
|
{-
|
|
1469
1470
|
When there is an error loading the content.dat, we are either
|
|
1470
|
-
1) in the dev server, and should show the relevant
|
|
1471
|
+
1) in the dev server, and should show the relevant BackendTask error for the page
|
|
1471
1472
|
we're navigating to. This could be done more cleanly, but it's simplest to just
|
|
1472
1473
|
do a fresh page load and use the code path for presenting an error for a fresh page.
|
|
1473
|
-
2) In a production app. That means we had a successful build, so there were no
|
|
1474
|
+
2) In a production app. That means we had a successful build, so there were no BackendTask failures,
|
|
1474
1475
|
so the app must be stale (unless it's in some unexpected state from a bug). In the future,
|
|
1475
1476
|
it probably makes sense to include some sort of hash of the app version we are fetching, match
|
|
1476
1477
|
it with the current version that's running, and perform this logic when we see there is a mismatch.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Pages.Internal.Script exposing (Script(..))
|
|
2
|
+
|
|
3
|
+
import BackendTask exposing (BackendTask)
|
|
4
|
+
import Cli.Program as Program
|
|
5
|
+
import FatalError exposing (FatalError)
|
|
6
|
+
import Html exposing (Html)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
{-| -}
|
|
10
|
+
type Script
|
|
11
|
+
= Script
|
|
12
|
+
((Maybe { indent : Int, newLines : Bool }
|
|
13
|
+
-> Html Never
|
|
14
|
+
-> String
|
|
15
|
+
)
|
|
16
|
+
-> Program.Config (BackendTask FatalError ())
|
|
17
|
+
)
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module Pages.Internal.StaticHttpBody exposing (Body(..), codec, encode)
|
|
2
2
|
|
|
3
|
+
import Base64
|
|
4
|
+
import Bytes exposing (Bytes)
|
|
3
5
|
import Codec exposing (Codec)
|
|
6
|
+
import Json.Decode
|
|
4
7
|
import Json.Encode as Encode
|
|
5
8
|
|
|
6
9
|
|
|
@@ -8,6 +11,7 @@ type Body
|
|
|
8
11
|
= EmptyBody
|
|
9
12
|
| StringBody String String
|
|
10
13
|
| JsonBody Encode.Value
|
|
14
|
+
| BytesBody String Bytes
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
encode : Body -> Encode.Value
|
|
@@ -26,6 +30,15 @@ encode body =
|
|
|
26
30
|
[ ( "content", content )
|
|
27
31
|
]
|
|
28
32
|
|
|
33
|
+
BytesBody _ content ->
|
|
34
|
+
encodeWithType "bytes"
|
|
35
|
+
[ ( "content"
|
|
36
|
+
, Base64.fromBytes content
|
|
37
|
+
|> Maybe.withDefault ""
|
|
38
|
+
|> Encode.string
|
|
39
|
+
)
|
|
40
|
+
]
|
|
41
|
+
|
|
29
42
|
|
|
30
43
|
encodeWithType : String -> List ( String, Encode.Value ) -> Encode.Value
|
|
31
44
|
encodeWithType typeName otherFields =
|
|
@@ -37,7 +50,7 @@ encodeWithType typeName otherFields =
|
|
|
37
50
|
codec : Codec Body
|
|
38
51
|
codec =
|
|
39
52
|
Codec.custom
|
|
40
|
-
(\vEmpty vString vJson value ->
|
|
53
|
+
(\vEmpty vString vJson vBytes value ->
|
|
41
54
|
case value of
|
|
42
55
|
EmptyBody ->
|
|
43
56
|
vEmpty
|
|
@@ -47,8 +60,29 @@ codec =
|
|
|
47
60
|
|
|
48
61
|
JsonBody body ->
|
|
49
62
|
vJson body
|
|
63
|
+
|
|
64
|
+
BytesBody contentType body ->
|
|
65
|
+
vBytes contentType body
|
|
50
66
|
)
|
|
51
67
|
|> Codec.variant0 "EmptyBody" EmptyBody
|
|
52
68
|
|> Codec.variant2 "StringBody" StringBody Codec.string Codec.string
|
|
53
69
|
|> Codec.variant1 "JsonBody" JsonBody Codec.value
|
|
70
|
+
|> Codec.variant2 "BytesBody" BytesBody Codec.string bytesCodec
|
|
54
71
|
|> Codec.buildCustom
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
bytesCodec : Codec Bytes
|
|
75
|
+
bytesCodec =
|
|
76
|
+
Codec.build (Base64.fromBytes >> Maybe.withDefault "" >> Encode.string)
|
|
77
|
+
(Json.Decode.string
|
|
78
|
+
|> Json.Decode.map Base64.toBytes
|
|
79
|
+
|> Json.Decode.andThen
|
|
80
|
+
(\decodedBytes ->
|
|
81
|
+
case decodedBytes of
|
|
82
|
+
Just bytes ->
|
|
83
|
+
Json.Decode.succeed bytes
|
|
84
|
+
|
|
85
|
+
Nothing ->
|
|
86
|
+
Json.Decode.fail "Couldn't parse bytes."
|
|
87
|
+
)
|
|
88
|
+
)
|
package/src/Pages/Manifest.elm
CHANGED
|
@@ -2,6 +2,7 @@ module Pages.Manifest exposing
|
|
|
2
2
|
( Config, Icon
|
|
3
3
|
, init
|
|
4
4
|
, withBackgroundColor, withCategories, withDisplayMode, withIarcRatingId, withLang, withOrientation, withShortName, withThemeColor
|
|
5
|
+
, withField
|
|
5
6
|
, DisplayMode(..), Orientation(..), IconPurpose(..)
|
|
6
7
|
, generator
|
|
7
8
|
, toJson
|
|
@@ -41,6 +42,11 @@ You pass your `Pages.Manifest.Config` record into the `Pages.application` functi
|
|
|
41
42
|
@docs withBackgroundColor, withCategories, withDisplayMode, withIarcRatingId, withLang, withOrientation, withShortName, withThemeColor
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
## Arbitrary Fields Escape Hatch
|
|
46
|
+
|
|
47
|
+
@docs withField
|
|
48
|
+
|
|
49
|
+
|
|
44
50
|
## Config options
|
|
45
51
|
|
|
46
52
|
@docs DisplayMode, Orientation, IconPurpose
|
|
@@ -58,9 +64,11 @@ You pass your `Pages.Manifest.Config` record into the `Pages.application` functi
|
|
|
58
64
|
-}
|
|
59
65
|
|
|
60
66
|
import ApiRoute
|
|
67
|
+
import BackendTask exposing (BackendTask)
|
|
61
68
|
import Color exposing (Color)
|
|
62
69
|
import Color.Convert
|
|
63
|
-
import
|
|
70
|
+
import Dict exposing (Dict)
|
|
71
|
+
import FatalError exposing (FatalError)
|
|
64
72
|
import Head
|
|
65
73
|
import Json.Encode as Encode
|
|
66
74
|
import LanguageTag exposing (LanguageTag, emptySubtags)
|
|
@@ -123,6 +131,7 @@ init options =
|
|
|
123
131
|
, shortName = Nothing
|
|
124
132
|
, icons = options.icons
|
|
125
133
|
, lang = usEnglish
|
|
134
|
+
, otherFields = Dict.empty
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
|
|
@@ -191,6 +200,17 @@ withLang languageTag config =
|
|
|
191
200
|
{ config | lang = languageTag }
|
|
192
201
|
|
|
193
202
|
|
|
203
|
+
{-| Escape hatch for specifying fields that aren't exposed through this module otherwise. The possible supported properties
|
|
204
|
+
in a manifest file can change over time, so see [MDN manifest.json docs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json)
|
|
205
|
+
for a full listing of the current supported properties.
|
|
206
|
+
-}
|
|
207
|
+
withField : String -> Encode.Value -> Config -> Config
|
|
208
|
+
withField name value config =
|
|
209
|
+
{ config
|
|
210
|
+
| otherFields = config.otherFields |> Dict.insert name value
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
194
214
|
orientationToString : Orientation -> String
|
|
195
215
|
orientationToString orientation =
|
|
196
216
|
case orientation of
|
|
@@ -239,6 +259,7 @@ type alias Config =
|
|
|
239
259
|
, shortName : Maybe String
|
|
240
260
|
, icons : List Icon
|
|
241
261
|
, lang : LanguageTag
|
|
262
|
+
, otherFields : Dict String Encode.Value
|
|
242
263
|
}
|
|
243
264
|
|
|
244
265
|
|
|
@@ -324,16 +345,16 @@ nonEmptyList list =
|
|
|
324
345
|
|
|
325
346
|
{-| A generator for Api.elm to include a manifest.json.
|
|
326
347
|
-}
|
|
327
|
-
generator : String ->
|
|
348
|
+
generator : String -> BackendTask FatalError Config -> ApiRoute.ApiRoute ApiRoute.Response
|
|
328
349
|
generator canonicalSiteUrl config =
|
|
329
350
|
ApiRoute.succeed
|
|
330
351
|
(config
|
|
331
|
-
|>
|
|
352
|
+
|> BackendTask.map (toJson canonicalSiteUrl >> Encode.encode 0)
|
|
332
353
|
)
|
|
333
354
|
|> ApiRoute.literal "manifest.json"
|
|
334
355
|
|> ApiRoute.single
|
|
335
356
|
|> ApiRoute.withGlobalHeadTags
|
|
336
|
-
(
|
|
357
|
+
(BackendTask.succeed
|
|
337
358
|
[ Head.manifestLink "/manifest.json"
|
|
338
359
|
]
|
|
339
360
|
)
|
|
@@ -420,6 +441,10 @@ toJson canonicalSiteUrl config =
|
|
|
420
441
|
, Encode.string "/" |> Just
|
|
421
442
|
)
|
|
422
443
|
]
|
|
444
|
+
++ (config.otherFields
|
|
445
|
+
|> Dict.toList
|
|
446
|
+
|> List.map (Tuple.mapSecond Just)
|
|
447
|
+
)
|
|
423
448
|
|> encodeMaybeObject
|
|
424
449
|
|
|
425
450
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
module Pages.ProgramConfig exposing (ProgramConfig)
|
|
2
2
|
|
|
3
3
|
import ApiRoute
|
|
4
|
+
import BackendTask exposing (BackendTask)
|
|
4
5
|
import Browser.Navigation
|
|
5
6
|
import Bytes exposing (Bytes)
|
|
6
7
|
import Bytes.Decode
|
|
7
8
|
import Bytes.Encode
|
|
8
|
-
import DataSource exposing (DataSource)
|
|
9
9
|
import Dict exposing (Dict)
|
|
10
|
+
import FatalError exposing (FatalError)
|
|
10
11
|
import Form.FormData exposing (FormData)
|
|
11
12
|
import Head
|
|
12
13
|
import Html exposing (Html)
|
|
@@ -48,9 +49,9 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
48
49
|
-> ( userModel, effect )
|
|
49
50
|
, update : Pages.FormState.PageFormState -> Dict String (Pages.Transition.FetcherState actionData) -> Maybe Pages.Transition.Transition -> sharedData -> pageData -> Maybe Browser.Navigation.Key -> userMsg -> userModel -> ( userModel, effect )
|
|
50
51
|
, subscriptions : route -> Path -> userModel -> Sub userMsg
|
|
51
|
-
, sharedData :
|
|
52
|
-
, data : route ->
|
|
53
|
-
, action : route ->
|
|
52
|
+
, sharedData : BackendTask FatalError sharedData
|
|
53
|
+
, data : Decode.Value -> route -> BackendTask FatalError (PageServerResponse pageData errorPage)
|
|
54
|
+
, action : Decode.Value -> route -> BackendTask FatalError (PageServerResponse actionData errorPage)
|
|
54
55
|
, onActionData : actionData -> Maybe userMsg
|
|
55
56
|
, view :
|
|
56
57
|
Pages.FormState.PageFormState
|
|
@@ -68,8 +69,8 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
68
69
|
{ view : userModel -> { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
|
|
69
70
|
, head : List Head.Tag
|
|
70
71
|
}
|
|
71
|
-
, handleRoute : route ->
|
|
72
|
-
, getStaticRoutes :
|
|
72
|
+
, handleRoute : route -> BackendTask FatalError (Maybe NotFoundReason)
|
|
73
|
+
, getStaticRoutes : BackendTask FatalError (List route)
|
|
73
74
|
, urlToRoute : Url -> route
|
|
74
75
|
, routeToPath : route -> List String
|
|
75
76
|
, site : Maybe SiteConfig
|
|
@@ -88,7 +89,10 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
88
89
|
}
|
|
89
90
|
-> userMsg
|
|
90
91
|
, apiRoutes :
|
|
91
|
-
(
|
|
92
|
+
(Maybe { indent : Int, newLines : Bool }
|
|
93
|
+
-> Html Never
|
|
94
|
+
-> String
|
|
95
|
+
)
|
|
92
96
|
-> List (ApiRoute.ApiRoute ApiRoute.Response)
|
|
93
97
|
, pathPatterns : List RoutePattern
|
|
94
98
|
, basePath : List String
|
|
@@ -98,7 +102,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
98
102
|
, encodeResponse : ResponseSketch pageData actionData sharedData -> Bytes.Encode.Encoder
|
|
99
103
|
, encodeAction : actionData -> Bytes.Encode.Encoder
|
|
100
104
|
, decodeResponse : Bytes.Decode.Decoder (ResponseSketch pageData actionData sharedData)
|
|
101
|
-
, globalHeadTags : Maybe ((Html Never -> String) ->
|
|
105
|
+
, globalHeadTags : Maybe ((Maybe { indent : Int, newLines : Bool } -> Html Never -> String) -> BackendTask FatalError (List Head.Tag))
|
|
102
106
|
, cmdToEffect : Cmd userMsg -> effect
|
|
103
107
|
, perform :
|
|
104
108
|
{ fetchRouteData :
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module Pages.Script exposing
|
|
2
|
+
( Script
|
|
3
|
+
, withCliOptions, withoutCliOptions
|
|
4
|
+
, writeFile
|
|
5
|
+
, log
|
|
6
|
+
, Error(..)
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
{-|
|
|
10
|
+
|
|
11
|
+
@docs Script
|
|
12
|
+
|
|
13
|
+
@docs withCliOptions, withoutCliOptions
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## File System Utilities
|
|
17
|
+
|
|
18
|
+
@docs writeFile
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## Utilities
|
|
22
|
+
|
|
23
|
+
@docs log
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## Errors
|
|
27
|
+
|
|
28
|
+
@docs Error
|
|
29
|
+
|
|
30
|
+
-}
|
|
31
|
+
|
|
32
|
+
import BackendTask exposing (BackendTask)
|
|
33
|
+
import BackendTask.Http
|
|
34
|
+
import BackendTask.Internal.Request
|
|
35
|
+
import Cli.OptionsParser as OptionsParser
|
|
36
|
+
import Cli.Program as Program
|
|
37
|
+
import FatalError exposing (FatalError)
|
|
38
|
+
import Json.Decode as Decode
|
|
39
|
+
import Json.Encode as Encode
|
|
40
|
+
import Pages.Internal.Script
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
{-| -}
|
|
44
|
+
type alias Script =
|
|
45
|
+
Pages.Internal.Script.Script
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
{-| -}
|
|
49
|
+
type Error
|
|
50
|
+
= --TODO make more descriptive
|
|
51
|
+
FileWriteError
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
{-| -}
|
|
55
|
+
writeFile : { path : String, body : String } -> BackendTask { fatal : FatalError, recoverable : Error } ()
|
|
56
|
+
writeFile { path, body } =
|
|
57
|
+
BackendTask.Internal.Request.request
|
|
58
|
+
{ name = "write-file"
|
|
59
|
+
, body =
|
|
60
|
+
BackendTask.Http.jsonBody
|
|
61
|
+
(Encode.object
|
|
62
|
+
[ ( "path", Encode.string path )
|
|
63
|
+
, ( "body", Encode.string body )
|
|
64
|
+
]
|
|
65
|
+
)
|
|
66
|
+
, expect =
|
|
67
|
+
-- TODO decode possible error details here
|
|
68
|
+
BackendTask.Http.expectJson (Decode.succeed ())
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
{-| -}
|
|
73
|
+
log : String -> BackendTask error ()
|
|
74
|
+
log message =
|
|
75
|
+
BackendTask.Internal.Request.request
|
|
76
|
+
{ name = "log"
|
|
77
|
+
, body =
|
|
78
|
+
BackendTask.Http.jsonBody
|
|
79
|
+
(Encode.object
|
|
80
|
+
[ ( "message", Encode.string message )
|
|
81
|
+
]
|
|
82
|
+
)
|
|
83
|
+
, expect = BackendTask.Http.expectJson (Decode.succeed ())
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
{-| -}
|
|
88
|
+
withoutCliOptions : BackendTask FatalError () -> Script
|
|
89
|
+
withoutCliOptions execute =
|
|
90
|
+
Pages.Internal.Script.Script
|
|
91
|
+
(\_ ->
|
|
92
|
+
Program.config
|
|
93
|
+
|> Program.add
|
|
94
|
+
(OptionsParser.build ())
|
|
95
|
+
|> Program.mapConfig
|
|
96
|
+
(\() ->
|
|
97
|
+
execute
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
{-| -}
|
|
103
|
+
withCliOptions : Program.Config cliOptions -> (cliOptions -> BackendTask FatalError ()) -> Script
|
|
104
|
+
withCliOptions config execute =
|
|
105
|
+
Pages.Internal.Script.Script
|
|
106
|
+
(\_ ->
|
|
107
|
+
config
|
|
108
|
+
|> Program.mapConfig execute
|
|
109
|
+
)
|
package/src/Pages/SiteConfig.elm
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
module Pages.SiteConfig exposing (SiteConfig)
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import BackendTask exposing (BackendTask)
|
|
4
|
+
import FatalError exposing (FatalError)
|
|
4
5
|
import Head
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
type alias SiteConfig =
|
|
8
9
|
{ canonicalUrl : String
|
|
9
|
-
, head :
|
|
10
|
+
, head : BackendTask FatalError (List Head.Tag)
|
|
10
11
|
}
|
|
@@ -11,7 +11,7 @@ type alias Request =
|
|
|
11
11
|
, method : String
|
|
12
12
|
, headers : List ( String, String )
|
|
13
13
|
, body : Body
|
|
14
|
-
,
|
|
14
|
+
, cacheOptions : Maybe Encode.Value
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
|
|
@@ -40,5 +40,5 @@ codec =
|
|
|
40
40
|
|> Codec.field "method" .method Codec.string
|
|
41
41
|
|> Codec.field "headers" .headers (Codec.list (Codec.tuple Codec.string Codec.string))
|
|
42
42
|
|> Codec.field "body" .body StaticHttpBody.codec
|
|
43
|
-
|> Codec.
|
|
43
|
+
|> Codec.nullableField "cacheOptions" .cacheOptions Codec.value
|
|
44
44
|
|> Codec.buildObject
|