Documentation
¶
Overview ¶
activeplan.go answers the subscription paywall's ONE question: does org X hold a LIVE PAID plan? It is the commerce "active-subscription check" — the tier sibling of CheckEntitlement (per-product license). CheckEntitlement deliberately cannot answer this: it filters Status=Active ONLY (a TRIALING subscriber would be mis-read as unentitled) and it is scoped to a single product id, whereas the paywall gates on the PLAN TIER regardless of product. So ActivePaidPlan is a distinct read over the SAME org resolver + subscription store, counting ACTIVE *and* TRIALING subscriptions and classifying the tier through @hanzo/plans (clients/plan.Paid) — the single source of truth for which tiers cost money.
It is an OPTIONAL capability on the in-process client (not on the narrow types.CommerceClient interface): the paywall (routers.PlanChecker) resolves it by type-assertion, mirroring types.ModelLister. A commerce build that cannot answer (split-deploy ZAP client, disabled stub) simply does not implement it, and the paywall fails OPEN — an outage never locks out a subscriber.
client.go is the in-process inter-subsystem commerce client — the REAL implementation of cloud's types.CommerceClient, absorbed here from the retired in-process stub that used to fail closed on entitlement. It answers cloud's licensing/entitlements tier with DIRECT Go calls into the embedded commerce datastore (subscriptions) plus the @hanzo/plans vocabulary (plan → license features) — no HTTP hop, no network.
MONEY-SAFETY. CheckEntitlement NEVER fabricates a grant. It returns Active:true ONLY when a real active, unexpired subscription in the org's own datastore namespace holds a plan tier whose @hanzo/plans license-features actually name the product. Any machinery it cannot resolve (commerce not co-resident, org not resolvable, subscription query error, plans vocabulary unavailable) returns an ERROR — the entitlements gate treats an erroring client as "cannot verify ⇒ 503", the specified secure default, so an unverifiable product is never enabled. A clean "resolved, but no plan licenses this product" is a real Active:false answer (the gate turns it into a 402 upgrade prompt), never an error and never a grant.
mount.go mounts the hanzoai/commerce MODULE into a cloud binary (HIP-0106) via the NATIVE co-residence contract: commerce registers its routes directly on the HOST's zip app (EmbedConfig.App) — one router, one specificity space, zero handler adaptation. This adapter narrows cloud.Deps, boots the embed, and wires the in-process seams. Direction is one-way: cloud → commerce.
PCI SCOPE. Commerce is a LIGHT ROUTER, NOT in PCI-DSS scope: tokens + intent IDs only, NEVER a PAN. PAN-touching paths call the out-of-process Payments / Vault (ZAP-RPC); when those clients are absent the payment handlers fail closed while tenant config + admin stay served — Mount warns loudly at startup.
FAIL-SOFT. A broken Embed does NOT crash the binary: commerce degrades to a 503 on its own prefixes while every co-resident subsystem stays up.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Prefixes = []string{
"/v1/commerce",
"/_/commerce",
"/v1/store",
"/v1/catalog",
"/v1/plans",
"/v1/billing/webhooks",
"/v1/billing/auto-recharge",
}
Prefixes is every root path the commerce surface owns on the shared app. Under the native SharedApp contract most of these are registered by commerce's own setupRoutes; the list is the fail-closed 503 set AND the wire contract prefix_test pins — the route families a session gate or the AI /v1/* catch-all must never swallow.
It is exported because the composition root DECLARES it (apps.Wire's commerce entry, Prefixes: commerce.Prefixes), which is what puts commerce on the light host's manifest. Derived instead, the walk would read the `app.Group("/v1")` this file opens for the store/catalog/plan bundle as a claim on ALL of /v1 and hand commerce every request in the fleet. Same list, one owner, stated once.
Functions ¶
func BalanceCents ¶
BalanceCents returns subject's available prepaid balance (USD cents) in org, read DIRECTLY from the co-resident embedded commerce ledger — no HTTP hop. It is the native twin of the /v1/billing/balance read (billing.zapGetBalance): resolve the org's own datastore namespace, tally the subject's iam-user transactions in the currency, and return Balance - Holds clamped at zero. It reuses the SAME currentEmbedded seam the in-process entitlement client resolves through.
This is the read the money cutover (admin/finance backfill) and the admin cockpit's credit panels use when commerce runs in the SAME binary: the admin commerce HTTP client dials an unroutable in-proc address and reads $0, which would silently migrate/report nothing. When commerce is NOT co-resident this returns an ERROR (never 0), so a caller can tell "not wired" from a real zero balance and fail loud rather than move money on a phantom figure. Subject is lowercased + trimmed; an empty currency defaults to usd.
func Mount ¶
Mount boots commerce ON the shared zip app (native co-residence). commerce's own setupRoutes registers /v1/commerce/* and /_/commerce/* directly; the standalone-only surfaces (bare /healthz, legacy /admin SPA, checkout SPA root catch-all, Listen) are skipped by the SharedApp contract. This adapter registers the remaining wire-contract families with commerce's own gate chains (see Prefixes).
func PublishEmbedded ¶
func PublishEmbedded(e *commercemod.Embedded)
PublishEmbedded records the mounted Embedded as the in-process entitlement source. Mount calls it once; nil un-publishes (tests).
Types ¶
type Client ¶
type Client = types.CommerceClient
Client is the in-process inter-subsystem seam cloud's licensing/entitlements tier calls. It IS cloud's types.CommerceClient — one narrow interface (GetOrgConfig + the real CheckEntitlement), not a second copy — kept as an alias so a value satisfies both names with no adapter. Add methods here only when a consumer needs them; keep it narrow.
func InProcessClient ¶
InProcessClient returns the process-wide, lazily-resolved client cloud's pickCommerceClient wires as deps.Commerce. BuildDeps runs before MountAll, so it resolves the published Embedded per call rather than capturing one; brand answers OrgConfig even before Mount publishes.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package transport is the ONE seam that lets every cloud subsystem that speaks the commerce billing S2S surface (clients/{billing,account,admin, referrals,authors,affiliates,usage} + the request-edge metering gate in build.go) reach the co-resident, in-process commerce handler with a DIRECT Go call instead of an HTTP hop to the standalone commerce pod (CLOUD_COMMERCE_HTTP_URL, commerce.hanzo.svc:8001).
|
Package transport is the ONE seam that lets every cloud subsystem that speaks the commerce billing S2S surface (clients/{billing,account,admin, referrals,authors,affiliates,usage} + the request-edge metering gate in build.go) reach the co-resident, in-process commerce handler with a DIRECT Go call instead of an HTTP hop to the standalone commerce pod (CLOUD_COMMERCE_HTTP_URL, commerce.hanzo.svc:8001). |