Skip to main content

Shared

@green-goods/shared is the single home for everything the apps have in common: hooks, providers, stores, protocol data modules, domain types, translations, and the Storybook-backed UI foundations. If logic could ever serve two surfaces, it lives here first; the client, admin, and agent packages stay thin on purpose.

The shared foundations story: the control scale with small, medium and large inputs, a select, and the shared icon buttons and card shells
Shared control sizes and card styles. Open in Storybook.

Inside src​

Shared is layered. Modules talk to the protocol and the network; stores and workflows hold state and state machines; hooks and providers expose both to React; components render on top. Nothing in a lower layer imports from a higher one. src/MODULES.md is the folder-by-folder map and the authority on where a new piece goes.

DirectoryWhat lives there
src/modules/Protocol and platform modules, one folder each: data/ (EAS, gardens, vaults, hypercerts, Karma, IPFS, GraphQL clients), job-queue/ (the offline-first work queue), commitment-pooling/ (pool, settlement, credit and voucher-pilot data and job executors), app/ (logger, environment), and the rest
src/stores/ and src/workflows/Client state stores and the XState machines behind multi-step flows
src/hooks/Domain hooks by area: auth, garden, work, assessment, vault, cookie-jar, hypercerts, conviction, and more
src/providers/App-level providers (auth, chain, query)
src/components/Shared UI primitives with Storybook coverage, including the token stories
src/styles/The theme and the generated DesignMD tokens every surface reads
src/utils/, src/types/, src/config/Pure helpers (addresses, errors, explorers), the domain types, and the query keys and chain config
src/public-contracts/ and src/lib/The public API contracts the agent serves, and the Hypercerts library bindings
src/commitment-pooling/ and src/profile-avatar/Entry points that gather one feature's modules and hooks behind a declared export, such as @green-goods/shared/commitment-pooling and its public-site subset @green-goods/shared/commitment-pooling/public; the pooling code itself lives in src/modules/commitment-pooling/ and src/hooks/commitment-pooling/
src/i18n/en.json, es.json, pt.json; every user-facing string ships in all three
src/ontology/The domain ontology the docs and guards project from
src/__tests__/Vitest suites and the test support the apps import through @green-goods/shared/testing

Run and test​

bun run --cwd packages/shared test
bun run --cwd packages/shared typecheck

bun run --cwd packages/shared check:stories proves story coverage when UI foundations change; bun run --cwd packages/shared test --scope all-configured --coverage is the fuller pass.

How it connects​

Everything downstream imports shared through its declared package exports, never src/** paths. That boundary is what lets a hook change ship with confidence: consumers see only the public surface. The flip side is fan-out, so when you change a hook signature, data shape, or exported utility, validate from the repo root rather than only inside this package.

Conventions that will bite you​

  • All reusable hooks live here. A hook created in client or admin is a bug by convention.
  • Tailwind classes in shared ship in both apps. Each app's index.css scans shared source (@source "../../shared/src/**/*.{ts,tsx}", minus tests, mocks, and stories), so a utility written in a shared component is in both bundles. The trap is narrower: a class that appears only in a story or a test is not scanned, and a class assembled from strings at runtime is never seen, so verify a new utility in the running app, not only in Storybook.
  • Query keys come from the central queryKeys; ad-hoc query arrays break invalidation.
  • Application defaults use useCurrentChain() or DEFAULT_CHAIN_ID, never wallet chain state.
  • Shared gates decide what the apps may offer, so check them before describing a feature as available. SETTLEMENT_ENABLED in src/config/app.ts is on today; when it is false, the shared mutations and job executor refuse settlement writes and new G$ rewards in every app. The voucher pilot reads its deployed contracts only for voucher offers and the voucher reward a request can carry. Offers come through the receipt-backed SERVICE_LIVE_ROUTES in src/modules/commitment-pooling/service-access-live-config.ts. SERVICE_ISSUER_ROUTES in src/modules/commitment-pooling/service-issuer-metadata.ts pins the reward module a request's reward binds, and it holds only Green Goods' issuer route, with its confirmed terms and capacity; Tech and Sun has not confirmed its own. The credit hooks in src/hooks/commitment-pooling/useCredit.ts have no app consumer.
  • Prefer event-driven invalidation over polling.
  • New user-facing strings land in all three locale files in the same change, or the i18n gate fails.

Go deeper​