Module registry and composition helpers for the Wagoe shell.
This namespace provides utilities to:
For now, only the :user module is supported.
Module registry and composition helpers for the Wagoe shell. This namespace provides utilities to: - Determine which modules are enabled based on configuration. - Compose route definitions from multiple modules. - Dispatch CLI commands to module-specific runners. For now, only the `:user` module is supported.
Modules every application gets. See registry/always-on-modules.
Modules every application gets. See `registry/always-on-modules`.
(assert-every-key-claimed! active known-keys)Throw when :active names a wagoe key nothing will assemble.
Throw when `:active` names a `wagoe` key nothing will assemble.
(compose-module-routes route-maps)Compose route definitions from multiple modules (new pattern).
Arguments: route-maps: collection of route maps from modules. Each route map has keys: :api, :web, :static.
Returns: Combined route map with merged routes: {:api [all-api-routes] :web [all-web-routes] :static [all-static-routes]}
Example: (compose-module-routes [{:api [['/users' {...}]] :web [] :static []} {:api [['/billing' {...}]] :web [] :static []}]) ;=> {:api [['/users' {...}] ['/billing' {...}]] ; :web [] ; :static []}
Compose route definitions from multiple modules (new pattern).
Arguments:
route-maps: collection of route maps from modules.
Each route map has keys: :api, :web, :static.
Returns:
Combined route map with merged routes:
{:api [all-api-routes]
:web [all-web-routes]
:static [all-static-routes]}
Example:
(compose-module-routes [{:api [['/users' {...}]] :web [] :static []}
{:api [['/billing' {...}]] :web [] :static []}])
;=> {:api [['/users' {...}] ['/billing' {...}]]
; :web []
; :static []}Modules that refuse to assemble outside :wagoe/profile :dev, and why.
Enforced here rather than in the module, because the module's library may
not be on the classpath — and optional-modules would then skip the key
with a log line before anything looked at the profile. A production config
naming the dev dashboard booted in silence, and would have started one the
day devtools reached :deps. Absent from the classpath is not a guard
(BOU-477).
The reason is in the message an operator reads at boot, so it is data here.
Also what three test families skip when they enumerate framework-modules
to assert every module assembles, is selectable as a service, or boots from
its documented config: none of that is true of a module that is not
deployable. every-dev-only-module-really-refuses keeps that exemption
honest.
Modules that refuse to assemble outside `:wagoe/profile :dev`, and why. Enforced here rather than in the module, because the module's library may not be on the classpath — and `optional-modules` would then skip the key with a log line before anything looked at the profile. A production config naming the dev dashboard booted in silence, and would have started one the day devtools reached `:deps`. Absent from the classpath is not a guard (BOU-477). The reason is in the message an operator reads at boot, so it is data here. Also what three test families skip when they enumerate `framework-modules` to assert every module assembles, is selectable as a service, or boots from its documented config: none of that is true of a module that is not deployable. `every-dev-only-module-really-refuses` keeps that exemption honest.
(discover-module-config active known-keys base-ns wiring-loadable?)(discover-module-config active known-keys base-ns wiring-loadable? resolve-var)Integrant entries for scaffolded modules named under :active, in the shape
framework-module-config returns.
wiring-loadable? is injected so this stays testable without a module on the
classpath; -main passes a function that requires the namespace.
Throws when a module key names a wiring namespace that will not load. The
silent skip is the whole defect: a typo in a key — :wagoe/tsaks, or the
:active/:inactive mix-up — produced no signal at all.
Integrant entries for scaffolded modules named under `:active`, in the shape `framework-module-config` returns. `wiring-loadable?` is injected so this stays testable without a module on the classpath; `-main` passes a function that requires the namespace. Throws when a module key names a wiring namespace that will not load. The silent skip is the whole defect: a typo in a key — `:wagoe/tsaks`, or the `:active`/`:inactive` mix-up — produced no signal at all.
(discovered-route-refs active known-keys)(discovered-route-refs active known-keys built)Integrant refs to the routes of every discovered module that has any, each
with its module key (module-routes-ref).
The HTTP handler cannot name a generated module, so it takes the routes as a
collection — this is what the application puts in :module-routes.
built is the config those modules produced, and the refs are filtered
against it. Referencing :wagoe/<name>-routes by convention alone was safe
only while every discovered module went through the scaffolder's four-key
shape, which always builds one. A module with a graph of its own need not
serve HTTP at all — a background-jobs library is exactly the kind of library
this is meant to welcome — and a ref to a component it never built is a
dangling ref, which Integrant refuses (BOU-330).
Integrant refs to the routes of every discovered module that has any, each with its module key (`module-routes-ref`). The HTTP handler cannot name a generated module, so it takes the routes as a collection — this is what the application puts in `:module-routes`. `built` is the config those modules produced, and the refs are filtered against it. Referencing `:wagoe/<name>-routes` by convention alone was safe only while every discovered module went through the scaffolder's four-key shape, which always builds one. A module with a graph of its own need not serve HTTP at all — a background-jobs library is exactly the kind of library this is meant to welcome — and a ref to a component it never built is a dangling ref, which Integrant refuses (BOU-330).
(dispatch-cli enabled-modules module->runner args)Dispatch CLI based on enabled modules.
Arguments: enabled-modules: vector of module keywords from config module->runner: map of module keyword to a function (fn [args] -> exit-code) args: raw CLI arguments vector
CLI convention: wagoe <module> <command> [options]
Dispatch CLI based on enabled modules. Arguments: enabled-modules: vector of module keywords from config module->runner: map of module keyword to a function (fn [args] -> exit-code) args: raw CLI arguments vector CLI convention: wagoe <module> <command> [options] - <module> is a keyword name like user or billing. - If <module> is omitted, and only one enabled module exists, that module is used by default. - If <module> is omitted and multiple modules are enabled, an error is reported and exit code 1 is returned. - If the selected module is not enabled or has no runner, exit code 1 is returned.
(enabled-libraries active)(enabled-libraries active extra)The libraries whose framework modules active switches on. See
registry/enabled-libraries.
The libraries whose framework modules `active` switches on. See `registry/enabled-libraries`.
(enabled-modules config)Return the vector of enabled modules based on app config.
Looks at [:active :wagoe/settings :modules] in the configuration map. If no modules are configured, defaults to [:user] for backwards compatibility.
Return the vector of enabled modules based on app config. Looks at [:active :wagoe/settings :modules] in the configuration map. If no modules are configured, defaults to [:user] for backwards compatibility.
(framework-module-config active
{:keys [extra-modules] :as ctx}
load-wiring!
resolve-var)Integrant entries for the framework modules active switches on.
Returns {:components {…} :http {…} :auth {…} :search {…} :data-export {…} :retention {…} :middleware [..] :routes [..] :job-handlers [..]}. :components merges into the system config,
:http into :wagoe/http-handler, :auth into :wagoe/auth-hooks and
:search into :wagoe/search. :middleware collects each module's
:extra-middleware — tenant's, for one — in module-key order.
:routes is a vector of refs to modules' route components, which reach the
handler as one collection rather than as a named slot per module (BOU-330).
:job-handlers is the same arrangement for background work: refs to
components that return {job-type handler-fn}, which reach the job registry
as one collection. Jobs can no more name the modules with handlers than the
HTTP handler can name the modules with routes (BOU-418). :recurring,
{job-type {:cron ..}}, are the schedules those handlers default to; one
under :wagoe/jobs :recurring wins (BOU-856).
ctx is what a module may need from the application and cannot know:
:config (the whole loaded map), :validation-config, and :enabled — the
set of sibling modules that are on, so audience can take a cache ref only
when there is a cache.
load-wiring! and resolve-var are injected so this is testable without a
module on the classpath; system-config passes the real ones.
Integrant entries for the framework modules `active` switches on.
Returns `{:components {…} :http {…} :auth {…} :search {…} :data-export {…}
:retention {…} :middleware [..] :routes [..] :job-handlers [..]}`. `:components` merges into the system config,
`:http` into `:wagoe/http-handler`, `:auth` into `:wagoe/auth-hooks` and
`:search` into `:wagoe/search`. `:middleware` collects each module's
`:extra-middleware` — tenant's, for one — in module-key order.
`:routes` is a vector of refs to modules' route components, which reach the
handler as one collection rather than as a named slot per module (BOU-330).
`:job-handlers` is the same arrangement for background work: refs to
components that return `{job-type handler-fn}`, which reach the job registry
as one collection. Jobs can no more name the modules with handlers than the
HTTP handler can name the modules with routes (BOU-418). `:recurring`,
{job-type {:cron ..}}, are the schedules those handlers default to; one
under `:wagoe/jobs :recurring` wins (BOU-856).
`ctx` is what a module may need from the application and cannot know:
`:config` (the whole loaded map), `:validation-config`, and `:enabled` — the
set of sibling modules that are on, so audience can take a cache ref only
when there is a cache.
`load-wiring!` and `resolve-var` are injected so this is testable without a
module on the classpath; `system-config` passes the real ones.:active key -> the library that owns it. See registry/framework-modules.
`:active` key -> the library that owns it. See `registry/framework-modules`.
(merge-auth acc k auth)A module's :auth hooks over acc, refusing a hook both set. A nil hook is
unset, as the user module reads it, so it claims no slot.
A module's `:auth` hooks over `acc`, refusing a hook both set. A nil hook is unset, as the user module reads it, so it claims no slot.
(merge-data-export acc k exporters)A module's :data-export exporters over acc, refusing an id both use.
A module's `:data-export` exporters over `acc`, refusing an id both use.
(merge-http acc k http)http over acc, refusing a key both set.
`http` over `acc`, refusing a key both set.
(merge-retention acc k policies)A module's :retention policies over acc, refusing an id both use.
A module's `:retention` policies over `acc`, refusing an id both use.
(merge-search acc k search)A module's :search index definitions over acc, refusing an index id
both define.
A module's `:search` index definitions over `acc`, refusing an index id both define.
(module-routes-ref k routes)routes, a ref to a routes contribution, with the module that contributes
it, so every route it holds can be tagged :wagoe/module.
`routes`, a ref to a routes contribution, with the module that contributes it, so every route it holds can be tagged `:wagoe/module`.
Modules whose library may legitimately be absent at runtime.
Both come from wagoe-devtools, which lives in the :repl alias — so
clojure -M:run against the dev config has the keys and not the jar. A
dev-only nicety must not stop the app from booting; every other missing
library is a real error and throws.
Modules whose library may legitimately be absent at runtime. Both come from wagoe-devtools, which lives in the `:repl` alias — so `clojure -M:run` against the dev config has the keys and not the jar. A dev-only nicety must not stop the app from booting; every other missing library is a real error and throws.
Where each module that can run on Redis keeps its host.
Each adapter connects to localhost when the host is nil, which is what
#env REDIS_HOST yields when the variable is unset. Right on a laptop;
outside dev and test it is a node talking to a Redis nobody deployed, or to
nothing (BOU-579).
Where each module that can run on Redis keeps its host. Each adapter connects to localhost when the host is nil, which is what `#env REDIS_HOST` yields when the variable is unset. Right on a laptop; outside dev and test it is a node talking to a Redis nobody deployed, or to nothing (BOU-579).
(require-wiring! wiring-ns)Load wiring-ns. Returns true when it loaded, false when it does not exist,
and rethrows anything else.
The distinction matters: a wiring namespace that exists but throws on load — freshly generated code with a compile error, or a missing transitive dep — is not a missing module, and reporting it as one buries the real error under a suggestion to check the spelling.
Load `wiring-ns`. Returns true when it loaded, false when it does not exist, and rethrows anything else. The distinction matters: a wiring namespace that exists but throws on load — freshly generated code with a compile error, or a missing transitive dep — is not a missing module, and reporting it as one buries the real error under a suggestion to check the spelling.
(scaffolded-module-keys active known-keys)The :active keys that declare a scaffolded module and are not already
wired by the caller.
A module is a :wagoe/<name> whose value carries :enabled?. Most of
:active is configuration — :wagoe/h2 names a database, :wagoe/http a
port, :wagoe/logging an adapter — and treating every key as a module made
the boot demand a wagoe.h2.shell.module-wiring. :enabled? is what
bb scaffold integrate prints, so declaring a module and being discovered as
one are the same act.
A different namespace (:wagoe.external/smtp) is a provider's settings.
The `:active` keys that declare a scaffolded module and are not already wired by the caller. A module is a `:wagoe/<name>` whose value carries `:enabled?`. Most of `:active` is configuration — `:wagoe/h2` names a database, `:wagoe/http` a port, `:wagoe/logging` an adapter — and treating every key as a module made the boot demand a `wagoe.h2.shell.module-wiring`. `:enabled?` is what `bb scaffold integrate` prints, so declaring a module and being discovered as one are the same act. A different namespace (`:wagoe.external/smtp`) is a provider's settings.
:active keys that configure a component wired under some other key.
Neither modules nor core components: each is a settings block that a
component reads with get-in, so nothing assembles them and nothing should.
The value names the reader, so an entry that has outlived it can be found.
Listed rather than inferred, because unclaimed-keys cannot otherwise tell
a settings block from a module key somebody misspelled — and telling those
apart is the whole point of it. An application names its own settings blocks
in :wagoe/config-keys.
`:active` keys that configure a component wired under some other key. Neither modules nor core components: each is a settings block that a component reads with `get-in`, so nothing assembles them and nothing should. The value names the reader, so an entry that has outlived it can be found. Listed rather than inferred, because `unclaimed-keys` cannot otherwise tell a settings block from a module key somebody misspelled — and telling those apart is the whole point of it. An application names its own settings blocks in `:wagoe/config-keys`.
(unclaimed-keys active known-keys):active keys under the wagoe namespace that nothing will assemble.
A key reaches a component one of four ways: it is a core key, a framework
module, a settings block something reads, or it carries :enabled? and is
discovered as a scaffolded module. :wagoe/dashboard {:port 9999} was none
of them, so it produced no component and no message — and a misspelled
module key falls through the same gap, looking exactly like a feature that
does not work (BOU-477).
Only the bare wagoe namespace: :wagoe.external/smtp is a provider's
settings, and :test/reset-endpoint-enabled? is not ours at all.
`:active` keys under the `wagoe` namespace that nothing will assemble.
A key reaches a component one of four ways: it is a core key, a framework
module, a settings block something reads, or it carries `:enabled?` and is
discovered as a scaffolded module. `:wagoe/dashboard {:port 9999}` was none
of them, so it produced no component and no message — and a misspelled
module key falls through the same gap, looking exactly like a feature that
does not work (BOU-477).
Only the bare `wagoe` namespace: `:wagoe.external/smtp` is a provider's
settings, and `:test/reset-endpoint-enabled?` is not ours at all.(wiring-candidates base-ns module)Where a module's wiring namespace may live, most preferred first.
An application's own code belongs under its own namespace, so
shop.product.shell.module-wiring is where bb scaffold writes it and the
first place to look (BOU-360).
wagoe.<module>.shell.module-wiring is the second: every project generated
before that change has its modules there, and the framework's own
application is one of them — its project namespace really is wagoe, so
this is not only a compatibility path. When base-ns is already "wagoe" the
two collapse to one candidate.
Where a module's wiring namespace may live, most preferred first. An application's own code belongs under its own namespace, so `shop.product.shell.module-wiring` is where `bb scaffold` writes it and the first place to look (BOU-360). `wagoe.<module>.shell.module-wiring` is the second: every project generated before that change has its modules there, and the framework's own application is one of them — its project namespace really is `wagoe`, so this is not only a compatibility path. When base-ns is already "wagoe" the two collapse to one candidate.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |