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
+140 -18
View File
@@ -4,6 +4,9 @@ import {
loadReleaseManifest,
ReleaseManifestError,
} from "../../src/bootstrap/load-release-manifest.ts";
import { computeContractSetDigest } from "../../src/contracts/contract-set-canonical.ts";
const EMPTY_SET_DIGEST = await computeContractSetDigest([]);
const runtime: Parameters<typeof loadReleaseManifest>[0] = {
build: {
@@ -22,12 +25,45 @@ const runtime: Parameters<typeof loadReleaseManifest>[0] = {
RELEASE_MANIFEST_URL: "/release-manifest.json",
BUILD_ID: "build-a",
RELEASE_ID: "release-a",
CONFIG_SCHEMA_VERSION: "1",
API_CONTRACT_VERSION: "1",
CONFIG_SCHEMA_VERSION: "2.0",
CAPABILITY_OVERRIDES: {
REALTIME: "DEFAULT",
WEB_WORKER: "DEFAULT",
SERVICE_WORKER: "DEFAULT",
OFFLINE_COMMANDS: "DEFAULT",
},
},
configSchema: "V2",
validationDurationMs: 0,
};
const manifest = {
schemaVersion: 2,
appVersion: "0.1.0",
buildId: "build-a",
commitSha: "abc123",
configSchemaVersion: "2.0",
assetManifestHash: "hash-a",
releaseId: "release-a",
builtAt: "2026-07-25T00:00:00Z",
routeChunks: { "route-home": "assets/home.js" },
contractSet: {
setAlgorithm: "CA_CONTRACT_SET_V1",
setDigest: EMPTY_SET_DIGEST,
packages: [],
},
};
const runtimeV1: Parameters<typeof loadReleaseManifest>[0] = {
...runtime,
config: {
...runtime.config,
CONFIG_SCHEMA_VERSION: "1",
LEGACY_API_CONTRACT_VERSION: "1",
},
configSchema: "V1",
};
const manifestV1 = {
schemaVersion: 1,
appVersion: "0.1.0",
buildId: "build-a",
@@ -40,12 +76,18 @@ const manifest = {
routeChunks: { "route-home": "assets/home.js" },
};
function jsonResponse(body: unknown): Response {
return new Response(JSON.stringify(body), {
headers: { "content-type": "application/json" },
});
}
describe("release manifest boot boundary", () => {
it("loads a coherent release tuple", async () => {
await expect(
loadReleaseManifest(
runtime,
{ fetcher: async () => new Response(JSON.stringify(manifest)) },
{ fetcher: async () => jsonResponse(manifest) },
),
).resolves.toMatchObject({ releaseId: "release-a" });
});
@@ -56,7 +98,7 @@ describe("release manifest boot boundary", () => {
runtime,
{
fetcher: async () =>
new Response(JSON.stringify({ ...manifest, buildId: "build-b" })),
jsonResponse({ ...manifest, buildId: "build-b" }),
},
),
).rejects.toMatchObject({
@@ -66,18 +108,6 @@ describe("release manifest boot boundary", () => {
});
it.each([
[
{ configSchemaVersion: "2" },
{},
"CONFIG_MISMATCH",
"MANIFEST_CONFIG_SCHEMA_MISMATCH",
],
[
{ apiContractVersion: "2" },
{},
"API_CONTRACT_MISMATCH",
"MANIFEST_API_CONTRACT_MISMATCH",
],
[
{ releaseId: "release-b" },
{},
@@ -98,7 +128,7 @@ describe("release manifest boot boundary", () => {
runtime,
{
fetcher: async () =>
Response.json({ ...manifest, ...manifestOverride }),
jsonResponse({ ...manifest, ...manifestOverride }),
...options,
},
),
@@ -106,6 +136,98 @@ describe("release manifest boot boundary", () => {
},
);
it.each(["3.0", "9.0"])(
"rejects unsupported V2 manifest config version %s at the schema boundary",
async (configSchemaVersion) => {
await expect(
loadReleaseManifest(runtime, {
fetcher: async () =>
jsonResponse({ ...manifest, configSchemaVersion }),
}),
).rejects.toMatchObject({
kind: "RELEASE_MANIFEST_FAILURE",
code: "MANIFEST_SCHEMA_INVALID",
});
},
);
it("rejects a contract set the build did not compile", async () => {
await expect(
loadReleaseManifest(runtime, {
fetcher: async () =>
jsonResponse({
...manifest,
contractSet: {
setAlgorithm: "CA_CONTRACT_SET_V1",
setDigest: EMPTY_SET_DIGEST,
packages: [
{
packageId: "@org-contracts/worklog",
version: "1.2.3",
digest: `sha256:${"a".repeat(64)}`,
runtimeProtocolVersion: 1,
sourceRevision: "abc1234",
},
],
},
}),
}),
).rejects.toMatchObject({
kind: "CONTRACT_SET_MISMATCH",
code: "CONTRACT_SET_PACKAGE_UNEXPECTED",
});
});
it("still reads a V1 manifest during the compatibility window", async () => {
await expect(
loadReleaseManifest(
runtimeV1,
{
fetcher: async () => jsonResponse(manifestV1),
},
),
).resolves.toMatchObject({ schemaVersion: 1, contractSet: null });
});
it("rejects a V2 runtime paired with a V1 manifest", async () => {
await expect(
loadReleaseManifest(runtime, {
fetcher: async () => jsonResponse({
...manifestV1,
configSchemaVersion: "2.0",
}),
}),
).rejects.toMatchObject({
kind: "PROTOCOL_PAIR_MISMATCH",
code: "MANIFEST_PROTOCOL_PAIR_MISMATCH",
});
});
it("rejects a V1 runtime paired with a V2 manifest", async () => {
await expect(
loadReleaseManifest(runtimeV1, {
fetcher: async () => jsonResponse(manifest),
}),
).rejects.toMatchObject({
kind: "PROTOCOL_PAIR_MISMATCH",
code: "MANIFEST_PROTOCOL_PAIR_MISMATCH",
});
});
it("requires matching legacy scalar versions for a V1 pair", async () => {
await expect(
loadReleaseManifest(runtimeV1, {
fetcher: async () => jsonResponse({
...manifestV1,
apiContractVersion: "2",
}),
}),
).rejects.toMatchObject({
kind: "API_CONTRACT_MISMATCH",
code: "MANIFEST_API_CONTRACT_MISMATCH",
});
});
it("rejects a manifest without a complete route chunk map", async () => {
const malformed = Object.fromEntries(
Object.entries(manifest).filter(([key]) => key !== "routeChunks"),
@@ -113,7 +235,7 @@ describe("release manifest boot boundary", () => {
await expect(
loadReleaseManifest(
runtime,
{ fetcher: async () => Response.json(malformed) },
{ fetcher: async () => jsonResponse(malformed) },
),
).rejects.toBeInstanceOf(ReleaseManifestError);
});
+108 -7
View File
@@ -6,17 +6,22 @@ import { assertSafeConfigNames } from "../../src/contracts/env.ts";
const validConfig = {
APP_ENV: "local",
API_BASE_URL: "http://localhost:8080",
API_BASE_URL: "http://localhost:8080/",
REQUEST_TIMEOUT_MS: 10_000,
MAX_RETRY_ATTEMPTS: 2,
TELEMETRY_ENABLED: false,
AUTH_MODE: "external",
CONFIG_SCHEMA_VERSION: "1",
API_CONTRACT_VERSION: "1",
CONFIG_SCHEMA_VERSION: "2.0",
RELEASE_MANIFEST_URL: "/release-manifest.json",
BUILD_ID: "build-a",
};
const validV1Config = {
...validConfig,
CONFIG_SCHEMA_VERSION: "1",
API_CONTRACT_VERSION: "1.4.0",
};
describe("runtime configuration boundary", () => {
it.each([
[{ ...validConfig, API_BASE_URL: undefined }, "required key"],
@@ -24,6 +29,30 @@ describe("runtime configuration boundary", () => {
[{ ...validConfig, MAX_RETRY_ATTEMPTS: 3 }, "retry cap"],
[{ ...validConfig, TELEMETRY_ENABLED: "false" }, "ambiguous boolean"],
[{ ...validConfig, CONFIG_SCHEMA_VERSION: "next" }, "version"],
[
{ ...validConfig, API_CONTRACT_VERSION: "1" },
"§5.1 scalar contract version is removed from V2",
],
[
{ ...validConfig, API_BASE_URL: "http://localhost:8080/api" },
"§6.2 base URL path must end with /",
],
[
{ ...validConfig, API_BASE_URL: "http://localhost:8080/#frag" },
"§6.2 hash in base URL",
],
[
{ ...validConfig, API_BASE_URL: "http://user:pw@localhost:8080/" },
"§6.2 credentials in URL",
],
[
{ ...validConfig, RELEASE_MANIFEST_URL: "/a/../b.json" },
"§6.2 dot segment traversal",
],
[
{ ...validConfig, RELEASE_MANIFEST_URL: "/manifest.json?v=1" },
"§6.2 query in manifest URL",
],
[{ ...validConfig, UNKNOWN_KEY: true }, "unknown key"],
])("rejects invalid config: %s (%s)", (candidate, _reason) => {
void _reason;
@@ -44,12 +73,55 @@ describe("runtime configuration boundary", () => {
validateRuntimeConfig({
...validConfig,
APP_ENV: "production",
API_BASE_URL: "https://api.example.test",
API_BASE_URL: "https://api.example.test/",
AUTH_MODE: "demo",
}).success,
).toBe(false);
});
it("accepts only the explicitly supported V1 and V2 boot versions", () => {
expect(validateRuntimeConfig(validV1Config)).toMatchObject({
success: true,
schema: "V1",
});
expect(validateRuntimeConfig(validConfig)).toMatchObject({
success: true,
schema: "V2",
});
for (const version of ["0", "1.0", "2.0.1", "3.0"]) {
expect(
validateRuntimeConfig({
...validV1Config,
CONFIG_SCHEMA_VERSION: version,
}).success,
).toBe(false);
}
});
it.each([
"file:///tmp/api/",
"data:text/plain,/",
"blob:https://example.test/00000000-0000-0000-0000-000000000000",
])("rejects a non-HTTP API endpoint in local mode: %s", (API_BASE_URL) => {
expect(validateRuntimeConfig({ ...validConfig, API_BASE_URL }).success).toBe(
false,
);
});
it.each(["file:///tmp/telemetry", "data:text/plain,telemetry"])(
"rejects a non-HTTP telemetry endpoint in local mode: %s",
(TELEMETRY_ENDPOINT) => {
expect(
validateRuntimeConfig({
...validConfig,
TELEMETRY_ENABLED: true,
TELEMETRY_ENDPOINT,
}).success,
).toBe(false);
},
);
it("validates a fetched config under the 500ms budget excluding network", async () => {
let current = 100;
const result = await loadRuntimeConfig({
@@ -59,12 +131,38 @@ describe("runtime configuration boundary", () => {
routerBasePath: "/",
runtimeConfigUrl: "/config.json",
},
fetcher: async () => new Response(JSON.stringify(validConfig)),
fetcher: async () =>
new Response(JSON.stringify(validConfig), {
headers: { "content-type": "application/json" },
}),
now: () => (current += 2),
});
expect(result.validationDurationMs).toBeLessThanOrEqual(500);
expect(result.config.API_BASE_URL).toBe("http://localhost:8080");
expect(result.config.API_BASE_URL).toBe("http://localhost:8080/");
expect(result.configSchema).toBe("V2");
expect(result.config.CAPABILITY_OVERRIDES.SERVICE_WORKER).toBe("DEFAULT");
});
it("does not include network acquisition in validationDurationMs", async () => {
let current = 0;
const result = await loadRuntimeConfig({
buildConfig: {
buildId: "build-a",
commitSha: "local",
routerBasePath: "/",
runtimeConfigUrl: "/config.json",
},
fetcher: async () => {
current = 10_000;
return new Response(JSON.stringify(validConfig), {
headers: { "content-type": "application/json" },
});
},
now: () => current,
});
expect(result.validationDurationMs).toBe(0);
});
it("returns only safe boot fields on failure", async () => {
@@ -76,7 +174,10 @@ describe("runtime configuration boundary", () => {
routerBasePath: "/",
runtimeConfigUrl: "/config.json",
},
fetcher: async () => new Response("{"),
fetcher: async () =>
new Response("{", {
headers: { "content-type": "application/json" },
}),
}),
).rejects.toMatchObject({
safe: {