fs-Packages — The Armory
Shared frontend service packages monorepo under the @script-development npm scope. Published to the public npm registry via OIDC Trusted Publishing.
Tech Stack
- Language: TypeScript 5.9+ (strict mode,
verbatimModuleSyntax) - Build: tsdown (Rolldown/oxc) — dual ESM + CJS output with type declarations
- Test: vitest 4 (100% coverage) + Stryker (90% mutation threshold)
- Lint / Format: oxlint + oxfmt
- Package lint: publint + attw
- Publish: OIDC Trusted Publishing (no stored tokens)
- CI: 8-gate pipeline — audit → format → lint → build → typecheck → pkg-lint → coverage → mutation
Architecture Overview
The Armory forges standardized service packages consumed across the Kendo, Brick Inventory, Entreezuil, UBLGenie, and The Laboratory territories. Each package follows a strict set of conventions:
- Factory pattern. Every package exports a
createXxxService()factory returning a plain service object. No classes, no singletons. - Single entry point. Each package has
src/index.tsas the sole barrel export. Named exports only; no defaults. - Peer dependencies. Vue-dependent packages declare
vueas a peer. Inter-package dependencies are peers too — consumers resolve the graph. - Loose coupling via structural typing.
fs-theme'sThemeStorageContractis the exemplar — it duck-types its storage dependency rather than importingfs-storage. - Identical build config. All packages share the same
tsdown.config.tsstructure. Drift is an architectural regression.
Packages
| Package | Vue | Purpose |
|---|---|---|
| fs-http | No | HTTP service factory with middleware architecture |
| fs-storage | No | localStorage service factory with prefix namespacing |
| fs-helpers | No | Tree-shakeable utilities (deep copy, type guards, case conversion) |
| fs-theme | Yes | Reactive dark/light mode with storage persistence |
| fs-loading | Yes | Loading state service with HTTP middleware |
| fs-adapter-store | Yes | Reactive adapter-store pattern with CRUD resource adapters |
| fs-toast | Yes | Component-agnostic toast queue (FIFO) |
| fs-dialog | Yes | Component-agnostic dialog stack (LIFO) with error middleware |
| fs-translation | Yes | Type-safe reactive i18n with dot-notation keys |
| fs-router | Yes | Type-safe router service factory with CRUD navigation and middleware pipeline |
Key Decisions
Most War Room ADRs target Laravel backends and do not apply to a library territory. The ones that do:
| Decision | Status | Impact |
|---|---|---|
| Adapter-Store Pattern | Accepted | Published here as fs-adapter-store; fs-packages is the canonical home |
| ADR Governance | Accepted | Governance applies; projections live in this territory's CLAUDE.md |
| Page Integration Tests | Accepted | Kendo, BIO, Entreezuil mock only @script-development/fs-http — fs-packages is the mock target |
Publishing
- Public npm registry under
@script-development/*. - Trusted Publishing via GitHub OIDC — no stored npm tokens.
- Versioning: manual
package.jsonbumps (not changesets). - Branch protection on
main: required PR + 1 approval, dismiss stale reviews, enforce on admins. - Publish workflow separates build (
contents: read) from publish (id-token: write).
Documentation
Ally-facing docs at packages.script.nl (VitePress + Cloudflare Pages). Every package has substantive coverage (What It Does, Basic Usage, API Reference). Progressive disclosure: Getting Started (quickstart) → Architecture (philosophy) → Package refs (API).