fix: index many-to-many query invalidation

This commit is contained in:
DongHyeonka
2026-08-01 23:17:09 +09:00
parent 853c2e3f30
commit 73a50426d6
18 changed files with 574 additions and 325 deletions
+18 -12
View File
@@ -10,7 +10,6 @@ import { createContractHttpExecutor } from "../adapters/http/http-execution-v3.t
import { createBrowserCrossContextInvalidationFromHost } from "../adapters/cross-context-invalidation/index.ts";
import {
createTanStackCacheCoordinator,
type InstalledQueryInvalidationDefinition,
} from "../adapters/query-cache/tanstack-cache-coordinator.ts";
import { createQueryClient } from "../adapters/query-cache/tanstack-query-cache.ts";
import { createServerStateScopeRuntime } from "../adapters/query-cache/server-state-scope-runtime.ts";
@@ -22,7 +21,10 @@ import type { ReleaseInfo } from "../application/ports/release-info-port.ts";
import { createRestProviderProfile } from "../contracts/rest-profiles.ts";
import type { ClockPort } from "../application/ports/clock-port.ts";
import { createInstalledFeatureInputs } from "../features/installed-feature-adapters.ts";
import { QUERY_REGISTRY } from "../features/installed-feature-contracts.ts";
import {
INVALIDATION_REGISTRY,
INVALIDATION_TOPIC_VERSIONS,
} from "../features/installed-feature-contracts.ts";
import { INSTALLED_RUNTIME_CAPABILITIES } from "../features/installed-runtime-capabilities.ts";
import { describeRuntimeCapabilities } from "../contracts/runtime-capabilities.ts";
import {
@@ -32,6 +34,10 @@ import {
import type { RuntimeConfigLoadResult } from "./load-runtime-config.ts";
import { createServerStateGenerationStore } from "./server-state-generation-store.ts";
import { COMPOSED_CONTRACT_CONTRIBUTIONS } from "../features/installed-contract-contributions.ts";
import {
indexInvalidationRegistry,
indexInvalidationTopicVersions,
} from "../contracts/query-invalidation.ts";
type HttpClientDependencies = Parameters<typeof createHttpClient>[0];
export type RuntimeHttpContract = Pick<
@@ -184,12 +190,11 @@ export async function createRuntimeAdapters(
});
},
});
// The composition root states the registry shape it consumes rather than
// inferring it from whichever features happen to be installed, so a build
// with zero installed features still type-checks.
const queryRegistry: Readonly<
Record<string, InstalledQueryInvalidationDefinition>
> = QUERY_REGISTRY;
const invalidationIndex = indexInvalidationRegistry(INVALIDATION_REGISTRY);
const invalidationTopicVersions = indexInvalidationTopicVersions(
INVALIDATION_REGISTRY,
INVALIDATION_TOPIC_VERSIONS,
);
const conditionalValidators = createConditionalValidatorStore();
const serverStateGeneration = createServerStateGenerationStore(() => {
const queryClient = createQueryClient({ diagnostics });
@@ -197,10 +202,10 @@ export async function createRuntimeAdapters(
createBrowserCrossContextInvalidationFromHost({
...(context.host === undefined ? {} : { host: context.host }),
cacheEpoch: `release.${context.release.releaseId}`,
topics: Object.values(queryRegistry).map((definition) =>
topics: [...invalidationTopicVersions].map(([topic, topicVersion]) =>
Object.freeze({
topic: definition.invalidationTopic,
topicVersion: definition.version,
topic,
topicVersion,
}),
),
observe(observation) {
@@ -223,7 +228,8 @@ export async function createRuntimeAdapters(
});
const queryInvalidation = createTanStackCacheCoordinator({
queryClient,
queryRegistry,
invalidationIndex,
topicVersions: invalidationTopicVersions,
crossContext: crossContextInvalidation,
diagnostics,
});