{"id":26120652,"url":"https://github.com/swiftrex/gatedmiddleware","last_synced_at":"2026-04-21T00:01:37.834Z","repository":{"id":40371101,"uuid":"260476466","full_name":"SwiftRex/GatedMiddleware","owner":"SwiftRex","description":"Turn SwiftRex middlewares on or off dynamically","archived":false,"fork":false,"pushed_at":"2022-05-12T08:43:25.000Z","size":30,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-10T13:45:55.080Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SwiftRex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-01T14:18:14.000Z","updated_at":"2022-05-12T12:44:40.000Z","dependencies_parsed_at":"2022-08-09T18:30:52.182Z","dependency_job_id":null,"html_url":"https://github.com/SwiftRex/GatedMiddleware","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/SwiftRex/GatedMiddleware","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FGatedMiddleware","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FGatedMiddleware/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FGatedMiddleware/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FGatedMiddleware/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SwiftRex","download_url":"https://codeload.github.com/SwiftRex/GatedMiddleware/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FGatedMiddleware/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32071013,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T21:26:33.338Z","status":"ssl_error","status_checked_at":"2026-04-20T21:26:22.081Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-10T13:43:37.531Z","updated_at":"2026-04-21T00:01:37.809Z","avatar_url":"https://github.com/SwiftRex.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GatedMiddleware\nTurn SwiftRex middlewares on or off dynamically\n\n\nGated middleware is a middleware that holds an inner middleware that could be either active or not.\n\nThere are two gate variations that can be used: by action or by state.\n\n## GatedMiddleware by action:\n\nIt holds an internal state, called `gate state`, that determines whether or not the inner middleware should be in `active` or `bypass` mode.\nThis can be changed dynamically.\n\nIt starts with an initial gate state, called \"default gate state\". From that point on, it will evaluate all incoming actions to detect a \"control\naction\", which is an action for switching on or off the gate state. This control action is detected thanks to a control action map closure or a\ncontrol action map KeyPath configured in the GatedMiddleware's init, which from a given input action allows the user to inform either or not this\nis a control action, by returning an Optional instance of that ControlAction (or nil in case it's a regular action).\n\nThe init also requires some comparison values, for turnOn or turnOff the gate. If it's a control action, and it's equals to turn on, it will set\nthe inner middleware to active. If it's a control action, and it's equals to turn off, it will set the inner middleware to bypass. If it's not a\ncontrol action, or it's not equals to any of the comparison values, the gate will remain untouched.\n\nThe gated middleware by action will ALWAYS forward control actions to inner middlewares, regardless of their gate state (active or bypass) and\nregardless of the turn on/turn off comparison result. This will allow important actions like disabling or enabling the inner middleware for\ncontrol actions, so for example, even for when we close the gate we still want to tell the inner middleware that it's gonna be bypassed and it\nshould kill all of its timers or async side-effects.\n\n## GatedMiddleware by state:\n\nIt won't hold any internal state, instead, it will use some state from your App Global State. You're responsible for mutating this state from your\nown reducers. At any point that the state tells that this middleware is `active`, it's gonna handle actions and be able to dispatch new actions.\nHowever, whenever the state is set to `bypass`, this middleware will ignore incoming actions and won't be able to dispatch any new action.\n\nWhen handling actions, the state is evaluated before reducers, so whatever state is set BEFORE reducer, will define if the inner middleware will\nbe called before and after the reducer, even if the reducer changes that value. An action that changes the state from `active` to `bypass`, will\ntrigger inner middleware before and after the reducer, and after the reducer that value will be already set to `bypass`, so you can stop timers\nand async tasks. An action that changes the state from `bypass` to `active`, will not trigger the inner middleware before the reducer nor after\nit, so you may want to send a second action to start the middleware timers again, because the gated middleware can't do that for you.\n\n\n## Examples:\n\n1. Gated by action, simple example\n```\n// sourcery: Prism\nenum AppAction {\n    case something\n    case anotherSomething\n    case dynamicMiddlewares(DynamicMiddlewareAction)\n}\n\n// sourcery: Prism\nenum DynamicMiddlewareAction: Equatable {\n    case toggleCrashReportsMiddleware(enable: Bool)\n}\n\nlet gatedCrashReportsMiddleware =\n    CrashReportsMiddleware\n        .init()\n        .gated(\n            controlAction: \\AppAction.dynamicMiddlewares?.toggleCrashReportsMiddleware?.enable,\n            default: .active            \n        )\n```\n\n2. Gated by action, with custom comparison:\n```\n// sourcery: Prism\nenum AppAction {\n    case something\n    case anotherSomething\n    case dynamicMiddlewares(DynamicMiddlewareAction)\n}\n\n// sourcery: Prism\nenum DynamicMiddlewareAction: Equatable {\n    case controlCrashReportsMiddleware(controlAction: MiddlewareControlAction)\n}\n\n// sourcery: Prism\nenum MiddlewareControlAction: Equatable {\n    case activate\n    case bypass\n    case sayHello\n}\n\nlet gatedCrashReportsMiddleware =\n    CrashReportsMiddleware\n        .init()\n        .gated(\n            controlAction: \\AppAction.dynamicMiddlewares?.controlCrashReportsMiddleware,\n            turnOn: MiddlewareControlAction.activate,\n            turnOff: MiddlewareControlAction.bypass,\n            default: .active\n        )\n        // in this example, MiddlewareControlAction.activate will activate the crash reports,\n        // MiddlewareControlAction.bypass will disable the crash reports, and\n        // MiddlewareControlAction.sayHello won't change the gate state, but will be forwarded to the\n        // crash reports middleware regardless of its current state.\n```\n\n3. Gated by state, simple example\n```\nstruct AppState {\n    var isCrashReportEnabled: Bool\n}\n\nlet gatedCrashReportsMiddleware =\n    CrashReportsMiddleware\n        .init()\n        .gated(\n            state: \\AppState.isCrashReportEnabled\n        )\n```\n\n## Lift, Composed and other higher-order middlewares\n\nYou can also lift the inner middleware before gating it, in case the AppActions or AppStates don't match. Evidently lift can also be done\nafter the gated middleware if this is what you need.\n\nGating composed middlewares will disable or enable all of them at once, and the control action will be the same and be forwarded to all\nthe inner middlewares all the times. If this is not what you need, you need disabling them individually, you can first gate them and with\nthe gated collection you compose them.\n\nThis has no interference on Reducers and this doesn't change the AppState in any way. GatedMiddleware only matches AppState with its inner\nmiddleware to allow proxying the `getState` context.\n\n## About the examples and code generation\n\nAll examples above use Sourcery Prism templates to simplify traversing action trees, but the `GatedMiddleware` offers closures in case you\nprefer switch/case approach or other custom functions.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftrex%2Fgatedmiddleware","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswiftrex%2Fgatedmiddleware","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftrex%2Fgatedmiddleware/lists"}