elm-pages 2.1.11 → 3.0.0-beta.1

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 (161) hide show
  1. package/codegen/elm-pages-codegen.js +38507 -0
  2. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmi +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmi +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmo +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmi +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmo +0 -0
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  12. package/generator/{template/public/style.css → dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/lock} +0 -0
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  14. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -0
  15. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +6795 -0
  16. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +25651 -0
  17. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +110 -0
  18. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +187 -0
  19. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/package.json +1 -0
  20. package/generator/dead-code-review/elm-stuff/tests-0.19.1/src/Reporter.elm +26 -0
  21. package/generator/dead-code-review/elm-stuff/tests-0.19.1/src/Runner.elm +62 -0
  22. package/generator/dead-code-review/elm.json +35 -0
  23. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +181 -0
  24. package/generator/dead-code-review/src/ReviewConfig.elm +9 -0
  25. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +455 -0
  26. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
  27. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
  28. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
  29. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
  30. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmi +0 -0
  31. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmo +0 -0
  32. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmi +0 -0
  33. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmo +0 -0
  34. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmi +0 -0
  35. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmo +0 -0
  36. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  37. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  38. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/lock +0 -0
  39. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  40. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -0
  41. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +6795 -0
  42. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +27617 -0
  43. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +110 -0
  44. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +187 -0
  45. package/generator/review/elm-stuff/tests-0.19.1/js/package.json +1 -0
  46. package/generator/review/elm-stuff/tests-0.19.1/src/Reporter.elm +26 -0
  47. package/generator/review/elm-stuff/tests-0.19.1/src/Runner.elm +62 -0
  48. package/generator/review/elm.json +13 -4
  49. package/{src → generator/review/src}/Pages/Review/NoContractViolations.elm +148 -148
  50. package/generator/review/tests/Pages/Review/NoContractViolationsTest.elm +331 -0
  51. package/generator/src/RouteBuilder.elm +420 -0
  52. package/generator/src/SharedTemplate.elm +4 -5
  53. package/generator/src/SiteConfig.elm +3 -9
  54. package/generator/src/build.js +308 -95
  55. package/generator/src/cli.js +103 -8
  56. package/generator/src/codegen.js +192 -35
  57. package/generator/src/compile-elm.js +183 -31
  58. package/generator/src/dev-server.js +353 -96
  59. package/generator/src/elm-application.json +3 -1
  60. package/generator/src/elm-codegen.js +34 -0
  61. package/generator/src/elm-file-constants.js +2 -0
  62. package/generator/src/error-formatter.js +20 -1
  63. package/generator/src/generate-template-module-connector.js +125 -927
  64. package/generator/src/hello.ts +5 -0
  65. package/generator/src/pre-render-html.js +58 -104
  66. package/generator/src/render-worker.js +27 -13
  67. package/generator/src/render.js +252 -197
  68. package/generator/src/request-cache-fs.js +18 -0
  69. package/generator/src/request-cache.js +128 -56
  70. package/generator/src/rewrite-client-elm-json.js +49 -0
  71. package/generator/src/route-codegen-helpers.js +62 -1
  72. package/generator/static-code/dev-style.css +22 -0
  73. package/generator/static-code/elm-pages.js +43 -39
  74. package/generator/static-code/hmr.js +98 -88
  75. package/generator/template/app/Api.elm +25 -0
  76. package/generator/template/app/ErrorPage.elm +38 -0
  77. package/generator/template/app/Route/Index.elm +87 -0
  78. package/generator/template/{src → app}/Shared.elm +34 -13
  79. package/generator/template/app/Site.elm +19 -0
  80. package/generator/template/{src → app}/View.elm +0 -0
  81. package/generator/template/elm-pages.config.mjs +5 -0
  82. package/generator/template/elm.json +1 -0
  83. package/generator/template/{public/index.js → index.ts} +7 -3
  84. package/generator/template/package.json +4 -4
  85. package/generator/template/public/favicon.ico +0 -0
  86. package/generator/template/public/images/icon-png.png +0 -0
  87. package/generator/template/src/.gitkeep +0 -0
  88. package/generator/template/style.css +4 -0
  89. package/package.json +33 -23
  90. package/src/ApiRoute.elm +176 -43
  91. package/src/BuildError.elm +10 -1
  92. package/src/CookieParser.elm +84 -0
  93. package/src/DataSource/Env.elm +38 -0
  94. package/src/DataSource/File.elm +27 -16
  95. package/src/DataSource/Glob.elm +126 -80
  96. package/src/DataSource/Http.elm +283 -304
  97. package/src/DataSource/Internal/Glob.elm +5 -21
  98. package/src/DataSource/Internal/Request.elm +25 -0
  99. package/src/DataSource/Port.elm +17 -14
  100. package/src/DataSource.elm +55 -318
  101. package/src/Form/Field.elm +717 -0
  102. package/src/Form/FieldStatus.elm +36 -0
  103. package/src/Form/FieldView.elm +417 -0
  104. package/src/Form/FormData.elm +22 -0
  105. package/src/Form/Validation.elm +391 -0
  106. package/src/Form/Value.elm +118 -0
  107. package/src/Form.elm +1683 -0
  108. package/src/FormData.elm +58 -0
  109. package/src/FormDecoder.elm +102 -0
  110. package/src/Head/Seo.elm +12 -4
  111. package/src/Head.elm +12 -2
  112. package/src/HtmlPrinter.elm +1 -1
  113. package/src/Internal/ApiRoute.elm +17 -4
  114. package/src/Internal/Request.elm +7 -0
  115. package/src/PageServerResponse.elm +68 -0
  116. package/src/Pages/ContentCache.elm +1 -229
  117. package/src/Pages/Fetcher.elm +58 -0
  118. package/src/Pages/FormState.elm +256 -0
  119. package/src/Pages/Generate.elm +800 -0
  120. package/src/Pages/Internal/Form.elm +17 -0
  121. package/src/Pages/Internal/NotFoundReason.elm +3 -55
  122. package/src/Pages/Internal/Platform/Cli.elm +777 -579
  123. package/src/Pages/Internal/Platform/Effect.elm +5 -5
  124. package/src/Pages/Internal/Platform/StaticResponses.elm +178 -394
  125. package/src/Pages/Internal/Platform/ToJsPayload.elm +24 -23
  126. package/src/Pages/Internal/Platform.elm +1244 -504
  127. package/src/Pages/Internal/ResponseSketch.elm +19 -0
  128. package/src/Pages/Internal/RoutePattern.elm +596 -45
  129. package/src/Pages/Manifest.elm +26 -0
  130. package/src/Pages/Msg.elm +79 -0
  131. package/src/Pages/ProgramConfig.elm +67 -14
  132. package/src/Pages/SiteConfig.elm +3 -6
  133. package/src/Pages/StaticHttp/Request.elm +4 -2
  134. package/src/Pages/StaticHttpRequest.elm +50 -215
  135. package/src/Pages/Transition.elm +70 -0
  136. package/src/Path.elm +1 -0
  137. package/src/Pattern.elm +98 -0
  138. package/src/RenderRequest.elm +2 -2
  139. package/src/RequestsAndPending.elm +111 -9
  140. package/src/Server/Request.elm +1253 -0
  141. package/src/Server/Response.elm +292 -0
  142. package/src/Server/Session.elm +316 -0
  143. package/src/Server/SetCookie.elm +169 -0
  144. package/src/TerminalText.elm +1 -1
  145. package/src/Test/Html/Internal/ElmHtml/Markdown.elm +0 -1
  146. package/src/Test/Html/Internal/ElmHtml/ToString.elm +1 -1
  147. package/generator/src/Page.elm +0 -359
  148. package/generator/src/codegen-template-module.js +0 -183
  149. package/generator/src/elm-pages-js-minified.js +0 -1
  150. package/generator/template/src/Api.elm +0 -14
  151. package/generator/template/src/Page/Index.elm +0 -69
  152. package/generator/template/src/Site.elm +0 -41
  153. package/src/DataSource/ServerRequest.elm +0 -60
  154. package/src/Internal/OptimizedDecoder.elm +0 -18
  155. package/src/KeepOrDiscard.elm +0 -6
  156. package/src/OptimizedDecoder/Pipeline.elm +0 -335
  157. package/src/OptimizedDecoder.elm +0 -818
  158. package/src/Pages/Internal/ApplicationType.elm +0 -6
  159. package/src/Pages/Secrets.elm +0 -83
  160. package/src/Secrets.elm +0 -111
  161. package/src/SecretsDict.elm +0 -45
@@ -0,0 +1,292 @@
1
+ module Server.Response exposing
2
+ ( Response
3
+ , json, plainText, temporaryRedirect, permanentRedirect
4
+ , emptyBody, body, bytesBody, base64Body
5
+ , render
6
+ , errorPage, mapError
7
+ , map
8
+ , withHeader, withHeaders, withStatusCode, withSetCookieHeader
9
+ , toJson
10
+ )
11
+
12
+ {-|
13
+
14
+
15
+ ## Responses
16
+
17
+ @docs Response
18
+
19
+ There are two top-level response types:
20
+
21
+ 1. Server Responses
22
+ 2. Render Responses
23
+
24
+ A Server Response is a way to directly send a low-level server response, with no additional magic. You can set a String body,
25
+ a list of headers, the status code, etc. The Server Response helpers like `json` and `temporaryRedirect` are just helpers for
26
+ building up those low-level Server Responses.
27
+
28
+ Render Responses are a little more special in the way they are connected to your elm-pages app. They allow you to render
29
+ the current Route Module. To do that, you'll need to pass along the `data` for your Route Module.
30
+
31
+ You can use `withHeader` and `withStatusCode` to customize either type of Response (Server Responses or Render Responses).
32
+
33
+
34
+ ## Server Responses
35
+
36
+ @docs json, plainText, temporaryRedirect, permanentRedirect
37
+
38
+
39
+ ## Custom Responses
40
+
41
+ @docs emptyBody, body, bytesBody, base64Body
42
+
43
+
44
+ ## Render Responses
45
+
46
+ @docs render
47
+
48
+
49
+ ## Rendering Error Pages
50
+
51
+ @docs errorPage, mapError
52
+
53
+ @docs map
54
+
55
+
56
+ ## Amending Responses
57
+
58
+ @docs withHeader, withHeaders, withStatusCode, withSetCookieHeader
59
+
60
+
61
+ ## Internals
62
+
63
+ @docs toJson
64
+
65
+ -}
66
+
67
+ import Base64
68
+ import Bytes exposing (Bytes)
69
+ import Json.Encode
70
+ import PageServerResponse exposing (PageServerResponse(..))
71
+ import Server.SetCookie as SetCookie exposing (SetCookie)
72
+
73
+
74
+ {-| -}
75
+ type alias Response data error =
76
+ PageServerResponse data error
77
+
78
+
79
+ {-| -}
80
+ map : (data -> mappedData) -> Response data error -> Response mappedData error
81
+ map mapFn pageServerResponse =
82
+ case pageServerResponse of
83
+ RenderPage response data ->
84
+ RenderPage response (mapFn data)
85
+
86
+ ServerResponse serverResponse ->
87
+ ServerResponse serverResponse
88
+
89
+ ErrorPage error response ->
90
+ ErrorPage error response
91
+
92
+
93
+ {-| -}
94
+ mapError : (errorPage -> mappedErrorPage) -> Response data errorPage -> Response data mappedErrorPage
95
+ mapError mapFn pageServerResponse =
96
+ case pageServerResponse of
97
+ RenderPage response data ->
98
+ RenderPage response data
99
+
100
+ ServerResponse serverResponse ->
101
+ ServerResponse serverResponse
102
+
103
+ ErrorPage error response ->
104
+ ErrorPage (mapFn error) response
105
+
106
+
107
+ {-| -}
108
+ plainText : String -> Response data error
109
+ plainText string =
110
+ { statusCode = 200
111
+ , headers = [ ( "Content-Type", "text/plain" ) ]
112
+ , body = Just string
113
+ , isBase64Encoded = False
114
+ }
115
+ |> ServerResponse
116
+
117
+
118
+ {-| -}
119
+ render : data -> Response data error
120
+ render data =
121
+ RenderPage
122
+ { statusCode = 200, headers = [] }
123
+ data
124
+
125
+
126
+ {-| -}
127
+ errorPage : errorPage -> Response data errorPage
128
+ errorPage errorPage_ =
129
+ ErrorPage errorPage_ { headers = [] }
130
+
131
+
132
+ {-| -}
133
+ emptyBody : Response data error
134
+ emptyBody =
135
+ { statusCode = 200
136
+ , headers = []
137
+ , body = Nothing
138
+ , isBase64Encoded = False
139
+ }
140
+ |> ServerResponse
141
+
142
+
143
+ {-| -}
144
+ body : String -> Response data error
145
+ body body_ =
146
+ { statusCode = 200
147
+ , headers = []
148
+ , body = Just body_
149
+ , isBase64Encoded = False
150
+ }
151
+ |> ServerResponse
152
+
153
+
154
+ {-| -}
155
+ base64Body : String -> Response data error
156
+ base64Body base64String =
157
+ { statusCode = 200
158
+ , headers = []
159
+ , body = Just base64String
160
+ , isBase64Encoded = True
161
+ }
162
+ |> ServerResponse
163
+
164
+
165
+ {-| -}
166
+ bytesBody : Bytes -> Response data error
167
+ bytesBody bytes =
168
+ { statusCode = 200
169
+ , headers = []
170
+ , body = bytes |> Base64.fromBytes
171
+ , isBase64Encoded = True
172
+ }
173
+ |> ServerResponse
174
+
175
+
176
+ {-| -}
177
+ json : Json.Encode.Value -> Response data error
178
+ json jsonValue =
179
+ { statusCode = 200
180
+ , headers =
181
+ [ ( "Content-Type", "application/json" )
182
+ ]
183
+ , body =
184
+ jsonValue
185
+ |> Json.Encode.encode 0
186
+ |> Just
187
+ , isBase64Encoded = False
188
+ }
189
+ |> ServerResponse
190
+
191
+
192
+ {-| Build a 308 permanent redirect response.
193
+
194
+ Permanent redirects tell the browser that a resource has permanently moved. If you redirect because a user is not logged in,
195
+ then you **do not** want to use a permanent redirect because the page they are looking for hasn't changed, you are just
196
+ temporarily pointing them to a new page since they need to authenticate.
197
+
198
+ Permanent redirects are aggressively cached so be careful not to use them when you mean to use temporary redirects instead.
199
+
200
+ If you need to specifically rely on a 301 permanent redirect (see <https://stackoverflow.com/a/42138726> on the difference between 301 and 308),
201
+ use `customResponse` instead.
202
+
203
+ -}
204
+ permanentRedirect : String -> Response data error
205
+ permanentRedirect url =
206
+ { body = Nothing
207
+ , statusCode = 308
208
+ , headers =
209
+ [ ( "Location", url )
210
+ ]
211
+ , isBase64Encoded = False
212
+ }
213
+ |> ServerResponse
214
+
215
+
216
+ {-| -}
217
+ temporaryRedirect : String -> Response data error
218
+ temporaryRedirect url =
219
+ { body = Nothing
220
+ , statusCode = 302
221
+ , headers =
222
+ [ ( "Location", url )
223
+ ]
224
+ , isBase64Encoded = False
225
+ }
226
+ |> ServerResponse
227
+
228
+
229
+ {-| -}
230
+ withStatusCode : Int -> Response data Never -> Response data Never
231
+ withStatusCode statusCode serverResponse =
232
+ case serverResponse of
233
+ RenderPage response data ->
234
+ RenderPage { response | statusCode = statusCode } data
235
+
236
+ ServerResponse response ->
237
+ ServerResponse { response | statusCode = statusCode }
238
+
239
+ ErrorPage error _ ->
240
+ never error
241
+
242
+
243
+ {-| -}
244
+ withHeader : String -> String -> Response data error -> Response data error
245
+ withHeader name value serverResponse =
246
+ case serverResponse of
247
+ RenderPage response data ->
248
+ RenderPage { response | headers = ( name, value ) :: response.headers } data
249
+
250
+ ServerResponse response ->
251
+ ServerResponse { response | headers = ( name, value ) :: response.headers }
252
+
253
+ ErrorPage error response ->
254
+ ErrorPage error { response | headers = ( name, value ) :: response.headers }
255
+
256
+
257
+ {-| -}
258
+ withHeaders : List ( String, String ) -> Response data error -> Response data error
259
+ withHeaders headers serverResponse =
260
+ case serverResponse of
261
+ RenderPage response data ->
262
+ RenderPage { response | headers = headers ++ response.headers } data
263
+
264
+ ServerResponse response ->
265
+ ServerResponse { response | headers = headers ++ response.headers }
266
+
267
+ ErrorPage error response ->
268
+ ErrorPage error { response | headers = headers ++ response.headers }
269
+
270
+
271
+ {-| -}
272
+ withSetCookieHeader : SetCookie -> Response data error -> Response data error
273
+ withSetCookieHeader cookie response =
274
+ response
275
+ |> withHeader "Set-Cookie"
276
+ (cookie
277
+ |> SetCookie.toString
278
+ )
279
+
280
+
281
+ {-| -}
282
+ toJson : Response Never Never -> Json.Encode.Value
283
+ toJson response =
284
+ case response of
285
+ RenderPage _ data ->
286
+ never data
287
+
288
+ ServerResponse serverResponse ->
289
+ PageServerResponse.toJson serverResponse
290
+
291
+ ErrorPage error _ ->
292
+ never error
@@ -0,0 +1,316 @@
1
+ module Server.Session exposing (Decoder, NotLoadedReason(..), Session(..), Value(..), clearFlashCookies, empty, expectSession, flashPrefix, get, insert, remove, setValues, succeed, unwrap, update, withFlash, withSession)
2
+
3
+ {-|
4
+
5
+ @docs Decoder, NotLoadedReason, Session, Value, clearFlashCookies, empty, expectSession, flashPrefix, get, insert, remove, setValues, succeed, unwrap, update, withFlash, withSession
6
+
7
+ -}
8
+
9
+ import DataSource exposing (DataSource)
10
+ import DataSource.Http
11
+ import DataSource.Internal.Request
12
+ import Dict exposing (Dict)
13
+ import Dict.Extra
14
+ import Json.Decode
15
+ import Json.Encode
16
+ import Server.Request as Request exposing (Parser)
17
+ import Server.Response exposing (Response)
18
+ import Server.SetCookie as SetCookie
19
+
20
+
21
+ {-| -}
22
+ type Session
23
+ = Session (Dict String Value)
24
+
25
+
26
+ {-| -}
27
+ type alias Decoder decoded =
28
+ Json.Decode.Decoder decoded
29
+
30
+
31
+ {-| -}
32
+ type Value
33
+ = Persistent String
34
+ | ExpiringFlash String
35
+ | NewFlash String
36
+
37
+
38
+ {-| -}
39
+ withFlash : String -> String -> Session -> Session
40
+ withFlash key value (Session session) =
41
+ session
42
+ |> Dict.insert key (NewFlash value)
43
+ |> Session
44
+
45
+
46
+ {-| -}
47
+ insert : String -> String -> Session -> Session
48
+ insert key value (Session session) =
49
+ session
50
+ |> Dict.insert key (Persistent value)
51
+ |> Session
52
+
53
+
54
+ {-| -}
55
+ get : String -> Session -> Maybe String
56
+ get key (Session session) =
57
+ session
58
+ |> Dict.get key
59
+ |> Maybe.map unwrap
60
+
61
+
62
+ {-| -}
63
+ unwrap : Value -> String
64
+ unwrap value =
65
+ case value of
66
+ Persistent string ->
67
+ string
68
+
69
+ ExpiringFlash string ->
70
+ string
71
+
72
+ NewFlash string ->
73
+ string
74
+
75
+
76
+ {-| -}
77
+ update : String -> (Maybe String -> Maybe String) -> Session -> Session
78
+ update key updateFn (Session session) =
79
+ session
80
+ |> Dict.update key
81
+ (\maybeValue ->
82
+ case maybeValue of
83
+ Just (Persistent value) ->
84
+ updateFn (Just value) |> Maybe.map Persistent
85
+
86
+ Just (ExpiringFlash value) ->
87
+ updateFn (Just value) |> Maybe.map NewFlash
88
+
89
+ Just (NewFlash value) ->
90
+ updateFn (Just value) |> Maybe.map NewFlash
91
+
92
+ Nothing ->
93
+ Nothing
94
+ |> updateFn
95
+ |> Maybe.map Persistent
96
+ )
97
+ |> Session
98
+
99
+
100
+ {-| -}
101
+ remove : String -> Session -> Session
102
+ remove key (Session session) =
103
+ session
104
+ |> Dict.remove key
105
+ |> Session
106
+
107
+
108
+ {-| -}
109
+ empty : Session
110
+ empty =
111
+ Session Dict.empty
112
+
113
+
114
+ {-| -}
115
+ type NotLoadedReason
116
+ = NoCookies
117
+ | MissingHeaders
118
+
119
+
120
+ {-| -}
121
+ succeed : constructor -> Decoder constructor
122
+ succeed constructor =
123
+ constructor
124
+ |> Json.Decode.succeed
125
+
126
+
127
+ {-| -}
128
+ setValues : Session -> Json.Encode.Value
129
+ setValues (Session session) =
130
+ session
131
+ |> Dict.toList
132
+ |> List.filterMap
133
+ (\( key, value ) ->
134
+ case value of
135
+ Persistent string ->
136
+ Just ( key, string )
137
+
138
+ NewFlash string ->
139
+ Just ( flashPrefix ++ key, string )
140
+
141
+ ExpiringFlash _ ->
142
+ Nothing
143
+ )
144
+ |> List.map (Tuple.mapSecond Json.Encode.string)
145
+ |> Json.Encode.object
146
+
147
+
148
+ {-| -}
149
+ flashPrefix : String
150
+ flashPrefix =
151
+ "__flash__"
152
+
153
+
154
+ {-| -}
155
+ clearFlashCookies : Dict String String -> Dict String String
156
+ clearFlashCookies dict =
157
+ Dict.Extra.removeWhen
158
+ (\key _ ->
159
+ key |> String.startsWith flashPrefix
160
+ )
161
+ dict
162
+
163
+
164
+ {-| -}
165
+ expectSession :
166
+ { name : String
167
+ , secrets : DataSource (List String)
168
+ , sameSite : String
169
+ }
170
+ -> Parser request
171
+ -> (request -> Result () Session -> DataSource ( Session, Response data errorPage ))
172
+ -> Parser (DataSource (Response data errorPage))
173
+ expectSession config userRequest toRequest =
174
+ Request.map2
175
+ (\sessionCookie userRequestData ->
176
+ sessionCookie
177
+ |> decryptCookie config
178
+ |> DataSource.andThen
179
+ (encodeSessionUpdate config toRequest userRequestData)
180
+ )
181
+ (Request.expectCookie config.name)
182
+ userRequest
183
+
184
+
185
+ {-| -}
186
+ withSession :
187
+ { name : String
188
+ , secrets : DataSource (List String)
189
+ , sameSite : String
190
+ }
191
+ -> Parser request
192
+ -> (request -> Result () (Maybe Session) -> DataSource ( Session, Response data errorPage ))
193
+ -> Parser (DataSource (Response data errorPage))
194
+ withSession config userRequest toRequest =
195
+ Request.map2
196
+ (\maybeSessionCookie userRequestData ->
197
+ let
198
+ decrypted : DataSource (Result () (Maybe Session))
199
+ decrypted =
200
+ case maybeSessionCookie of
201
+ Just sessionCookie ->
202
+ sessionCookie
203
+ |> decryptCookie config
204
+ |> DataSource.map (Result.map Just)
205
+
206
+ Nothing ->
207
+ Ok Nothing
208
+ |> DataSource.succeed
209
+ in
210
+ decrypted
211
+ |> DataSource.andThen
212
+ (encodeSessionUpdate config toRequest userRequestData)
213
+ )
214
+ (Request.cookie config.name)
215
+ userRequest
216
+
217
+
218
+ encodeSessionUpdate : { a | name : String, secrets : DataSource (List String) } -> (c -> d -> DataSource ( Session, Response data errorPage )) -> c -> d -> DataSource (Response data errorPage)
219
+ encodeSessionUpdate config toRequest userRequestData sessionResult =
220
+ sessionResult
221
+ |> toRequest userRequestData
222
+ |> DataSource.andThen
223
+ (\( sessionUpdate, response ) ->
224
+ DataSource.map
225
+ (\encoded ->
226
+ response
227
+ |> Server.Response.withSetCookieHeader
228
+ (SetCookie.setCookie config.name encoded
229
+ |> SetCookie.httpOnly
230
+ |> SetCookie.withPath "/"
231
+ -- TODO set expiration time
232
+ -- TODO do I need to encrypt the session expiration as part of it
233
+ -- TODO should I update the expiration time every time?
234
+ --|> SetCookie.withExpiration (Time.millisToPosix 100000000000)
235
+ )
236
+ )
237
+ (encrypt config.secrets
238
+ (setValues sessionUpdate)
239
+ )
240
+ )
241
+
242
+
243
+ decryptCookie : { a | secrets : DataSource (List String) } -> String -> DataSource (Result () Session)
244
+ decryptCookie config sessionCookie =
245
+ sessionCookie
246
+ |> decrypt config.secrets (Json.Decode.dict Json.Decode.string)
247
+ |> DataSource.map
248
+ (Result.map
249
+ (\dict ->
250
+ dict
251
+ |> Dict.toList
252
+ |> List.map
253
+ (\( key, value ) ->
254
+ if key |> String.startsWith flashPrefix then
255
+ ( key |> String.dropLeft (flashPrefix |> String.length)
256
+ , ExpiringFlash value
257
+ )
258
+
259
+ else
260
+ ( key, Persistent value )
261
+ )
262
+ |> Dict.fromList
263
+ |> Session
264
+ )
265
+ )
266
+
267
+
268
+ encrypt : DataSource (List String) -> Json.Encode.Value -> DataSource String
269
+ encrypt getSecrets input =
270
+ getSecrets
271
+ |> DataSource.andThen
272
+ (\secrets ->
273
+ DataSource.Internal.Request.request
274
+ { name = "encrypt"
275
+ , body =
276
+ DataSource.Http.jsonBody
277
+ (Json.Encode.object
278
+ [ ( "values", input )
279
+ , ( "secret"
280
+ , Json.Encode.string
281
+ (secrets
282
+ |> List.head
283
+ -- TODO use different default - require non-empty list?
284
+ |> Maybe.withDefault ""
285
+ )
286
+ )
287
+ ]
288
+ )
289
+ , expect =
290
+ DataSource.Http.expectJson
291
+ Json.Decode.string
292
+ }
293
+ )
294
+
295
+
296
+ decrypt : DataSource (List String) -> Json.Decode.Decoder a -> String -> DataSource (Result () a)
297
+ decrypt getSecrets decoder input =
298
+ getSecrets
299
+ |> DataSource.andThen
300
+ (\secrets ->
301
+ DataSource.Internal.Request.request
302
+ { name = "decrypt"
303
+ , body =
304
+ DataSource.Http.jsonBody
305
+ (Json.Encode.object
306
+ [ ( "input", Json.Encode.string input )
307
+ , ( "secrets", Json.Encode.list Json.Encode.string secrets )
308
+ ]
309
+ )
310
+ , expect =
311
+ decoder
312
+ |> Json.Decode.nullable
313
+ |> Json.Decode.map (Result.fromMaybe ())
314
+ |> DataSource.Http.expectJson
315
+ }
316
+ )