Registers the TECH_LOG_STUDIO_SESSION SAME_ORIGIN_COOKIE auth profile and declares the tech-log-studio-http-v1 contribution covering all 18 JSON Studio operations (everything except the multipart uploadStudioAsset), built from two shared builders (safeOperation/keyedOperation) so every KEYED command gets IDEMPOTENCY_REPLAY recovery and a zero retry budget, and every SAFE read gets a plain retry budget, without repeating the declaration shape 18 times. Rescopes the canonical package identity from "tech-log-studio-contract" to "@tech-log/studio-contract" (generator, canonical-source.json, contract-generation.test.ts) because the platform's contribution composer requires an npm-scoped packageId; the unscoped form failed composition. Updates the release-manifest test fixture, which hardcoded an empty expected contract set, to derive its expected packages from the real installed set now that TechLog is always installed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { createHash } from "node:crypto";
|
|
import { test } from "vitest";
|
|
|
|
import canonicalSource from "../../../src/features/tech-log/contracts/studio/canonical-source.json" with { type: "json" };
|
|
|
|
const YAML_PATH = "src/features/tech-log/contracts/studio/studio-api.openapi.yaml";
|
|
|
|
test("vendored contract matches the recorded canonical digest", () => {
|
|
const bytes = readFileSync(YAML_PATH);
|
|
const digest = `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
assert.equal(digest, canonicalSource.digest);
|
|
});
|
|
|
|
test("canonical source records the pinned revision and version", () => {
|
|
assert.equal(canonicalSource.packageId, "@tech-log/studio-contract");
|
|
assert.equal(canonicalSource.version, "2.0.0");
|
|
// revision은 생성 시점에 기록된다. canonical 저장소는 활발히 편집 중이므로
|
|
// 특정 값을 박아두면 계약이 그대로인데도 테스트가 깨진다. 형식만 고정한다.
|
|
assert.match(canonicalSource.sourceRevision, /^[0-9a-f]{7,64}$/);
|
|
assert.match(canonicalSource.digest, /^sha256:[0-9a-f]{64}$/);
|
|
});
|
|
|
|
test("canonical source lists all 19 operationIds", () => {
|
|
assert.equal(canonicalSource.operationIds.length, 19);
|
|
assert.ok(canonicalSource.operationIds.includes("uploadStudioAsset"));
|
|
assert.ok(canonicalSource.operationIds.includes("getStudioSession"));
|
|
});
|
|
|
|
test("vendored contract declares the CSRF header", () => {
|
|
const yaml = readFileSync(YAML_PATH, "utf8");
|
|
assert.ok(yaml.includes("X-CSRF-TOKEN"));
|
|
});
|