Strata architecture and SDDMenu
On this page

Analog Angular DI lifecycle across runtimes

Qualification record for the existing SPEC-003 consumer-owned Angular controller factory. Starting main SHA: 289032f2898cd15b3fb67cf35a45e1ba9ab4afac. The synchronized feature branch is test/analog-di-lifecycle-workerd.

Scope and existing contract

SPEC-003 already established the Node contract using the public Angular APIs createApplication, createEnvironmentInjector, runInInjectionContext, EnvironmentInjector, DestroyRef and InjectionToken, together with Strata's existing controllerFactory and onCleanup. This work reuses that fixture and does not add a Strata DI container or Angular dependency to @strata-sc/analog.

The consumer owns a separate application injector for its Nitro plugin. The factory creates one child environment injector for each controller invocation, resolves the controller synchronously inside runInInjectionContext, and registers child destruction with onCleanup. Captured dependencies remain usable after await; calling inject() in a handler body fails with NG0203. The controller injector is not Analog SSR's or its server-function injector.

Resolved workspace fixture tuple observed during this run: Node 22.23.1, Angular core/common/compiler 22.1.7, Angular platform-browser 22.2.1, platform-server/router 22.2.2, Analog packages 2.7.2, Nitro 2.13.4, H3 1.15.11, TypeScript 6.0.3, Vite 8.3.0, Wrangler 4.135.0, workerd compatibility date 2026-09-21. pnpm test:analog reported 86/86 checks passed. Its production and dev cases proved a shared application CatalogService, distinct request identities at a two-request rendezvous, same-request sharing with RequestAudit, STRATA_REQUEST identity, DestroyRef and ngOnDestroy cleanup, and cleanup after sync and async handler failures. The lone-rendezvous negative control did not meet.

Cross-runtime results

GateResultEvidence
Analog development serverGO for the SPEC-003 scenariospnpm test:analog, dev scenarios passed
Nitro node-server productionGO for the SPEC-003 scenariospnpm test:analog, production scenarios passed
Cloudflare Pages build and local workerdNO-GO for Angular DIpnpm test:server-components:cloudflare, real fixture Worker and Wrangler local runtime
External packed consumer using Angular DINOT QUALIFIEDExisting consumer checks do not install and exercise this DI fixture

The Cloudflare build resolves cloudflare-pages, and the same fixture runs under local Wrangler/workerd without nodejs_compat. The Worker graph contains @angular/compiler; the browser graph does not. A request to the DI route returns 500 before the controller factory creates a child injector. Wrangler reports EvalError: Code generation from strings disallowed for this context from Angular's JitEvaluator while compiling the RequestIdentity injectable factory. Before and after stats both show zero request injectors created, zero alive, and zero service/controller destruction callbacks. The Worker continues serving other routes. This is an Angular JIT/runtime limitation, not a missing cleanup callback or a Nitro bundling failure. Retaining the JIT compiler in the Worker bundle does not make dynamic code generation available.

No supported fix was found within the existing public APIs. Do not enable nodejs_compat, introduce dynamic evaluation, or describe the result as a portable Worker recipe. Consumer-owned Angular DI on local workerd is NO-GO for this tuple and configuration.

Composition coverage and gaps

The original run kept guards, interceptors, Standard Schema validation and the DI controller separate, so it did not qualify their composition. That specific Node gap is superseded by the Angular DI HTTP composition report: the existing controller now runs behind the existing consumer-owned guard and interceptor contracts, uses Standard Schema inputs, and passes a 24-request mixed isolation matrix in real Analog dev and Nitro Node production.

The new report also covers request provider overrides, factory/provider/ constructor failures and cleanup-error precedence. Active request behavior during Nitro shutdown and abort/cancellation are still not covered. Strata's cleanup scope remains invocation-scoped and awaited; no abort propagation contract is claimed. A startup failure while creating the consumer application injector prevents the plugin from registering its routes. Shutdown with active requests has not been tested; the fixture's Nitro close hook destroys the root application when invoked, with no tested drain or cancellation guarantee.

Bundle and confidentiality measurements

The Cloudflare qualification measured the whole current fixture Worker reachable graph at 2,444,654 JavaScript bytes (674,922 gzip bytes); this fixture includes unrelated Server Component and application code, so it is not the Angular DI delta. The preceding SPEC-003 Node experiment measured 4,492 KB without its DI plugin and 7,716 KB with it; that old comparison was not repeated at this starting main. No same-revision plugin-off/on Worker comparison or compressed standalone Worker artifact measurement was run.

The current Node runner's marker checks passed: the DI marker is in the server output and absent from client, public, and SSR outputs. The current workerd check confirms @angular/compiler is absent from browser output. It does not scan private DI canaries in source maps, SSR responses, or API response bodies; those confidentiality conditions are not qualified here.

Package and CI status

No runtime package changed, so no Changeset is warranted. No package was published and no deployment was attempted. pnpm test:analog passed 86/86 checks, and pnpm test:server-components:cloudflare passed with the expected workerd DI failure characterization. The requested pnpm test:full-stack-deployed-cloudflare command was blocked by automatic review because it can deploy when credentials are present; it was not retried. The separate packed full-stack consumer ran its local workerd rehearsal successfully, without deployment. The full-stack packed consumer and the Server Component packed consumer passed, but neither constructs an Angular DI controller. Repository build, lint, typecheck, tests, format check, release tests, performance-tool tests, the requested Node/workerd integration suite, website E2E against a fresh server on port 43791, and www:build:cloudflare passed. The first default website E2E attempt reused a server on port 3000 and failed its readiness/content assertions; with the fresh server and STRATA_WWW_BASE_URL, both tests passed. Entwine 0.5.1 check and build passed. GitHub Actions were not inspected remotely, and no PR was opened as part of this report.

Verdicts

  • Consumer-owned Angular DI on Node: GO, for the SPEC-003 scenarios only.
  • Consumer-owned Angular DI on local workerd: NO-GO.
  • Request provider isolation: GO for the SPEC-003 rendezvous and the 24-request mixed Node matrix.
  • Application provider lifetime: GO for reuse across tested requests; root injector destruction on Nitro shutdown is not directly asserted.
  • Provider override: GO for the tested request-local synthetic override; broader consumer patterns remain unqualified.
  • Cleanup and error precedence: GO for tested success, denial, input, factory/provider/controller, handler, interceptor and cleanup failures on Node.
  • Guard, interceptor and validation composition with Angular DI: GO on the tested Node fixture paths.
  • Server-only bundle confidentiality: PARTIAL; marker scans pass, private canary/source-map/API/SSR tests are missing.
  • External packed consumer: NOT QUALIFIED.
  • Shared Angular SSR/controller injector: NOT QUALIFIED.
  • Shared Analog server-function injector: NOT QUALIFIED.
  • Real Cloudflare deployment: NOT RUN.
  • Abort/cancellation lifecycle: NOT QUALIFIED.
  • Real production application: NOT QUALIFIED.
  • Strata 1.0: NOT YET QUALIFIED.

Next increment

Qualify the Angular component compiler and strict server/client graph boundary in the minimal Analog fixture. Keep the Worker result NO-GO; do not implement this next increment here.

Source: docs/research/analog-di-cross-runtime-lifecycle.md

Generated by Entwine · Markdown remains the source of truth.