contract

package
v1.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package contract wires Ledger into the Forge dashboard's contract path. It declares the `ledger` contributor and its intents, and binds the typed handlers that answer them. The React plugin in forge-dashboard (packages/plugin-ledger) reads these intents.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(d *dispatcher.Dispatcher, reg dash.Registry, wreg dash.WardenRegistry, deps Deps) error

Register loads and validates the manifest, registers the contributor, and binds every intent. The dashboard calls it through Extension.RegisterContractContributor.

Types

type Ack

type Ack struct {
	OK bool `json:"ok"`
}

Ack is the answer to a command with nothing else to report.

type CouponApplyInput

type CouponApplyInput struct {
	SubscriptionID string `json:"subscription_id"`
	Code           string `json:"code"`
}

type CouponCreateInput

type CouponCreateInput struct {
	Code           string            `json:"code"`
	Name           string            `json:"name"`
	Type           string            `json:"type"`
	Amount         types.Money       `json:"amount"`
	Percentage     int               `json:"percentage"`
	Currency       string            `json:"currency"`
	MaxRedemptions int               `json:"max_redemptions"`
	ValidFrom      *time.Time        `json:"valid_from"`
	ValidUntil     *time.Time        `json:"valid_until"`
	Metadata       map[string]string `json:"metadata"`
}

type CouponUpdateInput

type CouponUpdateInput struct {
	ID             string              `json:"id"`
	Name           *string             `json:"name"`
	MaxRedemptions *int                `json:"max_redemptions"`
	ValidFrom      Nullable[time.Time] `json:"valid_from"`
	ValidUntil     Nullable[time.Time] `json:"valid_until"`
	Metadata       *map[string]string  `json:"metadata"`
}

CouponUpdateInput carries only the fields a coupon may change after it is created. Its code, type, value and currency are fixed, because applied coupons are priced from them on every future invoice.

type CouponsListInput

type CouponsListInput struct {
	PageInput
	// Active lists only coupons inside their validity window now.
	Active bool `json:"active"`
}

type Deps

type Deps struct {
	Engine func() *ledger.Ledger

	// AppID is the extension's configured app, used when the principal carries
	// no app_id claim. Empty in a single-app deployment.
	AppID string

	// RequireAppClaim refuses any request whose principal has no app_id claim,
	// even when AppID is set. Turn it on in a multi-app deployment, where an
	// unscoped read would return every app's rows.
	RequireAppClaim bool

	Settings func() SettingsView
}

Deps is everything the handlers need. Engine is a function because the dashboard registers contributors before every extension has finished starting; a handler that runs before the engine exists answers UNAVAILABLE.

type EntitlementCheckInput

type EntitlementCheckInput struct {
	TenantID   string `json:"tenant_id"`
	FeatureKey string `json:"feature_key"`
}

type EntitlementInvalidateInput

type EntitlementInvalidateInput struct {
	TenantID   string `json:"tenant_id"`
	FeatureKey string `json:"feature_key"`
}

type FeatureCreateInput

type FeatureCreateInput struct {
	Key          string            `json:"key"`
	Name         string            `json:"name"`
	Description  string            `json:"description"`
	Type         string            `json:"type"`
	DefaultLimit int64             `json:"default_limit"`
	Period       string            `json:"period"`
	SoftLimit    bool              `json:"soft_limit"`
	Metadata     map[string]string `json:"metadata"`
}

FeatureCreateInput carries a new catalog feature. Its key and type are fixed once created: plans refer to a catalog feature by key and price it by type.

type FeatureUpdateInput

type FeatureUpdateInput struct {
	ID           string             `json:"id"`
	Name         *string            `json:"name"`
	Description  *string            `json:"description"`
	DefaultLimit *int64             `json:"default_limit"`
	Period       *string            `json:"period"`
	SoftLimit    *bool              `json:"soft_limit"`
	Metadata     *map[string]string `json:"metadata"`
}

FeatureUpdateInput names only what changes. An omitted field is left alone. There is no key or type: those are fixed once the feature is created.

type FeatureUsage

type FeatureUsage struct {
	Key       string `json:"key"`
	Name      string `json:"name"`
	Type      string `json:"type"`
	Period    string `json:"period"`
	Limit     int64  `json:"limit"`
	Used      int64  `json:"used"`
	Remaining int64  `json:"remaining"`
	SoftLimit bool   `json:"soft_limit"`
	OverLimit bool   `json:"over_limit"`
	Enabled   bool   `json:"enabled"`
}

type FeaturesListInput

type FeaturesListInput struct {
	PageInput
	Status string `json:"status"`
	// Global lists the catalog shared by every app instead of this app's own.
	Global bool `json:"global"`
}

type IDInput

type IDInput struct {
	ID string `json:"id"`
}

IDInput is the request for every intent that names one entity.

type ImportInput

type ImportInput struct {
	ProviderName string `json:"provider_name"`
	ProviderID   string `json:"provider_id"`
}

ImportInput names one record at a payment provider. An empty provider_name means the first registered provider, as the engine reads it.

type InvoiceDetail

type InvoiceDetail struct {
	Invoice       *invoice.Invoice           `json:"invoice"`
	Subscription  *subscription.Subscription `json:"subscription"`
	ExportFormats []string                   `json:"export_formats"`
}

type InvoiceExport

type InvoiceExport struct {
	Format   string `json:"format"`
	Filename string `json:"filename"`
	Content  []byte `json:"content"`
}

type InvoiceExportInput

type InvoiceExportInput struct {
	ID     string `json:"id"`
	Format string `json:"format"`
}

type InvoiceGenerateInput

type InvoiceGenerateInput struct {
	SubscriptionID string     `json:"subscription_id"`
	PeriodStart    *time.Time `json:"period_start,omitempty"`
	PeriodEnd      *time.Time `json:"period_end,omitempty"`
}

InvoiceGenerateInput names the subscription and, optionally, a period it has already had. With no period the invoice is for the current one.

type InvoiceMarkPaidInput

type InvoiceMarkPaidInput struct {
	ID         string     `json:"id"`
	PaymentRef string     `json:"payment_ref"`
	PaidAt     *time.Time `json:"paid_at"`
}

type InvoiceVoidInput

type InvoiceVoidInput struct {
	ID     string `json:"id"`
	Reason string `json:"reason"`
}

type InvoicesListInput

type InvoicesListInput struct {
	PageInput
	TenantID string     `json:"tenant_id"`
	Status   string     `json:"status"`
	Start    *time.Time `json:"start"`
	End      *time.Time `json:"end"`
}

type Nullable

type Nullable[T any] struct {
	Set   bool
	Null  bool
	Value T
}

Nullable is an update field that can be left alone, cleared, or set. A pointer cannot do this: JSON null and an absent key both decode to nil. A non-pointer type implementing json.Unmarshaler is called for null, so the three cases stay distinct.

func (*Nullable[T]) UnmarshalJSON

func (n *Nullable[T]) UnmarshalJSON(b []byte) error

type OverviewStats

type OverviewStats struct {
	Plans                 int            `json:"plans"`
	ActivePlans           int            `json:"active_plans"`
	SubscriptionsByStatus map[string]int `json:"subscriptions_by_status"`
	PendingInvoices       int            `json:"pending_invoices"`
	PastDueInvoices       int            `json:"past_due_invoices"`
	Coupons               int            `json:"coupons"`
	// Capped is true when a count reached the scan bound; the counts are then
	// lower bounds and the page must say so.
	Capped bool `json:"capped"`
}

type Page

type Page[T any] struct {
	Items   []T  `json:"items"`
	Limit   int  `json:"limit"`
	Offset  int  `json:"offset"`
	HasMore bool `json:"has_more"`
}

Page is the shape of every list response.

type PageInput

type PageInput struct {
	Limit  int `json:"limit"`
	Offset int `json:"offset"`
}

PageInput is the paging half of every list request.

type PaymentMethods

type PaymentMethods struct {
	Configured bool                     `json:"configured"`
	Methods    []provider.PaymentMethod `json:"methods"`
}

type PaymentMethodsInput

type PaymentMethodsInput struct {
	TenantID string `json:"tenant_id"`
}

type PlanCreateInput

type PlanCreateInput struct {
	Name        string            `json:"name"`
	Slug        string            `json:"slug"`
	Description string            `json:"description"`
	Currency    string            `json:"currency"`
	TrialDays   int               `json:"trial_days"`
	Features    []plan.Feature    `json:"features"`
	Pricing     *plan.Pricing     `json:"pricing"`
	Metadata    map[string]string `json:"metadata"`
}

type PlanUpdateInput

type PlanUpdateInput struct {
	ID          string             `json:"id"`
	Name        *string            `json:"name"`
	Slug        *string            `json:"slug"`
	Description *string            `json:"description"`
	Currency    *string            `json:"currency"`
	TrialDays   *int               `json:"trial_days"`
	Features    *[]plan.Feature    `json:"features"`
	Pricing     *plan.Pricing      `json:"pricing"`
	Metadata    *map[string]string `json:"metadata"`
}

PlanUpdateInput names only what changes. An omitted field is left alone. `features` and `pricing`, when present, replace the plan's whole list or pricing block.

type PlansListInput

type PlansListInput struct {
	PageInput
	Status string `json:"status"`
}

type RecentInvoicesInput

type RecentInvoicesInput struct {
	Limit int `json:"limit"`
}

type SettingsDetail

type SettingsDetail struct {
	SettingsView
	AppID           string   `json:"app_id"`
	RequireAppClaim bool     `json:"require_app_claim"`
	Providers       []string `json:"providers"`
	InvoiceFormats  []string `json:"invoice_formats"`
}

type SettingsView

type SettingsView struct {
	MeterBatchSize      int    `json:"meter_batch_size"`
	MeterFlushInterval  string `json:"meter_flush_interval"`
	EntitlementCacheTTL string `json:"entitlement_cache_ttl"`
	// LifecycleInterval is how often the lifecycle clock runs, as a Go
	// duration, or "off".
	LifecycleInterval string `json:"lifecycle_interval"`
}

SettingsView is the read-only engine configuration settings.detail reports. It comes from the extension's resolved configuration, not from constants.

type SubscriptionCancelInput

type SubscriptionCancelInput struct {
	ID string `json:"id"`
	// Immediately ends the subscription now. Otherwise it ends at the close of
	// the current billing period.
	Immediately bool `json:"immediately"`
}

type SubscriptionChangePlanInput

type SubscriptionChangePlanInput struct {
	ID       string            `json:"id"`
	PlanID   string            `json:"plan_id"`
	Quantity *map[string]int64 `json:"quantity"`
}

type SubscriptionCreateInput

type SubscriptionCreateInput struct {
	TenantID string           `json:"tenant_id"`
	PlanID   string           `json:"plan_id"`
	Quantity map[string]int64 `json:"quantity"`
}

type SubscriptionDetail

type SubscriptionDetail struct {
	Subscription   *subscription.Subscription `json:"subscription"`
	Plan           *plan.Plan                 `json:"plan"`
	AppliedCoupons []*coupon.Coupon           `json:"applied_coupons"`
}

type SubscriptionUsage

type SubscriptionUsage struct {
	Features []FeatureUsage `json:"features"`
}

type SubscriptionsListInput

type SubscriptionsListInput struct {
	PageInput
	// TenantID narrows the list to one customer. Empty lists every customer in
	// the app; the app, not the tenant, is the scope.
	TenantID string `json:"tenant_id"`
	Status   string `json:"status"`
}

type UsageAggregateInput

type UsageAggregateInput struct {
	TenantID    string   `json:"tenant_id"`
	FeatureKeys []string `json:"feature_keys"`
	Period      string   `json:"period"`
}

type UsageEventsInput

type UsageEventsInput struct {
	PageInput
	TenantID   string     `json:"tenant_id"`
	FeatureKey string     `json:"feature_key"`
	Start      *time.Time `json:"start"`
	End        *time.Time `json:"end"`
}

type UsageTotals

type UsageTotals struct {
	Period string           `json:"period"`
	Totals map[string]int64 `json:"totals"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL