Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion devbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"gren@0.6.3",
"curl@latest",
"jq@latest",
"github:blaix/ws4sql-nix/0.17dev7"
"github:blaix/ws4sql-nix/0.17dev7",
"sqlite@latest"
],
"shell": {
"init_hook": [],
Expand All @@ -15,6 +16,9 @@
],
"create-session": [
"./scripts/create-session.sh \"$@\""
],
"fetch-session": [
"./scripts/fetch-session.sh \"$@\""
]
}
}
Expand Down
124 changes: 124 additions & 0 deletions devbox.lock
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,130 @@
"store_path": "/nix/store/1bmfcixbhs5fxv2zzyc45grx3xgc90j9-nodejs-20.18.3"
}
}
},
"sqlite@latest": {
"last_modified": "2026-03-15T17:58:12Z",
"resolved": "github:NixOS/nixpkgs/a07d4ce6bee67d7c838a8a5796e75dff9caa21ef#sqlite",
"source": "devbox-search",
"version": "3.51.2",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/h7mm7vizdfzx9dkz8yvq1h3z1dkvk68k-sqlite-3.51.2-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/3rr70fkzzwyvizkjbghbpfyy0xnpk7c8-sqlite-3.51.2-man",
"default": true
},
{
"name": "dev",
"path": "/nix/store/g3pqc7h5cyvq69xi1ci4s73cn3h5rx93-sqlite-3.51.2-dev"
},
{
"name": "doc",
"path": "/nix/store/wkgrqxrqkn7pg26g9r02amdbhgqqa596-sqlite-3.51.2-doc"
},
{
"name": "out",
"path": "/nix/store/n78wl37nhy4qfspmkl37ib43fl9mgzkl-sqlite-3.51.2"
}
],
"store_path": "/nix/store/h7mm7vizdfzx9dkz8yvq1h3z1dkvk68k-sqlite-3.51.2-bin"
},
"aarch64-linux": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/8nlaycnvd4dc6q7vdh9nmda5rfw2wq1l-sqlite-3.51.2-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/q391c8xkvjy9q7qr2h18f6hci3gsyfmy-sqlite-3.51.2-man",
"default": true
},
{
"name": "out",
"path": "/nix/store/0abc9j54cpa41gmdcibp2hcyycd4w2dx-sqlite-3.51.2"
},
{
"name": "debug",
"path": "/nix/store/wr8dr1fpnv9qb4n3hvl8h56yf613605w-sqlite-3.51.2-debug"
},
{
"name": "dev",
"path": "/nix/store/hxcb0bf92dz5xm5i9ksb54m78d9mnbkv-sqlite-3.51.2-dev"
},
{
"name": "doc",
"path": "/nix/store/66hhhlpis6bxgvjq2bnd7m97qryzmpjd-sqlite-3.51.2-doc"
}
],
"store_path": "/nix/store/8nlaycnvd4dc6q7vdh9nmda5rfw2wq1l-sqlite-3.51.2-bin"
},
"x86_64-darwin": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/3n7rwbzrqg3v9x1zkcyca2p7vqn6006k-sqlite-3.51.2-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/6n9alxra4pk4gcvirric8676p0nvajgx-sqlite-3.51.2-man",
"default": true
},
{
"name": "doc",
"path": "/nix/store/s7dhcwp8c67s3711g3cavn8pcm7q6d0d-sqlite-3.51.2-doc"
},
{
"name": "out",
"path": "/nix/store/vr5ff6vjdy7z2g7zsnr2fhd83fdb22j6-sqlite-3.51.2"
},
{
"name": "dev",
"path": "/nix/store/vwzw5yj8z88sza9sczg9ra8lfx6zqv1f-sqlite-3.51.2-dev"
}
],
"store_path": "/nix/store/3n7rwbzrqg3v9x1zkcyca2p7vqn6006k-sqlite-3.51.2-bin"
},
"x86_64-linux": {
"outputs": [
{
"name": "bin",
"path": "/nix/store/k87a0gv4hg1zmm8j5d3ffmxyvhr13i41-sqlite-3.51.2-bin",
"default": true
},
{
"name": "man",
"path": "/nix/store/msdk5dj7zsrxyzdfirfdj2pgff5s2qbn-sqlite-3.51.2-man",
"default": true
},
{
"name": "out",
"path": "/nix/store/whs07fdxlw22fi8b3jzd2z871dh41qx6-sqlite-3.51.2"
},
{
"name": "debug",
"path": "/nix/store/npq7nfarcsgqd0ks8x0crlksiy5lvvfn-sqlite-3.51.2-debug"
},
{
"name": "dev",
"path": "/nix/store/5j4mx4vckmmms2spy8x8kqjxcb12kpf5-sqlite-3.51.2-dev"
},
{
"name": "doc",
"path": "/nix/store/ggx362g7cci0gjlyd3kc39gcbkwrzvkz-sqlite-3.51.2-doc"
}
],
"store_path": "/nix/store/k87a0gv4hg1zmm8j5d3ffmxyvhr13i41-sqlite-3.51.2-bin"
}
}
}
}
}
33 changes: 33 additions & 0 deletions scripts/fetch-session.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash

set -euo pipefail

usage() {
echo "Usage: $(basename "$0") FETCH_SESSION_TOKEN EMAIL_CONFIRMATION_CODE [HOST]"
echo
echo "Fetch a session token by POSTing a fetchSessionToken and emailConfirmationCode"
echo "to the /session/fetch endpoint."
echo
echo "Arguments:"
echo " FETCH_SESSION_TOKEN The fetch session token (required)"
echo " EMAIL_CONFIRMATION_CODE The email confirmation code (required)"
echo " HOST Server host (default: localhost:3000)"
echo
echo "Examples:"
echo " $(basename "$0") abc-123 ABCD1234"
echo " $(basename "$0") abc-123 ABCD1234 registry.gren-lang.org"
}

if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
usage
[ "$#" -lt 2 ] && exit 1
exit 0
fi

FETCH_SESSION_TOKEN="$1"
EMAIL_CONFIRMATION_CODE="$2"
HOST="${3:-localhost:3000}"

curl -sS -w "\nHTTP Status: %{http_code}\n" -o >(jq .) -X POST "http://${HOST}/session/fetch" \
-H "Content-Type: application/json" \
-d "{\"fetchSessionToken\": \"${FETCH_SESSION_TOKEN}\", \"emailConfirmationCode\": \"${EMAIL_CONFIRMATION_CODE}\"}"
58 changes: 24 additions & 34 deletions src/Main.gren
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import Bytes exposing (Bytes)
import Crypto
import Db
import Dict
import Email exposing (Email)
import Db.Encode
import HttpClient
import HttpServer exposing (Request, ServerError(..), Method(..))
import HttpServer.Response as Response exposing (Response)
import Init
import Json.Decode
import Node exposing (Environment, Program)
import Postmark
import Registry.Db
Expand Down Expand Up @@ -183,6 +181,11 @@ route model request response =
}
in
when config is


-- CHECK SERVER PRE-REQS


{ secureContext = Nothing } ->
Route.Error.serverError response "Missing secure context."

Expand All @@ -192,44 +195,31 @@ route model request response =
{ postmark = Just postmark, secureContext = Just secureContext } ->
when { method = request.method, path = path } is


-- SESSION ROUTES


{ method = POST, path = [ "session" ] } ->
when getEmail request.body is
Just email ->
Route.Session.create
{ db = model.db
, postmark = postmark
, secureContext = secureContext
, requestData = { email = email }
, response = response
}

Nothing ->
Route.Error.invalidRequestData response
"Request json did not contain a valid `email` field."
Route.Session.create
{ db = model.db
, postmark = postmark
, secureContext = secureContext
, body = request.body
, response = response
}

{ method = POST, path = [ "session", "fetch" ] } ->
Route.Session.fetch
{ db = model.db
, secureContext = secureContext
, body = request.body
, response = response
}

_ ->
Route.Error.notFound response


getEmail : Bytes -> Maybe Email
getEmail bytes =
bytes
|> Bytes.toString
|> Maybe.andThen decodeEmail
|> Maybe.andThen Email.fromString


decodeEmail : String -> Maybe String
decodeEmail json =
json
|> Json.Decode.decodeString emailDecoder
|> Result.toMaybe


emailDecoder : Json.Decode.Decoder String
emailDecoder =
Json.Decode.field "email" Json.Decode.string


print : Stream.Writable Bytes -> String -> Task Never {}
print stream string =
Expand Down
2 changes: 1 addition & 1 deletion src/Registry/Db.gren
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ migrate db =
fetch_session_token TEXT NOT NULL UNIQUE,

-- Create and return this when CLI posts with email_confirmation_code and fetch_session_token
session_token TEXT UNIQUE
token TEXT UNIQUE
) STRICT
"""
, parameters = []
Expand Down
Loading
Loading