Packages

macula

14.8.2
15.0.0-rc.2 15.0.0-rc.1 14.10.0 14.9.0 14.8.2 14.8.1 14.8.0 14.7.0 14.6.0 14.5.0 14.4.0 14.3.0 14.2.1 14.2.0 14.1.0 14.0.0 13.6.0 13.5.0 13.4.0 13.3.0 13.2.2 13.2.1 13.2.0 13.1.0 13.0.1 13.0.0 12.12.0 12.11.1 12.11.0 12.10.0 12.9.1 12.9.0 12.8.0 12.7.0 12.6.0 12.5.1 12.5.0 12.4.0 12.3.0 12.2.1 12.2.0 12.1.0 12.0.0 11.5.0 11.4.0 11.3.1 11.3.0 11.2.0 11.1.0 11.0.0 10.25.0 10.24.0 10.23.0 10.22.0 10.21.0 10.20.3 10.20.2 10.20.0 10.19.2 10.19.1 10.19.0 10.18.0 10.17.0 10.16.0 10.15.0 10.14.5 10.14.4 10.14.2 10.14.1 10.14.0 10.13.2 10.13.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 10.9.0 10.8.0 10.7.0 10.5.8 10.5.7 10.5.6 10.5.5 10.5.4 10.5.3 10.5.2 10.5.1 10.5.0 10.4.0 10.2.0 10.1.1 10.1.0 10.0.2 10.0.1 10.0.0 9.13.8 9.8.2 9.8.1 9.8.0 9.5.0 9.4.0 9.3.1 9.3.0 9.2.0 9.1.1 9.1.0 9.0.0 8.7.0 8.6.0 8.5.0 8.4.1 8.4.0 8.3.0 8.2.0 8.1.0 8.0.2 8.0.1 8.0.0 7.1.0 7.0.0 6.0.0 5.2.2 5.2.1 5.2.0 5.1.0 5.0.0 4.8.0 4.7.1 4.7.0 4.6.0 4.5.0 4.4.10 4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.1 4.3.0 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.1 4.1.0 4.0.0 3.16.0 3.15.3 3.15.2 3.15.1 3.14.0 3.13.0 3.12.1 3.12.0 3.11.1 3.11.0 3.10.3 3.10.2 3.10.1 3.9.0 3.8.0 3.7.0 3.5.0 3.4.0 3.3.0 3.2.0 3.1.0 3.0.0 2.1.1 2.1.0 2.0.0 1.5.2 1.5.1 1.4.30 1.4.29 1.4.28 1.4.27 1.4.26 1.4.25 1.4.24 1.4.23 1.4.22 1.4.21 1.4.20 1.4.19 1.4.18 1.4.17 1.4.16 1.4.15 1.4.14 1.4.13 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.1 1.3.0 1.2.0 1.1.0 1.0.10 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0 0.48.6 0.48.5 0.48.4 0.48.3 0.48.2 0.48.1 0.48.0 0.47.1 0.47.0 0.46.3 0.46.1 0.46.0 0.45.3 0.45.2 0.45.1 0.45.0 0.44.2 0.44.1 0.44.0 0.43.3 0.43.2 0.43.1 0.43.0 0.42.9 0.42.8 0.42.7 0.42.6 0.42.5 0.42.4 0.42.3 0.42.2 0.42.1 0.42.0 0.41.1 0.41.0 0.40.1 0.40.0 0.39.9 0.39.8 0.39.7 0.39.6 0.39.5 0.39.4 0.39.3 0.39.2 0.39.1 0.39.0 0.38.8 0.38.7 0.38.6 0.38.5 0.38.4 0.38.3 0.38.2 0.38.1 0.38.0 0.37.7 0.37.6 0.37.5 0.37.4 0.37.3 0.37.2 0.37.1 0.37.0 0.36.6 0.36.5 0.36.4 0.36.3 0.36.2 0.36.1 0.36.0 0.35.4 0.35.3 0.35.2 0.35.1 0.35.0 0.34.1 0.34.0 0.33.1 0.33.0 0.32.5 0.32.4 0.32.3 0.32.2 0.32.1 0.32.0 0.31.9 0.31.8 0.31.7 0.31.6 0.31.5 0.31.4 0.31.3 0.31.2 0.31.1 0.31.0 0.30.10 0.30.9 0.30.8 0.30.7 0.30.6 0.30.5 0.30.4 0.30.3 0.30.2 0.30.1 0.30.0 0.29.0 0.28.3 0.28.2 0.28.1 0.28.0 0.27.1 0.27.0 0.26.1 0.26.0 0.25.6 0.25.5 0.25.4 0.25.3 0.25.2 0.25.1 0.25.0 0.24.6 0.24.5 0.24.4 0.24.3 0.24.2 0.24.1 0.24.0 0.23.3 0.23.2 0.23.1 0.23.0 0.22.12 0.22.11 0.22.10 0.22.9 0.22.8 0.22.7 0.22.6 0.22.5 0.22.4 0.22.3 0.22.2 0.22.1 0.22.0 0.21.7 0.21.6 0.21.5 0.21.4 0.21.2 0.21.1 0.21.0 0.20.25 0.20.24 0.20.23 0.20.22 0.20.21 0.20.20 0.20.19 0.20.18 0.20.17 0.20.16 0.20.15 0.20.14 0.20.13 0.20.12 0.20.11 0.20.10 0.20.9 0.20.8 0.20.7 0.20.6 0.20.5 0.20.3 0.20.2 0.20.1 0.20.0 0.19.2 0.19.1 0.19.0 0.18.1 0.18.0 0.17.4 0.17.3 0.17.2 0.17.1 0.17.0 0.16.6 0.16.5 0.16.4 0.16.3 0.16.2 0.16.1 0.16.0 0.15.1 0.15.0 0.14.3 0.14.2 0.14.1 0.14.0 0.12.6 0.12.5 0.12.3 0.11.3 0.10.2 0.10.1 0.10.0 0.9.2 0.9.1 0.9.0 0.8.25 0.8.24 0.8.23 0.8.22 0.8.21 0.8.20 0.8.19 0.8.18 0.8.17 0.8.16 0.8.15 0.8.14 0.8.13 0.8.12 0.8.11 0.8.10 0.8.9 0.8.8 0.8.7 0.8.6 0.8.5 0.8.4 0.8.3 0.8.2 0.8.1 0.8.0 0.7.30 0.7.29 0.7.28 0.7.27 0.7.26 0.7.25 0.7.24 0.7.23 0.7.22 0.7.21 0.7.20 0.7.19 0.7.18 0.7.17 0.7.16 0.7.15 0.7.14 0.7.13 0.7.12 0.7.11 0.7.10 0.7.9 0.7.8 0.7.7 0.7.6 0.7.5 0.7.4 0.7.3 0.7.2 0.7.1 0.7.0 0.6.7 0.6.6 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.0 0.4.4 0.4.3 0.4.2 0.4.1 0.4.0 0.3.4 0.3.3 0.3.2 0.3.1

Macula HTTP/3 Mesh SDK — connect, subscribe, publish, call, advertise

Current section

Files

Jump to
macula rebar.config
Raw

rebar.config

%% -*- mode: erlang -*-
%% Macula HTTP/3 Mesh - Root Rebar3 Configuration

{erl_opts, [
    debug_info,
    warnings_as_errors,
    warn_export_vars,
    warn_unused_vars,
    warn_obsolete_guard
]}.

%% Include subdirectories in src/ for compilation. Each slice
%% directory holds modules for a coherent capability. Foundational
%% primitives (macula_id, macula_realm, macula_topic, etc.) stay
%% flat at src/ root; capability slices live in subdirs.
{src_dirs, [
    "src",
    "src/auth",
    "src/client",
    "src/identity",
    "src/macula_cert_system",
    "src/macula_cluster_system",
    "src/macula_dist_system",
    "src/macula_yggdrasil",
    "src/mri",
    "src/observability",
    "src/overlay",
    "src/peering",
    "src/pubsub",
    "src/record",
    "src/v1"
]}.

{pre_hooks, [
    {compile, "sh -c 'B=\"${REBAR_DEPS_DIR}/macula\"; [ -f \"$B/priv/build-nifs.sh\" ] || B=\".\"; sh \"$B/priv/build-nifs.sh\" \"$B\"'"}
]}.

{deps, [
    %% QUIC transport: Quinn via Rust NIF (replaces quicer/MsQuic)
    %% Built from native/macula_quic/ via cargo pre_hooks above

    %% MessagePack serialization
    %% (msgpack removed in v3.0.0 — wire protocol switched to CBOR
    %%  via macula_cbor / macula_cbor_nif Rust NIF. The `msgpack` atom
    %%  seen elsewhere in this codebase, e.g. macula_stream's
    %%  encoding()/raw|msgpack type, is just a symbolic tag callers can
    %%  pass through — it never required the msgpack library itself.
    %%  A stale local rebar.lock kept resolving the msgpack package
    %%  anyway, for one dead test file (removed 2026-09-05); every hex
    %%  release since v3.0.0 silently carried it as a phantom runtime
    %%  requirement as a result. Loose `~>` constraints below per
    %%  policy — exact pins block coordinated dep resolution.

    %% Process registry
    {gproc, "~> 1.3"},

    %% Telemetry for observability and metrics
    {telemetry, "~> 1.3"}

    %% JSON encoding: Using built-in json module (OTP 27+)

    %% Crypto, UCAN, DID, MRI NIFs: Built from native/ via Rust/Cargo
    %% (absorbed from macula-nifs package in v1.0)
    %% Falls back to pure Erlang when Rust toolchain not available

    %% Note: Ra/Raft was removed in v0.14.0
    %% Macula uses CRDTs (macula_crdt.erl) for masterless state management
]}.

{project_plugins, [
    {rebar3_hex, "~> 7.2.0"},
    rebar3_proper,
    rebar3_ex_doc
]}.

%% Test configuration
{eunit_opts, [
    verbose,
    %% The macula application refuses to start without a crypto profile.
    {sys_config, "config/test.sys.config"}
]}.

%% Cover instrumentation is OFF by default because it costs 95 s of every
%% eunit run (445 s -> 350 s, same 4393 tests) and NO CI STEP READS THE RESULT.
%% The capability is unchanged: scripts/run_coverage.sh asks for it explicitly
%% with `rebar3 eunit --cover', which works whatever this setting says, and
%% `rebar3 cover --verbose' still writes _build/test/cover/index.html.
{cover_enabled, false}.
{cover_opts, [verbose]}.
{cover_excl_mods, []}.  %% Modules to exclude from coverage (e.g., generated code)
{cover_print_enabled, true}.
{cover_export_enabled, true}.

%% cth_skip_is_failure (macula_testkit): a skip nobody allowed fails the run,
%% because `rebar3 ct' exits 0 on a case that skipped itself (macula#43).
{ct_opts, [
    {sys_config, "config/test.sys.config"},
    {ct_hooks, [cth_skip_is_failure]}
]}.

%% xref fails on what is a defect in a library: a call to a function that does
%% not exist, a function that does not exist, a local function nothing calls,
%% and a deprecated call. rebar3's default also checks exports_not_used, which
%% reports the functions a library exports for its consumers to call.
{xref_checks, [
    undefined_function_calls,
    undefined_functions,
    locals_not_used,
    deprecated_function_calls,
    deprecated_functions
]}.

%% A call that breaks a contract, and a function that cannot return, are the
%% warnings a consumer's dialyzer reports against these specs; they are not
%% turned off here, or a spec that refuses what the code accepts passes this
%% check and fails every consumer's.
{dialyzer, [
    {warnings, [
        no_unused,
        no_improper_lists,
        no_fun_app,
        no_match,
        no_opaque,
        error_handling
    ]},
    {plt_apps, top_level_deps},
    {plt_location, local},
    {base_plt_apps, [erts, kernel, stdlib, crypto, public_key, ssl]},
    {base_plt_location, global}
]}.

%% Shell configuration
{shell, [
    {apps, [macula]},
    {config, "config/sys.config"}
]}.

%% Release configuration
{relx, [
    {release, {macula, "3.0.0"}, [
        macula,
        sasl,
        runtime_tools
        %% observer - removed for headless deployments (requires wx/OpenGL)
    ]},

    {mode, dev},
    {include_erts, true},
    {extended_start_script, true},

    {sys_config, "./config/sys.config"},
    {vm_args, "./config/vm.args"},

    {overlay, [
        {mkdir, "log"},
        {mkdir, "data"},
        {copy, "README.md", "README.md"},
        {copy, "LICENSE", "LICENSE"}
    ]}
]}.

%% Profiles
{profiles, [
    %% Calls a consumer makes, for dialyzer to check against macula's specs
    %% (consumer_contracts/macula_consumer_contracts.erl): CI's dialyzer runs
    %% `rebar3 as consumer_contracts dialyzer'. A profile of its own, because
    %% the hex docs build reads every compiled directory of the default
    %% profile as an application and refuses one without a .app file. The hex
    %% package does not carry the directory.
    {consumer_contracts, [
        {extra_src_dirs, [{"consumer_contracts", [{recursive, false}]}]}
    ]},

    {test, [
        {deps, [
            {proper, "1.4.0"},
            {meck, "0.9.2"},
            {macula_testkit, "~> 0.2"}
        ]},
        %% Tests may use the deprecated `catch' expression where the
        %% semantics (catch-anything, return the error term) is exactly
        %% what a teardown wants; OTP 28 warns on it and warnings_as_errors
        %% would fail any fresh test-profile compile (meck's own matcher
        %% uses it too). Relaxed for tests only, like nowarn_export_all.
        {erl_opts, [nowarn_export_all, nowarn_deprecated_catch]},
        %% rebar3 compiles an extra source directory recursively: test covers its
        %% subdirectories, so each test module compiles once, into
        %% _build/test/lib/macula/test. Listing a subdirectory as well compiles its
        %% modules a second time, into a directory of their own.
        {extra_src_dirs, [
            "test",
            "bench"
        ]}
    ]},

    %% relx-only, deliberately no erl_opts: rebar3 merges a fetched
    %% dependency's erl_opts across EVERY profile it defines, not just
    %% whichever one the consumer actually activated (confirmed live
    %% 2026-09-05 with a controlled A/B rebuild -- a bare git dependency
    %% fetch of this exact repo with vs. without this profile's
    %% erl_opts was the only variable that changed). `no_debug_info' /
    %% `deterministic' here used to strip debug_info from every
    %% consumer's copy of macula unconditionally, whether or not THEY
    %% ever selected `prod' -- silently breaking `rebar3 dialyzer
    %% --plt-extra-apps macula' for anyone who depends on this library.
    %% Nothing in this repo's own CI/scripts invokes `rebar3 as prod'
    %% or a relx release build (grepped, zero hits) -- this profile's
    %% `relx' block is a local-dev-only convenience for running a
    %% leaner standalone macula node, and dropping debug_info from that
    %% one local artifact was never worth breaking every consumer's
    %% dialyzer. If a leaner local build is wanted again, pass
    %% `--erl_opts +no_debug_info' on the `rebar3 as prod release'
    %% command line instead of putting it back here.
    {prod, [
        {relx, [
            {mode, prod},
            {dev_mode, false},
            {include_src, false}
        ]}
    ]},

    {lint, [
        {plugins, [
            {rebar3_lint, "5.0.4"}
        ]}
    ]}
]}.

%% Elvis style rules — shared macula_min ruleset (mirrors evoq/reckon-db).
%% Targets deep nesting, nested try/catch, if-expressions. The plugin is in
%% the `lint' profile, so the command is `rebar3 as lint lint'.
{elvis, [
    {rulesets, #{
        macula_min => [
            {elvis_style, no_deep_nesting, #{level => 2}},
            {elvis_style, no_nested_try_catch, #{}},
            {elvis_style, no_if_expression, #{}}
        ]
    }},
    {config, [
        #{files => ["src/**/*.erl"], ruleset => macula_min}
    ]}
]}.

%% Documentation
{ex_doc, [
    %% Historical CHANGELOG entries name functions that are hidden or
    %% private today, and link the unrendered CHANGELOG_LEGACY.md.
    %% Rewriting past entries to please the link checker would change
    %% what was written at the time, so those references are not
    %% checked in that one file.
    {skip_undefined_reference_warnings_on, ["CHANGELOG.md"]},
    {extras, [
        {"README.md", #{title => "Overview"}},
        {"CHANGELOG.md", #{title => "Changelog"}},
        %% CHANGELOG_LEGACY.md (pre-3.0) is shipped in the hex package
        %% but intentionally NOT rendered in ex_doc — legacy entries
        %% predate the 3.0 wire-format cutover and use EDoc-style
        %% formatting that doesn't round-trip cleanly through ex_doc's
        %% Markdown parser. View the raw file on GitHub if you need
        %% pre-3.0 history.
        {"LICENSE", #{title => "License"}},
        {"docs/GLOSSARY.md", #{title => "Glossary"}},
        %% SDK Guides — daemon-facing (supervised wrappers)
        {"docs/guides/rpc/RPC_GUIDE.md", #{title => "RPC Guide"}},
        {"docs/guides/rpc/RPC_PROTOCOL.md", #{title => "RPC Protocol"}},
        {"docs/guides/pubsub/PUBSUB_GUIDE.md", #{title => "PubSub Guide"}},
        {"docs/guides/pubsub/PUBSUB_PROTOCOL.md", #{title => "PubSub Protocol"}},
        {"docs/guides/content/CONTENT_GUIDE.md", #{title => "Content Guide"}},
        {"docs/guides/content/CONTENT_PROTOCOL.md", #{title => "Content Protocol"}},
        {"docs/guides/streaming/STREAMING_GUIDE.md", #{title => "Streaming Guide"}},
        {"docs/guides/streaming/STREAMING_PROTOCOL.md", #{title => "Streaming Protocol"}},
        %% Shared — cross-cutting, needed regardless of which primitive pair
        {"docs/guides/shared/CONNECTING_GUIDE.md", #{title => "Connecting"}},
        {"docs/guides/shared/TOPIC_NAMING_GUIDE.md", #{title => "Topic Naming Convention"}},
        {"docs/guides/shared/AUTHORIZATION_GUIDE.md", #{title => "Authorization (UCAN/DID)"}},
        {"docs/guides/shared/MRI_GUIDE.md", #{title => "MRI (Resource Identifiers)"}},
        {"docs/guides/shared/RECORDS_GUIDE.md", #{title => "Records Guide"}},
        %% Separate capability axis — not primitive-pair-shared
        {"docs/guides/DIST_OVER_MESH_GUIDE.md", #{title => "Distribution Over Mesh"}},
        {"docs/guides/CLUSTERING_GUIDE.md", #{title => "Clustering"}},
        {"docs/guides/DEVELOPMENT.md", #{title => "Development Guide"}},
        %% Overlay — realm-scoped membership + gossip, absorbed from the
        %% standalone macula-hyparview/macula-plumtree packages in 10.4.0.
        %% No supervised OTP wrapper exists yet (unlike RPC/PubSub/Content/
        %% Streaming), so each guide covers both the "why" and the raw API.
        {"docs/guides/overlay/HYPARVIEW_GUIDE.md", #{title => "HyParView Guide"}},
        {"docs/guides/overlay/PLUMTREE_GUIDE.md", #{title => "Plumtree Guide"}}
    ]},
    {main, "readme"},
    {source_url, "https://github.com/macula-io/macula"},
    {assets, #{"assets" => "assets"}},
    {logo, "artwork/logo.svg"},
    {prefix_ref_vsn_with_v, false},
    %% Mirrors groups_for_modules: the daemon-facing Guide for each
    %% primitive pair groups separately from its raw-primitive Protocol
    %% doc, so the hexdocs sidebar screams "start here" vs. "raw wire
    %% internals" the same way it already screams "Supervised Wrappers"
    %% vs. everything else below. Cross-cutting guides get their own
    %% group; DIST_OVER_MESH/CLUSTERING/DEVELOPMENT stay in ex_doc's
    %% default ungrouped bucket — not primitive-pair material, no group
    %% pulls its own weight yet.
    {groups_for_extras, [
        {"Guides", [
            <<"docs/guides/rpc/RPC_GUIDE.md">>,
            <<"docs/guides/pubsub/PUBSUB_GUIDE.md">>,
            <<"docs/guides/content/CONTENT_GUIDE.md">>,
            <<"docs/guides/streaming/STREAMING_GUIDE.md">>
        ]},
        {"Protocols", [
            <<"docs/guides/rpc/RPC_PROTOCOL.md">>,
            <<"docs/guides/pubsub/PUBSUB_PROTOCOL.md">>,
            <<"docs/guides/content/CONTENT_PROTOCOL.md">>,
            <<"docs/guides/streaming/STREAMING_PROTOCOL.md">>
        ]},
        {"Shared Guides", [
            <<"docs/guides/shared/CONNECTING_GUIDE.md">>,
            <<"docs/guides/shared/TOPIC_NAMING_GUIDE.md">>,
            <<"docs/guides/shared/AUTHORIZATION_GUIDE.md">>,
            <<"docs/guides/shared/MRI_GUIDE.md">>,
            <<"docs/guides/shared/RECORDS_GUIDE.md">>
        ]},
        {"Overlay Guides", [
            <<"docs/guides/overlay/HYPARVIEW_GUIDE.md">>,
            <<"docs/guides/overlay/PLUMTREE_GUIDE.md">>
        ]}
    ]},
    %% Surfaces the 5 supervised OTP-behaviour primitive pairs as a
    %% distinct hexdocs sidebar group, ahead of the raw wire-protocol
    %% modules (macula_client, macula_station_link, macula_stream,
    %% macula_quic, ...) an application almost never touches directly.
    %% These are what "Devs will use" (the design question that
    %% prompted this) — everything else stays in ex_doc's default
    %% ungrouped bucket rather than hand-maintaining a second group
    %% that would just drift as modules are added.
    {groups_for_modules, [
        {"Supervised Wrappers", [
            macula_request, macula_response,
            macula_publisher, macula_subscriber,
            macula_feeder, macula_download,
            macula_pusher, macula_upload,
            macula_streamer, macula_stream_sink
        ]},
        %% Realm-scoped membership + gossip, absorbed from macula-hyparview/
        %% macula-plumtree in 10.4.0; renamed to macula_* names in 14.0.0 (#67).
        {"Overlay (HyParView + Plumtree)", [
            macula_hyparview_view, macula_hyparview_proto, macula_hyparview_endorsement,
            macula_plumtree, macula_realm_pubsub, macula_realm_pubsub_server,
            macula_realm_pubsub_registry, macula_or_set
        ]}
    ]}
]}.

%% Hex package configuration
{hex, [
    {doc, #{provider => ex_doc}},
    {licenses, ["Apache-2.0"]},
    {links, #{
        <<"GitHub">> => <<"https://github.com/macula-io/macula">>,
        <<"Documentation">> => <<"https://hexdocs.pm/macula">>,
        <<"Changelog">> => <<"https://github.com/macula-io/macula/blob/main/CHANGELOG.md">>
    }},
    {description, "Macula HTTP/3 Mesh SDK — connect to relay mesh, pub/sub, RPC, Erlang distribution over QUIC, post-quantum identity (ML-DSA-87 node keys, UCAN), MRI resource identifiers"},
    %% Kept equal to the `files' list in src/macula.app.src, which is the
    %% list rebar3_hex packages.
    {files, [
        "src",
        "include",
        "priv",
        "native/macula_quic/Cargo.toml",
        "native/macula_quic/Cargo.lock",
        "native/macula_quic/src",
        "native/macula_crypto_nif/Cargo.toml",
        "native/macula_crypto_nif/Cargo.lock",
        "native/macula_crypto_nif/src",
        "native/macula_mri_nif/Cargo.toml",
        "native/macula_mri_nif/Cargo.lock",
        "native/macula_mri_nif/src",
        "native/macula_cbor_nif/Cargo.toml",
        "native/macula_cbor_nif/Cargo.lock",
        "native/macula_cbor_nif/src",
        "rebar.config",
        "rebar.lock",
        "README.md",
        "CHANGELOG.md",
        "CHANGELOG_LEGACY.md",
        "LICENSE",
        "CONTRIBUTING.md",
        "CODE_OF_CONDUCT.md"
    ]}
]}.