refactor: 리펙토링

This commit is contained in:
DongHyeonka
2026-08-01 19:39:59 +09:00
parent 9c959ea2a5
commit c6da03369c
171 changed files with 20329 additions and 782 deletions
@@ -1,11 +1,3 @@
import type {
IndexedDbRepositoryPort,
IndexedDbWriteReceipt,
} from "../../application/ports/browser-file-storage/indexeddb-port.ts";
import type {
BrowserDataFailure,
BrowserDataResult,
} from "../../application/ports/browser-file-storage/shared.ts";
import {
WEB_PUSH_LIMITS,
WEB_PUSH_PROTOCOLS,
@@ -33,15 +25,66 @@ export type PushControlReceipt = Readonly<{
revision: number;
}>;
export type PushControlWriteReceipt = Readonly<{
key: string;
revision: number;
replayed: boolean;
}>;
/**
* The generic repository owns IndexedDB connection, migration, transaction,
* timeout, codec and version-change policy. This adapter adds only the
* Web Push authority transition rules on top of its revisioned CAS.
* The failure surface this adapter consumes. `code` is intentionally a plain
* string: the storage taxonomy is owned by whichever runtime backs the store,
* and an unrecognised code maps to the safe default in
* {@link mapRepositoryFailure} rather than failing to compile.
*/
export type PushControlRepository = Pick<
IndexedDbRepositoryPort<PushControlV1, never>,
"open" | "read" | "compareAndSwap" | "remove" | "close"
>;
export type PushControlStoreFailure = Readonly<{
code: string;
retryable: boolean;
}>;
export type PushControlStoreResult<Value> =
| Readonly<{ ok: true; value: Value }>
| Readonly<{ ok: false; error: PushControlStoreFailure }>;
/**
* The narrow durable store this capability requires: revisioned
* compare-and-swap over a single key.
*
* It is declared here, structurally, rather than imported from the browser
* file/storage port so the two capabilities stay independently removable. The
* generic IndexedDB repository satisfies it as-is; the composition root is
* where the two are joined, and it owns connection, migration, transaction,
* timeout, codec and version-change policy.
*/
export type PushControlRepository = Readonly<{
open(signal?: AbortSignal): Promise<PushControlStoreResult<void>>;
read(
key: string,
signal?: AbortSignal,
): Promise<
PushControlStoreResult<
Readonly<{ value: PushControlV1; revision: number }> | null
>
>;
compareAndSwap(
input: Readonly<{
key: string;
value: PushControlV1;
expectedRevision: number | null;
idempotencyKey: string;
signal?: AbortSignal;
}>,
): Promise<PushControlStoreResult<PushControlWriteReceipt>>;
remove(
input: Readonly<{
key: string;
expectedRevision: number | null;
idempotencyKey: string;
signal?: AbortSignal;
}>,
): Promise<PushControlStoreResult<PushControlWriteReceipt>>;
close(): void;
}>;
export interface PushAssociationFenceStore {
read(input?: Readonly<{
@@ -505,7 +548,7 @@ export function createPushAssociationFenceStore(
}
async function callRepository<Value>(
call: () => Promise<BrowserDataResult<Value>>,
call: () => Promise<PushControlStoreResult<Value>>,
operation: WebPushOperation,
): Promise<WebPushResult<Value>> {
try {
@@ -519,7 +562,7 @@ async function callRepository<Value>(
}
function mapRepositoryFailure(
failure: BrowserDataFailure,
failure: PushControlStoreFailure,
operation: WebPushOperation,
): WebPushResult<never> {
switch (failure.code) {
@@ -651,8 +694,8 @@ function validRepository(
}
function validWriteReceipt(
value: IndexedDbWriteReceipt,
): value is IndexedDbWriteReceipt {
value: PushControlWriteReceipt,
): value is PushControlWriteReceipt {
return (
Boolean(value) &&
value.key === CONTROL_KEY &&