Skip to content

Changed all services to use one instantiation pattern - #35

Open
ErisDS wants to merge 6 commits into
codex/service-instantiation-patternfrom
codex/standardise-all-services
Open

Changed all services to use one instantiation pattern#35
ErisDS wants to merge 6 commits into
codex/service-instantiation-patternfrom
codex/standardise-all-services

Conversation

@ErisDS

@ErisDS ErisDS commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Gives every runtime service under core/server/services the same public shape: an explicit init() entry point and a service facade.
  • Makes boot responsible for construction and updates consumers to use the initialized facade, while retaining lazy failure messages for accidental use before initialization.
  • Adds a contract test that classifies every top-level directory and prevents actual service roots from drifting back to incompatible export shapes.

This PR is based on #34 so the complete pattern and this repository-wide application can be reviewed separately.

What counts as a service here?

The conversion found 56 runtime service roots and 11 directories that currently live under services/ but do not represent independently initialized runtime services:

  • subsystems or modules: auth, api-version-compatibility, public-config
  • actions or jobs: invitations, update-check
  • infrastructure or factories: mail
  • support directories: email-rendering, files, integrations, lib, verification

Those directories are classified by the contract test but are not forced into a lifecycle they do not have. Moving them to their eventual domain or Kernel locations is intentionally separate from this mechanical standardisation.

Implementation notes

  • Service roots expose {init, service}. TypeScript roots use equivalent named exports.
  • init() owns construction and is safe to call more than once. Services whose state is intentionally refreshed on each Ghost boot, such as settings, permissions, themes, and route settings, retain that behaviour.
  • Composite services keep their existing nested API where changing it would be a separate design refactor.
  • Existing wrappers that only implemented lazy construction were folded into their root where possible. Wrappers that still provide meaningful composition remain internal implementation details.

Follow-ups

  • Add a generator for the standard service skeleton and its boot registration.
  • Move the 11 classified non-service directories as the repo-structure work establishes their final homes.
  • Consider a small declarative boot loader once service dependencies and initialization phases are explicit. The shared lazySingleton facade is deliberately smaller than that future abstraction.

Testing

  • pnpm lint from ghost/core
  • pnpm exec vitest run test/unit/server/services/service-roots.test.js
  • Full unit run: 606 files, 7,861 tests
  • Full E2E run: 607 suites, 2,045 passed, 1 skipped
  • GitHub CI, including MySQL and SQLite acceptance, legacy suites, Ghost-CLI archive install, and all E2E shards

ErisDS added 3 commits August 18, 2026 05:15
no ref

Service roots had accumulated several incompatible export and lifecycle shapes, which made boot ownership and dependency usage difficult to reason about. Standardising them on explicit init and service exports gives current consumers one contract and creates a stable base for generation and future boot-loader work.
no ref

Theme activation must refresh on each Ghost boot because tests and runtime reconfiguration can reset the theme engine without changing its path. Member welcome rendering now receives link tracking as an explicit dependency and relies on boot initialization instead of invoking the old nested lifecycle shape.
no ref

Custom redirects owns adapter-backed state that must be rebuilt on each Ghost boot. Keeping the first process-wide instance leaked an earlier boot's redirect store into later tests and runtime reconfiguration.
@github-actions

Copy link
Copy Markdown

E2E Tests Failed

To view the Playwright test report locally, run:

REPORT_DIR=$(mktemp -d) && gh run download 32101607621 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant