Provider-agnostic address infrastructure for modern applications.
AddressFlow sits between applications and location providers (Google Maps Platform, OpenStreetMap/Nominatim, Mapbox) to provide deterministic normalization, automatic request deduplication (traffic merging), tenant-owned address persistence, geographic boundary cost guards, and native geospatial map visualization.
- Provider-Agnostic Abstraction: Switch or failover between Google Maps, Mapbox, and configured OpenStreetMap/Nominatim instances without changing client code.
- Geographic Boundary & Cost Guard: Pre-flight checks prevent out-of-boundary queries from generating expensive upstream API calls.
- Automatic Request Deduplication (Traffic Merging): Concurrent requests with identical effective parameters share a provider call within one server process. Billing session tokens, languages, limits, tenant policies, and exact coordinates remain separate.
- Deterministic Normalization: Versioned Unicode NFKC string normalizer with abbreviation expansion.
- Leaflet.js & MapLibre GL Ready: Native GeoJSON formatters and map helpers (
@addressflow/map-helpers). - Application-Owned Data: Decouples application address records from third-party provider IDs.
- Usage & Cost Optimization Analytics: Transparent visibility into deduplicated requests, application hits, and provider request reductions.
- License: See LICENSE for the terms currently shipped in this repository.
AddressFlow supplies the address layer for a platform: search, geocoding, reverse lookup, normalization, provider routing, permitted address reuse, and upstream accounting. Your platform owns its business records and customer experience. Map rendering and map tiles are configured separately.
| Service or package | How a platform uses it | Current boundary |
|---|---|---|
@addressflow/client |
Call the AddressFlow API from a platform backend through a consistent TypeScript interface | Routing executes in the API server; the client does not hold provider credentials or run fallback logic |
| Google Maps Platform | Autocomplete, place resolution, forward and reverse geocoding | Session, storage, attribution, and map-display restrictions apply |
| Mapbox | Address autocomplete, ID lookup, forward and reverse geocoding | The adapter uses temporary Geocoding v5; permanent storage and Search Box POI discovery are not implemented |
| OSM through Nominatim | Geocode submitted addresses and reverse-geocode coordinates using a configured instance | Requires a private or contracted endpoint; autocomplete is unsupported |
| Leaflet | Render permitted locations on a raster map with markers and popups | A rendering library; does not perform geocoding or supply a tile-hosting contract |
| MapLibre GL | Render permitted locations as GeoJSON on a vector or raster map | A rendering library; configure a compatible style and tile service separately |
@addressflow/map-helpers |
Adapt canonical addresses to Leaflet coordinates/GeoJSON or a MapLibre source | Provides data helpers; the platform initializes the map and displays attribution |
OSM is a data ecosystem, Nominatim is a geocoder, and Leaflet/MapLibre are renderers. They are separate choices in the platform architecture. Google Places content displayed on a map must follow Google's map-display requirements; setting mapEngine helps provider selection, but applications must also render the returned content and attribution correctly. See Google's policy. Mapbox Geocoding v5 no longer supplies POI discovery; directory listings remain your own records or a separately licensed data source. See Mapbox's API documentation.
flowchart TD
Users["Listing owners, organizers, customers"] --> UI["Your platform forms and map pages"]
UI --> Backend["Your backend with AddressFlow client SDK"]
Backend --> Records["Your listings, venues, events and service providers"]
Backend --> API["AddressFlow API: authentication and geographic policy"]
API --> Local["Check verified, permitted local address match"]
Local -->|"Match"| Result["Canonical address and attribution"]
Local -->|"Miss"| Router["Select suitable primary and at most one fallback"]
Router --> Google["Google Maps APIs"]
Router --> Mapbox["Mapbox Geocoding"]
Router --> Nominatim["Configured Nominatim instance"]
Router -.->|"Record every HTTP attempt before dispatch"| Ledger["PostgreSQL upstream attempt ledger"]
Google --> Result
Mapbox --> Result
Nominatim --> Result
Result --> Backend
Backend --> Storage["Store only independently owned or retention-permitted data"]
Backend --> UI
UI --> Renderer["Compatible Google Map, Leaflet or MapLibre"]
Tiles["Separately configured map styles and tile service"] --> Renderer
- Deploy the AddressFlow API with PostgreSQL, apply the schema migration, and configure at least one provider. Redis is optional for distributed rate limiting.
- Provision the organization, project, and hashed API key through your deployment's database/admin tooling. Configure country/bounds restrictions, a primary provider, one fallback, and the intended map engine. A public onboarding/admin API and a setup wizard are planned, not currently supplied.
- Keep the AddressFlow key in your platform backend and call
@addressflow/clientthere. Provider credentials stay in the AddressFlow server environment. Give the browser your own application endpoints rather than a privileged server key. - For autocomplete, debounce input in the application, create one token per interaction, then resolve only the user-selected reference with its provider, identifier, type, and the same token. For a submitted full address, use
mode: "geocode". Resolve never switches the selected identifier to another provider. - Save business records in your platform database. Save address content through
POST /v1/addressesonly when retention is permitted. Attach a permitted identifier separately withPOST /v1/addresses/:id/provider-references. These write endpoints currently use HTTP; the client SDK exposes search, resolve, reverse, provider discovery, and usage methods. - Render the returned or legally retained coordinates using a compatible map engine, with attribution. Investigate usage through
client.usage.getSummary()orGET /v1/usage; reconcile actual charges with provider invoices.
For example, an event platform backend can geocode an organizer-submitted venue address through one SDK call:
import { AddressFlowClient } from "@addressflow/client";
const addressflow = new AddressFlowClient({
baseUrl: process.env.ADDRESSFLOW_URL,
apiKey: process.env.ADDRESSFLOW_API_KEY,
});
export async function findVenue(addressText: string) {
return addressflow.address.search({
query: addressText,
mode: "geocode",
countryCode: "IN",
language: "en",
limit: 5,
});
}The platform presents the candidates for confirmation. This call does not automatically save provider content, verify deliverability, or create an event. Configure the routing policy on the server; no provider-switching code is needed in findVenue.
A business owner enters a shop address during onboarding. AddressFlow supplies candidates or geocodes a submitted address; the owner confirms the intended location. The directory stores the listing and any retention-permitted location, then renders its own business records on a map.
flowchart LR
Owner["Business owner supplies address"] --> Lookup["AddressFlow search or geocode"]
Lookup --> Confirm["Owner confirms location"]
Confirm --> Save["Save listing and permitted location"]
Save --> Discover["Browse directory listings on a compatible map"]
- Provider use: Use Mapbox or Google for autocomplete, with provider-specific resolution. For a Leaflet/MapLibre directory that needs retained coordinates, use independently owned data or configured Nominatim geocoding where storage is permitted. Google's Places display rules apply when choosing a Google Maps experience.
- Development saved: The same address form/backend contract can serve restaurants, shops, and professional listings. Your team reuses normalization, typed provider references, geographic restrictions, bounded fallback, and usage accounting instead of implementing them separately for each provider.
- Platform work: Listing categories, owner verification, business hours, reviews, photos, duplicate-business detection, and nearby/radius search over your own records remain application features. AddressFlow's exact address matching does not merge duplicate businesses or provide a Yelp data feed.
An organizer supplies a venue address. AddressFlow geocodes it; the organizer confirms the location and may provide an independently sourced entrance or meeting-point description. The platform creates a venue record linked to events. Recurring events reuse the legally retained venue location through the platform's venue ID, avoiding a geocoding request on every event page view.
flowchart LR
Organizer["Organizer supplies venue address"] --> Lookup["AddressFlow geocodes and applies policy"]
Lookup --> Confirm["Confirm venue location"]
Confirm --> Venue["Venue record with permitted location"]
Venue --> Events["Multiple events reference the same venue"]
Events --> Map["Calendar and compatible venue map"]
- Provider use: A configured Nominatim instance can geocode submitted addresses and support retained OSM-derived venue data with attribution. Mapbox can support temporary interactive lookup; Google can support a Google Maps venue experience. Retaining paid-provider content requires the appropriate rights; changing field names or asking for confirmation does not grant them.
- Development saved: One address integration supports venue creation, venue edits, and coordinate-to-address lookup. Provider failures and completeness checks use the same routing policy, while the platform reuses its venue records across recurring events.
- Platform work: Event schedules, recurrence, ticketing, venue capacity, accessibility details, entrance verification, directions, and travel-time calculations remain separate features. AddressFlow does not establish that a venue is open or an event exists.
A professional submits a business location or a customer supplies a job address. AddressFlow standardizes the location and applies the project's geographic policy. The platform uses legally retained coordinates to match that job against its own service-area rules and available professionals. If a customer deliberately shares a pin, reverse geocoding can help label it; the platform handles consent and who may view the address.
flowchart LR
Input["Professional location or customer job address"] --> Lookup["AddressFlow geocode or reverse lookup"]
Lookup --> Location["Canonical location with provenance"]
Location --> Match["Your service-area and availability matching"]
Match --> Results["Eligible professionals and booking flow"]
- Provider use: Use autocomplete-capable providers during job entry, or configured Nominatim for submitted-address geocoding. Set country/bounds restrictions to avoid unsuitable searches. Use Leaflet/MapLibre for retention-permitted map data, or Google Maps when displaying Google Places content on a map.
- Development saved: Professionals and customers share one address model despite entering data through different forms. The team reuses reverse lookup, regional restrictions, provider failure handling, attribution metadata, and operation-level diagnostics.
- Platform work: Service-area polygons, radius/distance calculations, dispatch, live tracking, availability, professional ranking, quotes, and payments remain application logic. Current AddressFlow guards support countries and rectangular bounds; they are not a service-area matching engine or a navigation API.
AddressFlow consolidates repeated integration work behind one API. The benefit grows when several products, teams, or tenants use the same address infrastructure.
| Work your team would otherwise repeat | What AddressFlow already supplies | What your team still builds |
|---|---|---|
| Learn and map three provider response formats | Typed canonical address components and provider references | Product-specific address forms and confirmation |
| Implement provider selection and failure handling in every application | Server-side suitability checks and at most one fallback | Provider contracts, configuration, and coverage evaluation |
| Reimplement geographic checks and duplicate concurrent requests | Country/bounds policy and process-local request sharing with parameter-safe keys | Business service areas and any cross-replica request coordination |
| Debug Google sessions and ambiguous OSM IDs | Session-token forwarding and typed OSM identity | Correct token lifecycle and user selection in the application |
| Build repeated persistence checks | Retention checks, tenant-scoped references, verified local reuse, and transactional writes | Truthful data provenance and product record relationships |
| Translate coordinates for different map renderers | Leaflet and MapLibre data helpers and canonical coordinates | Map initialization, tiles/styles, clustering, and attribution display |
| Add operational counters separately to each integration | Per-HTTP-attempt operation, outcome, latency, and pending-state accounting | Invoice reconciliation and any actual monetary savings calculation |
For a company running a business directory, an events product, and a services marketplace, one provider or routing change can be made in the shared AddressFlow deployment while all three keep the same client contract. Existing geographic rules and accounting remain in that shared layer. A renderer change still requires frontend work, compatible data rights, and map configuration.
These are reductions in integration tasks, not a measured claim that delivery takes a particular number of hours or that provider bills fall by a fixed percentage. Measure onboarding time, provider-specific code maintained by each product, lookup success, and upstream attempts per completed interaction to assess the benefit in your own platform.
Work in progress (WIP) — not yet available: The management panel is a product workstream built around the existing SDKs, API, provider adapters, storage, and accounting. Its scope includes guided setup, provider management, operational dashboards, and paid service options. The web panel, customer signup, subscription billing, secrets vault, team administration, and managed hosting are not implemented in this repository yet.
The panel is being designed to let a customer create a project, connect providers, select a directory preset, test an address flow, and copy the integration settings without manually editing database rows. Charge for setup convenience, operational visibility, management features, and managed infrastructure. Third-party geocoding and tile charges remain separate unless an explicitly agreed provider contract permits another arrangement.
flowchart LR
Admin["Customer administrator"] --> Panel["Web management panel - WIP"]
Panel --> AdminAPI["Management API - WIP"]
AdminAPI --> Setup["Projects, presets and routing configuration"]
AdminAPI --> Vault["Encrypted provider-secret storage - WIP"]
AdminAPI --> Reporting["Usage and diagnostic reporting"]
Setup --> Runtime["AddressFlow runtime"]
Vault --> Runtime
Runtime --> Ledger["Existing upstream attempt ledger"]
Ledger --> Reporting
Billing["Subscriptions and entitlements - WIP"] --> AdminAPI
Provider credentials are currently deployment-wide environment variables. Connecting different credentials for each customer's project requires new backend secret storage and tenant-scoped credential selection; a panel alone will not provide that isolation.
| WIP capability | Customer value | Backend work required beyond today's runtime |
|---|---|---|
| Guided quick setup | Create a project, choose countries and map engine, and receive a working configuration | Project/key management endpoints, setup validation, and explicit test-dispatch confirmation |
| Directory presets | Start with business-listing, event-venue, or local-service workflows | Versioned presets for existing settings, with clearly separate geocode/autocomplete choices |
| Provider connections | Manage credentials without editing server environment files | Encrypted secrets, redacted displays, rotation, and tenant-scoped provider instances |
| Routing editor and preview | Choose primary/fallback and understand why a provider is eligible | Authorized configuration writes and a preview that explains policy; real lookups must use the attempt ledger |
| Usage and failure dashboard | See operations, upstream attempts, failed calls, pending outcomes, and local reuse | Time-windowed/reporting endpoints, filters, and aggregation |
| Budget and operational alerts | Learn when usage or errors exceed a configured threshold | Alert jobs, delivery configuration, and limits distinct from advisory alerts; cost estimates need verified tariffs and billing reconciliation |
| Team roles and change history | Delegate setup while controlling who changes keys and policy | Administrator authentication, role checks, and an audit trail separate from the upstream attempt ledger |
| Assisted onboarding and support | Get help configuring an integration and diagnosing provider behavior | Documented service scope, support workflow, and agreed response commitments |
| Managed deployments | Avoid operating AddressFlow infrastructure directly | Hosting automation, tenant isolation, backup/restore, monitoring, and operational support |
Directory presets would configure the address portion of a product. They would not create a complete Yelp-style directory, event marketplace, or booking system.
| Proposed offering | Fee model | Included value |
|---|---|---|
| Self-hosted runtime | Use under the repository's current license | Existing SDK/API capabilities; customers operate infrastructure and provider accounts |
| Assisted setup | One-time service fee | Provider configuration, migration assistance, and integration walkthrough |
| Management Panel Pro | Recurring workspace/project subscription | Setup wizard, configuration management, dashboards, and team controls as they become available |
| Managed AddressFlow | Platform subscription plus clearly defined platform usage charges | Hosted runtime, management panel, backups, monitoring, and support under an agreed service scope |
No prices or subscriptions are active in this repository. The proposed packaging does not change the shipped license, and purchasing a panel would not create additional rights to retain or redistribute third-party map data.
A practical first release is a setup wizard plus project/key management, a routing editor, a metered test console, and a dashboard backed by the existing attempt ledger. Add tenant-scoped secret handling before offering separate provider connections to shared-hosting customers. Add payment checkout, verified subscription webhooks, and server-enforced entitlements before selling self-service subscriptions; hide/show controls in a frontend are insufficient for access control. Enterprise identity integrations, advanced billing reconciliation, and service-area intelligence can follow demonstrated customer demand.
WIP — not yet available as an agent tool server or SDK: This workstream extends AddressFlow into a controlled execution layer for AI agents that need location services. The goal is to let an agent find and resolve addresses through a narrow tool interface while the platform controls provider access, geographic scope, and upstream consumption.
An agent enriching directory listings, preparing an event page, or matching a customer to local services can otherwise repeat searches, retry failures, and call several providers for the same task. A limit on one AddressFlow request does not limit an entire agent run. The harness is intended to enforce that wider boundary rather than relying on the agent's prompt to stay within budget.
flowchart TD
Agent["AI agent working on a listing, event or service request"] --> Tools["Scoped location tools - WIP"]
Tools --> Policy["Validate tenant, operation and geographic policy"]
Policy --> Budget["Reserve run and tenant allowance atomically - WIP"]
Budget -->|"Allowance exhausted"| Stop["Return structured budget-exhausted result"]
Budget -->|"Allowed"| Runtime["AddressFlow verified local lookup and bounded routing"]
Runtime --> Ledger["Record each upstream attempt before dispatch"]
Ledger --> Provider["Dispatch to an eligible provider"]
Provider --> Result["Canonical result with provenance and attribution"]
Result --> Agent
Ledger --> Accounting["Run-level accounting and panel visibility - WIP"]
The intended tools are address search, selected-reference resolution, and reverse geocoding. These are conceptual tool interfaces, not exported agent tools today. They would accept typed inputs and return canonical addresses, provider references, attribution, request/run IDs, and a structured outcome such as success, no result, policy rejection, or budget exhaustion.
The agent would receive a scoped tool credential, not Google or Mapbox credentials. A trusted application would assign tenant identity, run identity, allowed operations, regions, and limits. Provider access would remain behind AddressFlow; the application must also restrict direct provider/network access in its agent runtime so the agent cannot bypass the harness.
Examples of the intended use:
- Directory assistant: Geocode an owner-supplied listing address within a configured region, request clarification for ambiguous candidates, and stop when the run allowance is exhausted. Retain only content permitted by its provenance.
- Event assistant: Locate a submitted venue and reuse an existing permitted venue record. Avoid resolving the same selected venue repeatedly while generating descriptions, schedules, and event pages.
- Local-service assistant: Resolve a customer-supplied job location and pass the result to the platform's own service-area matching. Restrict which agent roles may access a private job address and how much lookup work a booking task can trigger.
| Control | Already available in AddressFlow | Harness work in progress |
|---|---|---|
| Typed location operations | Search, resolve, and reverse API/SDK methods | Agent tool schemas and integrations, such as an MCP tool server |
| Geographic scope | Country/bounds checks and response filtering | Trusted run policy that the agent cannot expand |
| Provider selection | Suitable primary, at most one fallback, and no cross-provider ID resolution | Per-run provider/operation allowlists enforced throughout primary and fallback selection |
| Request sharing | Identical concurrent calls share work within one process | Run-scoped idempotency and duplicate-task detection; reuse must respect provider retention and session rules |
| Consumption limits | Authenticated API-key rate limits and bounded calls per request | Atomic tenant/run upstream-attempt allowances, total tool-call limits, concurrency limits, deadlines, and cancellation |
| Attempt accounting | Durable pending/success/error records with provider and operation | Link attempts to agent runs, tool calls, reserved allowance, and reconciliation |
| Operator visibility | Usage summary API and operation counts | Panel views for agent runs, policy decisions, exhausted allowances, and controlled overrides |
Run limits must be enforced at the actual HTTP-dispatch boundary. A fallback consumes another upstream allowance; a verified local match does not. A separate tool-call limit bounds loops that repeatedly hit local data or are rejected before dispatch. Concurrent workers must reserve allowance atomically, and all fallback candidates must satisfy the same trusted run policy. Retries after a timeout must not reset the budget or assume the earlier request was free; pending attempts remain accounted for until their outcome is known.
The first harness release should enforce hard limits on upstream attempts and total tool calls. A monetary cap needs additional, verified operation pricing and provider billing reconciliation, including session billing and uncertain outcomes. Until that exists, the harness must describe its limit as an attempt allowance rather than promise a guaranteed currency cap. It must also preserve billing-session identity and avoid caching restricted provider content merely to reduce calls.
This workstream can become an additional paid management-panel capability: configure agent policies, inspect run-level consumption, and manage allowances from one interface. The commercial value is controlled, observable location access for automated workflows. The current release does not yet provide run-level budget enforcement or guarantee a reduction in provider invoices.
packages/types: Canonical Address, GeoJSON, and Provider typespackages/core: Normalization engine, Geoguard, Request Deduplicator, Routerpackages/providers/nominatim: Self-hosted or contracted Nominatim geocoding providerpackages/providers/google: Google Maps Places (New) & Geocoding providerpackages/providers/mapbox: Mapbox Places Geocoding v5 providerpackages/providers/mock: Offline testing mock providerpackages/server: PostgreSQL & Redis persistence, rate limiting, and orchestratorpackages/client: TypeScript Client SDKpackages/map-helpers: Leaflet and MapLibre adaptersapps/api: REST API server (/v1/...)
This README describes the current integration contract and the management panel and AI agent harness workstreams in progress. See the integration overview above for application flows and the provider routing, storage, and accounting section below for runtime configuration and migration details.
pnpm install
pnpm build
pnpm test
pnpm typecheckThe API requires DATABASE_URL for authentication, address persistence, and durable upstream accounting. There are no magic test keys or implicit development authentication. API-key quotas apply after authentication, and suspended organizations cannot authenticate. Set GOOGLE_MAPS_API_KEY, MAPBOX_ACCESS_TOKEN, or an explicit self-hosted/contracted NOMINATIM_BASE_URL. Public Nominatim is rejected: its usage policy prohibits autocomplete and requires geocoding services to operate their own service. The mock provider is registered only in test mode.
Before starting an upgraded installation, build the packages and apply the idempotent schema migration:
pnpm build
pnpm --filter @addressflow/api db:migrateThe migration adds the attempt ledger and storage verification fields, and replaces the global provider-ID constraint with an address-scoped constraint. Existing addresses remain stored but are excluded from local reuse. Review their original data rights before reimporting them; the migration does not certify, rehash, or delete legacy content. Back up the database before applying schema changes.
Search defaults to mode: "autocomplete". Use mode: "geocode" for a complete address lookup; Nominatim supports only this mode. The service first checks an exact normalized full-address match in the tenant's verified data. It verifies country, bounds, and completeness before returning local data. Stored records are indexed from their full address; a broad autocomplete query is never treated as the selected address's identity. Normalization v2 preserves hyphens, slashes, and unit markers.
Set DEFAULT_PROVIDER globally, or project settings defaultProvider, fallbackProvider, minimumAddressCompleteness (default 0.75), and mapEngine (none, google, leaflet, or maplibre). Selection checks operation support, declared country coverage, attempt tracking, and map-display compatibility. If the preferred provider is unsuitable or absent, registered suitable providers are ordered by canonical name. At most one different suitable fallback is selected, either explicitly or by that same order. An explicitly configured unavailable fallback is not silently replaced.
For geocoding and reverse lookup, completeness is the fraction of six observable fields present: formatted address, country code, street, house number, city/locality/district, and finite coordinates. A response below the threshold, empty results, or transient provider errors may trigger one fallback. The more complete response wins; equal scores retain the primary. Autocomplete requires an identifier and nonempty label and does not trigger paid details calls merely to measure completeness. These checks measure field presence, not deliverability or geographic accuracy. Provider confidence/relevance scores are not compared.
Each built-in adapter dispatches at most one HTTP request per invocation, with a four-second abort deadline and no hidden retries. Resolution requires provider and never falls back across provider-specific IDs. Nominatim IDs include their object prefix (N123, W123, or R123); legacy numeric inputs require an explicit type: "node" | "way" | "relation". openstreetmap is an alias for nominatim. Search and resolution produce consistent canonical IDs. Google details passes sessionToken and languageCode as query parameters with an Essentials field mask. Callers must generate a new token per autocomplete session, carry it through selection, and resolve using the selected reference's provider and identifier. See Google's session contract.
Permanent storage accepts independently owned user/application addresses and configured provider content whose policy explicitly permits retention (such as OSM data with attribution). Google-derived content and temporary Mapbox content are rejected even if relabeled with another source while retaining their provider references. Canonicalization does not transfer ownership. Clients remain responsible for truthfully identifying independently supplied data; stripping provenance is not a way to acquire storage rights. Unknown provider content is rejected. Raw reference metadata is discarded, and address/reference writes are transactional.
To retain a Google Place ID without copying Google content, first create an independently owned address with POST /v1/addresses, then call POST /v1/addresses/:id/provider-references with { "provider": "google", "type": "place_id", "identifier": "..." }. The endpoint checks ownership within the authenticated project. Temporary Mapbox identifiers are not accepted for permanent retention. Current defaults conservatively disable content caching for both Google and temporary Mapbox; permanent Mapbox geocoding is not enabled. See Google storage/display policy and Mapbox endpoint restrictions.
Every HTTP dispatch writes a pending upstream_attempts row before calling the provider, including its provider, operation, project, request ID, and whether it is potentially billable. The row is finalized with outcome, latency, and error code. A ledger write failure prevents dispatch; a completion-write failure leaves a pending record and does not trigger another provider. Custom adapters must declare supportsAttemptTracking, honor the supplied abort signal, and wrap their single HTTP dispatch in execution.runAttempt. Health inspection performs no hidden upstream search.
GET /v1/usage reports attempt totals, errors, pending records, and counts grouped by provider operation. Potentially billable attempts are not invoices: session discounts, free allowances, region-specific rates, and actual charges require reconciliation with provider billing. monetarySavings is always null. optimizationRatio is the fraction of completed requests served locally, rejected before dispatch, or entirely served by request sharing; it is not a money-saving percentage. Legacy usage events are excluded from the new request denominator.
Run PostgreSQL integration tests against a disposable database (the tests create and remove an isolated schema):
ADDRESSFLOW_TEST_DATABASE_URL=postgresql://localhost/addressflow_test pnpm exec vitest run