├── .ci.npmrc ├── .editorconfig ├── .eslintrc.js ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── .gitpod.yml ├── .husky ├── .gitignore └── pre-commit ├── .prettierrc.js ├── .vscode ├── common-imports.code-snippets ├── launch.json ├── morphic.code-snippets ├── newtype.code-snippets ├── operators.code-snippets └── settings.json ├── .yarn ├── patches │ └── eslint-plugin-codegen.patch ├── plugins │ └── @yarnpkg │ │ ├── plugin-interactive-tools.cjs │ │ └── plugin-typescript.cjs └── releases │ └── yarn-3.2.0.cjs ├── .yarnrc.yml ├── LICENSE.md ├── README.md ├── codecov.yml ├── jest.config.js ├── lerna.json ├── package.json ├── packages ├── .placeholder └── express │ ├── .babel.cjs.json │ ├── .babel.mjs.json │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ └── index.ts │ ├── test │ └── index.test.ts │ ├── tsconfig.build.esm.json │ └── tsconfig.json ├── pre-commit.sh ├── scripts └── jest-setup.ts ├── tsconfig.base.json ├── tsconfig.jest.json ├── tsconfig.json └── yarn.lock /.ci.npmrc: -------------------------------------------------------------------------------- 1 | //registry.npmjs.org/:_authToken=${NPM_TOKEN} -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | module.exports = { 3 | ignorePatterns: ["build", "dist"], 4 | parser: "@typescript-eslint/parser", 5 | parserOptions: { 6 | ecmaVersion: 2018, 7 | sourceType: "module" 8 | }, 9 | settings: { 10 | "import/parsers": { 11 | "@typescript-eslint/parser": [".ts", ".tsx"] 12 | }, 13 | "import/resolver": { 14 | typescript: { 15 | alwaysTryTypes: true 16 | } 17 | } 18 | }, 19 | extends: [ 20 | "eslint:recommended", 21 | "plugin:@typescript-eslint/eslint-recommended", 22 | "plugin:@typescript-eslint/recommended", 23 | "plugin:prettier/recommended" 24 | ], 25 | plugins: ["import", "sort-destructure-keys", "simple-import-sort", "codegen"], 26 | rules: { 27 | // codegen 28 | "codegen/codegen": "error", 29 | 30 | // eslint built-in rules, sorted alphabetically 31 | "no-fallthrough": "off", 32 | "no-irregular-whitespace": "off", 33 | "object-shorthand": "error", 34 | "prefer-destructuring": "off", 35 | "sort-imports": "off", 36 | 37 | // all other rules, sorted alphabetically 38 | "@typescript-eslint/ban-ts-comment": "off", 39 | "@typescript-eslint/ban-types": "off", 40 | "@typescript-eslint/camelcase": "off", 41 | "@typescript-eslint/consistent-type-imports": "error", 42 | "@typescript-eslint/explicit-function-return-type": "off", 43 | "@typescript-eslint/explicit-module-boundary-types": "off", 44 | "@typescript-eslint/interface-name-prefix": "off", 45 | "@typescript-eslint/no-empty-interface": "off", 46 | "@typescript-eslint/no-explicit-any": "off", 47 | "@typescript-eslint/no-unused-vars": "off", 48 | "@typescript-eslint/no-use-before-define": "off", 49 | "import/first": "error", 50 | "import/newline-after-import": "error", 51 | "import/no-duplicates": "error", 52 | "import/no-unresolved": "error", 53 | "import/order": "off", 54 | "simple-import-sort/imports": "error", 55 | "sort-destructure-keys/sort-destructure-keys": "error" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [mikearnaldi] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Use Node.js 12.x 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 12.x 18 | - name: npm install, build, and test 19 | run: | 20 | npm install -g yarn 21 | yarn 22 | yarn run ci 23 | cp .ci.npmrc .npmrc 24 | yarn lerna publish from-package --pre-dist-tag next --yes 25 | env: 26 | CI: "true" 27 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Use Node.js 12.x 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 12.x 18 | - name: npm install, build, and test 19 | run: | 20 | npm install -g yarn 21 | yarn 22 | yarn run ci 23 | env: 24 | CI: "true" 25 | 26 | - uses: codecov/codecov-action@v1.0.3 27 | with: 28 | token: ${{secrets.CODECOV_TOKEN}} 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.yarn/* 2 | !/.yarn/releases 3 | !/.yarn/patches 4 | !/.yarn/plugins 5 | !/.yarn/sdks 6 | 7 | lib/ 8 | node_modules/ 9 | .idea/ 10 | coverage/ 11 | yarn-error.log 12 | .npmrc 13 | .ionide/ 14 | .metals/ 15 | .ultra.cache.json 16 | tsbuildinfo/ 17 | del-tags.sh 18 | incubation/ -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: yarn && yarn build 3 | github: 4 | prebuilds: 5 | addCheck: true 6 | vscode: 7 | extensions: 8 | - dbaeumer.vscode-eslint 9 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | sh pre-commit.sh -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | trailingComma: 'none', 4 | singleQuote: false, 5 | printWidth: 88, 6 | tabWidth: 2, 7 | endOfLine: 'auto' 8 | }; 9 | -------------------------------------------------------------------------------- /.vscode/common-imports.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Effect": { 3 | "prefix": "+T", 4 | "body": ["import * as T from \"@effect-ts/core/Effect\""], 5 | "description": "Effect as T" 6 | }, 7 | "Managed": { 8 | "prefix": "+M", 9 | "body": ["import * as M from \"@effect-ts/core/Effect/Managed\""], 10 | "description": "Managed as M" 11 | }, 12 | "Layer": { 13 | "prefix": "+L", 14 | "body": ["import * as L from \"@effect-ts/core/Effect/Layer\""], 15 | "description": "Layer as L" 16 | }, 17 | "Ref": { 18 | "prefix": "+Ref", 19 | "body": ["import * as Ref from \"@effect-ts/core/Effect/Ref\""], 20 | "description": "Ref" 21 | }, 22 | "RefM": { 23 | "prefix": "+RefM", 24 | "body": ["import * as RefM from \"@effect-ts/core/Effect/RefM\""], 25 | "description": "RefM" 26 | }, 27 | "Map": { 28 | "prefix": "+Map", 29 | "body": ["import * as Map from \"@effect-ts/core/Classic/Map\""], 30 | "description": "Map" 31 | }, 32 | "Array": { 33 | "prefix": "+A", 34 | "body": ["import * as A from \"@effect-ts/core/Classic/Array\""], 35 | "description": "Array as A" 36 | }, 37 | "Record": { 38 | "prefix": "+R", 39 | "body": ["import * as R from \"@effect-ts/core/Classic/Record\""], 40 | "description": "Record as R" 41 | }, 42 | "NonEmptyArray": { 43 | "prefix": "+NA", 44 | "body": ["import * as NA from \"@effect-ts/core/Classic/NonEmptyArray\""], 45 | "description": "NonEmptyArray as NA" 46 | }, 47 | "Prelude": { 48 | "prefix": "+P", 49 | "body": ["import * as P from \"@effect-ts/core/Prelude\""], 50 | "description": "Prelude as NA" 51 | }, 52 | "DSL": { 53 | "prefix": "+DSL", 54 | "body": ["import * as DSL from \"@effect-ts/core/Prelude/DSL\""], 55 | "description": "Prelude DSL as DSL" 56 | }, 57 | "Queue": { 58 | "prefix": "+Q", 59 | "body": ["import * as Q from \"@effect-ts/core/Effect/Queue\""], 60 | "description": "Queue as Q" 61 | }, 62 | "Semaphore": { 63 | "prefix": "+Q", 64 | "body": ["import * as Sem from \"@effect-ts/core/Effect/Semaphore\""], 65 | "description": "Semaphore as Sem" 66 | }, 67 | "Stream": { 68 | "prefix": "+S", 69 | "body": ["import * as S from \"@effect-ts/core/Effect/Stream\""], 70 | "description": "Semaphore as S" 71 | }, 72 | "Async": { 73 | "prefix": "+As", 74 | "body": ["import * as As from \"@effect-ts/core/Async\""], 75 | "description": "Async as As" 76 | }, 77 | "Sync": { 78 | "prefix": "+Sy", 79 | "body": ["import * as Sy from \"@effect-ts/core/Sync\""], 80 | "description": "Sync as Sy" 81 | }, 82 | "Either": { 83 | "prefix": "+E", 84 | "body": ["import * as E from \"@effect-ts/core/Classic/Either\""], 85 | "description": "Either as E" 86 | }, 87 | "Exit": { 88 | "prefix": "+Ex", 89 | "body": ["import * as Ex from \"@effect-ts/core/Effect/Exit\""], 90 | "description": "Exit as Ex" 91 | }, 92 | "Cause": { 93 | "prefix": "+C", 94 | "body": ["import * as C from \"@effect-ts/core/Effect/Cause\""], 95 | "description": "Cause as C" 96 | }, 97 | "Option": { 98 | "prefix": "+O", 99 | "body": ["import * as O from \"@effect-ts/core/Classic/Option\""], 100 | "description": "Option as O" 101 | }, 102 | "Fiber": { 103 | "prefix": "+F", 104 | "body": ["import * as F from \"@effect-ts/core/Effect/Fiber\""], 105 | "description": "Fiber as F" 106 | }, 107 | "Iso": { 108 | "prefix": "+Iso", 109 | "body": ["import * as Iso from \"@effect-ts/monocle/Iso\""], 110 | "description": "Iso as Iso" 111 | }, 112 | "Prism": { 113 | "prefix": "+Prism", 114 | "body": ["import * as Prism from \"@effect-ts/monocle/Prism\""], 115 | "description": "Prism as Prism" 116 | }, 117 | "Lens": { 118 | "prefix": "+Lens", 119 | "body": ["import * as Lens from \"@effect-ts/monocle/Lens\""], 120 | "description": "Lens as Lens" 121 | }, 122 | "Optional": { 123 | "prefix": "+Opt", 124 | "body": ["import * as Op from \"@effect-ts/monocle/Optional\""], 125 | "description": "Optional as Op" 126 | }, 127 | "Traversal": { 128 | "prefix": "+Tr", 129 | "body": ["import * as Tr from \"@effect-ts/monocle/Traversal\""], 130 | "description": "Traversal as Tr" 131 | }, 132 | "Newtype": { 133 | "prefix": "+NT", 134 | "body": ["import * as NT from \"@effect-ts/core/Newtype\""], 135 | "description": "Newtype as NT" 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "Jest All", 8 | "program": "${workspaceFolder}/node_modules/.bin/jest", 9 | "args": ["--runInBand"], 10 | "console": "integratedTerminal", 11 | "internalConsoleOptions": "neverOpen", 12 | "disableOptimisticBPs": true, 13 | "windows": { 14 | "program": "${workspaceFolder}/node_modules/jest/bin/jest", 15 | } 16 | }, 17 | { 18 | "type": "node", 19 | "request": "launch", 20 | "name": "Jest Current File", 21 | "program": "${workspaceFolder}/node_modules/.bin/jest", 22 | "args": [ 23 | "${fileBasenameNoExtension}", 24 | "--config", 25 | "jest.config.js" 26 | ], 27 | "console": "integratedTerminal", 28 | "internalConsoleOptions": "neverOpen", 29 | "disableOptimisticBPs": true, 30 | "windows": { 31 | "program": "${workspaceFolder}/node_modules/jest/bin/jest", 32 | } 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /.vscode/morphic.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Morphic opaque": { 3 | "prefix": "moo", 4 | "body": [ 5 | "export interface $1 extends MO.AType {}", 6 | "export interface $1E extends MO.EType {}", 7 | "export const $1 = MO.opaque<$1E, $1>()($1_)", 8 | "" 9 | ], 10 | "description": "Defines a Morphic opaque signature" 11 | }, 12 | "Morphic": { 13 | "prefix": "mo", 14 | "body": ["const $1_ = MO.make(F => F.$0 )", ""], 15 | "description": "Defines a Morphic interface" 16 | }, 17 | "Import Morphic": { 18 | "prefix": "+MO", 19 | "body": ["import * as MO from \"@effect-ts/morphic\""], 20 | "description": "Imports Morphic as MO" 21 | }, 22 | "Morphic Newtype": { 23 | "prefix": "mont", 24 | "body": [ 25 | "export interface $1 extends NT.Newtype<\"$1\", $2> {}", 26 | "", 27 | "export const $1Iso = Iso.newtype<$1>()", 28 | "", 29 | "export const $1 = MO.make((F) => F.newtypeIso($1Iso, F.$3()))", 30 | "" 31 | ], 32 | "description": "Defines a Morphic newtype via iso" 33 | }, 34 | "Morphic Newtype Prism": { 35 | "prefix": "mont-pri", 36 | "body": [ 37 | "export interface $1 extends NT.Newtype<\"$1\", $2> {}", 38 | "", 39 | "export const $1Prism = Prism.newtype<$1>((_) => $3)", 40 | "export const $1Iso = Iso.newtype<$1>()", 41 | "", 42 | "export const $1 = MO.make((F) => F.newtypePrism($1Prism, F.$4()))", 43 | "" 44 | ], 45 | "description": "Defines a Morphic newtype via prism" 46 | }, 47 | "Morphic interface": { 48 | "prefix": "moi", 49 | "body": [ 50 | "const $1_ = MO.make(F => F.interface({ $0 }, { name: \"$1\" }))", 51 | "", 52 | "export interface $1 extends MO.AType {}", 53 | "export interface $1E extends MO.EType {}", 54 | "export const $1 = MO.opaque<$1E, $1>()($1_)", 55 | "" 56 | ], 57 | "description": "Defines a Morphic interface" 58 | }, 59 | "Morphic intersection": { 60 | "prefix": "mo&", 61 | "body": [ 62 | "const $1_ = MO.make(F => F.intersection($0)({ name: \"$1\" }))", 63 | "", 64 | "export interface $1 extends MO.AType {}", 65 | "export interface $1E extends MO.EType {}", 66 | "export const $1 = MO.opaque<$1E, $1>()($1_)", 67 | "" 68 | ], 69 | "description": "Defines a Morphic intersection" 70 | }, 71 | "Morphic opaque for tagged unions": { 72 | "prefix": "mo|", 73 | "body": [ 74 | "export const $1 = MO.makeADT('$2')({ $3 })", 75 | "export type $1 = MO.AType", 76 | "" 77 | ], 78 | "description": "Defines a Morphic tagged union" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /.vscode/newtype.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Classic Newtype": { 3 | "prefix": "newtype", 4 | "body": [ 5 | "const $1_ = NT.typeDef<$0>()(\"@newtype/$1\")", 6 | "export interface $1 extends NT.TypeOf {}", 7 | "export const $1 = NT.newtype<$1>()($1_)" 8 | ], 9 | "description": "Defines a Morphic newtype via iso" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/operators.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Pipe Operator |": { 3 | "prefix": "|", 4 | "body": ["[\"|>\"]()"], 5 | "description": "Pipe Operator" 6 | }, 7 | "Flow Operator": { 8 | "prefix": ">", 9 | "body": ["[\">>\"]()"], 10 | "description": "Flow Operator" 11 | }, 12 | "Operators Import": { 13 | "prefix": "op", 14 | "body": ["import \"@effect-ts/core/Operators\""], 15 | "description": "Operators Import" 16 | }, 17 | "Gen Function": { 18 | "prefix": "gen", 19 | "body": ["function* (_) {}"], 20 | "description": "Generator FUnction with _ input" 21 | }, 22 | "Gen Function $": { 23 | "prefix": "gen$", 24 | "body": ["function* ($) {}"], 25 | "description": "Generator FUnction with _ input" 26 | }, 27 | "Gen Yield *": { 28 | "prefix": "!", 29 | "body": ["yield* _()"], 30 | "description": "Yield generator calling _()" 31 | }, 32 | "Gen Yield $": { 33 | "prefix": "$", 34 | "body": ["yield* $()"], 35 | "description": "Yield generator calling $()" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "editor.formatOnSave": true, 4 | "eslint.format.enable": true, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 7 | }, 8 | "[javascriptreact]": { 9 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 10 | }, 11 | "[typescript]": { 12 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 13 | }, 14 | "[typescriptreact]": { 15 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 16 | }, 17 | "prettier.disableLanguages": [ 18 | "javascript", 19 | "javascriptreact", 20 | "typescript", 21 | "typescriptreact" 22 | ], 23 | "eslint.validate": [ 24 | "markdown", 25 | "javascript", 26 | "typescript" 27 | ], 28 | "editor.codeActionsOnSave": { 29 | "source.fixAll.eslint": true 30 | }, 31 | "editor.quickSuggestions": { 32 | "other": true, 33 | "comments": false, 34 | "strings": false 35 | }, 36 | "editor.acceptSuggestionOnCommitCharacter": true, 37 | "editor.acceptSuggestionOnEnter": "on", 38 | "editor.quickSuggestionsDelay": 10, 39 | "editor.suggestOnTriggerCharacters": true, 40 | "editor.tabCompletion": "off", 41 | "editor.suggest.localityBonus": true, 42 | "editor.suggestSelection": "recentlyUsed", 43 | "editor.wordBasedSuggestions": true, 44 | "editor.parameterHints.enabled": true, 45 | "files.watcherExclude": { 46 | "**/target": true 47 | }, 48 | "files.insertFinalNewline": true 49 | } 50 | -------------------------------------------------------------------------------- /.yarn/patches/eslint-plugin-codegen.patch: -------------------------------------------------------------------------------- 1 | diff --git a/dist/presets/barrel.js b/dist/presets/barrel.js 2 | index 713ce15ee45a50f8dc0ba40457526dfaf597afca..1dde9eed565ee4dfe00aa371fc38a2e6e950cce5 100644 3 | --- a/dist/presets/barrel.js 4 | +++ b/dist/presets/barrel.js 5 | @@ -62,7 +62,7 @@ const barrel = ({ meta, options: opts }) => { 6 | .filter(f => path.resolve(cwd, f) !== path.resolve(meta.filename)) 7 | .map(f => `./${f}`.replace(/(\.\/)+\./g, '.')) 8 | .filter(file => ['.js', '.mjs', '.ts', '.tsx'].includes(path.extname(file))) 9 | - .map(f => f.replace(/\.\w+$/, '')); 10 | + .map(f => f.replace(/\.\w+$/, '') + ".js"); 11 | const expectedContent = io_ts_extra_1.match(opts.import) 12 | .case(undefined, () => { 13 | return relativeFiles.map(f => `export * from '${f}'`).join('\n'); 14 | -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-typescript.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | //prettier-ignore 3 | module.exports = { 4 | name: "@yarnpkg/plugin-typescript", 5 | factory: function (require) { 6 | var plugin=(()=>{var Ft=Object.create,H=Object.defineProperty,Bt=Object.defineProperties,Kt=Object.getOwnPropertyDescriptor,zt=Object.getOwnPropertyDescriptors,Gt=Object.getOwnPropertyNames,Q=Object.getOwnPropertySymbols,$t=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty,De=Object.prototype.propertyIsEnumerable;var Re=(e,t,r)=>t in e?H(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,u=(e,t)=>{for(var r in t||(t={}))ne.call(t,r)&&Re(e,r,t[r]);if(Q)for(var r of Q(t))De.call(t,r)&&Re(e,r,t[r]);return e},g=(e,t)=>Bt(e,zt(t)),Lt=e=>H(e,"__esModule",{value:!0});var R=(e,t)=>{var r={};for(var s in e)ne.call(e,s)&&t.indexOf(s)<0&&(r[s]=e[s]);if(e!=null&&Q)for(var s of Q(e))t.indexOf(s)<0&&De.call(e,s)&&(r[s]=e[s]);return r};var I=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Vt=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Qt=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Gt(t))!ne.call(e,s)&&s!=="default"&&H(e,s,{get:()=>t[s],enumerable:!(r=Kt(t,s))||r.enumerable});return e},C=e=>Qt(Lt(H(e!=null?Ft($t(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var xe=I(J=>{"use strict";Object.defineProperty(J,"__esModule",{value:!0});function _(e){let t=[...e.caches],r=t.shift();return r===void 0?ve():{get(s,n,a={miss:()=>Promise.resolve()}){return r.get(s,n,a).catch(()=>_({caches:t}).get(s,n,a))},set(s,n){return r.set(s,n).catch(()=>_({caches:t}).set(s,n))},delete(s){return r.delete(s).catch(()=>_({caches:t}).delete(s))},clear(){return r.clear().catch(()=>_({caches:t}).clear())}}}function ve(){return{get(e,t,r={miss:()=>Promise.resolve()}){return t().then(n=>Promise.all([n,r.miss(n)])).then(([n])=>n)},set(e,t){return Promise.resolve(t)},delete(e){return Promise.resolve()},clear(){return Promise.resolve()}}}J.createFallbackableCache=_;J.createNullCache=ve});var Ee=I(($s,qe)=>{qe.exports=xe()});var Te=I(ae=>{"use strict";Object.defineProperty(ae,"__esModule",{value:!0});function Jt(e={serializable:!0}){let t={};return{get(r,s,n={miss:()=>Promise.resolve()}){let a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);let o=s(),d=n&&n.miss||(()=>Promise.resolve());return o.then(y=>d(y)).then(()=>o)},set(r,s){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(s):s,Promise.resolve(s)},delete(r){return delete t[JSON.stringify(r)],Promise.resolve()},clear(){return t={},Promise.resolve()}}}ae.createInMemoryCache=Jt});var we=I((Vs,Me)=>{Me.exports=Te()});var Ce=I(M=>{"use strict";Object.defineProperty(M,"__esModule",{value:!0});function Xt(e,t,r){let s={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers(){return e===oe.WithinHeaders?s:{}},queryParameters(){return e===oe.WithinQueryParameters?s:{}}}}function Yt(e){let t=0,r=()=>(t++,new Promise(s=>{setTimeout(()=>{s(e(r))},Math.min(100*t,1e3))}));return e(r)}function ke(e,t=(r,s)=>Promise.resolve()){return Object.assign(e,{wait(r){return ke(e.then(s=>Promise.all([t(s,r),s])).then(s=>s[1]))}})}function Zt(e){let t=e.length-1;for(t;t>0;t--){let r=Math.floor(Math.random()*(t+1)),s=e[t];e[t]=e[r],e[r]=s}return e}function er(e,t){return Object.keys(t!==void 0?t:{}).forEach(r=>{e[r]=t[r](e)}),e}function tr(e,...t){let r=0;return e.replace(/%s/g,()=>encodeURIComponent(t[r++]))}var rr="4.2.0",sr=e=>()=>e.transporter.requester.destroy(),oe={WithinQueryParameters:0,WithinHeaders:1};M.AuthMode=oe;M.addMethods=er;M.createAuth=Xt;M.createRetryablePromise=Yt;M.createWaitablePromise=ke;M.destroy=sr;M.encode=tr;M.shuffle=Zt;M.version=rr});var F=I((Js,Ue)=>{Ue.exports=Ce()});var Ne=I(ie=>{"use strict";Object.defineProperty(ie,"__esModule",{value:!0});var nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};ie.MethodEnum=nr});var B=I((Ys,We)=>{We.exports=Ne()});var Ze=I(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});var He=B();function ce(e,t){let r=e||{},s=r.data||{};return Object.keys(r).forEach(n=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(n)===-1&&(s[n]=r[n])}),{data:Object.entries(s).length>0?s:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var X={Read:1,Write:2,Any:3},U={Up:1,Down:2,Timeouted:3},_e=2*60*1e3;function ue(e,t=U.Up){return g(u({},e),{status:t,lastUpdate:Date.now()})}function Fe(e){return e.status===U.Up||Date.now()-e.lastUpdate>_e}function Be(e){return e.status===U.Timeouted&&Date.now()-e.lastUpdate<=_e}function le(e){return{protocol:e.protocol||"https",url:e.url,accept:e.accept||X.Any}}function ar(e,t){return Promise.all(t.map(r=>e.get(r,()=>Promise.resolve(ue(r))))).then(r=>{let s=r.filter(d=>Fe(d)),n=r.filter(d=>Be(d)),a=[...s,...n],o=a.length>0?a.map(d=>le(d)):t;return{getTimeout(d,y){return(n.length===0&&d===0?1:n.length+3+d)*y},statelessHosts:o}})}var or=({isTimedOut:e,status:t})=>!e&&~~t==0,ir=e=>{let t=e.status;return e.isTimedOut||or(e)||~~(t/100)!=2&&~~(t/100)!=4},cr=({status:e})=>~~(e/100)==2,ur=(e,t)=>ir(e)?t.onRetry(e):cr(e)?t.onSucess(e):t.onFail(e);function Qe(e,t,r,s){let n=[],a=$e(r,s),o=Le(e,s),d=r.method,y=r.method!==He.MethodEnum.Get?{}:u(u({},r.data),s.data),b=u(u(u({"x-algolia-agent":e.userAgent.value},e.queryParameters),y),s.queryParameters),f=0,p=(h,S)=>{let O=h.pop();if(O===void 0)throw Ve(de(n));let P={data:a,headers:o,method:d,url:Ge(O,r.path,b),connectTimeout:S(f,e.timeouts.connect),responseTimeout:S(f,s.timeout)},x=j=>{let T={request:P,response:j,host:O,triesLeft:h.length};return n.push(T),T},v={onSucess:j=>Ke(j),onRetry(j){let T=x(j);return j.isTimedOut&&f++,Promise.all([e.logger.info("Retryable failure",pe(T)),e.hostsCache.set(O,ue(O,j.isTimedOut?U.Timeouted:U.Down))]).then(()=>p(h,S))},onFail(j){throw x(j),ze(j,de(n))}};return e.requester.send(P).then(j=>ur(j,v))};return ar(e.hostsCache,t).then(h=>p([...h.statelessHosts].reverse(),h.getTimeout))}function lr(e){let{hostsCache:t,logger:r,requester:s,requestsCache:n,responsesCache:a,timeouts:o,userAgent:d,hosts:y,queryParameters:b,headers:f}=e,p={hostsCache:t,logger:r,requester:s,requestsCache:n,responsesCache:a,timeouts:o,userAgent:d,headers:f,queryParameters:b,hosts:y.map(h=>le(h)),read(h,S){let O=ce(S,p.timeouts.read),P=()=>Qe(p,p.hosts.filter(j=>(j.accept&X.Read)!=0),h,O);if((O.cacheable!==void 0?O.cacheable:h.cacheable)!==!0)return P();let v={request:h,mappedRequestOptions:O,transporter:{queryParameters:p.queryParameters,headers:p.headers}};return p.responsesCache.get(v,()=>p.requestsCache.get(v,()=>p.requestsCache.set(v,P()).then(j=>Promise.all([p.requestsCache.delete(v),j]),j=>Promise.all([p.requestsCache.delete(v),Promise.reject(j)])).then(([j,T])=>T)),{miss:j=>p.responsesCache.set(v,j)})},write(h,S){return Qe(p,p.hosts.filter(O=>(O.accept&X.Write)!=0),h,ce(S,p.timeouts.write))}};return p}function dr(e){let t={value:`Algolia for JavaScript (${e})`,add(r){let s=`; ${r.segment}${r.version!==void 0?` (${r.version})`:""}`;return t.value.indexOf(s)===-1&&(t.value=`${t.value}${s}`),t}};return t}function Ke(e){try{return JSON.parse(e.content)}catch(t){throw Je(t.message,e)}}function ze({content:e,status:t},r){let s=e;try{s=JSON.parse(e).message}catch(n){}return Xe(s,t,r)}function pr(e,...t){let r=0;return e.replace(/%s/g,()=>encodeURIComponent(t[r++]))}function Ge(e,t,r){let s=Ye(r),n=`${e.protocol}://${e.url}/${t.charAt(0)==="/"?t.substr(1):t}`;return s.length&&(n+=`?${s}`),n}function Ye(e){let t=r=>Object.prototype.toString.call(r)==="[object Object]"||Object.prototype.toString.call(r)==="[object Array]";return Object.keys(e).map(r=>pr("%s=%s",r,t(e[r])?JSON.stringify(e[r]):e[r])).join("&")}function $e(e,t){if(e.method===He.MethodEnum.Get||e.data===void 0&&t.data===void 0)return;let r=Array.isArray(e.data)?e.data:u(u({},e.data),t.data);return JSON.stringify(r)}function Le(e,t){let r=u(u({},e.headers),t.headers),s={};return Object.keys(r).forEach(n=>{let a=r[n];s[n.toLowerCase()]=a}),s}function de(e){return e.map(t=>pe(t))}function pe(e){let t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return g(u({},e),{request:g(u({},e.request),{headers:u(u({},e.request.headers),t)})})}function Xe(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}function Je(e,t){return{name:"DeserializationError",message:e,response:t}}function Ve(e){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:e}}A.CallEnum=X;A.HostStatusEnum=U;A.createApiError=Xe;A.createDeserializationError=Je;A.createMappedRequestOptions=ce;A.createRetryError=Ve;A.createStatefulHost=ue;A.createStatelessHost=le;A.createTransporter=lr;A.createUserAgent=dr;A.deserializeFailure=ze;A.deserializeSuccess=Ke;A.isStatefulHostTimeouted=Be;A.isStatefulHostUp=Fe;A.serializeData=$e;A.serializeHeaders=Le;A.serializeQueryParameters=Ye;A.serializeUrl=Ge;A.stackFrameWithoutCredentials=pe;A.stackTraceWithoutCredentials=de});var K=I((en,et)=>{et.exports=Ze()});var tt=I(w=>{"use strict";Object.defineProperty(w,"__esModule",{value:!0});var N=F(),mr=K(),z=B(),hr=e=>{let t=e.region||"us",r=N.createAuth(N.AuthMode.WithinHeaders,e.appId,e.apiKey),s=mr.createTransporter(g(u({hosts:[{url:`analytics.${t}.algolia.com`}]},e),{headers:u(g(u({},r.headers()),{"content-type":"application/json"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)})),n=e.appId;return N.addMethods({appId:n,transporter:s},e.methods)},yr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Post,path:"2/abtests",data:t},r),gr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Delete,path:N.encode("2/abtests/%s",t)},r),fr=e=>(t,r)=>e.transporter.read({method:z.MethodEnum.Get,path:N.encode("2/abtests/%s",t)},r),br=e=>t=>e.transporter.read({method:z.MethodEnum.Get,path:"2/abtests"},t),Pr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Post,path:N.encode("2/abtests/%s/stop",t)},r);w.addABTest=yr;w.createAnalyticsClient=hr;w.deleteABTest=gr;w.getABTest=fr;w.getABTests=br;w.stopABTest=Pr});var st=I((rn,rt)=>{rt.exports=tt()});var at=I(G=>{"use strict";Object.defineProperty(G,"__esModule",{value:!0});var me=F(),jr=K(),nt=B(),Or=e=>{let t=e.region||"us",r=me.createAuth(me.AuthMode.WithinHeaders,e.appId,e.apiKey),s=jr.createTransporter(g(u({hosts:[{url:`recommendation.${t}.algolia.com`}]},e),{headers:u(g(u({},r.headers()),{"content-type":"application/json"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)}));return me.addMethods({appId:e.appId,transporter:s},e.methods)},Ir=e=>t=>e.transporter.read({method:nt.MethodEnum.Get,path:"1/strategies/personalization"},t),Ar=e=>(t,r)=>e.transporter.write({method:nt.MethodEnum.Post,path:"1/strategies/personalization",data:t},r);G.createRecommendationClient=Or;G.getPersonalizationStrategy=Ir;G.setPersonalizationStrategy=Ar});var it=I((nn,ot)=>{ot.exports=at()});var jt=I(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});var l=F(),q=K(),m=B(),Sr=require("crypto");function Y(e){let t=r=>e.request(r).then(s=>{if(e.batch!==void 0&&e.batch(s.hits),!e.shouldStop(s))return s.cursor?t({cursor:s.cursor}):t({page:(r.page||0)+1})});return t({})}var Dr=e=>{let t=e.appId,r=l.createAuth(e.authMode!==void 0?e.authMode:l.AuthMode.WithinHeaders,t,e.apiKey),s=q.createTransporter(g(u({hosts:[{url:`${t}-dsn.algolia.net`,accept:q.CallEnum.Read},{url:`${t}.algolia.net`,accept:q.CallEnum.Write}].concat(l.shuffle([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}]))},e),{headers:u(g(u({},r.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)})),n={transporter:s,appId:t,addAlgoliaAgent(a,o){s.userAgent.add({segment:a,version:o})},clearCache(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then(()=>{})}};return l.addMethods(n,e.methods)};function ct(){return{name:"MissingObjectIDError",message:"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option."}}function ut(){return{name:"ObjectNotFoundError",message:"Object not found."}}function lt(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Rr=e=>(t,r)=>{let d=r||{},{queryParameters:s}=d,n=R(d,["queryParameters"]),a=u({acl:t},s!==void 0?{queryParameters:s}:{}),o=(y,b)=>l.createRetryablePromise(f=>$(e)(y.key,b).catch(p=>{if(p.status!==404)throw p;return f()}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:"1/keys",data:a},n),o)},vr=e=>(t,r,s)=>{let n=q.createMappedRequestOptions(s);return n.queryParameters["X-Algolia-User-ID"]=t,e.transporter.write({method:m.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:r}},n)},xr=e=>(t,r,s)=>e.transporter.write({method:m.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:t,cluster:r}},s),Z=e=>(t,r,s)=>{let n=(a,o)=>L(e)(t,{methods:{waitTask:D}}).waitTask(a.taskID,o);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",t),data:{operation:"copy",destination:r}},s),n)},qr=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Rules]})),Er=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Settings]})),Tr=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Synonyms]})),Mr=e=>(t,r)=>{let s=(n,a)=>l.createRetryablePromise(o=>$(e)(t,a).then(o).catch(d=>{if(d.status!==404)throw d}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/keys/%s",t)},r),s)},wr=()=>(e,t)=>{let r=q.serializeQueryParameters(t),s=Sr.createHmac("sha256",e).update(r).digest("hex");return Buffer.from(s+r).toString("base64")},$=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/keys/%s",t)},r),kr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/logs"},t),Cr=()=>e=>{let t=Buffer.from(e,"base64").toString("ascii"),r=/validUntil=(\d+)/,s=t.match(r);if(s===null)throw lt();return parseInt(s[1],10)-Math.round(new Date().getTime()/1e3)},Ur=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping/top"},t),Nr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/clusters/mapping/%s",t)},r),Wr=e=>t=>{let n=t||{},{retrieveMappings:r}=n,s=R(n,["retrieveMappings"]);return r===!0&&(s.getClusters=!0),e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping/pending"},s)},L=e=>(t,r={})=>{let s={transporter:e.transporter,appId:e.appId,indexName:t};return l.addMethods(s,r.methods)},Hr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/keys"},t),_r=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters"},t),Fr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/indexes"},t),Br=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping"},t),Kr=e=>(t,r,s)=>{let n=(a,o)=>L(e)(t,{methods:{waitTask:D}}).waitTask(a.taskID,o);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",t),data:{operation:"move",destination:r}},s),n)},zr=e=>(t,r)=>{let s=(n,a)=>Promise.all(Object.keys(n.taskID).map(o=>L(e)(o,{methods:{waitTask:D}}).waitTask(n.taskID[o],a)));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:t}},r),s)},Gr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:t}},r),$r=e=>(t,r)=>{let s=t.map(n=>g(u({},n),{params:q.serializeQueryParameters(n.params||{})}));return e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:s},cacheable:!0},r)},Lr=e=>(t,r)=>Promise.all(t.map(s=>{let d=s.params,{facetName:n,facetQuery:a}=d,o=R(d,["facetName","facetQuery"]);return L(e)(s.indexName,{methods:{searchForFacetValues:dt}}).searchForFacetValues(n,a,u(u({},r),o))})),Vr=e=>(t,r)=>{let s=q.createMappedRequestOptions(r);return s.queryParameters["X-Algolia-User-ID"]=t,e.transporter.write({method:m.MethodEnum.Delete,path:"1/clusters/mapping"},s)},Qr=e=>(t,r)=>{let s=(n,a)=>l.createRetryablePromise(o=>$(e)(t,a).catch(d=>{if(d.status!==404)throw d;return o()}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/keys/%s/restore",t)},r),s)},Jr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:t}},r),Xr=e=>(t,r)=>{let s=Object.assign({},r),f=r||{},{queryParameters:n}=f,a=R(f,["queryParameters"]),o=n?{queryParameters:n}:{},d=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],y=p=>Object.keys(s).filter(h=>d.indexOf(h)!==-1).every(h=>p[h]===s[h]),b=(p,h)=>l.createRetryablePromise(S=>$(e)(t,h).then(O=>y(O)?Promise.resolve():S()));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Put,path:l.encode("1/keys/%s",t),data:o},a),b)},pt=e=>(t,r)=>{let s=(n,a)=>D(e)(n.taskID,a);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/batch",e.indexName),data:{requests:t}},r),s)},Yr=e=>t=>Y(g(u({},t),{shouldStop:r=>r.cursor===void 0,request:r=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/browse",e.indexName),data:r},t)})),Zr=e=>t=>{let r=u({hitsPerPage:1e3},t);return Y(g(u({},r),{shouldStop:s=>s.hits.lengthg(u({},n),{hits:n.hits.map(a=>(delete a._highlightResult,a))}))}}))},es=e=>t=>{let r=u({hitsPerPage:1e3},t);return Y(g(u({},r),{shouldStop:s=>s.hits.lengthg(u({},n),{hits:n.hits.map(a=>(delete a._highlightResult,a))}))}}))},te=e=>(t,r,s)=>{let y=s||{},{batchSize:n}=y,a=R(y,["batchSize"]),o={taskIDs:[],objectIDs:[]},d=(b=0)=>{let f=[],p;for(p=b;p({action:r,body:h})),a).then(h=>(o.objectIDs=o.objectIDs.concat(h.objectIDs),o.taskIDs.push(h.taskID),p++,d(p)))};return l.createWaitablePromise(d(),(b,f)=>Promise.all(b.taskIDs.map(p=>D(e)(p,f))))},ts=e=>t=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/clear",e.indexName)},t),(r,s)=>D(e)(r.taskID,s)),rs=e=>t=>{let a=t||{},{forwardToReplicas:r}=a,s=R(a,["forwardToReplicas"]),n=q.createMappedRequestOptions(s);return r&&(n.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/clear",e.indexName)},n),(o,d)=>D(e)(o.taskID,d))},ss=e=>t=>{let a=t||{},{forwardToReplicas:r}=a,s=R(a,["forwardToReplicas"]),n=q.createMappedRequestOptions(s);return r&&(n.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/clear",e.indexName)},n),(o,d)=>D(e)(o.taskID,d))},ns=e=>(t,r)=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/deleteByQuery",e.indexName),data:t},r),(s,n)=>D(e)(s.taskID,n)),as=e=>t=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s",e.indexName)},t),(r,s)=>D(e)(r.taskID,s)),os=e=>(t,r)=>l.createWaitablePromise(yt(e)([t],r).then(s=>({taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),yt=e=>(t,r)=>{let s=t.map(n=>({objectID:n}));return te(e)(s,k.DeleteObject,r)},is=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s/rules/%s",e.indexName,t)},a),(d,y)=>D(e)(d.taskID,y))},cs=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s/synonyms/%s",e.indexName,t)},a),(d,y)=>D(e)(d.taskID,y))},us=e=>t=>gt(e)(t).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),ls=e=>(t,r)=>{let y=r||{},{query:s,paginate:n}=y,a=R(y,["query","paginate"]),o=0,d=()=>ft(e)(s||"",g(u({},a),{page:o})).then(b=>{for(let[f,p]of Object.entries(b.hits))if(t(p))return{object:p,position:parseInt(f,10),page:o};if(o++,n===!1||o>=b.nbPages)throw ut();return d()});return d()},ds=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/%s",e.indexName,t)},r),ps=()=>(e,t)=>{for(let[r,s]of Object.entries(e.hits))if(s.objectID===t)return parseInt(r,10);return-1},ms=e=>(t,r)=>{let o=r||{},{attributesToRetrieve:s}=o,n=R(o,["attributesToRetrieve"]),a=t.map(d=>u({indexName:e.indexName,objectID:d},s?{attributesToRetrieve:s}:{}));return e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:a}},n)},hs=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/rules/%s",e.indexName,t)},r),gt=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/settings",e.indexName),data:{getVersion:2}},t),ys=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/synonyms/%s",e.indexName,t)},r),bt=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/task/%s",e.indexName,t.toString())},r),gs=e=>(t,r)=>l.createWaitablePromise(Pt(e)([t],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),Pt=e=>(t,r)=>{let o=r||{},{createIfNotExists:s}=o,n=R(o,["createIfNotExists"]),a=s?k.PartialUpdateObject:k.PartialUpdateObjectNoCreate;return te(e)(t,a,n)},fs=e=>(t,r)=>{let O=r||{},{safe:s,autoGenerateObjectIDIfNotExist:n,batchSize:a}=O,o=R(O,["safe","autoGenerateObjectIDIfNotExist","batchSize"]),d=(P,x,v,j)=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",P),data:{operation:v,destination:x}},j),(T,V)=>D(e)(T.taskID,V)),y=Math.random().toString(36).substring(7),b=`${e.indexName}_tmp_${y}`,f=he({appId:e.appId,transporter:e.transporter,indexName:b}),p=[],h=d(e.indexName,b,"copy",g(u({},o),{scope:["settings","synonyms","rules"]}));p.push(h);let S=(s?h.wait(o):h).then(()=>{let P=f(t,g(u({},o),{autoGenerateObjectIDIfNotExist:n,batchSize:a}));return p.push(P),s?P.wait(o):P}).then(()=>{let P=d(b,e.indexName,"move",o);return p.push(P),s?P.wait(o):P}).then(()=>Promise.all(p)).then(([P,x,v])=>({objectIDs:x.objectIDs,taskIDs:[P.taskID,...x.taskIDs,v.taskID]}));return l.createWaitablePromise(S,(P,x)=>Promise.all(p.map(v=>v.wait(x))))},bs=e=>(t,r)=>ye(e)(t,g(u({},r),{clearExistingRules:!0})),Ps=e=>(t,r)=>ge(e)(t,g(u({},r),{replaceExistingSynonyms:!0})),js=e=>(t,r)=>l.createWaitablePromise(he(e)([t],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),he=e=>(t,r)=>{let o=r||{},{autoGenerateObjectIDIfNotExist:s}=o,n=R(o,["autoGenerateObjectIDIfNotExist"]),a=s?k.AddObject:k.UpdateObject;if(a===k.UpdateObject){for(let d of t)if(d.objectID===void 0)return l.createWaitablePromise(Promise.reject(ct()))}return te(e)(t,a,n)},Os=e=>(t,r)=>ye(e)([t],r),ye=e=>(t,r)=>{let d=r||{},{forwardToReplicas:s,clearExistingRules:n}=d,a=R(d,["forwardToReplicas","clearExistingRules"]),o=q.createMappedRequestOptions(a);return s&&(o.queryParameters.forwardToReplicas=1),n&&(o.queryParameters.clearExistingRules=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/batch",e.indexName),data:t},o),(y,b)=>D(e)(y.taskID,b))},Is=e=>(t,r)=>ge(e)([t],r),ge=e=>(t,r)=>{let d=r||{},{forwardToReplicas:s,replaceExistingSynonyms:n}=d,a=R(d,["forwardToReplicas","replaceExistingSynonyms"]),o=q.createMappedRequestOptions(a);return s&&(o.queryParameters.forwardToReplicas=1),n&&(o.queryParameters.replaceExistingSynonyms=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/batch",e.indexName),data:t},o),(y,b)=>D(e)(y.taskID,b))},ft=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),dt=e=>(t,r,s)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},s),mt=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/search",e.indexName),data:{query:t}},r),ht=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/search",e.indexName),data:{query:t}},r),As=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Put,path:l.encode("1/indexes/%s/settings",e.indexName),data:t},a),(d,y)=>D(e)(d.taskID,y))},D=e=>(t,r)=>l.createRetryablePromise(s=>bt(e)(t,r).then(n=>n.status!=="published"?s():void 0)),Ss={AddObject:"addObject",Analytics:"analytics",Browser:"browse",DeleteIndex:"deleteIndex",DeleteObject:"deleteObject",EditSettings:"editSettings",ListIndexes:"listIndexes",Logs:"logs",Recommendation:"recommendation",Search:"search",SeeUnretrievableAttributes:"seeUnretrievableAttributes",Settings:"settings",Usage:"usage"},k={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject"},ee={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},Ds={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},Rs={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};i.ApiKeyACLEnum=Ss;i.BatchActionEnum=k;i.ScopeEnum=ee;i.StrategyEnum=Ds;i.SynonymEnum=Rs;i.addApiKey=Rr;i.assignUserID=vr;i.assignUserIDs=xr;i.batch=pt;i.browseObjects=Yr;i.browseRules=Zr;i.browseSynonyms=es;i.chunkedBatch=te;i.clearObjects=ts;i.clearRules=rs;i.clearSynonyms=ss;i.copyIndex=Z;i.copyRules=qr;i.copySettings=Er;i.copySynonyms=Tr;i.createBrowsablePromise=Y;i.createMissingObjectIDError=ct;i.createObjectNotFoundError=ut;i.createSearchClient=Dr;i.createValidUntilNotFoundError=lt;i.deleteApiKey=Mr;i.deleteBy=ns;i.deleteIndex=as;i.deleteObject=os;i.deleteObjects=yt;i.deleteRule=is;i.deleteSynonym=cs;i.exists=us;i.findObject=ls;i.generateSecuredApiKey=wr;i.getApiKey=$;i.getLogs=kr;i.getObject=ds;i.getObjectPosition=ps;i.getObjects=ms;i.getRule=hs;i.getSecuredApiKeyRemainingValidity=Cr;i.getSettings=gt;i.getSynonym=ys;i.getTask=bt;i.getTopUserIDs=Ur;i.getUserID=Nr;i.hasPendingMappings=Wr;i.initIndex=L;i.listApiKeys=Hr;i.listClusters=_r;i.listIndices=Fr;i.listUserIDs=Br;i.moveIndex=Kr;i.multipleBatch=zr;i.multipleGetObjects=Gr;i.multipleQueries=$r;i.multipleSearchForFacetValues=Lr;i.partialUpdateObject=gs;i.partialUpdateObjects=Pt;i.removeUserID=Vr;i.replaceAllObjects=fs;i.replaceAllRules=bs;i.replaceAllSynonyms=Ps;i.restoreApiKey=Qr;i.saveObject=js;i.saveObjects=he;i.saveRule=Os;i.saveRules=ye;i.saveSynonym=Is;i.saveSynonyms=ge;i.search=ft;i.searchForFacetValues=dt;i.searchRules=mt;i.searchSynonyms=ht;i.searchUserIDs=Jr;i.setSettings=As;i.updateApiKey=Xr;i.waitTask=D});var It=I((on,Ot)=>{Ot.exports=jt()});var At=I(re=>{"use strict";Object.defineProperty(re,"__esModule",{value:!0});function vs(){return{debug(e,t){return Promise.resolve()},info(e,t){return Promise.resolve()},error(e,t){return Promise.resolve()}}}var xs={Debug:1,Info:2,Error:3};re.LogLevelEnum=xs;re.createNullLogger=vs});var Dt=I((un,St)=>{St.exports=At()});var xt=I(fe=>{"use strict";Object.defineProperty(fe,"__esModule",{value:!0});var Rt=require("http"),vt=require("https"),qs=require("url");function Es(){let e={keepAlive:!0},t=new Rt.Agent(e),r=new vt.Agent(e);return{send(s){return new Promise(n=>{let a=qs.parse(s.url),o=a.query===null?a.pathname:`${a.pathname}?${a.query}`,d=u({agent:a.protocol==="https:"?r:t,hostname:a.hostname,path:o,method:s.method,headers:s.headers},a.port!==void 0?{port:a.port||""}:{}),y=(a.protocol==="https:"?vt:Rt).request(d,h=>{let S="";h.on("data",O=>S+=O),h.on("end",()=>{clearTimeout(f),clearTimeout(p),n({status:h.statusCode||0,content:S,isTimedOut:!1})})}),b=(h,S)=>setTimeout(()=>{y.abort(),n({status:0,content:S,isTimedOut:!0})},h*1e3),f=b(s.connectTimeout,"Connection timeout"),p;y.on("error",h=>{clearTimeout(f),clearTimeout(p),n({status:0,content:h.message,isTimedOut:!1})}),y.once("response",()=>{clearTimeout(f),p=b(s.responseTimeout,"Socket timeout")}),s.data!==void 0&&y.write(s.data),y.end()})},destroy(){return t.destroy(),r.destroy(),Promise.resolve()}}}fe.createNodeHttpRequester=Es});var Et=I((dn,qt)=>{qt.exports=xt()});var kt=I((pn,Tt)=>{"use strict";var Mt=Ee(),Ts=we(),W=st(),be=F(),Pe=it(),c=It(),Ms=Dt(),ws=Et(),ks=K();function wt(e,t,r){let s={appId:e,apiKey:t,timeouts:{connect:2,read:5,write:30},requester:ws.createNodeHttpRequester(),logger:Ms.createNullLogger(),responsesCache:Mt.createNullCache(),requestsCache:Mt.createNullCache(),hostsCache:Ts.createInMemoryCache(),userAgent:ks.createUserAgent(be.version).add({segment:"Node.js",version:process.versions.node})};return c.createSearchClient(g(u(u({},s),r),{methods:{search:c.multipleQueries,searchForFacetValues:c.multipleSearchForFacetValues,multipleBatch:c.multipleBatch,multipleGetObjects:c.multipleGetObjects,multipleQueries:c.multipleQueries,copyIndex:c.copyIndex,copySettings:c.copySettings,copyRules:c.copyRules,copySynonyms:c.copySynonyms,moveIndex:c.moveIndex,listIndices:c.listIndices,getLogs:c.getLogs,listClusters:c.listClusters,multipleSearchForFacetValues:c.multipleSearchForFacetValues,getApiKey:c.getApiKey,addApiKey:c.addApiKey,listApiKeys:c.listApiKeys,updateApiKey:c.updateApiKey,deleteApiKey:c.deleteApiKey,restoreApiKey:c.restoreApiKey,assignUserID:c.assignUserID,assignUserIDs:c.assignUserIDs,getUserID:c.getUserID,searchUserIDs:c.searchUserIDs,listUserIDs:c.listUserIDs,getTopUserIDs:c.getTopUserIDs,removeUserID:c.removeUserID,hasPendingMappings:c.hasPendingMappings,generateSecuredApiKey:c.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:c.getSecuredApiKeyRemainingValidity,destroy:be.destroy,initIndex:n=>a=>c.initIndex(n)(a,{methods:{batch:c.batch,delete:c.deleteIndex,getObject:c.getObject,getObjects:c.getObjects,saveObject:c.saveObject,saveObjects:c.saveObjects,search:c.search,searchForFacetValues:c.searchForFacetValues,waitTask:c.waitTask,setSettings:c.setSettings,getSettings:c.getSettings,partialUpdateObject:c.partialUpdateObject,partialUpdateObjects:c.partialUpdateObjects,deleteObject:c.deleteObject,deleteObjects:c.deleteObjects,deleteBy:c.deleteBy,clearObjects:c.clearObjects,browseObjects:c.browseObjects,getObjectPosition:c.getObjectPosition,findObject:c.findObject,exists:c.exists,saveSynonym:c.saveSynonym,saveSynonyms:c.saveSynonyms,getSynonym:c.getSynonym,searchSynonyms:c.searchSynonyms,browseSynonyms:c.browseSynonyms,deleteSynonym:c.deleteSynonym,clearSynonyms:c.clearSynonyms,replaceAllObjects:c.replaceAllObjects,replaceAllSynonyms:c.replaceAllSynonyms,searchRules:c.searchRules,getRule:c.getRule,deleteRule:c.deleteRule,saveRule:c.saveRule,saveRules:c.saveRules,replaceAllRules:c.replaceAllRules,browseRules:c.browseRules,clearRules:c.clearRules}}),initAnalytics:()=>n=>W.createAnalyticsClient(g(u(u({},s),n),{methods:{addABTest:W.addABTest,getABTest:W.getABTest,getABTests:W.getABTests,stopABTest:W.stopABTest,deleteABTest:W.deleteABTest}})),initRecommendation:()=>n=>Pe.createRecommendationClient(g(u(u({},s),n),{methods:{getPersonalizationStrategy:Pe.getPersonalizationStrategy,setPersonalizationStrategy:Pe.setPersonalizationStrategy}}))}}))}wt.version=be.version;Tt.exports=wt});var Ut=I((mn,je)=>{var Ct=kt();je.exports=Ct;je.exports.default=Ct});var Ws={};Vt(Ws,{default:()=>Ks});var Oe=C(require("@yarnpkg/core")),E=C(require("@yarnpkg/core")),Ie=C(require("@yarnpkg/plugin-essentials")),Ht=C(require("semver"));var se=C(require("@yarnpkg/core")),Nt=C(Ut()),Cs="e8e1bd300d860104bb8c58453ffa1eb4",Us="OFCNCOG2CU",Wt=async(e,t)=>{var a;let r=se.structUtils.stringifyIdent(e),n=Ns(t).initIndex("npm-search");try{return((a=(await n.getObject(r,{attributesToRetrieve:["types"]})).types)==null?void 0:a.ts)==="definitely-typed"}catch(o){return!1}},Ns=e=>(0,Nt.default)(Us,Cs,{requester:{async send(r){try{let s=await se.httpUtils.request(r.url,r.data||null,{configuration:e,headers:r.headers});return{content:s.body,isTimedOut:!1,status:s.statusCode}}catch(s){return{content:s.response.body,isTimedOut:!1,status:s.response.statusCode}}}}});var _t=e=>e.scope?`${e.scope}__${e.name}`:`${e.name}`,Hs=async(e,t,r,s)=>{if(r.scope==="types")return;let{project:n}=e,{configuration:a}=n,o=a.makeResolver(),d={project:n,resolver:o,report:new E.ThrowReport};if(!await Wt(r,a))return;let b=_t(r),f=E.structUtils.parseRange(r.range).selector;if(!E.semverUtils.validRange(f)){let P=await o.getCandidates(r,new Map,d);f=E.structUtils.parseRange(P[0].reference).selector}let p=Ht.default.coerce(f);if(p===null)return;let h=`${Ie.suggestUtils.Modifier.CARET}${p.major}`,S=E.structUtils.makeDescriptor(E.structUtils.makeIdent("types",b),h),O=E.miscUtils.mapAndFind(n.workspaces,P=>{var T,V;let x=(T=P.manifest.dependencies.get(r.identHash))==null?void 0:T.descriptorHash,v=(V=P.manifest.devDependencies.get(r.identHash))==null?void 0:V.descriptorHash;if(x!==r.descriptorHash&&v!==r.descriptorHash)return E.miscUtils.mapAndFind.skip;let j=[];for(let Ae of Oe.Manifest.allDependencies){let Se=P.manifest[Ae].get(S.identHash);typeof Se!="undefined"&&j.push([Ae,Se])}return j.length===0?E.miscUtils.mapAndFind.skip:j});if(typeof O!="undefined")for(let[P,x]of O)e.manifest[P].set(x.identHash,x);else{try{if((await o.getCandidates(S,new Map,d)).length===0)return}catch{return}e.manifest[Ie.suggestUtils.Target.DEVELOPMENT].set(S.identHash,S)}},_s=async(e,t,r)=>{if(r.scope==="types")return;let s=_t(r),n=E.structUtils.makeIdent("types",s);for(let a of Oe.Manifest.allDependencies)typeof e.manifest[a].get(n.identHash)!="undefined"&&e.manifest[a].delete(n.identHash)},Fs=(e,t)=>{t.publishConfig&&t.publishConfig.typings&&(t.typings=t.publishConfig.typings),t.publishConfig&&t.publishConfig.types&&(t.types=t.publishConfig.types)},Bs={hooks:{afterWorkspaceDependencyAddition:Hs,afterWorkspaceDependencyRemoval:_s,beforeWorkspacePacking:Fs}},Ks=Bs;return Ws;})(); 7 | return plugin; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs 5 | spec: "@yarnpkg/plugin-typescript" 6 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 7 | spec: "@yarnpkg/plugin-interactive-tools" 8 | 9 | yarnPath: .yarn/releases/yarn-3.2.0.cjs 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Michael Arnaldi. 2 | 3 | Copyright (c) 2020 Matechs Garage Ltd. 4 | 5 | Copyright (c) 2020 Matechs Holdings Ltd. 6 | 7 | Copyright (c) 2020 The Contributors. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Welcome to Effect-TS - Express 2 | 3 | Please follow up to: [https://github.com/Effect-TS/express/tree/master/packages/express](https://github.com/Effect-TS/express/tree/master/packages/express) 4 | 5 | ## Install (WIP) 6 | 7 | We recommend the usage of `yarn` and if you hf `yarn workspaces` that handles by default hoisting of dependencies: 8 | 9 | ```sh 10 | yarn add @effect-ts/express @effect-ts/core 11 | ``` 12 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: yes 4 | patch: no 5 | changes: no 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | rootDir: "./", 6 | clearMocks: true, 7 | collectCoverage: false, 8 | coverageDirectory: "coverage", 9 | collectCoverageFrom: ["packages/**/src/**/*.ts"], 10 | setupFiles: ["./scripts/jest-setup.ts"], 11 | modulePathIgnorePatterns: [ 12 | "/packages/.*/build", 13 | "/packages/.*/dist", 14 | "/packages/.*/compiler-debug", 15 | "/_tmp" 16 | ], 17 | verbose: true, 18 | globals: { 19 | "ts-jest": { 20 | tsconfig: "/tsconfig.jest.json", 21 | useESM: true 22 | } 23 | }, 24 | moduleNameMapper: { 25 | "^(\\.{1,2}/.*)\\.js$": "$1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*", 4 | "packages_be/*", 5 | "packages_fe/*", 6 | "packages_http/*", 7 | "packages_inc/*", 8 | "packages_sys/*" 9 | ], 10 | "npmClient": "yarn", 11 | "useWorkspaces": true, 12 | "version": "independent", 13 | "command": { 14 | "version": { 15 | "message": "chore(release): publish" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "effect-ts", 3 | "private": true, 4 | "repository": "https://github.com/Effect-TS/express.git", 5 | "workspaces": [ 6 | "packages/*", 7 | "incubation/*" 8 | ], 9 | "scripts": { 10 | "prepublishOnly": "yarn prettier --write \"./packages*/*/build/**/*.ts\"", 11 | "ci": "yarn run clean && yarn run build && yarn run tc && yarn run lint && yarn run test", 12 | "clean": "ultra -r clean", 13 | "build": "ultra -r build", 14 | "test": "jest --detectOpenHandles", 15 | "autofix": "ultra -r autofix", 16 | "lint": "ultra -r lint", 17 | "tc": "ultra -r tc", 18 | "postinstall": "husky install && ts-patch install -s", 19 | "version:alpha": "lerna version prerelease --conventional-commits --preid=alpha", 20 | "version:preminor": "lerna version preminor --conventional-commits", 21 | "version:minor": "lerna version minor --conventional-commits", 22 | "version:prepatch": "lerna version prepatch --conventional-commits", 23 | "version:patch": "lerna version patch --conventional-commits", 24 | "version:graduate": "lerna version --conventional-commits --conventional-graduate", 25 | "version": "yarn install && git stage yarn.lock", 26 | "commit": "cz", 27 | "ets:rimraf": "cd $INIT_CWD && rimraf", 28 | "ets:tsc": "cd $INIT_CWD && tsc", 29 | "ets:babel": "cd $INIT_CWD && babel", 30 | "ets:ts-node": "cd $INIT_CWD && ts-node", 31 | "ets:eslint": "cd $INIT_CWD && eslint", 32 | "ets:prettier": "cd $INIT_CWD && prettier", 33 | "ets:concurrently": "cd $INIT_CWD && concurrently", 34 | "ets:build-utils": "cd $INIT_CWD && build-utils", 35 | "ets:madge": "cd $INIT_CWD && madge" 36 | }, 37 | "config": { 38 | "commitizen": { 39 | "path": "cz-conventional-changelog" 40 | } 41 | }, 42 | "devDependencies": { 43 | "@babel/cli": "^7.17.6", 44 | "@babel/core": "^7.17.5", 45 | "@effect-ts/build-utils": "^0.38.2", 46 | "@effect-ts/core": "^0.58.0", 47 | "@effect-ts/tracing-plugin": "^0.19.0", 48 | "@types/cpx": "^1.5.2", 49 | "@types/express": "^4.17.13", 50 | "@types/glob": "^7.2.0", 51 | "@types/jest": "^27.4.1", 52 | "@types/node": "^17.0.21", 53 | "@types/rimraf": "^3.0.2", 54 | "@typescript-eslint/eslint-plugin": "^5.12.1", 55 | "@typescript-eslint/parser": "^5.12.1", 56 | "babel-plugin-annotate-pure-calls": "^0.4.0", 57 | "chalk": "^4.1.2", 58 | "concurrently": "^7.0.0", 59 | "cpx": "^1.5.0", 60 | "cz-conventional-changelog": "^3.3.0", 61 | "eslint": "^8.10.0", 62 | "eslint-config-prettier": "^8.4.0", 63 | "eslint-import-resolver-typescript": "^2.5.0", 64 | "eslint-plugin-codegen": "^0.16.1", 65 | "eslint-plugin-import": "^2.25.4", 66 | "eslint-plugin-jest": "^26.1.1", 67 | "eslint-plugin-prettier": "^4.0.0", 68 | "eslint-plugin-simple-import-sort": "^7.0.0", 69 | "eslint-plugin-sort-destructure-keys": "^1.4.0", 70 | "express": "^4.17.3", 71 | "fast-check": "^2.22.0", 72 | "fast-equals": "^3.0.0", 73 | "fast-safe-stringify": "^2.1.1", 74 | "glob": "^7.2.0", 75 | "husky": "7.0.4", 76 | "isomorphic-fetch": "^3.0.0", 77 | "jest": "^27.5.1", 78 | "lerna": "^4.0.0", 79 | "prettier": "^2.5.1", 80 | "reflect-metadata": "^0.1.13", 81 | "rimraf": "^3.0.2", 82 | "ts-jest": "^27.1.3", 83 | "ts-node": "^10.5.0", 84 | "typescript": "4.5.5", 85 | "ultra-runner": "^3.10.5", 86 | "yarn-deduplicate": "^3.1.0" 87 | }, 88 | "packageManager": "yarn@3.2.0", 89 | "dependencies": { 90 | "@babel/plugin-transform-modules-commonjs": "^7.16.8", 91 | "babel-plugin-replace-import-extension": "^1.1.2", 92 | "ts-patch": "^2.0.1" 93 | }, 94 | "resolutions": { 95 | "eslint-plugin-codegen": "patch:eslint-plugin-codegen@0.16.1#.yarn/patches/eslint-plugin-codegen.patch" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /packages/.placeholder: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------- /packages/express/.babel.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | [ 4 | "@babel/transform-modules-commonjs" 5 | ], 6 | [ 7 | "annotate-pure-calls" 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/express/.babel.mjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | [ 4 | "replace-import-extension", 5 | { 6 | "extMapping": { 7 | ".js": ".mjs" 8 | } 9 | } 10 | ], 11 | [ 12 | "annotate-pure-calls" 13 | ] 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/express/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | scripts/merge.ts 4 | scripts/genp.ts 5 | bench/ 6 | -------------------------------------------------------------------------------- /packages/express/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.25.1](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.25.0...@effect-ts/express@0.25.1) (2022-02-26) 7 | 8 | **Note:** Version bump only for package @effect-ts/express 9 | 10 | 11 | 12 | 13 | 14 | # [0.25.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.24.0...@effect-ts/express@0.25.0) (2022-02-26) 15 | 16 | **Note:** Version bump only for package @effect-ts/express 17 | 18 | 19 | 20 | 21 | 22 | # [0.24.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.23.0...@effect-ts/express@0.24.0) (2021-12-02) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * replace deprecated setKey calls ([#302](https://github.com/Effect-TS/express/issues/302)) ([fe99916](https://github.com/Effect-TS/express/commit/fe999162ff9139abdeaaf758aa32ad2e576d84dd)) 28 | 29 | 30 | 31 | 32 | 33 | # [0.23.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.22.0...@effect-ts/express@0.23.0) (2021-11-26) 34 | 35 | **Note:** Version bump only for package @effect-ts/express 36 | 37 | 38 | 39 | 40 | 41 | # [0.22.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.21.0...@effect-ts/express@0.22.0) (2021-11-24) 42 | 43 | **Note:** Version bump only for package @effect-ts/express 44 | 45 | 46 | 47 | 48 | 49 | # [0.21.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.20.3...@effect-ts/express@0.21.0) (2021-10-04) 50 | 51 | **Note:** Version bump only for package @effect-ts/express 52 | 53 | 54 | 55 | 56 | 57 | ## [0.20.3](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.20.2...@effect-ts/express@0.20.3) (2021-06-26) 58 | 59 | **Note:** Version bump only for package @effect-ts/express 60 | 61 | 62 | 63 | 64 | 65 | ## [0.20.2](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.20.1...@effect-ts/express@0.20.2) (2021-06-11) 66 | 67 | 68 | ### Bug Fixes 69 | 70 | * **express:** destroy open connections ([0161323](https://github.com/Effect-TS/express/commit/01613230a0e59518f7db1e0be5fa6af459aca220)) 71 | 72 | 73 | 74 | 75 | 76 | ## [0.20.1](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.20.0...@effect-ts/express@0.20.1) (2021-06-06) 77 | 78 | **Note:** Version bump only for package @effect-ts/express 79 | 80 | 81 | 82 | 83 | 84 | # [0.20.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.19.0...@effect-ts/express@0.20.0) (2021-05-30) 85 | 86 | **Note:** Version bump only for package @effect-ts/express 87 | 88 | 89 | 90 | 91 | 92 | # [0.19.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.18.1...@effect-ts/express@0.19.0) (2021-05-11) 93 | 94 | **Note:** Version bump only for package @effect-ts/express 95 | 96 | 97 | 98 | 99 | 100 | ## [0.18.1](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.18.0...@effect-ts/express@0.18.1) (2021-05-10) 101 | 102 | **Note:** Version bump only for package @effect-ts/express 103 | 104 | 105 | 106 | 107 | 108 | # [0.18.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.17.0...@effect-ts/express@0.18.0) (2021-05-08) 109 | 110 | **Note:** Version bump only for package @effect-ts/express 111 | 112 | 113 | 114 | 115 | 116 | # [0.17.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.16.0...@effect-ts/express@0.17.0) (2021-04-21) 117 | 118 | **Note:** Version bump only for package @effect-ts/express 119 | 120 | 121 | 122 | 123 | 124 | # [0.16.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.15.0...@effect-ts/express@0.16.0) (2021-04-18) 125 | 126 | **Note:** Version bump only for package @effect-ts/express 127 | 128 | 129 | 130 | 131 | 132 | # [0.15.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.14.0...@effect-ts/express@0.15.0) (2021-04-16) 133 | 134 | **Note:** Version bump only for package @effect-ts/express 135 | 136 | 137 | 138 | 139 | 140 | # [0.14.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.13.0...@effect-ts/express@0.14.0) (2021-04-12) 141 | 142 | **Note:** Version bump only for package @effect-ts/express 143 | 144 | 145 | 146 | 147 | 148 | # [0.13.0](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.12.1...@effect-ts/express@0.13.0) (2021-04-10) 149 | 150 | 151 | ### Bug Fixes 152 | 153 | * **express:** update effect-ts to 0.29.0 ([8095b42](https://github.com/Effect-TS/express/commit/8095b42855756833219509845a080bcf45a08ed0)) 154 | 155 | 156 | 157 | 158 | 159 | ## [0.12.1](https://github.com/Effect-TS/express/compare/@effect-ts/express@0.12.0...@effect-ts/express@0.12.1) (2021-04-06) 160 | 161 | 162 | ### Features 163 | 164 | * **express:** update build, conventional commits ([36ac71a](https://github.com/Effect-TS/express/commit/36ac71a41ec598d15189abc0075c2176ac5ba5a4)) 165 | -------------------------------------------------------------------------------- /packages/express/README.md: -------------------------------------------------------------------------------- 1 | ### Effect-TS Express 2 | 3 | This package is a work in progress wrapper around `express` 4 | 5 | ## Install 6 | 7 | We recommend the usage of `yarn` and if you hf `yarn workspaces` that handles by default hoisting of dependencies: 8 | 9 | ```sh 10 | yarn add @effect-ts/express @effect-ts/core 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@effect-ts/express", 3 | "version": "0.25.1", 4 | "license": "MIT", 5 | "repository": "https://github.com/Effect-TS/express.git", 6 | "homepage": "https://www.matechs.com", 7 | "scripts": { 8 | "clean": "yarn ets:rimraf build tsbuildinfo dist", 9 | "build-cjs": "yarn ets:babel build/esm --config-file ./.babel.cjs.json --out-dir build/cjs --out-file-extension .js --source-maps", 10 | "build-mjs": "yarn ets:babel build/esm --config-file ./.babel.mjs.json --out-dir build/mjs --out-file-extension .mjs --source-maps", 11 | "build-ts": "yarn ets:tsc -p tsconfig.build.esm.json", 12 | "build-post": "yarn ets:build-utils pack", 13 | "build": "yarn build-ts && yarn ets:concurrently \"yarn build-cjs\" \"yarn build-mjs\" && yarn build-post", 14 | "lint": "yarn ets:eslint . --ext .ts,.tsx", 15 | "autofix": "yarn prettier && yarn lint --fix && yarn prettier", 16 | "prettier": "yarn ets:prettier --write \"./{src,test,demo}/**/*.ts\"", 17 | "tc": "yarn ets:tsc --noEmit", 18 | "circular": "yarn ets:madge --circular --no-color --no-spinner build/esm" 19 | }, 20 | "publishConfig": { 21 | "access": "public", 22 | "directory": "dist" 23 | }, 24 | "sideEffects": false, 25 | "config": { 26 | "side": [], 27 | "modules": [] 28 | }, 29 | "peerDependencies": { 30 | "@effect-ts/core": "^0.58.0", 31 | "express": ">= 4.17.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/express/src/index.ts: -------------------------------------------------------------------------------- 1 | // ets_tracing: off 2 | 3 | // tracing: off 4 | 5 | import type { NonEmptyArray } from "@effect-ts/core/Collections/Immutable/NonEmptyArray" 6 | import * as T from "@effect-ts/core/Effect" 7 | import type { Cause } from "@effect-ts/core/Effect/Cause" 8 | import * as F from "@effect-ts/core/Effect/Fiber" 9 | import * as L from "@effect-ts/core/Effect/Layer" 10 | import * as M from "@effect-ts/core/Effect/Managed" 11 | import * as Supervisor from "@effect-ts/core/Effect/Supervisor" 12 | import type { Has } from "@effect-ts/core/Has" 13 | import { AtomicBoolean } from "@effect-ts/core/Support/AtomicBoolean" 14 | import { died, pretty } from "@effect-ts/system/Cause" 15 | import { literal } from "@effect-ts/system/Function" 16 | import { tag } from "@effect-ts/system/Has" 17 | import type { _A, _R } from "@effect-ts/system/Utils" 18 | import type { NextHandleFunction } from "connect" 19 | import type { NextFunction, Request, RequestHandler, Response } from "express" 20 | import express from "express" 21 | import type { Server } from "http" 22 | import type { Socket } from "net" 23 | 24 | export class NodeServerCloseError { 25 | readonly _tag = "NodeServerCloseError" 26 | constructor(readonly error: Error) {} 27 | } 28 | 29 | export class NodeServerListenError { 30 | readonly _tag = "NodeServerListenError" 31 | constructor(readonly error: Error) {} 32 | } 33 | 34 | export const ExpressAppConfigTag = literal("@effect-ts/express/AppConfig") 35 | 36 | export interface ExpressAppConfig { 37 | readonly _tag: typeof ExpressAppConfigTag 38 | readonly port: number 39 | readonly host: string 40 | readonly exitHandler: typeof defaultExitHandler 41 | } 42 | 43 | export const ExpressAppConfig = tag(ExpressAppConfigTag) 44 | 45 | export function LiveExpressAppConfig( 46 | host: string, 47 | port: number, 48 | exitHandler: ( 49 | req: Request, 50 | res: Response, 51 | next: NextFunction 52 | ) => (cause: Cause) => T.RIO 53 | ) { 54 | return L.fromEffect(ExpressAppConfig)( 55 | T.access((r: R) => ({ 56 | _tag: ExpressAppConfigTag, 57 | host, 58 | port, 59 | exitHandler: (req, res, next) => (cause) => 60 | T.provideAll_(exitHandler(req, res, next)(cause), r) 61 | })) 62 | ) 63 | } 64 | 65 | export const ExpressAppTag = literal("@effect-ts/express/App") 66 | 67 | export const makeExpressApp = M.gen(function* (_) { 68 | const open = yield* _( 69 | T.succeedWith(() => new AtomicBoolean(true))["|>"]( 70 | M.makeExit((_) => T.succeedWith(() => _.set(false))) 71 | ) 72 | ) 73 | 74 | const app = yield* _(T.succeedWith(() => express())) 75 | 76 | const { exitHandler, host, port } = yield* _(ExpressAppConfig) 77 | 78 | const connections = new Set() 79 | 80 | const server = yield* _( 81 | M.make_( 82 | T.effectAsync((cb) => { 83 | const onError = (err: Error) => { 84 | cb(T.die(new NodeServerListenError(err))) 85 | } 86 | const server = app.listen(port, host, () => { 87 | cb( 88 | T.succeedWith(() => { 89 | server.removeListener("error", onError) 90 | return server 91 | }) 92 | ) 93 | }) 94 | server.addListener("error", onError) 95 | server.on("connection", (connection) => { 96 | connections.add(connection) 97 | connection.on("close", () => { 98 | connections.delete(connection) 99 | }) 100 | }) 101 | }), 102 | (server) => 103 | T.effectAsync((cb) => { 104 | connections.forEach((s) => { 105 | s.end() 106 | s.destroy() 107 | }) 108 | server.close((err) => { 109 | if (err) { 110 | cb(T.die(new NodeServerCloseError(err))) 111 | } else { 112 | cb(T.unit) 113 | } 114 | }) 115 | }) 116 | ) 117 | ) 118 | 119 | const supervisor = yield* _( 120 | Supervisor.track["|>"](M.makeExit((s) => s.value["|>"](T.chain(F.interruptAll)))) 121 | ) 122 | 123 | function runtime< 124 | Handlers extends NonEmptyArray> 125 | >(handlers: Handlers) { 126 | return T.map_( 127 | T.runtime< 128 | _R< 129 | { 130 | [k in keyof Handlers]: [Handlers[k]] extends [ 131 | EffectRequestHandler 132 | ] 133 | ? T.RIO 134 | : never 135 | }[number] 136 | > 137 | >()["|>"](T.map((r) => r.supervised(supervisor))), 138 | (r) => 139 | handlers.map( 140 | (handler): RequestHandler => 141 | (req, res, next) => { 142 | r.runFiber( 143 | T.onTermination_( 144 | open.get ? handler(req, res, next) : T.interrupt, 145 | exitHandler(req, res, next) 146 | ) 147 | ) 148 | } 149 | ) 150 | ) 151 | } 152 | 153 | return { 154 | _tag: ExpressAppTag, 155 | app, 156 | supervisor, 157 | server, 158 | runtime 159 | } 160 | }) 161 | 162 | export interface ExpressApp extends _A {} 163 | export const ExpressApp = tag(ExpressAppTag) 164 | export const LiveExpressApp = L.fromManaged(ExpressApp)(makeExpressApp) 165 | 166 | export type ExpressEnv = Has & Has 167 | 168 | export function LiveExpress( 169 | host: string, 170 | port: number 171 | ): L.Layer 172 | export function LiveExpress( 173 | host: string, 174 | port: number, 175 | exitHandler: ( 176 | req: Request, 177 | res: Response, 178 | next: NextFunction 179 | ) => (cause: Cause) => T.RIO 180 | ): L.Layer 181 | export function LiveExpress( 182 | host: string, 183 | port: number, 184 | exitHandler?: ( 185 | req: Request, 186 | res: Response, 187 | next: NextFunction 188 | ) => (cause: Cause) => T.RIO 189 | ): L.Layer { 190 | return LiveExpressAppConfig(host, port, exitHandler || defaultExitHandler)[">+>"]( 191 | LiveExpressApp 192 | ) 193 | } 194 | 195 | export const expressApp = T.accessService(ExpressApp)((_) => _.app) 196 | 197 | export const expressServer = T.accessService(ExpressApp)((_) => _.server) 198 | 199 | export const { app: withExpressApp, server: withExpressServer } = T.deriveAccessM( 200 | ExpressApp 201 | )(["app", "server"]) 202 | 203 | export const methods = [ 204 | "all", 205 | "get", 206 | "post", 207 | "put", 208 | "delete", 209 | "patch", 210 | "options", 211 | "head", 212 | "checkout", 213 | "connect", 214 | "copy", 215 | "lock", 216 | "merge", 217 | "mkactivity", 218 | "mkcol", 219 | "move", 220 | "m-search", 221 | "notify", 222 | "propfind", 223 | "proppatch", 224 | "purge", 225 | "report", 226 | "search", 227 | "subscribe", 228 | "trace", 229 | "unlock", 230 | "unsubscribe" 231 | ] as const 232 | 233 | export type Methods = typeof methods[number] 234 | 235 | export type PathParams = string | RegExp | Array 236 | 237 | export interface ParamsDictionary { 238 | [key: string]: string 239 | } 240 | 241 | export interface ParsedQs { 242 | [key: string]: undefined | string | string[] | ParsedQs | ParsedQs[] 243 | } 244 | 245 | export interface EffectRequestHandler< 246 | R, 247 | P = ParamsDictionary, 248 | ResBody = any, 249 | ReqBody = any, 250 | ReqQuery = ParsedQs, 251 | Locals extends Record = Record 252 | > { 253 | ( 254 | req: Request, 255 | res: Response, 256 | next: NextFunction 257 | ): T.RIO 258 | } 259 | 260 | export function expressRuntime< 261 | Handlers extends NonEmptyArray> 262 | >(handlers: Handlers) { 263 | return T.accessServiceM(ExpressApp)((_) => _.runtime(handlers)) 264 | } 265 | 266 | export function match(method: Methods): { 267 | >>( 268 | path: PathParams, 269 | ...handlers: Handlers 270 | ): T.RIO< 271 | ExpressEnv & 272 | _R< 273 | { 274 | [k in keyof Handlers]: [Handlers[k]] extends [ 275 | EffectRequestHandler 276 | ] 277 | ? T.RIO 278 | : never 279 | }[number] 280 | >, 281 | void 282 | > 283 | } { 284 | return function (path, ...handlers) { 285 | return expressRuntime(handlers)["|>"]( 286 | T.chain((expressHandlers) => 287 | withExpressApp((app) => 288 | T.succeedWith(() => { 289 | app[method](path, ...expressHandlers) 290 | }) 291 | ) 292 | ) 293 | ) 294 | } 295 | } 296 | 297 | export function defaultExitHandler( 298 | _req: Request, 299 | _res: Response, 300 | _next: NextFunction 301 | ): (cause: Cause) => T.RIO { 302 | return (cause) => 303 | T.succeedWith(() => { 304 | if (died(cause)) { 305 | console.error(pretty(cause)) 306 | } 307 | _res.status(500).end() 308 | }) 309 | } 310 | 311 | export function use< 312 | Handlers extends NonEmptyArray> 313 | >( 314 | ...handlers: Handlers 315 | ): T.RIO< 316 | ExpressEnv & 317 | _R< 318 | { 319 | [k in keyof Handlers]: [Handlers[k]] extends [ 320 | EffectRequestHandler 321 | ] 322 | ? T.RIO 323 | : never 324 | }[number] 325 | >, 326 | void 327 | > 328 | export function use< 329 | Handlers extends NonEmptyArray> 330 | >( 331 | path: PathParams, 332 | ...handlers: Handlers 333 | ): T.RIO< 334 | ExpressEnv & 335 | _R< 336 | { 337 | [k in keyof Handlers]: [Handlers[k]] extends [ 338 | EffectRequestHandler 339 | ] 340 | ? T.RIO 341 | : never 342 | }[number] 343 | >, 344 | void 345 | > 346 | export function use(...args: any[]): T.RIO { 347 | return withExpressApp((app) => { 348 | if (typeof args[0] === "function") { 349 | return expressRuntime( 350 | args as unknown as NonEmptyArray< 351 | EffectRequestHandler 352 | > 353 | )["|>"]( 354 | T.chain((expressHandlers) => T.succeedWith(() => app.use(...expressHandlers))) 355 | ) 356 | } else { 357 | return expressRuntime( 358 | args.slice(1) as unknown as NonEmptyArray< 359 | EffectRequestHandler 360 | > 361 | )["|>"]( 362 | T.chain((expressHandlers) => 363 | T.succeedWith(() => app.use(args[0], ...expressHandlers)) 364 | ) 365 | ) 366 | } 367 | }) 368 | } 369 | 370 | export const all = match("all") 371 | export const get = match("get") 372 | export const post = match("post") 373 | export const put = match("put") 374 | const delete_ = match("delete") 375 | export { delete_ as delete } 376 | export const patch = match("patch") 377 | export const options = match("options") 378 | export const head = match("head") 379 | export const checkout = match("checkout") 380 | export const connect = match("connect") 381 | export const copy = match("copy") 382 | export const lock = match("lock") 383 | export const merge = match("merge") 384 | export const mkactivity = match("mkactivity") 385 | export const mkcol = match("mkcol") 386 | export const move = match("move") 387 | export const mSearch = match("m-search") 388 | export const notify = match("notify") 389 | export const propfind = match("propfind") 390 | export const proppatch = match("proppatch") 391 | export const purge = match("purge") 392 | export const report = match("report") 393 | export const search = match("search") 394 | export const subscribe = match("subscribe") 395 | export const trace = match("trace") 396 | export const unlock = match("unlock") 397 | export const unsubscribe = match("unsubscribe") 398 | 399 | /** 400 | * Lift an express requestHandler into an effectified variant 401 | */ 402 | export function classic( 403 | _: NextHandleFunction, 404 | __trace?: string 405 | ): EffectRequestHandler 406 | export function classic( 407 | _: RequestHandler, 408 | __trace?: string 409 | ): EffectRequestHandler 410 | export function classic( 411 | _: RequestHandler | NextHandleFunction, 412 | __trace?: string 413 | ): EffectRequestHandler { 414 | return (req, res, next) => T.succeedWith(() => _(req, res, next), __trace) 415 | } 416 | 417 | /** 418 | * The same as T.never, keeps the main fiber alive until interrupted 419 | */ 420 | export const listen = T.never 421 | -------------------------------------------------------------------------------- /packages/express/test/index.test.ts: -------------------------------------------------------------------------------- 1 | import * as T from "@effect-ts/core/Effect" 2 | import * as Exit from "@effect-ts/core/Effect/Exit" 3 | import * as L from "@effect-ts/core/Effect/Layer" 4 | import { pipe } from "@effect-ts/core/Function" 5 | import { tag } from "@effect-ts/core/Has" 6 | import * as exp from "express" 7 | 8 | import * as Express from "../src/index.js" 9 | 10 | describe("Express", () => { 11 | it("should answer positively", async () => { 12 | interface MessageService { 13 | _tag: "@demo/MessageService" 14 | makeMessage: T.UIO 15 | } 16 | 17 | const MessageService = tag() 18 | 19 | const LiveMessageService = L.fromEffect(MessageService)( 20 | T.succeedWith(() => ({ 21 | _tag: "@demo/MessageService", 22 | makeMessage: T.succeedWith(() => "ok") 23 | })) 24 | ) 25 | 26 | const host = "127.0.0.1" 27 | const port = 31157 28 | 29 | const exit = await pipe( 30 | Express.get("/", Express.classic(exp.json()), (_, _res) => 31 | T.gen(function* ($) { 32 | const { makeMessage } = yield* $(MessageService) 33 | const message = yield* $(makeMessage) 34 | _res.send({ message }) 35 | }) 36 | ), 37 | T.zipRight( 38 | T.tryPromise(() => fetch(`http://${host}:${port}/`).then((x) => x.json())) 39 | ), 40 | T.provideSomeLayer(Express.LiveExpress(host, port)["+++"](LiveMessageService)), 41 | T.runPromiseExit 42 | ) 43 | 44 | expect(exit).toEqual(Exit.succeed({ message: "ok" })) 45 | }) 46 | 47 | it("should log defect", async () => { 48 | const fakeLog = jest.fn() 49 | const consoleSpy = jest.spyOn(console, "error") 50 | 51 | consoleSpy.mockImplementation(fakeLog) 52 | 53 | const host = "127.0.0.1" 54 | const port = 31157 55 | 56 | await pipe( 57 | T.tuple( 58 | Express.use( 59 | Express.classic((req, _, next) => { 60 | req["message"] = "defect" 61 | next() 62 | }) 63 | ), 64 | Express.get("/", (_req) => 65 | T.succeedWith(() => { 66 | throw new Error(_req["message"]) 67 | }) 68 | ) 69 | ), 70 | T.zipRight(T.tryPromise(() => fetch(`http://${host}:${port}/`))), 71 | T.provideSomeLayer(Express.LiveExpress(host, port)), 72 | T.runPromiseExit 73 | ) 74 | 75 | consoleSpy.mockRestore() 76 | 77 | expect(fakeLog).toBeCalled() 78 | expect(fakeLog.mock.calls[0][0]).toContain("Error: defect") 79 | expect(fakeLog.mock.calls[0][0]).toContain("test/index.test.ts:65:24") 80 | }) 81 | }) 82 | -------------------------------------------------------------------------------- /packages/express/tsconfig.build.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "build/esm", 5 | "declarationDir": "build/dts", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "declarationMap": true, 9 | "module": "ES6", 10 | "target": "ES2018", 11 | "incremental": true, 12 | "tsBuildInfoFile": "tsbuildinfo/es6.tsbuildinfo", 13 | "removeComments": false, 14 | "plugins": [ 15 | { 16 | "transform": "@effect-ts/tracing-plugin", 17 | "moduleMap": { 18 | "^src/(.*)": "(@effect-ts/express): _src/$1" 19 | } 20 | } 21 | ] 22 | }, 23 | "include": [ 24 | "src/**/*" 25 | ], 26 | "exclude": [ 27 | "test", 28 | "node_modules" 29 | ] 30 | } -------------------------------------------------------------------------------- /packages/express/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": ["DOM"], 5 | "target": "ES2018", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true 8 | }, 9 | "include": ["src/**/*", "scripts/**/*", "bench/**/*", "test/**/*", "demo/**/*"] 10 | } 11 | -------------------------------------------------------------------------------- /pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | yarn dedupe -c 3 | -------------------------------------------------------------------------------- /scripts/jest-setup.ts: -------------------------------------------------------------------------------- 1 | import "isomorphic-fetch" 2 | import "@effect-ts/core/Tracing/Enable" 3 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "downlevelIteration": true, 4 | "resolveJsonModule": true, 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "skipLibCheck": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "preserveSymlinks": true, 11 | "moduleResolution": "node", 12 | "noEmit": false, 13 | "lib": ["es2020", "DOM"], 14 | "sourceMap": true, 15 | "declarationMap": true, 16 | "strict": true, 17 | "noImplicitReturns": false, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": false, 20 | "noFallthroughCasesInSwitch": true, 21 | "noEmitOnError": false, 22 | "noErrorTruncation": true, 23 | "allowJs": false, 24 | "checkJs": false, 25 | "forceConsistentCasingInFileNames": true, 26 | "suppressImplicitAnyIndexErrors": true, 27 | "stripInternal": true, 28 | "noImplicitAny": true, 29 | "noImplicitThis": true, 30 | "strictNullChecks": true, 31 | "baseUrl": ".", 32 | "target": "ES2018" 33 | }, 34 | "exclude": ["node_modules", "build", "lib"] 35 | } 36 | -------------------------------------------------------------------------------- /tsconfig.jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "files": [], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "target": "ES2018", 7 | "plugins": [ 8 | { 9 | "transform": "@effect-ts/tracing-plugin", 10 | "moduleMap": { 11 | "^packages/express/src/(.*)": "(@effect-ts/express): src/$1", 12 | "^packages/express/test/(.*)": "(@effect-ts/express/test): test/$1" 13 | } 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "files": [], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "target": "ES2018" 7 | } 8 | } 9 | --------------------------------------------------------------------------------