diff --git a/README.md b/README.md
index 031258e..7c2ba04 100644
--- a/README.md
+++ b/README.md
@@ -131,7 +131,10 @@ gleam run -m squall generate https://rickandmortyapi.com/graphql
## Examples
-See the [example/](./example/) directory for a complete working example.
+See the [examples/](./examples/) directory for complete working examples:
+
+- **[01-basic](./examples/01-basic/)** - Basic usage with Erlang/JavaScript targets
+- **[02-lustre](./examples/02-lustre/)** - Frontend app using Lustre
## Roadmap
diff --git a/example/README.md b/examples/01-basic/README.md
similarity index 100%
rename from example/README.md
rename to examples/01-basic/README.md
diff --git a/example/gleam.toml b/examples/01-basic/gleam.toml
similarity index 93%
rename from example/gleam.toml
rename to examples/01-basic/gleam.toml
index 594b198..3b1836c 100644
--- a/example/gleam.toml
+++ b/examples/01-basic/gleam.toml
@@ -5,7 +5,7 @@ version = "1.0.0"
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
gleam_json = ">= 3.0.0 and < 4.0.0"
gleam_http = ">= 4.3.0 and < 5.0.0"
-squall = { path = "../" }
+squall = { path = "../../" }
# For Erlang target (default)
gleam_httpc = ">= 5.0.0 and < 6.0.0"
diff --git a/example/manifest.toml b/examples/01-basic/manifest.toml
similarity index 69%
rename from example/manifest.toml
rename to examples/01-basic/manifest.toml
index 88b74ed..8973077 100644
--- a/example/manifest.toml
+++ b/examples/01-basic/manifest.toml
@@ -6,16 +6,14 @@ packages = [
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
{ name = "glam", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "237C2CE218A2A0A5D46D625F8EF5B78F964BC91018B78D692B17E1AB84295229" },
{ name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
- { name = "gleam_fetch", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "2CBF9F2E1C71AEBBFB13A9D5720CD8DB4263EB02FE60C5A7A1C6E17B0151C20C" },
{ name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" },
{ name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" },
- { name = "gleam_javascript", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "EF6C77A506F026C6FB37941889477CD5E4234FCD4337FF0E9384E297CB8F97EB" },
- { name = "gleam_json", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "874FA3C3BB6E22DD2BB111966BD40B3759E9094E05257899A7C08F5DE77EC049" },
+ { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
{ name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
{ name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" },
{ name = "simplifile", version = "2.3.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "957E0E5B75927659F1D2A1B7B75D7B9BA96FAA8D0C53EA71C4AD9CD0C6B848F6" },
- { name = "squall", version = "0.1.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "glam", "gleam_fetch", "gleam_http", "gleam_httpc", "gleam_javascript", "gleam_json", "gleam_stdlib", "simplifile", "swell"], source = "local", path = ".." },
- { name = "swell", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "swell", source = "hex", outer_checksum = "7CCA8C61349396C5B59B3C0627185F5B30917044E0D61CB7E0E5CC75C1B4A8E9" },
+ { name = "squall", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "glam", "gleam_http", "gleam_httpc", "gleam_json", "gleam_stdlib", "simplifile", "swell"], source = "local", path = "../.." },
+ { name = "swell", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "swell", source = "hex", outer_checksum = "CA28A95AB9A01E51D1FCFC0FC4F7102C7F47D04B9711138248D08C2A9F1FE6A3" },
]
[requirements]
@@ -24,4 +22,4 @@ gleam_httpc = { version = ">= 5.0.0 and < 6.0.0" }
gleam_json = { version = ">= 3.0.0 and < 4.0.0" }
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
-squall = { path = "../" }
+squall = { path = "../../" }
diff --git a/example/src/example.gleam b/examples/01-basic/src/example.gleam
similarity index 100%
rename from example/src/example.gleam
rename to examples/01-basic/src/example.gleam
diff --git a/example/src/graphql/get_character.gleam b/examples/01-basic/src/graphql/get_character.gleam
similarity index 100%
rename from example/src/graphql/get_character.gleam
rename to examples/01-basic/src/graphql/get_character.gleam
diff --git a/example/src/graphql/get_character.gql b/examples/01-basic/src/graphql/get_character.gql
similarity index 100%
rename from example/src/graphql/get_character.gql
rename to examples/01-basic/src/graphql/get_character.gql
diff --git a/example/src/graphql/get_character_with_fragment.gleam b/examples/01-basic/src/graphql/get_character_with_fragment.gleam
similarity index 100%
rename from example/src/graphql/get_character_with_fragment.gleam
rename to examples/01-basic/src/graphql/get_character_with_fragment.gleam
diff --git a/example/src/graphql/get_character_with_fragment.gql b/examples/01-basic/src/graphql/get_character_with_fragment.gql
similarity index 100%
rename from example/src/graphql/get_character_with_fragment.gql
rename to examples/01-basic/src/graphql/get_character_with_fragment.gql
diff --git a/examples/02-lustre/README.md b/examples/02-lustre/README.md
new file mode 100644
index 0000000..5e8b45c
--- /dev/null
+++ b/examples/02-lustre/README.md
@@ -0,0 +1,5 @@
+# lustre example
+
+```sh
+gleam run -m lustre/dev start # Run the project
+```
diff --git a/examples/02-lustre/gleam.toml b/examples/02-lustre/gleam.toml
new file mode 100644
index 0000000..1fde76c
--- /dev/null
+++ b/examples/02-lustre/gleam.toml
@@ -0,0 +1,28 @@
+name = "lustre_example"
+version = "1.0.0"
+target = "javascript"
+
+# Fill out these fields if you intend to generate HTML documentation or publish
+# your project to the Hex package manager.
+#
+# description = ""
+# licences = ["Apache-2.0"]
+# repository = { type = "github", user = "", repo = "" }
+# links = [{ title = "Website", href = "" }]
+#
+# For a full reference of all the available options, you can have a look at
+# https://gleam.run/writing-gleam/gleam-toml/.
+
+[dependencies]
+gleam_stdlib = ">= 0.44.0 and < 2.0.0"
+lustre = ">= 5.0.0 and < 6.0.0"
+lustre_http = ">= 1.0.0 and < 2.0.0"
+gleam_json = ">= 3.0.0 and < 4.0.0"
+gleam_http = ">= 4.3.0 and < 5.0.0"
+gleam_fetch = ">= 1.0.0 and < 2.0.0"
+squall = { path = "../../" }
+gleam_javascript = ">= 1.0.0 and < 2.0.0"
+
+[dev-dependencies]
+gleeunit = ">= 1.0.0 and < 2.0.0"
+lustre_dev_tools = ">= 2.2.2 and < 3.0.0"
diff --git a/examples/02-lustre/index.html b/examples/02-lustre/index.html
new file mode 100644
index 0000000..d09dca4
--- /dev/null
+++ b/examples/02-lustre/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Rick and Morty Characters - Lustre + Squall
+
+
+
+
+
+
diff --git a/examples/02-lustre/manifest.toml b/examples/02-lustre/manifest.toml
new file mode 100644
index 0000000..8944e41
--- /dev/null
+++ b/examples/02-lustre/manifest.toml
@@ -0,0 +1,61 @@
+# This file was generated by Gleam
+# You typically do not need to edit this file
+
+packages = [
+ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
+ { name = "booklet", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "booklet", source = "hex", outer_checksum = "08E0FDB78DC4D8A5D3C80295B021505C7D2A2E7B6C6D5EAB7286C36F4A53C851" },
+ { name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" },
+ { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" },
+ { name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
+ { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
+ { name = "glam", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "237C2CE218A2A0A5D46D625F8EF5B78F964BC91018B78D692B17E1AB84295229" },
+ { name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
+ { name = "gleam_community_colour", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "E34DD2C896AC3792151EDA939DA435FF3B69922F33415ED3C4406C932FBE9634" },
+ { name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
+ { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
+ { name = "gleam_fetch", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "2CBF9F2E1C71AEBBFB13A9D5720CD8DB4263EB02FE60C5A7A1C6E17B0151C20C" },
+ { name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" },
+ { name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" },
+ { name = "gleam_javascript", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "EF6C77A506F026C6FB37941889477CD5E4234FCD4337FF0E9384E297CB8F97EB" },
+ { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
+ { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" },
+ { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
+ { name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
+ { name = "gleam_time", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "D560E672C7279C89908981E068DF07FD16D0C859DCA266F908B18F04DF0EB8E6" },
+ { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
+ { name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" },
+ { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" },
+ { name = "glisten", version = "8.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "534BB27C71FB9E506345A767C0D76B17A9E9199934340C975DC003C710E3692D" },
+ { name = "gramps", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "8B7195978FBFD30B43DF791A8A272041B81E45D245314D7A41FC57237AA882A0" },
+ { name = "group_registry", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "group_registry", source = "hex", outer_checksum = "BC798A53D6F2406DB94E27CB45C57052CB56B32ACF7CC16EA20F6BAEC7E36B90" },
+ { name = "houdini", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "5DB1053F1AF828049C2B206D4403C18970ABEF5C18671CA3C2D2ED0DD64F6385" },
+ { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
+ { name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
+ { name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
+ { name = "lustre", version = "5.4.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "40E097BABCE65FB7C460C073078611F7F5802EB07E1A9BFB5C229F71B60F8E50" },
+ { name = "lustre_dev_tools", version = "2.2.2", build_tools = ["gleam"], requirements = ["argv", "booklet", "filepath", "gleam_community_ansi", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_regexp", "gleam_stdlib", "glint", "group_registry", "justin", "lustre", "mist", "polly", "simplifile", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "C66A09B0B268B596F021971E4E4111E4B2B4A1DF5BDFE6C28A1E1FE4CA371F1A" },
+ { name = "lustre_http", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_http", source = "hex", outer_checksum = "FA293FECBC779074C18E3F74D6668D1F13841899283C87B8C358BB6572D25498" },
+ { name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
+ { name = "mist", version = "5.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gleam_yielder", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7C4BE717A81305323C47C8A591E6B9BA4AC7F56354BF70B4D3DF08CC01192668" },
+ { name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
+ { name = "polly", version = "2.1.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib", "simplifile"], otp_app = "polly", source = "hex", outer_checksum = "1BA4D0ACE9BCF52AEA6AD9DE020FD8220CCA399A379E50A1775FC5C1204FCF56" },
+ { name = "simplifile", version = "2.3.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "957E0E5B75927659F1D2A1B7B75D7B9BA96FAA8D0C53EA71C4AD9CD0C6B848F6" },
+ { name = "snag", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "274F41D6C3ECF99F7686FDCE54183333E41D2C1CA5A3A673F9A8B2C7A4401077" },
+ { name = "squall", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "glam", "gleam_http", "gleam_httpc", "gleam_json", "gleam_stdlib", "simplifile", "swell"], source = "local", path = "../.." },
+ { name = "swell", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "swell", source = "hex", outer_checksum = "CA28A95AB9A01E51D1FCFC0FC4F7102C7F47D04B9711138248D08C2A9F1FE6A3" },
+ { name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
+ { name = "tom", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "74D0C5A3761F7A7D06994755D4D5AD854122EF8E9F9F76A3E7547606D8C77091" },
+ { name = "wisp", version = "2.1.0", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "362BDDD11BF48EB38CDE51A73BC7D1B89581B395CA998E3F23F11EC026151C54" },
+]
+
+[requirements]
+gleam_fetch = { version = ">= 1.0.0 and < 2.0.0" }
+gleam_http = { version = ">= 4.3.0 and < 5.0.0" }
+gleam_javascript = { version = ">= 1.0.0 and < 2.0.0" }
+gleam_json = { version = ">= 3.0.0 and < 4.0.0" }
+gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
+gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
+lustre = { version = ">= 5.0.0 and < 6.0.0" }
+lustre_dev_tools = { version = ">= 2.2.2 and < 3.0.0" }
+lustre_http = { version = ">= 1.0.0 and < 2.0.0" }
+squall = { path = "../../" }
diff --git a/examples/02-lustre/src/graphql/get_characters.gleam b/examples/02-lustre/src/graphql/get_characters.gleam
new file mode 100644
index 0000000..eb53bef
--- /dev/null
+++ b/examples/02-lustre/src/graphql/get_characters.gleam
@@ -0,0 +1,90 @@
+import gleam/dynamic/decode
+import gleam/http/request.{type Request}
+import gleam/json
+import gleam/option.{type Option}
+import squall
+
+pub type Characters {
+ Characters(results: Option(List(Character)))
+}
+
+pub fn characters_decoder() -> decode.Decoder(Characters) {
+ use results <- decode.field(
+ "results",
+ decode.optional(decode.list(character_decoder())),
+ )
+ decode.success(Characters(results: results))
+}
+
+pub type Character {
+ Character(
+ id: Option(String),
+ name: Option(String),
+ status: Option(String),
+ species: Option(String),
+ )
+}
+
+pub fn character_decoder() -> decode.Decoder(Character) {
+ use id <- decode.field("id", decode.optional(decode.string))
+ use name <- decode.field("name", decode.optional(decode.string))
+ use status <- decode.field("status", decode.optional(decode.string))
+ use species <- decode.field("species", decode.optional(decode.string))
+ decode.success(Character(id: id, name: name, status: status, species: species))
+}
+
+pub fn characters_to_json(input: Characters) -> json.Json {
+ json.object([
+ #(
+ "results",
+ json.nullable(input.results, fn(list) {
+ json.array(from: list, of: character_to_json)
+ }),
+ ),
+ ])
+}
+
+pub fn character_to_json(input: Character) -> json.Json {
+ json.object([
+ #("id", json.nullable(input.id, json.string)),
+ #("name", json.nullable(input.name, json.string)),
+ #("status", json.nullable(input.status, json.string)),
+ #("species", json.nullable(input.species, json.string)),
+ ])
+}
+
+pub type GetCharactersResponse {
+ GetCharactersResponse(characters: Option(Characters))
+}
+
+pub fn get_characters_response_decoder() -> decode.Decoder(
+ GetCharactersResponse,
+) {
+ use characters <- decode.field(
+ "characters",
+ decode.optional(characters_decoder()),
+ )
+ decode.success(GetCharactersResponse(characters: characters))
+}
+
+pub fn get_characters_response_to_json(
+ input: GetCharactersResponse,
+) -> json.Json {
+ json.object([
+ #("characters", json.nullable(input.characters, characters_to_json)),
+ ])
+}
+
+pub fn get_characters(client: squall.Client) -> Result(Request(String), String) {
+ squall.prepare_request(
+ client,
+ "query GetCharacters {\n characters {\n results {\n id\n name\n status\n species\n }\n }\n}\n",
+ json.object([]),
+ )
+}
+
+pub fn parse_get_characters_response(
+ body: String,
+) -> Result(GetCharactersResponse, String) {
+ squall.parse_response(body, get_characters_response_decoder())
+}
diff --git a/examples/02-lustre/src/graphql/get_characters.gql b/examples/02-lustre/src/graphql/get_characters.gql
new file mode 100644
index 0000000..bf4dc26
--- /dev/null
+++ b/examples/02-lustre/src/graphql/get_characters.gql
@@ -0,0 +1,10 @@
+query GetCharacters {
+ characters {
+ results {
+ id
+ name
+ status
+ species
+ }
+ }
+}
diff --git a/examples/02-lustre/src/lustre_example.gleam b/examples/02-lustre/src/lustre_example.gleam
new file mode 100644
index 0000000..764903a
--- /dev/null
+++ b/examples/02-lustre/src/lustre_example.gleam
@@ -0,0 +1,139 @@
+import gleam/fetch
+import gleam/javascript/promise
+import gleam/list
+import gleam/option.{None, Some}
+import graphql/get_characters
+import lustre
+import lustre/attribute
+import lustre/effect.{type Effect}
+import lustre/element.{type Element}
+import lustre/element/html
+import squall
+
+pub fn main() {
+ let app = lustre.application(init, update, view)
+ let assert Ok(_) = lustre.start(app, "#app", Nil)
+}
+
+// MODEL
+
+pub type Model {
+ Model(state: State)
+}
+
+pub type State {
+ Loading
+ Loaded(characters: List(get_characters.Character))
+ Failed(message: String)
+}
+
+fn init(_flags) -> #(Model, Effect(Msg)) {
+ #(Model(Loading), fetch_characters())
+}
+
+// UPDATE
+
+pub type Msg {
+ HandleCharacters(Result(get_characters.GetCharactersResponse, String))
+}
+
+fn update(_model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
+ case msg {
+ HandleCharacters(Ok(response)) -> {
+ let characters = case response.characters {
+ Some(chars) ->
+ case chars.results {
+ Some(results) -> results
+ None -> []
+ }
+ None -> []
+ }
+ #(Model(Loaded(characters)), effect.none())
+ }
+ HandleCharacters(Error(err)) -> #(Model(Failed(err)), effect.none())
+ }
+}
+
+// VIEW
+
+fn view(model: Model) -> Element(Msg) {
+ html.div([], [
+ html.h1([], [html.text("Rick and Morty Characters")]),
+ case model.state {
+ Loading -> html.p([], [html.text("Loading characters...")])
+ Failed(message) ->
+ html.div([], [
+ html.p([attribute.style("color", "red")], [
+ html.text("Error: " <> message),
+ ]),
+ ])
+ Loaded(characters) -> render_characters(characters)
+ },
+ ])
+}
+
+fn render_characters(characters: List(get_characters.Character)) -> Element(Msg) {
+ html.div([], [
+ html.ul(
+ [],
+ characters
+ |> list.map(fn(character) {
+ html.li([], [
+ html.div([], [
+ html.strong([], [
+ html.text(option.unwrap(character.name, "Unknown")),
+ ]),
+ html.text(" - "),
+ html.text(
+ "Status: " <> option.unwrap(character.status, "Unknown"),
+ ),
+ html.text(", "),
+ html.text(
+ "Species: " <> option.unwrap(character.species, "Unknown"),
+ ),
+ ]),
+ ])
+ }),
+ ),
+ ])
+}
+
+// EFFECTS
+
+fn fetch_characters() -> Effect(Msg) {
+ effect.from(fn(dispatch) {
+ let client = squall.new("https://rickandmortyapi.com/graphql", [])
+ let assert Ok(req) = get_characters.get_characters(client)
+
+ fetch.send(req)
+ |> promise.map(fn(fetch_result) {
+ case fetch_result {
+ Ok(resp) -> {
+ fetch.read_text_body(resp)
+ |> promise.await(fn(text_result) {
+ case text_result {
+ Ok(text) -> {
+ let result =
+ get_characters.parse_get_characters_response(text.body)
+ dispatch(HandleCharacters(result))
+ promise.resolve(Nil)
+ }
+ Error(_) -> {
+ dispatch(
+ HandleCharacters(Error("Failed to read response body")),
+ )
+ promise.resolve(Nil)
+ }
+ }
+ })
+ }
+ Error(_) -> {
+ dispatch(HandleCharacters(Error("Failed to fetch characters")))
+ promise.resolve(Nil)
+ }
+ }
+ })
+
+ Nil
+ })
+}
diff --git a/examples/02-lustre/test/lustre_example_test.gleam b/examples/02-lustre/test/lustre_example_test.gleam
new file mode 100644
index 0000000..fba3c88
--- /dev/null
+++ b/examples/02-lustre/test/lustre_example_test.gleam
@@ -0,0 +1,13 @@
+import gleeunit
+
+pub fn main() -> Nil {
+ gleeunit.main()
+}
+
+// gleeunit test functions end in `_test`
+pub fn hello_world_test() {
+ let name = "Joe"
+ let greeting = "Hello, " <> name <> "!"
+
+ assert greeting == "Hello, Joe!"
+}
diff --git a/gleam.toml b/gleam.toml
index 85c6fab..89dbdb6 100644
--- a/gleam.toml
+++ b/gleam.toml
@@ -1,5 +1,5 @@
name = "squall"
-version = "1.0.0"
+version = "1.0.1"
description = "☁️ Type-safe GraphQL client generator for Gleam"
licences = ["Apache-2.0"]
repository = { type = "github", user = "bigmoves", repo = "squall" }