Skip to content

[pull] next from storybookjs:next#805

Merged
pull[bot] merged 25 commits into
code:nextfrom
storybookjs:next
May 29, 2026
Merged

[pull] next from storybookjs:next#805
pull[bot] merged 25 commits into
code:nextfrom
storybookjs:next

Conversation

@pull

@pull pull Bot commented May 29, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

JReinhold and others added 25 commits May 27, 2026 14:43
Replace the previously-async, preload-coupled query API with a sync default
call and an explicit `.loaded()` sugar:

- Query handlers are now strictly synchronous readers. Their ctx only exposes
  `state` and `queries` — no commands, no setState.
- `queries.foo(input)` returns the validated handler result immediately and
  fires `load(input)` in the background, deduped per (service, query, input)
  while one is already in flight.
- `await queries.foo.loaded(input)` awaits the full load (including
  transitive deps discovered through sync handler reads) before returning.
- `preload` is renamed to `load`. Load is async and receives a LoadSelf
  exposing state, queries (auto-tracked), and commands — no setState.
- `getService(id)` is now synchronous and continues to expose queries plus
  commands cross-service.
- `ReadonlySelf` / `WritableSelf` are replaced by `QuerySelf`, `LoadSelf`,
  and `CommandSelf` so each context's mutation surface is explicit.

Implementation:
- Process-global in-flight load registry keyed by stable JSON hash of the
  parsed input. Promise is registered before the body runs so synchronous
  cycle reads observe the load as in-flight.
- `.loaded()` drives a drain loop: alternates draining settled loads with
  re-running the handler under a session that tracks ancestorChain (cycle
  detection) and settledKeys (no refire). Capped at 32 iterations; overflow
  throws `OpenServiceLoadedDrainExceededError`.
- Subscriptions defer first emission until any pending load settles.
- Static builds drive `load` (instead of `preload`) via the runtime's new
  `runLoadOnce` helper, which awaits the load's local collector drain.
- Schema validation for query input/output is now sync via
  `validateSchemaSync`; async schemas raise `OpenServiceAsyncSchemaError`.

Tests cover the existing surface plus new behaviors: transitive dep await,
in-flight dedup, cycle break without deadlock, drain-loop overflow,
loaded() rejection, subscription deferred first emit, and reactive
re-emit after sync handler throws.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the "defer first emission until any in-flight load settles" logic in
subscribeToQuery. The microtask now wires up the computed/effect right away,
so subscribers receive the current state value (often null) immediately and
a follow-up emission once the load settles and state changes.

Rationale: deferring the first emission added subscribe-time coupling to the
in-flight load registry for a small UX win (no transient pre-load value).
Consumers that need to suppress the pre-load value can branch on the value
themselves. The simpler model also makes subscribe state-of-the-world
predictable regardless of whether some other caller already fired the load.

Tests updated to reflect the two-emission shape ([null, value] instead of
just [value]).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a top-of-file overview to service-runtime.ts explaining the dependency-
tracking design, then expands JSDoc on the load functions with worked
examples:

- triggerLoad: documents the register-before-run pattern and walks through
  a concrete a→b→a cycle example to show how ancestorChain protects against
  deadlock.
- runLoadBody: explains why each load invocation gets its own collector
  and wrapper map.
- buildLoadWrappedQueries: explains the lifecycle of the wrapped map and
  the three behaviors (cycle skip, .loaded() chain inheritance, .subscribe
  passthrough).
- runLoaded: documents the full algorithm with a bar.loaded() worked
  example showing both iterations of the drain+discover loop.
- createDefaultQuery: documents the three skip cases (ancestor cycle,
  already-settled, no session) inline so the call site is readable.

README adds a Worked Example table walking through the same bar→foo case
step by step, plus an explainer for the difference between sync-handler
tracking (module-scoped session) and async-load-body tracking (wrapped
self.queries).

No behavior changes — documentation only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolve open-service conflicts: keep load/loaded() API from the PR while
incorporating next's registry-based buildStaticFiles(), services preset
gating, and duplicate-registration documentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Changed service fixture IDs from 'test/' to 'internal-fixture/' for better clarity and organization.
- This update affects multiple service definitions across the open-service module, ensuring consistency in naming conventions.
- Changed the type of noInputSchema in fixtures.ts from undefined to void for improved clarity and consistency in schema definitions.
- Rename every `test/...` service id to `internal-fixture/...` per
  @ndelangen and @JReinhold's suggestion. Keeps the `test/` namespace free
  for future end-user service ids and makes it clearer at a glance which
  ids belong to the internal test suite.
- Change `noInputSchema` from `v.undefined()` to `v.void()` per
  @ndelangen. More idiomatic for "no input" semantics in valibot.
- Rewrite `createDerivedBooleanFromChildQueryServiceDef` so the derived
  query resolves the source service via `ctx.getService(...)` at handler
  call time instead of capturing the registered instance through a factory
  parameter, per @ndelangen. The fixture now matches how a real consumer
  would compose services. Updated the one test caller.

All 52 tests pass; typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Removed the `sourceService` parameter from `createDerivedBooleanFromChildQueryServiceDef` for simplification.
- Updated service fixture IDs from 'test/' to 'internal-fixture/' across multiple test files for consistency and clarity.
- Adjusted test expectations to reflect the new service IDs, ensuring all tests align with the updated naming conventions.
…s/storybook into claude/practical-jones-e3d0c1
…tion

- Updated `ctx.getService` to accept a type parameter, allowing for more precise typing of service lookups.
- Adjusted multiple service handlers to utilize the new typing feature, improving type safety and reducing the need for type assertions.
- Expanded the README with guidelines on cross-service composition and type usage for better clarity.
- Added tests to verify the correct typing behavior when resolving services with generics.

All tests pass and type checks are clean.
…rvice queries

- Replaced `static` configuration with `filePath` and `staticInputs` in multiple service definitions for consistency.
- Updated the `buildStaticFiles` function to utilize the new `filePath` and `staticInputs` properties, ensuring proper static file generation.
- Adjusted related tests to reflect changes in file path handling and static input definitions, enhancing clarity and maintainability.

All tests pass and type checks are clean.
…ce registration

- Replaced `QueryDefinition` with `AnyQueryDefinition` for enhanced type flexibility in service definitions.
- Introduced `resolveRegisteredStaticInputs` function to normalize static inputs during service registration, allowing for context-dependent inputs.
- Updated `registerService` and `getService` functions to ensure proper type casting and handling of runtime services.
- Adjusted related type definitions to improve clarity and maintainability.

All tests pass and type checks are clean.
…d related tests

- Updated service definitions to replace `filePath` with `staticPath` for consistency in static file generation.
- Adjusted related tests and documentation to reflect the new naming convention.
- Ensured all references to `filePath` are updated to maintain functionality and clarity.

All tests pass and type checks are clean.
- Removed the LoadCtx parameter from the static input resolution function to streamline the process.
- Updated the documentation to clarify the behavior of static inputs in service registration.
- Ensured that the function now directly returns the static inputs without additional checks.

All tests pass and type checks are clean.
- Enhanced the documentation for the `Query` type to clarify the behavior of the `.subscribe` method.
- Updated description to specify that subscribers receive the current value immediately and subsequent updates after the background load settles.

All tests pass and type checks are clean.
- Introduced a new test to verify that dependency loads are not refired during the final evaluation of the `.loaded()` method in service runtime.
- Updated service definitions to include a spy for monitoring load calls and ensure correct behavior.
- Enhanced documentation in the service runtime to clarify the return behavior of handlers during the final evaluation.

All tests pass and type checks are clean.
- Introduced a new test to verify that the `runLoadOnce` method does not duplicate loads when the body synchronously re-reads itself.
- Enhanced service definitions to include spies for monitoring load and command calls, ensuring correct behavior during execution.
- Updated the service runtime to manage in-flight loads more effectively, preventing unintended duplications.

All tests pass and type checks are clean.
- Updated the test for dependency load behavior to utilize a spy on the load method of the service definition, enhancing monitoring of load calls.
- Ensured proper restoration of the spy after the test execution to maintain test integrity.
- All tests pass and type checks are clean.
Open Service: Sync queries, load/loaded() API, strict reader handlers
CSF Next: Propagate skip tags to .test children
@pull pull Bot locked and limited conversation to collaborators May 29, 2026
@pull pull Bot added the ⤵️ pull label May 29, 2026
@pull pull Bot merged commit d6ce689 into code:next May 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants