├── nix
├── pkgs
│ ├── reflex
│ │ └── default.nix
│ ├── arionEvaluate
│ │ └── default.nix
│ ├── makeDockerComposeFile
│ │ └── default.nix
│ ├── mylib
│ │ ├── composeAll.nix
│ │ ├── default.nix
│ │ └── exportEnvsCommand.nix
│ ├── nix-gitignore
│ │ ├── default.nix
│ │ ├── update.sh
│ │ └── revision.json
│ ├── morph
│ │ ├── update.sh
│ │ ├── revision.json
│ │ └── default.nix
│ ├── shmig
│ │ ├── update.sh
│ │ └── revision.json
│ ├── nixform
│ │ ├── update.sh
│ │ ├── revision.json
│ │ └── default.nix
│ ├── ntmuxp
│ │ ├── update.sh
│ │ ├── revision.json
│ │ └── default.nix
│ ├── pgtest
│ │ ├── update.sh
│ │ ├── default.nix
│ │ └── revision.json
│ ├── pnpm2nix
│ │ ├── update.sh
│ │ ├── default.nix
│ │ └── revision.json
│ ├── waitforit
│ │ ├── revisionDarwin.json
│ │ ├── revisionLinux.json
│ │ ├── default.nix
│ │ └── update.sh
│ ├── pnpm
│ │ ├── default.nix
│ │ ├── revision.json
│ │ └── update.sh
│ ├── yarn2nix
│ │ ├── default.nix
│ │ ├── revision.json
│ │ └── update.sh
│ ├── arion
│ │ ├── revision.json
│ │ ├── default.nix
│ │ └── update.sh
│ ├── docker-volume-rm-if-exists
│ │ ├── docker-volume-rm-if-exists
│ │ └── default.nix
│ ├── writeShellScript
│ │ └── default.nix
│ ├── opensslDecrypt
│ │ └── default.nix
│ ├── dump-schema
│ │ ├── default.nix
│ │ └── dump-schema
│ ├── wait-for-postgres
│ │ ├── default.nix
│ │ └── wait-for-postgres
│ ├── readRevision
│ │ └── default.nix
│ ├── pg_prove
│ │ └── default.nix
│ └── gitCryptUnlock
│ │ └── default.nix
├── overlays.nix
├── pkgs.nix
├── nixpkgs
│ ├── revision.json
│ ├── update.sh
│ └── default.nix
└── pkgsLinux.nix
├── .gitattributes
├── config
├── public
│ ├── region.nix
│ ├── database.nix
│ ├── dhparams.pem
│ └── keys.nix
└── ignored
│ ├── graphile-license.example
│ ├── github-oauth.nix.example
│ ├── aws.nix.example
│ ├── passwords-dev.setup.sh
│ └── passwords.setup.sh
├── packages
├── client
│ ├── NextjsApp
│ │ ├── PagesCustom
│ │ │ ├── Error.purs_
│ │ │ └── NotFound.purs_
│ │ ├── Pages
│ │ │ ├── Examples
│ │ │ │ ├── Ace.scss
│ │ │ │ ├── HigherOrderComponents.deps.js
│ │ │ │ ├── HigherOrderComponents.scss
│ │ │ │ ├── Lazy.purs
│ │ │ │ ├── Ace.purs
│ │ │ │ ├── Basic.purs
│ │ │ │ ├── Interpret.purs
│ │ │ │ ├── Lifecycle.purs
│ │ │ │ ├── TextNodes.purs
│ │ │ │ ├── DeeplyNested.purs
│ │ │ │ ├── ComponentsInputs.purs
│ │ │ │ ├── KeyboardInput.purs
│ │ │ │ ├── Components.purs
│ │ │ │ ├── ComponentsMultitype.purs
│ │ │ │ ├── HigherOrderComponents.purs
│ │ │ │ ├── EffectsAffAjax.purs
│ │ │ │ ├── EffectsEffectRandom.purs
│ │ │ │ └── Ace.deps.js
│ │ │ ├── Login.purs
│ │ │ └── Register.purs
│ │ ├── Blocks
│ │ │ ├── PurescriptLogo.js
│ │ │ ├── PurescriptLogo.purs
│ │ │ └── PurescriptLogo.svg
│ │ ├── NodeEnv.js
│ │ ├── PageImplementations
│ │ │ ├── Login
│ │ │ │ ├── Css.js
│ │ │ │ ├── Css.purs
│ │ │ │ ├── Css.module.scss
│ │ │ │ └── Types.purs
│ │ │ ├── Register
│ │ │ │ ├── Css.js
│ │ │ │ ├── Css.purs
│ │ │ │ ├── Css.module.scss
│ │ │ │ └── Types.purs
│ │ │ ├── VerifyUserEmailMobile
│ │ │ │ ├── Css.js
│ │ │ │ ├── Css.module.scss
│ │ │ │ ├── Css.purs
│ │ │ │ └── Types.purs
│ │ │ ├── VerifyUserEmailWeb
│ │ │ │ ├── Css.js
│ │ │ │ ├── Css.module.scss
│ │ │ │ ├── Css.purs
│ │ │ │ └── Types.purs
│ │ │ ├── Secret
│ │ │ │ └── Types.purs
│ │ │ └── Secret.purs
│ │ ├── Constants.purs
│ │ ├── Link
│ │ │ ├── Types.purs
│ │ │ └── Lib.purs
│ │ ├── Navigate
│ │ │ ├── Mobile.purs
│ │ │ └── Client.purs
│ │ ├── Manifest
│ │ │ ├── PageManifest.purs
│ │ │ └── ClientPagesManifest.purs
│ │ ├── Navigate.purs
│ │ ├── Router
│ │ │ └── Server.purs
│ │ ├── NodeEnv.purs
│ │ ├── Queries
│ │ │ └── IsUsernameOrEmailInUse.purs
│ │ └── Data
│ │ │ └── InUseUsernameOrEmail.purs
│ ├── client-and-mobile-deps.js
│ ├── server.entry.js
│ ├── mobile.entry.js
│ ├── client.entry.js
│ ├── client-and-mobile-deps.scss
│ └── NextjsGraphqlApi
│ │ ├── Object
│ │ ├── WebLoginPayload.purs
│ │ ├── WebRegisterPayload.purs
│ │ ├── PostsEdge.purs
│ │ ├── UsersEdge.purs
│ │ ├── UserAuthenticationsEdge.purs
│ │ └── PageInfo.purs
│ │ ├── Scopes.purs
│ │ └── Subscription.purs
├── src
│ ├── Mjml.js
│ ├── Firstline.js
│ ├── LoaderUtils.js
│ ├── EmailValidator.js
│ ├── ExpressSession.js
│ ├── EmailValidator.purs
│ ├── Webpack
│ │ ├── Compiler.js
│ │ ├── Plugins.js
│ │ ├── GetError.purs
│ │ ├── Plugins.purs
│ │ ├── FFI.js
│ │ └── FFI.purs
│ ├── GraphileWorker.js
│ ├── PassportGithub.js
│ ├── ConnectPgSimple.js
│ ├── Firstline.purs
│ ├── Cordova
│ │ ├── EventTypes
│ │ │ ├── Network.purs
│ │ │ └── Battery.purs
│ │ └── EventTypes.purs
│ ├── Chokidar.js
│ ├── HeterogeneousExtraShow.purs
│ ├── RecursiveReaddirAsync.js
│ ├── NodeUrlExtra.purs
│ ├── WebpackSpagoLoader.js
│ ├── LoaderUtils.purs
│ ├── ForeignObjectExtra.purs
│ ├── ConnectPgSimple.purs
│ ├── OptparseExtra.purs
│ ├── SpecAssertsExtra.purs
│ ├── Favicons.js
│ ├── WebpackSpagoLoader.purs
│ ├── ContribWebpackPlugins.purs
│ ├── SimpleLookupEnv.purs
│ ├── RunExtra.purs
│ ├── Chokidar.purs
│ ├── Data
│ │ └── Email.purs
│ ├── HalogenElementsExtra.purs
│ ├── HalogenVdomStringRendererRaw.purs
│ ├── ContribWebpackPlugins.js
│ ├── BuildSeleniumChromeDriver.purs_
│ ├── Postgraphile.js
│ ├── ArgonautCodecDecodersExtran.purs
│ ├── ReadWriteStdinYesNo.purs_
│ ├── TimeExtra.purs
│ ├── FRPEventExtra.purs
│ └── SimpleXMLWithIndentation.purs
├── client-halogen-examples
│ ├── lazy
│ │ ├── README.md
│ │ ├── .gitignore
│ │ └── src
│ │ │ ├── LazyLoadedImportImplementation.js
│ │ │ ├── LazyLoaded.purs
│ │ │ ├── LazyLoadedImport.purs
│ │ │ └── LazyLoadedImport.js
│ ├── ace
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ └── README.md
│ ├── text-nodes
│ │ ├── README.md
│ │ └── .gitignore
│ ├── components
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ ├── src
│ │ │ └── Main.purs
│ │ └── README.md
│ ├── interpret
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ └── README.md
│ ├── lifecycle
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ └── README.md
│ ├── deeply-nested
│ │ ├── .gitignore
│ │ ├── src
│ │ │ ├── Main.purs
│ │ │ ├── C.purs
│ │ │ ├── E.purs
│ │ │ ├── F.purs
│ │ │ ├── D.purs
│ │ │ ├── A.purs
│ │ │ └── B.purs
│ │ └── README.md
│ ├── effects-aff-ajax
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ ├── src
│ │ │ └── Main.purs
│ │ └── README.md
│ ├── keyboard-input
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ └── README.md
│ ├── components-multitype
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ ├── src
│ │ │ └── Main.purs
│ │ └── README.md
│ ├── effects-effect-random
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ ├── src
│ │ │ └── Main.purs
│ │ └── README.md
│ ├── higher-order-components
│ │ ├── .gitignore
│ │ ├── spago.dhall
│ │ └── src
│ │ │ └── Main.purs
│ ├── basic
│ │ ├── README.md
│ │ └── src
│ │ │ └── Button.purs
│ └── components-inputs
│ │ ├── README.md
│ │ └── src
│ │ └── Display.purs
├── api-server-config
│ └── ApiServerConfig.purs
├── client-tests
│ └── Test
│ │ └── Main.purs
├── db-tests
│ ├── extensions
│ │ ├── random_boolean.sql
│ │ ├── random_string.sql
│ │ ├── random_email.sql
│ │ ├── random_between.sql
│ │ ├── has_column.sql
│ │ ├── allow_app_roles_execute_pgtap_functions.sql
│ │ ├── random_enum.sql
│ │ └── randomly_set_empty_jwt_user_id.sql_
│ ├── tests-todo
│ │ └── tables
│ │ │ ├── users
│ │ │ ├── select
│ │ │ │ ├── app_user.sql
│ │ │ │ └── app_owner.sql
│ │ │ ├── insert
│ │ │ │ └── app_owner.sql
│ │ │ ├── delete
│ │ │ │ └── app_owner.sql
│ │ │ ├── priviliges
│ │ │ │ ├── app_user.sql
│ │ │ │ └── app_owner.sql
│ │ │ └── update
│ │ │ │ └── app_owner.sql
│ │ │ ├── posts
│ │ │ ├── priviligies
│ │ │ │ ├── app_user.sql
│ │ │ │ ├── app_owner.sql
│ │ │ │ └── app_admin.sql
│ │ │ └── common.sql
│ │ │ └── users_oauths
│ │ │ └── priviliges
│ │ │ ├── app_user.sql
│ │ │ └── app_owner.sql
│ └── tests
│ │ ├── roles
│ │ ├── app_anonymous.sql
│ │ ├── app_user.sql
│ │ ├── app_admin.sql
│ │ └── app_owner.sql
│ │ ├── actions
│ │ ├── confirm
│ │ │ └── priviliges.sql_
│ │ ├── reset_password
│ │ │ ├── priviliges.sql_
│ │ │ └── error_when_token_not_exists.sql_
│ │ ├── register
│ │ │ ├── priviliges.sql_
│ │ │ ├── success_when_user_not_exists.sql_
│ │ │ └── error_when_email_already_registered.sql_
│ │ ├── resend_confirmation
│ │ │ ├── priviliges.sql_
│ │ │ └── success.sql_
│ │ ├── send_reset_password
│ │ │ ├── priviliges.sql_
│ │ │ └── error_when_email_not_exists.sql_
│ │ ├── login_or_register_oauth
│ │ │ └── priviliges.sql_
│ │ ├── web_login
│ │ │ ├── priviliges.sql
│ │ │ ├── error_when_password_is_wrong.sql_
│ │ │ ├── error_when_email_is_wrong.sql_
│ │ │ ├── success_by_username_when_password_is_valid.sql
│ │ │ └── success_by_email_when_password_is_valid.sql
│ │ └── really_create_user
│ │ │ ├── priviliges.sql
│ │ │ └── success_not_verified.sql
│ │ ├── queries
│ │ ├── current_user
│ │ │ └── priviliges.sql
│ │ └── user_by_username_or_verified_email
│ │ │ ├── priviliges.sql
│ │ │ ├── success_by_username.sql
│ │ │ └── success_by_email.sql
│ │ ├── schemas
│ │ ├── app_hidden.sql
│ │ └── app_private.sql
│ │ └── no_missing_indexes_on_foreign_keys.sql
├── worker
│ └── Worker
│ │ ├── JobIds.purs
│ │ ├── EmailUI.purs
│ │ ├── Types.purs
│ │ └── Config
│ │ └── FromEnv.purs
├── api-server
│ └── ApiServer
│ │ ├── PostgraphilePassportAuthPlugin
│ │ ├── Shared.js
│ │ └── Shared.purs
│ │ ├── FrontendServerHttpProxy.purs_
│ │ ├── PostgraphilePassportAuthPlugin.js
│ │ └── FrontendServerHttpProxy.js_
├── client-webpack
│ ├── README.md
│ ├── cordova-webpack.config.js
│ └── NextjsWebpack
│ │ ├── WebpackConfig
│ │ ├── Types.purs
│ │ └── SpagoOptions.purs
│ │ ├── BuildManifestPlugin.js
│ │ └── FaviconsConfig.purs
└── feature-tests
│ └── FeatureTests
│ ├── FeatureTestSpecUtils
│ ├── AffRetry.purs
│ ├── EmailAVar.purs
│ └── LunaparkUtils.purs
│ ├── Tests
│ └── Login
│ │ └── ErrorNotConfirmedSpec.purs_
│ └── AllTests.purs
├── migrations
├── 0000000001-start
│ ├── 99_jwt.up.sql_
│ ├── 06_is_between_0_and_100.up.sql
│ ├── 03_current_user_id_required.up.sql
│ ├── 02_current_user_id_or_null.up.sql
│ ├── 05_generate_url_safe_token.up.sql
│ ├── 01_prelude.up.sql
│ └── 04_tg__set_updated_at.up.sql
├── 0000000003-posts
│ └── 01_posts
│ │ ├── 02_triggers.up.sql
│ │ ├── 03_policies.up.sql
│ │ └── 01_table.up.sql
├── 0000000003-posts.sql
├── 0000000002-users
│ ├── 03_app_public.functions.current_user.up.sql
│ ├── 07_app_private.tables.user_authentication_secrets.up.sql
│ ├── 16_app_private.tables.user_sessions.up.sql
│ ├── 01_app_private.tables.user_secrets.up.sql
│ └── 09_app_public.functions.user_by_username_or_email.up.sql
└── 0000000001-start.sql
├── packages.dhall
├── spago.dhall
├── docs
├── on-cordova-development.md
├── TODO.md
└── inspiration.md
├── regenerate-graphql-api-purs-codegen.sh
├── spago-worker.dhall
├── docker
└── common
│ ├── postgres.nix
│ ├── pgadmin.nix
│ ├── db_tests.nix
│ ├── server.nix
│ └── migrator.nix
├── plugins
├── fetch.json
└── android.json
├── spago-api-server.dhall
├── spago-feature-tests.dhall
├── .gitignore
├── postcss.config.js
├── dev-commands
├── all-commands.nix
└── dev
│ └── lib.nix
└── regenerate-purs-files.sh
/nix/pkgs/reflex/default.nix:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | /docs/bundle.js binary
2 |
--------------------------------------------------------------------------------
/config/public/region.nix:
--------------------------------------------------------------------------------
1 | "us-west-1"
2 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PagesCustom/Error.purs_:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PagesCustom/NotFound.purs_:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/ignored/graphile-license.example:
--------------------------------------------------------------------------------
1 | ............
2 |
--------------------------------------------------------------------------------
/packages/src/Mjml.js:
--------------------------------------------------------------------------------
1 | exports._mjml2html = require('mjml')
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lazy/README.md:
--------------------------------------------------------------------------------
1 | # Text nodes
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/ace/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lazy/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/text-nodes/README.md:
--------------------------------------------------------------------------------
1 | # Text nodes
2 |
--------------------------------------------------------------------------------
/packages/src/Firstline.js:
--------------------------------------------------------------------------------
1 | exports._firstline = require('firstline')
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/interpret/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lifecycle/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/text-nodes/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-aff-ajax/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/keyboard-input/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components-multitype/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-effect-random/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/packages/client/client-and-mobile-deps.js:
--------------------------------------------------------------------------------
1 | import "./client-and-mobile-deps.scss"
2 |
--------------------------------------------------------------------------------
/packages/src/LoaderUtils.js:
--------------------------------------------------------------------------------
1 | exports._getOptions = require('loader-utils').getOptions
2 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/higher-order-components/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/example.js
2 |
--------------------------------------------------------------------------------
/config/ignored/github-oauth.nix.example:
--------------------------------------------------------------------------------
1 | {
2 | CLIENT_ID="";
3 | CLIENT_SECRET="";
4 | }
5 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Ace.scss:
--------------------------------------------------------------------------------
1 | .ace_editor {
2 | height: 200px;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/src/EmailValidator.js:
--------------------------------------------------------------------------------
1 | exports.emailValidate = require('email-validator').validate
2 |
--------------------------------------------------------------------------------
/config/ignored/aws.nix.example:
--------------------------------------------------------------------------------
1 | {
2 | EC2_ACCESS_KEY = "...";
3 | EC2_SECRET_KEY = "...";
4 | }
5 |
--------------------------------------------------------------------------------
/packages/client/server.entry.js:
--------------------------------------------------------------------------------
1 | import { main } from "./NextjsApp/Entries/Server.purs"
2 |
3 | main()
4 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/HigherOrderComponents.deps.js:
--------------------------------------------------------------------------------
1 | import './HigherOrderComponents.scss'
2 |
--------------------------------------------------------------------------------
/packages/src/ExpressSession.js:
--------------------------------------------------------------------------------
1 | exports.expressSession = function() {
2 | return require("express-session")
3 | }
4 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/99_jwt.up.sql_:
--------------------------------------------------------------------------------
1 | create type app_public.jwt as (
2 | role text,
3 | user_id uuid
4 | );
5 |
--------------------------------------------------------------------------------
/packages.dhall:
--------------------------------------------------------------------------------
1 | let upstream =
2 | /home/srghma/projects/my-purescript-package-sets/mypackages.dhall
3 | in upstream
4 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Blocks/PurescriptLogo.js:
--------------------------------------------------------------------------------
1 | exports.purescriptLogoSrc = require('./PurescriptLogo.svg').default
2 |
--------------------------------------------------------------------------------
/nix/pkgs/arionEvaluate/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, arion }:
2 |
3 | import "${pkgs.arion}/share/arion/nix/eval-composition.nix"
4 |
--------------------------------------------------------------------------------
/packages/src/EmailValidator.purs:
--------------------------------------------------------------------------------
1 | module EmailValidator where
2 |
3 | foreign import emailValidate :: String -> Boolean
4 |
5 |
--------------------------------------------------------------------------------
/packages/client/mobile.entry.js:
--------------------------------------------------------------------------------
1 | import "./client-and-mobile-deps"
2 | import { main } from "./NextjsApp/Entries/Mobile.purs"
3 |
4 | main()
5 |
--------------------------------------------------------------------------------
/config/public/database.nix:
--------------------------------------------------------------------------------
1 | {
2 | POSTGRES_USER = "app_admin"; # superuser, only for running migrations
3 | DATABASE_NAME = "nextjsdemo";
4 | }
5 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Blocks/PurescriptLogo.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Blocks.PurescriptLogo where
2 |
3 | foreign import purescriptLogoSrc :: String
4 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/NodeEnv.js:
--------------------------------------------------------------------------------
1 |
2 | exports.env = {
3 | apiUrl: process.env.apiUrl,
4 | isProduction: process.env.isProduction,
5 | }
6 |
--------------------------------------------------------------------------------
/packages/client/client.entry.js:
--------------------------------------------------------------------------------
1 | import "./client-and-mobile-deps"
2 | import { main } from "./NextjsApp/Entries/Client.purs"
3 |
4 | main()
5 |
6 |
--------------------------------------------------------------------------------
/spago.dhall:
--------------------------------------------------------------------------------
1 | { name = "all"
2 | , dependencies = ./dependencies.dhall
3 | , packages = ./packages.dhall
4 | , sources =
5 | [ "./packages/**/*.purs"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/src/Webpack/Compiler.js:
--------------------------------------------------------------------------------
1 | exports._webpack = require('webpack')
2 |
3 | exports._webpackCompilerRun = function(compiler, handler) {
4 | compiler.run(handler)
5 | }
6 |
--------------------------------------------------------------------------------
/nix/overlays.nix:
--------------------------------------------------------------------------------
1 | [
2 | # (pkgs: pkgsOld: {
3 | # nodejs = pkgsOld.nodejs-14_x;
4 | # nodePackages = pkgsOld.nodePackages_14_x;
5 | # })
6 | (import ./pkgs/overlay.nix)
7 | ]
8 |
--------------------------------------------------------------------------------
/nix/pkgs.nix:
--------------------------------------------------------------------------------
1 | let
2 | nixpkgs = import ./nixpkgs;
3 |
4 | config = { allowUnfree = true; };
5 |
6 | overlays = import ./overlays.nix;
7 | in import nixpkgs { inherit config overlays; }
8 |
--------------------------------------------------------------------------------
/packages/api-server-config/ApiServerConfig.purs:
--------------------------------------------------------------------------------
1 | module ApiServerConfig where
2 |
3 | expressSessionMiddleware_cookieName :: String
4 | expressSessionMiddleware_cookieName = "connect.sid"
5 |
6 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Login/Css.js:
--------------------------------------------------------------------------------
1 | // Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | exports.styles = require('./Css.module.scss').default
3 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Register/Css.js:
--------------------------------------------------------------------------------
1 | // Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | exports.styles = require('./Css.module.scss').default
3 |
--------------------------------------------------------------------------------
/migrations/0000000003-posts/01_posts/02_triggers.up.sql:
--------------------------------------------------------------------------------
1 | create trigger _100_timestamps
2 | before update on app_public.posts
3 | for each row
4 | execute function app_private.tg__set_updated_at();
5 |
--------------------------------------------------------------------------------
/docs/on-cordova-development.md:
--------------------------------------------------------------------------------
1 | # how to console.log to logcat
2 |
3 | ```purs
4 | traceM (Data.Argonaut.Core.stringifyWithSpace 2 (Unsafe.Coerce.unsafeCoerce { message: "newRoute", xxx: show xxx }))
5 | ```
6 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailMobile/Css.js:
--------------------------------------------------------------------------------
1 | // Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | exports.styles = require('./Css.module.scss').default
3 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailWeb/Css.js:
--------------------------------------------------------------------------------
1 | // Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | exports.styles = require('./Css.module.scss').default
3 |
--------------------------------------------------------------------------------
/packages/client/client-and-mobile-deps.scss:
--------------------------------------------------------------------------------
1 | @use "material-components-web/material-components-web";
2 |
3 | :root {
4 | --mdc-theme-primary: #00c6ff;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | }
10 |
--------------------------------------------------------------------------------
/nix/pkgs/makeDockerComposeFile/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 |
3 | expression:
4 |
5 | pkgs.writeTextFile {
6 | name = "docker-compose.yaml";
7 | text = builtins.toJSON expression; # yaml is subset of json
8 | }
9 |
--------------------------------------------------------------------------------
/nix/pkgs/mylib/composeAll.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 |
3 | with lib;
4 |
5 | let
6 |
7 | compose = f: g: x: f (g x);
8 | id = x: x;
9 | composeAll = builtins.foldl' compose id;
10 |
11 | in
12 |
13 | composeAll
14 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Constants.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Constants where
2 |
3 | pagesManifestId :: String
4 | pagesManifestId = "#__PAGES_MANIFEST__"
5 |
6 | pagesDataId :: String
7 | pagesDataId = "#__PAGE_DATA__"
8 |
--------------------------------------------------------------------------------
/packages/src/GraphileWorker.js:
--------------------------------------------------------------------------------
1 | exports._run = require("graphile-worker").run
2 | exports._quickAddJob = require("graphile-worker").quickAddJob
3 | exports._stop = function(runner) { return runner.stop() }
4 |
--------------------------------------------------------------------------------
/nix/nixpkgs/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "owner": "nixos",
3 | "repo": "nixpkgs-channels",
4 | "rev": "84d74ae9c9cbed73274b8e4e00be14688ffc93fe",
5 | "sha256": "03nfq5g4h7vlq431vhfaxz12nkm0qsd56fppn11yjl2wx92b5b4j"
6 | }
7 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/ace/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/ace/**/*.purs" ],
5 | dependencies = config.dependencies # [ "ace" ]
6 | }
7 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/components/**/*.purs" ],
5 | dependencies = config.dependencies
6 | }
7 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lifecycle/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/lifecycle/**/*.purs" ],
5 | dependencies = config.dependencies
6 | }
7 |
--------------------------------------------------------------------------------
/nix/pkgs/nix-gitignore/default.nix:
--------------------------------------------------------------------------------
1 | { runCommand, fetchFromGitHub, lib, readRevision, ... }:
2 |
3 | let
4 | src = fetchFromGitHub (
5 | readRevision ./revision.json
6 | );
7 | in
8 | import src { inherit lib runCommand; }
9 |
--------------------------------------------------------------------------------
/packages/client-tests/Test/Main.purs:
--------------------------------------------------------------------------------
1 | module Test.Main where
2 |
3 | import Prelude
4 | import Effect (Effect)
5 | import Effect.Console (log)
6 |
7 | main :: Effect Unit
8 | main = do
9 | log "You should add some tests."
10 |
--------------------------------------------------------------------------------
/nix/pkgs/morph/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/DBCDK/morph > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/nix/pkgs/shmig/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/mbucc/shmig > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/keyboard-input/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/keyboard-input/**/*.purs" ],
5 | dependencies = config.dependencies
6 | }
7 |
--------------------------------------------------------------------------------
/packages/src/PassportGithub.js:
--------------------------------------------------------------------------------
1 | exports._passportStrategyGithub = function(options, verify) {
2 | return new (require('passport-github').Strategy)(
3 | Object.assign({ passReqToCallback: true }, options),
4 | verify
5 | )
6 | }
7 |
--------------------------------------------------------------------------------
/nix/pkgs/nixform/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/srghma/nixform > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/nix/pkgs/ntmuxp/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/srghma/ntmuxp > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/nix/pkgs/pgtest/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/srghma/pgtest > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/interpret/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/interpret/**/*.purs" ],
5 | dependencies = config.dependencies # [ "affjax" ]
6 | }
7 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/random_boolean.sql:
--------------------------------------------------------------------------------
1 |
2 | begin;
3 |
4 | create or replace function random_boolean() returns boolean as $$
5 | begin
6 | return random() > 0.5;
7 | end;
8 | $$ language plpgsql strict;
9 |
10 | commit;
11 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/random_string.sql:
--------------------------------------------------------------------------------
1 |
2 | begin;
3 |
4 | create or replace function random_string() returns text as $$
5 | begin
6 | return md5(random()::text);
7 | end;
8 | $$ language plpgsql strict;
9 |
10 | commit;
11 |
--------------------------------------------------------------------------------
/nix/pkgs/pgtest/default.nix:
--------------------------------------------------------------------------------
1 | { fetchFromGitHub, lib, readRevision }:
2 |
3 | let
4 | revData = readRevision ./revision.json;
5 |
6 | src = fetchFromGitHub {
7 | inherit (revData) rev sha256 owner repo;
8 | };
9 | in
10 | src
11 |
--------------------------------------------------------------------------------
/nix/pkgs/pnpm2nix/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/adisbladis/pnpm2nix > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/nix/pkgs/waitforit/revisionDarwin.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v2.4.1",
3 | "sha256": "0r69dbwcm4bc92x4xclkp00dzpmwi0ggc3fly9gqwvzh5xs6g8r9",
4 | "url": "https://github.com/maxcnunes/waitforit/releases/download/v2.4.1/waitforit-darwin_amd64"
5 | }
6 |
--------------------------------------------------------------------------------
/nix/pkgs/waitforit/revisionLinux.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v2.4.1",
3 | "sha256": "04fvl4wpmlvfgq2s8dqsjh63vjwb6hiw3397x72dy54ala1vfs4m",
4 | "url": "https://github.com/maxcnunes/waitforit/releases/download/v2.4.1/waitforit-linux_amd64"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/src/ConnectPgSimple.js:
--------------------------------------------------------------------------------
1 | exports.mkExpressSessionStore = function(expressSession) {
2 | return function(config) {
3 | const PgSession = require("connect-pg-simple")(expressSession)
4 |
5 | return new PgSession(config)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/nix-gitignore/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/siers/nix-gitignore > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components-multitype/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/components-multitype/src/**/*.purs" ],
5 | dependencies = config.dependencies
6 | }
7 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-aff-ajax/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/effects-aff-ajax/**/*.purs" ],
5 | dependencies = config.dependencies # [ "affjax" ]
6 | }
7 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/higher-order-components/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/higher-order-components/**/*.purs" ],
5 | dependencies = config.dependencies
6 | }
7 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lazy/src/LazyLoadedImportImplementation.js:
--------------------------------------------------------------------------------
1 | exports.lazyLoadedImport = function() {
2 | // or can use require.ensure
3 | var x = import(
4 | './LazyLoaded.purs'
5 | )
6 | console.log(x)
7 | return x
8 | }
9 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/random_email.sql:
--------------------------------------------------------------------------------
1 |
2 | begin;
3 |
4 | create or replace function random_email() returns text as $$
5 | begin
6 | return md5(random()::text) || '@mail.com';
7 | end;
8 | $$ language plpgsql strict;
9 |
10 | commit;
11 |
--------------------------------------------------------------------------------
/nix/pkgs/mylib/default.nix:
--------------------------------------------------------------------------------
1 | { lib }:
2 |
3 | rec {
4 | recursiveMerge = import ./recursiveMerge.nix { inherit lib; };
5 | composeAll = import ./composeAll.nix { inherit lib; };
6 | exportEnvsCommand = import ./exportEnvsCommand.nix { inherit lib; };
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/pnpm2nix/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, fetchFromGitHub, readRevision, ... }:
2 |
3 | let
4 | src = fetchFromGitHub (
5 | readRevision ./revision.json
6 | );
7 |
8 | pnpm2nix = pkgs.callPackage "${src}/default.nix" {};
9 | in
10 | pnpm2nix
11 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-effect-random/spago.dhall:
--------------------------------------------------------------------------------
1 | let config = ../../spago.dhall
2 |
3 | in config // {
4 | sources = config.sources # [ "examples/effects-effect-random/**/*.purs" ],
5 | dependencies = config.dependencies # [ "random" ]
6 | }
7 |
--------------------------------------------------------------------------------
/packages/src/Firstline.purs:
--------------------------------------------------------------------------------
1 | module Firstline where
2 |
3 | import Control.Promise (Promise)
4 | import Effect.Uncurried (EffectFn1)
5 | import Protolude
6 | import Pathy (Abs, File, Path)
7 |
8 | foreign import _firstline :: EffectFn1 String (Promise String)
9 |
--------------------------------------------------------------------------------
/docs/TODO.md:
--------------------------------------------------------------------------------
1 | # phone number as username + sms 6-digit code
2 |
3 | https://youtu.be/CZ-Ahh6v0PY
4 | https://github.com/firebase/FirebaseUI-Android
5 | https://github.com/firebase/FirebaseUI-IOS
6 | https://www.youtube.com/watch?v=3tlSUMsEqAA&ab_channel=SamarthAgarwal
7 |
--------------------------------------------------------------------------------
/packages/src/Cordova/EventTypes/Network.purs:
--------------------------------------------------------------------------------
1 | module Cordova.EventTypes.Network where
2 |
3 | import Web.Event.Event (EventType(..))
4 |
5 | online :: EventType
6 | online = EventType "online"
7 |
8 | offline :: EventType
9 | offline = EventType "offline"
10 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/random_between.sql:
--------------------------------------------------------------------------------
1 |
2 | begin;
3 |
4 | create or replace function random_between(low int, high int) returns int as $$
5 | begin
6 | return floor(random()* (high-low + 1) + low);
7 | end;
8 | $$ language plpgsql strict;
9 |
10 | commit;
11 |
--------------------------------------------------------------------------------
/nix/pkgs/pnpm/default.nix:
--------------------------------------------------------------------------------
1 | { fetchFromGitHub, readRevision, ... }:
2 |
3 | let
4 | nixpkgs = fetchFromGitHub (
5 | readRevision ./revision.json
6 | );
7 |
8 | pkgs = import nixpkgs { config = { allowUnfree = true; }; };
9 | in
10 | pkgs.nodePackages_10_x.pnpm
11 |
--------------------------------------------------------------------------------
/nix/pkgs/yarn2nix/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, fetchFromGitHub, readRevision, ... }:
2 |
3 | let
4 | src = fetchFromGitHub (
5 | readRevision ./revision.json
6 | );
7 |
8 | # src = ~/projects/yarn2nix;
9 |
10 | src_ = import src { inherit pkgs; };
11 | in
12 | src_
13 |
--------------------------------------------------------------------------------
/nix/pkgs/morph/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/DBCDK/morph",
3 | "rev": "c048d6339f18613a1544bc62ff852cb4c6de1042",
4 | "date": "2020-09-08T16:17:32+02:00",
5 | "sha256": "0yb8prji2nqjsj1aiiqnbqaajbi5l17rg8k78ry7pl3a8sqa3h1x",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/ntmuxp/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/srghma/ntmuxp",
3 | "rev": "e755165d84a2d1c93809a83e9e02d8539a0b627a",
4 | "date": "2019-08-01T10:52:48+03:00",
5 | "sha256": "0qrjaxmqr7zidr8h460115dba7jkr6rd403lzsxgmdmmwifkjwzc",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/pgtest/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/srghma/pgtest",
3 | "rev": "d01ecaf5a7442fec2ed36e76e5f68b90194f57a1",
4 | "date": "2019-01-12T11:03:24+02:00",
5 | "sha256": "17qmw2k4h8hz9ijmdskgkf8hv5jmzwfwhkm9n46fv3srz8j2q64h",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/pnpm/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/srghma/nixpkgs",
3 | "rev": "7ea948f912efda9b85b3f6ed1ad9810ff995b298",
4 | "date": "2019-01-26T19:26:17+02:00",
5 | "sha256": "0q6b6415v4bgrh8mha2v2xsrr5qv823f06z7zi3q3jjls6mbliln",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/shmig/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/mbucc/shmig",
3 | "rev": "81006b75e31b0772d68f4e988194c4eb33f0c4eb",
4 | "date": "2019-06-09T10:38:26-04:00",
5 | "sha256": "0zd1yqink2kq7i68hi03723dgwp7p7y3phvs8js3rxsz4va6chgc",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailWeb/Css.module.scss:
--------------------------------------------------------------------------------
1 | .root {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 |
6 | max-width: 30%;
7 | min-width: 400px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/src/Chokidar.js:
--------------------------------------------------------------------------------
1 | exports._watch = function({ files, onAll }) {
2 | const watcher = require('chokidar').watch(files)
3 |
4 | watcher.on('all', function(event, path) {
5 | onAll(path)
6 | })
7 |
8 | return function() {
9 | watcher.close()
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/nix/pkgs/arion/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/hercules-ci/arion",
3 | "rev": "427a3b0e3c453a29876962d0e415e757e50d6ed7",
4 | "date": "2020-10-02T13:00:10+02:00",
5 | "sha256": "0b5dvbadwaykc7xl7glfzd6pr9dfsw6m3dq438289xc6zsq6qs9r",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/mylib/exportEnvsCommand.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 |
3 | with lib;
4 |
5 | let
6 |
7 | exportEnvsCommand = attrs: builtins.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "export " + name + "=" + builtins.toString value) attrs);
8 |
9 | in
10 |
11 | exportEnvsCommand
12 |
--------------------------------------------------------------------------------
/nix/pkgs/nixform/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/srghma/nixform",
3 | "rev": "3f091c9df7dcc2bfae3ea94549aee67b605b4497",
4 | "date": "2018-09-22T10:38:55+03:00",
5 | "sha256": "1wbcyna67kjxlxi8m5wg1zq56i58zrw6k3v2czpnjpi8y8ibgc4j",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/yarn2nix/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/moretea/yarn2nix",
3 | "rev": "37c3b7c1d1170ed6e063b804c4dbe871f4043349",
4 | "date": "2020-07-16T14:12:19+00:00",
5 | "sha256": "0z1gx5mqsi0ny3lcdvq4rvjr3bnp84pkfz7mdpcza6b4vmigmpxn",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailMobile/Css.module.scss:
--------------------------------------------------------------------------------
1 | .root {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 |
6 | max-width: 30%;
7 | min-width: 400px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/src/HeterogeneousExtraShow.purs:
--------------------------------------------------------------------------------
1 | module HeterogeneousExtraShow where
2 |
3 | import Protolude
4 | import Heterogeneous.Mapping (class Mapping)
5 |
6 | data Show = Show
7 |
8 | instance showMappingAction :: (Show n) => Mapping Show n String where
9 | mapping Show = show
10 |
--------------------------------------------------------------------------------
/nix/pkgs/pnpm2nix/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/adisbladis/pnpm2nix",
3 | "rev": "f67be0925a91b92f54d99dbdead7a06920b979ac",
4 | "date": "2020-07-10T15:56:51+00:00",
5 | "sha256": "1qn21p3n02asz3h6llavxkjm845dj5w4q88ndgrxzww0xm1r8wsi",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/morph/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, fetchFromGitHub, readRevision, ... }:
2 |
3 | let
4 | revData = readRevision ./revision.json;
5 |
6 | src = fetchFromGitHub {
7 | inherit (revData) rev sha256 owner repo;
8 | };
9 | in
10 | pkgs.callPackage "${src}/nix-packaging/default.nix" { }
11 |
--------------------------------------------------------------------------------
/nix/pkgs/nix-gitignore/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "url": "https://github.com/siers/nix-gitignore",
3 | "rev": "a9609739209cef90e2e8eaa0b5b656721d3da63e",
4 | "date": "2020-05-02T18:37:36+03:00",
5 | "sha256": "1h7dgiy0kiyzsv0s2w5p6z5103k4s8wc6i793cwq1srk2kwdsrxm",
6 | "fetchSubmodules": false
7 | }
8 |
--------------------------------------------------------------------------------
/nix/pkgs/pnpm/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/srghma/nixpkgs --rev 7ea948f912efda9b85b3f6ed1ad9810ff995b298 --no-deepClone > "$SCRIPT_DIR/revision.json"
6 |
--------------------------------------------------------------------------------
/nix/pkgs/docker-volume-rm-if-exists/docker-volume-rm-if-exists:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | volume="$1"
4 |
5 | if docker volume list | grep "$volume" &>/dev/null; then
6 | echo "removing volume $volume"
7 | docker volume rm "$volume"
8 | else
9 | echo "volume $volume don't exists, ignoring"
10 | fi
11 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Link/Types.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Link.Types where
2 |
3 | import Halogen as H
4 | import NextjsApp.Route as NextjsApp.Route
5 | import Web.UIEvent.MouseEvent as Web.UIEvent.MouseEvent
6 | import Protolude
7 |
8 | type Query
9 | = Const Void
10 |
11 | type Message
12 | = Void
13 |
--------------------------------------------------------------------------------
/packages/worker/Worker/JobIds.purs:
--------------------------------------------------------------------------------
1 | module Worker.JobIds where
2 |
3 | -- generated by ./gen-job-ids-from-migrations.hs
4 |
5 | type JobIds a =
6 | { "JOB__SEND_PASSWORD_CHANGED_EMAIL" :: a
7 | , "JOB__SEND_PASSWORD_RESET_EMAIL" :: a
8 | , "JOB__SEND_VERIFICATION_EMAIL_FOR_USER_EMAIL" :: a
9 | }
10 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/06_is_between_0_and_100.up.sql:
--------------------------------------------------------------------------------
1 | create or replace function app_hidden.is_from_0_to_100(
2 | num decimal(3,0)
3 | ) returns boolean as $$
4 | select (num >= 0) AND (num <= 100);
5 | $$ immutable strict language sql;
6 |
7 | grant execute on function app_hidden.is_from_0_to_100(decimal) to public;
8 |
--------------------------------------------------------------------------------
/packages/src/RecursiveReaddirAsync.js:
--------------------------------------------------------------------------------
1 | const rra = require('recursive-readdir-async')
2 |
3 | exports._recursiveTreeList = function(pagesDir, options) {
4 | return rra.list(
5 | pagesDir,
6 | {
7 | mode: rra.TREE,
8 | recursive: true,
9 | include: options.include,
10 | }
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailWeb/Css.purs:
--------------------------------------------------------------------------------
1 | -- Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | module NextjsApp.PageImplementations.VerifyUserEmailWeb.Css (styles) where
3 |
4 | import Halogen.HTML (ClassName)
5 |
6 | foreign import styles ::
7 | { root :: ClassName
8 | }
9 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailMobile/Css.purs:
--------------------------------------------------------------------------------
1 | -- Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | module NextjsApp.PageImplementations.VerifyUserEmailMobile.Css (styles) where
3 |
4 | import Halogen.HTML (ClassName)
5 |
6 | foreign import styles ::
7 | { root :: ClassName
8 | }
9 |
--------------------------------------------------------------------------------
/nix/pkgs/writeShellScript/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs }:
2 |
3 | name: text:
4 | pkgs.writeTextFile {
5 | inherit name;
6 |
7 | executable = true;
8 |
9 | text = ''
10 | #!${pkgs.stdenv.shell} -eu
11 | ${text}
12 | '';
13 |
14 | checkPhase = ''
15 | ${pkgs.stdenv.shell} -n $out
16 | '';
17 | }
18 |
--------------------------------------------------------------------------------
/packages/src/NodeUrlExtra.purs:
--------------------------------------------------------------------------------
1 | module NodeUrlExtra where
2 |
3 | import Node.URL (Query)
4 | import Foreign.Object (Object)
5 | import Unsafe.Coerce (unsafeCoerce)
6 |
7 | -- | Should be one level
8 | toQuery :: Object String -> Query
9 | toQuery = unsafeCoerce
10 |
11 | fromQuery :: Query -> Object String
12 | fromQuery = unsafeCoerce
13 |
--------------------------------------------------------------------------------
/packages/api-server/ApiServer/PostgraphilePassportAuthPlugin/Shared.js:
--------------------------------------------------------------------------------
1 | exports.mkSelectGraphQLResultFromTable = (user_id, sql) =>
2 | (tableAlias, sqlBuilder) => {
3 | sqlBuilder.where(
4 | sql.fragment`${tableAlias}.id = ${sql.value(user_id)}`
5 | )
6 | }
7 |
8 | exports.appPublicUsersFragment = fragment => fragment`app_public.users`
9 |
--------------------------------------------------------------------------------
/nix/pkgs/opensslDecrypt/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 |
3 | keyFile: name: ciphertext:
4 | pkgs.lib.removeSuffix "\n" (
5 | builtins.readFile (
6 | pkgs.runCommand name {} ''
7 | echo "${ciphertext}" | \
8 | ${pkgs.openssl}/bin/openssl enc -aes-256-cbc -a -d -kfile "${keyFile}" -out "$out"
9 | ''
10 | )
11 | )
12 |
--------------------------------------------------------------------------------
/packages/src/WebpackSpagoLoader.js:
--------------------------------------------------------------------------------
1 | exports.getAbsoluteOutputDirFromSpago = require('webpack-spago-loader/lib/getAbsoluteOutputDirFromSpago')
2 |
3 | exports.getSourcesFromSpago = require('webpack-spago-loader/lib/getSourcesFromSpago')
4 |
5 | exports.rules = require('webpack-spago-loader/rules')
6 |
7 | exports.watcherJob = require('webpack-spago-loader/rules')
8 |
--------------------------------------------------------------------------------
/regenerate-graphql-api-purs-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euxo pipefail
4 |
5 | ###################################
6 |
7 | rm -rfd ./packages/client/NextjsGraphqlApi
8 |
9 | ./node_modules/.bin/purescript-graphql-client-generator \
10 | --input-json ./schemas/schema.json --output ./packages/client/NextjsGraphqlApi --api NextjsGraphqlApi
11 |
--------------------------------------------------------------------------------
/spago-worker.dhall:
--------------------------------------------------------------------------------
1 | { name = "worker"
2 | , dependencies = ./dependencies.dhall
3 | , packages = ./packages.dhall
4 | , sources =
5 | [ "./packages/src/**/*.purs"
6 | , "./packages/worker/**/*.purs"
7 | , "./packages/client/NextjsApp/AppM.purs"
8 | , "./packages/client/NextjsApp/Route.purs"
9 | , "./packages/client/NextjsApp/Link/Types.purs"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/docker/common/postgres.nix:
--------------------------------------------------------------------------------
1 | {}:
2 |
3 | {
4 | image = "postgres:10";
5 |
6 | volumes = [
7 | "postgres_data:/var/lib/postgresql/data"
8 | ];
9 |
10 | environment = {
11 | POSTGRES_USER = "app_admin"; # superuser, only for running migrations
12 | POSTGRES_PASSWORD = "app_admin_pass";
13 | POSTGRES_DB = "nextjsdemo_test";
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/nix/pkgs/yarn2nix/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | nix-prefetch-git https://github.com/moretea/yarn2nix > "$SCRIPT_DIR/revision.json"
6 | # nix-prefetch-git https://github.com/srghma/yarn2nix --rev f559fc67c80204931444227d95f93d02161f2570 > "$SCRIPT_DIR/revision.json"
7 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/has_column.sql:
--------------------------------------------------------------------------------
1 |
2 | begin;
3 |
4 | -- has_column( schema, table, column )
5 | CREATE OR REPLACE FUNCTION has_column ( NAME, NAME, NAME )
6 | RETURNS TEXT AS $$
7 | SELECT ok( _cexists( $1, $2, $3 ), 'Column ' || quote_ident($1) || '.' || quote_ident($2) || '.' || quote_ident($3) || ' should exist' );
8 | $$ LANGUAGE SQL;
9 |
10 | commit;
11 |
--------------------------------------------------------------------------------
/packages/src/LoaderUtils.purs:
--------------------------------------------------------------------------------
1 | module LoaderUtils where
2 |
3 | import Effect.Uncurried (EffectFn1, runEffectFn1)
4 | import Protolude
5 | import Webpack.Loader (LoaderContext)
6 | import Node.URL (Query)
7 |
8 | foreign import _getOptions :: EffectFn1 LoaderContext Query
9 |
10 | getOptions :: LoaderContext -> Effect Query
11 | getOptions = runEffectFn1 _getOptions
12 |
--------------------------------------------------------------------------------
/packages/src/Cordova/EventTypes/Battery.purs:
--------------------------------------------------------------------------------
1 | module Cordova.EventTypes.Battery where
2 |
3 | import Web.Event.Event (EventType(..))
4 |
5 | batterycritical :: EventType
6 | batterycritical = EventType "batterycritical"
7 |
8 | batterylow :: EventType
9 | batterylow = EventType "batterylow"
10 |
11 | batterystatus :: EventType
12 | batterystatus = EventType "batterystatus"
13 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/Main.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.Main where
2 |
3 | import Prelude
4 |
5 | import Effect (Effect)
6 | import Example.DeeplyNested.A as A
7 | import Halogen.Aff as HA
8 | import Halogen.VDom.Driver (runUI)
9 |
10 | main :: Effect Unit
11 | main = HA.runHalogenAff do
12 | body <- HA.awaitBody
13 | runUI A.component unit body
14 |
--------------------------------------------------------------------------------
/migrations/0000000003-posts.sql:
--------------------------------------------------------------------------------
1 | -- generated by ./gen-migrations.hs
2 |
3 | -- ==== UP ====
4 |
5 | begin;
6 |
7 | \include 0000000003-posts/01_posts/01_table.up.sql
8 | \include 0000000003-posts/01_posts/02_triggers.up.sql
9 | \include 0000000003-posts/01_posts/03_policies.up.sql
10 |
11 |
12 | commit;
13 |
14 | -- ==== DOWN ====
15 |
16 | -- do nothing, this should never happen
17 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/allow_app_roles_execute_pgtap_functions.sql:
--------------------------------------------------------------------------------
1 |
2 | -- allow our application roles execute pg_tap functions (like foreign_tables_are)
3 | grant usage on schema public to app_user, app_anonymous;
4 | grant select, insert, update, delete on all tables in schema public to app_user, app_anonymous;
5 | grant execute on all functions in schema public to app_user, app_anonymous;
6 |
--------------------------------------------------------------------------------
/packages/src/ForeignObjectExtra.purs:
--------------------------------------------------------------------------------
1 | module ForeignObjectExtra where
2 |
3 | import Protolude
4 | import Foreign.Object (Object)
5 | import Foreign.Object as Object
6 |
7 | updateKeys :: forall a . (String -> String) -> Object a -> Object a
8 | updateKeys f o =
9 | (Object.toUnfoldable o :: Array (Tuple String a))
10 | # map (\(Tuple k v) -> Tuple (f k) v)
11 | # Object.fromFoldable
12 |
--------------------------------------------------------------------------------
/packages/src/ConnectPgSimple.purs:
--------------------------------------------------------------------------------
1 | module ConnectPgSimple where
2 |
3 | import ExpressSession (ExpressSession, ExpressSessionStore)
4 |
5 | import Database.PostgreSQL (Pool)
6 |
7 | type Config =
8 | { pool :: Pool
9 | , schemaName :: String
10 | , tableName :: String
11 | -- | , ttl
12 | }
13 |
14 | foreign import mkExpressSessionStore :: ExpressSession -> Config -> ExpressSessionStore
15 |
--------------------------------------------------------------------------------
/packages/client-webpack/README.md:
--------------------------------------------------------------------------------
1 | # how webpack-spago-loader is being used
2 |
3 | on build (client and server) - the `webpack-spago-loader/build-job` one-off task is being used
4 | on dev (client and server) - the `webpack-spago-loader/watcher-job` watcher is being used
5 |
6 | -- on build and dev for mobile - the plugin is used because we run webpack through cordova and there is no way to check is it one time
7 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Navigate/Mobile.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Navigate.Mobile where
2 |
3 | import Protolude
4 |
5 | import FRP.Event (EventIO)
6 |
7 | import NextjsApp.Route as NextjsApp.Route
8 |
9 | navigate :: EventIO (Variant NextjsApp.Route.WebRoutesWithParamRow) -> (Variant NextjsApp.Route.WebRoutesWithParamRow) -> Effect Unit
10 | navigate newRouteEventIO route = newRouteEventIO.push route
11 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/higher-order-components/src/Main.purs:
--------------------------------------------------------------------------------
1 | module Example.HOC.Main where
2 |
3 | import Prelude
4 |
5 | import Effect (Effect)
6 | import Example.HOC.Harness as Harness
7 | import Halogen.Aff as HA
8 | import Halogen.VDom.Driver (runUI)
9 |
10 | main :: Effect Unit
11 | main = HA.runHalogenAff do
12 | body <- HA.awaitBody
13 | runUI Harness.component unit body
14 |
--------------------------------------------------------------------------------
/packages/feature-tests/FeatureTests/FeatureTestSpecUtils/AffRetry.purs:
--------------------------------------------------------------------------------
1 | module FeatureTests.FeatureTestSpecUtils.AffRetry where
2 |
3 | import Prelude
4 | import Effect.Aff.Retry as AffRetry
5 | import Data.Time.Duration
6 |
7 | retryAction action =
8 | AffRetry.recovering
9 | (AffRetry.constantDelay (Milliseconds 200.0) <> AffRetry.limitRetries 10)
10 | [\_ _ -> pure true]
11 | (\_ -> action)
12 |
--------------------------------------------------------------------------------
/migrations/0000000002-users/03_app_public.functions.current_user.up.sql:
--------------------------------------------------------------------------------
1 | create function app_public.current_user() returns app_public.users as $$
2 | select users.*
3 | from app_public.users
4 | where id = app_public.current_user_id_or_null();
5 | $$ language sql stable set search_path from current;
6 |
7 | comment on function app_public.current_user() is E'The currently logged in user (or null if not logged in).';
8 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components/src/Main.purs:
--------------------------------------------------------------------------------
1 | module Example.Components.Main where
2 |
3 | import Prelude
4 |
5 | import Effect (Effect)
6 | import Example.Components.Container as Container
7 | import Halogen.Aff as HA
8 | import Halogen.VDom.Driver (runUI)
9 |
10 | main :: Effect Unit
11 | main = HA.runHalogenAff do
12 | body <- HA.awaitBody
13 | runUI Container.component unit body
14 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-effect-random/src/Main.purs:
--------------------------------------------------------------------------------
1 | module Example.Effects.Effect.Random.Main where
2 |
3 | import Prelude
4 |
5 | import Effect (Effect)
6 | import Example.Effects.Effect.Random.Component (component)
7 | import Halogen.Aff as HA
8 | import Halogen.VDom.Driver (runUI)
9 |
10 | main :: Effect Unit
11 | main = HA.runHalogenAff do
12 | body <- HA.awaitBody
13 | runUI component unit body
14 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/HigherOrderComponents.scss:
--------------------------------------------------------------------------------
1 | .Panel {
2 | border: 1px solid #ccc;
3 | border-radius: 2px;
4 | margin: 1em;
5 | border-radius: 0.2em;
6 | }
7 |
8 | .Panel--open {
9 | border-radius: 0.2em 0.2em 0.5em 0.5em;
10 | }
11 |
12 | .Panel-header {
13 | background: #ddd;
14 | padding: 0.5em;
15 | text-align: right;
16 | }
17 |
18 | .Panel-content {
19 | padding: 0.5em;
20 | }
21 |
--------------------------------------------------------------------------------
/nix/pkgs/nixform/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 |
3 | let
4 | terraform = pkgs.terraform.withPlugins (p: with p; [ aws tls local ]);
5 |
6 | revData = builtins.fromJSON (builtins.readFile ./revision.json);
7 |
8 | src = builtins.fetchTarball {
9 | inherit (revData) sha256;
10 | url = "${revData.url}/archive/${revData.rev}.tar.gz";
11 | };
12 | in
13 | pkgs.callPackage "${src}/default.nix" { inherit terraform; }
14 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-aff-ajax/src/Main.purs:
--------------------------------------------------------------------------------
1 | module Example.Effects.Aff.Ajax.Main where
2 |
3 | import Prelude
4 |
5 | import Effect (Effect)
6 | import Example.Effects.Aff.Ajax.Component (component)
7 | import Halogen.Aff as HA
8 | import Halogen.VDom.Driver (runUI)
9 |
10 | -- | Run the app.
11 | main :: Effect Unit
12 | main = HA.runHalogenAff do
13 | body <- HA.awaitBody
14 | runUI component unit body
15 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Login/Css.purs:
--------------------------------------------------------------------------------
1 | -- Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | module NextjsApp.PageImplementations.Login.Css (styles) where
3 |
4 | import Halogen.HTML (ClassName)
5 |
6 | foreign import styles ::
7 | { root :: ClassName
8 | , logo :: ClassName
9 | , buttons :: ClassName
10 | , buttons__button :: ClassName
11 | , input :: ClassName
12 | }
13 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Register/Css.purs:
--------------------------------------------------------------------------------
1 | -- Do not edit, this file was autogenerated by generate-halogen-css-modules
2 | module NextjsApp.PageImplementations.Register.Css (styles) where
3 |
4 | import Halogen.HTML (ClassName)
5 |
6 | foreign import styles ::
7 | { root :: ClassName
8 | , logo :: ClassName
9 | , buttons :: ClassName
10 | , buttons__button :: ClassName
11 | , input :: ClassName
12 | }
13 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components-multitype/src/Main.purs:
--------------------------------------------------------------------------------
1 | module Example.Components.Multitype.Main where
2 |
3 | import Prelude
4 | import Effect (Effect)
5 | import Halogen.Aff as HA
6 | import Halogen.VDom.Driver (runUI)
7 | import Example.Components.Multitype.Container as Container
8 |
9 | main :: Effect Unit
10 | main = HA.runHalogenAff do
11 | body <- HA.awaitBody
12 | runUI Container.component unit body
13 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Manifest/PageManifest.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Manifest.PageManifest where
2 |
3 | import Protolude
4 | import Data.Array as Data.Array
5 |
6 | type PageManifest
7 | = { css :: Array String
8 | , js :: Array String
9 | }
10 |
11 | mergePageManifests :: PageManifest -> PageManifest -> PageManifest
12 | mergePageManifests a b = { css: Data.Array.nubEq (a.css <> b.css), js: Data.Array.nubEq (a.js <> b.js) }
13 |
--------------------------------------------------------------------------------
/plugins/fetch.json:
--------------------------------------------------------------------------------
1 | {
2 | "cordova-plugin-whitelist": {
3 | "source": {
4 | "type": "registry",
5 | "id": "cordova-plugin-whitelist@^1.3.4"
6 | },
7 | "is_top_level": true,
8 | "variables": {}
9 | },
10 | "cordova-plugin-webpack": {
11 | "source": {
12 | "type": "registry",
13 | "id": "cordova-plugin-webpack@^1.0.5"
14 | },
15 | "is_top_level": true,
16 | "variables": {}
17 | }
18 | }
--------------------------------------------------------------------------------
/plugins/android.json:
--------------------------------------------------------------------------------
1 | {
2 | "prepare_queue": {
3 | "installed": [],
4 | "uninstalled": []
5 | },
6 | "config_munge": {
7 | "files": {}
8 | },
9 | "installed_plugins": {
10 | "cordova-plugin-webpack": {
11 | "PACKAGE_NAME": "com.cordova.HalogenNextjs"
12 | },
13 | "cordova-plugin-whitelist": {
14 | "PACKAGE_NAME": "com.cordova.HalogenNextjs"
15 | }
16 | },
17 | "dependent_plugins": {}
18 | }
19 |
--------------------------------------------------------------------------------
/nix/pkgs/arion/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, fetchFromGitHub, readRevision, ... }:
2 |
3 | # let
4 | # src = fetchFromGitHub (
5 | # readRevision ./revision.json
6 | # );
7 |
8 | # # src = /home/srghma/projects/arion;
9 |
10 | # arion = pkgs.callPackage "${src}/arion.nix" {};
11 | # # arion = (import src {}).arion;
12 | # in
13 | # arion
14 |
15 | (import (builtins.fetchTarball https://github.com/hercules-ci/arion/tarball/master) {}).arion
16 |
--------------------------------------------------------------------------------
/packages/worker/Worker/EmailUI.purs:
--------------------------------------------------------------------------------
1 | module Worker.EmailUI where
2 |
3 | import Protolude
4 | import Halogen.HTML as HH
5 | import Halogen.HTML.Properties as HP
6 |
7 | -- XXX: note that
and
result in warning "... are not registered"
8 |
9 | link_to_styled text url =
10 | HH.a
11 | [ HP.style "color: #f57a12; text-decoration: none; font-style: oblique; font-weight: bold;"
12 | , HP.href url
13 | ]
14 | [ HH.text text
15 | ]
16 |
17 |
--------------------------------------------------------------------------------
/nix/pkgs/docker-volume-rm-if-exists/default.nix:
--------------------------------------------------------------------------------
1 | { stdenv, lib, makeWrapper, docker }:
2 |
3 | stdenv.mkDerivation rec {
4 | name = "docker-volume-rm-if-exists";
5 |
6 | nativeBuildInputs = [ makeWrapper ];
7 |
8 | phases = [ "installPhase" ];
9 |
10 | installPhase = ''
11 | mkdir -p $out/bin
12 |
13 | makeWrapper ${./docker-volume-rm-if-exists} $out/bin/${name} \
14 | --prefix PATH : ${lib.makeBinPath [ docker ]}
15 | '';
16 | }
17 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Blocks/PurescriptLogo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/src/OptparseExtra.purs:
--------------------------------------------------------------------------------
1 | module OptparseExtra where
2 |
3 | import Options.Applicative
4 | import Protolude
5 |
6 | import Data.String.NonEmpty (NonEmptyString)
7 | import Data.String.NonEmpty as NonEmptyString
8 |
9 | nonEmptyString :: ReadM NonEmptyString
10 | nonEmptyString = eitherReader $ NonEmptyString.fromString >>> note "Expected non empty string"
11 |
12 | nonempty :: ReadM String
13 | nonempty = nonEmptyString <#> NonEmptyString.toString
14 |
--------------------------------------------------------------------------------
/config/public/dhparams.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIIBCAKCAQEAnhhDKZIyg84On8G29O9aURmFohj2x5PNignaKoSXJuRu3+kvZNhs
3 | 4JpwCXrNndlgXiSpqa5dkYALUn7M8mxsiBlhLp3z6ZeFvbwaSBdDBQst7M9X21Ko
4 | 0swPuaakLbx+85WgLgLJxYWh5KmSw8P22x6JPTZQ2Ss3B/QJVTnJey1GDwkar1uI
5 | 7mF1tGTapCwn3ximpm/Xq164pv7dMEt5T/MEHQIZY6/Slzt+9aNkhYwacoy285fe
6 | nI04IIYTltgT/mPtfL7ckcM4v6Jtitp6f9e7XOUwkbCD60/4Eb7E7EUl7xq62+ee
7 | wbAGr7LgMDPOhxsP9OK9TinE4VN8xMnewwIBAg==
8 | -----END DH PARAMETERS-----
9 |
--------------------------------------------------------------------------------
/docs/inspiration.md:
--------------------------------------------------------------------------------
1 | - https://github.com/bouzuya/tamaru/blob/master/src/Bouzuya/Halogen/StringRenderer.purs
2 | - https://github.com/bouzuya/fwt/blob/648b2e8b2bdf4e52718c108ba2e8c113c2faac4d/src/View.purs#L114
3 | - https://github.com/natefaubion/slamdata/blob/8d7534b0a8e9819b2719ca088c620cf098630c80/src/SlamData/Workspace/Card/Setups/Geo/Heatmap/Eval.purs#L158
4 | - https://github.com/nwolverson/purescript-weekchart/blob/fbc6223ff9f80ba6bc936c923b38ee1b11d53af3/src/Main.purs#L63
5 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Navigate.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Navigate where
2 |
3 | import Protolude
4 |
5 | import Control.Monad.Reader (asks)
6 |
7 | import NextjsApp.Route as NextjsApp.Route
8 |
9 | navigate ::
10 | forall r m routes.
11 | MonadEffect m =>
12 | MonadAsk { navigate :: Variant routes -> Effect Unit | r } m =>
13 | Variant routes ->
14 | m Unit
15 | navigate route = do
16 | navigate' <- asks _.navigate
17 | liftEffect $ navigate' route
18 |
--------------------------------------------------------------------------------
/migrations/0000000003-posts/01_posts/03_policies.up.sql:
--------------------------------------------------------------------------------
1 | alter table app_public.posts enable row level security;
2 |
3 | create policy select_posts on app_public.posts for select using (true);
4 | create policy update_posts on app_public.posts for update using (user_id = app_public.current_user_id_or_null());
5 | create policy delete_posts on app_public.posts for delete using (user_id = app_public.current_user_id_or_null());
6 |
7 | grant select on table app_public.posts to app_user;
8 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lifecycle/README.md:
--------------------------------------------------------------------------------
1 | # Lifecycles
2 |
3 | This example demonstrates component lifecycles.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-lifecycle
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/lifecycle/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/spago-api-server.dhall:
--------------------------------------------------------------------------------
1 | { name = "api-server"
2 | , dependencies = ./dependencies.dhall
3 | , packages = ./packages.dhall
4 | , sources =
5 | [ "./packages/src/**/*.purs"
6 | , "./packages/api-server/**/*.purs"
7 | , "./packages/api-server-exceptions/**/*.purs"
8 | , "./packages/api-server-config/**/*.purs"
9 | , "./packages/client/NextjsApp/AppM.purs"
10 | , "./packages/client/NextjsApp/Route.purs"
11 | , "./packages/client/NextjsApp/Link/Types.purs"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/03_current_user_id_required.up.sql:
--------------------------------------------------------------------------------
1 | create or replace function app_public.current_user_id_required() returns uuid as $function$
2 | select current_setting('jwt.claims.user_id', false)::uuid;
3 | $function$ LANGUAGE sql stable;
4 |
5 | comment on function app_public.current_user_id_required() is
6 | '@omit
7 | Get current user id or raise error that returns 403 status code';
8 |
9 | grant execute on function app_public.current_user_id_required() to public;
10 |
--------------------------------------------------------------------------------
/packages/src/Webpack/Plugins.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack")
2 |
3 | exports.webpack = {
4 | _DefinePlugin: function(opts) {
5 | return new webpack.DefinePlugin(opts)
6 | },
7 | _ProvidePlugin: function(opts) {
8 | return new webpack.ProvidePlugin(opts)
9 | },
10 | _NoEmitOnErrorsPlugin: new webpack.NoEmitOnErrorsPlugin(),
11 | optimize: {
12 | _LimitChunkCountPlugin: function(opts) { return new webpack.optimize.LimitChunkCountPlugin(opts) }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/spago-feature-tests.dhall:
--------------------------------------------------------------------------------
1 | { name = "feature-tests"
2 | , dependencies = ./dependencies.dhall
3 | , packages = ./packages.dhall
4 | , sources =
5 | [ "./packages/src/**/*.purs"
6 | , "./packages/feature-tests/**/*.purs"
7 | , "./packages/worker/**/*.purs"
8 | , "./packages/client/NextjsApp/AppM.purs"
9 | , "./packages/client/NextjsApp/Route.purs"
10 | , "./packages/client/NextjsApp/WebRouteDuplexCodec.purs"
11 | , "./packages/client/NextjsApp/Link/Types.purs"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/nix/pkgs/arion/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | # nix-prefetch-git https://github.com/hercules-ci/arion --rev cc9e70a2ccdacb435c835079b9d473683ac0639b > "$SCRIPT_DIR/revision.json"
6 | nix-prefetch-git https://github.com/hercules-ci/arion > "$SCRIPT_DIR/revision.json"
7 | # nix-prefetch-git https://github.com/srghma/arion --rev 108767c03231cfd9bde6c06df122f08563f77cb2 > "$SCRIPT_DIR/revision.json"
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.gcroots/
2 | /bower_components/
3 | /node_modules/
4 | /.pulp-cache/
5 | /output/
6 | /generated-docs/
7 | /.psc*
8 | /.purs*
9 | /.psa*
10 | /.spago
11 | /examples/dist/
12 | /yarn-error.log
13 | .dist/
14 | .dist-dev/
15 | /plugins/cordova-plugin-webpack/
16 | /plugins/cordova-plugin-whitelist/
17 | /platforms/android/
18 | /core
19 | /www/
20 | /package-lock.json
21 | /config/ignored/*
22 | !/config/ignored/*.example
23 | !/config/ignored/*.setup.sh
24 | .tmp-arion-*.yaml
25 | /.feature-tests
26 |
--------------------------------------------------------------------------------
/packages/src/SpecAssertsExtra.purs:
--------------------------------------------------------------------------------
1 | module SpecAssertsExtra where
2 |
3 | import Control.Monad.Error.Class
4 | import Effect.Exception
5 | import Data.String (Pattern(..), contains)
6 | import Prelude
7 | import Test.Spec.Assertions (fail, shouldContain, shouldEqual)
8 |
9 | shouldContainString
10 | :: forall m f
11 | . MonadThrow Error m
12 | => String
13 | -> Pattern
14 | -> m Unit
15 | shouldContainString e c =
16 | unless (contains c e) $
17 | fail $ (show c) <> " ∉ " <> (show e)
18 |
19 |
--------------------------------------------------------------------------------
/nix/pkgs/ntmuxp/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 |
3 | let
4 | terraform = pkgs.terraform.withPlugins (p: with p; [ aws tls local ]);
5 |
6 | revData = builtins.fromJSON (builtins.readFile ./revision.json);
7 |
8 | src = builtins.fetchTarball {
9 | inherit (revData) sha256;
10 | url = "${revData.url}/archive/${revData.rev}.tar.gz";
11 | };
12 |
13 | # src = ~/projects/ntmuxp;
14 | in
15 | # pkgs.callPackage "${src}/default.nix" { inherit pkgs; }
16 | pkgs.callPackage "${src}/default.nix" { }
17 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/random_enum.sql:
--------------------------------------------------------------------------------
1 |
2 | begin;
3 |
4 | -- call as random_enum(null::app_public.leed_rating_enum)
5 | create or replace function random_enum(relation_name anyelement, out result anyenum)
6 | returns anyenum as $func$
7 | begin
8 | execute format(
9 | $sql$
10 | select unnest(enum_range(null::%1$I))
11 | order by random()
12 | limit 1;
13 | $sql$,
14 | pg_typeof(relation_name)
15 | ) into result;
16 | return;
17 | end;
18 | $func$ language plpgsql;
19 |
20 | commit;
21 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/README.md:
--------------------------------------------------------------------------------
1 | # DeeplyNested
2 |
3 | the structure is the following
4 |
5 | A
6 | B
7 | D
8 | F
9 | E
10 | C
11 |
12 |
13 | ## Building
14 |
15 | You can build this example from the root of the Halogen project:
16 |
17 | ```sh
18 | npm install
19 | npm run example-nested
20 | ```
21 |
22 | This will bundle a runnable JS file, `example.js`, in the `examples/nested/dist` directory. You can view the running application by opening the corresponding `index.html` file.
23 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Router/Server.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Router.Server where
2 |
3 | import Protolude
4 | import Halogen as H
5 | import NextjsApp.AppM (AppM)
6 | import NextjsApp.Router.Shared (CurrentPageInfo, Query, maybeRenderPage)
7 |
8 | serverComponent ::
9 | forall r.
10 | H.Component Query { currentPageInfo :: Maybe CurrentPageInfo | r } Void AppM
11 | serverComponent =
12 | H.mkComponent
13 | { initialState: identity
14 | , render: maybeRenderPage
15 | , eval: H.mkEval $ H.defaultEval
16 | }
17 |
--------------------------------------------------------------------------------
/packages/src/Favicons.js:
--------------------------------------------------------------------------------
1 | const favicons = require('favicons')
2 |
3 | exports._favicons = function(buffer) {
4 | return function(config) {
5 | return function (onError, onSuccess) {
6 | favicons(buffer, config, function (err, res) {
7 | if (err) {
8 | onError(err)
9 | } else {
10 | onSuccess(res)
11 | }
12 | })
13 |
14 | return function (cancelError, onCancelerError, onCancelerSuccess) {
15 | onCancelerSuccess();
16 | };
17 | };
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/nix/pkgs/dump-schema/default.nix:
--------------------------------------------------------------------------------
1 | { stdenv, lib, makeWrapper, postgresql, coreutils }:
2 |
3 | stdenv.mkDerivation rec {
4 | name = "dump-schema";
5 |
6 | nativeBuildInputs = [ makeWrapper ];
7 |
8 | phases = [ "installPhase" ];
9 |
10 | installPhase = ''
11 | mkdir -p $out/bin
12 |
13 | cp ${./dump-schema} $out/dump-schema
14 |
15 | patchShebangs $out/dump-schema
16 |
17 | makeWrapper $out/dump-schema $out/bin/${name} \
18 | --prefix PATH : ${lib.makeBinPath [ postgresql coreutils ]}
19 | '';
20 | }
21 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-aff-ajax/README.md:
--------------------------------------------------------------------------------
1 | # `Aff` and AJAX
2 |
3 | This example demonstrates how to make an AJAX request in a component `eval` function.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-effects-aff-ajax
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/effects-aff-ajax/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/packages/api-server/ApiServer/PostgraphilePassportAuthPlugin/Shared.purs:
--------------------------------------------------------------------------------
1 | module ApiServer.PostgraphilePassportAuthPlugin.Shared where
2 |
3 | import ApiServer.PostgraphilePassportAuthPlugin.Types
4 |
5 | import Protolude
6 | import Effect.Uncurried
7 | import Data.Function.Uncurried
8 |
9 | foreign import appPublicUsersFragment :: FragmentMaker -> SqlFragment
10 |
11 | foreign import mkSelectGraphQLResultFromTable ::
12 | Fn2
13 | String
14 | { fragment :: FragmentMaker, value :: SqlValueFn }
15 | (EffectFn2 String QueryBuilder Unit)
16 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/select/app_user.sql:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_user'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 |
5 | begin;
6 |
7 | select no_plan();
8 |
9 | insert into app_public.users
10 | (id, email, first_name, last_name)
11 | values
12 | (:user_id, random_email(), random_string(), random_string());
13 |
14 | set local role :role;
15 | select is(current_user, :role);
16 |
17 | select is_empty(
18 | 'select id from app_public.users'
19 | );
20 |
21 | select finish();
22 |
23 | rollback;
24 |
--------------------------------------------------------------------------------
/packages/src/Webpack/GetError.purs:
--------------------------------------------------------------------------------
1 | module Webpack.GetError where
2 |
3 | import Protolude
4 | import Data.Array as Array
5 | import Data.Array.NonEmpty (NonEmptyArray)
6 | import Data.Array.NonEmpty as NonEmptyArray
7 | import Webpack.Compiler (MultiStats)
8 |
9 | webpackGetErrors :: Maybe Error -> MultiStats -> Maybe (NonEmptyArray Error)
10 | webpackGetErrors = \error stats -> case error of
11 | Just e -> Just $ NonEmptyArray.singleton e
12 | Nothing -> Array.findMap (\stat -> NonEmptyArray.fromArray stat.compilation.errors) stats.stats
13 |
--------------------------------------------------------------------------------
/packages/src/Webpack/Plugins.purs:
--------------------------------------------------------------------------------
1 | module Webpack.Plugins where
2 |
3 | import Foreign (Foreign)
4 | import Foreign.Object (Object)
5 | import Webpack.Types (WebpackPluginInstance)
6 |
7 | foreign import webpack ::
8 | { _DefinePlugin :: Object Foreign -> WebpackPluginInstance
9 | , _ProvidePlugin :: forall options. { | options } -> WebpackPluginInstance
10 | , _NoEmitOnErrorsPlugin :: WebpackPluginInstance
11 | , optimize ::
12 | { _LimitChunkCountPlugin :: forall options. { | options } -> WebpackPluginInstance
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lazy/src/LazyLoaded.purs:
--------------------------------------------------------------------------------
1 | module Example.Lazy.LazyLoaded (component) where
2 |
3 | import Protolude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 |
8 | component :: forall q i o m. H.Component q i o m
9 | component =
10 | H.mkComponent
11 | { initialState: const unit
12 | , render
13 | , eval: H.mkEval H.defaultEval
14 | }
15 |
16 | render :: forall m query. Unit -> H.ComponentHTML query () m
17 | render _ =
18 | HH.div_
19 | [ HH.text "I'm lazy loaded child (LOADED)"
20 | ]
21 |
--------------------------------------------------------------------------------
/packages/feature-tests/FeatureTests/FeatureTestSpecUtils/EmailAVar.purs:
--------------------------------------------------------------------------------
1 | module FeatureTests.FeatureTestSpecUtils.EmailAVar where
2 |
3 | import Protolude
4 |
5 | import Control.Monad.Reader.Class (asks)
6 | import Effect.AVar (AVar)
7 | import Effect.Aff.AVar as AVar
8 | import Worker.Main as Worker
9 | import Worker.Types as Worker
10 |
11 | waitForEmail
12 | :: forall m r
13 | . MonadAsk { emailAVar :: AVar Worker.Email | r } m
14 | => MonadAff m
15 | => m Worker.Email
16 | waitForEmail = asks _.emailAVar >>= liftAff <<< AVar.take
17 |
18 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/effects-effect-random/README.md:
--------------------------------------------------------------------------------
1 | # `Effect` and Random
2 |
3 | This example demonstrates how to use an `Effect` function in a component `eval` function.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-effects-effect-random
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/effects-effect-random/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | // require('postcss-import'),
4 | // require('postcss-preset-env'),
5 | // require('cssnano')({ preset: 'default' }),
6 | // ...(
7 | // production ?
8 | // {
9 | // '@fullhuman/postcss-purgecss': {
10 | // content: ['./client/**/*.js'],
11 | // defaultExtractor: (content) => content.match(/[\w-/:]+(? Array Rule
18 |
--------------------------------------------------------------------------------
/docker/common/pgadmin.nix:
--------------------------------------------------------------------------------
1 | {}:
2 |
3 | # -- user - pgadmin4@pgadmin.org
4 | # -- user pass - admin
5 | # -- hostname - postgres (yes, pgadmin4 client reaches postgres through pgadmin4 server, you dont need to expose $POSTGRES_PORT port)
6 | # -- username - $POSTGRES_USER
7 | # -- password - $POSTGRES_PASSWORD
8 |
9 | {
10 | image = "dpage/pgadmin4:latest";
11 | ports = [
12 | "5050:80"
13 | ];
14 | depends_on = [
15 | "postgres"
16 | ];
17 |
18 | environment = {
19 | PGADMIN_DEFAULT_EMAIL = "foo";
20 | PGADMIN_DEFAULT_PASSWORD = "foo";
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/ace/README.md:
--------------------------------------------------------------------------------
1 | # Ace Editor
2 |
3 | This example demonstrates integrating a third-party component. It uses queries to control behavior in Ace editor and output messages to observe changes within the editor.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-ace
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/ace/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components-multitype/README.md:
--------------------------------------------------------------------------------
1 | # Component With Multiple Child Component Types
2 |
3 | This example demonstrates a component which has child components of differing types.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-components-multitype
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/components-multitype/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/packages/src/Webpack/FFI.js:
--------------------------------------------------------------------------------
1 | exports.webpackEntrypontName = function(entrypoint) { return entrypoint.name }
2 |
3 | exports.webpackEntrypontGetFiles = function(entrypoint) { return entrypoint.getFiles() }
4 |
5 | exports._rawSource = function(string) {
6 | return new (require('webpack-sources').RawSource)(string)
7 | }
8 |
9 | exports.setAsset = function(assets, name, rawSource) { assets[name] = rawSource }
10 |
11 | exports.compilationGetEntrypoints = function(compilation) {
12 | // console.log('compilation', compilation.entrypoints)
13 | return compilation.entrypoints
14 | }
15 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components/README.md:
--------------------------------------------------------------------------------
1 | # Components
2 |
3 | This example demonstrates a button component embedded in a parent component. The parent component can send queries to and receive output messages from the button.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-components
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/components/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/keyboard-input/README.md:
--------------------------------------------------------------------------------
1 | # Keyboard Input (Event Sources)
2 |
3 | This example demonstrates how to selectively capture keyboard events and, more generally, how to use `EventSource`s in Halogen.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-keyboard-input
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/keyboard-input/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/dev-commands/all-commands.nix:
--------------------------------------------------------------------------------
1 | { pkgs }:
2 |
3 | let
4 |
5 | config = rec {
6 | # type Name = String
7 | # type Code = String
8 | # Map Name Code -> List Pkg
9 | mkScripts = attrsetOfNamesAndCode: pkgs.lib.attrValues (pkgs.lib.mapAttrs (name: code: pkgs.writeShellScriptBin name code) attrsetOfNamesAndCode);
10 |
11 | mkCommand = environment: content: ''
12 | set -eux
13 |
14 | ${pkgs.mylib.exportEnvsCommand environment}
15 |
16 | ${content}
17 | '';
18 | };
19 |
20 | in
21 |
22 | builtins.concatLists [
23 | (import ./dev/default.nix { inherit pkgs config; })
24 | ]
25 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailWeb/Types.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.PageImplementations.VerifyUserEmailWeb.Types where
2 |
3 | import Protolude
4 |
5 | import Halogen as H
6 |
7 | type Query
8 | = Const Void
9 |
10 | type Input
11 | = Unit
12 |
13 | type Message
14 | = Void
15 |
16 | data Action
17 | = Action__Initialize
18 |
19 | type ChildSlots = ()
20 |
21 | data VerifyUserEmailError
22 | = VerifyUserEmailError__TokenExpired
23 | | VerifyUserEmailError__Unknown String
24 |
25 | type State =
26 | { loginError :: Maybe VerifyUserEmailError
27 | }
28 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/02_current_user_id_or_null.up.sql:
--------------------------------------------------------------------------------
1 | -- TODO: should be in app_hidden?
2 |
3 | create or replace function app_public.current_user_id_or_null() returns uuid as $function$
4 | select nullif(current_setting('jwt.claims.user_id', true), '')::uuid;
5 | $function$ LANGUAGE sql stable;
6 |
7 | comment on function app_public.current_user_id_or_null() is
8 | '@omit
9 | Handy method to get the current user ID for use in RLS policies, etc; in GraphQL, use `query { currentUser { id } }` instead.';
10 |
11 | grant execute on function app_public.current_user_id_or_null() to public;
12 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/VerifyUserEmailMobile/Types.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.PageImplementations.VerifyUserEmailMobile.Types where
2 |
3 | import Protolude
4 |
5 | import Halogen as H
6 |
7 | type Query
8 | = Const Void
9 |
10 | type Input
11 | = Unit
12 |
13 | type Message
14 | = Void
15 |
16 | data Action
17 | = Action__Initialize
18 |
19 | type ChildSlots = ()
20 |
21 | data VerifyUserEmailError
22 | = VerifyUserEmailError__TokenExpired
23 | | VerifyUserEmailError__Unknown String
24 |
25 | type State =
26 | { loginError :: Maybe VerifyUserEmailError
27 | }
28 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/roles/app_anonymous.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_anonymous'$$
2 |
3 | begin;
4 |
5 | select no_plan();
6 |
7 | select database_privs_are(
8 | current_database(),
9 | :role,
10 | array['CONNECT', 'TEMPORARY']::text[]
11 | );
12 |
13 | select schema_privs_are(
14 | 'public',
15 | :role,
16 | array['USAGE', 'CREATE']::text[]
17 | );
18 |
19 | select schema_privs_are(
20 | 'app_public',
21 | :role,
22 | array['USAGE']::text[]
23 | );
24 |
25 | select schema_privs_are(
26 | 'app_private',
27 | :role,
28 | array[]::text[]
29 | );
30 |
31 | select finish();
32 |
33 | rollback;
34 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lazy/src/LazyLoadedImport.purs:
--------------------------------------------------------------------------------
1 | module Example.Lazy.LazyLoadedImport where
2 |
3 | import Protolude
4 |
5 | import Control.Promise (Promise)
6 | import Control.Promise as Promise
7 | import Data.Time.Duration (Milliseconds(..))
8 | import Effect.Aff (delay)
9 | import Halogen as H
10 |
11 | foreign import lazyLoadedImport_ :: forall q i o m . Effect (Promise { component :: H.Component q i o m })
12 |
13 | lazyLoadedImport :: forall q i o m . Aff (H.Component q i o m)
14 | lazyLoadedImport = do
15 | delay (Milliseconds 3000.0)
16 | Promise.toAffE lazyLoadedImport_ <#> _.component
17 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/roles/app_user.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_user'$$
2 |
3 | begin;
4 |
5 | select no_plan();
6 |
7 | select database_privs_are(
8 | current_database(),
9 | :role,
10 | array['CONNECT', 'TEMPORARY']::text[]
11 | );
12 |
13 | -- TODO: should create?
14 | select schema_privs_are(
15 | 'public',
16 | :role,
17 | array['USAGE', 'CREATE']
18 | );
19 |
20 | select schema_privs_are(
21 | 'app_public',
22 | :role,
23 | array['USAGE']
24 | );
25 |
26 | select schema_privs_are(
27 | 'app_private',
28 | :role,
29 | array[]::text[]
30 | );
31 |
32 | select finish();
33 |
34 | rollback;
35 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/05_generate_url_safe_token.up.sql:
--------------------------------------------------------------------------------
1 | -- From https://stackoverflow.com/a/1374794/3574379
2 | -- base64 strings can contains the "+", "=" and "/" which are unsafe
3 | -- remove these characters
4 |
5 | create or replace function app_public.generate_url_safe_token() returns text as $function$
6 | select translate(
7 | encode(gen_random_bytes(8), 'base64'),
8 | '+/=',
9 | ''
10 | )
11 | $function$ LANGUAGE sql stable;
12 |
13 | comment on function app_public.generate_url_safe_token() is
14 | '@omit';
15 |
16 | grant execute on function app_public.generate_url_safe_token() to public;
17 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/C.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.C (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 |
8 | type State = Unit
9 |
10 | data Action = Void
11 |
12 | type ChildSlots = ()
13 |
14 | component :: forall q i o m. H.Component q i o m
15 | component =
16 | H.mkComponent
17 | { initialState: const unit
18 | , render
19 | , eval: H.mkEval H.defaultEval
20 | }
21 |
22 | render :: forall m. State -> H.ComponentHTML Action ChildSlots m
23 | render state =
24 | HH.ul_
25 | [ HH.li_ [ HH.text "c" ]
26 | ]
27 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/E.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.E (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 |
8 | type State = Unit
9 |
10 | data Action = Void
11 |
12 | type ChildSlots = ()
13 |
14 | component :: forall q i o m. H.Component q i o m
15 | component =
16 | H.mkComponent
17 | { initialState: const unit
18 | , render
19 | , eval: H.mkEval H.defaultEval
20 | }
21 |
22 | render :: forall m. State -> H.ComponentHTML Action ChildSlots m
23 | render state =
24 | HH.ul_
25 | [ HH.li_ [ HH.text "e" ]
26 | ]
27 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/F.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.F (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 |
8 | type State = Unit
9 |
10 | data Action = Void
11 |
12 | type ChildSlots = ()
13 |
14 | component :: forall q i o m. H.Component q i o m
15 | component =
16 | H.mkComponent
17 | { initialState: const unit
18 | , render
19 | , eval: H.mkEval H.defaultEval
20 | }
21 |
22 | render :: forall m. State -> H.ComponentHTML Action ChildSlots m
23 | render state =
24 | HH.ul_
25 | [ HH.li_ [ HH.text "f" ]
26 | ]
27 |
--------------------------------------------------------------------------------
/migrations/0000000001-start.sql:
--------------------------------------------------------------------------------
1 | -- generated by ./gen-migrations.hs
2 |
3 | -- ==== UP ====
4 |
5 | begin;
6 |
7 | \include 0000000001-start/01_prelude.up.sql
8 | \include 0000000001-start/02_current_user_id_or_null.up.sql
9 | \include 0000000001-start/03_current_user_id_required.up.sql
10 | \include 0000000001-start/04_tg__set_updated_at.up.sql
11 | \include 0000000001-start/05_generate_url_safe_token.up.sql
12 | \include 0000000001-start/06_is_between_0_and_100.up.sql
13 | \include 0000000001-start/07_implication.up.sql
14 |
15 |
16 | commit;
17 |
18 | -- ==== DOWN ====
19 |
20 | -- do nothing, this should never happen
21 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/select/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_owner'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 |
5 | begin;
6 |
7 | select no_plan();
8 |
9 | insert into app_public.users
10 | (id, email, first_name, last_name)
11 | values
12 | (:user_id, random_email(), random_string(), random_string());
13 |
14 | set local role :role;
15 | select is(current_user, :role);
16 |
17 | prepare expected as values
18 | (:user_id :: uuid);
19 |
20 | select set_eq(
21 | 'select id from app_public.users',
22 | 'expected'
23 | );
24 |
25 | select finish();
26 |
27 | rollback;
28 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/confirm/priviliges.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set func $$'confirm'$$
4 | \set args $$'{"text"}'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_owner',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_user',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_owner',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/queries/current_user/priviliges.sql:
--------------------------------------------------------------------------------
1 | \set schema $$'app_public'$$
2 | \set func $$'current_user'$$
3 | \set args $$'{}'$$::text[]
4 |
5 | begin;
6 |
7 | select no_plan();
8 |
9 | SELECT function_privs_are(
10 | :schema,
11 | :func,
12 | :args,
13 | 'app_owner',
14 | '{"EXECUTE"}'
15 | );
16 |
17 | SELECT function_privs_are(
18 | :schema,
19 | :func,
20 | :args,
21 | 'app_user',
22 | '{"EXECUTE"}'
23 | );
24 |
25 | SELECT function_privs_are(
26 | :schema,
27 | :func,
28 | :args,
29 | 'app_anonymous',
30 | '{"EXECUTE"}'
31 | );
32 |
33 | select finish();
34 |
35 | rollback;
36 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/basic/README.md:
--------------------------------------------------------------------------------
1 | # Basic
2 |
3 | This example demonstrates close to the smallest Halogen component you can build. It's unlikely you'd make components this small in a real world application, but this lets you see the essential parts of a component definition.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-basic
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/basic/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/packages/db-tests/extensions/randomly_set_empty_jwt_user_id.sql_:
--------------------------------------------------------------------------------
1 | create or replace function randomly_set_empty_jwt_user_id() returns void as $function$
2 | declare
3 | /* rand integer := random_between(0, 3); */
4 | rand integer := 1;
5 | begin
6 | case
7 | when rand = 0 then
8 | null;
9 | when rand = 1 then
10 | set local jwt.claims.user_id to default;
11 | when rand = 2 then
12 | set local jwt.claims.user_id to '';
13 | when rand = 3 then
14 | set local jwt.claims.user_id to random_string();
15 | end case;
16 | end;
17 | $function$ LANGUAGE plpgsql;
18 |
19 | select randomly_set_empty_jwt_user_id();
20 |
--------------------------------------------------------------------------------
/packages/feature-tests/FeatureTests/FeatureTestSpecUtils/LunaparkUtils.purs:
--------------------------------------------------------------------------------
1 | module FeatureTests.FeatureTestSpecUtils.LunaparkUtils where
2 |
3 | import Protolude
4 | import FeatureTests.FeatureTestSpecUtils.AffRetry
5 | import FeatureTests.FeatureTestSpecUtils.Lunapark (runLunapark)
6 | import Lunapark as Lunapark
7 | import Test.Spec.Assertions (shouldEqual)
8 |
9 | waitForInputValueToEqual location expected =
10 | retryAction $
11 | ( ( runLunapark $
12 | Lunapark.findElement location
13 | >>= \e -> Lunapark.getAttribute e "value"
14 | )
15 | >>= \text -> text `shouldEqual` expected
16 | )
17 |
18 |
--------------------------------------------------------------------------------
/docker/common/db_tests.nix:
--------------------------------------------------------------------------------
1 | { pkgs, rootProjectDir }:
2 | {
3 | useHostStore = true;
4 |
5 | volumes = [
6 | "${rootProjectDir}/db_tests:/db_tests:ro"
7 | "/tmp" # for shmig
8 | ];
9 |
10 | working_dir = "/db_tests/tests";
11 |
12 | environment = rec {
13 | POSTGRES_USER = "app_admin";
14 | POSTGRES_PASSWORD = "app_admin_pass";
15 | PGPASSWORD = POSTGRES_PASSWORD; # for db-tests-prepare (for psql)
16 | POSTGRES_HOST = "postgres";
17 | POSTGRES_PORT = 5432;
18 | POSTGRES_DB = "nextjsdemo_test";
19 | };
20 |
21 | depends_on = [
22 | "postgres"
23 | ];
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components-inputs/README.md:
--------------------------------------------------------------------------------
1 | # Components With Input
2 |
3 | This example demonstrates a component which receives input from a parent component. When the parent re-renders the child component will receive a new input value and update accordingly.
4 |
5 | ## Building
6 |
7 | You can build this example from the root of the Halogen project:
8 |
9 | ```sh
10 | npm install
11 | npm run example-components-inputs
12 | ```
13 |
14 | This will bundle a runnable JS file, `example.js`, in the `examples/components-inputs/dist` directory. You can view the running application by opening the corresponding `index.html` file.
15 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/roles/app_admin.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_admin'$$
2 |
3 | begin;
4 |
5 | select no_plan();
6 |
7 | select database_privs_are(
8 | current_database(),
9 | :role,
10 | array['CONNECT', 'TEMPORARY', 'CREATE']
11 | );
12 |
13 | -- TODO: should create?
14 | select schema_privs_are(
15 | 'public',
16 | :role,
17 | array['USAGE', 'CREATE']
18 | );
19 |
20 | select schema_privs_are(
21 | 'app_public',
22 | :role,
23 | array['USAGE', 'CREATE']
24 | );
25 |
26 | select schema_privs_are(
27 | 'app_private',
28 | :role,
29 | array['USAGE', 'CREATE']
30 | );
31 |
32 | select finish();
33 |
34 | rollback;
35 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/roles/app_owner.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_owner'$$
2 |
3 | begin;
4 |
5 | select no_plan();
6 |
7 | select database_privs_are(
8 | current_database(),
9 | :role,
10 | array['CONNECT', 'TEMPORARY', 'CREATE']
11 | );
12 |
13 | -- TODO: should create?
14 | select schema_privs_are(
15 | 'public',
16 | :role,
17 | array['USAGE', 'CREATE']
18 | );
19 |
20 | select schema_privs_are(
21 | 'app_public',
22 | :role,
23 | array['USAGE', 'CREATE']
24 | );
25 |
26 | select schema_privs_are(
27 | 'app_private',
28 | :role,
29 | array['USAGE', 'CREATE']
30 | );
31 |
32 | select finish();
33 |
34 | rollback;
35 |
--------------------------------------------------------------------------------
/packages/src/ContribWebpackPlugins.purs:
--------------------------------------------------------------------------------
1 | module ContribWebpackPlugins where
2 |
3 | import Webpack.Types (WebpackPluginInstance)
4 |
5 | foreign import _MiniCssExtractPlugin :: forall options. { | options } -> WebpackPluginInstance
6 |
7 | foreign import _CleanWebpackPlugin :: WebpackPluginInstance
8 |
9 | foreign import _BundleAnalyzerPlugin :: forall options. { | options } -> WebpackPluginInstance
10 |
11 | foreign import _HtmlWebpackPlugin :: forall options. { | options } -> WebpackPluginInstance
12 |
13 | data HtmlWebpackPlugin__Tags
14 |
15 | foreign import htmlWebpackPlugin__tags__toString :: HtmlWebpackPlugin__Tags -> Array String
16 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/reset_password/priviliges.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set func $$'reset_password'$$
4 | \set args $$'{"text","text"}'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_owner',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_user',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_owner',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/packages/src/SimpleLookupEnv.purs:
--------------------------------------------------------------------------------
1 | module SimpleLookupEnv where
2 |
3 | import Prelude
4 | import Data.Maybe (maybe)
5 | import Data.Int as Data.Int
6 | import Effect.Exception (throw)
7 | import Node.Process (lookupEnv)
8 | import Effect (Effect)
9 |
10 | lookupEnvValue :: String -> Effect String
11 | lookupEnvValue name = lookupEnv name >>= maybe (throw $ "Missing environment variable " <> name) pure
12 |
13 | lookupEnvValueInt :: String -> Effect Int
14 | lookupEnvValueInt name = lookupEnvValue name >>= (\string -> (pure $ Data.Int.fromString string) >>= maybe (throw $ "Invalid " <> name <> ": expected valid integer but got " <> string) pure)
15 |
--------------------------------------------------------------------------------
/migrations/0000000002-users/16_app_private.tables.user_sessions.up.sql:
--------------------------------------------------------------------------------
1 | -- from https://github.com/voxpelli/node-connect-pg-simple/blob/master/table.sql
2 |
3 | -- based on guide from https://www.npmjs.com/package/express-pg-session
4 |
5 | CREATE TABLE app_private.user_sessions (
6 | "sid" varchar NOT NULL COLLATE "default",
7 | "sess" json NOT NULL,
8 | "expire" timestamp(6) NOT NULL
9 | )
10 | WITH (OIDS=FALSE);
11 |
12 | ALTER TABLE app_private.user_sessions ADD CONSTRAINT "app_private_user_sessions_pkey" PRIMARY KEY ("sid") NOT DEFERRABLE INITIALLY IMMEDIATE;
13 |
14 | CREATE INDEX "IDX_session_expire" ON app_private.user_sessions ("expire");
15 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/register/priviliges.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set func $$'register'$$
4 | \set args $$'{"text", "text", "text", "text"}'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_owner',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_user',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_owner',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/resend_confirmation/priviliges.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set func $$'resend_confirmation'$$
4 | \set args $$'{"text"}'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_owner',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_user',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_owner',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/send_reset_password/priviliges.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set func $$'send_reset_password'$$
4 | \set args $$'{"text"}'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_owner',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_user',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_owner',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/nix/nixpkgs/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix curl jq
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 |
6 | owner="nixos"
7 | repo="nixpkgs-channels"
8 | rev="nixos-unstable"
9 |
10 | full_rev=$(curl --silent https://api.github.com/repos/$owner/$repo/git/refs/heads/$rev | jq -r .object.sha)
11 |
12 | echo "full_rev=$full_rev"
13 |
14 | expected_sha=$(nix-prefetch-url https://github.com/$owner/$repo/archive/$full_rev.tar.gz)
15 |
16 | cat >"$SCRIPT_DIR/revision.json" <
SelectionSet
13 | Scope__WebLoginPayload
14 | r
15 | user = selectionForCompositeField
16 | "user"
17 | []
18 | graphqlDefaultResponseFunctorOrScalarDecoderTransformer
19 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/queries/user_by_username_or_verified_email/priviliges.sql:
--------------------------------------------------------------------------------
1 | \set schema $$'app_public'$$
2 | \set func $$'user_by_username_or_verified_email'$$
3 | \set args $$'{text}'$$::text[]
4 |
5 | begin;
6 |
7 | select no_plan();
8 |
9 | SELECT function_privs_are(
10 | :schema,
11 | :func,
12 | :args,
13 | 'app_owner',
14 | '{"EXECUTE"}'
15 | );
16 |
17 | SELECT function_privs_are(
18 | :schema,
19 | :func,
20 | :args,
21 | 'app_user',
22 | '{"EXECUTE"}'
23 | );
24 |
25 | SELECT function_privs_are(
26 | :schema,
27 | :func,
28 | :args,
29 | 'app_anonymous',
30 | '{"EXECUTE"}'
31 | );
32 |
33 | select finish();
34 |
35 | rollback;
36 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Object/WebRegisterPayload.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Object.WebRegisterPayload where
2 |
3 | import GraphQLClient
4 | ( SelectionSet
5 | , selectionForCompositeField
6 | , graphqlDefaultResponseFunctorOrScalarDecoderTransformer
7 | )
8 | import NextjsGraphqlApi.Scopes (Scope__User, Scope__WebRegisterPayload)
9 |
10 | user :: forall r . SelectionSet
11 | Scope__User
12 | r -> SelectionSet
13 | Scope__WebRegisterPayload
14 | r
15 | user = selectionForCompositeField
16 | "user"
17 | []
18 | graphqlDefaultResponseFunctorOrScalarDecoderTransformer
19 |
--------------------------------------------------------------------------------
/packages/src/RunExtra.purs:
--------------------------------------------------------------------------------
1 | module RunExtra where
2 |
3 | import Protolude
4 |
5 | import Data.Array (uncons)
6 | import Effect.Aff (delay)
7 | import Prim.Row (class Cons) as Row
8 | import Run (Run, AFF)
9 | import Run as Run
10 | import Run.Except (EXCEPT)
11 | import Run.Except as Run
12 | import Unsafe.Coerce (unsafeCoerce)
13 |
14 | -- from https://github.com/purescript-webrow/webrow/blob/68144f421b6652b93bb9ceeb9ed69762286ae905/src/WebRow/PostgreSQL/PG.purs#L135
15 | --
16 | -- | Run.expand definition is based on `Union` constraint
17 | -- | We want to use Row.Cons here instead
18 | expand' ∷ ∀ l b t t_. Row.Cons l b t_ t ⇒ SProxy l → Run t_ ~> Run t
19 | expand' _ = unsafeCoerce
20 |
21 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Login/Css.module.scss:
--------------------------------------------------------------------------------
1 | .root {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 |
6 | max-width: 30%;
7 | min-width: 400px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | }
11 |
12 | .logo {
13 | max-width: 45%;
14 | min-width: 200px;
15 | margin-left: auto;
16 | margin-right: auto;
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | flex-direction: row;
22 | justify-content: flex-end;
23 | }
24 |
25 | .buttons__button {
26 | margin-left: 10px;
27 | }
28 |
29 | .input {
30 | display: flex;
31 | flex-direction: column;
32 | justify-content: center;
33 | padding-bottom: 10px;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Register/Css.module.scss:
--------------------------------------------------------------------------------
1 | .root {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 |
6 | max-width: 30%;
7 | min-width: 400px;
8 | margin-left: auto;
9 | margin-right: auto;
10 | }
11 |
12 | .logo {
13 | max-width: 45%;
14 | min-width: 200px;
15 | margin-left: auto;
16 | margin-right: auto;
17 | }
18 |
19 | .buttons {
20 | display: flex;
21 | flex-direction: row;
22 | justify-content: flex-end;
23 | }
24 |
25 | .buttons__button {
26 | margin-left: 10px;
27 | }
28 |
29 | .input {
30 | display: flex;
31 | flex-direction: column;
32 | justify-content: center;
33 | padding-bottom: 10px;
34 | }
35 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/login_or_register_oauth/priviliges.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_private'$$
3 | \set func $$'login_or_register_oauth'$$
4 | \set args $$'{ "text", "text", "text", "text", "text", "text" }'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_owner',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_user',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_owner',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/packages/feature-tests/FeatureTests/Tests/Login/ErrorNotConfirmedSpec.purs_:
--------------------------------------------------------------------------------
1 | module FeatureTests.Tests.Login.ErrorNotConfirmedSpec where
2 |
3 | import Prelude
4 | import Control.Monad.Error.Class
5 | import Control.Monad.Reader.Trans
6 | import Data.Maybe
7 | import Data.Identity
8 | import Data.Time.Duration
9 | import Effect
10 | import Effect.Aff
11 | import Effect.Class
12 | import Effect.Console
13 | import Effect.Exception
14 | import Selenium.Browser
15 | import Selenium.Builder
16 | import Selenium.Monad
17 | import Selenium.Types
18 | import Test.Spec
19 | import Unsafe.Coerce
20 | import BuildSeleniumChromeDriver
21 | import FeatureTest
22 |
23 | spec :: FeatureTestSpec Unit
24 | spec = pure unit
25 |
--------------------------------------------------------------------------------
/nix/pkgs/readRevision/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs }:
2 |
3 | with pkgs;
4 | with lib;
5 |
6 | # EXAMPLE:
7 | # update command example:
8 | # nix-prefetch-git https://github.com/srghma/dunsted-volume > $DOTFILES/nixos/root/prefetched-git-revisions/dunsted-volume.json
9 |
10 | # test match like `nix-instantiate --eval -E 'builtins.match "https?://.*/(.*)/(.*)" "https://github.com/srghma/dunsted-volume"'`
11 | path:
12 |
13 | let
14 | revData = builtins.fromJSON (builtins.readFile path);
15 | url = revData.url;
16 |
17 | m = builtins.match "https?://.*/(.*)/(.*)" url;
18 | owner = builtins.elemAt m 0;
19 | repo = builtins.elemAt m 1;
20 | in { inherit owner repo; inherit (revData) rev sha256; }
21 |
--------------------------------------------------------------------------------
/nix/pkgs/pg_prove/default.nix:
--------------------------------------------------------------------------------
1 | { stdenv, postgresql, perlPackages, makeWrapper, lib }:
2 |
3 | # pgql is required to be in $PATH (https://github.com/NixOS/nixpkgs/issues/55663)
4 | stdenv.mkDerivation rec {
5 | name = "pg_prove";
6 |
7 | nativeBuildInputs = [ makeWrapper ];
8 |
9 | phases = [ "installPhase" ];
10 |
11 | installPhase = ''
12 | mkdir -p $out/bin
13 |
14 | makeWrapper ${perlPackages.TAPParserSourceHandlerpgTAP}/bin/pg_prove $out/bin/pg_prove \
15 | --prefix PATH : ${lib.makeBinPath [ postgresql ]}
16 |
17 | makeWrapper ${perlPackages.TAPParserSourceHandlerpgTAP}/bin/pg_tapgen $out/bin/pg_tapgen \
18 | --prefix PATH : ${lib.makeBinPath [ postgresql ]}
19 | '';
20 | }
21 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/posts/priviligies/app_user.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$ :: name
3 | \set table $$'posts'$$ :: name
4 | \set role $$'app_user'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY['SELECT']::text[]
15 | );
16 |
17 | SELECT any_column_privs_are(
18 | :schema,
19 | :table,
20 | :role,
21 | ARRAY['SELECT']::text[]
22 | );
23 |
24 | SELECT column_privs_are(:schema, :table, col, :role, ARRAY['SELECT']::text[])
25 | FROM (
26 | VALUES('id'), ('name'), ('user_id'), ('content'), ('created_at'), ('updated_at')
27 | ) AS tableAlias (col);
28 |
29 |
30 | select finish();
31 |
32 | rollback;
33 |
--------------------------------------------------------------------------------
/regenerate-purs-files.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euxo pipefail
4 |
5 | ###################################
6 |
7 | generate-halogen-css-modules \
8 | -d ./packages/client
9 |
10 | ###################################
11 |
12 | # sd --flags c "^import ([\w\.]+) (\(.+\) )as ([\w\.]+)" 'import $1 as $3' $(fd --type f ".purs" ./)
13 |
14 | update-module-name-purs \
15 | -d ./packages/api-server \
16 | -d ./packages/api-server-exceptions \
17 | -d ./packages/api-server-config \
18 | -d ./packages/client \
19 | -d ./packages/client-tests \
20 | -d ./packages/client-webpack \
21 | -d ./packages/db-tests \
22 | -d ./packages/feature-tests \
23 | -d ./packages/src \
24 | -d ./packages/worker
25 |
--------------------------------------------------------------------------------
/docker/common/server.nix:
--------------------------------------------------------------------------------
1 | { pkgs, rootProjectDir, rootYarnModules }:
2 |
3 | {
4 | useHostStore = true;
5 |
6 | environment = rec {
7 | POSTGRES_USER = "app_admin";
8 | POSTGRES_PASSWORD = "app_admin_pass";
9 | POSTGRES_HOST = "postgres";
10 | POSTGRES_PORT = 5432;
11 | POSTGRES_DB = "nextjsdemo_test";
12 |
13 | PORT = 5000;
14 | HOST = "0.0.0.0";
15 | EXPOSED_SCHEMA = "app_public";
16 | NODE_ENV = "development";
17 | DATABASE_URL = "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${toString POSTGRES_PORT}/${POSTGRES_DB}";
18 | JWT_SECRET = "change_me";
19 | CORS_ALLOW_ORIGIN = "*";
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Navigate/Client.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Navigate.Client where
2 |
3 | import Protolude
4 |
5 | import Foreign as Foreign
6 |
7 | import NextjsApp.Route as NextjsApp.Route
8 | import NextjsApp.WebRouteDuplexCodec as NextjsApp.WebRouteDuplexCodec
9 | import Routing.Duplex as Routing.Duplex
10 | import Routing.PushState as Routing.PushState
11 |
12 | navigate :: Routing.PushState.PushStateInterface -> (Variant NextjsApp.Route.WebRoutesWithParamRow) -> Effect Unit
13 | navigate pushStateInterface route = do
14 | path <- Routing.Duplex.print NextjsApp.WebRouteDuplexCodec.routeCodec route
15 | # either (throwError <<< error <<< show) pure
16 | pushStateInterface.pushState (Foreign.unsafeToForeign unit) path
17 |
--------------------------------------------------------------------------------
/migrations/0000000002-users/01_app_private.tables.user_secrets.up.sql:
--------------------------------------------------------------------------------
1 | create table app_private.user_secrets (
2 | id uuid not null primary key default uuid_generate_v4(),
3 | password_hash text,
4 | reset_password_token text,
5 | reset_password_token_generated_at timestamptz,
6 | first_failed_reset_password_attempt timestamptz,
7 | first_failed_password_attempt timestamptz,
8 | reset_password_attempts int default 0 not null,
9 | password_attempts int4 default 0 not null
10 | );
11 |
12 | alter table app_private.user_secrets enable row level security;
13 |
14 | comment on table app_private.user_secrets is
15 | E'The contents of this table should never be visible to the user. Contains data mostly related to authentication.';
16 |
--------------------------------------------------------------------------------
/nix/pkgs/waitforit/default.nix:
--------------------------------------------------------------------------------
1 | { stdenv, fetchurl }:
2 |
3 | let
4 | revDataLinux = builtins.fromJSON (builtins.readFile ./revisionLinux.json);
5 | revDataDarwin = builtins.fromJSON (builtins.readFile ./revisionDarwin.json);
6 |
7 | revData = if stdenv.isLinux then revDataLinux else revDataDarwin;
8 |
9 | inherit (revData) url version sha256;
10 |
11 | program = fetchurl {
12 | inherit url sha256;
13 | };
14 | in
15 |
16 | stdenv.mkDerivation {
17 | name = "waitforit-${version}";
18 |
19 | unpackPhase = ":";
20 |
21 | installPhase = ''
22 | mkdir -p $out/bin
23 | cp ${program} $out/bin/waitforit
24 | chmod +x $out/bin/waitforit
25 | '';
26 |
27 | meta.platforms = stdenv.lib.platforms.all;
28 | }
29 |
--------------------------------------------------------------------------------
/packages/src/Chokidar.purs:
--------------------------------------------------------------------------------
1 | module Chokidar where
2 |
3 | import Effect.Uncurried (EffectFn1, mkEffectFn1, runEffectFn1)
4 | import Protolude
5 | import Data.Array.NonEmpty (NonEmptyArray)
6 | import FRP.Event (Event)
7 | import FRP.Event as Event
8 |
9 | -- | data ChokidarEvent
10 | foreign import _watch ::
11 | EffectFn1
12 | { files :: NonEmptyArray String
13 | -- | , options ::
14 | -- | { ignored :: String
15 | -- | , ignoreInitial :: Boolean
16 | -- | , cwd :: String
17 | -- | }
18 | , onAll :: EffectFn1 String Unit
19 | }
20 | (Effect Unit)
21 |
22 | watch :: NonEmptyArray String -> Event String
23 | watch files = Event.makeEvent \push -> runEffectFn1 _watch { files, onAll: mkEffectFn1 push }
24 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/NodeEnv.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.NodeEnv where
2 |
3 |
4 | type Env =
5 | { apiUrl :: String
6 | , isProduction :: Boolean
7 | }
8 |
9 | foreign import env :: Env
10 |
11 | -- | foreign import jwtKey :: String
12 |
13 | -- | oneDay = 60.0 {- sec -} * 60.0 {- min -} * 24.0 {- h -}
14 |
15 | -- | jwtMaxAgeInSeconds :: Number
16 | -- | jwtMaxAgeInSeconds = oneDay
17 |
18 | -- | jwtDomain :: Maybe String
19 | -- | jwtDomain =
20 | -- | if env.isProduction
21 | -- | then Just "todomydomain.com" -- TODO: server on `https://api.todomydomain.com/graphql`, client on `https://todomydomain.com/graphql`
22 | -- | else Nothing -- this is actually more restrictive, it allows only on the same ORIGIN (subdomain + domain)
23 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/schemas/app_hidden.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_hidden'$$
3 |
4 | begin;
5 |
6 | select no_plan();
7 |
8 | select tables_are(
9 | :schema,
10 | array['user_emails']::text[]
11 | );
12 |
13 | select types_are(:schema, array[]::text[]);
14 |
15 | select domains_are(:schema, array[]::text[]);
16 |
17 | select enums_are( :schema, array[]::text[]);
18 |
19 | select functions_are(
20 | :schema,
21 | array[
22 | 'biconditional_statement',
23 | 'implication',
24 | 'is_from_0_to_100'
25 | ]::text[]
26 | );
27 |
28 | select views_are(
29 | :schema,
30 | array[]::text[]
31 | );
32 |
33 | select materialized_views_are(
34 | :schema,
35 | array[]::text[]
36 | );
37 |
38 | select finish();
39 |
40 | rollback;
41 |
--------------------------------------------------------------------------------
/packages/src/Data/Email.purs:
--------------------------------------------------------------------------------
1 | module Data.Email where
2 |
3 | import Protolude
4 | import Unsafe.Coerce (unsafeCoerce)
5 | import Data.String.NonEmpty (NonEmptyString)
6 | import Data.String.NonEmpty as NonEmptyString
7 | import EmailValidator
8 |
9 | newtype Email = Email NonEmptyString
10 |
11 | toNonEmptyString :: Email -> NonEmptyString
12 | toNonEmptyString = unsafeCoerce
13 |
14 | toString :: Email -> String
15 | toString = unsafeCoerce
16 |
17 | fromNonEmptyString :: NonEmptyString -> Maybe Email
18 | fromNonEmptyString email =
19 | if emailValidate (NonEmptyString.toString email)
20 | then Just (Email email)
21 | else Nothing
22 |
23 | fromString :: String -> Maybe Email
24 | fromString = NonEmptyString.fromString >=> fromNonEmptyString
25 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/posts/priviligies/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$ :: name
3 | \set table $$'posts'$$ :: name
4 | \set role $$'app_owner'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY['SELECT', 'UPDATE', 'DELETE']::text[]
15 | );
16 |
17 | SELECT any_column_privs_are(
18 | :schema,
19 | :table,
20 | :role,
21 | ARRAY['SELECT', 'UPDATE']::text[]
22 | );
23 |
24 | SELECT column_privs_are(:schema, :table, col, :role, ARRAY['SELECT', 'UPDATE']::text[])
25 | FROM (
26 | VALUES('id'), ('name'), ('user_id'), ('content'), ('created_at'), ('updated_at')
27 | ) AS tableAlias(col);
28 |
29 |
30 | select finish();
31 |
32 | rollback;
33 |
--------------------------------------------------------------------------------
/packages/src/HalogenElementsExtra.purs:
--------------------------------------------------------------------------------
1 | module HalogenElementsExtra where
2 |
3 | import Halogen.HTML as Halogen.HTML
4 | import Halogen.HTML.Properties as Halogen.HTML.Properties
5 |
6 | content :: ∀ r i. String -> Halogen.HTML.IProp ( content :: String | r ) i
7 | content = Halogen.HTML.Properties.prop (Halogen.HTML.PropName "content")
8 |
9 | async :: ∀ r i. String -> Halogen.HTML.IProp ( id :: String | r ) i
10 | async = Halogen.HTML.prop (Halogen.HTML.PropName "async")
11 |
12 | media_ :: forall r i. String -> Halogen.HTML.IProp ( media :: String | r ) i
13 | media_ = Halogen.HTML.prop (Halogen.HTML.PropName "media")
14 |
15 | as_ :: forall r i. String -> Halogen.HTML.IProp ( as :: String | r ) i
16 | as_ = Halogen.HTML.prop (Halogen.HTML.PropName "as")
17 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/web_login/priviliges.sql:
--------------------------------------------------------------------------------
1 | \set schema $$'app_private'$$
2 | \set func $$'web_login'$$
3 | \set args $$'{"text", "text"}'$$::text[]
4 |
5 | begin;
6 |
7 | select no_plan();
8 |
9 | SELECT function_privs_are(
10 | :schema,
11 | :func,
12 | :args,
13 | 'app_admin',
14 | '{"EXECUTE"}'
15 | );
16 |
17 | SELECT function_privs_are(
18 | :schema,
19 | :func,
20 | :args,
21 | 'app_owner',
22 | '{"EXECUTE"}'
23 | );
24 |
25 | SELECT function_privs_are(
26 | :schema,
27 | :func,
28 | :args,
29 | 'app_user',
30 | '{"EXECUTE"}'
31 | );
32 |
33 | SELECT function_privs_are(
34 | :schema,
35 | :func,
36 | :args,
37 | 'app_anonymous',
38 | '{"EXECUTE"}'
39 | );
40 |
41 | select finish();
42 |
43 | rollback;
44 |
--------------------------------------------------------------------------------
/packages/src/HalogenVdomStringRendererRaw.purs:
--------------------------------------------------------------------------------
1 | module HalogenVdomStringRendererRaw where
2 |
3 | import Protolude
4 |
5 | import Halogen.HTML as Halogen.HTML
6 | import Halogen.HTML.Core as Halogen.HTML.Core
7 | import Halogen.VDom.DOM.StringRenderer as HalogenVdomStringRenderer.DOM
8 |
9 | newtype RawTextWidget = RawTextWidget String
10 |
11 | rawText :: ∀ i . String -> Halogen.HTML.HTML RawTextWidget i
12 | rawText string = Halogen.HTML.Core.widget (RawTextWidget string)
13 |
14 | renderHtmlWithRawTextSupport :: ∀ i . Halogen.HTML.HTML RawTextWidget i -> String
15 | renderHtmlWithRawTextSupport html = HalogenVdomStringRenderer.DOM.render renderWidget (unwrap html)
16 | where
17 | renderWidget (RawTextWidget string) = string
18 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Login.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Login (page) where
2 |
3 | import Protolude
4 | import NextjsApp.PageImplementations.Login as NextjsApp.PageImplementations.Login
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import NextjsApp.AppM (AppM(..))
7 | import NextjsApp.Route as NextjsApp.Route
8 |
9 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
10 | pageSpec =
11 | { pageData: PageData__Static unit
12 | , component: NextjsApp.PageImplementations.Login.component
13 | , title: "Login"
14 | }
15 |
16 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
17 | page = mkPageSpecBoxed pageSpec
18 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Register.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Register (page) where
2 |
3 | import Protolude
4 | import NextjsApp.PageImplementations.Register as NextjsApp.PageImplementations.Register
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import NextjsApp.AppM (AppM(..))
7 | import NextjsApp.Route as NextjsApp.Route
8 |
9 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
10 | pageSpec =
11 | { pageData: PageData__Static unit
12 | , component: NextjsApp.PageImplementations.Register.component
13 | , title: "Register"
14 | }
15 |
16 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
17 | page = mkPageSpecBoxed pageSpec
18 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Secret/Types.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.PageImplementations.Secret.Types where
2 |
3 | import Protolude
4 | import Data.Argonaut (class DecodeJson, class EncodeJson)
5 | import Data.Argonaut.Decode.Generic (genericDecodeJson)
6 | import Data.Argonaut.Encode.Generic (genericEncodeJson)
7 |
8 | newtype SecretPageUserData = SecretPageUserData
9 | { id :: String
10 | , name :: Maybe String
11 | , username :: String
12 | }
13 |
14 | derive instance genericSecretPageUserData :: Generic SecretPageUserData _
15 |
16 | instance encodeJsonSecretPageUserData :: EncodeJson SecretPageUserData where
17 | encodeJson = genericEncodeJson
18 |
19 | instance decodeJsonSecretPageUserData :: DecodeJson SecretPageUserData where
20 | decodeJson = genericDecodeJson
21 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Lazy.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.Lazy (page) where
2 |
3 | import Protolude
4 | import Example.Lazy.Main as Example.Lazy.Main
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.Lazy.Main.component
14 | , title: "Halogen Example - lazy"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Scopes.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Scopes where
2 |
3 | data Scope__DeleteUserAuthenticationPayload
4 |
5 | data Scope__DeleteUserPayload
6 |
7 | data Scope__ForgotPasswordPayload
8 |
9 | data Scope__ListenPayload
10 |
11 | data Scope__PageInfo
12 |
13 | data Scope__Post
14 |
15 | data Scope__PostsConnection
16 |
17 | data Scope__PostsEdge
18 |
19 | data Scope__ResetPasswordPayload
20 |
21 | data Scope__UpdateUserPayload
22 |
23 | data Scope__User
24 |
25 | data Scope__UserAuthentication
26 |
27 | data Scope__UserAuthenticationsEdge
28 |
29 | data Scope__UserEmail
30 |
31 | data Scope__UsersEdge
32 |
33 | data Scope__VerifyUserEmailPayload
34 |
35 | data Scope__WebLoginPayload
36 |
37 | data Scope__WebRegisterPayload
38 |
39 | data Scope__Node
40 |
--------------------------------------------------------------------------------
/packages/api-server/ApiServer/FrontendServerHttpProxy.purs_:
--------------------------------------------------------------------------------
1 | module ApiServer.FrontendServerHttpProxy where
2 |
3 | import Data.Function.Uncurried
4 | import Effect
5 | import Effect.Uncurried
6 | import Node.Express.App
7 | import Node.Express.Passport
8 | import Node.Express.Types
9 | import Protolude
10 |
11 | import Data.Argonaut (Json)
12 | import Data.Maybe (Maybe(..))
13 | import Data.Newtype (class Newtype)
14 | import Data.Nullable (Nullable)
15 | import Data.Nullable as Nullable
16 | import Effect.Aff (Aff, runAff_)
17 | import Effect.Exception (Error)
18 | import Node.HTTP (Server)
19 |
20 | foreign import _installFrontendServerProxy ::
21 | EffectFn3
22 | Server
23 | Application
24 | String
25 | Unit
26 |
27 | installFrontendServerProxy = runEffectFn3 _installFrontendServerProxy
28 |
--------------------------------------------------------------------------------
/packages/src/ContribWebpackPlugins.js:
--------------------------------------------------------------------------------
1 | exports._MiniCssExtractPlugin = function(opts) {
2 | const MiniCssExtractPlugin = require("mini-css-extract-plugin")
3 | return new MiniCssExtractPlugin(opts)
4 | }
5 |
6 | exports._CleanWebpackPlugin = new (require("clean-webpack-plugin").CleanWebpackPlugin)()
7 |
8 | exports._BundleAnalyzerPlugin = function (opts) { return new (require("webpack-bundle-analyzer").BundleAnalyzerPlugin)(opts) }
9 |
10 | exports._HtmlWebpackPlugin = function (opts) { new (require("html-webpack-plugin"))(opts) }
11 |
12 | exports.htmlWebpackPlugin__tags__toString = function (tags) {
13 | const r = tags.toString()
14 |
15 | console.log('htmlWebpackPlugin__tags__toString', r)
16 |
17 | if (!Array.isArray(r)) { throw new Error('not an array') }
18 |
19 | return r
20 | }
21 |
--------------------------------------------------------------------------------
/migrations/0000000003-posts/01_posts/01_table.up.sql:
--------------------------------------------------------------------------------
1 | create table app_public.posts (
2 | id uuid primary key default uuid_generate_v4(),
3 | name varchar(255) not null CHECK (name <> ''),
4 | content varchar(255) not null CHECK (name <> ''),
5 |
6 | user_id
7 | uuid
8 | not null
9 | references app_public.users(id)
10 | on delete cascade
11 | on update cascade,
12 |
13 | created_at timestamptz not null default now(),
14 | updated_at timestamptz not null default now()
15 | );
16 |
17 | create index app_public_posts_user_id on app_public.posts (user_id);
18 |
--------------------------------------------------------------------------------
/config/public/keys.nix:
--------------------------------------------------------------------------------
1 | rec {
2 | srghmaKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDGoNIxTQUeb8GbuBR87l133ozDBlPi+WbpYCfrSBD1s5MBxlulWiM38Np+1+uhcndjZEZaa5qjVWlWDicn2f8sAQzFJ024OjBAueJpH5ZhUkgTFh/kEXzV3Xbx7dL6MStxSlzTSLuXsWLHfX9NsFxwmyYihs2tQ7zqM8157zxr/J/MJ0OCVMUxHrmJICk1cRZyTv4I5sRxs+wRf3qpYIhRYXkR6kIW1A0f1/7VmYRAc+pI1GBkaQuI+0anvPvv7SWcW/l9piw0DAxkG85GLie9qP6Ag8Rj/zp0ri3Pu1jFO7uCC5l6DTa8vEgsPrTH5mQEdSrXSObvzuCdlWBAEnooKml/FVLKMm8xbyF4FtxK4m5mt31EdVAzmaILUpIF0TSdAzo4H7D3/Eq6poR33AWa5CPbhPHhjHbDIVSe2kKtzNo9RqdIPgDu5wEs9YkHg+qmnWkLBCNbKQDmAjfuwAS674lEWWYYUn/HJhG6og3hMrGFwURQ6US+Ogx0PNHLc61CAnite+bptkItodu/6C7lfRgWLrWxHPxjajv/UXwVZoTKLRYRVT9tm2Ib38TJcdGp6Kc/+BCuCzI/I0l4tXdkI8sx4g31Rk8c2IO7GHsBXs/6zyrzQOFAYX7FvOK6KhaWtIZ2sGur5MSX6PU323upjv7ri76IEhrXoZ+GwqyfUQ== srghma@gmail.com";
3 |
4 | devKeys = [ srghmaKey ];
5 | }
6 |
--------------------------------------------------------------------------------
/migrations/0000000002-users/09_app_public.functions.user_by_username_or_email.up.sql:
--------------------------------------------------------------------------------
1 | create function app_public.user_by_username_or_verified_email(username_or_email text) returns app_public.users as $$
2 | select users.*
3 | from app_public.users
4 | where
5 | -- Match username against users username, or any verified email address
6 | (
7 | users.username = user_by_username_or_verified_email.username_or_email
8 | or
9 | exists(
10 | select 1
11 | from app_hidden.user_emails
12 | where user_id = users.id
13 | and is_verified is true
14 | and email = user_by_username_or_verified_email.username_or_email::citext
15 | )
16 | );
17 | $$ language sql
18 | stable
19 | strict -- all args are required
20 | set search_path from current;
21 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Ace.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.Ace (page) where
2 |
3 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
4 | import Protolude
5 | import Halogen as H
6 | import Example.Ace.Container as Example.Ace.Container
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.Ace.Container.component
14 | , title: "Halogen Example - Ace button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/posts/common.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$ :: name
3 | \set table $$'posts'$$ :: name
4 |
5 | begin;
6 |
7 | select no_plan();
8 |
9 | select has_table(:schema, :table);
10 |
11 | select columns_are(
12 | :schema,
13 | :table,
14 | ARRAY[
15 | 'id',
16 | 'user_id',
17 | 'name',
18 | 'content',
19 | 'created_at',
20 | 'updated_at'
21 | ]
22 | );
23 |
24 | select indexes_are(
25 | :schema,
26 | :table,
27 | ARRAY[
28 | 'posts_pkey',
29 | 'app_public_posts_user_id'
30 | ]
31 | );
32 |
33 | select rules_are(
34 | :schema,
35 | :table,
36 | ARRAY[]::text[]
37 | );
38 |
39 | select triggers_are(
40 | :schema,
41 | :table,
42 | ARRAY['set_updated_at']
43 | );
44 |
45 | select finish();
46 |
47 | rollback;
48 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/01_prelude.up.sql:
--------------------------------------------------------------------------------
1 | -- tables and functions to be exposed to graphql
2 | create schema app_public;
3 | grant usage on schema app_public to app_anonymous, app_user;
4 | alter default privileges in schema app_public grant usage, select on sequences to app_anonymous, app_user;
5 |
6 | -- same privileges as app_public, but simply not exposed to graphql
7 | create schema app_hidden;
8 | grant usage on schema app_hidden to app_anonymous, app_user;
9 | alter default privileges in schema app_hidden grant usage, select on sequences to app_anonymous, app_user;
10 |
11 | -- secrets that require elevated privileges to access
12 | create schema app_private;
13 | grant usage on schema app_hidden to app_user;
14 | alter default privileges in schema app_hidden grant usage, select on sequences to app_user;
15 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Basic.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.Basic (page) where
2 |
3 | import Protolude
4 | import Example.Basic.Button as Example.Basic.Button
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.Basic.Button.component
14 | , title: "Halogen Example - Basic button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Queries/IsUsernameOrEmailInUse.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Queries.IsUsernameOrEmailInUse where
2 |
3 | import Protolude
4 |
5 | import NextjsGraphqlApi.Object.User as NextjsGraphqlApi.Object.User
6 | import NextjsGraphqlApi.Query as NextjsGraphqlApi.Query
7 | import Data.Maybe as Maybe
8 | import Data.String.NonEmpty (NonEmptyString)
9 | import Data.String.NonEmpty as NonEmptyString
10 | import NextjsApp.Queries.Utils (graphqlApiQueryRequestOrThrow)
11 |
12 | isUsernameOrEmailInUse :: NonEmptyString -> Aff Boolean
13 | isUsernameOrEmailInUse usernameOrEmail = graphqlApiQueryRequestOrThrow $
14 | NextjsGraphqlApi.Query.userByUsernameOrVerifiedEmail
15 | { usernameOrEmail: NonEmptyString.toString usernameOrEmail
16 | }
17 | (NextjsGraphqlApi.Object.User.id)
18 | <#> Maybe.isJust
19 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/lazy/src/LazyLoadedImport.js:
--------------------------------------------------------------------------------
1 | // TODO:
2 | // wait for https://github.com/erikd/language-javascript/issues/119
3 | // and remove LazyLoadedImportImplementation file which exists only to hack compilation error "unexpected keyword `import`"
4 | //
5 | // when we import like this - the `import` keyword from `LazyLoadedImportImplementation.js` is not parsed by purescript, but rather linked to THIS foreign import file using webpack-spago-loader
6 | //
7 | //
8 | // so, it imports like this:
9 | // - LazyLoadedImport.purs (wrapper)
10 | // -> LazyLoadedImport.js (this is where the `import` should be)
11 | // -> ./LazyLoadedImportImplementation.js (hack)
12 | // -> LazyLoaded.purs (the page definition)
13 | exports.lazyLoadedImport_ = require('./LazyLoadedImportImplementation.js').lazyLoadedImport
14 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/really_create_user/priviliges.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_private'$$
3 | \set func $$'really_create_user'$$
4 | \set args $$'{"text", "text", "bool", "text", "text", "text"}'$$::text[]
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT function_privs_are(
11 | :schema,
12 | :func,
13 | :args,
14 | 'app_admin',
15 | '{"EXECUTE"}'
16 | );
17 |
18 | SELECT function_privs_are(
19 | :schema,
20 | :func,
21 | :args,
22 | 'app_owner',
23 | '{"EXECUTE"}'
24 | );
25 |
26 | SELECT function_privs_are(
27 | :schema,
28 | :func,
29 | :args,
30 | 'app_user',
31 | '{"EXECUTE"}'
32 | );
33 |
34 | SELECT function_privs_are(
35 | :schema,
36 | :func,
37 | :args,
38 | 'app_anonymous',
39 | '{"EXECUTE"}'
40 | );
41 |
42 | select finish();
43 |
44 | rollback;
45 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Interpret.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.Interpret (page) where
2 |
3 | import Protolude
4 | import Example.Interpret.Main as Example.Interpret.Main
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.Interpret.Main.ui'
14 | , title: "Halogen Example - Interpret button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Lifecycle.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.Lifecycle (page) where
2 |
3 | import Protolude
4 | import Example.Lifecycle.Main as Example.Lifecycle.Main
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.Lifecycle.Main.ui
14 | , title: "Halogen Example - Lifecycle button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/TextNodes.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.TextNodes (page) where
2 |
3 | import Protolude
4 | import Example.TextNodes.Main as Example.TextNodes.Main
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.TextNodes.Main.component
14 | , title: "Halogen Example - Text nodes"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/insert/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_owner'$$
3 | \set user1_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set user2_id $$'00000000-0000-0000-0000-000000000002'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | insert into app_public.users
11 | (id, email, first_name, last_name)
12 | values
13 | (:user1_id, random_email(), random_string(), random_string());
14 |
15 | set local role :role;
16 | set local jwt.claims.user_id to :user1_id;
17 | select is(current_user, :role);
18 |
19 | prepare inserter as
20 | insert into app_public.users
21 | values (:user2_id, 'user2@mail.com', random_string(), random_string())
22 | returning *;
23 |
24 | -- cant insert another user
25 |
26 | select throws_ok('inserter');
27 |
28 | select finish();
29 |
30 | rollback;
31 |
--------------------------------------------------------------------------------
/packages/src/BuildSeleniumChromeDriver.purs_:
--------------------------------------------------------------------------------
1 | module BuildSeleniumChromeDriver where
2 |
3 | import Prelude
4 | import Test.Spec (Spec, describe, it)
5 | import Data.Maybe (maybe)
6 | import Data.Time.Duration (Milliseconds(..))
7 | import Effect (Effect)
8 | import Effect.Aff (launchAff, delay)
9 | import Effect.Class (liftEffect)
10 | import Effect.Console (log)
11 | import Selenium
12 | import Selenium.Browser
13 | import Selenium.Builder
14 | import Selenium.Types
15 | import Control.Monad.Error.Class (throwError)
16 | import Effect.Exception (error)
17 | import Unsafe.Coerce
18 | import Effect.Aff
19 | import Effect.Aff.Compat
20 |
21 | buildSeleniumChromeDriver :: Aff Driver
22 | buildSeleniumChromeDriver = fromEffectFnAff _buildSeleniumChromeDriver
23 |
24 | foreign import _buildSeleniumChromeDriver ∷ EffectFnAff Driver
25 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Login/Types.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.PageImplementations.Login.Types where
2 |
3 | import Protolude
4 |
5 | import Halogen.Hooks.Formless as F
6 | import Halogen as H
7 | import NextjsApp.PageImplementations.Login.Form (FormChildSlots, LoginDataValidated, LoginForm)
8 |
9 | type Query
10 | = Const Void
11 |
12 | type Input
13 | = Unit
14 |
15 | type Message
16 | = Void
17 |
18 | data Action
19 | = Action__HandleLoginForm LoginDataValidated
20 |
21 | type ChildSlots
22 | = ( formless :: H.Slot (F.Query LoginForm (Const Void) FormChildSlots) LoginDataValidated Unit )
23 |
24 | data LoginError
25 | = LoginError__LoginFailed
26 | | LoginError__UnknownError String
27 | -- | | LoginError__UsernameOrEmailNotRegistered
28 |
29 | type State = { loginError :: Maybe LoginError }
30 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/DeeplyNested.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.DeeplyNested (page) where
2 |
3 | import Protolude
4 | import Example.DeeplyNested.A as Example.DeeplyNested.A
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.DeeplyNested.A.component
14 | , title: "Halogen Example - DeeplyNested button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Object/PostsEdge.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Object.PostsEdge where
2 |
3 | import GraphQLClient
4 | ( SelectionSet
5 | , selectionForField
6 | , graphqlDefaultResponseScalarDecoder
7 | , selectionForCompositeField
8 | , graphqlDefaultResponseFunctorOrScalarDecoderTransformer
9 | )
10 | import NextjsGraphqlApi.Scopes (Scope__PostsEdge, Scope__Post)
11 | import Data.Maybe (Maybe)
12 | import NextjsGraphqlApi.Scalars (Cursor)
13 |
14 | cursor :: SelectionSet Scope__PostsEdge (Maybe Cursor)
15 | cursor = selectionForField "cursor" [] graphqlDefaultResponseScalarDecoder
16 |
17 | node :: forall r . SelectionSet Scope__Post r -> SelectionSet Scope__PostsEdge r
18 | node = selectionForCompositeField
19 | "node"
20 | []
21 | graphqlDefaultResponseFunctorOrScalarDecoderTransformer
22 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Object/UsersEdge.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Object.UsersEdge where
2 |
3 | import GraphQLClient
4 | ( SelectionSet
5 | , selectionForField
6 | , graphqlDefaultResponseScalarDecoder
7 | , selectionForCompositeField
8 | , graphqlDefaultResponseFunctorOrScalarDecoderTransformer
9 | )
10 | import NextjsGraphqlApi.Scopes (Scope__UsersEdge, Scope__User)
11 | import Data.Maybe (Maybe)
12 | import NextjsGraphqlApi.Scalars (Cursor)
13 |
14 | cursor :: SelectionSet Scope__UsersEdge (Maybe Cursor)
15 | cursor = selectionForField "cursor" [] graphqlDefaultResponseScalarDecoder
16 |
17 | node :: forall r . SelectionSet Scope__User r -> SelectionSet Scope__UsersEdge r
18 | node = selectionForCompositeField
19 | "node"
20 | []
21 | graphqlDefaultResponseFunctorOrScalarDecoderTransformer
22 |
--------------------------------------------------------------------------------
/config/ignored/passwords-dev.setup.sh:
--------------------------------------------------------------------------------
1 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
2 |
3 | cat > $SCRIPT_DIR/passwords.nix < Aff Unit
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/config/ignored/passwords.setup.sh:
--------------------------------------------------------------------------------
1 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
2 |
3 | cat > $SCRIPT_DIR/passwords.nix </dev/null 2>&1
9 |
10 | pg_dump --schema-only --no-owner --file=schemas/schema.sql "$DATABASE_URL"
11 |
12 | if [ -f node_modules/postgraphile/node_modules/graphile-build-pg/res/watch-fixtures.sql ]; then
13 | cat node_modules/postgraphile/node_modules/graphile-build-pg/res/watch-fixtures.sql | psql --no-psqlrc "$DATABASE_URL" >/dev/null 2>&1
14 | else
15 | cat node_modules/graphile-build-pg/res/watch-fixtures.sql | psql --no-psqlrc "$DATABASE_URL" >/dev/null 2>&1
16 | fi;
17 |
18 | echo " done"
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/HigherOrderComponents.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.HigherOrderComponents (page) where
2 |
3 | import Protolude
4 | import Example.HOC.Harness as Example.HOC.Harness
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.HOC.Harness.component
14 | , title: "Halogen Example - HigherOrderComponents button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Manifest/ClientPagesManifest.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Manifest.ClientPagesManifest where
2 |
3 | import Protolude
4 | import NextjsApp.Manifest.PageManifest as NextjsApp.Manifest.PageManifest
5 | import NextjsApp.Route as NextjsApp.Route
6 | import Nextjs.Utils as Nextjs.Utils
7 | import Web.DOM.ParentNode as Web.DOM.ParentNode
8 | import Data.Argonaut.Decode as ArgonautCodecs
9 | import NextjsApp.Constants as NextjsApp.Constants
10 |
11 | type ClientPagesManifest
12 | = Record (NextjsApp.Route.WebRoutesVacantRow NextjsApp.Manifest.PageManifest.PageManifest)
13 |
14 | getBuildManifest :: Aff ClientPagesManifest
15 | getBuildManifest = do
16 | json <- Nextjs.Utils.findJsonFromScriptElement (Web.DOM.ParentNode.QuerySelector NextjsApp.Constants.pagesManifestId)
17 | Nextjs.Utils.requiredJsonDecodeResult $ ArgonautCodecs.decodeJson json
18 |
--------------------------------------------------------------------------------
/packages/feature-tests/FeatureTests/AllTests.purs:
--------------------------------------------------------------------------------
1 | module FeatureTests.AllTests where
2 |
3 | import Protolude
4 | import Test.Spec (SpecT, describe)
5 | import Data.Identity
6 | import FeatureTests.FeatureTestSpec
7 | import FeatureTests.Tests.Login.SuccessSpec as FeatureTests.Tests.Login.SuccessSpec
8 | -- | import FeatureTests.Tests.Login.ErrorNotConfirmedSpec as FeatureTests.Tests.Login.ErrorNotConfirmedSpec
9 | import FeatureTests.Tests.Register.SuccessSpec as FeatureTests.Tests.Register.SuccessSpec
10 |
11 | allTests :: SpecT Aff FeatureSpecConfig Identity Unit
12 | allTests = do
13 | describe "login" do
14 | it "success" FeatureTests.Tests.Login.SuccessSpec.spec
15 | -- | it "error not confirmed" FeatureTests.Tests.Login.ErrorNotConfirmedSpec.spec
16 | describe "register" do
17 | itOnly "success" FeatureTests.Tests.Register.SuccessSpec.spec
18 |
--------------------------------------------------------------------------------
/nix/pkgs/waitforit/update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env nix-shell
2 | #!nix-shell -i bash -p nix-prefetch-git
3 |
4 | SCRIPT_DIR=$(dirname "$(readlink -f "$BASH_SOURCE")")
5 | version="v2.4.1"
6 |
7 | urlLinux="https://github.com/maxcnunes/waitforit/releases/download/$version/waitforit-linux_amd64"
8 | urlDarwin="https://github.com/maxcnunes/waitforit/releases/download/$version/waitforit-darwin_amd64"
9 |
10 | #########
11 |
12 | sha256=$(nix-prefetch-url --type sha256 $urlLinux)
13 |
14 | cat > $SCRIPT_DIR/revisionLinux.json < $SCRIPT_DIR/revisionDarwin.json < {
5 | url = "https://github.com/${spec.owner}/${spec.repo}/archive/${spec.rev}.tar.gz";
6 | inherit (spec) sha256;
7 | };
8 |
9 | nixcfg = import ;
10 |
11 | nixpkgs = builtins.derivation {
12 | inherit src;
13 | system = builtins.currentSystem;
14 | name = "${src.name}-unpacked";
15 | builder = builtins.storePath nixcfg.shell;
16 | args = [
17 | (builtins.toFile "builder" ''
18 | $coreutils/mkdir $out
19 | cd $out
20 | $gzip -d < $src | $tar -x --strip-components=1
21 | '')
22 | ];
23 | coreutils = builtins.storePath nixcfg.coreutils;
24 | tar = builtins.storePath nixcfg.tar;
25 | gzip = builtins.storePath nixcfg.gzip;
26 | };
27 | in
28 | nixpkgs
29 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/web_login/error_when_email_is_wrong.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_owner'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set email $$'user@mail.com'$$
5 | \set password $$'secret_pass'$$
6 | \set other_email $$'non_existent@mail.com'$$
7 |
8 | begin;
9 |
10 | select no_plan();
11 |
12 | insert into app_public.users
13 | (id, email, first_name, last_name, is_confirmed, password_hash)
14 | values
15 | (:user_id, :email, random_string(), random_string(), random_boolean(), crypt(:password, gen_salt('bf')));
16 |
17 | set local role :role;
18 | select is(current_user, :role);
19 |
20 | prepare do_stuff as
21 | select app_public.login(:other_email, :password);
22 |
23 | select throws_ok(
24 | 'do_stuff',
25 | 'APP_EXCEPTION__LOGIN__EMAIL_NOT_REGISTERED'
26 | );
27 |
28 | select finish();
29 |
30 | rollback;
31 |
--------------------------------------------------------------------------------
/packages/client-webpack/NextjsWebpack/BuildManifestPlugin.js:
--------------------------------------------------------------------------------
1 | // https://github.com/vercel/next.js/blob/497cac4b93de9ecf6c7ed79bd6557dcd3bb51be5/packages/next/build/webpack/plugins/build-manifest-plugin.ts#L243-L255
2 | // https://github.com/webpack/webpack/issues/11425
3 |
4 | const webpack = require('webpack')
5 |
6 | exports.mkNextJsBuildManifest = function(doWork) {
7 | class NextJsBuildManifest {
8 | apply(compiler) {
9 | compiler.hooks.make.tap('NextJsBuildManifest', (compilation) => {
10 | compilation.hooks.processAssets.tap(
11 | {
12 | name: 'NextJsBuildManifest',
13 | stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
14 | },
15 | (assets) => {
16 | doWork(compilation, assets)
17 | }
18 | )
19 | })
20 | }
21 | }
22 |
23 | return new NextJsBuildManifest()
24 | }
25 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/register/error_when_email_already_registered.sql_:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_owner'$$
3 |
4 | \set first_name $$'user1_first_name'$$
5 | \set last_name $$'user1_first_name'$$
6 |
7 | \set email $$'user@mail.com'$$
8 | \set password $$'secret_pass'$$
9 |
10 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
11 |
12 | begin;
13 |
14 | select no_plan();
15 |
16 | insert into app_public.users
17 | (id, email, first_name, last_name, is_confirmed)
18 | values
19 | (:user_id, :email, random_string(), random_string(), random_boolean());
20 |
21 | prepare do_stuff as
22 | select id from app_public.register(
23 | :first_name,
24 | :last_name,
25 | :email,
26 | :password
27 | );
28 |
29 | select throws_ok(
30 | 'do_stuff',
31 | 'APP_EXCEPTION__REGISTER__ALREADY_REGISTERED'
32 | );
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/packages/src/ArgonautCodecDecodersExtran.purs:
--------------------------------------------------------------------------------
1 | module ArgonautCodecDecodersExtran where
2 |
3 | import Protolude
4 | import Data.Argonaut.Decode
5 | import Data.Argonaut.Core (Json)
6 | import Data.Argonaut.Decode.Decoders (decodeString)
7 | import Data.Argonaut.Decode.Decoders as Decoders
8 | import Data.Argonaut.Decode.Generic (genericDecodeJson)
9 | import Data.Show.Generic (genericShow)
10 | import Data.String as String
11 | import Data.String.NonEmpty (NonEmptyString)
12 | import Data.String.NonEmpty as NonEmptyString
13 |
14 | decodeNonEmptyString :: Json -> Either JsonDecodeError NonEmptyString
15 | decodeNonEmptyString json =
16 | note (Named "NonEmptyString" $ UnexpectedValue json)
17 | =<< map (NonEmptyString.fromString) (decodeString json)
18 |
19 | decodeNonempty :: Json -> Either JsonDecodeError String
20 | decodeNonempty = map NonEmptyString.toString <<< decodeNonEmptyString
21 |
--------------------------------------------------------------------------------
/packages/src/Cordova/EventTypes.purs:
--------------------------------------------------------------------------------
1 | module Cordova.EventTypes where
2 |
3 | import Web.Event.Event (EventType(..))
4 |
5 | deviceready :: EventType
6 | deviceready = EventType "deviceready"
7 |
8 | pause :: EventType
9 | pause = EventType "pause"
10 |
11 | resume :: EventType
12 | resume = EventType "resume"
13 |
14 | backbutton :: EventType
15 | backbutton = EventType "backbutton"
16 |
17 | menubutton :: EventType
18 | menubutton = EventType "menubutton"
19 |
20 | searchbutton :: EventType
21 | searchbutton = EventType "searchbutton"
22 |
23 | startcallbutton :: EventType
24 | startcallbutton = EventType "startcallbutton"
25 |
26 | endcallbutton :: EventType
27 | endcallbutton = EventType "endcallbutton"
28 |
29 | volumedownbutton :: EventType
30 | volumedownbutton = EventType "volumedownbutton"
31 |
32 | volumeupbutton :: EventType
33 | volumeupbutton = EventType "volumeupbutton"
34 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/no_missing_indexes_on_foreign_keys.sql:
--------------------------------------------------------------------------------
1 | -- check for fks where there is no matching index
2 | -- on the referencing side
3 | -- or a bad index
4 |
5 | begin;
6 |
7 | select plan(1);
8 |
9 | -- this is what you want
10 | select is_empty('select find_missing_indexes_on_foreign_keys()');
11 |
12 | -- but sometimes you'll want it to return non-empty records
13 |
14 | /* select set_eq( */
15 | /* -- no need to create this index, because unique constraint creates it */
16 | /* 'select * from find_missing_indexes_on_foreign_keys()', */
17 | /* $$values */
18 | /* ( */
19 | /* 'app_public'::name, */
20 | /* 'users__mtm__projects'::name, */
21 | /* 'users__mtm__projects_project_id_fkey'::name, */
22 | /* 'no index', */
23 | /* 'projects'::name */
24 | /* ) */
25 | /* $$ */
26 | /* ); */
27 |
28 | select finish();
29 |
30 | rollback;
31 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/delete/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_owner'$$
3 | \set user1_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set user2_id $$'00000000-0000-0000-0000-000000000002'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | insert into app_public.users
11 | (id, email, first_name, last_name)
12 | values
13 | (:user1_id, random_email(), random_string(), random_string()),
14 | (:user2_id, random_email(), random_string(), random_string());
15 |
16 | set local role :role;
17 | set local jwt.claims.user_id to :user1_id;
18 | select is(current_user, :role);
19 |
20 | delete from app_public.users where id in (:user1_id, :user2_id);
21 | -- cant delete another user
22 | prepare expected as values(:user2_id :: uuid);
23 |
24 | select set_eq(
25 | 'select id from app_public.users',
26 | 'expected'
27 | );
28 |
29 | select finish();
30 |
31 | rollback;
32 |
--------------------------------------------------------------------------------
/packages/api-server/ApiServer/PostgraphilePassportAuthPlugin.js:
--------------------------------------------------------------------------------
1 | const { makeExtendSchemaPlugin, gql } = require("graphile-utils");
2 |
3 | exports.mkPassportLoginPlugin = mkResolvers => makeExtendSchemaPlugin(build => ({
4 | typeDefs: gql`
5 | input WebRegisterInput {
6 | username: String!
7 | email: String!
8 | password: String!
9 | name: String
10 | avatarUrl: String
11 | }
12 |
13 | type WebRegisterPayload {
14 | user: User! @pgField
15 | }
16 |
17 | input WebLoginInput {
18 | username: String!
19 | password: String!
20 | }
21 |
22 | type WebLoginPayload {
23 | user: User! @pgField
24 | }
25 |
26 | extend type Mutation {
27 | webRegister(input: WebRegisterInput!): WebRegisterPayload
28 | webLogin(input: WebLoginInput!): WebLoginPayload
29 | }
30 | `,
31 | resolvers: mkResolvers(build)
32 | }));
33 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/EffectsEffectRandom.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Pages.Examples.EffectsEffectRandom (page) where
2 |
3 | import Protolude
4 | import Example.Effects.Effect.Random.Component as Example.Effects.Effect.Random.Component
5 | import Nextjs.Page (PageSpecBoxed, PageData(..), PageSpec, mkPageSpecBoxed)
6 | import Halogen as H
7 | import NextjsApp.AppM (AppM(..))
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | pageSpec :: PageSpec NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow) Unit
11 | pageSpec =
12 | { pageData: PageData__Static unit
13 | , component: H.hoist liftAff $ Example.Effects.Effect.Random.Component.component
14 | , title: "Halogen Example - EffectsEffectRandom button"
15 | }
16 |
17 | page :: PageSpecBoxed NextjsApp.Route.WebRoutesWithParamRow (AppM NextjsApp.Route.WebRoutesWithParamRow)
18 | page = mkPageSpecBoxed pageSpec
19 |
--------------------------------------------------------------------------------
/packages/src/ReadWriteStdinYesNo.purs_:
--------------------------------------------------------------------------------
1 | readStdin :: Aff String
2 | readStdin = makeAff \callback -> do
3 | ref <- Ref.new ""
4 | Node.Stream.onDataString Node.Process.stdin Node.Encoding.UTF8 \s -> do
5 | buffer <- Ref.read ref
6 | Ref.write (buffer <> s) ref
7 | Node.Stream.onEnd Node.Process.stdin do
8 | buffer <- Ref.read ref
9 | callback (pure buffer)
10 | pure nonCanceler
11 |
12 | readEndStdin :: Aff Unit
13 | readEndStdin = makeAff \callback -> do
14 | Node.Stream.onEnd Node.Process.stdin do
15 | traceM "end"
16 | callback $ Right unit
17 | pure nonCanceler
18 |
19 | writeStdout :: String -> Effect Unit
20 | writeStdout s =
21 | void (Node.Stream.writeString Node.Process.stdout Node.Encoding.UTF8 s (pure unit))
22 |
23 | pressCtrlDToContinue :: Aff Unit
24 | pressCtrlDToContinue = do
25 | liftEffect $ writeStdout "Press \"CTRL-D\" to continue: "
26 | readEndStdin
27 |
--------------------------------------------------------------------------------
/packages/src/TimeExtra.purs:
--------------------------------------------------------------------------------
1 | module TimeExtra where
2 |
3 | import Prelude
4 | import Data.Time.Duration (class Duration, Milliseconds)
5 | import Effect.Now (nowDateTime)
6 | import Data.DateTime (diff)
7 | import Data.Time.Duration (class Duration)
8 | import Debug.Trace (traceM)
9 | import Data.Tuple (Tuple(..))
10 | import Effect.Class (liftEffect, class MonadEffect)
11 |
12 | time :: forall a d m. MonadEffect m => Duration d => m a -> m (Tuple d a)
13 | time action = do
14 | dateTimeVal <- liftEffect nowDateTime
15 | output <- action
16 | dateTimeVal' <- liftEffect nowDateTime
17 | pure (Tuple (diff dateTimeVal' dateTimeVal) output)
18 |
19 | traceTime :: forall a m. MonadEffect m => String -> m a -> m a
20 | traceTime name action = do
21 | Tuple (milliseconds :: Milliseconds) output <- time action
22 | traceM $ "Time diff for action \"" <> name <> "\": " <> show milliseconds
23 | pure output
24 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/D.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.D (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 | import Example.DeeplyNested.F as F
8 | import Data.Const (Const)
9 | import Type.Proxy (Proxy(..))
10 |
11 | type State = Unit
12 |
13 | data Action = Void
14 |
15 | type ChildSlots =
16 | ( f :: H.Slot (Const Void) Void Unit
17 | )
18 |
19 | _f :: Proxy "f"
20 | _f = Proxy
21 |
22 | component :: forall q i o m. H.Component q i o m
23 | component =
24 | H.mkComponent
25 | { initialState: const unit
26 | , render
27 | , eval: H.mkEval H.defaultEval
28 | }
29 |
30 | render :: forall m. State -> H.ComponentHTML Action ChildSlots m
31 | render state =
32 | HH.ul_
33 | [ HH.li_ [ HH.text "d" ]
34 | , HH.li_ [ HH.slot _f unit F.component unit absurd ]
35 | , HH.li_ [ HH.text "d end" ]
36 | ]
37 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/interpret/README.md:
--------------------------------------------------------------------------------
1 | # Interpret
2 |
3 | This example illustrates using `ReaderT` with `Aff` as the effect type for a component, and then interpreting this back down to `Aff` so it can be run as a normal component. This can be used, for example, to implement a read-only configuration for your application, or a global state if you store a mutable reference.
4 |
5 | For an example application which uses `ReaderT` with `Aff` to implement a global state, see [Real World Halogen](https://github.com/thomashoneyman/purescript-halogen-realworld/).
6 |
7 | ## Building
8 |
9 | You can build this example from the root of the Halogen project:
10 |
11 | ```sh
12 | npm install
13 | npm run example-interpret
14 | ```
15 |
16 | This will bundle a runnable JS file, `example.js`, in the `examples/interpret/dist` directory. You can view the running application by opening the corresponding `index.html` file.
17 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/priviliges/app_user.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set table $$'users'$$
4 | \set role $$'app_user'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY[
15 | 'SELECT'
16 | ]
17 | );
18 |
19 | SELECT any_column_privs_are(
20 | :schema,
21 | :table,
22 | :role,
23 | ARRAY[
24 | 'SELECT'
25 | ]
26 | );
27 |
28 | SELECT column_privs_are(:schema, :table, 'id', :role, ARRAY['SELECT']);
29 | SELECT column_privs_are(:schema, :table, 'first_name', :role, ARRAY['SELECT']);
30 | SELECT column_privs_are(:schema, :table, 'last_name', :role, ARRAY['SELECT']);
31 | SELECT column_privs_are(:schema, :table, 'created_at', :role, ARRAY['SELECT']);
32 | SELECT column_privs_are(:schema, :table, 'updated_at', :role, ARRAY['SELECT']);
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/migrations/0000000001-start/04_tg__set_updated_at.up.sql:
--------------------------------------------------------------------------------
1 | create function app_private.tg__set_updated_at() returns trigger as $$
2 | begin
3 | new.updated_at := current_timestamp;
4 | return new;
5 | end;
6 | $$ language plpgsql;
7 |
8 | /* create function app_private.tg__set_updated_at() returns trigger as $$ */
9 | /* begin */
10 | /* NEW.created_at = (case when TG_OP = 'INSERT' then NOW() else OLD.created_at end); */
11 | /* NEW.updated_at = (case when TG_OP = 'UPDATE' and OLD.updated_at >= NOW() then OLD.updated_at + interval '1 millisecond' else NOW() end); */
12 | /* return NEW; */
13 | /* end; */
14 | /* $$ language plpgsql volatile set search_path from current; */
15 |
16 | /* comment on function app_private.tg__set_updated_at() is E'This trigger should be called on all tables with created_at, updated_at - it ensures that they cannot be manipulated and that updated_at will always be larger than the previous updated_at.'; */
17 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/posts/priviligies/app_admin.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$ :: name
3 | \set table $$'posts'$$ :: name
4 | \set role $$'app_admin'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY[
15 | 'SELECT',
16 | 'INSERT',
17 | 'UPDATE',
18 | 'DELETE',
19 | 'REFERENCES',
20 | 'TRIGGER',
21 | 'TRUNCATE'
22 | ]
23 | );
24 |
25 | SELECT any_column_privs_are(
26 | :schema,
27 | :table,
28 | :role,
29 | ARRAY[
30 | 'SELECT',
31 | 'UPDATE',
32 | 'INSERT',
33 | 'REFERENCES'
34 | ]
35 | );
36 |
37 | SELECT column_privs_are(:schema, :table, col, :role, ARRAY['SELECT', 'UPDATE', 'INSERT', 'REFERENCES'])
38 | FROM (
39 | VALUES('id'), ('name'), ('user_id'), ('content'), ('created_at'), ('updated_at')
40 | ) AS tableAlias (col);
41 |
42 |
43 | select finish();
44 |
45 | rollback;
46 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/queries/user_by_username_or_verified_email/success_by_username.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_anonymous'$$
2 | \set user_secret_id $$'00000000-0000-0000-0000-000000000001'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set email $$'user@mail.com'$$
5 | \set username $$'username2'$$
6 |
7 | begin;
8 |
9 | select no_plan();
10 |
11 | INSERT INTO app_private.user_secrets (id)
12 | VALUES (:user_secret_id);
13 |
14 | INSERT INTO app_public.users (id, user_secret_id, username)
15 | VALUES (:user_id, :user_secret_id, :username);
16 |
17 | set local role :role;
18 | select is(current_user, :role);
19 |
20 | prepare actual as
21 | select id, username
22 | from app_public.user_by_username_or_verified_email(:username);
23 |
24 | prepare expected as values
25 | (:user_id::uuid, :username);
26 |
27 | select set_eq(
28 | 'actual',
29 | 'expected'
30 | );
31 |
32 | select finish();
33 |
34 | rollback;
35 |
--------------------------------------------------------------------------------
/packages/src/Webpack/FFI.purs:
--------------------------------------------------------------------------------
1 | module Webpack.FFI where
2 |
3 | import Effect.Uncurried (EffectFn1, EffectFn3)
4 | import Protolude
5 | import Webpack.Types (Assets, Compilation, RawSource, WebpackEntrypont)
6 | import Foreign (Foreign)
7 | import Foreign.JsMap (JsMap)
8 | import Node.Buffer (Buffer)
9 | import Unsafe.Coerce (unsafeCoerce)
10 |
11 | foreign import webpackEntrypontName :: EffectFn1 WebpackEntrypont String
12 |
13 | foreign import webpackEntrypontGetFiles :: EffectFn1 WebpackEntrypont (Array String)
14 |
15 | foreign import _rawSource :: Foreign -> RawSource
16 |
17 | rawSourceFromString :: String -> RawSource
18 | rawSourceFromString = _rawSource <<< unsafeCoerce
19 |
20 | rawSourceFromBuffer :: Buffer -> RawSource
21 | rawSourceFromBuffer = _rawSource <<< unsafeCoerce
22 |
23 | foreign import setAsset :: EffectFn3 Assets String RawSource Unit
24 |
25 | foreign import compilationGetEntrypoints :: EffectFn1 Compilation (JsMap String WebpackEntrypont)
26 |
--------------------------------------------------------------------------------
/docker/common/migrator.nix:
--------------------------------------------------------------------------------
1 | { pkgs, rootProjectDir }:
2 |
3 | {
4 | useHostStore = true;
5 |
6 | entrypoint = ""; # I hate people that use custom entrypoints
7 |
8 | command = "${pkgs.coreutils}/bin/true"; # do nothing on `docker-compose up`
9 |
10 | working_dir = "/migrations";
11 |
12 | environment = {
13 | TYPE = "postgresql";
14 | LOGIN = "app_admin";
15 | PASSWORD = "app_admin_pass";
16 | HOST = "postgres";
17 | PORT = 5432;
18 | DATABASE = "nextjsdemo_test";
19 |
20 | PATH = let
21 | env = pkgs.buildEnv {
22 | name = "system-path";
23 | paths = with pkgs; [
24 | waitforit
25 | wait-for-postgres
26 | shmig
27 | ];
28 | };
29 | in "${env}/bin:/bin:/run/system/bin";
30 | };
31 |
32 | volumes = [
33 | "${rootProjectDir}/migrations:/migrations:ro"
34 | "/tmp" # for shmig
35 | ];
36 |
37 | depends_on = [
38 | "postgres"
39 | ];
40 | }
41 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/web_login/success_by_username_when_password_is_valid.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_owner'$$
2 | \set user_secret_id $$'00000000-0000-0000-0000-000000000001'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set email $$'user@mail.com'$$
5 | \set username $$'username2'$$
6 | \set password $$'secret_pass'$$
7 |
8 | begin;
9 |
10 | select no_plan();
11 |
12 | INSERT INTO app_private.user_secrets (id, password_hash)
13 | VALUES (:user_secret_id, crypt(:password, gen_salt('bf')));
14 |
15 | INSERT INTO app_public.users (id, user_secret_id, username)
16 | VALUES (:user_id, :user_secret_id, :username);
17 |
18 | set local role :role;
19 | select is(current_user, :role);
20 |
21 | prepare actual as
22 | select id from app_private.web_login(:username, :password);
23 |
24 | prepare expected as values
25 | (:user_id::uuid);
26 |
27 | select set_eq(
28 | 'actual',
29 | 'expected'
30 | );
31 |
32 | select finish();
33 |
34 | rollback;
35 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/really_create_user/success_not_verified.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_owner'$$
2 | \set email $$'user@mail.com'$$
3 | \set username $$'username2'$$
4 | \set password $$'secret_pass'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | set local role :role;
11 | select is(current_user, :role);
12 |
13 | prepare actual as
14 | select username from app_private.really_create_user(
15 | username => :username,
16 | email => :email,
17 | email_is_verified => false,
18 | name => null,
19 | avatar_url => null,
20 | password => :password
21 | );
22 |
23 | prepare expected as values
24 | (:username);
25 |
26 | select set_eq(
27 | 'actual',
28 | 'expected'
29 | );
30 |
31 | set local role 'app_admin';
32 |
33 | select set_eq(
34 | 'select task_identifier from "graphile_worker".jobs',
35 | ARRAY['JOB__SEND_VERIFICATION_EMAIL_FOR_USER_EMAIL']
36 | );
37 |
38 | select finish();
39 |
40 | rollback;
41 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/update/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set role $$'app_owner'$$
3 | \set user1_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set user2_id $$'00000000-0000-0000-0000-000000000002'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | insert into app_public.users
11 | (id, email, first_name, last_name)
12 | values
13 | (:user1_id, 'user@mail.com', random_string(), random_string()),
14 | (:user2_id, 'user2@mail.com', random_string(), random_string());
15 |
16 | set local role :role;
17 | set local jwt.claims.user_id to :user1_id;
18 | select is(current_user, :role);
19 |
20 | update app_public.users set email = 'new_user@mail.com' where id = :user1_id;
21 | update app_public.users set email = 'new_user2@mail.com' where id = :user2_id;
22 |
23 | -- cant update another user
24 | prepare expected as values ('new_user@mail.com'), ('user2@mail.com');
25 |
26 | select set_eq(
27 | 'select email from app_public.users',
28 | 'expected'
29 | );
30 |
31 | select finish();
32 |
33 | rollback;
34 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/send_reset_password/error_when_email_not_exists.sql_:
--------------------------------------------------------------------------------
1 |
2 |
3 | \set role $$'app_owner'$$
4 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
5 | \set email $$'user@mail.com'$$
6 | \set password $$'secret_pass'$$
7 |
8 | begin;
9 |
10 | select no_plan();
11 |
12 | select pgtest.spy('app_private', 'rabbitmq__send_reset_password_mail', ARRAY['app_public.users']);
13 |
14 | -- Test body
15 | set local role :role;
16 | select is(current_user, :role);
17 |
18 | prepare do_stuff as
19 | select app_public.send_reset_password(:email);
20 |
21 | select throws_ok(
22 | 'do_stuff',
23 | 'APP_EXCEPTION__SEND_RESET_PASSWORD__EMAIL_NOT_REGISTERED'
24 | );
25 |
26 | -- Test body END
27 |
28 | -- Check app_private.rabbitmq__send_reset_password has not been called
29 |
30 | set local role 'app_owner';
31 |
32 | select pgtest.assert_called(pgtest.get_mock_id('app_private', 'rabbitmq__send_reset_password_mail', ARRAY['app_public.users']), 0);
33 |
34 | select finish();
35 |
36 | rollback;
37 |
--------------------------------------------------------------------------------
/dev-commands/dev/lib.nix:
--------------------------------------------------------------------------------
1 | { pkgs }:
2 |
3 | rec {
4 | config =
5 | {
6 | POSTGRES_HOST = "0.0.0.0";
7 | POSTGRES_PORT = 5432;
8 |
9 | SERVER_HOST = "0.0.0.0";
10 | SERVER_PORT = 5000;
11 |
12 | CLIENT_HOST = "0.0.0.0";
13 | CLIENT_PORT = 3000;
14 | };
15 |
16 | migratorEnv =
17 | {
18 | inherit (import "${pkgs.rootProjectDir}/config/public/database.nix")
19 | DATABASE_NAME;
20 |
21 | inherit (import "${pkgs.rootProjectDir}/config/ignored/passwords.nix")
22 | DATABASE_OWNER_PASSWORD;
23 |
24 | inherit (config)
25 | POSTGRES_HOST
26 | POSTGRES_PORT;
27 | };
28 |
29 | serverEnv =
30 | {
31 | inherit (import "${pkgs.rootProjectDir}/config/public/database.nix")
32 | DATABASE_NAME;
33 |
34 | inherit (import "${pkgs.rootProjectDir}/config/ignored/passwords.nix")
35 | DATABASE_OWNER_PASSWORD;
36 |
37 | inherit (config)
38 | POSTGRES_HOST
39 | POSTGRES_PORT;
40 | };
41 | }
42 |
--------------------------------------------------------------------------------
/nix/pkgs/gitCryptUnlock/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 |
3 | let
4 | inherit (pkgs) stdenv git-crypt git;
5 | in
6 |
7 | key:
8 | src:
9 | stdenv.mkDerivation {
10 | name = "decrypted-source";
11 | inherit src;
12 | buildInputs = [ git-crypt git ];
13 | phases = [ "installPhase" ];
14 | installPhase = ''
15 | mkdir -p $out
16 |
17 | # copy content of folder with hidden files to $out
18 | cp -r $src/. $out
19 |
20 | cd $out
21 |
22 | # git crypt requires git
23 | git init
24 |
25 | # set only for this repo
26 | git config user.email "you@example.com"
27 | git config user.name "Your Name"
28 |
29 | git add --all
30 | git commit --quiet -m "dummy"
31 |
32 | # prevent "error: unable to unlink old... permission denied"
33 | # see https://stackoverflow.com/questions/11774397/git-push-error-unable-to-unlink-old-permission-denied/11774432
34 | chmod -R +w $out
35 |
36 | git-crypt unlock ${key}
37 |
38 | # don't leave traces
39 | rm -rfd .git
40 | '';
41 | }
42 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Subscription.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Subscription where
2 |
3 | import Type.Row (type (+))
4 | import GraphQLClient
5 | ( SelectionSet
6 | , Scope__RootSubscription
7 | , selectionForCompositeField
8 | , toGraphQLArguments
9 | , graphqlDefaultResponseFunctorOrScalarDecoderTransformer
10 | )
11 | import NextjsGraphqlApi.Scopes (Scope__ListenPayload)
12 |
13 | type ListenInputRowRequired r = ( topic :: String | r )
14 |
15 | type ListenInput = { | ListenInputRowRequired + () }
16 |
17 | listen :: forall r . ListenInput -> SelectionSet
18 | Scope__ListenPayload
19 | r -> SelectionSet
20 | Scope__RootSubscription
21 | r
22 | listen input = selectionForCompositeField
23 | "listen"
24 | (toGraphQLArguments
25 | input)
26 | graphqlDefaultResponseFunctorOrScalarDecoderTransformer
27 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users_oauths/priviliges/app_user.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set table $$'user_oauths'$$
4 | \set role $$'app_user'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY[]::text[]
15 | );
16 |
17 | SELECT any_column_privs_are(
18 | :schema,
19 | :table,
20 | :role,
21 | ARRAY[]::text[]
22 | );
23 |
24 | SELECT column_privs_are(:schema, :table, 'id', :role, ARRAY[]::text[]);
25 | SELECT column_privs_are(:schema, :table, 'user_id', :role, ARRAY[]::text[]);
26 | SELECT column_privs_are(:schema, :table, 'service', :role, ARRAY[]::text[]);
27 | SELECT column_privs_are(:schema, :table, 'service_identifier', :role, ARRAY[]::text[]);
28 | SELECT column_privs_are(:schema, :table, 'created_at', :role, ARRAY[]::text[]);
29 | SELECT column_privs_are(:schema, :table, 'updated_at', :role, ARRAY[]::text[]);
30 |
31 | select finish();
32 |
33 | rollback;
34 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Object/UserAuthenticationsEdge.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Object.UserAuthenticationsEdge where
2 |
3 | import GraphQLClient
4 | ( SelectionSet
5 | , selectionForField
6 | , graphqlDefaultResponseScalarDecoder
7 | , selectionForCompositeField
8 | , graphqlDefaultResponseFunctorOrScalarDecoderTransformer
9 | )
10 | import NextjsGraphqlApi.Scopes
11 | (Scope__UserAuthenticationsEdge, Scope__UserAuthentication)
12 | import Data.Maybe (Maybe)
13 | import NextjsGraphqlApi.Scalars (Cursor)
14 |
15 | cursor :: SelectionSet Scope__UserAuthenticationsEdge (Maybe Cursor)
16 | cursor = selectionForField "cursor" [] graphqlDefaultResponseScalarDecoder
17 |
18 | node :: forall r . SelectionSet
19 | Scope__UserAuthentication
20 | r -> SelectionSet
21 | Scope__UserAuthenticationsEdge
22 | r
23 | node = selectionForCompositeField
24 | "node"
25 | []
26 | graphqlDefaultResponseFunctorOrScalarDecoderTransformer
27 |
--------------------------------------------------------------------------------
/packages/api-server/ApiServer/FrontendServerHttpProxy.js_:
--------------------------------------------------------------------------------
1 | // from https://github.com/graphile/bootstrap-react-apollo/blob/master/server/middleware/installClientServerProxy.js
2 |
3 | const httpProxy = require("http-proxy")
4 |
5 | exports._installFrontendServerProxy = function installFrontendServer(httpServer, app, targetUrl) {
6 | const proxy = httpProxy.createProxyServer({
7 | target: targetUrl,
8 | ws: true,
9 | })
10 |
11 | proxy.on('error', e => {
12 | console.error("Proxy error occurred:", e)
13 | })
14 |
15 | app.use((req, res, _next) => {
16 | proxy.web(req, res, {}, e => {
17 | console.error(e)
18 |
19 | res.statusCode = 503
20 |
21 | res.end("Error occurred while proxying to client application - is it running? " + e.message)
22 | })
23 | })
24 |
25 | // DONT PROXY WEBSOCKET ON DEV TO CLIENT SSR SERVER
26 | // because Postgraphile of this api server will handle it
27 | // httpServer.on("upgrade", (req, socket, head) => {
28 | // proxy.ws(req, socket, head)
29 | // })
30 | }
31 |
--------------------------------------------------------------------------------
/packages/worker/Worker/Config/FromEnv.purs:
--------------------------------------------------------------------------------
1 | module Worker.Config.FromEnv where
2 |
3 | import Protolude
4 |
5 | import Data.NonEmpty (NonEmpty(..))
6 | import Data.String.NonEmpty (NonEmptyString)
7 | import Data.String.NonEmpty as NonEmptyString
8 | import Env as Env
9 | import Foreign.Object (Object)
10 |
11 | type EnvConfig =
12 | { nodemailerRealPass :: Maybe String
13 | , nodemailerRealUser :: Maybe String
14 | , databaseOwnerPassword :: String
15 | }
16 |
17 | envConfig :: Effect EnvConfig
18 | envConfig = Env.parse Env.defaultInfo $ ado
19 | nodemailerRealPass <- Env.optionalVar Env.nonempty "nodemailerRealPass" (Env.defaultOptionalVarOptions { sensitive = true })
20 | nodemailerRealUser <- Env.optionalVar Env.nonempty "nodemailerRealUser" (Env.defaultOptionalVarOptions { sensitive = true })
21 | databaseOwnerPassword <- Env.var Env.nonempty "databaseOwnerPassword" (Env.defaultVarOptions { sensitive = true })
22 |
23 | in
24 | { nodemailerRealPass
25 | , nodemailerRealUser
26 | , databaseOwnerPassword
27 | }
28 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Pages/Examples/Ace.deps.js:
--------------------------------------------------------------------------------
1 | // FROM https://github.com/ajaxorg/ace-builds/issues/129#issuecomment-406783352
2 |
3 | import 'ace-builds/src-min-noconflict/ace' // Load Ace Editor
4 |
5 | // Import initial theme and mode so we don't have to wait for 2 extra HTTP requests
6 | import 'ace-builds/src-min-noconflict/theme-chrome'
7 | import 'ace-builds/src-min-noconflict/mode-javascript'
8 |
9 | // cdnjs didn't have a "no-conflict" version, so we'll use jsdelivr
10 | const CDN = 'https://cdn.jsdelivr.net/npm/ace-builds@1.3.3/src-min-noconflict';
11 |
12 | // Now we tell ace to use the CDN locations to look for files
13 | ace.config.set('basePath', CDN);
14 | ace.config.set('modePath', CDN);
15 | ace.config.set('themePath', CDN);
16 | ace.config.set('workerPath', CDN);
17 |
18 | // // Create Editor
19 | // const editor = ace.edit('editor');
20 |
21 | // // Set Editor Theme and Mode
22 | // editor.setTheme('ace/theme/chrome');
23 | // editor.session.setMode('ace/mode/javascript');
24 |
25 | /////////////////
26 |
27 | import './Ace.scss'
28 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/queries/user_by_username_or_verified_email/success_by_email.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_anonymous'$$
2 | \set user_secret_id $$'00000000-0000-0000-0000-000000000001'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set email $$'user@mail.com'$$
5 | \set username $$'username2'$$
6 |
7 | begin;
8 |
9 | select no_plan();
10 |
11 | INSERT INTO app_private.user_secrets (id)
12 | VALUES (:user_secret_id);
13 |
14 | INSERT INTO app_public.users (id, user_secret_id, username)
15 | VALUES (:user_id, :user_secret_id, :username);
16 |
17 | INSERT INTO app_hidden.user_emails (user_id, email, is_verified)
18 | VALUES (:user_id, :email, true);
19 |
20 | set local role :role;
21 | select is(current_user, :role);
22 |
23 | prepare actual as
24 | select id, username
25 | from app_public.user_by_username_or_verified_email(:email);
26 |
27 | prepare expected as values
28 | (:user_id::uuid, :username);
29 |
30 | select set_eq(
31 | 'actual',
32 | 'expected'
33 | );
34 |
35 | select finish();
36 |
37 | rollback;
38 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/components-inputs/src/Display.purs:
--------------------------------------------------------------------------------
1 | module Example.Components.Inputs.Display where
2 |
3 | import Prelude
4 |
5 | import Data.Maybe (Maybe(..))
6 | import Halogen as H
7 | import Halogen.HTML as HH
8 |
9 | type Slot p = forall q. H.Slot q Void p
10 |
11 | type Input = Int
12 |
13 | type State = Int
14 |
15 | data Action = HandleInput Int
16 |
17 | component :: forall q o m. H.Component q Input o m
18 | component =
19 | H.mkComponent
20 | { initialState: identity
21 | , render
22 | , eval: H.mkEval $ H.defaultEval
23 | { handleAction = handleAction
24 | , receive = Just <<< HandleInput
25 | }
26 | }
27 |
28 | render :: forall m. State -> H.ComponentHTML Action () m
29 | render state =
30 | HH.div_
31 | [ HH.text "My input value is:"
32 | , HH.strong_ [ HH.text (show state) ]
33 | ]
34 |
35 | handleAction :: forall o m. Action -> H.HalogenM State Action () o m Unit
36 | handleAction = case _ of
37 | HandleInput n -> do
38 | oldN <- H.get
39 | when (oldN /= n) $ H.put n
40 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Data/InUseUsernameOrEmail.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Data.InUseUsernameOrEmail where
2 |
3 | import Protolude
4 |
5 | import Data.String.NonEmpty (NonEmptyString)
6 | import Data.String.NonEmpty as NonEmptyString
7 | import NextjsApp.Queries.IsUsernameOrEmailInUse (isUsernameOrEmailInUse)
8 |
9 | data InUseUsernameOrEmail__Error
10 | = InUseUsernameOrEmail__Error__Empty
11 | | InUseUsernameOrEmail__Error__NotInUse
12 |
13 | newtype InUseUsernameOrEmail = InUseUsernameOrEmail NonEmptyString
14 |
15 | toString :: InUseUsernameOrEmail -> String
16 | toString (InUseUsernameOrEmail s) = NonEmptyString.toString s
17 |
18 | fromString :: String -> Aff (Either InUseUsernameOrEmail__Error InUseUsernameOrEmail)
19 | fromString = NonEmptyString.fromString >>>
20 | case _ of
21 | Nothing -> pure $ Left InUseUsernameOrEmail__Error__Empty
22 | Just usernameOrEmail -> isUsernameOrEmailInUse usernameOrEmail <#>
23 | if _
24 | then Right (InUseUsernameOrEmail usernameOrEmail)
25 | else Left InUseUsernameOrEmail__Error__NotInUse
26 |
--------------------------------------------------------------------------------
/packages/src/FRPEventExtra.purs:
--------------------------------------------------------------------------------
1 | module FRPEventExtra where
2 |
3 | import Protolude
4 | import FRP.Event (Event)
5 | import FRP.Event as Event
6 | import Effect.Ref as Ref
7 |
8 | withPrevious :: forall a. Event a -> Event { previous :: Maybe a, current :: a }
9 | withPrevious event =
10 | Event.makeEvent \push -> do
11 | latest <- Ref.new Nothing
12 | closeInner <-
13 | Event.subscribe event \current -> do
14 | previous <- Ref.read latest
15 | Ref.write (Just current) latest
16 | push { previous, current }
17 | pure closeInner
18 |
19 | distinctWith :: forall a. (a -> a -> Boolean) -> Event a -> Event a
20 | distinctWith isEq event =
21 | Event.filterMap
22 | ( \{ current, previous } -> case previous of
23 | Just previous' ->
24 | if isEq previous' current then
25 | Nothing
26 | else
27 | Just current
28 | Nothing -> Just current
29 | )
30 | (withPrevious event)
31 |
32 | distinct :: forall a. Eq a => Event a -> Event a
33 | distinct = distinctWith eq
34 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/PageImplementations/Secret.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.PageImplementations.Secret (component) where
2 |
3 | import NextjsApp.PageImplementations.Secret.Types
4 | import Protolude
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 | import NextjsApp.AppM (AppM)
8 | import NextjsApp.Route as NextjsApp.Route
9 |
10 | type Query
11 | = Const Void
12 |
13 | type Input
14 | = SecretPageUserData
15 |
16 | type Message
17 | = Void
18 |
19 | type State
20 | = SecretPageUserData
21 |
22 | type Action
23 | = Void
24 |
25 | type ChildSlots
26 | = ()
27 |
28 | component :: H.Component Query Input Message AppM
29 | component =
30 | H.mkComponent
31 | { initialState: identity
32 | , render
33 | , eval: H.mkEval $ H.defaultEval
34 | }
35 |
36 | render
37 | :: forall (slots :: Row Type) routes
38 | . State
39 | -> HH.ComponentHTML
40 | Action
41 | (slots :: Row Type)
42 | (AppM routes)
43 | render (SecretPageUserData input) =
44 | HH.div_
45 | [ HH.text "You are on secret page"
46 | , HH.text $ show input
47 | ]
48 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users/priviliges/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set table $$'users'$$
4 | \set role $$'app_owner'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY[
15 | 'SELECT',
16 | 'DELETE',
17 | 'UPDATE'
18 | ]
19 | );
20 |
21 | -- TODO: what is this?
22 | SELECT any_column_privs_are(
23 | :schema,
24 | :table,
25 | :role,
26 | ARRAY[
27 | 'SELECT',
28 | 'UPDATE'
29 | ]
30 | );
31 |
32 | -- TODO: what is this too?
33 | SELECT column_privs_are(:schema, :table, 'id', :role, ARRAY['SELECT', 'UPDATE']);
34 | SELECT column_privs_are(:schema, :table, 'first_name', :role, ARRAY['SELECT', 'UPDATE']);
35 | SELECT column_privs_are(:schema, :table, 'last_name', :role, ARRAY['SELECT', 'UPDATE']);
36 | SELECT column_privs_are(:schema, :table, 'created_at', :role, ARRAY['SELECT', 'UPDATE']);
37 | SELECT column_privs_are(:schema, :table, 'updated_at', :role, ARRAY['SELECT', 'UPDATE']);
38 |
39 | select finish();
40 |
41 | rollback;
42 |
--------------------------------------------------------------------------------
/packages/client/NextjsApp/Link/Lib.purs:
--------------------------------------------------------------------------------
1 | module NextjsApp.Link.Lib where
2 |
3 | import Protolude
4 |
5 | import Control.Monad.Reader.Class (class MonadAsk)
6 | import Control.Monad.State (class MonadState)
7 | import Effect.Class (class MonadEffect)
8 | import Halogen as H
9 | import NextjsApp.Navigate as NextjsApp.Navigate
10 | import Web.Event.Event as Web.Event.Event
11 | import Web.UIEvent.MouseEvent (MouseEvent)
12 | import Web.UIEvent.MouseEvent as Web.UIEvent.MouseEvent
13 |
14 | elementLabel :: H.RefLabel
15 | elementLabel = H.RefLabel "link"
16 |
17 | handleMouseEvent :: ∀ t16 t17 t19 t4. Bind t4 ⇒ MonadEffect t4 ⇒ MonadState { route :: Variant t17 | t16 } t4 ⇒ MonadAsk { navigate :: Variant t17 -> Effect Unit | t19 } t4 ⇒ MouseEvent → t4 Unit
18 | handleMouseEvent mouseEvent = do
19 | -- TODO: ignore newtab clicks https://github.com/vercel/next.js/blob/8dd3d2a8e2b266611a60b9550d2ecac02f14fd57/packages/next/client/link.tsx#L171-L182
20 | H.liftEffect $ Web.Event.Event.preventDefault (Web.UIEvent.MouseEvent.toEvent mouseEvent)
21 |
22 | H.gets _.route >>= NextjsApp.Navigate.navigate
23 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/web_login/success_by_email_when_password_is_valid.sql:
--------------------------------------------------------------------------------
1 | \set role $$'app_owner'$$
2 | \set user_secret_id $$'00000000-0000-0000-0000-000000000001'$$
3 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
4 | \set email $$'user@mail.com'$$
5 | \set username $$'username2'$$
6 | \set password $$'secret_pass'$$
7 |
8 | begin;
9 |
10 | select no_plan();
11 |
12 | INSERT INTO app_private.user_secrets (id, password_hash)
13 | VALUES (:user_secret_id, crypt(:password, gen_salt('bf')));
14 |
15 | INSERT INTO app_public.users (id, user_secret_id, username)
16 | VALUES (:user_id, :user_secret_id, :username);
17 |
18 | INSERT INTO app_hidden.user_emails (user_id, email, is_verified)
19 | VALUES (:user_id, :email, true);
20 |
21 | set local role :role;
22 | select is(current_user, :role);
23 |
24 | prepare actual as
25 | select id from app_private.web_login(:email, :password);
26 |
27 | prepare expected as values
28 | (:user_id::uuid);
29 |
30 | select set_eq(
31 | 'actual',
32 | 'expected'
33 | );
34 |
35 | select finish();
36 |
37 | rollback;
38 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/A.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.A (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 | import Example.DeeplyNested.B as B
8 | import Example.DeeplyNested.C as C
9 | import Data.Const (Const)
10 | import Type.Proxy (Proxy(..))
11 |
12 | type State = Unit
13 |
14 | data Action = Void
15 |
16 | type ChildSlots =
17 | ( b :: H.Slot (Const Void) Void Unit
18 | , c :: H.Slot (Const Void) Void Unit
19 | )
20 |
21 | _b :: Proxy "b"
22 | _b = Proxy
23 |
24 | _c :: Proxy "c"
25 | _c = Proxy
26 |
27 | component :: forall q i o m. H.Component q i o m
28 | component =
29 | H.mkComponent
30 | { initialState: const unit
31 | , render
32 | , eval: H.mkEval H.defaultEval
33 | }
34 |
35 | render :: forall m. State -> H.ComponentHTML Action ChildSlots m
36 | render state =
37 | HH.ul_
38 | [ HH.li_ [ HH.text "a" ]
39 | , HH.li_ [ HH.slot _b unit B.component unit absurd ]
40 | , HH.li_ [ HH.slot _c unit C.component unit absurd ]
41 | , HH.li_ [ HH.text "a end" ]
42 | ]
43 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/deeply-nested/src/B.purs:
--------------------------------------------------------------------------------
1 | module Example.DeeplyNested.B (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 | import Example.DeeplyNested.D as D
8 | import Example.DeeplyNested.E as E
9 | import Data.Const (Const)
10 | import Type.Proxy (Proxy(..))
11 |
12 | type State = Unit
13 |
14 | data Action = Void
15 |
16 | type ChildSlots =
17 | ( d :: H.Slot (Const Void) Void Unit
18 | , e :: H.Slot (Const Void) Void Unit
19 | )
20 |
21 | _d :: Proxy "d"
22 | _d = Proxy
23 |
24 | _e :: Proxy "e"
25 | _e = Proxy
26 |
27 | component :: forall q i o m. H.Component q i o m
28 | component =
29 | H.mkComponent
30 | { initialState: const unit
31 | , render
32 | , eval: H.mkEval H.defaultEval
33 | }
34 |
35 | render :: forall m. State -> H.ComponentHTML Action ChildSlots m
36 | render state =
37 | HH.ul_
38 | [ HH.li_ [ HH.text "b" ]
39 | , HH.li_ [ HH.slot _d unit D.component unit absurd ]
40 | , HH.li_ [ HH.slot _e unit E.component unit absurd ]
41 | , HH.li_ [ HH.text "b end" ]
42 | ]
43 |
--------------------------------------------------------------------------------
/nix/pkgs/wait-for-postgres/wait-for-postgres:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | # idea stolen from https://gist.github.com/nicerobot/1136dcfba6ce3da67ce3ded5101a4078
4 |
5 | # USAGE
6 | # ./wait-for-postgres postgres://$LOGIN:$PASSWORD@$HOST:$PORT/$DATABASE
7 |
8 | # Retries a command on failure (idea stolen from http://fahdshariff.blogspot.com/2014/02/retrying-commands-in-shell-scripts.html).
9 | # $1 - the max number of attempts
10 | # $2 - the seconds to sleep
11 | # $3... - the command to run
12 | retry() {
13 | max_attempts="$1"; shift
14 | seconds="$1"; shift
15 | cmd="$@"
16 | attempt_num=1
17 |
18 | until $cmd
19 | do
20 | if [ $attempt_num -eq $max_attempts ]
21 | then
22 | echo "Attempt $attempt_num failed and there are no more attempts left!"
23 | return 1
24 | else
25 | echo "Attempt $attempt_num failed! Trying again in $seconds seconds..."
26 | attempt_num=`expr "$attempt_num" + 1`
27 | sleep "$seconds"
28 | fi
29 | done
30 | }
31 |
32 | retry 5 1 psql -c '\l' ${@} >/dev/null
33 |
34 | echo >&2 "$(date +%Y%m%dt%H%M%S) Postgres is up - executing command"
35 |
--------------------------------------------------------------------------------
/packages/client-halogen-examples/basic/src/Button.purs:
--------------------------------------------------------------------------------
1 | module Example.Basic.Button (component) where
2 |
3 | import Prelude
4 |
5 | import Halogen as H
6 | import Halogen.HTML as HH
7 | import Halogen.HTML.Events as HE
8 | import Halogen.HTML.Properties as HP
9 |
10 | type State = { enabled :: Boolean }
11 |
12 | data Action = Toggle
13 |
14 | component :: forall q i o m. H.Component q i o m
15 | component =
16 | H.mkComponent
17 | { initialState
18 | , render
19 | , eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
20 | }
21 |
22 | initialState :: forall i. i -> State
23 | initialState _ = { enabled: false }
24 |
25 | render :: forall m. State -> H.ComponentHTML Action () m
26 | render state =
27 | let
28 | label = if state.enabled then "On" else "Off"
29 | in
30 | HH.button
31 | [ HP.title label
32 | , HE.onClick \_ -> Toggle
33 | ]
34 | [ HH.text label ]
35 |
36 | handleAction ∷ forall o m. Action → H.HalogenM State Action () o m Unit
37 | handleAction = case _ of
38 | Toggle ->
39 | H.modify_ \st -> st { enabled = not st.enabled }
40 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/schemas/app_private.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_private'$$
3 |
4 | begin;
5 |
6 | select no_plan();
7 |
8 | select tables_are(
9 | :schema,
10 | array[
11 | 'user_authentication_secrets',
12 | 'user_secrets',
13 | 'user_sessions'
14 | ]::text[]
15 | );
16 |
17 | select types_are(:schema, array[]::text[]);
18 |
19 | select domains_are(:schema, array[]::text[]);
20 |
21 | select enums_are(:schema, array[]::text[]);
22 |
23 | select functions_are(
24 | :schema,
25 | array[
26 | 'tg__set_updated_at',
27 | 'link_or_register_user',
28 | 'web_login',
29 | 'really_create_user',
30 | 'register_user'
31 | /* 'tg_send_verification_email_for_user_email', */
32 | /* 'tg_user_email_secrets__insert_with_user_email', */
33 | /* 'tg_user_secrets__insert_with_user', */
34 | /* 'tg_users__make_first_user_admin' */
35 | ]::text[]
36 | );
37 |
38 | select views_are(
39 | :schema,
40 | array[]::text[]
41 | );
42 |
43 | select materialized_views_are(
44 | :schema,
45 | array[]::text[]
46 | );
47 |
48 | select finish();
49 |
50 | rollback;
51 |
--------------------------------------------------------------------------------
/packages/db-tests/tests-todo/tables/users_oauths/priviliges/app_owner.sql:
--------------------------------------------------------------------------------
1 |
2 | \set schema $$'app_public'$$
3 | \set table $$'user_oauths'$$
4 | \set role $$'app_owner'$$
5 |
6 | begin;
7 |
8 | select no_plan();
9 |
10 | SELECT table_privs_are(
11 | :schema,
12 | :table,
13 | :role,
14 | ARRAY[
15 | 'SELECT',
16 | 'DELETE'
17 | ]
18 | );
19 |
20 | -- TODO: what is this?
21 | SELECT any_column_privs_are(
22 | :schema,
23 | :table,
24 | :role,
25 | ARRAY[
26 | 'SELECT'
27 | ]
28 | );
29 |
30 | SELECT column_privs_are(:schema, :table, 'id', :role, ARRAY['SELECT']);
31 | SELECT column_privs_are(:schema, :table, 'user_id', :role, ARRAY['SELECT']);
32 | SELECT column_privs_are(:schema, :table, 'service', :role, ARRAY['SELECT']);
33 | SELECT column_privs_are(:schema, :table, 'service_identifier', :role, ARRAY['SELECT']);
34 | SELECT column_privs_are(:schema, :table, 'created_at', :role, ARRAY['SELECT']);
35 | SELECT column_privs_are(:schema, :table, 'updated_at', :role, ARRAY['SELECT']);
36 |
37 | select finish();
38 |
39 | rollback;
40 |
--------------------------------------------------------------------------------
/packages/client/NextjsGraphqlApi/Object/PageInfo.purs:
--------------------------------------------------------------------------------
1 | module NextjsGraphqlApi.Object.PageInfo where
2 |
3 | import GraphQLClient
4 | (SelectionSet, selectionForField, graphqlDefaultResponseScalarDecoder)
5 | import NextjsGraphqlApi.Scopes (Scope__PageInfo)
6 | import Data.Maybe (Maybe)
7 | import NextjsGraphqlApi.Scalars (Cursor)
8 |
9 | endCursor :: SelectionSet Scope__PageInfo (Maybe Cursor)
10 | endCursor = selectionForField "endCursor" [] graphqlDefaultResponseScalarDecoder
11 |
12 | hasNextPage :: SelectionSet Scope__PageInfo Boolean
13 | hasNextPage = selectionForField
14 | "hasNextPage"
15 | []
16 | graphqlDefaultResponseScalarDecoder
17 |
18 | hasPreviousPage :: SelectionSet Scope__PageInfo Boolean
19 | hasPreviousPage = selectionForField
20 | "hasPreviousPage"
21 | []
22 | graphqlDefaultResponseScalarDecoder
23 |
24 | startCursor :: SelectionSet Scope__PageInfo (Maybe Cursor)
25 | startCursor = selectionForField
26 | "startCursor"
27 | []
28 | graphqlDefaultResponseScalarDecoder
29 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/reset_password/error_when_token_not_exists.sql_:
--------------------------------------------------------------------------------
1 |
2 |
3 | \set role $$'app_owner'$$
4 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
5 | \set email $$'user@mail.com'$$
6 | \set password $$'secret_pass'$$
7 | \set token $$'some-token'$$
8 | \set new_password $$'new_secret_pass'$$
9 |
10 | begin;
11 |
12 | select no_plan();
13 |
14 | select pgtest.spy('app_private', 'rabbitmq__send_password_was_changed_mail', ARRAY['app_public.users']);
15 |
16 | -- Test body
17 | set local role :role;
18 | select is(current_user, :role);
19 |
20 | prepare do_stuff as
21 | select app_public.reset_password(:token, :new_password);
22 |
23 | select throws_ok(
24 | 'do_stuff',
25 | 'APP_EXCEPTION__RESET_PASSWORD__TOKEN_IS_INVALID'
26 | );
27 |
28 | -- Test body END
29 |
30 | -- Check app_private.rabbitmq__reset_password has not been called
31 |
32 | set local role 'app_owner';
33 |
34 | select pgtest.assert_called(pgtest.get_mock_id('app_private', 'rabbitmq__send_password_was_changed_mail', ARRAY['app_public.users']), 0);
35 |
36 | select finish();
37 |
38 | rollback;
39 |
--------------------------------------------------------------------------------
/packages/client-webpack/NextjsWebpack/FaviconsConfig.purs:
--------------------------------------------------------------------------------
1 | module NextjsWebpack.FaviconsConfig where
2 |
3 | import Data.Nullable as Nullable
4 | import Favicons (FaviconsConfig)
5 |
6 | faviconsConfig :: Boolean -> FaviconsConfig
7 | faviconsConfig isProd =
8 | { path: "/"
9 | , appName: Nullable.notNull "Nextjs example app"
10 | , appShortName: Nullable.notNull "Nextjs"
11 | , appDescription: Nullable.notNull "Example application for the best framework"
12 | , developerName: Nullable.null
13 | , developerURL: Nullable.null
14 | , dir: "auto"
15 | , lang: "en-US"
16 | , background: "#fff"
17 | , theme_color: "#fff"
18 | , appleStatusBarStyle: "black-translucent"
19 | , display: "standalone"
20 | , orientation: "any"
21 | , scope: "/"
22 | , start_url: "/"
23 | , version: "1.0"
24 | , logging: false
25 | , pixel_art: false
26 | , loadManifestWithCredentials: false
27 | , icons:
28 | { android: isProd
29 | , appleIcon: false
30 | , appleStartup: false
31 | , coast: false
32 | , favicons: isProd
33 | , firefox: isProd
34 | , windows: false
35 | , yandex: false
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/client-webpack/NextjsWebpack/WebpackConfig/SpagoOptions.purs:
--------------------------------------------------------------------------------
1 | module NextjsWebpack.WebpackConfig.SpagoOptions where
2 |
3 | import Protolude
4 | import Data.String as String
5 | import WebpackSpagoLoader (SpagoOptions, getAbsoluteOutputDirFromSpago, getSourcesFromSpago)
6 | import Effect.Uncurried (runEffectFn1)
7 | import Pathy (Abs, File, Path)
8 | import PathyExtra (printPathPosixSandboxAny)
9 |
10 | spagoOptions :: Path Abs File -> Effect SpagoOptions
11 | spagoOptions spagoDhall = do
12 | let
13 | spagoDhall' = printPathPosixSandboxAny spagoDhall
14 | output <- runEffectFn1 getAbsoluteOutputDirFromSpago spagoDhall'
15 | pursFiles <- runEffectFn1 getSourcesFromSpago spagoDhall'
16 | pure
17 | { output
18 | , pursFiles
19 | , compiler: "psa"
20 | -- note that warnings are shown only when file is recompiled, delete output folder to show all warnings
21 | , compilerOptions:
22 | { censorCodes:
23 | String.joinWith ","
24 | [ "ImplicitQualifiedImport"
25 | , "UnusedImport"
26 | , "ImplicitImport"
27 | ]
28 | -- strict: true
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/db-tests/tests/actions/resend_confirmation/success.sql_:
--------------------------------------------------------------------------------
1 |
2 |
3 | \set role $$'app_owner'$$
4 | \set user_id $$'00000000-0000-0000-0000-000000000001'$$
5 | \set email $$'user@mail.com'$$
6 | \set password $$'secret_pass'$$
7 |
8 | begin;
9 |
10 | select no_plan();
11 |
12 | insert into app_public.users
13 | (id, email, first_name, last_name, is_confirmed, password_hash)
14 | values
15 | (:user_id, :email, random_string(), random_string(), false, crypt(:password, gen_salt('bf')));
16 |
17 | -- Spy
18 |
19 | select pgtest.spy('app_private', 'rabbitmq__send_confirmation_mail', ARRAY['app_public.users']);
20 |
21 | -- Spy END
22 |
23 | -- Test body
24 | set local role :role;
25 | select is(current_user, :role);
26 |
27 | prepare do_stuff as
28 | select app_public.resend_confirmation(:email);
29 |
30 | select lives_ok('do_stuff');
31 |
32 | -- Test body END
33 |
34 | -- Check function has been called
35 |
36 | set local role 'app_owner';
37 |
38 | select pgtest.assert_called(pgtest.get_mock_id('app_private', 'rabbitmq__send_confirmation_mail', ARRAY['app_public.users']), 1);
39 |
40 | select finish();
41 |
42 | rollback;
43 |
--------------------------------------------------------------------------------
/packages/src/SimpleXMLWithIndentation.purs:
--------------------------------------------------------------------------------
1 | module SimpleXMLWithIndentation where
2 |
3 | import Protolude
4 | import Data.String.Yarn (unlines) as String
5 | import Data.String.Common (joinWith) as String
6 |
7 | indent :: String -> String
8 | indent x = " " <> x
9 |
10 | unlinesIndent :: Array String -> String
11 | unlinesIndent = String.unlines <<< map indent
12 |
13 | tagStart :: String -> String
14 | tagStart x = "<" <> x <> ">"
15 |
16 | tagEnd :: String -> String
17 | tagEnd x = "" <> x <> ">"
18 |
19 | printProp :: Tuple String String -> String
20 | printProp (name /\ val) = name <> "=\"" <> val <> "\""
21 |
22 | printProps :: Array (Tuple String String) -> String
23 | printProps = String.joinWith " " <<< map printProp
24 |
25 | tagOneline :: String -> Array (String /\ String) -> String -> String
26 | tagOneline tagName props content = tagStart (tagName <> " " <> printProps props) <> content <> tagEnd tagName
27 |
28 | tagMultiLine :: String -> Array (String /\ String) -> Array String -> String
29 | tagMultiLine tagName props content = String.unlines $ [ tagStart (tagName <> " " <> printProps props), unlinesIndent content, tagEnd tagName ]
30 |
--------------------------------------------------------------------------------