├── lib ├── bin ├── edge.logging.dev │ ├── deps.edn │ └── README.adoc ├── edge.test-utils │ ├── README.adoc │ ├── deps.edn │ └── src │ │ └── edge │ │ └── test │ │ └── system.clj ├── edge.socket-server │ ├── deps.edn │ └── src │ │ └── juxt │ │ └── edge │ │ └── server │ │ └── pretty_repl.clj ├── edge-app-template │ ├── resources │ │ └── clj │ │ │ └── new │ │ │ └── app.template │ │ │ ├── log_dev_app.properties │ │ │ ├── dev.clj │ │ │ ├── reframe │ │ │ ├── subs.cljs │ │ │ ├── db.cljs │ │ │ ├── handlers.cljs │ │ │ ├── views.cljs │ │ │ └── main.cljs │ │ │ ├── dir-locals.el │ │ │ ├── core.clj │ │ │ ├── main.cljs │ │ │ ├── index.html │ │ │ ├── app.css │ │ │ ├── deps.edn │ │ │ └── config.edn │ ├── .gitignore │ ├── deps.edn │ └── links │ │ └── cljs_calva_settings.json ├── edge.ig.bidi │ ├── deps.edn │ └── src │ │ └── edge │ │ └── bidi │ │ └── ig.clj ├── edge.app │ ├── README.adoc │ └── deps.edn ├── graphql-ws │ ├── deps.edn │ └── src │ │ └── juxt │ │ └── edge │ │ └── graphql_ws │ │ └── core.cljs ├── edge.dev.nrepl │ ├── deps.edn │ └── src │ │ └── edge │ │ └── dev │ │ └── nrepl.clj ├── edge.app.prod │ ├── deps.edn │ └── src │ │ └── edge │ │ └── main.clj ├── crux.ig │ ├── deps.edn │ ├── README.adoc │ └── src │ │ └── juxt │ │ └── crux │ │ └── ig │ │ └── system.clj ├── edge.ig.yada │ ├── deps.edn │ └── src │ │ └── edge │ │ └── yada │ │ └── ig.clj ├── edge.rebel.auto-dev │ ├── deps.edn │ └── src │ │ └── edge │ │ └── rebel │ │ └── main.clj ├── edge.kick │ ├── deps.edn │ └── src │ │ └── edge │ │ ├── kick.clj │ │ └── kick │ │ └── builder.clj ├── edge.system │ ├── deps.edn │ ├── src │ │ └── edge │ │ │ ├── system │ │ │ └── meta.clj │ │ │ └── system.clj │ ├── README.adoc │ └── test │ │ └── edge │ │ └── system_test.clj ├── edge.app.logging │ └── deps.edn ├── edge.asciidoctor │ └── deps.edn ├── edge.migration │ ├── deps.edn │ └── test │ │ ├── phonebook-app │ │ ├── input │ │ │ └── 1 │ │ └── output.edn │ │ ├── tutorial.oic │ │ ├── input │ │ │ └── 1 │ │ └── output.edn │ │ ├── yada.example-auth │ │ ├── input │ │ │ └── 1 │ │ └── output.edn │ │ ├── phonebook-api │ │ ├── input │ │ │ └── 1 │ │ └── output.edn │ │ ├── edge │ │ └── migration_test.clj │ │ ├── tutorial.vent │ │ ├── input │ │ │ └── 1 │ │ └── output.edn │ │ └── main │ │ ├── input │ │ └── 1 │ │ └── output.edn ├── README.adoc └── edge.app.dev │ ├── README.adoc │ ├── deps.edn │ └── src │ └── user.clj ├── examples ├── bin ├── lib ├── main │ ├── target │ │ ├── dev │ │ │ └── .gitkeep │ │ └── prod │ │ │ └── .gitkeep │ ├── .gitignore │ ├── resources │ │ ├── doc │ │ └── public │ │ │ ├── highlight │ │ │ ├── styles │ │ │ │ ├── tomorrow-night.min.css │ │ │ │ └── tomorrow-night.css │ │ │ └── LICENSE │ │ │ ├── juxt.png │ │ │ ├── img │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon-60x60.png │ │ │ ├── favicon-76x76.png │ │ │ ├── favicon-96x96.png │ │ │ ├── favicon-120x120.png │ │ │ ├── favicon-152x152.png │ │ │ ├── favicon-192x192.png │ │ │ ├── logo.svg │ │ │ └── logo-normal.svg │ │ │ └── fonts │ │ │ ├── Roboto-Light.ttf │ │ │ └── RochesterYada.woff2 │ ├── bin │ │ ├── test │ │ ├── repl │ │ ├── server │ │ ├── test-websocket │ │ ├── test-graphql-stream │ │ └── run │ ├── dev │ │ ├── log_dev_app.properties │ │ └── dev.clj │ ├── .vscode │ │ └── settings.json │ ├── .dir-locals.el │ ├── test │ │ └── edge │ │ │ ├── api_test.clj │ │ │ ├── system_test.clj │ │ │ └── examples_test.clj │ ├── README.adoc │ ├── src │ │ └── edge │ │ │ ├── executor.clj │ │ │ ├── hello.clj │ │ │ ├── event_bus.clj │ │ │ ├── selmer.clj │ │ │ └── yada │ │ │ ├── lacinia.clj │ │ │ └── graphql_ws.clj │ ├── prod │ │ └── user.clj │ └── deps.edn ├── phonebook-api │ ├── target │ │ └── .gitkeep │ ├── dev │ │ ├── log_dev_app.properties │ │ ├── dev.clj │ │ ├── edge │ │ │ ├── event_bus.clj │ │ │ └── selmer.clj │ │ └── config.edn │ ├── resources │ │ └── phonebook-api │ │ │ ├── sass │ │ │ ├── _admonition.scss │ │ │ ├── _code.scss │ │ │ ├── _footer.scss │ │ │ ├── _variables.scss │ │ │ ├── phonebook.scss │ │ │ ├── _body.scss │ │ │ ├── _main.scss │ │ │ ├── _reset.scss │ │ │ ├── _fonts.scss │ │ │ └── _table.scss │ │ │ ├── templates │ │ │ ├── phonebook-404.html │ │ │ ├── _wrapper.html │ │ │ ├── phonebook-entry.html │ │ │ └── phonebook.html │ │ │ └── public │ │ │ └── js │ │ │ └── phonebook.js │ ├── .dir-locals.el │ ├── src │ │ ├── public │ │ │ └── phonebook.css │ │ └── edge │ │ │ └── phonebook │ │ │ └── db.clj │ └── deps.edn ├── tutorial.vent │ ├── target │ │ ├── dev │ │ │ └── .gitkeep │ │ └── prod │ │ │ └── .gitkeep │ ├── .gitignore │ ├── dev │ │ ├── log_dev_app.properties │ │ └── dev.clj │ ├── .vscode │ │ └── settings.json │ ├── .dir-locals.el │ ├── src │ │ ├── tutorial │ │ │ └── vent │ │ │ │ ├── frontend │ │ │ │ ├── main.clj │ │ │ │ └── ajax.cljs │ │ │ │ ├── reload.clj │ │ │ │ ├── lib.clj │ │ │ │ ├── http_api.clj │ │ │ │ └── db.clj │ │ ├── index.html │ │ └── config.edn │ └── deps.edn ├── juxt.edge.doc-site │ ├── target │ │ ├── dev │ │ │ └── .gitkeep │ │ └── prod │ │ │ └── .gitkeep │ ├── dev │ │ ├── log_dev_app.properties │ │ └── dev.clj │ ├── .dir-locals.el │ ├── src │ │ └── juxt │ │ │ └── edge │ │ │ ├── doc_site │ │ │ ├── cljs.edn │ │ │ └── doc.cljs │ │ │ └── doc_site.clj │ ├── demo │ │ ├── doc │ │ │ ├── docinfo │ │ │ │ ├── docinfo.html │ │ │ │ └── docinfo-footer.html │ │ │ ├── sources │ │ │ │ └── index.adoc │ │ │ └── asciidoctor │ │ │ │ └── attributes.edn │ │ └── config.edn │ └── deps.edn ├── tutorial.oic │ ├── dev │ │ ├── log_dev_app.properties │ │ └── dev.clj │ ├── src │ │ ├── public │ │ │ └── tutorial.oic.css │ │ ├── config.edn │ │ └── tutorial │ │ │ └── oic │ │ │ ├── web.clj │ │ │ └── oic.clj │ ├── .dir-locals.el │ ├── img │ │ ├── github.png │ │ ├── login.png │ │ ├── connections.png │ │ ├── authorize-app.png │ │ └── create-application.png │ └── deps.edn ├── juxt.crux.demo │ ├── dev │ │ ├── log_dev_app.properties │ │ └── dev.clj │ ├── .dir-locals.el │ ├── src │ │ ├── config.edn │ │ ├── public │ │ │ └── demo.css │ │ └── juxt │ │ │ └── crux │ │ │ └── demo │ │ │ └── foo.clj │ └── deps.edn ├── yada.example-auth │ ├── dev │ │ ├── log_dev_app.properties │ │ └── dev.clj │ ├── src │ │ ├── public │ │ │ └── yada.basic-auth.css │ │ ├── config.edn │ │ └── yada │ │ │ └── example_auth.clj │ ├── .dir-locals.el │ └── deps.edn ├── phonebook-app │ ├── src │ │ └── edge │ │ │ └── phonebook_app │ │ │ ├── client_routes.cljc │ │ │ └── routes.clj │ ├── deps.edn │ └── resources │ │ └── phonebook-app │ │ └── templates │ │ ├── phonebook-app.html │ │ └── _wrapper.html ├── phonebook-graphql │ ├── deps.edn │ └── resources │ │ └── phonebook-graphql │ │ └── graphql-schema.edn └── cloudformation │ └── elasticbeanstalk │ ├── README.adoc │ └── stack.yaml ├── doc ├── resources │ └── doc │ │ ├── sources │ │ ├── dev-logging.adoc │ │ ├── tutorial.adoc │ │ ├── documentation.adoc │ │ ├── uberjar.adoc │ │ ├── socket-repl.adoc │ │ ├── lifecycle.adoc │ │ ├── guidelines.adoc │ │ ├── editor.adoc │ │ ├── elastic-beanstalk.adoc │ │ ├── windows.adoc │ │ ├── index.adoc │ │ ├── why-edge.adoc │ │ └── setup.adoc │ │ ├── docinfo │ │ ├── docinfo.html │ │ └── docinfo-footer.html │ │ └── asciidoctor │ │ └── attributes.edn └── README.adoc ├── practicalli.study-group-api ├── dev │ ├── log_dev_app.properties │ └── dev.clj ├── .dir-locals.el ├── src │ ├── config.edn │ ├── practicalli │ │ └── study_group_api │ │ │ └── core.clj │ └── public │ │ └── study-group-api.css └── deps.edn ├── .gitignore ├── bin ├── onejar ├── capsule ├── update-edge ├── .eftest.logback.xml ├── app ├── uberjar ├── eftest ├── rebel └── .eftest.clj ├── LICENSE └── README.adoc /lib/bin: -------------------------------------------------------------------------------- 1 | ../bin -------------------------------------------------------------------------------- /examples/bin: -------------------------------------------------------------------------------- 1 | ../bin -------------------------------------------------------------------------------- /examples/lib: -------------------------------------------------------------------------------- 1 | ../lib -------------------------------------------------------------------------------- /examples/main/target/dev/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/main/target/prod/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/phonebook-api/target/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tutorial.vent/target/dev/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tutorial.vent/target/prod/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/target/dev/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/target/prod/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/main/.gitignore: -------------------------------------------------------------------------------- 1 | figwheel_server.log 2 | -------------------------------------------------------------------------------- /examples/tutorial.vent/.gitignore: -------------------------------------------------------------------------------- 1 | /db.edn 2 | -------------------------------------------------------------------------------- /examples/main/resources/doc: -------------------------------------------------------------------------------- 1 | ../../../doc/resources/doc -------------------------------------------------------------------------------- /lib/edge.logging.dev/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"]} 2 | -------------------------------------------------------------------------------- /examples/main/bin/test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clojure -A:test $* 4 | -------------------------------------------------------------------------------- /examples/main/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=edge 2 | -------------------------------------------------------------------------------- /lib/edge.test-utils/README.adoc: -------------------------------------------------------------------------------- 1 | = Utilities for Helping with Testing 2 | -------------------------------------------------------------------------------- /examples/tutorial.oic/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=tutorial.oic 2 | -------------------------------------------------------------------------------- /examples/tutorial.vent/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=tutorial.vent 2 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=juxt.crux.demo 2 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=juxt.edge.doc 2 | -------------------------------------------------------------------------------- /examples/main/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | -------------------------------------------------------------------------------- /examples/main/resources/public/highlight/styles/tomorrow-night.min.css: -------------------------------------------------------------------------------- 1 | tomorrow-night.css -------------------------------------------------------------------------------- /examples/phonebook-api/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=edge.phonebook 2 | -------------------------------------------------------------------------------- /examples/tutorial.oic/src/public/tutorial.oic.css: -------------------------------------------------------------------------------- 1 | #app { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /examples/main/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | ../../lib/edge-app-template/links/cljs_calva_settings.json -------------------------------------------------------------------------------- /examples/yada.example-auth/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=yada.basic-auth 2 | -------------------------------------------------------------------------------- /examples/yada.example-auth/src/public/yada.basic-auth.css: -------------------------------------------------------------------------------- 1 | #app { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /examples/main/bin/repl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ../bin/rebel --cljs --nrepl -A:dev:build:dev/build 4 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/dev-logging.adoc: -------------------------------------------------------------------------------- 1 | include::../../../../lib/edge.logging.dev/README.adoc[] 2 | -------------------------------------------------------------------------------- /examples/tutorial.oic/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-clojure-cli-global-options . "-A:dev"))) 3 | -------------------------------------------------------------------------------- /examples/tutorial.vent/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | ../../lib/edge-app-template/links/cljs_calva_settings.json -------------------------------------------------------------------------------- /lib/edge.socket-server/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {fipp {:mvn/version "0.6.16"}}} 4 | -------------------------------------------------------------------------------- /practicalli.study-group-api/dev/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger=practicalli.study-group-api 2 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-clojure-cli-global-options . "-A:dev"))) 3 | -------------------------------------------------------------------------------- /examples/yada.example-auth/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-clojure-cli-global-options . "-A:dev"))) 3 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/log_dev_app.properties: -------------------------------------------------------------------------------- 1 | app_root_logger={{root-ns}} 2 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_admonition.scss: -------------------------------------------------------------------------------- 1 | .question { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /examples/main/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-clojure-cli-global-options . "-A:dev:build:dev/build:dev/cljs"))) 3 | -------------------------------------------------------------------------------- /examples/tutorial.vent/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-clojure-cli-global-options . "-A:dev:build:dev/build"))) 3 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /examples/phonebook-api/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /examples/tutorial.oic/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /lib/edge.ig.bidi/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {integrant {:mvn/version "0.6.3"} 4 | bidi {:mvn/version "2.1.4"}}} 5 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /examples/main/test/edge/api_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.api-test 4 | "Testing the API" 5 | 6 | ) 7 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_code.scss: -------------------------------------------------------------------------------- 1 | code { 2 | &:before { 3 | content: "$ "; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_footer.scss: -------------------------------------------------------------------------------- 1 | footer { 2 | margin: 20pt 12pt 0 12pt; 3 | font-size: 60%; 4 | } -------------------------------------------------------------------------------- /examples/yada.example-auth/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /lib/edge.app/README.adoc: -------------------------------------------------------------------------------- 1 | = lib.app 2 | 3 | Everything you need to run an app. 4 | 5 | A meta package for: 6 | 7 | * edge.system 8 | -------------------------------------------------------------------------------- /practicalli.study-group-api/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /examples/tutorial.oic/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/tutorial.oic/img/github.png -------------------------------------------------------------------------------- /examples/tutorial.oic/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/tutorial.oic/img/login.png -------------------------------------------------------------------------------- /examples/main/resources/public/juxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/juxt.png -------------------------------------------------------------------------------- /examples/tutorial.oic/img/connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/tutorial.oic/img/connections.png -------------------------------------------------------------------------------- /examples/main/bin/server: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "[Edge] Starting development environment, please wait..." 4 | 5 | clojure -A:dev:dev/rebel:dev/nrepl 6 | -------------------------------------------------------------------------------- /examples/tutorial.oic/img/authorize-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/tutorial.oic/img/authorize-app.png -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all])) 4 | 5 | ;; Add your helpers here 6 | -------------------------------------------------------------------------------- /lib/edge.app/deps.edn: -------------------------------------------------------------------------------- 1 | {:deps 2 | {juxt.edge/edge.system {:local/root "../edge.system"} 3 | juxt.edge/app.logging {:local/root "../edge.app.logging"}}} 4 | -------------------------------------------------------------------------------- /lib/graphql-ws/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | org.clojure/clojurescript {:mvn/version "1.9.946"}}} 5 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/src/juxt/edge/doc_site/cljs.edn: -------------------------------------------------------------------------------- 1 | {:figwheel {:on-jsload "juxt.edge.doc-site/figwheel-reload"} 2 | :compiler {:main juxt.edge.doc-site}} 3 | -------------------------------------------------------------------------------- /examples/tutorial.oic/img/create-application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/tutorial.oic/img/create-application.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-16x16.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-32x32.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-60x60.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-76x76.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-96x96.png -------------------------------------------------------------------------------- /lib/edge.test-utils/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {integrant/integrant {:mvn/version "0.7.0"} 3 | juxt.edge/edge.system {:local/root "../edge.system"}}} 4 | -------------------------------------------------------------------------------- /examples/main/resources/public/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-120x120.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-152x152.png -------------------------------------------------------------------------------- /examples/main/resources/public/img/favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/img/favicon-192x192.png -------------------------------------------------------------------------------- /examples/main/resources/public/fonts/RochesterYada.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/practicalli/juxt-edge-first-app/master/examples/main/resources/public/fonts/RochesterYada.woff2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.cpcache 2 | **/.rebel_readline_history 3 | **/.nrepl-port 4 | **/target/*/** 5 | **/log/* 6 | !**/target/*/.gitkeep 7 | 8 | # pack'd output 9 | /*.jar 10 | **/*.jar 11 | -------------------------------------------------------------------------------- /lib/edge.dev.nrepl/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"], 2 | :deps 3 | {cider/cider-nrepl {:mvn/version "0.21.0"} 4 | refactor-nrepl/refactor-nrepl {:mvn/version "2.4.0"} 5 | nrepl {:mvn/version "0.6.0"}}} 6 | -------------------------------------------------------------------------------- /bin/onejar: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clojure -Sdeps '{:deps {pack/pack.alpha {:git/url "https://github.com/juxt/pack.alpha.git" :sha "73552d02e43fa7fac4e3f245257742a9534ea0f2"}}}' -m mach.pack.alpha.one-jar "$@" 4 | -------------------------------------------------------------------------------- /examples/tutorial.vent/dev/dev.clj: -------------------------------------------------------------------------------- 1 | (ns dev 2 | (:require 3 | [dev-extras :refer :all] 4 | [tutorial.vent.db :as db] 5 | [tutorial.vent.lib :refer :all])) 6 | 7 | ;; Add your helpers here 8 | -------------------------------------------------------------------------------- /bin/capsule: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clojure -Sdeps '{:deps {pack/pack.alpha {:git/url "https://github.com/juxt/pack.alpha.git" :sha "73552d02e43fa7fac4e3f245257742a9534ea0f2"}}}' -m mach.pack.alpha.capsule "$@" 4 | -------------------------------------------------------------------------------- /examples/main/README.adoc: -------------------------------------------------------------------------------- 1 | = DEPRECATED: Do not use. 2 | 3 | main is now a relic in favour utilizing your own folder built with `./bin/app`. 4 | This folder hangs around for the yada documentation for now. 5 | -------------------------------------------------------------------------------- /lib/edge-app-template/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.cpcache 9 | /.lein-* 10 | /.nrepl-history 11 | /.nrepl-port 12 | .hgignore 13 | .hg/ 14 | -------------------------------------------------------------------------------- /examples/main/bin/test-websocket: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | curl -i --output - -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: localhost:3000" -H "Origin: http://localhost:3000" http://localhost:3000/graphql-stream-ws 4 | -------------------------------------------------------------------------------- /examples/phonebook-app/src/edge/phonebook_app/client_routes.cljc: -------------------------------------------------------------------------------- 1 | (ns edge.phonebook-app.client-routes 2 | (:require [bidi.bidi :as bidi])) 3 | 4 | (def client-routes 5 | [ 6 | ["" :index] 7 | [["/" :id] :entry]]) 8 | -------------------------------------------------------------------------------- /bin/update-edge: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git pull --no-rebase https://github.com/juxt/edge.git 4 | 5 | repo_root="${PWD}/$(dirname "$0")/.." 6 | 7 | cd "$(dirname "$0")/../lib/edge.migration" && clojure -m edge.migration "$repo_root" 8 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | $fg: #e8e8e8; 2 | $blue: #4a90e2; 3 | $white: #fff; 4 | $offwhite: #fcfcfc; 5 | $darkblue: #414958; 6 | $darkgrey: #363738; 7 | 8 | $font-color: #222 !default; 9 | -------------------------------------------------------------------------------- /lib/edge.app.prod/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {juxt.edge/edge.system {:local/root "../edge.system"} 4 | juxt.edge/lib.socket-server {:local/root "../edge.socket-server"} 5 | integrant/integrant {:mvn/version "0.7.0"}}} 6 | -------------------------------------------------------------------------------- /lib/crux.ig/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {juxt/crux-core {:mvn/version "19.07-1.3.0-alpha"} 4 | integrant {:mvn/version "0.7.0"}} 5 | :aliases 6 | {:dev 7 | {:extra-deps 8 | {org.rocksdb/rocksdbjni {:mvn/version "5.17.2"}}}}} 9 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-ns-refresh-before-fn . "dev-extras/suspend") 3 | (cider-ns-refresh-after-fn . "dev-extras/resume") 4 | (cider-repl-init-code . ("(dev)")) 5 | (cider-clojure-cli-global-options . "-A:dev"))) 6 | -------------------------------------------------------------------------------- /examples/phonebook-api/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-ns-refresh-before-fn . "dev-extras/suspend") 3 | (cider-ns-refresh-after-fn . "dev-extras/resume") 4 | (cider-repl-init-code . ("(dev)")) 5 | (cider-clojure-cli-global-options . "-A:dev"))) 6 | -------------------------------------------------------------------------------- /lib/edge.ig.yada/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps {org.clojure/clojure {:mvn/version "1.10.0"} 3 | yada {:mvn/version "1.2.15"} 4 | integrant {:mvn/version "0.6.3"} 5 | juxt.edge/edge.system {:local/root "../edge.system"}}} 6 | -------------------------------------------------------------------------------- /practicalli.study-group-api/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-ns-refresh-before-fn . "dev-extras/suspend") 3 | (cider-ns-refresh-after-fn . "dev-extras/resume") 4 | (cider-repl-init-code . ("(dev)")) 5 | (cider-clojure-cli-global-options . "-A:dev"))) 6 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/phonebook.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "reset"; 3 | @import "fonts"; 4 | @import "body"; 5 | @import "main"; 6 | @import "table"; 7 | @import "code"; 8 | @import "admonition"; 9 | @import "footer"; 10 | -------------------------------------------------------------------------------- /examples/main/bin/test-graphql-stream: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -i http://localhost:3000/graphql-stream \ 4 | -X POST \ 5 | -H "Accept: text/event-stream" \ 6 | -H "Content-Type: application/json" \ 7 | -d '{"query": "subscription { personupdates { firstname phone }}"}' -------------------------------------------------------------------------------- /lib/edge.rebel.auto-dev/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | ;; Bring your own rebel 3 | :deps {io.aviso/pretty {:mvn/version "0.1.35"} 4 | fipp {:mvn/version "0.6.16"}} 5 | :aliases 6 | {:dev 7 | {:extra-deps 8 | {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}}}} 9 | -------------------------------------------------------------------------------- /lib/edge.kick/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {juxt/kick.alpha 4 | {:git/url "https://github.com/juxt/kick.alpha.git" 5 | :sha "eb7ee22efac8f69b2a042980e4736aec5ec352ed"} 6 | integrant {:mvn/version "0.6.3"} 7 | juxt.edge/edge.system {:local/root "../edge.system"}}} 8 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_body.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 10px auto; 3 | max-width: 920px; 4 | line-height: 1.6; 5 | border-right: 1px solid #ccc; 6 | } 7 | 8 | @media (max-width: 599px) { 9 | body { 10 | text-align: justify; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/edge.system/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"], 2 | :deps 3 | {bidi/bidi {:mvn/version "2.1.4"}, 4 | integrant/integrant {:mvn/version "0.7.0"}, 5 | aero/aero {:mvn/version "1.1.3"}}, 6 | :aliases 7 | {:test {:extra-paths ["test"] 8 | :extra-deps {juxt.edge/test-utils {:local/root "../edge.test-utils"}}}}} 9 | -------------------------------------------------------------------------------- /doc/resources/doc/docinfo/docinfo.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/reframe/subs.cljs: -------------------------------------------------------------------------------- 1 | (ns {{root-ns}}.frontend.subs 2 | (:require [re-frame.core :refer [reg-sub]])) 3 | 4 | (reg-sub 5 | ::greetings 6 | (fn [db _] 7 | (:greetings db))) 8 | 9 | (reg-sub 10 | ::greeting-index 11 | (fn [db _] 12 | (:greeting-index db))) 13 | -------------------------------------------------------------------------------- /lib/edge.app.logging/deps.edn: -------------------------------------------------------------------------------- 1 | {:deps 2 | {org.slf4j/jcl-over-slf4j {:mvn/version "1.7.25"} 3 | org.slf4j/jul-to-slf4j {:mvn/version "1.7.25"} 4 | org.slf4j/log4j-over-slf4j {:mvn/version "1.7.25"} 5 | ch.qos.logback/logback-classic {:mvn/version "1.2.3" 6 | :exclusions [org.slf4j/slf4j-api]}}} 7 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/templates/phonebook-404.html: -------------------------------------------------------------------------------- 1 | {% extends "_wrapper.html" %} 2 | 3 | {% block main %} 4 | 5 |

No Phonebook Entry

6 | 7 |
9 | Go back to the Index 10 |

11 | 12 |
13 | 14 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/demo/doc/docinfo/docinfo.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/reframe/db.cljs: -------------------------------------------------------------------------------- 1 | (ns {{root-ns}}.frontend.db) 2 | 3 | ;; initial state of app-db 4 | (def app-db {:greetings ["Hello from reagent and re-frame in Edge!" 5 | "Hiya!" 6 | "Bonjour!" 7 | "Gracias!"] 8 | :greeting-index 0}) 9 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/tutorial.adoc: -------------------------------------------------------------------------------- 1 | = Tutorial: Creating a twitter clone 2 | 3 | We are going to create a new twitter clone called 'vent'. 4 | 5 | ---- 6 | cd tutorial.vent 7 | ---- 8 | 9 | Start a nrepl 10 | 11 | ---- 12 | ../bin/rebel --cljs -A:dev:build:dev/build 13 | ---- 14 | 15 | ---- 16 | dev=> (go) 17 | ---- 18 | 19 | Navigate to http://localhost:3000 20 | -------------------------------------------------------------------------------- /examples/phonebook-app/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"], 2 | :deps 3 | {venantius/accountant {:mvn/version "0.2.4"}, 4 | bidi/bidi {:mvn/version "2.1.4"}, 5 | reagent/reagent {:mvn/version "0.8.1"}, 6 | org.clojure/clojurescript {:mvn/version "1.10.339"}, 7 | integrant/integrant {:mvn/version "0.7.0"}, 8 | selmer/selmer {:mvn/version "1.12.2"}, 9 | yada/yada {:mvn/version "1.2.15"}}} 10 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/tutorial/vent/frontend/main.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.vent.frontend.main 2 | (:require hicada.compiler)) 3 | 4 | (defmacro html 5 | [body] 6 | (hicada.compiler/compile body {:create-element 'js/React.createElement 7 | :transform-fn (comp) 8 | :array-children? false} 9 | {} &env)) 10 | -------------------------------------------------------------------------------- /lib/edge.asciidoctor/deps.edn: -------------------------------------------------------------------------------- 1 | {:deps 2 | {aero/aero {:mvn/version "1.1.3"}, 3 | hiccup/hiccup {:mvn/version "2.0.0-alpha1"}, 4 | integrant/integrant {:mvn/version "0.8.0-alpha2"}, 5 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}, 6 | yada/yada {:mvn/version "1.2.15"} 7 | 8 | org.asciidoctor/asciidoctorj {:mvn/version "1.6.0-alpha.6"} 9 | org.jruby/jruby {:mvn/version "1.7.26"}}} 10 | -------------------------------------------------------------------------------- /lib/edge.migration/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | io.dominic/ednup {:git/url "https://github.com/SevereOverfl0w/ednup.git" 5 | :sha "87b2734303d815e6209495b9c6a6ee77aa17ab4b"} 6 | org.clojure/tools.cli {:mvn/version "0.4.1"} 7 | jansi-clj {:mvn/version "0.1.1"}} 8 | 9 | :aliases 10 | {:test 11 | {:extra-paths ["test"]}}} 12 | -------------------------------------------------------------------------------- /lib/edge.migration/test/phonebook-app/input/1: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"], 2 | :deps 3 | {venantius/accountant {:mvn/version "0.2.4"}, 4 | bidi/bidi {:mvn/version "2.1.4"}, 5 | reagent/reagent {:mvn/version "0.8.1"}, 6 | org.clojure/clojurescript {:mvn/version "1.10.339"}, 7 | integrant/integrant {:mvn/version "0.7.0"}, 8 | selmer/selmer {:mvn/version "1.12.2"}, 9 | yada/yada {:mvn/version "1.2.15"}}} 10 | -------------------------------------------------------------------------------- /lib/edge.migration/test/phonebook-app/output.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"], 2 | :deps 3 | {venantius/accountant {:mvn/version "0.2.4"}, 4 | bidi/bidi {:mvn/version "2.1.4"}, 5 | reagent/reagent {:mvn/version "0.8.1"}, 6 | org.clojure/clojurescript {:mvn/version "1.10.339"}, 7 | integrant/integrant {:mvn/version "0.7.0"}, 8 | selmer/selmer {:mvn/version "1.12.2"}, 9 | yada/yada {:mvn/version "1.2.15"}}} 10 | -------------------------------------------------------------------------------- /lib/edge.socket-server/src/juxt/edge/server/pretty_repl.clj: -------------------------------------------------------------------------------- 1 | (ns juxt.edge.server.pretty-repl 2 | (:require 3 | [fipp.edn :as fipp] 4 | [clojure.core.server :as clojure.server] 5 | [clojure.main :as m])) 6 | 7 | (defn repl 8 | [] 9 | (m/repl 10 | :init clojure.server/repl-init 11 | :read clojure.server/repl-read 12 | :print fipp/pprint)) 13 | 14 | (defn -main 15 | [& args] 16 | (repl)) 17 | -------------------------------------------------------------------------------- /bin/.eftest.logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/demo/doc/docinfo/docinfo-footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Copyright © 2019, JUXT LTD. All Rights Reserved.

4 |

This is a demo application

5 |
6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /lib/edge.system/src/edge/system/meta.clj: -------------------------------------------------------------------------------- 1 | (ns edge.system.meta) 2 | 3 | (defmulti useful-info (fn [k config state] 4 | (if (vector? k) 5 | (first k) 6 | k))) 7 | 8 | (defmethod useful-info :default [_ _ _] nil) 9 | 10 | (defn useful-infos 11 | [config state] 12 | (filter some? 13 | (for [k (keys state)] 14 | (useful-info k (get config k) (get state k))))) 15 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/src/config.edn: -------------------------------------------------------------------------------- 1 | {:ig/system 2 | {:juxt.crux.demo.foo/read-write {:system #ig/ref :juxt.crux.ig/system} 3 | :juxt.crux.ig.system/standalone {:kv-backend "crux.kv.rocksdb.RocksKv"} 4 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 5 | :port 8300} 6 | :edge.bidi.ig/vhost [["http://localhost:8300" 7 | ["" 8 | [["/" #ig/ref :juxt.crux.demo.foo/read-write]]]]]}} 9 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | (cider-ns-refresh-before-fn . "dev-extras/suspend") 3 | (cider-ns-refresh-after-fn . "dev-extras/resume") 4 | (cider-repl-init-code . ("(dev)")) 5 | (cider-clojure-cli-global-options . "-A:dev{{#kick}}:build:dev/build{{/kick}}"){{#cljs}} 6 | (cider-default-cljs-repl . edge) 7 | (cider-cljs-repl-types . ((edge "(do (require 'dev-extras) ((resolve 'dev-extras/cljs-repl)))"))){{/cljs}})) 8 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/demo/doc/sources/index.adoc: -------------------------------------------------------------------------------- 1 | = Hello, world! 2 | 3 | == Routes source 4 | 5 | WARNING: This link doesn't work without a /sources/! 6 | 7 | Link to srcloc:juxt.edge.doc-site/routes[routes]. 8 | 9 | include::srcblk:juxt.edge.doc-site/routes[] 10 | 11 | == The config 12 | 13 | [source,clojure] 14 | ---- 15 | include::resource:config.edn[] 16 | ---- 17 | 18 | === Including keys 19 | 20 | include::config:prod:ns/demo[] 21 | 22 | include::config:dev:ns/demo[] 23 | -------------------------------------------------------------------------------- /examples/phonebook-graphql/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"], 2 | :deps 3 | {com.walmartlabs/lacinia {:mvn/version "0.32.0"}, 4 | aleph/aleph {:mvn/version "0.4.7-alpha2"}, 5 | manifold/manifold {:mvn/version "0.1.8"}, 6 | cheshire/cheshire {:mvn/version "5.8.1"}, 7 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}, 8 | yada/yada {:mvn/version "1.2.15"}, 9 | integrant/integrant {:mvn/version "0.7.0"} 10 | juxt.edge/phonebook-api {:local/root "../phonebook-api"}}} 11 | -------------------------------------------------------------------------------- /lib/edge.app.prod/src/edge/main.clj: -------------------------------------------------------------------------------- 1 | (ns edge.main 2 | (:require 3 | edge.system 4 | [integrant.core :as ig])) 5 | 6 | (def system nil) 7 | 8 | (defn -main [& args] 9 | (let [system-config (edge.system/system-config {:profile :prod}) 10 | sys (ig/init system-config)] 11 | (.addShutdownHook 12 | (Runtime/getRuntime) 13 | (Thread. 14 | (fn [] 15 | (ig/halt! sys)))) 16 | (alter-var-root #'system (constantly sys))) 17 | @(promise)) 18 | -------------------------------------------------------------------------------- /examples/cloudformation/elasticbeanstalk/README.adoc: -------------------------------------------------------------------------------- 1 | = Example Elastic Beanstalk Stack 2 | 3 | This is an example Cloudformation Elastic Beanstalk stack you can use for hosting your application. 4 | You can upload a JAR produced with, e.g. `../bin/onejar --args '-m edge.main'` and it will run on Elastic Beanstalk. 5 | 6 | This is a sample, you should evolve the template over time as your needs grow. 7 | 2 example points would be adding new environments, and increasing the number of instances in use. 8 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/reframe/handlers.cljs: -------------------------------------------------------------------------------- 1 | (ns {{root-ns}}.frontend.handlers 2 | (:require 3 | [re-frame.core :as rf] 4 | [{{root-ns}}.frontend.db :as db])) 5 | 6 | ;; -- Handlers -------------------------------------------------------------- 7 | 8 | (rf/reg-event-db 9 | ::initialize-db 10 | (fn [_ _] 11 | db/app-db)) 12 | 13 | (rf/reg-event-db 14 | ::set-random-greeting-index 15 | (fn [db _] 16 | (assoc db :greeting-index (rand-int 4)))) 17 | -------------------------------------------------------------------------------- /examples/phonebook-app/resources/phonebook-app/templates/phonebook-app.html: -------------------------------------------------------------------------------- 1 | {% extends "_wrapper.html" %} 2 | 3 | {% block main %} 4 | 5 |

Phonebook

6 | 7 |

8 | A phonebook client written as a single page application in 9 | ClojureScript. 10 |

11 | 12 |
13 |

Initialising...

14 |
15 | 16 | 17 | 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_main.scss: -------------------------------------------------------------------------------- 1 | main { 2 | margin: 0 12pt; 3 | > h1 { 4 | margin: 0.5em 0; 5 | } 6 | > section, div, p { 7 | margin: 0.5em 0; 8 | } 9 | > section > h1 { 10 | margin: 1em 0 0 0; 11 | font-size: 150%; 12 | } 13 | > section > section > h1 { 14 | font-size: 110%; 15 | margin: 1em 0 0.5em 0; 16 | } 17 | li { 18 | margin-left: 2em; 19 | list-style-type: square; 20 | } 21 | } -------------------------------------------------------------------------------- /lib/edge.system/README.adoc: -------------------------------------------------------------------------------- 1 | = aero/integrant 2 | 3 | An opinionated aero/integrant integration. 4 | 5 | == Usage 6 | 7 | Add a key, `:ig/system` to your config.edn containing your integrant system. 8 | For now, config.edn is hardcoded and cannot be overriden. 9 | 10 | .Example 11 | [source,clojure] 12 | ---- 13 | {:http/port 8080 14 | :ig/system {:yada.ig/httpd {:port #ref [:http/port] 15 | :handler #ig/ref :bidi.ig/handler} 16 | :bidi.ig/handler {:routes […]}}} 17 | ---- 18 | -------------------------------------------------------------------------------- /doc/resources/doc/docinfo/docinfo-footer.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 |

Copyright © 2019, JUXT LTD. All Rights Reserved.

8 |
9 | 10 |
11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /lib/edge.system/test/edge/system_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.system-test 4 | (:require 5 | [clojure.test :refer :all] 6 | [integrant.core :as ig] 7 | [edge.test.system :refer [with-system-fixture *system*]])) 8 | 9 | (defn new-system 10 | "Define a minimal system which is just enough for the tests in this 11 | namespace to run" 12 | [] 13 | {}) 14 | 15 | (use-fixtures :once (with-system-fixture new-system)) 16 | 17 | (deftest system-test 18 | (is *system*) 19 | (is (= {} *system*))) 20 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/core.clj: -------------------------------------------------------------------------------- 1 | (ns {{root-ns}}.core 2 | {{#web}} (:require 3 | [yada.yada :as yada] 4 | [integrant.core :as ig])) 5 | 6 | (defn string-resource 7 | [x] 8 | (yada/as-resource x)) 9 | 10 | (defmethod ig/init-key ::string 11 | [_ x] 12 | (string-resource x)){{/web}}{{^web}} (:require 13 | [integrant.core :as ig])) 14 | 15 | (defmethod ig/init-key ::state 16 | [_ init] 17 | (println "Creating state atom in {{root-ns}}.core (src/{{sanitized}}/core.clj)") 18 | (atom init)){{/web}} 19 | -------------------------------------------------------------------------------- /examples/phonebook-graphql/resources/phonebook-graphql/graphql-schema.edn: -------------------------------------------------------------------------------- 1 | {:objects 2 | {:person 3 | {:fields {:firstname {:type String} 4 | :surname {:type String} 5 | :phone {:type String}}} 6 | 7 | :personUpdate 8 | {:fields 9 | {:id {:type Int} 10 | :person {:type :person}}}} 11 | 12 | :queries 13 | {:person {:type (non-null :person) 14 | :args {:id {:type Int}} 15 | :resolve :person}} 16 | 17 | :subscriptions 18 | {:personupdates 19 | {:type :personUpdate 20 | :args {} 21 | :stream :stream-person}}} 22 | -------------------------------------------------------------------------------- /lib/edge-app-template/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["resources" "src"] 2 | :deps {org.clojure/clojure {:mvn/version "1.9.0"} 3 | seancorfield/clj-new {:mvn/version "0.7.6"}} 4 | :aliases 5 | {:test {:extra-paths ["test"] 6 | :extra-deps {org.clojure/test.check {:mvn/version "RELEASE"}}} 7 | :runner 8 | {:extra-deps {com.cognitect/test-runner 9 | {:git/url "https://github.com/cognitect-labs/test-runner" 10 | :sha "76568540e7f40268ad2b646110f237a60295fa3c"}} 11 | :main-opts ["-m" "cognitect.test-runner" 12 | "-d" "test"]}}} 13 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/demo/doc/asciidoctor/attributes.edn: -------------------------------------------------------------------------------- 1 | {"docinfo" "shared" 2 | "docinfodir" "doc" 3 | "experimental" true 4 | "figure-caption" false 5 | "highlightjs-theme" "tomorrow-night" 6 | "highlightjsdir" "/highlight" 7 | "icons" "font" 8 | "iconfont-cdn" "/css/font-awesome.min.css" 9 | "icontype" "svg" 10 | "imagesdir" "/img" 11 | "nofooter" true 12 | "sectnums" true 13 | "sectanchors" true 14 | "source-highlighter" "highlightjs" 15 | "stylesdir" "/" 16 | "stylesheet" "juxt.css" 17 | "linkcss" true 18 | "toc" "left" 19 | "webfonts" false 20 | "xrefstyle" "short"} 21 | -------------------------------------------------------------------------------- /doc/resources/doc/asciidoctor/attributes.edn: -------------------------------------------------------------------------------- 1 | {"docinfo" "shared" 2 | "docinfodir" "doc" 3 | "experimental" true 4 | "figure-caption" false 5 | "highlightjs-theme" "tomorrow-night" 6 | "highlightjsdir" "/highlight" 7 | "icons" "font" 8 | "iconfont-cdn" "/font-awesome/css/font-awesome.min.css" 9 | "icontype" "svg" 10 | "imagesdir" "/img" 11 | "nofooter" true 12 | "sectnums" true 13 | "sectanchors" true 14 | "source-highlighter" "highlightjs" 15 | "stylesdir" "/doc/css" 16 | "stylesheet" "juxt.css" 17 | "linkcss" true 18 | "toc" "left" 19 | "webfonts" false 20 | "xrefstyle" "short"} 21 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vent 6 | 7 | 8 | 9 | 10 | 11 |
Loading…
12 | 13 | 14 | 15 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/main/src/edge/executor.clj: -------------------------------------------------------------------------------- 1 | (ns edge.executor 2 | (:require 3 | [integrant.core :as ig] 4 | [clojure.tools.logging :as log] 5 | [manifold.executor :as me])) 6 | 7 | (defmethod ig/init-key :edge/executor [_ _] 8 | (log/debug "Starting executor") 9 | (me/fixed-thread-executor 10)) 10 | 11 | (defmethod ig/halt-key! :edge/executor [_ e] 12 | (when e 13 | (log/debug "Shutting down executor") 14 | (.shutdownNow e) 15 | (log/debug "Awaiting executor termination") 16 | (.awaitTermination e 5 java.util.concurrent.TimeUnit/SECONDS) 17 | (log/debug "Executor terminated"))) 18 | -------------------------------------------------------------------------------- /lib/README.adoc: -------------------------------------------------------------------------------- 1 | = lib 2 | 3 | Here you will find libraries which support your applications. 4 | Some are Edge libraries (prefixed with "edge.") and some of them are yours. 5 | 6 | Feel free to add new libraries to this folder to support your application. 7 | You can refer to them from your `deps.edn` like so: 8 | 9 | [source,clojure] 10 | ---- 11 | group/name {:local/root "../lib/group.name"} 12 | ---- 13 | 14 | In a library, you should add a dependency on another library by doing "../". 15 | 16 | [source,clojure] 17 | .edge.app/deps.edn 18 | ---- 19 | juxt.edge/edge.system {:local/root "../edge.system"} 20 | ---- 21 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/main.cljs: -------------------------------------------------------------------------------- 1 | (ns ^:figwheel-hooks {{root-ns}}.frontend.main) 2 | 3 | (js/console.log "Hello, world") 4 | 5 | ;; This is called once 6 | (defonce init 7 | (do (set! (.-innerHTML (js/document.getElementById "app")) 8 | "

Loaded {{name}}!

9 |

Edit src/{{sanitized}}/frontend/main.cljs to change this message.

") 10 | true)) 11 | 12 | ;; This is called every time you make a code change 13 | (defn ^:after-load reload [] 14 | (set! (.-innerText (js/document.getElementById "app")) "Hot Reloaded {{name}}!")) 15 | -------------------------------------------------------------------------------- /lib/edge-app-template/links/cljs_calva_settings.json: -------------------------------------------------------------------------------- 1 | // This file is a symlink to an Edge-wide file, if you'd like to make a change 2 | // to only your project, copy it into your project before modifying it. 3 | { 4 | "calva.customCljsRepl": { 5 | "name": "Edge Figwheel Main", 6 | "startCode": "(do (require 'dev-extras) (dev-extras/go) (println \"Edge Figwheel Main started\") ((resolve 'dev-extras/cljs-repl)))", 7 | "tellUserToStartRegExp": "Edge Figwheel Main started", 8 | "printThisLineRegExp": "\\[Edge\\]|Open URL", 9 | "connectedRegExp": "To quit, type: :cljs/quit" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bin/app: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for arg do 4 | shift 5 | case "$arg" in 6 | -*) set -- "$@" "$arg" ;; 7 | *) project_name="$arg" ;; 8 | esac 9 | done 10 | 11 | for var in "$@" 12 | do 13 | if [ "$var" = "--help" ] || [ "$var" = "-h" ]; then 14 | project_name="edge/internal.help" 15 | fi 16 | done 17 | 18 | 19 | if [ "$#" -gt 0 ] && [ -z "$project_name" ]; then 20 | project_name="$1" 21 | shift 22 | fi 23 | 24 | clojure -Sdeps '{:deps {seancorfield/clj-new {:mvn/version "0.7.6"}}}' \ 25 | -m clj-new.create \ 26 | ./lib/edge-app-template::edge-app-template \ 27 | "${project_name:-edge/internal.help}" -- "$@" 28 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/documentation.adoc: -------------------------------------------------------------------------------- 1 | = Documentation 2 | 3 | We think it's a good idea to continue to document your project as we've done with Edge. 4 | You might want to update the CSS stylesheet, source highlighting and other Asiidoctor attributes. 5 | They can be found in `doc/resources/doc/asciidoctor/attributes.edn`. 6 | 7 | == Updating the footer in HTML documentation 8 | 9 | If the footer has a copyright declaration from JUXT, you can update this by updating `doc/resources/doc/docinfo/docinfo-footer.html`. 10 | This file name must not be changed as it is looked for by Asciidoctorj when 11 | generating the HTML output. 12 | -------------------------------------------------------------------------------- /examples/main/test/edge/system_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.system-test 4 | (:require 5 | [clojure.test :refer :all :exclude [deftest]] 6 | [integrant.core :as ig] 7 | [edge.test.system :refer [with-system-fixture *system*]] 8 | [schema.test :refer [deftest]] 9 | [yada.test :refer [response-for]])) 10 | 11 | (defn new-system 12 | "Define a minimal system which is just enough for the tests in this 13 | namespace to run" 14 | [] 15 | {}) 16 | 17 | (use-fixtures :once (with-system-fixture new-system)) 18 | 19 | (deftest system-test 20 | (is *system*) 21 | (is (= {} *system*))) 22 | -------------------------------------------------------------------------------- /lib/edge.ig.bidi/src/edge/bidi/ig.clj: -------------------------------------------------------------------------------- 1 | (ns edge.bidi.ig 2 | (:require 3 | bidi.vhosts 4 | [integrant.core :as ig])) 5 | 6 | ;; Workaround for https://github.com/juxt/bidi/issues/187 pending a merge of https://github.com/juxt/bidi/pull/196 7 | (defn- fix-vhost 8 | "Remove coercions to the route structures" 9 | [vhost input] 10 | (update vhost :vhosts 11 | (fn [vhosts] 12 | (mapv 13 | vector 14 | (map first vhosts) 15 | (map second input))))) 16 | 17 | (defmethod ig/init-key ::vhost 18 | [_ args] 19 | (fix-vhost (apply bidi.vhosts/vhosts-model args) args)) 20 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/tutorial/vent/reload.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.vent.reload 2 | (:require 3 | cljs.repl 4 | [integrant.core :as ig] 5 | figwheel.repl)) 6 | 7 | (defn frontend 8 | [] 9 | (when-let [repl-env (resolve 'figwheel.main.api/repl-env)] 10 | (when-let [env (repl-env "app")] 11 | (when (seq (figwheel.repl/connections-available env)) 12 | (cljs.repl/-evaluate env 13 | "" 14 | 1 15 | "tutorial.vent.frontend.main.re_fetch()")))) 16 | nil) 17 | 18 | 19 | (defmethod ig/init-key ::frontend 20 | [_ _] 21 | (frontend)) 22 | -------------------------------------------------------------------------------- /practicalli.study-group-api/src/config.edn: -------------------------------------------------------------------------------- 1 | {:ig/system 2 | 3 | { 4 | ;; component resources 5 | :practicalli.study-group-api.core/hello-language nil 6 | :practicalli.study-group-api.core/string "Hello, study-group-api!" 7 | 8 | ;; Integrant configuration for yada web listener 9 | :edge.yada.ig/listener 10 | {:handler #ig/ref :edge.bidi.ig/vhost 11 | :port 3636} 12 | 13 | ;; Integrant 14 | :edge.bidi.ig/vhost 15 | [["http://localhost:3636" 16 | 17 | ;; routes 18 | ["" 19 | [["/" #ig/ref :practicalli.study-group-api.core/string] 20 | ["/hello" #ig/ref :practicalli.study-group-api.core/hello-language]]]]]}} 21 | -------------------------------------------------------------------------------- /lib/edge.app.dev/README.adoc: -------------------------------------------------------------------------------- 1 | = App dev 2 | 3 | // tag::content[] 4 | Provides application dev files for use in applications. 5 | 6 | == deps.edn 7 | 8 | `juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}` 9 | 10 | == Usage 11 | 12 | Put the coordinate in your deps.edn, usually in an alias named `:dev`. 13 | In your `dev/dev.clj` set up your namespace like so: 14 | 15 | [source,clojure] 16 | ---- 17 | (ns dev 18 | (:require 19 | [dev-extras :refer :all])) 20 | ---- 21 | 22 | The vars that this brings in are development-related utilities. 23 | Also provides a development-oriented logging setup with filtering and file rotation. 24 | // end::content[] 25 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/templates/_wrapper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Edge Phonebook 9 | 10 | 11 | 12 | 13 | {% block body %} 14 |
15 | {% block main %} 16 | {% endblock %} 17 |
18 | {% endblock %} 19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/edge.migration/test/tutorial.oic/input/1: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | juxt.edge/lib.app {:local/root "../lib.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 13 | 14 | :aliases 15 | {:dev 16 | {:extra-paths ["dev"] 17 | :extra-deps 18 | {juxt.edge/lib.app.dev {:local/root "../lib.app.dev"}}} 19 | 20 | :prod 21 | {:extra-deps 22 | {juxt.edge/lib.app.prod {:local/root "../lib.app.prod"}}}}} 23 | -------------------------------------------------------------------------------- /lib/edge.migration/test/yada.example-auth/input/1: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | juxt.edge/lib.app {:local/root "../lib.app"} 5 | 6 | yada {:mvn/version "1.2.16-SNAPSHOT"} 7 | juxt.edge/yada.ig {:local/root "../lib.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 13 | 14 | :aliases 15 | {:dev 16 | {:extra-paths ["dev"] 17 | :extra-deps 18 | {juxt.edge/lib.app.dev {:local/root "../lib.app.dev"}}} 19 | 20 | :prod 21 | {:extra-deps 22 | {juxt.edge/lib.app.prod {:local/root "../lib.app.prod"}}}}} 23 | -------------------------------------------------------------------------------- /bin/uberjar: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eux 4 | 5 | build_data="$(mktemp -d)" 6 | export build_data 7 | OLDPWD="$PWD" 8 | 9 | trap 'rm -rf "$build_data"; cd "$OLDPWD"' EXIT 10 | 11 | app="$1" 12 | dir="$(dirname "$0")/../${app}" 13 | 14 | # Compile sass & clojurescript 15 | cd "$dir" 16 | clojure -R:build -m io.dominic.krei.alpha.main production "$build_data" 17 | 18 | # AOT compile the application 19 | clojure -A:aot \ 20 | -e \ 21 | '(binding [*compile-path* (System/getenv "build_data")] 22 | (compile (symbol (System/getProperty "main"))))' 23 | 24 | # Create an uberjar including the build data 25 | clojure -A:pack \ 26 | -e "$build_data" \ 27 | "${OLDPWD}/${app}.jar" 28 | -------------------------------------------------------------------------------- /examples/tutorial.oic/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 13 | 14 | :aliases 15 | {:dev 16 | {:extra-paths ["dev"] 17 | :extra-deps 18 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 19 | 20 | :prod 21 | {:extra-deps 22 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 23 | -------------------------------------------------------------------------------- /examples/yada.example-auth/src/config.edn: -------------------------------------------------------------------------------- 1 | {:ig/system 2 | {:yada.example-auth/basic-auth-example-resource 3 | 4 | ;; Passwords in clear-text 5 | {:users {"alice" {:yada.example-auth/name "Alice Roberts" 6 | :yada.example-auth/password "Seeshai6"} 7 | "bob2" {:yada.example-auth/name "Bob Mortimer" 8 | :yada.example-auth/password "bohthoM6"}}} 9 | 10 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 11 | :port 3080} 12 | 13 | :edge.bidi.ig/vhost [["http://localhost:3080" 14 | ["/" 15 | [["basic" #ig/ref :yada.example-auth/basic-auth-example-resource]]]]]}} 16 | -------------------------------------------------------------------------------- /practicalli.study-group-api/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | integrant {:mvn/version "0.7.0"} 10 | 11 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 12 | 13 | :aliases 14 | {:dev 15 | {:extra-paths ["dev"] 16 | :extra-deps 17 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 18 | 19 | :prod 20 | {:extra-deps 21 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 22 | -------------------------------------------------------------------------------- /examples/yada.example-auth/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.2.16-SNAPSHOT"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 13 | 14 | :aliases 15 | {:dev 16 | {:extra-paths ["dev"] 17 | :extra-deps 18 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 19 | 20 | :prod 21 | {:extra-deps 22 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 23 | -------------------------------------------------------------------------------- /bin/eftest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | deps='{:deps {eftest {:mvn/version "0.5.7"} cider/orchard {:mvn/version "0.4.0"}}}' 4 | args=() 5 | 6 | while :; do 7 | case $1 in 8 | -A*) 9 | args+=("$1") 10 | shift 11 | ;; 12 | --) 13 | shift 14 | break 15 | ;; 16 | -?*) 17 | break 18 | ;; 19 | *) 20 | break 21 | esac 22 | done 23 | 24 | # Particularly use illegal-access=deny here due to the pretty output of eftest. 25 | clojure -J--illegal-access=deny "-J-Dlogback.configurationFile=$(dirname "$0")/.eftest.logback.xml" "${args[@]}" -Sdeps "$deps" "$(dirname "$0")/.eftest.clj" "$@" 26 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/reframe/views.cljs: -------------------------------------------------------------------------------- 1 | (ns {{root-ns}}.frontend.views 2 | (:require [reagent.core :as r :refer [atom]] 3 | [re-frame.core :refer [subscribe dispatch dispatch-sync]] 4 | [{{root-ns}}.frontend.handlers :as handlers] 5 | [{{root-ns}}.frontend.subs :as subs])) 6 | 7 | (defn main-panel 8 | [] 9 | (let [greetings (subscribe [::subs/greetings]) 10 | greeting-index (subscribe [::subs/greeting-index])] 11 | (fn [] 12 | [:div 13 | [:p (get @greetings @greeting-index)] 14 | [:button 15 | {:on-click #(dispatch [::handlers/set-random-greeting-index])} 16 | [:p "press me!"]]]))) 17 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/tutorial/vent/frontend/ajax.cljs: -------------------------------------------------------------------------------- 1 | (ns tutorial.vent.frontend.ajax 2 | (:require 3 | [cljs.reader :refer [read-string]])) 4 | 5 | (defmulti page-fetch :name) 6 | 7 | (defmethod page-fetch :default 8 | [_] 9 | nil) 10 | 11 | (defn fetch-page 12 | [page state*] 13 | (some-> (page-fetch page) 14 | (.then (fn [data] (.text data))) 15 | (.then (fn [text] (read-string text))) 16 | (.then (fn [x] (swap! state* 17 | (fn [state] 18 | (if (= page (:page state)) 19 | (assoc-in state [:page :data] x) 20 | state))))))) 21 | -------------------------------------------------------------------------------- /lib/edge.migration/test/tutorial.oic/output.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 13 | 14 | :aliases 15 | {:dev 16 | {:extra-paths ["dev"] 17 | :extra-deps 18 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 19 | 20 | :prod 21 | {:extra-deps 22 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 23 | -------------------------------------------------------------------------------- /lib/edge.migration/test/yada.example-auth/output.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.2.16-SNAPSHOT"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 13 | 14 | :aliases 15 | {:dev 16 | {:extra-paths ["dev"] 17 | :extra-deps 18 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 19 | 20 | :prod 21 | {:extra-deps 22 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 23 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_reset.scss: -------------------------------------------------------------------------------- 1 | // Box sizing -- https://css-tricks.com/box-sizing/ 2 | 3 | html { 4 | } 5 | body { 6 | font-family: Arial, sans-serif; 7 | background-color: $offwhite; 8 | color: $font-color; 9 | } 10 | header, footer, section { 11 | display: block; 12 | } 13 | * { 14 | box-sizing: border-box; 15 | padding: 0; 16 | margin: 0; 17 | } 18 | *:before, *:after { 19 | box-sizing: inherit; 20 | } 21 | a { 22 | color: $blue; 23 | text-decoration: none; 24 | font-weight: bold; 25 | } 26 | a:hover { 27 | opacity: 0.6; 28 | } 29 | em { 30 | color: $blue; 31 | font-style: normal; 32 | font-weight: bold; 33 | } 34 | strong { 35 | font-weight: bold; 36 | } 37 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/reframe/main.cljs: -------------------------------------------------------------------------------- 1 | (ns ^:figwheel-hooks {{root-ns}}.frontend.main 2 | (:require [reagent.core :as r] 3 | [re-frame.core :as rf] 4 | [{{root-ns}}.frontend.views :as views] 5 | [{{root-ns}}.frontend.handlers :as handlers])) 6 | 7 | (defn mount-root [] 8 | (when-let [section (.getElementById js/document "app")] 9 | (rf/clear-subscription-cache!) 10 | (r/render [views/main-panel] section))) 11 | 12 | (defn init [] 13 | (rf/dispatch-sync [::handlers/initialize-db]) 14 | (enable-console-print!) 15 | (mount-root)) 16 | 17 | ;; This is called every time you make a code change 18 | (defn ^:after-load reload [] 19 | (mount-root)) 20 | 21 | (defonce run (init)) 22 | -------------------------------------------------------------------------------- /practicalli.study-group-api/src/practicalli/study_group_api/core.clj: -------------------------------------------------------------------------------- 1 | (ns practicalli.study-group-api.core 2 | (:require 3 | [yada.yada :as yada] 4 | [integrant.core :as ig])) 5 | 6 | (defn string-resource 7 | [x] 8 | (yada/as-resource x)) 9 | 10 | (defmethod ig/init-key ::string 11 | [_ x] 12 | (string-resource x)) 13 | 14 | 15 | (def hello-language 16 | (yada/resource 17 | {:methods 18 | {:get 19 | {:produces 20 | {:media-type "text/plain" 21 | :language #{"en" "zh-ch;q=0.9"}} 22 | :response 23 | #(case (yada/language %) 24 | "zh-ch" "你好世界\n" 25 | "en" "Hello World!\n")}}})) 26 | 27 | 28 | (defmethod ig/init-key 29 | ::hello-language 30 | [_ _] 31 | hello-language) 32 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{name}} 7 | 8 | 9 | 10 | 13 |
14 |

Content

{{#cljs}} 15 |
Loading ClojureScript...
{{/cljs}}{{^cljs}} 16 |

Edit this message in src/index.html.

{{/cljs}} 17 |

Learn Edge

18 |
{{#cljs}} 19 | {{/cljs}} 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | integrant {:mvn/version "0.7.0"} 10 | 11 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 12 | juxt.crux/ig {:local/root "../lib/crux.ig"} 13 | org.rocksdb/rocksdbjni {:mvn/version "5.17.2"}} 14 | 15 | :aliases 16 | {:dev 17 | {:extra-paths ["dev"] 18 | :extra-deps 19 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 20 | 21 | :prod 22 | {:extra-deps 23 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 24 | -------------------------------------------------------------------------------- /doc/README.adoc: -------------------------------------------------------------------------------- 1 | = Edge documentation 2 | 3 | This directory represents the Edge documentation module. 4 | 5 | It is explicitly referenced by `app`. 6 | 7 | Asciidoc sources can be found in link:resources/doc/sources[]. 8 | 9 | The JUXT documentation style is in 10 | link:resources/doc/asciidoctor/css/juxt.css[], which is built using 11 | https://github.com/asciidoctor/asciidoctor-stylesheet-factory[]. 12 | 13 | The module contains some ClojureScript support in 14 | link:src/edge/doc/doc.cljs[]. 15 | 16 | == Building on Edge 17 | 18 | If you use Edge at the springboard for your own application, we 19 | suggest you might consider retaining this documentation module, and 20 | modify the Asciidoc sources accordingly. We hope this module gives you 21 | a head-start in your own documentation efforts. 22 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_fonts.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto-Light'; 3 | src: url('fonts/Roboto-Light.ttf') format('truetype'); 4 | } 5 | 6 | @font-face { 7 | font-family: 'RochesterYada'; 8 | font-style: normal; 9 | font-weight: 400; 10 | src: url('fonts/RochesterYada.woff2') format('woff2'); 11 | } 12 | 13 | // font families 14 | $default-font-family: 'Roboto-Light', Arial, sans-serif !default; 15 | $yada-font-family: 'RochesterYada', sans-serif !default; 16 | $icon-font-family: FontAwesome !default; 17 | 18 | body, 19 | button, 20 | input { 21 | font-family: $default-font-family; 22 | } 23 | 24 | .yada { 25 | font-family: $yada-font-family; 26 | font-size: 1.40em; 27 | font-weight: normal; 28 | line-height: 70%; 29 | } 30 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/src/public/demo.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: #eee; 3 | height: 100%; 4 | 5 | font-family: sans-serif; 6 | } 7 | 8 | *, *:after, *:before { 9 | box-sizing: border-box; 10 | } 11 | 12 | body { 13 | display: flex; 14 | justify-content: center; 15 | align-items: center; 16 | 17 | margin: 0; 18 | padding: 1em; 19 | } 20 | 21 | .content { 22 | background-color: white; 23 | padding: 2rem; 24 | 25 | max-width: 960px; 26 | width: 50vw; 27 | 28 | margin: auto; 29 | 30 | box-shadow: 0 0 2em rgba(0, 0, 0, 0.4); 31 | border-radius: 5px; 32 | 33 | text-align: center; 34 | } 35 | 36 | #app { 37 | box-sizing: border-box; 38 | min-height: 50px; 39 | width: 100%; 40 | background-color: #efefef; 41 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); 42 | padding: 1em; 43 | } 44 | -------------------------------------------------------------------------------- /examples/phonebook-api/src/public/phonebook.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: #eee; 3 | height: 100%; 4 | 5 | font-family: sans-serif; 6 | } 7 | 8 | *, *:after, *:before { 9 | box-sizing: border-box; 10 | } 11 | 12 | body { 13 | display: flex; 14 | justify-content: center; 15 | align-items: center; 16 | 17 | margin: 0; 18 | padding: 1em; 19 | } 20 | 21 | .content { 22 | background-color: white; 23 | padding: 2rem; 24 | 25 | max-width: 960px; 26 | width: 50vw; 27 | 28 | margin: auto; 29 | 30 | box-shadow: 0 0 2em rgba(0, 0, 0, 0.4); 31 | border-radius: 5px; 32 | 33 | text-align: center; 34 | } 35 | 36 | #app { 37 | box-sizing: border-box; 38 | min-height: 50px; 39 | width: 100%; 40 | background-color: #efefef; 41 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); 42 | padding: 1em; 43 | } 44 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/sass/_table.scss: -------------------------------------------------------------------------------- 1 | table { 2 | width: 100%; 3 | } 4 | 5 | table, th, td { 6 | border-collapse: collapse; 7 | border: 1px solid black; 8 | } 9 | 10 | th, td { 11 | padding: 0.4em; 12 | } 13 | 14 | label { 15 | float: left; 16 | width: 5em; 17 | margin-right: 1em; 18 | } 19 | 20 | input { 21 | padding: 0.2em; 22 | font-size: 100%; 23 | } 24 | 25 | button { 26 | background: green; 27 | color: white; 28 | border: 0px solid black; 29 | padding: 0.5em; 30 | margin: 0.5em 0; 31 | width: 10em; 32 | font-weight: bold; 33 | font-size: 100%; 34 | margin-right: 1em; 35 | } 36 | 37 | .container { 38 | margin: 3em 0; 39 | } 40 | 41 | button[disabled=disabled], 42 | button:disabled { 43 | background: #ccc; 44 | color: #eee; 45 | } -------------------------------------------------------------------------------- /examples/phonebook-app/resources/phonebook-app/templates/_wrapper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Edge Phonebook (ClojureScript) 9 | 10 | 13 | 14 | 15 | 16 | 17 | {% block body %} 18 |
19 | {% block main %} 20 | {% endblock %} 21 |
22 | {% endblock %} 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/edge.test-utils/src/edge/test/system.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.test.system 4 | (:require 5 | [integrant.core :as ig] 6 | [edge.system])) 7 | 8 | (def ^:dynamic *system* nil) 9 | 10 | (defmacro ^:private with-system 11 | [system ks & body] 12 | `(let [system# ~system 13 | s# (ig/init system# (or ~ks (keys system#)))] 14 | (try 15 | (binding [*system* s#] 16 | ~@body) 17 | (finally 18 | (ig/halt! s#))))) 19 | 20 | (defn- default-system 21 | [] 22 | (edge.system/system-config 23 | {:profile :test})) 24 | 25 | (defn with-system-fixture 26 | ([] 27 | (with-system-fixture default-system)) 28 | ([system] 29 | (fn [f] 30 | (with-system (system) nil 31 | (f))))) 32 | 33 | (defn with-subsystem-fixture 34 | ([ks] 35 | (with-subsystem-fixture default-system)) 36 | ([system ks] 37 | (fn [f] 38 | (with-system (system) ks 39 | (f))))) 40 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/uberjar.adoc: -------------------------------------------------------------------------------- 1 | = Creating an Uberjar 2 | 3 | Edge provides a script for running pack to build an uberjar. 4 | To use it, you can simply run the below from your project sub-directory (the same folder as your deps.edn). 5 | 6 | [source,shell] 7 | ---- 8 | $ ../bin/onejar -A:prod --args '-m edge.main' project.jar 9 | ---- 10 | 11 | The `-A:prod` indicates an alias you would like to have its `:extra-deps` and `:paths` included in your resulting jar. 12 | `--args` are default arguments to your jar, in this case we are specifying that the application should run edge.main, part of the edge production modules. 13 | 14 | You can run this jar in production quite easily: 15 | 16 | [source,shell] 17 | ---- 18 | $ java -Xmx1G -jar project.jar 19 | ---- 20 | 21 | We recommend that you specify the memory usage of your JVM, as the default on Java 6+ is usually insufficient for hosts run only this JVM process. 22 | A rule of thumb is to use 2/3rds of the memory of your host. 23 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/public/js/phonebook.js: -------------------------------------------------------------------------------- 1 | log = function(msg, e) { 2 | console.log(msg + ":= " + e) 3 | console.dir(e) 4 | } 5 | 6 | phonebook = { 7 | delete: function() { 8 | x = new XMLHttpRequest() 9 | x.onload = function(e) { 10 | if (e.target.status == 200) { 11 | window.location.reload(); 12 | } 13 | } 14 | x.onerror = function(e) { log("onerror is ", e)} 15 | x.open("DELETE", window.location.pathname) 16 | x.send("") 17 | }, 18 | update: function() { 19 | x = new XMLHttpRequest() 20 | x.onload = function(e) { 21 | if (e.target.status == 204) { 22 | window.location.reload(); 23 | } 24 | } 25 | x.onerror = function(e) { log("onerror is ", e)} 26 | x.open("PUT", window.location.pathname) 27 | x.send(new FormData(document.getElementById("entry"))) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/phonebook-app/src/edge/phonebook_app/routes.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | ;; Our phonebook but as a single page application (SPA) 4 | 5 | (ns edge.phonebook-app.routes 6 | (:require 7 | [clojure.java.io :as io] 8 | [integrant.core :as ig] 9 | [selmer.parser :as selmer] 10 | [yada.yada :as yada])) 11 | 12 | (defn- routes 13 | [{:edge.phonebook/keys [db]}] 14 | [["" (yada/resource 15 | {:id ::phonebook-app 16 | :path-info? true ; We want to serve the same content for 17 | ; every path below here. 18 | :methods 19 | {:get 20 | {:produces "text/html" 21 | :response 22 | (fn [ctx] 23 | (selmer/render-file 24 | "phonebook-app.html" 25 | {:ctx ctx} 26 | {:custom-resource-path (io/resource "phonebook-app/templates/")}))}}})]]) 27 | 28 | (defmethod ig/init-key :edge.phonebook-app/routes [_ config] 29 | (routes config)) 30 | -------------------------------------------------------------------------------- /practicalli.study-group-api/src/public/study-group-api.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: #eee; 3 | height: 100%; 4 | font-family: sans-serif; 5 | } 6 | 7 | *, *:after, *:before { 8 | box-sizing: border-box; 9 | } 10 | 11 | body { 12 | margin: auto; 13 | } 14 | 15 | nav { 16 | margin: 0; 17 | background-color: #333333; 18 | } 19 | 20 | h1 { 21 | padding: 2rem; 22 | margin: auto; 23 | color: #f4901d; 24 | } 25 | 26 | .content { 27 | background-color: white; 28 | padding: 0 2rem 0 2rem; 29 | max-width: 960px; 30 | width: 90vw; 31 | margin: 2rem auto; 32 | border: 1px solid rgba(34, 36, 38, 0.15); 33 | border-radius: 5px; 34 | box-shadow: inset 0 0 3px rgba(68, 68, 68, 0.2); 35 | text-align: center; 36 | } 37 | 38 | #app { 39 | box-sizing: border-box; 40 | min-height: 50px; 41 | padding: 1em; 42 | width: 100%; 43 | background-color: #eee; 44 | border-radius: 5px; 45 | box-shadow: inset 0 0 3px rgba(68, 68, 68, 0.2); 46 | } 47 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/app.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: #eee; 3 | height: 100%; 4 | font-family: sans-serif; 5 | } 6 | 7 | *, *:after, *:before { 8 | box-sizing: border-box; 9 | } 10 | 11 | body { 12 | margin: auto; 13 | } 14 | 15 | nav { 16 | margin: 0; 17 | background-color: #333333; 18 | } 19 | 20 | h1 { 21 | padding: 2rem; 22 | margin: auto; 23 | color: #f4901d; 24 | } 25 | 26 | .content { 27 | background-color: white; 28 | padding: 0 2rem 0 2rem; 29 | max-width: 960px; 30 | width: 90vw; 31 | margin: 2rem auto; 32 | border: 1px solid rgba(34, 36, 38, 0.15); 33 | border-radius: 5px; 34 | box-shadow: inset 0 0 3px rgba(68, 68, 68, 0.2); 35 | text-align: center; 36 | } 37 | 38 | #app { 39 | box-sizing: border-box; 40 | min-height: 50px; 41 | padding: 1em; 42 | width: 100%; 43 | background-color: #eee; 44 | border-radius: 5px; 45 | box-shadow: inset 0 0 3px rgba(68, 68, 68, 0.2); 46 | } 47 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/templates/phonebook-entry.html: -------------------------------------------------------------------------------- 1 | {% extends "_wrapper.html" %} 2 | 3 | {% block main %} 4 | 5 |

Phonebook Entry

6 | 7 |
8 |

Update entry

9 |
10 |

11 | 12 | 13 |

14 |

15 | 16 | 17 |

18 |

19 | 20 | 21 |

22 |
23 | 24 | 25 |

26 | Index 27 |

28 | 29 | 30 | 31 |
32 | 33 | 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /examples/main/bin/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Recommended way of starting an unpacked repo of Edge in production 4 | 5 | # Feel free to change this 6 | APP_NAME=Edge 7 | 8 | # Comment this to disable the production REPL, otherwise use it to specify the port. 9 | SOCKET_REPL_PORT=50505 10 | 11 | # Exported so it can accessed inside the JVM 12 | export NREPL_PORT=5601 13 | 14 | # The -Xms JVM argument 15 | INIT_MEMORY=256m 16 | 17 | # The -Xmx JVM argument 18 | MAX_MEMORY=1200m 19 | 20 | # Profile 21 | PROFILE=$1 22 | 23 | aliases=build:prod/build:prod 24 | 25 | if [[ -n $NREPL_PORT ]]; then 26 | aliases+=:dev/nrepl 27 | fi 28 | 29 | if [[ -n $SOCKET_REPL_PORT ]]; then 30 | prod_repl_arg=-J-Dclojure.server.myrepl="{:port,$SOCKET_REPL_PORT,:accept,clojure.core.server/repl,:address,\"localhost\"}" 31 | fi 32 | 33 | echo "Starting $APP_NAME" 34 | 35 | COMMAND="clojure $prod_repl_arg -J-Djava.awt.headless=true -J-Xms$INIT_MEMORY -J-Xmx$MAX_MEMORY -A:$aliases -m user $PROFILE" 36 | 37 | echo $COMMAND 38 | 39 | exec $COMMAND 40 | -------------------------------------------------------------------------------- /examples/tutorial.oic/src/config.edn: -------------------------------------------------------------------------------- 1 | { 2 | :ig/system 3 | { 4 | ;; This value is asynchronously initialised, partially to speed up 5 | ;; resets. The '*' prefix indicates a reference rather than value. 6 | :tutorial.oic.oic/*client 7 | {:oauth/client-id "insert client-id here" 8 | :oauth/client-secret "insert client-secret here" 9 | :oauth/redirect-uri "http://localhost:3000/oauth-callback" 10 | :openid-connect/configuration-url "https://insert-domain-here/.well-known/openid-configuration"} 11 | 12 | :tutorial.oic.web/authorize 13 | {:tutorial.oic.oic/*client #ig/ref :tutorial.oic.oic/*client} 14 | 15 | :tutorial.oic.web/oauth-callback 16 | {:tutorial.oic.oic/*client #ig/ref :tutorial.oic.oic/*client} 17 | 18 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 19 | :port 3000} 20 | :edge.bidi.ig/vhost 21 | [["http://localhost:3000" 22 | ["" 23 | [["/authorize" #ig/ref :tutorial.oic.web/authorize] 24 | ["/oauth-callback" #ig/ref :tutorial.oic.web/oauth-callback] 25 | ]]]]}} 26 | -------------------------------------------------------------------------------- /lib/edge.migration/test/phonebook-api/input/1: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib.ig.bidi"} 9 | integrant {:mvn/version "0.7.0"} 10 | 11 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 12 | 13 | hiccup {:mvn/version "1.0.5"} 14 | prismatic/schema {:mvn/version "1.1.9"} 15 | selmer/selmer {:mvn/version "1.12.2"} 16 | manifold/manifold {:mvn/version "0.1.8"}} 17 | 18 | 19 | :aliases 20 | {:dev 21 | {:extra-paths ["dev" "target"] 22 | :extra-deps 23 | {juxt.edge/lib.app.dev {:local/root "../lib.app.dev"} 24 | juxt.edge/kick {:local/root "../edge.kick"} 25 | deraen/sass4clj {:mvn/version "0.3.1"} 26 | juxt/kick.alpha 27 | {:git/url "https://github.com/juxt/kick.alpha.git" 28 | :sha "06063beadfa72dfe23480727c347976b608e8316"}}} 29 | 30 | :prod 31 | {:extra-deps 32 | {juxt.edge/lib.app.prod {:local/root "../lib.app.prod"}}}}} 33 | -------------------------------------------------------------------------------- /examples/phonebook-api/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | integrant {:mvn/version "0.7.0"} 10 | 11 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 12 | 13 | hiccup {:mvn/version "1.0.5"} 14 | prismatic/schema {:mvn/version "1.1.9"} 15 | selmer/selmer {:mvn/version "1.12.2"} 16 | manifold/manifold {:mvn/version "0.1.8"}} 17 | 18 | 19 | :aliases 20 | {:dev 21 | {:extra-paths ["dev" "target"] 22 | :extra-deps 23 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"} 24 | juxt.edge/kick {:local/root "../lib/edge.kick"} 25 | deraen/sass4clj {:mvn/version "0.3.1"} 26 | juxt/kick.alpha 27 | {:git/url "https://github.com/juxt/kick.alpha.git" 28 | :sha "06063beadfa72dfe23480727c347976b608e8316"}}} 29 | 30 | :prod 31 | {:extra-deps 32 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2016-2019 JUXT LTD. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/edge.app.dev/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"], 2 | :deps 3 | {juxt.edge/edge.system {:local/root "../edge.system"}, 4 | integrant/integrant {:mvn/version "0.7.0"}, 5 | integrant/repl {:mvn/version "0.3.1"}, 6 | io.aviso/pretty {:mvn/version "0.1.35"}, 7 | 8 | org.clojure/tools.namespace {:mvn/version "0.3.0-alpha4"} 9 | org.clojure/java.classpath {:mvn/version "0.3.0"} 10 | 11 | ;; Spyscope's version of fipp doesn't work with Java 11 12 | spyscope/spyscope {:mvn/version "0.1.6" 13 | :exclusions [fipp/fipp]} 14 | fipp/fipp {:mvn/version "0.6.14"} 15 | 16 | juxt.edge/logging.dev {:local/root "../edge.logging.dev"} 17 | 18 | ;; add-lib branch, see http://insideclojure.org/2018/05/04/add-lib/ 19 | 20 | ;; aws-maven brings in a logback.xml, causing horrible errors. Using a fork 21 | ;; which has removed it. 22 | org.clojure/tools.deps.alpha {:git/url "https://github.com/SevereOverfl0w/tools.deps.alpha.git" 23 | :sha "a4173975e22e5a41cc3be85270729ed102be3917" 24 | :exclusions [org.slf4j/slf4j-nop 25 | ]}}} 26 | -------------------------------------------------------------------------------- /lib/edge.migration/test/phonebook-api/output.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | integrant {:mvn/version "0.7.0"} 10 | 11 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 12 | 13 | hiccup {:mvn/version "1.0.5"} 14 | prismatic/schema {:mvn/version "1.1.9"} 15 | selmer/selmer {:mvn/version "1.12.2"} 16 | manifold/manifold {:mvn/version "0.1.8"}} 17 | 18 | 19 | :aliases 20 | {:dev 21 | {:extra-paths ["dev" "target"] 22 | :extra-deps 23 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"} 24 | juxt.edge/kick {:local/root "../lib/edge.kick"} 25 | deraen/sass4clj {:mvn/version "0.3.1"} 26 | juxt/kick.alpha 27 | {:git/url "https://github.com/juxt/kick.alpha.git" 28 | :sha "06063beadfa72dfe23480727c347976b608e8316"}}} 29 | 30 | :prod 31 | {:extra-deps 32 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}}} 33 | -------------------------------------------------------------------------------- /lib/edge.system/src/edge/system.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.system 4 | "Components and their dependency relationships" 5 | (:require 6 | [aero.core :as aero] 7 | [clojure.java.io :as io] 8 | [integrant.core :as ig])) 9 | 10 | ;; There will be integrant tags in our Aero configuration. We need to 11 | ;; let Aero know about them using this defmethod. 12 | (defmethod aero/reader 'ig/ref [_ _ value] 13 | (ig/ref value)) 14 | 15 | (let [lock (Object.)] 16 | (defn- load-namespaces 17 | [system-config] 18 | (locking lock 19 | (ig/load-namespaces system-config)))) 20 | 21 | (defn config 22 | "Read EDN config, with the given aero options. See Aero docs at 23 | https://github.com/juxt/aero for details." 24 | [opts] 25 | (-> (io/resource "config.edn") ;; <1> 26 | (aero/read-config opts)) ;; <2> 27 | ) 28 | 29 | (defn system-config 30 | "Construct a new system, configured with the given profile" 31 | [opts] 32 | (let [config (config opts) ;; <1> 33 | system-config (:ig/system config)] ;; <2> 34 | (load-namespaces system-config) ;; <3> 35 | (ig/prep system-config) ;; <4> 36 | )) 37 | -------------------------------------------------------------------------------- /examples/main/src/edge/hello.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.hello 4 | "Demonstrating a simple example of a yada web resource" 5 | (:require 6 | [yada.yada :as yada])) 7 | 8 | (defn hello-routes [] 9 | ["/hello" (yada/handler "Hello World!\n")]) 10 | 11 | (defn hello-language [] 12 | ["/hello-language" 13 | (yada/resource 14 | {:methods 15 | {:get 16 | {:produces 17 | {:media-type "text/plain" 18 | :language #{"en" "zh-ch;q=0.9"}} 19 | :response 20 | #(case (yada/language %) 21 | "zh-ch" "你好世界\n" 22 | "en" "Hello World!\n")}}})]) 23 | 24 | (defn hello-atom [] 25 | ["/hello-atom" 26 | (yada/as-resource (atom "Hello World!\n"))]) 27 | 28 | (defn hello-parameter [] 29 | ["/hello-parameter" 30 | (yada/resource 31 | {:methods 32 | {:get 33 | {:parameters {:query {:p String}} 34 | :produces "text/plain" 35 | :response (fn [ctx] (format "Hello %s!\n" (-> ctx :parameters :query :p))) 36 | }}})]) 37 | 38 | (defn other-hello-routes [] 39 | ["" [ 40 | (hello-language) 41 | (hello-atom) 42 | (hello-parameter) 43 | ]]) 44 | -------------------------------------------------------------------------------- /lib/edge.migration/test/edge/migration_test.clj: -------------------------------------------------------------------------------- 1 | (ns edge.migration-test 2 | (:require 3 | [clojure.edn :as edn] 4 | [clojure.java.io :as io] 5 | [clojure.test :refer :all] 6 | edge.migration 7 | [rewrite-clj.parser :refer [parse-string]])) 8 | 9 | (deftest migrations-run 10 | (doseq [example-project ["main" "phonebook-api" "phonebook-app" "tutorial.oic" "tutorial.vent" "yada.example-auth"]] 11 | (let [output (io/resource (str example-project "/output.edn"))] 12 | (doseq [history (->> (range 1000) ;; 1000 to prevent infinite loops 13 | (map inc) 14 | (keep #(io/resource (str example-project "/input/" %))) 15 | (take-while some?))] 16 | (is 17 | (= (edn/read-string (slurp output)) 18 | (edn/read-string 19 | (edge.migration/migrate-file 20 | (parse-string (slurp history)) 21 | {:lib-dir "../lib/"})))) 22 | (is 23 | (= (slurp output) 24 | (edge.migration/migrate-file 25 | (parse-string (slurp history)) 26 | {:lib-dir "../lib/"}))))))) 27 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/socket-repl.adoc: -------------------------------------------------------------------------------- 1 | = Pretty Printing Server Socket REPL 2 | 3 | Edge ships with a pretty printing server socket REPL you can enable in production. 4 | It is a dependency of `lib.app.prod`, so will be available automatically in production. 5 | See <> if you're not using lib.app.prod. 6 | 7 | == Usage 8 | 9 | To use, add this to your server start command: 10 | 11 | [source] 12 | ---- 13 | -Dclojure.server.myrepl='{:port 50505,:accept juxt.edge.server.pretty-repl/repl}' 14 | ---- 15 | 16 | A complete command may look like so: 17 | 18 | [source,shell] 19 | ---- 20 | java -Dclojure.server.myrepl='{:port 50505,:accept juxt.edge.server.pretty-repl/repl}' -jar app.jar 21 | ---- 22 | 23 | [WARNING] 24 | .Note for Capsule JARs 25 | ==== 26 | If you're using a capsule jar, you need to wrap your JVM arguments in `-Dcapsule.jvm.args` like so: 27 | 28 | [source,shell] 29 | ---- 30 | java -Dcapsule.jvm.args="-Dclojure.server.myrepl='{:port 50505,:accept juxt.edge.server.pretty-repl/repl}'" 31 | ---- 32 | ==== 33 | 34 | [[manual-setup]] 35 | == Manual Setup 36 | 37 | [source,clojure] 38 | ---- 39 | juxt.edge/lib.socket-server {:local/root "../lib.socket-server"} 40 | ---- 41 | -------------------------------------------------------------------------------- /examples/main/src/edge/event_bus.clj: -------------------------------------------------------------------------------- 1 | (ns edge.event-bus 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [integrant.core :as ig] 5 | [manifold.stream :as ms] 6 | [manifold.deferred :as d] 7 | manifold.bus)) 8 | 9 | (defn new-stream [component] 10 | (assert (:streams component)) 11 | (let [s (ms/stream)] ; executor? 12 | (swap! (:streams component) conj s) 13 | s)) 14 | 15 | (defn new-promise [component] 16 | (assert (:promises component)) 17 | (let [p (promise)] 18 | (swap! (:promises component) conj p) 19 | p)) 20 | 21 | (defmethod ig/init-key :edge/event-bus 22 | [_ _] 23 | {:manifold/event-bus (manifold.bus/event-bus) 24 | :streams (atom []) 25 | :promises (atom [])}) 26 | 27 | (defmethod ig/halt-key! :edge/event-bus [_ {:keys [streams promises]}] 28 | (when-let [streams @streams] 29 | (doseq [s streams] 30 | (when-not (ms/closed? s) 31 | (log/debug "Closing stream due to stopping EventBus component") 32 | (ms/close! s)))) 33 | (when-let [promises @promises] 34 | (doseq [p promises] 35 | (when-not (realized? p) 36 | (log/debug "Delivering promise due to stopping EventBus component") 37 | (deliver p :component-stopped))))) 38 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/lifecycle.adoc: -------------------------------------------------------------------------------- 1 | = Lifecycle of an Edge project 2 | 3 | [[update]] 4 | == Updating from upstream 5 | 6 | In order to access bug fixes and new features, you should periodically update your Edge application. 7 | 8 | [source,shell] 9 | ---- 10 | acme$ ./bin/update-edge 11 | ---- 12 | 13 | WARNING: A refactoring occurred around the 18th of March 2019 which requires you to run `./bin/update-edge` twice. 14 | 15 | == Modifying your Edge 16 | 17 | Edge is part of your project to allow you to modify it. 18 | If you run into a limitation or bug in Edge please https://github.com/juxt/edge/issues/new[report it], but also feel free to modify your local version. 19 | One of the reasons JUXT want a cloned Edge, is so we can put in client-specific changes when we don't have a good idea for a general solution. 20 | 21 | When you <>, your changes will automatically be merged with those in Edge (you won't lose your changes). 22 | If there's a conflict during the automatic merge, you will be prompted by git to resolve it. 23 | 24 | Depending on where you modify, you may find that there are more or less merge conflicts. 25 | Generally, even internally Edge is very stable, so you should not expect too many conflicts. 26 | -------------------------------------------------------------------------------- /examples/phonebook-api/dev/edge/event_bus.clj: -------------------------------------------------------------------------------- 1 | (ns edge.event-bus 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [integrant.core :as ig] 5 | [manifold.stream :as ms] 6 | [manifold.deferred :as d] 7 | manifold.bus)) 8 | 9 | (defn new-stream [component] 10 | (assert (:streams component)) 11 | (let [s (ms/stream)] ; executor? 12 | (swap! (:streams component) conj s) 13 | s)) 14 | 15 | (defn new-promise [component] 16 | (assert (:promises component)) 17 | (let [p (promise)] 18 | (swap! (:promises component) conj p) 19 | p)) 20 | 21 | (defmethod ig/init-key :edge/event-bus 22 | [_ _] 23 | {:manifold/event-bus (manifold.bus/event-bus) 24 | :streams (atom []) 25 | :promises (atom [])}) 26 | 27 | (defmethod ig/halt-key! :edge/event-bus [_ {:keys [streams promises]}] 28 | (when-let [streams @streams] 29 | (doseq [s streams] 30 | (when-not (ms/closed? s) 31 | (log/debug "Closing stream due to stopping EventBus component") 32 | (ms/close! s)))) 33 | (when-let [promises @promises] 34 | (doseq [p promises] 35 | (when-not (realized? p) 36 | (log/debug "Delivering promise due to stopping EventBus component") 37 | (deliver p :component-stopped))))) 38 | -------------------------------------------------------------------------------- /examples/juxt.crux.demo/src/juxt/crux/demo/foo.clj: -------------------------------------------------------------------------------- 1 | (ns juxt.crux.demo.foo 2 | (:require 3 | crux.api 4 | [yada.yada :as yada] 5 | [integrant.core :as ig])) 6 | 7 | (def id #uuid "50005565-299f-4c08-86d0-b1919bf4b7a9") 8 | 9 | (defmethod ig/init-key ::read-write 10 | [_ {:keys [system]}] 11 | (yada/resource 12 | {:id ::read-write 13 | :methods 14 | {:get 15 | {:produces ["text/html" "application/edn" "application/json"] 16 | :response (fn [ctx] 17 | (let [db (crux.api/db system)] 18 | (map 19 | #(crux.api/entity db (first %)) 20 | (crux.api/q 21 | db 22 | {:find '[?e] 23 | :where [['?e :crux.db/id id]]}))))} 24 | :post 25 | {:produces "text/plain" 26 | :consumes "application/edn" 27 | :response 28 | (fn [ctx] 29 | (crux.api/submit-tx 30 | system 31 | [[:crux.tx/put id 32 | (merge {:crux.db/id id} (:body ctx))]]) 33 | (yada/redirect ctx ::read-write))}}})) 34 | 35 | ;; To populate data using cURL: 36 | ; $ curl -H "Content-Type: application/edn" -d '{:foo/username "Bart"}' localhost:8300 37 | -------------------------------------------------------------------------------- /examples/yada.example-auth/src/yada/example_auth.clj: -------------------------------------------------------------------------------- 1 | (ns yada.example-auth 2 | (:require 3 | [clojure.spec.alpha :as s] 4 | [integrant.core :as ig] 5 | [yada.yada :as yada])) 6 | 7 | (s/def ::name string?) 8 | (s/def ::password string?) 9 | 10 | (defn basic-auth-example-resource [users] 11 | ;; MAL->DMC: Could we enable spec asserts in the dev alias? 12 | (s/assert (s/map-of string? (s/keys :req [::name ::password])) users) 13 | (yada/resource 14 | {:access-control 15 | {:realms 16 | {"default" 17 | {:authentication-schemes 18 | [{:scheme "Basic" 19 | :verify 20 | (fn [[user-id given-password]] 21 | (when-let [user (get users user-id)] 22 | (when (= given-password (::password user)) 23 | {::user (dissoc user ::password)})))}] 24 | :authorization 25 | {:validate 26 | (fn [ctx creds] (when creds ctx))}}}} 27 | 28 | :methods 29 | {:get 30 | {:produces 31 | {:media-type "text/plain" :charset "utf8"} 32 | :response 33 | (fn [ctx] 34 | (format 35 | "Welcome %s" 36 | (-> ctx :authentication (get "default") ::user ::name)))}}})) 37 | 38 | (defmethod ig/init-key ::basic-auth-example-resource 39 | [_ {:keys [users]}] 40 | (basic-auth-example-resource users)) 41 | -------------------------------------------------------------------------------- /lib/crux.ig/README.adoc: -------------------------------------------------------------------------------- 1 | = Crux-integrant 2 | 3 | A convenient crux/integrant integration, for creating your crux systems with pure data. 4 | 5 | == Usage 6 | 7 | As well as this library, you will need a dependency on crux and either rocksdb or lmdb: 8 | 9 | [source,clojure] 10 | ---- 11 | juxt.crux/ig {:local/root "../lib/crux.ig"} 12 | juxt/crux {:mvn/version "19.04-1.0.2-alpha"} 13 | 14 | ;; Only one of these required: 15 | org.rocksdb/rocksdbjni {:mvn/version "5.17.2"} 16 | ;; 17 | lmdb {:TODO TODO} 18 | ---- 19 | 20 | 21 | === System components 22 | 23 | System components all derive from `:juxt.crux.ig/system`. 24 | 25 | Parameters take configuration as defined in Crux docs: https://juxt.pro/crux/docs/configuration.html#_properties 26 | 27 | .Derivations from standard Crux config 28 | event-log-dir:: If unspecified, will be a temporary directory that is consistent for the JVM 29 | db-dir:: If unspecified, will be a temporary directory that is consistent for the JVM 30 | 31 | .System Components 32 | * `juxt.crux.ig.system/standalone` 33 | * `juxt.crux.ig.system/local-node` 34 | 35 | Example: 36 | 37 | [source,clojure] 38 | ---- 39 | :juxt.crux.ig.system/standalone {:kv-backend "crux.kv.rocksdb.RocksKv"} 40 | :my-web-server {:system #ig/ref :juxt.crux.ig/system} 41 | ---- 42 | 43 | === Embedded Kafka 44 | 45 | TBD 46 | -------------------------------------------------------------------------------- /bin/rebel: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "[Edge] Starting development environment, please wait…" 4 | 5 | # Dependencies are stored in a Bash array. 6 | dependencies=( 'com.bhauman/rebel-readline {:mvn/version "0.1.4"}' 7 | 'juxt.edge/rebel.auto-dev {:local/root "../lib/edge.rebel.auto-dev"}' ) 8 | 9 | jvm_opts=() 10 | 11 | cljs=0 12 | nrepl=0 13 | 14 | while :; do 15 | case $1 in 16 | --cljs) 17 | cljs=1 18 | dependencies+=( 'com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}' ) 19 | shift 20 | ;; 21 | --nrepl) 22 | nrepl=1 23 | dependencies+=( 'juxt.edge/dev.nrepl {:local/root "../lib/edge.dev.nrepl"}' ) 24 | jvm_opts+=( '-J-Dedge.load_edge.dev.nrepl=true' ) 25 | shift 26 | ;; 27 | --) 28 | shift 29 | break 30 | ;; 31 | -?*) 32 | break 33 | ;; 34 | *) 35 | break 36 | esac 37 | done 38 | 39 | if [ "$cljs" -eq 1 ] && [ "$nrepl" -eq 1 ]; then 40 | dependencies+=( 'cider/piggieback {:mvn/version "0.4.1"}' ) 41 | fi 42 | 43 | # Build up the EDN dependency string to pass to `clojure`. 44 | deps="{:deps { ${dependencies[*]} }}" 45 | 46 | clojure "${jvm_opts[@]}" -Sdeps "$deps" "$@" -m edge.rebel.main 47 | -------------------------------------------------------------------------------- /lib/edge.migration/test/tutorial.vent/input/1: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 13 | org.clojure/clojurescript {:mvn/version "1.10.439"}} 14 | 15 | :aliases 16 | {:dev 17 | {:extra-paths ["dev"] 18 | :extra-deps 19 | {juxt.edge/lib.app.dev {:local/root "../lib.app.dev"}}} 20 | 21 | :prod 22 | {:extra-deps 23 | {juxt.edge/lib.app.prod {:local/root "../lib.app.prod"}}} 24 | 25 | :build {:extra-deps 26 | {juxt.edge/kick {:local/root "../edge.kick"} 27 | juxt/kick.alpha 28 | {:git/url "https://github.com/juxt/kick.alpha.git" 29 | :sha "06063beadfa72dfe23480727c347976b608e8316"} 30 | com.bhauman/figwheel-main {:mvn/version "0.2.0"} 31 | 32 | hicada {:mvn/version "0.1.8"} 33 | brutha {:mvn/version "0.2.1"}}} 34 | 35 | :build/once {:main-opts ["-m edge.kick"]} 36 | 37 | :dev/build 38 | {:extra-paths ["target/dev"]} 39 | 40 | :prod/build 41 | {:extra-paths ["target/prod"]}}} 42 | -------------------------------------------------------------------------------- /examples/tutorial.vent/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 13 | org.clojure/clojurescript {:mvn/version "1.10.439"}} 14 | 15 | :aliases 16 | {:dev 17 | {:extra-paths ["dev"] 18 | :extra-deps 19 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 20 | 21 | :prod 22 | {:extra-deps 23 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}} 24 | 25 | :build {:extra-deps 26 | {juxt.edge/kick {:local/root "../lib/edge.kick"} 27 | juxt/kick.alpha 28 | {:git/url "https://github.com/juxt/kick.alpha.git" 29 | :sha "06063beadfa72dfe23480727c347976b608e8316"} 30 | com.bhauman/figwheel-main {:mvn/version "0.2.0"} 31 | 32 | hicada {:mvn/version "0.1.8"} 33 | brutha {:mvn/version "0.2.1"}}} 34 | 35 | :build/once {:main-opts ["-m edge.kick"]} 36 | 37 | :dev/build 38 | {:extra-paths ["target/dev"]} 39 | 40 | :prod/build 41 | {:extra-paths ["target/prod"]}}} 42 | -------------------------------------------------------------------------------- /lib/edge.migration/test/tutorial.vent/output.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 9 | 10 | integrant {:mvn/version "0.7.0"} 11 | 12 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"} 13 | org.clojure/clojurescript {:mvn/version "1.10.439"}} 14 | 15 | :aliases 16 | {:dev 17 | {:extra-paths ["dev"] 18 | :extra-deps 19 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 20 | 21 | :prod 22 | {:extra-deps 23 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}} 24 | 25 | :build {:extra-deps 26 | {juxt.edge/kick {:local/root "../lib/edge.kick"} 27 | juxt/kick.alpha 28 | {:git/url "https://github.com/juxt/kick.alpha.git" 29 | :sha "06063beadfa72dfe23480727c347976b608e8316"} 30 | com.bhauman/figwheel-main {:mvn/version "0.2.0"} 31 | 32 | hicada {:mvn/version "0.1.8"} 33 | brutha {:mvn/version "0.2.1"}}} 34 | 35 | :build/once {:main-opts ["-m edge.kick"]} 36 | 37 | :dev/build 38 | {:extra-paths ["target/dev"]} 39 | 40 | :prod/build 41 | {:extra-paths ["target/prod"]}}} 42 | -------------------------------------------------------------------------------- /lib/edge.logging.dev/README.adoc: -------------------------------------------------------------------------------- 1 | = Development-oriented logging configuration 2 | 3 | A complete logging environment for dev. 4 | 5 | == Log output 6 | 7 | Log messages at WARN or ERROR will be printed to STDOUT. 8 | All application log messages will go to log/app.log. 9 | All log messages will go to log/all.log. 10 | 11 | Your application log messages are detected by looking at log_dev_app.properties, which will look like `app_root_logger=acme.app`. 12 | 13 | Log messages are limited to a maximum size of 512MB for each file (for a total of 1GB), when this happens the oldest files are deleted. 14 | Logs older than 15 days are deleted automatically. 15 | 16 | == Log input 17 | 18 | Logs are collected from 19 | 20 | * SLF4J 21 | * Log4j 1 22 | * Log4j 2 23 | * Commons Logging 24 | * OSGI LogService 25 | * java.util.logging (only when used in conjunction with `dev-extras` from lib.dev.app) 26 | 27 | == Notes 28 | 29 | Make sure your production logback.xml is not activated at the same time as this library (usually the `:dev` alias). 30 | This will commonly happen if you place your logback.xml in `src` or `resources`. 31 | You should instead create a `prod` folder for production-only assets like your production logback.xml. 32 | 33 | == Attribution 34 | 35 | This would not have been possible without Stuart Sierra's foundation in link:https://github.com/stuartsierra/log.dev/[log.dev]. 36 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.9.0"} 4 | yada {:mvn/version "1.3.0-alpha7"} 5 | 6 | integrant {:mvn/version "0.7.0"} 7 | 8 | org.asciidoctor/asciidoctorj {:mvn/version "1.6.0-alpha.6"} 9 | org.jruby/jruby {:mvn/version "1.7.26"} 10 | edge/asciidoctor {:local/root "../lib/edge.asciidoctor"}} 11 | 12 | :aliases 13 | {:dev 14 | {:extra-paths ["dev"] 15 | :extra-deps 16 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 17 | 18 | :demo 19 | {:extra-paths ["demo"] 20 | :extra-deps 21 | {juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 22 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"} 23 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 24 | juxt.asciidoctor/stylesheets {:mvn/version "0.1.2"}}} 25 | 26 | :prod 27 | {:extra-deps 28 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}} 29 | 30 | :build 31 | {:extra-deps 32 | {juxt.edge/kick {:local/root "../lib/edge.kick"} 33 | juxt/kick.alpha 34 | {:git/url "https://github.com/juxt/kick.alpha.git" 35 | :sha "ef8f26dc30305ee9c9e98a1a7dc97320868308f1"} 36 | com.bhauman/figwheel-main {:mvn/version "0.1.9"}}} 37 | 38 | :build/once {:main-opts ["-m edge.kick"]} 39 | 40 | :dev/build 41 | {:extra-paths ["target/dev"]} 42 | 43 | :prod/build 44 | {:extra-paths ["target/prod"]}}} 45 | -------------------------------------------------------------------------------- /lib/edge.kick/src/edge/kick.clj: -------------------------------------------------------------------------------- 1 | (ns edge.kick 2 | (:require 3 | [edge.system :as system] 4 | [edge.kick.builder :refer [load-provider-namespaces]] 5 | [juxt.kick.alpha.core :as kick])) 6 | 7 | (defn- clean 8 | [path] 9 | (letfn [(removable-files [f] 10 | (remove #(= (.getName %) ".gitkeep") (.listFiles f))) 11 | (clean [f] 12 | (when (.isDirectory f) 13 | (doseq [f (removable-files f)] 14 | (clean f))) 15 | (.delete f))] 16 | (doseq [path (removable-files path)] 17 | (clean path)))) 18 | 19 | (defn -main 20 | [& [target-arg]] 21 | (let [config (system/config {:profile :prod}) 22 | kick-init-config (get-in config [:edge.kick/config] 23 | (get-in config [:ig/system :edge.kick/builder])) 24 | kick-config (assoc kick-init-config 25 | :kick.builder/target 26 | (or target-arg 27 | (:kick.builder/target kick-init-config)))] 28 | (load-provider-namespaces kick-config) 29 | ;; When a target-arg is given, assume that we are not reusing a dir. 30 | ;; Otherwise assume the directory is being reused and we are the first 31 | ;; thing being run. 32 | (when-not target-arg 33 | (clean (java.io.File. (:kick.builder/target kick-config)))) 34 | (kick/build-once kick-config))) 35 | -------------------------------------------------------------------------------- /bin/.eftest.clj: -------------------------------------------------------------------------------- 1 | (require '[eftest.runner :refer [find-tests run-tests]]) 2 | (require '[eftest.report :refer [report-to-file]]) 3 | (require 'eftest.report.progress) 4 | (require 'clojure.test) 5 | (require 'orchard.query) 6 | 7 | (def junit? (= (first *command-line-args*) "--junit")) 8 | (def junit-path (when junit? 9 | (second *command-line-args*))) 10 | 11 | (defn combined-reporter 12 | "Combines the reporters by running first one directly, 13 | and others with clojure.test/*report-counters* bound to nil." 14 | [report rst] 15 | (fn [m] 16 | (report m) 17 | (doseq [report rst] 18 | (binding [clojure.test/*report-counters* nil] 19 | (report m))))) 20 | 21 | (let [summary (run-tests 22 | (find-tests 23 | ;; This is slow, because requiring namespaces is slow 24 | (orchard.query/namespaces {:load-project-ns? true 25 | :project? true})) 26 | {:report 27 | (combined-reporter 28 | eftest.report.progress/report 29 | (filter 30 | identity 31 | [(when junit? 32 | (report-to-file 33 | (requiring-resolve 'eftest.report.junit/report) 34 | junit-path))]))})] 35 | (System/exit (+ (:error summary) (:fail summary)))) 36 | -------------------------------------------------------------------------------- /examples/phonebook-api/resources/phonebook-api/templates/phonebook.html: -------------------------------------------------------------------------------- 1 | {% extends "_wrapper.html" %} 2 | 3 | {% block main %} 4 | 5 |

Phonebook

6 | 7 |

{{ messages.description }}

8 | 9 |
10 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for entry in entries %} 28 | 29 | 30 | 31 | 32 | 33 | 34 | {% endfor %} 35 | 36 |
IdSurnameFirstnamePhone
{{ entry.id }}{{ entry.surname }}{{ entry.firstname }}{{ entry.phone }}
37 | 38 |

Add entry

39 | 40 |
41 |

42 | 43 | 44 |

45 |

46 | 47 | 48 |

49 |

50 | 51 | 52 |

53 |

54 | 55 |

56 |
57 | 58 |
59 | 60 | {% endblock %} 61 | -------------------------------------------------------------------------------- /examples/main/src/edge/selmer.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.selmer 4 | (:require 5 | [hiccup.core :refer [html]] 6 | [integrant.core :as ig] 7 | [selmer.filter-parser :refer [compile-filter-body]] 8 | [selmer.parser :as selmer] 9 | [yada.yada :as yada])) 10 | 11 | (defn- make-url-fn [k] 12 | (fn [args context-map] 13 | (when-let [ctx (:ctx context-map)] 14 | (get (yada/uri-info 15 | ctx 16 | (keyword (first args)) 17 | {:route-params 18 | (reduce (fn [acc [k v]] 19 | (assoc acc 20 | (keyword k) 21 | ((compile-filter-body v) context-map))) 22 | {} 23 | (partition 2 (rest args)))}) 24 | k)))) 25 | 26 | (defn add-url-tag! 27 | "Add a tag that gives access to yada's uri-info function in templates" 28 | [] 29 | (selmer/add-tag! :href (make-url-fn :href)) 30 | (selmer/add-tag! :url (make-url-fn :uri)) 31 | (selmer/add-tag! :source (fn [args context-map] 32 | (html [:tt [:a {:href (str "/sources/" (first args))} (first args)]])))) 33 | 34 | (defmethod ig/init-key :edge/selmer 35 | [_ {:edge.selmer/keys [template-caching?]}] 36 | (selmer/set-resource-path! "templates") 37 | 38 | (if template-caching? 39 | (selmer.parser/cache-on!) 40 | (selmer.parser/cache-off!)) 41 | 42 | (add-url-tag!)) 43 | -------------------------------------------------------------------------------- /examples/phonebook-api/dev/edge/selmer.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016, JUXT LTD. 2 | 3 | (ns edge.selmer 4 | (:require 5 | [hiccup.core :refer [html]] 6 | [integrant.core :as ig] 7 | [selmer.filter-parser :refer [compile-filter-body]] 8 | [selmer.parser :as selmer] 9 | [yada.yada :as yada])) 10 | 11 | (defn- make-url-fn [k] 12 | (fn [args context-map] 13 | (when-let [ctx (:ctx context-map)] 14 | (get (yada/uri-info 15 | ctx 16 | (keyword (first args)) 17 | {:route-params 18 | (reduce (fn [acc [k v]] 19 | (assoc acc 20 | (keyword k) 21 | ((compile-filter-body v) context-map))) 22 | {} 23 | (partition 2 (rest args)))}) 24 | k)))) 25 | 26 | (defn add-url-tag! 27 | "Add a tag that gives access to yada's uri-info function in templates" 28 | [] 29 | (selmer/add-tag! :href (make-url-fn :href)) 30 | (selmer/add-tag! :url (make-url-fn :uri)) 31 | (selmer/add-tag! :source (fn [args context-map] 32 | (html [:tt [:a {:href (str "/sources/" (first args))} (first args)]])))) 33 | 34 | (defmethod ig/init-key :edge/selmer 35 | [_ {:edge.selmer/keys [template-caching?]}] 36 | (selmer/set-resource-path! "templates") 37 | 38 | (if template-caching? 39 | (selmer.parser/cache-on!) 40 | (selmer.parser/cache-off!)) 41 | 42 | (add-url-tag!)) 43 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/demo/config.edn: -------------------------------------------------------------------------------- 1 | {:ns/demo #profile {:prod "Prod works" 2 | :dev "Dev works"} 3 | :ig/system 4 | {:edge.asciidoctor/engine nil 5 | :juxt.edge.doc-site/routes {:edge.asciidoctor/engine #ig/ref :edge.asciidoctor/engine} 6 | [:juxt.edge.doc-site/assets :edge.yada.ig/resources] {:path "public/"} 7 | [:juxt.asciidoctor/assets :edge.yada.ig/classpath-name] 8 | {:name "juxt/asciidoctor/stylesheets/juxt.css"} 9 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 10 | :port 3000} 11 | :edge.bidi.ig/vhost [["http://localhost:3000" 12 | ["" 13 | [["/" #ig/ref :juxt.edge.doc-site/routes] 14 | ["/juxt.css" #ig/ref :juxt.asciidoctor/assets] 15 | ["" #ig/ref [:juxt.edge.doc-site/assets :edge.yada.ig/resources]]]]]] 16 | :edge.kick/builder 17 | {:kick.builder/target #profile {:dev "target/dev" 18 | :prod "target/prod"} 19 | 20 | :kick/figwheel-main {:builds [{:id "doc" 21 | :main juxt.edge.doc-site.doc 22 | :output-to "public/doc.js" 23 | :output-dir "public/doc.out" 24 | :asset-path "/doc.out" 25 | :optimizations #profile {:dev :none 26 | :prod :advanced}}]}}}} 27 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/src/juxt/edge/doc_site.clj: -------------------------------------------------------------------------------- 1 | (ns juxt.edge.doc-site 2 | (:require 3 | [integrant.core :as ig] 4 | [clojure.java.io :as io] 5 | [edge.asciidoctor :refer [load-doc]] 6 | [yada.yada :as yada])) 7 | 8 | (defn routes [engine] 9 | [["" (merge 10 | (yada/redirect ::doc-resource {:route-params {:name "index"}}) 11 | {:id ::doc-index})] 12 | [[;; regex derived from bidi's default, but adding / to allow directories 13 | [#"[A-Za-z0-9\\-\\_\\.\/]+" :name] ".html"] 14 | (yada/resource 15 | {:id ::doc-resource 16 | :methods 17 | {:get 18 | {:produces [{:media-type "text/html;q=0.8" :charset "utf-8"} 19 | {:media-type "application/json"}] 20 | :response (fn [ctx] 21 | (let [path (str "doc/sources/" (-> ctx :parameters :path :name) ".adoc")] 22 | (try 23 | (.convert 24 | (load-doc 25 | ctx 26 | engine 27 | (-> ctx :parameters :path :name) 28 | (slurp (io/resource path)))) 29 | (catch Exception e 30 | (throw (ex-info (format "Failed to convert %s" path) 31 | {:path path} e))))))}}})]]) 32 | 33 | (defmethod ig/init-key ::routes [_ {:keys [edge.asciidoctor/engine]}] 34 | (routes engine)) 35 | -------------------------------------------------------------------------------- /lib/edge.dev.nrepl/src/edge/dev/nrepl.clj: -------------------------------------------------------------------------------- 1 | (ns ^{:clojure.tools.namespace.repl/load false} edge.dev.nrepl 2 | (:require 3 | [nrepl.server] 4 | [clojure.java.io :as io] 5 | [cider.nrepl] 6 | [refactor-nrepl.middleware :as refactor.nrepl] 7 | [io.aviso.ansi])) 8 | 9 | (def piggieback 10 | (try 11 | (require 'cider.piggieback) 12 | (resolve 'cider.piggieback/wrap-cljs-repl) 13 | (catch java.io.FileNotFoundException _ 14 | ;; Ignore, piggieback isn't present 15 | ))) 16 | 17 | (defn start-nrepl 18 | [opts] 19 | (let [server 20 | (nrepl.server/start-server 21 | :port (:port opts) 22 | :handler 23 | (apply nrepl.server/default-handler 24 | (cond-> (map #'cider.nrepl/resolve-or-fail cider.nrepl/cider-middleware) 25 | true 26 | (conj #'refactor.nrepl/wrap-refactor) 27 | piggieback 28 | (conj piggieback))))] 29 | (let [port (:port server) 30 | port-file (io/file ".nrepl-port")] 31 | (.deleteOnExit port-file) 32 | (spit port-file port)) 33 | (println (io.aviso.ansi/yellow (str "[Edge] nREPL client can be connected to port " (:port server)))) 34 | server)) 35 | 36 | (def port (or (some-> 37 | (System/getenv "NREPL_PORT") 38 | Integer/parseInt) 39 | 5600)) 40 | 41 | (println "[Edge] Starting nREPL server on port" port) 42 | 43 | (def server (start-nrepl {:port port})) 44 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.10.0"} 4 | juxt.edge/lib.app {:local/root "../lib/edge.app"}{{#web}} 5 | 6 | yada {:mvn/version "1.3.0-alpha7"} 7 | juxt.edge/yada.ig {:local/root "../lib/edge.ig.yada"} 8 | juxt.edge/bidi.ig {:local/root "../lib/edge.ig.bidi"}{{/web}} 9 | integrant {:mvn/version "0.7.0"} 10 | 11 | org.clojure/tools.logging {:mvn/version "0.5.0-alpha"}} 12 | 13 | :aliases 14 | {:dev 15 | {:extra-paths ["dev"] 16 | :extra-deps 17 | {juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"}}} 18 | 19 | :prod 20 | {:extra-deps 21 | {juxt.edge/lib.app.prod {:local/root "../lib/edge.app.prod"}}}{{#kick}} 22 | 23 | :build {:extra-deps 24 | {juxt.edge/kick {:local/root "../lib/edge.kick"} 25 | juxt/kick.alpha 26 | {:git/url "https://github.com/juxt/kick.alpha.git" 27 | :sha "06063beadfa72dfe23480727c347976b608e8316"}{{#cljs}} 28 | org.clojure/clojurescript {:mvn/version "1.10.238"}{{#reframe}} 29 | reagent {:mvn/version "0.8.1"} 30 | re-frame {:mvn/version "0.10.6"}{{/reframe}} 31 | com.bhauman/figwheel-main {:mvn/version "0.2.0"}{{/cljs}}{{#sass}} 32 | deraen/sass4clj {:mvn/version "0.3.1"}{{/sass}}}} 33 | 34 | :build/once {:main-opts ["-m edge.kick"]} 35 | 36 | :dev/build 37 | {:extra-paths ["target/dev"]} 38 | 39 | :prod/build 40 | {:extra-paths ["target/prod"]}{{/kick}}}} 41 | -------------------------------------------------------------------------------- /examples/main/resources/public/highlight/styles/tomorrow-night.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Night Theme */ 2 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 3 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 4 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 5 | 6 | /* Tomorrow Comment */ 7 | .hljs-comment, 8 | .hljs-quote { 9 | color: #969896; 10 | } 11 | 12 | /* Tomorrow Red */ 13 | .hljs-variable, 14 | .hljs-template-variable, 15 | .hljs-tag, 16 | .hljs-name, 17 | .hljs-selector-id, 18 | .hljs-selector-class, 19 | .hljs-regexp, 20 | .hljs-deletion { 21 | color: #cc6666; 22 | } 23 | 24 | /* Tomorrow Orange */ 25 | .hljs-number, 26 | .hljs-built_in, 27 | .hljs-builtin-name, 28 | .hljs-literal, 29 | .hljs-type, 30 | .hljs-params, 31 | .hljs-meta, 32 | .hljs-link { 33 | color: #de935f; 34 | } 35 | 36 | /* Tomorrow Yellow */ 37 | .hljs-attribute { 38 | color: #f0c674; 39 | } 40 | 41 | /* Tomorrow Green */ 42 | .hljs-string, 43 | .hljs-symbol, 44 | .hljs-bullet, 45 | .hljs-addition { 46 | color: #b5bd68; 47 | } 48 | 49 | /* Tomorrow Blue */ 50 | .hljs-title, 51 | .hljs-section { 52 | color: #81a2be; 53 | } 54 | 55 | /* Tomorrow Purple */ 56 | .hljs-keyword, 57 | .hljs-selector-tag { 58 | color: #b294bb; 59 | } 60 | 61 | .hljs { 62 | display: block; 63 | overflow-x: auto; 64 | background: #1d1f21; 65 | color: #c5c8c6; 66 | padding: 0.5em; 67 | } 68 | 69 | .hljs-emphasis { 70 | font-style: italic; 71 | } 72 | 73 | .hljs-strong { 74 | font-weight: bold; 75 | } 76 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/tutorial/vent/lib.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.vent.lib 2 | (:require 3 | [tutorial.vent.db :as db])) 4 | 5 | (defn favorites 6 | [] 7 | [{:id "1" 8 | :text "A favorited tweet" 9 | :author {:name "John smith"} 10 | :username "john_smith" 11 | :favorite? true} 12 | {:id "2" 13 | :text "Another favorite tweet" 14 | :author {:name "Jane Smith"} 15 | :username "jane_smith" 16 | :favorite? true}]) 17 | 18 | (defn all 19 | [] 20 | [{:id "1" 21 | :text "A hardcoded tweet" 22 | :author {:name "John Smith"} 23 | :username "john_smith" 24 | :favorite? true} 25 | {:id "2" 26 | :text "A second hardcoded tweet" 27 | :author {:name "Jane Smith"} 28 | :username "jane_smith"}]) 29 | 30 | (defn followers 31 | [{:keys [username]}] 32 | {"john_smith" 33 | {:name "John Smith"} 34 | "jane_smith" 35 | {:name "Jane Smith" 36 | :following? true}}) 37 | 38 | (defn following 39 | [{:keys [username]}] 40 | {"jane_smith" 41 | {:name "Jane Smith" 42 | :following? true}}) 43 | 44 | (defn toggle-favorite 45 | [{:keys [vent-id]}] 46 | (println "toggling favorite on" vent-id)) 47 | 48 | (defn- generate-id 49 | [] 50 | (str (java.util.UUID/randomUUID))) 51 | 52 | (defn add-vent 53 | [{:keys [text username]}] 54 | (println username 55 | "is venting about" text 56 | "with id" (generate-id))) 57 | 58 | (defn toggle-follow 59 | [{:keys [to-follow username]}] 60 | (println username "is follwoing or unfollowing" to-follow)) 61 | -------------------------------------------------------------------------------- /lib/edge.kick/src/edge/kick/builder.clj: -------------------------------------------------------------------------------- 1 | (ns edge.kick.builder 2 | (:require 3 | [integrant.core :as ig] 4 | [edge.system.meta :refer [useful-info]] 5 | [juxt.kick.alpha.core :as kick])) 6 | 7 | (defn load-provider-namespaces 8 | [kick-config] 9 | (doseq [provider (keys kick-config) 10 | :when (= (namespace provider) "kick")] 11 | (when (= (namespace provider) "kick") 12 | (let [sym (symbol (str "juxt.kick.alpha.providers." (name provider)))] 13 | (try (do (require sym) sym) 14 | (catch java.io.FileNotFoundException _)))))) 15 | 16 | (defmethod ig/init-key :edge.kick/builder 17 | [_ v] 18 | (load-provider-namespaces v) 19 | (kick/watch v)) 20 | 21 | (defmethod ig/halt-key! :edge.kick/builder 22 | [_ close] 23 | (close)) 24 | 25 | (defmethod ig/suspend-key! :edge.kick/builder [_ _]) 26 | 27 | (defmethod ig/resume-key :edge.kick/builder 28 | [key opts old-opts old-impl] 29 | (if (= opts old-opts) 30 | old-impl 31 | (do (ig/halt-key! key old-impl) 32 | (ig/init-key key opts)))) 33 | 34 | (defmethod useful-info :edge.kick/builder 35 | [_ config state] 36 | (when (get-in config [:kick/figwheel-main 37 | :figwheel-config 38 | :auto-testing]) 39 | (format "Tests available at: http://localhost:%d/figwheel-extra-main/auto-testing" 40 | (get-in config 41 | [:kick/figwheel-main 42 | :figwheel-config 43 | :ring-server-options 44 | :port] 45 | 9500)))) 46 | -------------------------------------------------------------------------------- /examples/main/resources/public/highlight/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006, Ivan Sagalaev 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of highlight.js nor the names of its contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /lib/crux.ig/src/juxt/crux/ig/system.clj: -------------------------------------------------------------------------------- 1 | (ns juxt.crux.ig.system 2 | (:require [clojure.java.io :as io] 3 | crux.api 4 | [integrant.core :as ig]) 5 | (:import java.nio.file.attribute.FileAttribute 6 | java.nio.file.Files)) 7 | 8 | (defn- delete-directory 9 | "Delete a directory and all files within" 10 | [f] 11 | (run! io/delete-file (filter #(.isFile %) (file-seq f))) 12 | (run! io/delete-file (reverse (file-seq f)))) 13 | 14 | (def ^:private tmp-dir 15 | ;; tools refresh wipes this out, to which I don't have an easy solution. 16 | ;; I could move it to another namespace which has reloading disabled perhaps. 17 | (memoize 18 | (fn [identity] 19 | (let [path (Files/createTempDirectory nil (into-array FileAttribute []))] 20 | (.addShutdownHook 21 | (Runtime/getRuntime) 22 | (new Thread (fn [] (delete-directory (.toFile path))))) 23 | (.mkdir (.toFile path)) 24 | (str path))))) 25 | 26 | (defmethod ig/halt-key! :juxt.crux.ig/system 27 | [_ system] 28 | (.close system)) 29 | 30 | (defmethod ig/prep-key :juxt.crux.ig/system 31 | [k opts] 32 | (cond-> opts 33 | (not (contains? opts :event-log-dir)) 34 | (assoc :event-log-dir (tmp-dir [k "event-log"])) 35 | (not (contains? opts :db-dir)) 36 | (assoc :db-dir (tmp-dir [k "db-dir"])))) 37 | 38 | (derive ::standalone :juxt.crux.ig/system) 39 | 40 | (defmethod ig/init-key ::standalone 41 | [_ opts] 42 | (crux.api/start-standalone-node opts)) 43 | 44 | (derive ::cluster-node :juxt.crux.ig/system) 45 | 46 | (defmethod ig/init-key ::cluster-node 47 | [_ opts] 48 | (crux.api/start-cluster-node opts)) 49 | -------------------------------------------------------------------------------- /lib/edge.app.dev/src/user.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2016-2019, JUXT LTD. 2 | 3 | (ns user 4 | (:require 5 | [clojure.tools.namespace.repl :refer :all] 6 | [clojure.java.classpath :refer [classpath-directories]] 7 | [io.aviso.ansi] 8 | [integrant.repl.state] 9 | [spyscope.core])) 10 | 11 | ;; Work around TNS-45. This used to be fixed by using a forked version of tns, 12 | ;; but because it now comes in transitively, it cannot be compared. This might 13 | ;; be fixed by TDEPS-17. 14 | (let [edge-target? (fn [f] 15 | ;; match target, target/dev target/prod, etc. 16 | (re-matches #".*target(/\w+)?" (str f)))] 17 | (apply set-refresh-dirs 18 | (remove edge-target? (classpath-directories)))) 19 | 20 | (let [prefix "edge.load_"] 21 | (doseq [[prop _] 22 | (filter 23 | (fn [[prop _]] 24 | (.startsWith prop prefix)) 25 | (into {} (System/getProperties)))] 26 | (require (symbol (subs prop (count prefix)))))) 27 | 28 | (let [lock (Object.)] 29 | (defn dev 30 | "Call this to switch to the dev namespace." 31 | [] 32 | (println "[Edge] Loading Clojure code, please wait...") 33 | (locking lock 34 | (require 'dev)) 35 | (when-not integrant.repl.state/system 36 | (println (io.aviso.ansi/bold-yellow "[Edge] Enter (go) to start the dev system"))) 37 | (in-ns 'dev))) 38 | 39 | (defn fixed! 40 | "If, for some reason, the Clojure code in the project fails to 41 | compile - we still bring up a REPL to help debug the problem. Once 42 | the problem has been resolved you can call this function to continue 43 | development." 44 | [] 45 | (refresh-all) 46 | (in-ns 'dev)) 47 | -------------------------------------------------------------------------------- /examples/main/src/edge/yada/lacinia.clj: -------------------------------------------------------------------------------- 1 | (ns edge.yada.lacinia 2 | (:require 3 | [clojure.tools.logging :as log] 4 | [manifold.deferred :as d] 5 | [manifold.stream :as ms] 6 | com.walmartlabs.lacinia.parser 7 | [com.walmartlabs.lacinia :refer [execute]] 8 | [com.walmartlabs.lacinia.executor :as executor] 9 | [com.walmartlabs.lacinia.resolve :as resolve])) 10 | 11 | ;; TODO: Promote to yada/ext 12 | (defn subscription-stream [schema q {:keys [edge/executor] :as config}] 13 | (assert schema) 14 | ;; see com.walmartlabs.lacinia.pedestal.subscriptions/query-parser-interceptor 15 | (assert (map? schema)) 16 | 17 | (let [parsed-query (com.walmartlabs.lacinia.parser/parse-query schema q nil) 18 | prepared (com.walmartlabs.lacinia.parser/prepare-with-query-variables parsed-query {} #_variables) 19 | ;; TODO: Validate 20 | ;;(validator/validate actual-schema prepared {}) 21 | ctx (merge config {com.walmartlabs.lacinia.constants/parsed-query-key prepared})] 22 | 23 | (let [source-stream (ms/stream 100 nil executor) 24 | close-fn (com.walmartlabs.lacinia.executor/invoke-streamer 25 | ctx (fn callback [value] 26 | (let [value 27 | (executor/execute-query 28 | (assoc ctx ::executor/resolved-value value))] 29 | 30 | (resolve/on-deliver! 31 | value 32 | (fn [result] 33 | (ms/put! source-stream result))))))] 34 | 35 | ;; If the source-stream we're about to return is ever closed, stop producing data 36 | (ms/on-closed source-stream close-fn) 37 | 38 | source-stream))) 39 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/guidelines.adoc: -------------------------------------------------------------------------------- 1 | = Contributing Guidelines 2 | 3 | == Asciidoc 4 | 5 | Asciidoc should be formatted according to link:https://asciidoctor.org/docs/asciidoc-recommended-practices/[Asciidoctor's Recommended Practices]. 6 | The notable thing that's counter-intuitive is "One Sentence Per Line". 7 | 8 | == Updating the Template 9 | 10 | Be very careful about waving away difficult setup for modules behind "oh, but the template generator can do that!". 11 | 12 | * This kind of change makes it difficult to roll out improvements to existing users 13 | * Users should always be looking at low-clutter files in order to allow them to maximize focus on their project, not Edge 14 | 15 | Clojure is an extremely dynamic language, and it's likely that you can find a solution which involves dynamic loading. 16 | 17 | == Updating modules 18 | 19 | Be careful around the really common paths for users (lib.app.dev, lib.app.prod). 20 | I don't think Edge needs perfect stability, but close enough should happen. 21 | 22 | When updating things think really hard about the impact on existing programs. 23 | Conditional & deferred resolutions of dependencies may be helpful for these cases. 24 | 25 | It's okay to offer new features, but degraded unless the user takes action. 26 | 27 | == Writing Documentation 28 | 29 | A great reference on how documentation should be written is https://jacobian.org/tags/great-documentation/[]. 30 | See link:https://docs.djangoproject.com/en/2.1/[Django's] for an example. 31 | 32 | == Design Principles 33 | 34 | Design principles to keep in mind when working on things. 35 | 36 | * Developers want to focus on their projects not Edge, component systems are just incidental complexity 37 | * Modules allow people to reduce the program scope stored in their head at once 38 | * Modules allow updating code for people without merge conflicts 39 | * Simple and Easy is a careful balance, but Edge aims to be easy 40 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/editor.adoc: -------------------------------------------------------------------------------- 1 | = Set up your editor for Clojure 2 | 3 | There's a number of good choices for Clojure editors. 4 | This page will link you to the installation documentation for your editor, and provide some common config choices. 5 | 6 | == Atom 7 | 8 | Atom has two popular options. 9 | 10 | link:https://atom.io/packages/proto-repl[ProtoREPL] is the older of the two, and is well established. 11 | ProtoREPL has an link:https://git.io/atom_clojure_setup[Opinionated Setup Guide]. 12 | 13 | == Emacs 14 | 15 | Emacs is a favourite in the Clojure community. 16 | For emacs, the most popular package for integrating with Clojure is CIDER. 17 | 18 | * link:http://www.cider.mx/en/latest/installation/[CIDER's installation]. 19 | 20 | If you're new to emacs, you should try link:https://www.braveclojure.com/basic-emacs/[]. 21 | 22 | == Intellij (Cursive) 23 | 24 | If you're most at home in an IDE, you'll be looking for link:https://cursive-ide.com/[Cursive]. 25 | Free for non-commerical use, but you'll need a license for commercial use. 26 | 27 | == Spacemacs 28 | 29 | Spacemacs has a fantastic Clojure layer. 30 | Find more information in the link:http://spacemacs.org/layers/+lang/clojure/README.html[Spacemacs layer README]. 31 | 32 | If you're new to Spacemacs, check out this video: link:https://www.youtube.com/watch?v=Uuwg-069NYE[] 33 | 34 | == Vim 35 | 36 | Vim's most popular package for Clojure integration is tpope's link:https://github.com/tpope/vim-fireplace[vim-fireplace]. 37 | It is commonly paired with link:https://github.com/guns/vim-sexp[vim-sexp] and/or link:https://github.com/eraserhd/parinfer-rust[parinfer]. 38 | Finally, for some convenience, you might want to add link:https://github.com/SevereOverfl0w/vim-replant[REPLant]. 39 | 40 | You can find a collection of hints on the JUXT blog at link:https://juxt.pro/blog/posts/vim-1.html[]. 41 | 42 | == VSCode 43 | 44 | link:https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva[Calva] is a fantastic integration for Clojure with VSCode. 45 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/tutorial/vent/http_api.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.vent.http-api 2 | (:require 3 | [integrant.core :as ig] 4 | [yada.yada :as yada] 5 | yada.handler 6 | [yada.security :refer [verify]] 7 | [clojure.walk :as walk])) 8 | 9 | (defn- resolve-params 10 | [m pull] 11 | (reduce-kv 12 | (fn [pulled k v] 13 | (assoc pulled k (get-in m v))) 14 | pull 15 | pull)) 16 | 17 | (defn- api-resource 18 | [res] 19 | (yada.handler/insert-interceptor 20 | (yada/handler 21 | (yada/resource 22 | (-> res 23 | (update :methods 24 | (fn [methods] 25 | (reduce-kv 26 | (fn [methods k v] 27 | (let [sym (::symbol v)] 28 | (require (symbol (namespace sym))) 29 | 30 | (-> (walk/postwalk 31 | (fn [x] 32 | (if (= 'String x) 33 | String 34 | x)) 35 | methods) 36 | 37 | (update-in [k :produces] 38 | (fnil conj #{}) 39 | "application/edn") 40 | (assoc-in [k :response] 41 | (fn [ctx] 42 | (def ctx ctx) 43 | (if-let [params (::params v)] 44 | ((resolve sym) 45 | (resolve-params ctx params)) 46 | ((resolve sym)))))))) 47 | methods 48 | methods)))))) 49 | yada.security/authorize 50 | (fn [ctx] 51 | (assoc ctx :authentication "developer")))) 52 | 53 | (defmethod ig/init-key ::api-resource 54 | [_ res] 55 | (api-resource res)) 56 | -------------------------------------------------------------------------------- /examples/main/prod/user.clj: -------------------------------------------------------------------------------- 1 | (ns user 2 | (:gen-class) 3 | (:require 4 | [clojure.tools.namespace.repl :as repl] 5 | [clojure.tools.logging :as log] 6 | [integrant.core :as ig] 7 | [edge.system :refer [system-config]])) 8 | 9 | (repl/disable-reload!) 10 | 11 | (when (System/getProperty "edge.load_nrepl") 12 | (require 'nrepl)) 13 | 14 | (def system {}) 15 | 16 | (defonce system-agent (agent {})) 17 | 18 | (defn resume [profile] 19 | (println "Resuming system") 20 | (ig/init (system-config {:profile profile}))) 21 | 22 | (defn reset* [] 23 | (log/info "Signal HUP received, halting!") 24 | (ig/halt! system) 25 | (log/info "System halted. Refreshing code") 26 | (repl/refresh) 27 | (log/info "Code refreshed. Resuming system.") 28 | ;; TODO: parameterize profile 29 | (resume :prod)) 30 | 31 | (defn reset 32 | ([] 33 | (let [thread-bindings (get-thread-bindings)] 34 | (send 35 | system-agent 36 | (fn [system] 37 | (with-bindings thread-bindings 38 | (reset*)))))) 39 | ([thread-bindings] 40 | (send 41 | system-agent 42 | (fn [system] 43 | (with-bindings thread-bindings 44 | (reset*)))))) 45 | 46 | (defn -main 47 | "Run the system. The first argument is the configuration profile (as a 48 | string), defaulting to 'prod'." 49 | [& args] 50 | 51 | (set-error-handler! 52 | system-agent 53 | (fn [a error] 54 | (println "ERROR:" error) 55 | ;; TODO: Restart the agent 56 | )) 57 | 58 | (add-watch 59 | system-agent 60 | :reset 61 | (fn [k r old new] 62 | (alter-var-root #'system (constantly new)))) 63 | 64 | (let [profile (or (some-> (first args) keyword) :prod) 65 | system-config (system-config {:profile profile})] 66 | (send system-agent (constantly (ig/init system-config))) 67 | 68 | (let [bindings (get-thread-bindings)] 69 | (sun.misc.Signal/handle 70 | (sun.misc.Signal. "HUP") 71 | (reify sun.misc.SignalHandler 72 | (handle [_ signal] 73 | (reset bindings))))))) 74 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/tutorial/vent/db.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.vent.db 2 | "A mock database which will simulate storage of EDN data." 3 | (:require 4 | [clojure.edn :as edn] 5 | [clojure.java.io :as io] 6 | [clojure.pprint :as pp] 7 | [tutorial.vent.reload :as vent.reload]) 8 | (:refer-clojure :exclude [read])) 9 | 10 | (def ^:private file-lock (Object.)) 11 | (def ^:private file (io/file "db.edn")) 12 | 13 | (defn- ->edn 14 | [x] 15 | (binding [*print-length* nil 16 | *print-level* nil 17 | *print-namespace-maps* false 18 | pp/*print-right-margin* 100 19 | pp/*print-miser-width* 80] 20 | (let [edn-str (with-out-str 21 | (pp/pprint x))] 22 | ;; Confirm that the edn reads back, i.e. there are no #object or similar 23 | ;; that can't be read 24 | (try 25 | (edn/read-string edn-str) 26 | (catch Exception e 27 | (throw (ex-info "Your data cannot be read back safely" {:data x} 28 | e)))) 29 | edn-str))) 30 | 31 | (defn reset 32 | [] 33 | (locking file-lock 34 | (spit file 35 | (->edn 36 | {:users {"jane_smith" {:name "Jane Smith"} 37 | "john_smith" {:name "John Smith" 38 | :follows ["developer"]} 39 | "developer" {:name "Edit Me!" 40 | :follows ["john_smith"]}} 41 | :vents [{:id "1" 42 | :username "jane_smith" 43 | :text "A tweet from the database"} 44 | {:id "2" 45 | :username "john_smith" 46 | :text "Another tweet from the database" 47 | :favorite? true}]})) 48 | (vent.reload/frontend))) 49 | 50 | (locking file-lock 51 | (when-not (.exists file) 52 | (reset))) 53 | 54 | (defn store 55 | [x] 56 | (locking file-lock 57 | (spit file (->edn x)) 58 | (vent.reload/frontend))) 59 | 60 | (defn read 61 | [] 62 | (locking file-lock 63 | (edn/read (-> file io/reader clojure.lang.LineNumberingPushbackReader.)))) 64 | -------------------------------------------------------------------------------- /lib/edge.ig.yada/src/edge/yada/ig.clj: -------------------------------------------------------------------------------- 1 | (ns edge.yada.ig 2 | (:require 3 | [clojure.java.io :as io] 4 | [edge.system.meta :refer [useful-info]] 5 | [yada.yada :as yada] 6 | [integrant.core :as ig] 7 | [yada.resources.resources-resource :refer [new-resources-resource]])) 8 | 9 | (defmethod ig/init-key ::listener 10 | [_ opts] 11 | (assoc (yada/listener (:handler opts) 12 | (dissoc opts :handler)) 13 | ::handler (:handler opts))) 14 | 15 | (defmethod ig/halt-key! ::listener 16 | [_ {:keys [close]}] 17 | (when close (close))) 18 | 19 | (defmethod ig/init-key ::redirect 20 | [_ {:keys [target opts]}] 21 | (apply yada/redirect (filter some? [target opts]))) 22 | 23 | (defmethod ig/init-key ::resources 24 | [_ {:keys [path id]}] 25 | (cond-> (new-resources-resource path) 26 | id 27 | (assoc :id id))) 28 | 29 | (defmethod ig/init-key ::classpath-name 30 | [_ {:keys [name]}] 31 | (yada/as-resource (io/resource name))) 32 | 33 | (defmethod ig/init-key ::webjar 34 | [_ {:keys [webjar] :as options}] 35 | (@(requiring-resolve 'yada.resources.webjar-resource/new-webjar-resource) 36 | webjar 37 | options)) 38 | 39 | (defmethod ig/init-key ::webjars-route-pair 40 | [_ options] 41 | (@(requiring-resolve 'yada.resources.webjar-resource/webjars-route-pair) 42 | options)) 43 | 44 | ;; Use getName to avoid requiring a direct dependency on bidi, etc. 45 | (defmulti ^:private hosts 46 | (fn [config state] 47 | (some-> (::handler state) type (.getName)))) 48 | 49 | (defmethod hosts "bidi.vhosts.VHostsModel" 50 | [config state] 51 | (let [vhosts (mapcat first (:vhosts (::handler state)))] 52 | (map (fn [vhost] 53 | (if (= :* vhost) 54 | (str "http://localhost:" (:port state)) 55 | (str (name (:scheme vhost)) "://" (:host vhost)))) 56 | vhosts))) 57 | 58 | (defmethod hosts :default 59 | [config state] 60 | ;; Not a terrible assumption 61 | [(str "http://localhost:" (:port state))]) 62 | 63 | (defmethod useful-info ::listener 64 | [_ config state] 65 | (str "Website listening on: " 66 | (apply str (interpose " " (hosts config state))))) 67 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/elastic-beanstalk.adoc: -------------------------------------------------------------------------------- 1 | = Using the Elastic Beanstalk Quickstart 2 | 3 | It's very convenient in the early stages of your project to quickly run it in an environment. 4 | This guide will give you some information on the example Cloudformation Script provided in Edge. 5 | 6 | == Creating your Stack 7 | 8 | WARN: Following the steps outlined below _will incur charges_. 9 | 10 | The cloudformation template can be found at `examples/cloudformation/elasticbeanstalk/stack.yaml` in the Edge repository. 11 | This template is meant to be modified by you to fit your needs, its a starting point. 12 | 13 | You can create a stack with the template using multiple strategies. 14 | 15 | === Create Stack Strategy 1: The AWS CLI 16 | 17 | Use this strategy if you already have your AWS CLI configured. 18 | `aws configure` can be used to configure AWS CLI to setup your profiles if you haven't already. 19 | 20 | [source,shell] 21 | ---- 22 | $ aws cloudformation create-stack --stack-name "$my-stack-name" --parameters ParameterKey=Description,ParameterValue='ACME Todo List Application' ParameterKey=CNAMEPrefix,ParameterValue=acme-todo 23 | ---- 24 | 25 | === Create Stack Strategy 2: Upload the template to the AWS Console 26 | 27 | . Log in to the link:https://console.aws.amazon.com/console/home[AWS Console] 28 | . Click "Services", then "Cloudformation" 29 | . Click "Create Stack" button 30 | . Select "Template is Ready" 31 | . Select "Upload a template file" 32 | . Choose the file `examples/cloudformation/elasticbeanstalk/stack.yaml` inside of your Edge repository 33 | . Follow the rest of the wizard 34 | 35 | == Produce an Uberjar 36 | 37 | To release to Elastic Beanstalk, you will need an uberjar. 38 | Please see <>. 39 | 40 | == Upload your jar 41 | 42 | Monitor the creation of your cloudformation stack from the "Stacks" tab in that service. 43 | Once complete, navigate to "Services" > "Elastic Beanstalk". 44 | 45 | Click on your newly created Environment. 46 | In the overview section there's an "Upload and Deploy" button, click that. 47 | Browse to your created uberjar, and upload it. 48 | The version should be something useful to you, you could use an incrementing counter, e.g. 1, 2, 3, etc. 49 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/windows.adoc: -------------------------------------------------------------------------------- 1 | = Windows Prerequisites 2 | 3 | Both WSL and Git Bash have been tested. 4 | 5 | Under both of these, Windows-based editors will unfortunately be unable to jump to source. 6 | This is a result of the JVM believing the path is /c/Users/User/foo.clj, but your editor looking for C:\Users\User\foo.clj. 7 | There is no easy fix for this right now. 8 | You can run your editor via WSL if it is terminal based though (e.g. vim / emacs), and that will work! 9 | 10 | == WSL 11 | 12 | Everything works under WSL. 13 | You will need to install Java and run the Clojure Tools install script inside WSL. 14 | 15 | === Java 16 | 17 | Open your Bash terminal. 18 | You can find it by searching "bash" in the Start Menu. 19 | Then type the following into the terminal: 20 | 21 | [source,shell] 22 | ---- 23 | $ apt-get update 24 | $ apt-get install default-jdk 25 | ---- 26 | 27 | === Clojure Tools 28 | 29 | 1. Follow the Linux installation instructions at https://clojure.org/guides/getting_started 30 | 2. Test that it works by typing `clojure`. 31 | 3. You now have a REPL (after some waiting), try `(println "Hello, World!")`. 32 | 33 | 34 | == GitBash 35 | 36 | === Java 37 | 38 | You will need to install Java onto your host machine. 39 | You can download it from link:https://github.com/ojdkbuild/ojdkbuild[ojdkbuild] if you don't have it already. 40 | 41 | === Clojure Tools 42 | 43 | You will need to provide a custom prefix to the Clojure Tools install script. 44 | This means that you need to alter the instructions slightly, where they call `sudo ./linux-install...` you should also add `-p ~/clojure`. 45 | 46 | Here's an example invocation, but ensure to check for the latest version at link:https://clojure.org/guides/getting_started[Clojure's Getting Started Guide]. 47 | 48 | .Example Invocation 49 | [source,shell] 50 | ---- 51 | $ sudo ./linux-install-1.10.0.411.sh -p ~/clojure/ 52 | ---- 53 | 54 | Next you will need to edit your `.bashrc` with lines like this: 55 | 56 | [source,bash] 57 | ---- 58 | export PATH="$HOME/clojure/bin" 59 | ---- 60 | 61 | Test that it works by typing `source ~/.bashrc` followed by `clojure`. 62 | Now you should be presented with a REPL, try your first evaluation: `(println "Hello, World!")`. 63 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/index.adoc: -------------------------------------------------------------------------------- 1 | = Edge Documentation 2 | 3 | link:https://clojurians.zulipchat.com/#narrow/stream/151045-JUXT[image:https://img.shields.io/badge/zulip-join_chat-brightgreen.svg[]] 4 | 5 | For newcomers to the Clojure language it can be quite a daunting task to put together a real Clojure application from scratch. 6 | That's why we've created a foundation for projects that includes solutions for the daunting tasks, and lets you focus on your application. 7 | 8 | == Get Started 9 | 10 | Are you new to Edge? 11 | This is the place to start! 12 | 13 | . link:https://clojure.org/guides/getting_started[Install clj] (<>) 14 | . <> 15 | . <> 16 | . <> 17 | 18 | == Using Edge 19 | 20 | * <> 21 | * <> 22 | * <> 23 | * <> 24 | * <> 25 | * <> 26 | 27 | === Edge integrated add-ons 28 | 29 | * <> (RESTful Web Server) 30 | * <> (Web Router) 31 | * <> (Common functionality for applications) 32 | * <> (Common developer functionality for applications) 33 | * <> (Common production functionality for applications) 34 | * <> (Integrate crux with integrant) 35 | 36 | === Production guides 37 | 38 | * <> 39 | * <> 40 | * <> 41 | * <> (e.g. the provided `edge.main`) 42 | 43 | == The Edge Project 44 | 45 | * <> 46 | * <> 47 | //* Getting help 48 | //* How to get involved 49 | //* License 50 | -------------------------------------------------------------------------------- /examples/phonebook-api/dev/config.edn: -------------------------------------------------------------------------------- 1 | {:port 4900 2 | :ig/system 3 | {:edge.bidi.ig/vhost [["http://localhost:4900" 4 | ["/" #ig/ref :edge.phonebook/routes]]] 5 | 6 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 7 | :port #ref [:port]} 8 | 9 | :edge/event-bus nil 10 | 11 | :edge.phonebook/db 12 | {:edge.phonebook/entries 13 | {100 {:firstname "Theron" :surname "Reach" :phone "321545"} 14 | 101 {:firstname "Sonya" :surname "Membreno" :phone "616301"} 15 | 102 {:firstname "Idell" :surname "Riedel" :phone "736601"} 16 | 103 {:firstname "Maynard" :surname "Hird" :phone "166965"} 17 | 104 {:firstname "Ashlea" :surname "Dupont" :phone "781721"} 18 | 105 {:firstname "Katherine" :surname "Prudhomme" :phone "997800"} 19 | 106 {:firstname "Liliana" :surname "Lariviere" :phone "230891"} 20 | 107 {:firstname "Mikaela" :surname "Mattei" :phone "704746"} 21 | 108 {:firstname "Eugenio" :surname "Fickes" :phone "832799"} 22 | 109 {:firstname "Constance" :surname "Motes" :phone "265262"} 23 | 110 {:firstname "Rolande" :surname "Fredericks" :phone "668014"} 24 | 111 {:firstname "Miles" :surname "Byerly" :phone "899053"} 25 | 112 {:firstname "Jeanelle" :surname "Rockmore" :phone "582535"} 26 | 113 {:firstname "Dina" :surname "Lollis" :phone "631574"} 27 | 114 {:firstname "Celena" :surname "Leng" :phone "508699"} 28 | 115 {:firstname "Jeannie" :surname "Aday" :phone "168060"} 29 | 116 {:firstname "Kali" :surname "Waldow" :phone "266694"} 30 | 117 {:firstname "Danyelle" :surname "Vitela" :phone ""} 31 | 118 {:firstname "Rick" :surname "Stalzer" :phone "955030"} 32 | 119 {:firstname "Kera" :surname "Sammets" :phone "756942"}} 33 | :edge/event-bus #ig/ref :edge/event-bus} 34 | 35 | :edge.phonebook/routes 36 | {:edge.phonebook/db #ig/ref :edge.phonebook/db 37 | :edge.http/port #ref [:port]} 38 | 39 | :edge/selmer {:edge.selmer/template-caching? false} 40 | 41 | :edge.kick/builder 42 | {:kick.builder/target "target" 43 | 44 | :kick/sass {:builds [{:id "phonebook" 45 | :source "phonebook-api/sass/phonebook.scss" 46 | :target "phonebook-api/css/phonebook.css"}]}}}} 47 | -------------------------------------------------------------------------------- /examples/cloudformation/elasticbeanstalk/stack.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Parameters: 3 | Description: 4 | Type: String 5 | Description: Description of your application for Elastic Beanstalk Resources 6 | Default: "Some Application" 7 | CNAMEPrefix: 8 | Type: String 9 | Description: Prefix to be used in the generated CNAME 10 | Resources: 11 | BeanstalkInstanceRole: 12 | Type: "AWS::IAM::Role" 13 | Properties: 14 | AssumeRolePolicyDocument: 15 | Version: 2012-10-17 16 | Statement: 17 | - 18 | Effect: Allow 19 | Principal: 20 | Service: 21 | - ec2.amazonaws.com 22 | Action: 23 | - sts:AssumeRole 24 | ManagedPolicyArns: 25 | - arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier 26 | - arn:aws:iam::aws:policy/AWSElasticBeanstalkMulticontainerDocker 27 | BeanstalkInstanceProfile: 28 | Type: AWS::IAM::InstanceProfile 29 | Properties: 30 | Roles: 31 | - !Ref BeanstalkInstanceRole 32 | Application: 33 | Type: AWS::ElasticBeanstalk::Application 34 | Properties: 35 | Description: !Ref Description 36 | ConfigurationTemplate: 37 | Type: AWS::ElasticBeanstalk::ConfigurationTemplate 38 | Properties: 39 | ApplicationName: !Ref Application 40 | Description: !Join [" ", [!Ref Description, "Configuration"]] 41 | OptionSettings: 42 | - Namespace: aws:autoscaling:launchconfiguration 43 | OptionName: IamInstanceProfile 44 | Value: !Ref BeanstalkInstanceProfile 45 | - Namespace: aws:autoscaling:asg 46 | OptionName: MinSize 47 | Value: '1' 48 | - Namespace: aws:autoscaling:asg 49 | OptionName: MaxSize 50 | Value: '1' 51 | - Namespace: aws:elasticbeanstalk:environment 52 | OptionName: EnvironmentType 53 | Value: LoadBalanced 54 | - Namespace: aws:elasticbeanstalk:cloudwatch:logs 55 | OptionName: StreamLogs 56 | Value: true 57 | SolutionStackName: 64bit Amazon Linux 2018.03 v2.8.2 running Java 8 58 | Environment: 59 | Type: AWS::ElasticBeanstalk::Environment 60 | Properties: 61 | ApplicationName: !Ref Application 62 | Description: !Join [" ", [!Ref Description, "Environment"]] 63 | CNAMEPrefix: !Ref CNAMEPrefix 64 | TemplateName: !Ref ConfigurationTemplate 65 | -------------------------------------------------------------------------------- /lib/edge-app-template/resources/clj/new/app.template/config.edn: -------------------------------------------------------------------------------- 1 | {{#kick}}{:edge.kick/config 2 | {:kick.builder/target #profile {:dev "target/dev" 3 | :prod "target/prod"}{{#sass}} 4 | :kick/sass {:builds [{:id "{{name}}" 5 | :source "{{name}}.scss" 6 | :target "public/{{name}}.css"}]}{{/sass}}{{#cljs}} 7 | :kick/figwheel-main {:builds [{:id "app" 8 | :main {{root-ns}}.frontend.main 9 | :output-to "public/frontend.js" 10 | :output-dir "public/frontend.out" 11 | :asset-path "/frontend.out" 12 | :optimizations #profile {:dev :none 13 | :prod :advanced}}] 14 | :figwheel-config 15 | {:ring-server-options 16 | {:port {{figwheel-port}}}}}{{/cljs}}} 17 | 18 | :ig.system/base 19 | {:{{root-ns}}.core/string "Hello, {{name}}!" 20 | [:edge.yada.ig/classpath-name :{{root-ns}}/index] {:name "index.html"} 21 | [:edge.yada.ig/resources :{{root-ns}}/assets] {:path "public"} 22 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 23 | :port {{server-port}}} 24 | :edge.bidi.ig/vhost [["http://localhost:{{server-port}}" 25 | ["" 26 | [["/" #ig/ref [:{{root-ns}}/index :edge.yada.ig/classpath-name]] 27 | ["/hello" #ig/ref :{{root-ns}}.core/string] 28 | ["" #ig/ref [:{{root-ns}}/assets :edge.yada.ig/resources]]]]]]} 29 | 30 | :ig.system/dev 31 | {:edge.kick/builder #ref [:edge.kick/config]} 32 | 33 | :ig/system #profile {:dev #merge [#ref [:ig.system/base] 34 | #ref [:ig.system/dev]] 35 | :default #ref [:ig.system/base]}}{{/kick}}{{^kick}}{{#web}}{:ig/system 36 | {:{{root-ns}}.core/string "Hello, {{name}}!" 37 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 38 | :port {{server-port}}} 39 | :edge.bidi.ig/vhost [["http://localhost:{{server-port}}" 40 | ["" 41 | [["/" #ig/ref :{{root-ns}}.core/string]]]]]}}{{/web}}{{^web}}{:ig/system 42 | {:{{root-ns}}.core/state {:events 0}}}{{/web}}{{/kick}} 43 | -------------------------------------------------------------------------------- /examples/phonebook-api/src/edge/phonebook/db.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2015, JUXT LTD. 2 | 3 | (ns edge.phonebook.db 4 | (:require 5 | [clojure.tools.logging :refer :all] 6 | [integrant.core :as ig] 7 | [manifold.bus :refer [publish!]])) 8 | 9 | (defn add-entry 10 | "Add a new entry to the database. Returns the id of the newly added 11 | entry." 12 | [db entry] 13 | (dosync 14 | ;; Why use 2 refs when one atom would do? It comes down to being able 15 | ;; to return nextval from this function. While this is possible to do 16 | ;; with an atom, its feels less elegant. 17 | (let [nextval @(:next-entry db)] 18 | (alter (:phonebook db) conj [nextval entry]) 19 | (alter (:next-entry db) inc) 20 | nextval))) 21 | 22 | (defn update-entry 23 | "Update a new entry to the database. Returns the id of the newly added 24 | entry." 25 | [db id entry] 26 | (dosync 27 | (alter (:phonebook db) assoc id entry)) 28 | (assert (:manifold/event-bus db)) 29 | (publish! 30 | (:manifold/event-bus db) 31 | :phonebook 32 | {:event :entry-updated 33 | :id id 34 | :value entry 35 | :message (format "Phonebook entry %d replaced with %s" id entry)})) 36 | 37 | (defn delete-entry 38 | "Delete a entry from the database." 39 | [db id] 40 | (dosync 41 | (alter (:phonebook db) dissoc id))) 42 | 43 | (defn get-entries 44 | [db] 45 | @(:phonebook db)) 46 | 47 | (defn matches? [q entry] 48 | (some (partial re-seq (re-pattern (str "(?i:\\Q" q "\\E)"))) 49 | (map str (vals (second entry))))) 50 | 51 | (defn search-entries 52 | [db q] 53 | (let [entries (get-entries db) 54 | f (filter (partial matches? q) entries)] 55 | (into {} f))) 56 | 57 | (defn get-entry 58 | [db id] 59 | (get @(:phonebook db) id)) 60 | 61 | (defn count-entries 62 | [db] 63 | (count @(:phonebook db))) 64 | 65 | (defn apply-update 66 | "Apply an update to an entry in the database, returns the updated 67 | value" 68 | [db id f] 69 | (dosync 70 | (let [updated-value (apply f [(get-entry db id)])] 71 | (update-entry db id updated-value) 72 | updated-value))) 73 | 74 | (defmethod ig/init-key :edge.phonebook/db 75 | [_ {:edge.phonebook/keys [entries] 76 | :edge/keys [event-bus]}] 77 | {:phonebook (ref entries) 78 | :next-entry (ref (if (not-empty entries) 79 | (inc (apply max (keys entries))) 80 | 1)) 81 | :manifold/event-bus (:manifold/event-bus event-bus)}) 82 | -------------------------------------------------------------------------------- /examples/juxt.edge.doc-site/src/juxt/edge/doc_site/doc.cljs: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2019, JUXT LTD. 2 | 3 | (ns ^:figwheel-hooks juxt.edge.doc-site.doc 4 | (:require 5 | [goog.dom :as dom])) 6 | 7 | ;; Create a GET function that can be called by docs 8 | 9 | ;; Question: How does tick call arbitary functions? buttons/actions? 10 | ;; TODO: Run up tick in a separate workspace 11 | 12 | (enable-console-print!) 13 | 14 | (defn button [label onclick] 15 | (dom/createDom "button" #js {"onclick" onclick} label)) 16 | 17 | (defn div [class & body] 18 | (apply dom/createDom "div" #js {"class" class} body)) 19 | 20 | (defn pre [class & body] 21 | (apply dom/createDom "pre" #js {"class" class} body)) 22 | 23 | (defn p [& body] 24 | (apply dom/createDom "p" nil body)) 25 | 26 | (defn tt [& body] 27 | (apply dom/createDom "tt" nil body)) 28 | 29 | (defn source-listing [code] 30 | (div "listingblock" 31 | (div "content" 32 | (pre "highlightjs highlight" 33 | (dom/createDom "code" #js {"class" "hljs"} code))))) 34 | 35 | (defn http 36 | ([method uri cb] 37 | (http method uri cb {})) 38 | ([method uri cb opts] 39 | (let [req (new js/XMLHttpRequest)] 40 | (.open req method uri) 41 | (.setRequestHeader req "Accept" "text/plain") 42 | (.addEventListener req "load" (fn [ev] 43 | (cb ev req))) 44 | (.send req)))) 45 | 46 | (defn init [] 47 | (let [parent (.querySelector js/document "#hello .content") 48 | output (dom/createDom "div" nil) 49 | 50 | hello 51 | (fn [] 52 | (http 53 | "GET" "/hello" 54 | (fn [ev req] 55 | (dom/removeChildren output) 56 | (dom/append output (source-listing 57 | (str 58 | (.getAllResponseHeaders req) 59 | "\r\n" 60 | (.-responseText (.-currentTarget ev))))))))] 61 | 62 | (when parent 63 | (hello) 64 | (dom/removeChildren parent) 65 | (dom/append 66 | parent 67 | (p "Let's send a " (tt "GET") " request to " (tt "/hello") " and check what it returns.") 68 | output 69 | #_(button "GET" (fn [ev] (hello))))))) 70 | 71 | (defonce _ 72 | (do 73 | (println "Edge: window loaded") 74 | (init))) 75 | 76 | (defn ^:after-load figwheel-reload [] 77 | (println "Edge: figwheel-reload!") 78 | (init)) 79 | -------------------------------------------------------------------------------- /examples/main/src/edge/yada/graphql_ws.clj: -------------------------------------------------------------------------------- 1 | (ns edge.yada.graphql-ws 2 | (:require 3 | [cheshire.core :as json] 4 | [clojure.tools.logging :as log] 5 | [manifold.stream :as ms])) 6 | 7 | ;; https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md 8 | 9 | ;; From subscriptions-transport-ws/src/message-types.ts 10 | (def ^:client GQL_CONNECTION_INIT "connection_init") 11 | (def ^:server GQL_CONNECTION_ACK "connection_ack") 12 | (def ^:server GQL_CONNECTION_ERROR "connection_error") 13 | (def ^:client GQL_CONNECTION_TERMINATE "connection_terminate") 14 | (def ^:client GQL_START "start") 15 | (def ^:server GQL_DATA "data") 16 | (def ^:server GQL_ERROR "error") 17 | (def ^:server GQL_COMPLETE "complete") 18 | (def ^:client GQL_STOP "stop") 19 | 20 | (defn gql-error [id e] 21 | {:type GQL_ERROR :id id :payload (str e)}) 22 | 23 | (defmulti handle-incoming-ws-message (fn [msg ctx] (:type msg))) 24 | 25 | (defmethod handle-incoming-ws-message GQL_CONNECTION_INIT 26 | [msg {:keys [edge.manifold/stream] :as ctx}] 27 | (log/debugf 28 | "GraphQL connection initiated from %s, acknowledging" 29 | (-> ctx :edge.yada/ctx :request :remote-addr)) 30 | (ms/put! stream (json/encode {:type GQL_CONNECTION_ACK}))) 31 | 32 | (defmethod handle-incoming-ws-message GQL_START 33 | [msg {:keys [edge.manifold/stream 34 | edge.graphql/schema 35 | edge/executor 36 | edge.graphql/subscription-streams-by-id] 37 | :as ctx}] 38 | 39 | ;; TODO: Variables 40 | 41 | (let [id (some-> msg :id) 42 | q (some-> msg :payload :query)] 43 | 44 | (log/debug "Handle start, id" id ", q is" q) 45 | 46 | (try 47 | (when-not id (throw (ex-info "No id present" {}))) 48 | (when-not q (throw (ex-info "No query present" {}))) 49 | 50 | (let [source (edge.yada.lacinia/subscription-stream schema q ctx)] 51 | (swap! subscription-streams-by-id assoc id source) 52 | (ms/connect 53 | (ms/transform 54 | (map #(json/encode {:type GQL_DATA :id id :payload {:data %}})) 55 | source) 56 | stream)) 57 | 58 | (catch Exception e 59 | (log/info e "Error starting GraphQL subscription") 60 | (ms/put! stream (json/encode (gql-error id e))))))) 61 | 62 | (defmethod handle-incoming-ws-message GQL_STOP 63 | [msg {:keys [edge.graphql/subscription-streams-by-id]}] 64 | (let [id (some-> msg :id)] 65 | (log/debug "Should stop id" id) 66 | (when-let [source (get @subscription-streams-by-id id)] 67 | (log/debug "Found source for" id ", now closing it") 68 | (ms/close! source) 69 | (swap! subscription-streams-by-id dissoc id)))) 70 | -------------------------------------------------------------------------------- /examples/main/resources/public/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 17 | 24 | 25 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /examples/main/resources/public/img/logo-normal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 17 | 24 | 25 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Edge 2 | 3 | link:https://clojurians.zulipchat.com/#narrow/stream/151045-JUXT[image:https://img.shields.io/badge/zulip-join_chat-brightgreen.svg[]] 4 | 5 | Documentation is hosted at link:https://juxt.pro/edge/docs/index.html[juxt.pro]. 6 | The sources can be browsed offline in <>. 7 | 8 | TIP: Use link:https://github.com/asciidoctor/asciidoctor-browser-extension[Asciidoctor browser extension] to view these as html in your browser. 9 | 10 | == Intro 11 | 12 | For newcomers to the Clojure language it can be quite a daunting task to put together a real Clojure application from scratch. 13 | That's why we've done this initial step for you and creating a project that you can learn from and build upon. 14 | 15 | This isn't merely a toy application. 16 | Edge is JUXT's baseline architecture which we use for our own professional Clojure projects. 17 | The name is taken from https://en.wikipedia.org/wiki/Datum_reference[Datum edge]. 18 | 19 | == Features 20 | 21 | Edge is a simple foundation integrating the following: 22 | 23 | * link:https://clojure.org/guides/deps_and_cli[Dependency management] 24 | * Development setup 25 | * link:https://github.com/juxt/aero[Configuration] 26 | * link:https://github.com/juxt/yada[Web server] & link:https://github.com/juxt/bidi[routing] 27 | 28 | With examples for: 29 | 30 | * link:https://github.com/juxt/edge/tree/master/examples/tutorial.vent[A single page application] 31 | * link:https://github.com/juxt/edge/tree/master/examples/phonebook-api[A REST API] 32 | * link:https://github.com/juxt/edge/tree/master/examples/phonebook-graphql[A GraphQL API] 33 | 34 | For more information on why you'd use Edge, see link:https://juxt.pro/edge/docs/why-edge.html[Why Edge?]. 35 | 36 | == Copyright & License 37 | 38 | The MIT License (MIT) 39 | 40 | Copyright © 2016-2019 JUXT LTD. 41 | 42 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 43 | 44 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47 | -------------------------------------------------------------------------------- /examples/main/test/edge/examples_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright © 2017, JUXT LTD. 2 | 3 | (ns edge.examples-test 4 | (:require 5 | [buddy.sign.jwt :as jwt] 6 | [yada.yada :as yada] 7 | [ring.util.codec :as codec] 8 | [clojure.test :refer :all] 9 | [edge.examples :refer :all])) 10 | 11 | (deftest basic-authentication-test 12 | (let [response (yada/response-for basic-auth-resource-example :get "/" {})] 13 | (is (= 401 (:status response))) 14 | (is (= ["Basic realm=\"default\""] (get-in response [:headers "www-authenticate"])))) 15 | 16 | (let [response (yada/response-for basic-auth-resource-example :get "/" {:headers {"authorization" (str "Basic " (codec/base64-encode (.getBytes "alice:password")))}})] 17 | (is (= 200 (:status response))))) 18 | 19 | (deftest custom-auth-static-authentication-test 20 | (let [response (yada/response-for custom-auth-static-resource-example :get "/" {})] 21 | (is (= 200 (:status response))) 22 | (testing "Absence of authenticate header" 23 | (is (nil? (get-in response [:headers "www-authenticate"])))))) 24 | 25 | (deftest custom-auth-trusted-header-test 26 | (let [response (yada/response-for custom-auth-trusted-header-resource-example :get "/" {})] 27 | (is (= 401 (:status response))) 28 | (testing "Absence of authenticate header" 29 | (is (nil? (get-in response [:headers "www-authenticate"])))) 30 | (let [response (yada/response-for custom-auth-trusted-header-resource-example :get "/" {:headers {"x-whoami" "bob"}})] 31 | (is (= 200 (:status response)))))) 32 | 33 | (defn sign [creds] 34 | (jwt/sign {:claims (pr-str creds)} secret)) 35 | 36 | (def alice-sig "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOiJ7OnVzZXIgXCJhbGljZVwiLCA6cm9sZXMgI3s6dXNlcn19In0.yMoqLM3zPkej-W6CoEaJ7GWxxrsbEiYa_yiRw7rPDmU") 37 | 38 | (def dave-sig "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbXMiOiJ7OnVzZXIgXCJkYXZlXCIsIDpyb2xlcyAje319In0.Kd90HYTQFDC-ZAC95CvrnY1PWQXGBkLMOzS2lnC9ZA8") 39 | 40 | (deftest secrets-test [] 41 | (is (= alice-sig (sign {:user "alice" :roles #{:user}}))) 42 | (is (= dave-sig (sign {:user "dave" :roles #{}})))) 43 | 44 | (deftest custom-auth-signed-header-test 45 | (let [response (yada/response-for custom-auth-signed-header-resource-example :get "/" {})] 46 | (testing "No authentication given" 47 | (is (= 401 (:status response))) 48 | (testing "Absence of authenticate header" 49 | (is (nil? (get-in response [:headers "www-authenticate"]))))) 50 | (testing "Alice" 51 | (let [response (yada/response-for custom-auth-signed-header-resource-example :get "/" {:headers {"x-whoami" alice-sig}})] 52 | (is (= 200 (:status response))))) 53 | (testing "Dave is forbidden with 403." 54 | (let [response (yada/response-for custom-auth-signed-header-resource-example :get "/" {:headers {"x-whoami" dave-sig}})] 55 | (is (= 403 (:status response))))))) 56 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/why-edge.adoc: -------------------------------------------------------------------------------- 1 | = Why Edge? 2 | 3 | It takes a lot of time and effort to put together and maintain a complete Clojure environment. 4 | That's why we've created Edge. 5 | Edge is intended for both professional and educational use, including students learning Clojure, educators, as well as professional Clojure programmers in small and large organisations. 6 | 7 | == Compared with other approaches 8 | 9 | When starting new projects, days or weeks can be wasted learning how to assemble various libraries and tools. 10 | You can derive from previous projects and public examples, but that wastes time understanding which parts are relevant to you. 11 | Edge provides a generic base you can build upon, without any research or disentangling. 12 | 13 | === Compared to Templates 14 | 15 | Templates provide an alternative way to start a project quickly, but you take the full burden of maintaining that template after generation. 16 | Edge allows you to update your project at any point. 17 | If a bug is fixed in Edge, you will receive that fix when you next update. 18 | 19 | === Compared with Libraries 20 | 21 | Edge is easy to modify as needed, because its code is part of your project. 22 | Some frameworks are libraries, but this hinders changing them. 23 | Modifying a library is a complex process, requiring forking, deploying and dependency conflict resolution. 24 | This takes valuable time from working on your actual goal. 25 | 26 | == Features of Edge 27 | 28 | === Developer Ergonomics 29 | 30 | A lot of investment has gone into Edge's developer ergonomics. 31 | The goal was to create an environment combining the techniques from several projects. 32 | A sample of novel features: 33 | 34 | * Deep CIDER integration, e.g. `cider-refresh` configuration and automatic cljs jack-in 35 | * Console logs are filtered to warnings, errors and all logs from your project 36 | * Automatically link to servers when starting the system 37 | * Dynamically load dependencies into your REPL at runtime 38 | 39 | Developing these features yourself is possible, but requires pulling together knowledge from many different areas: editor tooling, logback, classloaders, etc. 40 | Edge already has solutions to these problems, and makes them instantly available to anyone. 41 | 42 | === Modular 43 | 44 | Many projects, even small ones, have a multi-service architecture. 45 | Edge allows your services to share common code as libraries in the same repo, which can be used for business logic or migration utilities. 46 | 47 | Even in a single-service architecture, small libraries allow you to create well defined boundaries in your application. 48 | These boundaries have their own tests and documentation, this leads to simpler and more stable software. 49 | 50 | === Open Source 51 | 52 | The complete system, including the Clojure language, the Java Virtual Machine on which it runs, the Clojure code within Edge and the numerous Clojure and Java libraries that are employed, are licensed with open-source licenses. 53 | This provides you will full flexibility over the Edge project, you can decide to fork the codebase at any point and go your own way. 54 | -------------------------------------------------------------------------------- /lib/edge.rebel.auto-dev/src/edge/rebel/main.clj: -------------------------------------------------------------------------------- 1 | (ns edge.rebel.main 2 | (:require 3 | [clojure.pprint :as pp] 4 | [fipp.edn :as fipp] 5 | rebel-readline.clojure.main 6 | rebel-readline.core 7 | [rebel-readline.jline-api :as api] 8 | [rebel-readline.clojure.line-reader :as clj-line-reader] 9 | io.aviso.ansi)) 10 | 11 | (defn syntax-highlight-pprint 12 | "Print a syntax highlighted clojure value. 13 | 14 | This printer respects the current color settings set in the 15 | service. 16 | 17 | The `rebel-readline.jline-api/*line-reader*` and 18 | `rebel-readline.jline-api/*service*` dynamic vars have to be set for 19 | this to work." 20 | [x] 21 | (binding [*out* (.. api/*line-reader* getTerminal writer)] 22 | (try 23 | (print (api/->ansi 24 | (clj-line-reader/highlight-clj-str 25 | (with-out-str (pp/pprint x))))) 26 | (catch java.lang.StackOverflowError e 27 | (pp/pprint x))))) 28 | 29 | (defn syntax-highlight-fipp 30 | "Print a syntax highlighted clojure value. 31 | 32 | This printer respects the current color settings set in the 33 | service. 34 | 35 | The `rebel-readline.jline-api/*line-reader*` and 36 | `rebel-readline.jline-api/*service*` dynamic vars have to be set for 37 | this to work." 38 | [x] 39 | (binding [*out* (.. api/*line-reader* getTerminal writer)] 40 | (try 41 | (print (api/->ansi 42 | (clj-line-reader/highlight-clj-str 43 | (with-out-str (fipp/pprint x))))) 44 | (catch java.lang.StackOverflowError _ 45 | (try 46 | (fipp/pprint x) 47 | ;; Just in case of 48 | ;; https://github.com/brandonbloom/fipp/issues/28 49 | (catch java.lang.StackOverflowError _ 50 | (prn x))))))) 51 | 52 | (defn -main 53 | [& args] 54 | (rebel-readline.core/ensure-terminal 55 | (rebel-readline.clojure.main/repl 56 | :init (fn [] 57 | (try 58 | (println "[Edge] Loading Clojure code, please wait...") 59 | (require 'dev) 60 | (in-ns 'dev) 61 | (println (str 62 | (io.aviso.ansi/yellow "[Edge] Now enter ") 63 | (io.aviso.ansi/bold-yellow "(go)") 64 | (io.aviso.ansi/yellow " to start the dev system"))) 65 | 66 | (catch Exception e 67 | (if (= (.getMessage e) 68 | "Could not locate dev__init.class, dev.clj or dev.cljc on classpath.") 69 | (do 70 | (println (io.aviso.ansi/red "[Edge] Failed to require dev. Falling back to `user`. ")) 71 | (println (io.aviso.ansi/bold-red "[Edge] Make sure to supply `-A:dev` when running `../bin/rebel`."))) 72 | 73 | (do 74 | (.printStackTrace e) 75 | (println "[Edge] Failed to require dev, this usually means there was a syntax error. See exception above.") 76 | (println "[Edge] Please correct it, and enter (fixed!) to resume development.")))))) 77 | :print syntax-highlight-pprint) 78 | ;; When the REPL stops, stop: 79 | (System/exit 0))) 80 | -------------------------------------------------------------------------------- /examples/tutorial.oic/src/tutorial/oic/web.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.oic.web 2 | (:require 3 | [aleph.http :as http] 4 | [integrant.core :as ig] 5 | [manifold.deferred :as d] 6 | [ring.util.codec :as codec] 7 | [yada.yada :as yada] 8 | 9 | ;; Note: this may be promoted to yada 1.3.x or a separate Edge 10 | ;; module 11 | [tutorial.oic.oic :as oic] 12 | 13 | [clojure.tools.logging :as log])) 14 | 15 | (defmethod ig/init-key ::authorize [_ {:keys [tutorial.oic.oic/*client]}] 16 | (yada/resource 17 | {:methods 18 | {:get 19 | {:produces "text/plain" 20 | :response 21 | (fn [ctx] 22 | (d/let-flow [client *client 23 | url (:openid-connect/authorization-endpoint client) 24 | client-id (:oauth/client-id client) 25 | redirect-uri (:oauth/redirect-uri client)] 26 | (-> ctx 27 | (yada/redirect 28 | (str 29 | url "?" 30 | (codec/form-encode 31 | {"response_type" "code" 32 | "client_id" client-id 33 | "redirect_uri" redirect-uri 34 | "scope" "openid profile permissions"}))))))}}})) 35 | 36 | (defmethod ig/init-key ::oauth-callback [_ {:keys [tutorial.oic.oic/*client]}] 37 | (yada/resource 38 | {:methods 39 | {:get 40 | {:parameters {:query {:code String}} 41 | :produces "text/plain" 42 | :response 43 | (fn [ctx] 44 | (-> 45 | (d/let-flow [code (get-in ctx [:parameters :query :code]) 46 | client *client 47 | token-url (:openid-connect/token-endpoint client) 48 | client-id (:oauth/client-id client) 49 | client-secret (:oauth/client-secret client) 50 | redirect-uri (:oauth/redirect-uri client) 51 | 52 | callback-response 53 | (http/post 54 | token-url 55 | {:accept "application/json" 56 | :form-params 57 | {"grant_type" "authorization_code" 58 | "client_id" client-id 59 | "client_secret" client-secret 60 | "code" code 61 | "redirect_uri" redirect-uri}}) 62 | 63 | decoded (oic/validate-callback-response 64 | callback-response 65 | (:openid-connect/jwks client))] 66 | 67 | ;; We could now set a cookie (session id or signed JWT 68 | ;; token) to prove that these claims are established for 69 | ;; future request. 70 | 71 | ;; We might also redirect appropriately. 72 | 73 | ;; For the purposes of this tutorial, let's just print the 74 | ;; user's name. 75 | (str "Your name is " (get-in decoded [:claims "name"]))) 76 | 77 | ;; Error handling 78 | (d/catch 79 | (fn [e] 80 | (log/errorf e "Error in OAuth2 callback occured: %s" (.getMessage e)) 81 | (d/error-deferred (throw (ex-info "Failed to authorize" {:status 500} e))) 82 | ))))}}})) 83 | -------------------------------------------------------------------------------- /examples/tutorial.oic/src/tutorial/oic/oic.clj: -------------------------------------------------------------------------------- 1 | (ns tutorial.oic.oic 2 | (:require 3 | [aleph.http :as http] 4 | [buddy.core.keys :as bck] 5 | [buddy.sign.jws :as jws] 6 | [cheshire.core :as json] 7 | [clojure.java.io :as io] 8 | [clojure.string :as string] 9 | [clojure.tools.logging :as log] 10 | [integrant.core :as ig] 11 | [manifold.deferred :as d])) 12 | 13 | (defn- b64-decode-json-str 14 | "Decode a base-64 encoded JSON string. (UTF-8 assumed, no BOM check)." 15 | [s] nil 16 | (try 17 | (json/decode (String. (.decode (java.util.Base64/getUrlDecoder) s))) 18 | (catch Exception e 19 | (throw (ex-info "Failed to decode string" {:string s} e))))) 20 | 21 | (defn- decode-jwt 22 | "Transform a properly formed JWT into a Clojure map. From 23 | https://gist.github.com/raymcdermott/1f38ec455df433b96da789a70a4dd346" 24 | [jwt] 25 | (when-let [jwt-parts (string/split jwt #"\.")] 26 | (when (= 3 (count jwt-parts)) 27 | (let [[b64-header b64-payload b64-signature] jwt-parts] 28 | {:header (b64-decode-json-str b64-header) 29 | :payload (b64-decode-json-str b64-payload) 30 | :signature b64-signature})))) 31 | 32 | (defn- cert->pem 33 | "Convert cert to PEM. From 34 | https://gist.github.com/raymcdermott/1f38ec455df433b96da789a70a4dd346" 35 | [cert] 36 | (bck/str->public-key 37 | (str "-----BEGIN CERTIFICATE-----\n" 38 | (string/join "\n" (string/join "\n" (re-seq #".{1,64}" cert))) 39 | "\n-----END CERTIFICATE-----\n"))) 40 | 41 | (defn validate-callback-response [response jwks] 42 | 43 | (when-not (= (:status response) 200) 44 | (throw (ex-info "Callback response did not return OK status" {}))) 45 | 46 | (let [body (json/parse-stream (io/reader (:body response))) 47 | id-token (get body "id_token") 48 | expires-in (get body "expires_in") ; TODO: use this! 49 | jwt (decode-jwt id-token) 50 | issuer (get-in jwt [:payload "iss"]) 51 | kid (get-in jwt [:header "kid"]) 52 | signing-key (first (filter #(= kid (get % "kid")) (get jwks "keys"))) 53 | cert (first (get signing-key "x5c")) 54 | claims (json/decode 55 | (String. 56 | (jws/unsign 57 | id-token 58 | (cert->pem cert) 59 | {:alg (keyword (string/lower-case (get signing-key "alg")))}) 60 | "UTF-8"))] 61 | 62 | ;; TODO: ID Token Validation 63 | ;; See https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation 64 | 65 | {:issuer issuer 66 | :expires-in expires-in 67 | :claims claims 68 | :jwt jwt})) 69 | 70 | (defn jwks [config-url] 71 | (d/let-flow 72 | [config-response (http/get config-url) 73 | config (-> config-response :body io/input-stream io/reader json/decode-stream) 74 | token-endpoint (get config "token_endpoint") 75 | jwks-uri (get config "jwks_uri") 76 | jwks-response (http/get jwks-uri) 77 | jwks (-> jwks-response :body io/input-stream io/reader json/decode-stream)] 78 | 79 | {:openid-connect/jwks jwks 80 | :openid-connect/authorization-endpoint (get config "authorization_endpoint") 81 | :openid-connect/token-endpoint (get config "token_endpoint")})) 82 | 83 | (defmethod ig/init-key ::*client [_ v] 84 | ;; Returns a deferred value, containing client configuration 85 | (d/let-flow [jwks (jwks (:openid-connect/configuration-url v))] 86 | (merge v jwks))) 87 | -------------------------------------------------------------------------------- /lib/graphql-ws/src/juxt/edge/graphql_ws/core.cljs: -------------------------------------------------------------------------------- 1 | (ns juxt.edge.graphql-ws.core 2 | (:require 3 | [goog.object :as object])) 4 | 5 | (defn- websocket 6 | ([url] (new js/WebSocket url)) 7 | ([url protocol] (new js/WebSocket url protocol))) 8 | 9 | (defn- send 10 | [ws operation-message] 11 | (.send ws (js/JSON.stringify (clj->js operation-message)))) 12 | 13 | (defn- on-open 14 | [ws cb] 15 | (object/set ws "onopen" cb)) 16 | 17 | (defn- on-message 18 | [ws cb] 19 | (object/set ws "onmessage" cb)) 20 | 21 | (defn- cljsify-gql-message-event 22 | [evt] 23 | (let [x (js/JSON.parse (.-data evt))] 24 | (js->clj x :keywordize-keys true))) 25 | 26 | (def ^:client GQL_CONNECTION_INIT "connection_init") 27 | (def ^:server GQL_CONNECTION_ACK "connection_ack") 28 | (def ^:server GQL_CONNECTION_ERROR "connection_error") 29 | (def ^:client GQL_CONNECTION_TERMINATE "connection_terminate") 30 | (def ^:client GQL_CONNECTION_KEEP_ALIVE "connection_keep_alive") 31 | (def ^:client GQL_START "start") 32 | (def ^:server GQL_DATA "data") 33 | (def ^:server GQL_ERROR "error") 34 | (def ^:server GQL_COMPLETE "complete") 35 | (def ^:client GQL_STOP "stop") 36 | 37 | (defn- create-graphql-websocket 38 | [ws ready-fn callback-fn connection-params] 39 | (doto ws 40 | (on-open 41 | (fn [evt] 42 | (send ws (cond-> {:type GQL_CONNECTION_INIT} 43 | connection-params 44 | (assoc :payload connection-params))) 45 | (ready-fn ws))) 46 | (on-message 47 | (comp 48 | callback-fn 49 | (fn [{:keys [type id payload]}] 50 | (condp = type 51 | GQL_CONNECTION_ACK {:type :gql.ws/ack} 52 | GQL_CONNECTION_KEEP_ALIVE {:type :gql.ws/keep-alive} 53 | GQL_COMPLETE {:type :gql.ws/complete 54 | :gql.ws.operation/id id} 55 | GQL_ERROR {:type :gql.ws/error 56 | :gql.ws/error-type :failing-operation 57 | :gql.ws.operation/id id 58 | :gql.ws.error/errors [payload]} 59 | GQL_DATA (if (:errors payload) 60 | {:type :gql.ws/error 61 | :gql.ws/error-type :resolver-error 62 | :gql.ws.operation/id id 63 | :gql.ws.error/errors (:errors payload) 64 | :gql.ws/data (:data payload)} 65 | {:type :gql.ws/data 66 | :gql.ws.operation/id id 67 | :gql.ws/data (:data payload)}))) 68 | cljsify-gql-message-event)))) 69 | 70 | (defn- gql-start 71 | [ws id payload] 72 | (send ws {:type GQL_START 73 | :id id 74 | :payload payload})) 75 | 76 | (defn- gql-stop 77 | [ws id] 78 | (send ws {:type GQL_STOP 79 | :id id})) 80 | 81 | (defn- subscribe 82 | [ws id {:keys [query variables operation-name] 83 | :as subscription-payload}] 84 | (gql-start ws id subscription-payload)) 85 | 86 | (defn init 87 | [{:keys [url connection-params subscriptions]} callback] 88 | {:ws 89 | (create-graphql-websocket (websocket url) 90 | (fn ready [ws] 91 | (doseq [[k v] subscriptions] 92 | (subscribe ws k v))) 93 | callback 94 | connection-params) 95 | :subscription-ids (keys subscriptions)}) 96 | 97 | (defn stop-all! 98 | [{:keys [ws subscription-ids]}] 99 | (doseq [id subscription-ids] 100 | (gql-stop ws id)) 101 | (.close ws)) 102 | -------------------------------------------------------------------------------- /examples/tutorial.vent/src/config.edn: -------------------------------------------------------------------------------- 1 | {:ig/system 2 | {[:tutorial.vent/index :edge.yada.ig/classpath-name] {:name "index.html"} 3 | [:tutorial.vent/assets :edge.yada.ig/resources] {:path "public/"} 4 | 5 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/favorites] 6 | {:methods 7 | {:get {:tutorial.vent.http-api/symbol 8 | tutorial.vent.lib/favorites}}} 9 | 10 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/all] 11 | {:methods 12 | {:get {:tutorial.vent.http-api/symbol 13 | tutorial.vent.lib/all}}} 14 | 15 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/followers] 16 | {:methods 17 | {:get {:tutorial.vent.http-api/symbol 18 | tutorial.vent.lib/followers 19 | :tutorial.vent.http-api/params 20 | {:username [:authentication]}}}} 21 | 22 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/following] 23 | {:methods 24 | {:get {:tutorial.vent.http-api/symbol 25 | tutorial.vent.lib/following 26 | :tutorial.vent.http-api/params 27 | {:username [:authentication]}}}} 28 | 29 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/toggle-favorite] 30 | {:methods 31 | {:post {:tutorial.vent.http-api/symbol tutorial.vent.lib/toggle-favorite 32 | :tutorial.vent.http-api/params {:vent-id [:route-params :vent-id]}}}} 33 | 34 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/toggle-follow-user] 35 | {:methods 36 | {:post {:tutorial.vent.http-api/symbol tutorial.vent.lib/toggle-follow 37 | :tutorial.vent.http-api/params {:to-follow [:route-params :username] 38 | :username [:authentication]}}}} 39 | 40 | [:tutorial.vent.http-api/api-resource :tutorial.vent.lib/vent] 41 | {:methods 42 | {:put {:tutorial.vent.http-api/symbol 43 | tutorial.vent.lib/add-vent 44 | :consumes "multipart/form-data" 45 | :parameters {:form {:text String}} 46 | :tutorial.vent.http-api/params {:text [:parameters :form :text] 47 | :username [:authentication]}}}} 48 | 49 | :edge.yada.ig/listener {:handler #ig/ref :edge.bidi.ig/vhost 50 | :port 3000} 51 | :edge.bidi.ig/vhost [["http://localhost:3000" 52 | ["" 53 | [["/" #ig/ref [:tutorial.vent/index :edge.yada.ig/classpath-name]] 54 | ["/" 55 | [["favorites" #ig/ref :tutorial.vent.lib/favorites] 56 | ["all" #ig/ref :tutorial.vent.lib/all] 57 | ["followers" #ig/ref :tutorial.vent.lib/followers] 58 | ["following" #ig/ref :tutorial.vent.lib/following] 59 | ["vent" #ig/ref :tutorial.vent.lib/vent] 60 | [[:vent-id "/favorite"] #ig/ref :tutorial.vent.lib/toggle-favorite] 61 | [[:username "/follow"] #ig/ref :tutorial.vent.lib/toggle-follow-user]]] 62 | ["" #ig/ref [:tutorial.vent/assets :edge.yada.ig/resources]]]]]] 63 | :edge.kick/builder 64 | {:kick.builder/target #profile {:dev "target/dev" 65 | :prod "target/prod"} 66 | :kick/figwheel-main {:builds [{:id "app" 67 | :main tutorial.vent.frontend.main 68 | :output-to "public/frontend.js" 69 | :output-dir "public/frontend.out" 70 | :asset-path "/frontend.out" 71 | :optimizations #profile {:dev :none 72 | :prod :advanced}}]}} 73 | :tutorial.vent.reload/frontend nil}} 74 | -------------------------------------------------------------------------------- /doc/resources/doc/sources/setup.adoc: -------------------------------------------------------------------------------- 1 | = How to build your own project upon Edge 2 | 3 | Edge is designed to be built upon. 4 | You are free to make whatever changes you like (additions and deletions), in accordance with the <<_license>> (MIT). 5 | 6 | == Create a repository 7 | 8 | If you don't have a remote repository already (e.g. on GitHub), here's how to create a new local one: 9 | 10 | [source,shell] 11 | ---- 12 | src$ mkdir acme 13 | src$ cd acme 14 | acme$ git init 15 | ---- 16 | 17 | If you already have a repository, you can clone it like so: 18 | 19 | [source,shell] 20 | ---- 21 | src$ git clone git@github.com:acme/acme.git 22 | src$ cd acme 23 | ---- 24 | 25 | == Add Edge to your project 26 | 27 | Once you have your repository, you can add Edge as a remote, and incorporate it in: 28 | 29 | [source,shell] 30 | ---- 31 | acme$ git remote add edge https://github.com/juxt/edge.git 32 | acme$ git pull --allow-unrelated-histories --no-rebase edge master 33 | ---- 34 | 35 | == Add a remote later (optional) 36 | 37 | It's a good idea to have somewhere to back up your commits. 38 | 39 | For example, if you create a new repository on GitHub called `acme` under the organisation `acme`, you could add the repository to your project like this: 40 | 41 | .Create a git remote 42 | [source,shell] 43 | ---- 44 | acme$ git remote add origin git@github.com:acme/acme.git 45 | acme$ git push -u origin master 46 | ---- 47 | 48 | == Create a new app 49 | 50 | With your new project created, you're ready to create an app. 51 | Apps are deps.edn projects within Edge which are intended to be run as a server. 52 | 53 | From the root of the repo, run the `./bin/app` script. 54 | It can be run with an optional flags which add support for Sass or Clojurescript, these are `--sass` and `--cljs` respectively. 55 | 56 | [NOTE] 57 | ==== 58 | Your project name should be namespaced to match your application. 59 | If your company was named "Acme" you might use "acme/api" or "com.acme/api". 60 | 61 | If you're unsure, use your company name at work, or your github username for hobby projects. 62 | There's a low chance of conflicts in an application. 63 | 64 | The project namespace will determine the Clojure namespaces within your application. 65 | ==== 66 | 67 | [NOTE] 68 | ==== 69 | The below commands will create a folder based on your project name. 70 | If you don't like the folder name, you can safely rename it (e.g. via `mv`) without any adverse affects. 71 | ==== 72 | 73 | [source,shell] 74 | ---- 75 | edge$ ./bin/app acme/api 76 | edge$ ./bin/app acme/blog --sass 77 | edge$ ./bin/app acme/dashboard --cljs 78 | edge$ ./bin/app acme/radar --sass --cljs 79 | ---- 80 | 81 | == Next steps 82 | 83 | <>. 84 | 85 | == License 86 | 87 | ---- 88 | The MIT License (MIT) 89 | 90 | Copyright © 2016-2019 JUXT LTD. 91 | 92 | Permission is hereby granted, free of charge, to any person obtaining a copy of 93 | this software and associated documentation files (the "Software"), to deal in 94 | the Software without restriction, including without limitation the rights to 95 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 96 | the Software, and to permit persons to whom the Software is furnished to do so, 97 | subject to the following conditions: 98 | 99 | The above copyright notice and this permission notice shall be included in all 100 | copies or substantial portions of the Software. 101 | 102 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 103 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 104 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 105 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 106 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 107 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 108 | ---- 109 | -------------------------------------------------------------------------------- /lib/edge.migration/test/main/input/1: -------------------------------------------------------------------------------- 1 | {:paths ["src" "sass" "resources" "bin"] 2 | :deps 3 | { 4 | org.clojure/clojure {:mvn/version "1.9.0"} 5 | org.clojure/clojurescript {:mvn/version "1.10.238"} 6 | 7 | ;; clojure.spec 8 | org.clojure/spec.alpha {:mvn/version "0.1.143"} 9 | 10 | ;; Server deps 11 | aero {:mvn/version "1.1.3"} 12 | bidi {:mvn/version "2.1.4"} 13 | integrant {:mvn/version "0.7.0"} 14 | prismatic/schema {:mvn/version "1.1.7"} 15 | selmer {:mvn/version "1.10.8"} 16 | yada {:mvn/version "1.3.0-alpha7"} 17 | 18 | ;; App deps 19 | reagent {:mvn/version "0.7.0"} 20 | com.cognitect/transit-clj {:mvn/version "0.8.300"} 21 | 22 | ;; Edge modules 23 | juxt.edge/graphql-ws {:local/root "../graphql-ws"} 24 | juxt.edge/doc-site {:local/root "../juxt.edge.doc-site"} 25 | juxt.edge/phonebook-api {:local/root "../phonebook-api"} 26 | juxt.edge/phonebook-app {:local/root "../phonebook-app"} ; depends on phonebook for server API 27 | juxt.edge/phonebook-graphql {:local/root "../phonebook-graphql"} 28 | juxt.edge/edge.system {:local/root "../edge.system"} 29 | juxt.edge/lib.app {:local/root "../lib.app"} 30 | 31 | org.clojure/tools.logging {:mvn/version "0.4.0"} 32 | 33 | org.webjars.bower/react {:mvn/version "15.4.2"} 34 | org.webjars.bower/es6-promise {:mvn/version "4.0.5"} 35 | org.webjars.bower/fetch {:mvn/version "0.9.0"} 36 | org.webjars/graphiql {:mvn/version "0.11.11"} 37 | org.webjars.npm/graphiql-subscriptions-fetcher {:mvn/version "0.0.2" 38 | :exclusions [org.webjars.npm/graphiql]} 39 | org.webjars.npm/subscriptions-transport-ws {:mvn/version "0.8.3" 40 | :exclusions [org.webjars.npm/graphiql]} 41 | org.webjars/font-awesome {:mvn/version "4.6.3"} 42 | juxt.asciidoctor/stylesheets {:mvn/version "0.1.2"} 43 | 44 | 45 | ;; Java 9+ support 46 | com.fasterxml.jackson.core/jackson-core {:mvn/version "2.9.4"} 47 | javax.xml.bind/jaxb-api {:mvn/version "2.3.0"}} 48 | 49 | :aliases 50 | {:dev 51 | {:extra-paths ["dev" "test"] 52 | :extra-deps 53 | {org.clojure/test.check {:mvn/version "0.9.0"} 54 | juxt.edge/lib.app.dev {:local/root "../lib.app.dev"} 55 | juxt.edge/test-utils {:local/root "../edge.test-utils"}}} 56 | 57 | :build { 58 | :extra-deps 59 | {juxt.edge/kick {:local/root "../edge.kick"} 60 | juxt/kick.alpha 61 | {:git/url "https://github.com/juxt/kick.alpha.git" 62 | :sha "eb7ee22efac8f69b2a042980e4736aec5ec352ed"} 63 | ;; Kick operates a BYOD (bring-your-own-dependency) policy 64 | figwheel-sidecar {:mvn/version "0.5.18" 65 | :exclusions [org.clojure/tools.nrepl]} 66 | nrepl {:mvn/version "0.6.0"} 67 | deraen/sass4clj {:mvn/version "0.3.1"} 68 | 69 | ;; Shadow-cljs is disabled as it conflicts with Figwheel 70 | ;;thheller/shadow-cljs {:mvn/version "2.4.26"} 71 | ;; As there's a bug in tools.deps.alpha (TDEPS-26): 72 | ;;org.jboss.xnio/xnio-nio {:mvn/version "3.3.6.Final"} 73 | }} 74 | 75 | :build/once {:main-opts ["-m" "edge.kick"]} 76 | 77 | :dev/build {:extra-paths ["target/dev"]} 78 | 79 | :prod/build {:extra-paths ["target/prod"]} 80 | 81 | :prod {:extra-paths ["prod"]} 82 | 83 | :pack 84 | {:extra-deps 85 | {pack/pack.alpha 86 | {:git/url "https://github.com/juxt/pack.alpha.git" 87 | :sha "d16bb29fa1581519c2659aed3c94e9a22a0329b8"}} 88 | :main-opts ["-m" "mach.pack.alpha.capsule" 89 | "-m" "edge.main"]} 90 | 91 | :aot {:jvm-opts ["-Dmain=edge.main" 92 | "-Dclojure.compiler.elide-meta=[:doc,:file,:line,:added]" 93 | "-Dclojure.compiler.direct-linking=true"]} 94 | 95 | :release {:extra-paths ["target"] 96 | :main-opts ["-m" "edge.main"]} 97 | 98 | :test {:extra-paths ["test"] 99 | :extra-deps 100 | {com.cognitect/test-runner 101 | {:git/url "https://github.com/cognitect-labs/test-runner.git" 102 | :sha "5fb4fc46ad0bf2e0ce45eba5b9117a2e89166479"} 103 | juxt.edge/test-utils {:local/root "../edge.test-utils"}} 104 | :main-opts ["-m" "cognitect.test-runner"]}}} 105 | -------------------------------------------------------------------------------- /examples/main/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "sass" "resources" "bin"] 2 | :deps 3 | { 4 | org.clojure/clojure {:mvn/version "1.9.0"} 5 | org.clojure/clojurescript {:mvn/version "1.10.238"} 6 | 7 | ;; clojure.spec 8 | org.clojure/spec.alpha {:mvn/version "0.1.143"} 9 | 10 | ;; Server deps 11 | aero {:mvn/version "1.1.3"} 12 | bidi {:mvn/version "2.1.4"} 13 | integrant {:mvn/version "0.7.0"} 14 | prismatic/schema {:mvn/version "1.1.7"} 15 | selmer {:mvn/version "1.10.8"} 16 | yada {:mvn/version "1.3.0-alpha7"} 17 | 18 | ;; App deps 19 | reagent {:mvn/version "0.7.0"} 20 | com.cognitect/transit-clj {:mvn/version "0.8.300"} 21 | 22 | ;; Edge modules 23 | juxt.edge/graphql-ws {:local/root "../lib/graphql-ws"} 24 | juxt.edge/doc-site {:local/root "../juxt.edge.doc-site"} 25 | juxt.edge/phonebook-api {:local/root "../phonebook-api"} 26 | juxt.edge/phonebook-app {:local/root "../phonebook-app"} ; depends on phonebook for server API 27 | juxt.edge/phonebook-graphql {:local/root "../phonebook-graphql"} 28 | juxt.edge/edge.system {:local/root "../lib/edge.system"} 29 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 30 | 31 | org.clojure/tools.logging {:mvn/version "0.4.0"} 32 | 33 | org.webjars.bower/react {:mvn/version "15.4.2"} 34 | org.webjars.bower/es6-promise {:mvn/version "4.0.5"} 35 | org.webjars.bower/fetch {:mvn/version "0.9.0"} 36 | org.webjars/graphiql {:mvn/version "0.11.11"} 37 | org.webjars.npm/graphiql-subscriptions-fetcher {:mvn/version "0.0.2" 38 | :exclusions [org.webjars.npm/graphiql]} 39 | org.webjars.npm/subscriptions-transport-ws {:mvn/version "0.8.3" 40 | :exclusions [org.webjars.npm/graphiql]} 41 | org.webjars/font-awesome {:mvn/version "4.6.3"} 42 | juxt.asciidoctor/stylesheets {:mvn/version "0.1.2"} 43 | 44 | 45 | ;; Java 9+ support 46 | com.fasterxml.jackson.core/jackson-core {:mvn/version "2.9.4"} 47 | javax.xml.bind/jaxb-api {:mvn/version "2.3.0"}} 48 | 49 | :aliases 50 | {:dev 51 | {:extra-paths ["dev" "test"] 52 | :extra-deps 53 | {org.clojure/test.check {:mvn/version "0.9.0"} 54 | juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"} 55 | juxt.edge/test-utils {:local/root "../lib/edge.test-utils"}}} 56 | 57 | :build { 58 | :extra-deps 59 | {juxt.edge/kick {:local/root "../lib/edge.kick"} 60 | juxt/kick.alpha 61 | {:git/url "https://github.com/juxt/kick.alpha.git" 62 | :sha "eb7ee22efac8f69b2a042980e4736aec5ec352ed"} 63 | ;; Kick operates a BYOD (bring-your-own-dependency) policy 64 | figwheel-sidecar {:mvn/version "0.5.18" 65 | :exclusions [org.clojure/tools.nrepl]} 66 | nrepl {:mvn/version "0.6.0"} 67 | deraen/sass4clj {:mvn/version "0.3.1"} 68 | 69 | ;; Shadow-cljs is disabled as it conflicts with Figwheel 70 | ;;thheller/shadow-cljs {:mvn/version "2.4.26"} 71 | ;; As there's a bug in tools.deps.alpha (TDEPS-26): 72 | ;;org.jboss.xnio/xnio-nio {:mvn/version "3.3.6.Final"} 73 | }} 74 | 75 | :build/once {:main-opts ["-m" "edge.kick"]} 76 | 77 | :dev/build {:extra-paths ["target/dev"]} 78 | 79 | :prod/build {:extra-paths ["target/prod"]} 80 | 81 | :prod {:extra-paths ["prod"]} 82 | 83 | :pack 84 | {:extra-deps 85 | {pack/pack.alpha 86 | {:git/url "https://github.com/juxt/pack.alpha.git" 87 | :sha "d16bb29fa1581519c2659aed3c94e9a22a0329b8"}} 88 | :main-opts ["-m" "mach.pack.alpha.capsule" 89 | "-m" "edge.main"]} 90 | 91 | :aot {:jvm-opts ["-Dmain=edge.main" 92 | "-Dclojure.compiler.elide-meta=[:doc,:file,:line,:added]" 93 | "-Dclojure.compiler.direct-linking=true"]} 94 | 95 | :release {:extra-paths ["target"] 96 | :main-opts ["-m" "edge.main"]} 97 | 98 | :test {:extra-paths ["test"] 99 | :extra-deps 100 | {com.cognitect/test-runner 101 | {:git/url "https://github.com/cognitect-labs/test-runner.git" 102 | :sha "5fb4fc46ad0bf2e0ce45eba5b9117a2e89166479"} 103 | juxt.edge/test-utils {:local/root "../lib/edge.test-utils"}} 104 | :main-opts ["-m" "cognitect.test-runner"]}}} 105 | -------------------------------------------------------------------------------- /lib/edge.migration/test/main/output.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "sass" "resources" "bin"] 2 | :deps 3 | { 4 | org.clojure/clojure {:mvn/version "1.9.0"} 5 | org.clojure/clojurescript {:mvn/version "1.10.238"} 6 | 7 | ;; clojure.spec 8 | org.clojure/spec.alpha {:mvn/version "0.1.143"} 9 | 10 | ;; Server deps 11 | aero {:mvn/version "1.1.3"} 12 | bidi {:mvn/version "2.1.4"} 13 | integrant {:mvn/version "0.7.0"} 14 | prismatic/schema {:mvn/version "1.1.7"} 15 | selmer {:mvn/version "1.10.8"} 16 | yada {:mvn/version "1.3.0-alpha7"} 17 | 18 | ;; App deps 19 | reagent {:mvn/version "0.7.0"} 20 | com.cognitect/transit-clj {:mvn/version "0.8.300"} 21 | 22 | ;; Edge modules 23 | juxt.edge/graphql-ws {:local/root "../lib/graphql-ws"} 24 | juxt.edge/doc-site {:local/root "../juxt.edge.doc-site"} 25 | juxt.edge/phonebook-api {:local/root "../phonebook-api"} 26 | juxt.edge/phonebook-app {:local/root "../phonebook-app"} ; depends on phonebook for server API 27 | juxt.edge/phonebook-graphql {:local/root "../phonebook-graphql"} 28 | juxt.edge/edge.system {:local/root "../lib/edge.system"} 29 | juxt.edge/lib.app {:local/root "../lib/edge.app"} 30 | 31 | org.clojure/tools.logging {:mvn/version "0.4.0"} 32 | 33 | org.webjars.bower/react {:mvn/version "15.4.2"} 34 | org.webjars.bower/es6-promise {:mvn/version "4.0.5"} 35 | org.webjars.bower/fetch {:mvn/version "0.9.0"} 36 | org.webjars/graphiql {:mvn/version "0.11.11"} 37 | org.webjars.npm/graphiql-subscriptions-fetcher {:mvn/version "0.0.2" 38 | :exclusions [org.webjars.npm/graphiql]} 39 | org.webjars.npm/subscriptions-transport-ws {:mvn/version "0.8.3" 40 | :exclusions [org.webjars.npm/graphiql]} 41 | org.webjars/font-awesome {:mvn/version "4.6.3"} 42 | juxt.asciidoctor/stylesheets {:mvn/version "0.1.2"} 43 | 44 | 45 | ;; Java 9+ support 46 | com.fasterxml.jackson.core/jackson-core {:mvn/version "2.9.4"} 47 | javax.xml.bind/jaxb-api {:mvn/version "2.3.0"}} 48 | 49 | :aliases 50 | {:dev 51 | {:extra-paths ["dev" "test"] 52 | :extra-deps 53 | {org.clojure/test.check {:mvn/version "0.9.0"} 54 | juxt.edge/lib.app.dev {:local/root "../lib/edge.app.dev"} 55 | juxt.edge/test-utils {:local/root "../lib/edge.test-utils"}}} 56 | 57 | :build { 58 | :extra-deps 59 | {juxt.edge/kick {:local/root "../lib/edge.kick"} 60 | juxt/kick.alpha 61 | {:git/url "https://github.com/juxt/kick.alpha.git" 62 | :sha "eb7ee22efac8f69b2a042980e4736aec5ec352ed"} 63 | ;; Kick operates a BYOD (bring-your-own-dependency) policy 64 | figwheel-sidecar {:mvn/version "0.5.18" 65 | :exclusions [org.clojure/tools.nrepl]} 66 | nrepl {:mvn/version "0.6.0"} 67 | deraen/sass4clj {:mvn/version "0.3.1"} 68 | 69 | ;; Shadow-cljs is disabled as it conflicts with Figwheel 70 | ;;thheller/shadow-cljs {:mvn/version "2.4.26"} 71 | ;; As there's a bug in tools.deps.alpha (TDEPS-26): 72 | ;;org.jboss.xnio/xnio-nio {:mvn/version "3.3.6.Final"} 73 | }} 74 | 75 | :build/once {:main-opts ["-m" "edge.kick"]} 76 | 77 | :dev/build {:extra-paths ["target/dev"]} 78 | 79 | :prod/build {:extra-paths ["target/prod"]} 80 | 81 | :prod {:extra-paths ["prod"]} 82 | 83 | :pack 84 | {:extra-deps 85 | {pack/pack.alpha 86 | {:git/url "https://github.com/juxt/pack.alpha.git" 87 | :sha "d16bb29fa1581519c2659aed3c94e9a22a0329b8"}} 88 | :main-opts ["-m" "mach.pack.alpha.capsule" 89 | "-m" "edge.main"]} 90 | 91 | :aot {:jvm-opts ["-Dmain=edge.main" 92 | "-Dclojure.compiler.elide-meta=[:doc,:file,:line,:added]" 93 | "-Dclojure.compiler.direct-linking=true"]} 94 | 95 | :release {:extra-paths ["target"] 96 | :main-opts ["-m" "edge.main"]} 97 | 98 | :test {:extra-paths ["test"] 99 | :extra-deps 100 | {com.cognitect/test-runner 101 | {:git/url "https://github.com/cognitect-labs/test-runner.git" 102 | :sha "5fb4fc46ad0bf2e0ce45eba5b9117a2e89166479"} 103 | juxt.edge/test-utils {:local/root "../lib/edge.test-utils"}} 104 | :main-opts ["-m" "cognitect.test-runner"]}}} 105 | --------------------------------------------------------------------------------