refactor: 프론트 템플릿 리펙토링
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import type { MutationIntentFactory } from "../../src/application/ports/mutation-intent-factory.ts";
|
||||
import { QueryInvalidationProvider } from "../../src/presentation/adapters/query/query-invalidation-provider.tsx";
|
||||
import { MutationIntentProvider } from "../../src/presentation/adapters/query/mutation-intent-provider.tsx";
|
||||
import {
|
||||
defineQueryInvalidationTopic,
|
||||
type QueryInvalidationCoordinator,
|
||||
} from "../../src/contracts/query-invalidation.ts";
|
||||
import { createRuntimeIdentityRegistry } from "../../src/contracts/query-keys.ts";
|
||||
import type { QueryResultMeasure } from "../../src/contracts/server-state.ts";
|
||||
import type { CacheScopeSnapshot } from "../../src/contracts/server-state-scope.ts";
|
||||
|
||||
export const RESOURCE_INVALIDATION_TOPIC =
|
||||
defineQueryInvalidationTopic("resource");
|
||||
|
||||
export function scopeSnapshot(
|
||||
generation = 1,
|
||||
fingerprint = "scope-fingerprint-0001",
|
||||
): CacheScopeSnapshot & { fence(): void } {
|
||||
let current = true;
|
||||
const lifetime = new AbortController();
|
||||
const identities = createRuntimeIdentityRegistry({
|
||||
tokenFactory: () => "scope-identity-token-0001",
|
||||
});
|
||||
return {
|
||||
generation,
|
||||
fingerprint,
|
||||
identities,
|
||||
signal: lifetime.signal,
|
||||
isCurrent: () => current,
|
||||
fence() {
|
||||
current = false;
|
||||
lifetime.abort();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function measureOne(): QueryResultMeasure {
|
||||
return { itemCount: 1, estimatedBytes: 8 };
|
||||
}
|
||||
|
||||
export function queryClient() {
|
||||
return new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { retry: false, staleTime: 0, gcTime: Infinity },
|
||||
mutations: { retry: false },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function deterministicMutationIntentFactory(): MutationIntentFactory {
|
||||
let sequence = 0;
|
||||
return Object.freeze({
|
||||
create(input) {
|
||||
sequence += 1;
|
||||
return Object.freeze({
|
||||
intentId: `intent-${sequence}`,
|
||||
operationId: input.operationId,
|
||||
canonicalInputIdentity: input.canonicalInputIdentity,
|
||||
...(input.requiresIdempotencyKey
|
||||
? { idempotencyKey: `key-${sequence}` }
|
||||
: {}),
|
||||
createdAtMonotonicMs: sequence,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function wrapper(
|
||||
client: QueryClient,
|
||||
mutationIntentFactory = deterministicMutationIntentFactory(),
|
||||
) {
|
||||
const coordinator: QueryInvalidationCoordinator = {
|
||||
async invalidate(topics) {
|
||||
for (const topic of topics) {
|
||||
await client.invalidateQueries({
|
||||
queryKey: [topic],
|
||||
exact: false,
|
||||
refetchType: "active",
|
||||
});
|
||||
}
|
||||
},
|
||||
beginMutation() {
|
||||
return { release: async () => {} };
|
||||
},
|
||||
async resetLocal() {
|
||||
await client.cancelQueries();
|
||||
client.clear();
|
||||
},
|
||||
dispose() {},
|
||||
};
|
||||
return function QueryWrapper({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<MutationIntentProvider factory={mutationIntentFactory}>
|
||||
<QueryClientProvider client={client}>
|
||||
<QueryInvalidationProvider coordinator={coordinator}>
|
||||
{children}
|
||||
</QueryInvalidationProvider>
|
||||
</QueryClientProvider>
|
||||
</MutationIntentProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user