Accrue.Entitlements (accrue v1.5.1)

Copy Markdown View Source

Public, fail-closed entitlement gate API.

Four boolean/scalar functions answer "what has this billable paid for?" from local subscription state only (via the configured Accrue.Entitlements.Resolver, default Accrue.Entitlements.Resolver.LocalMap):

Fail-closed contract

Every function fails closed: nil/non-billable/no-customer/no-active-sub/ unmapped/raising-resolver all collapse to false / [] / 0. {:ok, true} (a present affirmative match) is the SOLE path to true. Errors, exceptions, throws, and exits are caught and collapse to the fail-closed value — a billing/availability hiccup never grants a paid feature for free.

Multi-active-plan

has_active_plan?/2 tests membership in the resolved active_plans SET (ALL active plan atoms), never the representative :plan — so a billable holding two active subscriptions on two different mapped plans answers true for BOTH, consistent with the UNION semantics of entitled?/2 and features_for/1.

Telemetry (per-check, NOT the audit ledger)

Each check emits [:accrue, :entitlements, :check, :start | :stop | :exception] via Accrue.Telemetry.span/3 with metadata %{feature, result, resolver, reason, surface, subject_type, subject_id}. subject_id is the internal customer/billable id only — never email/name or any PII. Per-check decisions are telemetry only; this module NEVER writes to the accrue_events audit ledger.

surface: :plug | :live is an additive, guard-supplied metadata dimension (D-18): entitled?/3 and has_active_plan?/3 accept an optional opts keyword list whose :surface is merged onto the same :check span, so a deny/allow from the Plug guard is distinguishable from one from the LiveView on_mount guard. It defaults to nil for direct (non-guard) callers and is internal telemetry only — the public Accrue.entitled?/2 / Accrue.has_active_plan?/2 facade delegates stay arity 2.

Summary

Functions

Returns an explicit policy deferral for Apple Family Sharing.

Returns the exact, externally-managed Apple subscription guidance.

Returns an explicit policy deferral for Apple offer authoring.

Returns the bounded Apple purchase context for an authenticated entitlement account.

Returns true iff billable's resolved active feature set contains feature. Fail-closed false otherwise.

Returns the seat/quota count for quota_key (min(cap, quantity) where a cap exists, else the raw quantity). Fail-closed 0.

Returns the sorted, deduped list of features granted by billable's active plans. Always a plain [atom], never a MapSet. Fail-closed [].

Returns true iff billable holds plan among its active plans. plan is a plan atom or a price_id string (reverse-indexed to its plan atom). Tests membership in the SET of ALL active plans — multi-active-plan correct. Fail-closed false otherwise.

Observes opaque signed Apple evidence through host-configured verification.

Explicitly converts a still-current block to a bounded warning decision.

Explicitly provisions the stable account for an authenticated host owner.

Returns a typed, revision-bound purchase preflight decision.

Queues bounded Apple lineage reconciliation without exposing provider history state.

Repairs an authorized, currently unbound Apple lineage without exposing ownership details.

Reads a canonical entitlement snapshot without provisioning or provider I/O.

Functions

apple_family_sharing()

@spec apple_family_sharing() :: {:ok, Accrue.Entitlements.Apple.Intake.Outcome.t()}

Returns an explicit policy deferral for Apple Family Sharing.

apple_management()

@spec apple_management() :: {:ok, Accrue.Entitlements.Source.Outcome.t()}

Returns the exact, externally-managed Apple subscription guidance.

apple_offer_authoring()

@spec apple_offer_authoring() :: {:ok, Accrue.Entitlements.Apple.Intake.Outcome.t()}

Returns an explicit policy deferral for Apple offer authoring.

apple_purchase_context(account, opts \\ [])

Returns the bounded Apple purchase context for an authenticated entitlement account.

entitled?(billable, feature, opts \\ [])

@spec entitled?(term(), atom(), keyword()) :: boolean()

Returns true iff billable's resolved active feature set contains feature. Fail-closed false otherwise.

opts is an additive, internal keyword list; surface: :plug | :live (guard-supplied, D-18) is merged onto the :check span metadata. All existing 2-arity callers (incl. the Accrue.entitled?/2 facade delegate) are unaffected.

entitlement_quantity(billable, quota_key)

@spec entitlement_quantity(term(), atom()) :: non_neg_integer()

Returns the seat/quota count for quota_key (min(cap, quantity) where a cap exists, else the raw quantity). Fail-closed 0.

features_for(billable)

@spec features_for(term()) :: [atom()]

Returns the sorted, deduped list of features granted by billable's active plans. Always a plain [atom], never a MapSet. Fail-closed [].

has_active_plan?(billable, plan, opts \\ [])

@spec has_active_plan?(term(), atom() | String.t(), keyword()) :: boolean()

Returns true iff billable holds plan among its active plans. plan is a plan atom or a price_id string (reverse-indexed to its plan atom). Tests membership in the SET of ALL active plans — multi-active-plan correct. Fail-closed false otherwise.

opts is an additive, internal keyword list; surface: :plug | :live (guard-supplied, D-18) is merged onto the :check span metadata. All existing 2-arity callers (incl. the Accrue.has_active_plan?/2 facade delegate) are unaffected.

observe_apple_evidence(account, signed_transaction, opts \\ [])

Observes opaque signed Apple evidence through host-configured verification.

override_purchase_decision(decision, reason, actor_id, opts \\ [])

Explicitly converts a still-current block to a bounded warning decision.

provision_account(owner_type, owner_id, opts \\ [])

@spec provision_account(String.t(), String.t(), keyword()) ::
  {:ok, Accrue.Entitlements.Account.t()} | {:error, term()}

Explicitly provisions the stable account for an authenticated host owner.

purchase_decision(account, rail, product_id, opts \\ [])

@spec purchase_decision(
  Accrue.Entitlements.Account.t() | String.t(),
  atom(),
  String.t(),
  keyword()
) ::
  Accrue.Entitlements.PurchaseDecision.t()
  | {:error, :unauthorized_billable_reference | :account_fetch_failed}

Returns a typed, revision-bound purchase preflight decision.

reconcile_apple_lineage(account, lineage_ref, opts \\ [])

@spec reconcile_apple_lineage(Accrue.Entitlements.Account.t(), binary(), keyword()) ::
  {:ok, Accrue.Entitlements.Apple.Intake.Outcome.t()}
  | {:error, :unauthorized | :reconciliation_unavailable}

Queues bounded Apple lineage reconciliation without exposing provider history state.

repair_apple_lineage(account, lineage_ref, opts \\ [])

@spec repair_apple_lineage(Accrue.Entitlements.Account.t(), binary(), keyword()) ::
  {:ok, Accrue.Entitlements.Apple.Intake.Outcome.t()}
  | {:error, :unauthorized | :verification_failed}

Repairs an authorized, currently unbound Apple lineage without exposing ownership details.

snapshot(account_or_billable, opts \\ [])

@spec snapshot(
  Accrue.Entitlements.Account.t() | term(),
  keyword()
) :: {:ok, Accrue.Entitlements.Snapshot.t()} | {:error, :not_found}

Reads a canonical entitlement snapshot without provisioning or provider I/O.