@stokr/homepage-host-federation-types
v1.0.2
Published
Ambient TypeScript declarations for Module Federation imports from the homepage host (`host/...`).
Keywords
Readme
src/shared — federated host surface + remote types
This folder has two jobs:
- Runtime barrel (
index.ts) — exposed to remotes ashost/sharedvia Module Federation. - Types package (
@stokr/homepage-host-federation-types) — ambient TypeScript declarations so remotes understandimport … from 'host/…'.
Broader host ↔ remote setup: FEDERATION.md. Expose map: src/federation/exposes.json.
Maintaining types/host.d.ts
When you add or change a host expose:
- Update
src/federation/exposes.json. - Add or update the matching
declare module 'host/…'intypes/host.d.ts. - Rebuild and deploy the host so remotes get the new runtime chunk.
- Bump / redistribute the types package so remotes get the new declarations.
When you change exports from host/shared (this barrel), update the declare module 'host/shared' block to match.
Publishing @stokr/homepage-host-federation-types
The package is types-only. package.json points at types/host.d.ts and ships only that file.
Publishing is automatic — there is no manual npm publish step. A Gitea Actions
workflow (.gitea/workflows/publish-host-types.yml)
publishes a new version whenever src/shared/types/host.d.ts or src/shared/package.json
changes on development (this repo's default branch):
- It reads the currently published version from the npm registry.
scripts/decide-publish-mode.mjscompares that to the committedpackage.jsonversion and printscommittedorbump:committed— the committed version is already ahead of what's published (you bumped it on purpose — see below). Publish it exactly as committed.bump— nothing was manually bumped. Sync the local version to match the registry's latest, then run realnpm version patchon top of that, so the actual semver increment is done by npm itself (not hand-rolled arithmetic) — this is what makes routinehost.d.tsedits publish automatically without ever needing to touch the version number.
- It publishes with
NPM_TOKEN(a repo secret with publish rights on the@stokrscope).
npm registry versions are immutable — publishing the same version twice fails outright
(403 You cannot publish over the previously published version). That's the reason
step 2 exists at all: since the bump from step 2 is never committed back to git, the
checked-in package.json version stays static across many pushes, so CI can't just
npm publish whatever's in the file — it would succeed once and then fail on every
push after that. It has to compute a genuinely new version every time.
So for routine edits to host.d.ts (adding/adjusting a type as you change an
expose), just commit and push to development — CI handles the rest.
When to bump the version yourself
Only for an intentional breaking change to the type surface (removing or
reshaping a declare module block, like the host/shell → host/shared
consolidation) — bump major so consumers see the jump:
cd src/shared
npm version major --no-git-tag-version # e.g. 1.0.1 → 2.0.0Commit that bump; CI will publish exactly that version instead of an auto patch.
Prerequisites
- The
@stokrnpm scope exists and"publishConfig": { "access": "public" }is set (required for public scoped packages) — already true inpackage.json. - An
NPM_TOKENsecret must exist in this repo's Gitea Actions secrets (Settings → Actions → Secrets onstokr/homepage, not GitHub — this repo runs Gitea Actions from.gitea/workflows/) for the workflow to succeed.
Creating NPM_TOKEN
npm removed classic tokens (Nov 2025) — there is no more "Automation token, no expiration" option. Only granular access tokens exist now, and any token with write permission is capped at 90 days — npm rejects longer expirations outright.
- npmjs.com → Access Tokens → Generate New Token → Granular Access Token.
- Permissions: Read and write.
- Scope: this package only (
@stokr/homepage-host-federation-types), or the whole@stokrorg if you want one token reusable for future auto-published packages — don't leave it at "all packages." - Expiration: 90 days (the max allowed).
- Add it as a repo secret named
NPM_TOKENin Gitea.
This token expires every 90 days and must be regenerated and re-added as the
NPM_TOKEN secret before then, or the publish step starts failing (loudly —
CI will fail, it won't silently skip). Put a reminder somewhere durable (team
calendar, on-call runbook, whatever your team actually checks); there's no way
to make an npm write token longer-lived than that today.
npm also offers "Trusted Publishing" (OIDC) for CI providers it supports, which removes the stored-token/rotation problem entirely — worth revisiting if Gitea Actions gains support for it, but not confirmed to work today.
Manual publish (fallback, e.g. testing locally)
cd src/shared
npm version patch
npm publish --dry-run # see what would be uploaded
npm publishAfter publish
Remotes install with:
npm add -D @stokr/homepage-host-federation-types@^1.0.0and keep the TypeScript reference above. Their ^ semver range means routine
patch releases are picked up on the next npm install with no devDependency
edit needed; only a manual bump (major/minor) requires updating that range.
How it works
Remote app Homepage host
───────── ─────────────
import { useAuth } from 'host/shared'
│
│ runtime: Module Federation loads host remoteEntry.js
▼
host exposes "./shared" → src/shared/index.ts → real modules
import type / editor / tsc
│
│ types only: @stokr/homepage-host-federation-types
▼
types/host.d.ts → declare module 'host/shared' { … }- Remotes never import this folder as application code at runtime.
- They import the single federated module
host/shared(seesrc/federation/exposes.json). - They install this folder (or a published copy) as a devDependency so TypeScript knows its shape.
- Automatic DTS from
@module-federation/vite(dts: { generateTypes: true }on the host) does not reliably serve the generated types to remotes yet in this project's toolchain (@mf-types.zip404s even though the manifest advertises it — likely a rough edge in this dts-plugin version with the Rolldown-based Vite build here). We maintaintypes/host.d.tsby hand, auto-published per above, until that's resolved.
Keep the declare module 'host/shared' block in sync with src/federation/exposes.json
and the real exports of src/shared/index.ts.
Folder structure
src/shared/
├── package.json # @stokr/homepage-host-federation-types (types-only package)
├── README.md # this file
├── index.ts # federated barrel → host/shared (also exports queryClient, GlobalProviders)
├── app-config.ts
├── firebase-config.ts
│
├── types/
│ └── host.d.ts # ambient modules for remotes (package entry)
├── scripts/
│ └── decide-publish-mode.mjs # used by the CI publish workflow
│
├── api/ # axios helpers, fetchData
├── context/ # AuthProvider, useAuth, session helpers
├── components/ # Header, Footer, MainMenu, 2FA, StepsProgress, …
├── providers/
│ └── GlobalProviders.tsx # QueryClientProvider + StyleSheetManager + Router + AuthProvider
├── utils/ # app URLs, user-identity, queryClient (used by context / index.ts)
└── lib-internals/ # local copies of components-library internals (see its README)| Path | Role |
| -------------------------------------------------- | ------------------------------------------------------- |
| index.ts | What remotes get from host/shared at runtime |
| types/host.d.ts | What remotes get from the types package for tsc / IDE |
| api/, context/, components/, app-config.ts | Implementation behind the barrel |
| package.json | Publishes only types/host.d.ts ("files") |
Not in this folder: domain models live in src/models/ (host-internal today). They are not part of the types package unless you add declarations or federate them later.
Consuming types in a remote
Install (no npm publish required)
Local / sibling clone:
"devDependencies": {
"@stokr/homepage-host-federation-types": "file:../homepage/src/shared"
}Or, from npm (published automatically by CI on every push that touches host.d.ts — see above):
"devDependencies": {
"@stokr/homepage-host-federation-types": "^2.0.0"
}npm add -D @stokr/homepage-host-federation-types@file:../homepage/src/shared
# or
npm add -D @stokr/homepage-host-federation-types@^2.0.0Reference the ambient declarations
Ambient declare module blocks are not picked up by normal imports alone. In the remote, add either:
/// <reference types="@stokr/homepage-host-federation-types" />(e.g. in src/vite-env.d.ts) or, if appropriate for that project:
{
"compilerOptions": {
"types": ["@stokr/homepage-host-federation-types"]
}
}Prefer the triple-slash reference if the remote already configures "types" for Vite / Jest / etc.
Peer dependencies listed in package.json (react, axios, @tanstack/react-query, …) should already be installed in the remote for federation; they are needed so types inside host.d.ts resolve.
Without publishing
Use a file: (or monorepo workspace:) dependency pointing at src/shared. Same triple-slash / types setup. Publishing is optional convenience, not required for local remotes.
