feat: 기능 추가 과정중

This commit is contained in:
donghyeon-ka
2026-07-30 15:58:20 +09:00
parent d3ef801fe6
commit 6c52cdb916
648 changed files with 126325 additions and 6680 deletions
@@ -0,0 +1,86 @@
import type { AuthSessionPort } from "../../application/ports/auth-session-port.ts";
import type { QueryInvalidationCoordinator } from "../../contracts/query-invalidation.ts";
import {
createRuntimeIdentityRegistry,
type RuntimeIdentityRegistry,
} from "../../contracts/query-keys.ts";
import type {
CacheScopeSnapshot,
ServerStateScopeRuntime,
} from "../../contracts/server-state-scope.ts";
export function createServerStateScopeRuntime(dependencies: Readonly<{
session: Pick<AuthSessionPort, "subscribe">;
queryInvalidation: QueryInvalidationCoordinator;
tokenFactory?: () => string;
}>): ServerStateScopeRuntime {
const listeners = new Set<() => void>();
let generation = 1;
let identities = newIdentityRegistry(dependencies.tokenFactory);
let fingerprint = scopeFingerprint(dependencies.tokenFactory);
let disposed = false;
let resetChain = Promise.resolve();
function createSnapshot(): CacheScopeSnapshot {
const capturedGeneration = generation;
const capturedIdentities = identities;
return Object.freeze({
generation: capturedGeneration,
fingerprint,
identities: capturedIdentities,
isCurrent: () =>
!disposed &&
generation === capturedGeneration &&
identities === capturedIdentities,
});
}
let currentSnapshot = createSnapshot();
const unsubscribe = dependencies.session.subscribe(() => {
if (disposed) return;
const previousIdentities = identities;
const targetGeneration = ++generation;
resetChain = resetChain
.then(() => dependencies.queryInvalidation.resetLocal())
.catch(() => {})
.finally(() => {
previousIdentities.close();
if (disposed || generation !== targetGeneration) return;
identities = newIdentityRegistry(dependencies.tokenFactory);
fingerprint = scopeFingerprint(dependencies.tokenFactory);
currentSnapshot = createSnapshot();
for (const listener of listeners) listener();
});
});
return Object.freeze({
getSnapshot: () => currentSnapshot,
subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
},
dispose() {
if (disposed) return;
disposed = true;
unsubscribe();
listeners.clear();
identities.close();
},
});
}
function newIdentityRegistry(
tokenFactory: (() => string) | undefined,
): RuntimeIdentityRegistry {
return createRuntimeIdentityRegistry({
...(tokenFactory ? { tokenFactory } : {}),
});
}
function scopeFingerprint(tokenFactory: (() => string) | undefined): string {
const candidate = tokenFactory?.() ?? crypto.randomUUID();
if (!/^[A-Za-z0-9._:-]{16,128}$/.test(candidate)) {
throw new TypeError("Invalid cache scope fingerprint.");
}
return candidate;
}