refactor: 프론트 템플릿 리펙토링

This commit is contained in:
donghyeon-ka
2026-09-18 15:16:58 +09:00
parent c10a709f2c
commit 5cc41467ae
80 changed files with 7227 additions and 4672 deletions
+309
View File
@@ -0,0 +1,309 @@
import { vi } from "vitest";
import type {
ImageProbeScheduler,
} from "../../src/adapters/browser-transfer/image-cdn/browser-image-probe.ts";
import type {
ImageCapabilityVerificationScheduler,
} from "../../src/adapters/browser-transfer/image-cdn/image-cdn-runtime.ts";
export function responseAt(
url: string,
body: Uint8Array,
init: ResponseInit,
): Response {
const responseBytes = new Uint8Array(body.byteLength);
responseBytes.set(body);
const response = new Response(responseBytes.buffer, init);
Object.defineProperty(response, "url", {
configurable: false,
enumerable: true,
value: url,
});
return response;
}
export function publicImageHeaders(
mediaType: string,
contentLength?: number,
): Headers {
const headers = new Headers({
"cache-control":
"public, max-age=31536000, s-maxage=31536000, immutable",
"content-type": mediaType,
vary: "Accept-Encoding",
});
if (contentLength !== undefined) {
headers.set("content-length", String(contentLength));
}
return headers;
}
export function pngBytes(
width: number,
height: number,
animated = false,
): Uint8Array {
const header = new Uint8Array(13);
const headerView = new DataView(header.buffer);
headerView.setUint32(0, width);
headerView.setUint32(4, height);
header[8] = 8;
header[9] = 6;
return concatenateBytes([
Uint8Array.from([
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
]),
pngChunk("IHDR", header),
...(animated
? [pngChunk("acTL", new Uint8Array(8))]
: []),
pngChunk("IDAT", new Uint8Array()),
pngChunk("IEND", new Uint8Array()),
]);
}
function pngChunk(type: string, payload: Uint8Array): Uint8Array {
const chunk = new Uint8Array(12 + payload.byteLength);
const view = new DataView(chunk.buffer);
view.setUint32(0, payload.byteLength);
writeAscii(chunk, 4, type);
chunk.set(payload, 8);
return chunk;
}
export function jpegBytes(width: number, height: number): Uint8Array {
return Uint8Array.from([
0xff,
0xd8,
0xff,
0xc0,
0x00,
0x11,
0x08,
(height >>> 8) & 0xff,
height & 0xff,
(width >>> 8) & 0xff,
width & 0xff,
0x03,
0x01,
0x11,
0x00,
0x02,
0x11,
0x00,
0x03,
0x11,
0x00,
0xff,
0xda,
]);
}
export function webpBytes(
width: number,
height: number,
animated = false,
): Uint8Array {
const chunkType = animated ? "VP8X" : "VP8 ";
const payload = new Uint8Array(10);
if (animated) {
payload[0] = 0x02;
writeUint24LittleEndian(payload, 4, width - 1);
writeUint24LittleEndian(payload, 7, height - 1);
} else {
payload.set([0x9d, 0x01, 0x2a], 3);
const view = new DataView(payload.buffer);
view.setUint16(6, width, true);
view.setUint16(8, height, true);
}
const chunk = concatenateBytes([
asciiBytes(chunkType),
littleEndianUint32(payload.byteLength),
payload,
]);
return concatenateBytes([
asciiBytes("RIFF"),
littleEndianUint32(4 + chunk.byteLength),
asciiBytes("WEBP"),
chunk,
]);
}
export function avifBytes(
width: number,
height: number,
brand = "avif",
): Uint8Array {
const fileType = isoBox(
"ftyp",
concatenateBytes([
asciiBytes(brand),
new Uint8Array(4),
asciiBytes(brand),
]),
);
const spatialExtent = new Uint8Array(12);
const extentView = new DataView(spatialExtent.buffer);
extentView.setUint32(4, width);
extentView.setUint32(8, height);
const primaryItem = new Uint8Array(6);
new DataView(primaryItem.buffer).setUint16(4, 1);
const itemInfoEntry = new Uint8Array(13);
itemInfoEntry[0] = 2;
const itemInfoView = new DataView(itemInfoEntry.buffer);
itemInfoView.setUint16(4, 1);
writeAscii(itemInfoEntry, 8, "av01");
const itemInfo = new Uint8Array(6);
new DataView(itemInfo.buffer).setUint16(4, 1);
const propertyAssociation = new Uint8Array(12);
const associationView = new DataView(
propertyAssociation.buffer,
);
associationView.setUint32(4, 1);
associationView.setUint16(8, 1);
propertyAssociation[10] = 1;
propertyAssociation[11] = 0x81;
const properties = isoBox(
"iprp",
concatenateBytes([
isoBox("ipco", isoBox("ispe", spatialExtent)),
isoBox("ipma", propertyAssociation),
]),
);
const metadata = isoBox(
"meta",
concatenateBytes([
new Uint8Array(4),
isoBox("pitm", primaryItem),
isoBox(
"iinf",
concatenateBytes([
itemInfo,
isoBox("infe", itemInfoEntry),
]),
),
properties,
]),
);
return concatenateBytes([
fileType,
metadata,
isoBox("mdat", Uint8Array.of(0)),
]);
}
export function isoBox(type: string, payload: Uint8Array): Uint8Array {
const box = new Uint8Array(8 + payload.byteLength);
const view = new DataView(box.buffer);
view.setUint32(0, box.byteLength);
writeAscii(box, 4, type);
box.set(payload, 8);
return box;
}
export function littleEndianUint32(value: number): Uint8Array {
const bytes = new Uint8Array(4);
new DataView(bytes.buffer).setUint32(0, value, true);
return bytes;
}
export function writeUint24LittleEndian(
bytes: Uint8Array,
offset: number,
value: number,
): void {
bytes[offset] = value & 0xff;
bytes[offset + 1] = (value >>> 8) & 0xff;
bytes[offset + 2] = (value >>> 16) & 0xff;
}
export function asciiBytes(value: string): Uint8Array {
return Uint8Array.from(
[...value].map((character) => character.charCodeAt(0)),
);
}
export function writeAscii(
target: Uint8Array,
offset: number,
value: string,
): void {
target.set(asciiBytes(value), offset);
}
export function concatenateBytes(
chunks: readonly Uint8Array[],
): Uint8Array {
const combined = new Uint8Array(
chunks.reduce((total, chunk) => total + chunk.byteLength, 0),
);
let offset = 0;
for (const chunk of chunks) {
combined.set(chunk, offset);
offset += chunk.byteLength;
}
return combined;
}
export function manualImageProbeScheduler(): Readonly<{
scheduler: ImageProbeScheduler;
fire(): void;
}> {
let callback: (() => void) | undefined;
return {
scheduler: {
setTimeout(nextCallback) {
callback = nextCallback;
return 1;
},
clearTimeout: vi.fn(),
},
fire() {
if (!callback) {
throw new TypeError("No image probe timeout is scheduled.");
}
callback();
},
};
}
export function manualCapabilityVerificationScheduler(): Readonly<{
scheduler: ImageCapabilityVerificationScheduler;
delays: readonly number[];
clearTimeout: ReturnType<typeof vi.fn>;
fire(): void;
}> {
let callback: (() => void) | undefined;
const delays: number[] = [];
const clearTimeout = vi.fn();
return {
scheduler: {
setTimeout(nextCallback, milliseconds) {
callback = nextCallback;
delays.push(milliseconds);
return 1;
},
clearTimeout,
},
delays,
clearTimeout,
fire() {
if (!callback) {
throw new TypeError(
"No capability verification timeout is scheduled.",
);
}
callback();
},
};
}
export function base64Url(bytes: Uint8Array): string {
let binary = "";
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary)
.replace(/\+/gu, "-")
.replace(/\//gu, "_")
.replace(/=+$/gu, "");
}