feat: select the TechLog Studio adapter from runtime configuration
Adds TECH_LOG_STUDIO_SOURCE (MOCK | HTTP, default MOCK) to the V2 runtime
config schema so a build can switch createTechLogFeatureInstalledInput
between the mock and HTTP Studio gateways without a rebuild. V1 documents
predate the key and always normalize to MOCK. The HTTP gateway is
constructed with only { operations } per Task 4's actual signature -
no CSRF provider is wired here; that lands with attachCredentials at a
later composition-root task.
Updates every existing Studio test call site to the new required
createTechLogFeatureInstalledInput(context) signature via a shared
tests/helpers/studio-install-context.ts MOCK fixture, so the whole
existing Studio suite keeps exercising the mock adapter unchanged.
This commit is contained in:
@@ -505,6 +505,7 @@ export async function createRuntimeAdapters(
|
||||
});
|
||||
const featureInputs = createInstalledFeatureInputs({
|
||||
contractOperations,
|
||||
studioSource: config.TECH_LOG_STUDIO_SOURCE,
|
||||
});
|
||||
|
||||
return Object.freeze({
|
||||
|
||||
@@ -50,6 +50,12 @@ export type RuntimeConfig = Readonly<{
|
||||
* feature the build did not install cannot be named into existence here.
|
||||
*/
|
||||
FEATURE_OVERRIDES: ProductFeatureOverrideMap;
|
||||
/**
|
||||
* §3.5-adjacent runtime switch: which Studio gateway adapter this build
|
||||
* talks to. A V1 document predates the key and is always normalized to
|
||||
* MOCK.
|
||||
*/
|
||||
TECH_LOG_STUDIO_SOURCE: "MOCK" | "HTTP";
|
||||
/** Present only while a V1 document is still accepted. */
|
||||
LEGACY_API_CONTRACT_VERSION?: string;
|
||||
}>;
|
||||
@@ -132,6 +138,11 @@ export function validateRuntimeConfig(value: unknown): RuntimeConfigValidation {
|
||||
FEATURE_OVERRIDES: Object.freeze({
|
||||
...(isV2 ? (parsed as RuntimeConfigV2).FEATURE_OVERRIDES : {}),
|
||||
}),
|
||||
// A V1 document predates the Studio adapter switch; it always normalizes
|
||||
// to the mock so the backend-absent default holds for legacy documents.
|
||||
TECH_LOG_STUDIO_SOURCE: isV2
|
||||
? (parsed as RuntimeConfigV2).TECH_LOG_STUDIO_SOURCE
|
||||
: "MOCK",
|
||||
...(isV2
|
||||
? {}
|
||||
: {
|
||||
|
||||
@@ -49,6 +49,9 @@ export const ENV_REGISTRY = Object.freeze({
|
||||
CAPABILITY_OVERRIDES: runtime("public", false, null),
|
||||
// §3.5: likewise for features — subtractive, keyed by installed feature id.
|
||||
FEATURE_OVERRIDES: runtime("public", false, null),
|
||||
// TechLog Studio gateway adapter selection. Defaults to MOCK while the
|
||||
// backend does not exist yet.
|
||||
TECH_LOG_STUDIO_SOURCE: runtime("public", false, "MOCK"),
|
||||
// §3.5: build-time narrowing of the product manifest. A feature left out
|
||||
// here is not imported by any registry and never reaches the bundle.
|
||||
VITE_PRODUCT_FEATURES: build("compile-time", false, null),
|
||||
|
||||
@@ -156,6 +156,9 @@ export const runtimeConfigV2ArtifactSchema = z
|
||||
CONFIG_SCHEMA_VERSION: z.literal("2.0"),
|
||||
CAPABILITY_OVERRIDES: capabilityOverrideArtifactSchema,
|
||||
FEATURE_OVERRIDES: featureOverrideArtifactSchema,
|
||||
// TechLog Studio adapter selection. Backend is not live yet, so the
|
||||
// default is the in-memory mock; a document may opt a build into HTTP.
|
||||
TECH_LOG_STUDIO_SOURCE: z.enum(["MOCK", "HTTP"]).default("MOCK"),
|
||||
})
|
||||
.strict()
|
||||
.superRefine(runtimeConfigArtifactInvariants);
|
||||
|
||||
@@ -19,9 +19,10 @@ type InstalledFeatureInputs = Readonly<
|
||||
>;
|
||||
|
||||
export function createInstalledFeatureInputs(
|
||||
context: Parameters<typeof createReferenceFeatureInstalledInput>[0],
|
||||
context: Parameters<typeof createReferenceFeatureInstalledInput>[0] &
|
||||
Readonly<{ studioSource: "MOCK" | "HTTP" }>,
|
||||
): InstalledFeatureInputs {
|
||||
const techLogFeature = createTechLogFeatureInstalledInput();
|
||||
const techLogFeature = createTechLogFeatureInstalledInput(context);
|
||||
if (!INSTALLED_PRODUCT_FEATURE_IDS.includes(REFERENCE_FEATURE_ID)) {
|
||||
// A build that narrowed the reference feature out still ships TechLog.
|
||||
return Object.freeze({
|
||||
|
||||
@@ -2,13 +2,36 @@ import {
|
||||
TECH_LOG_FEATURE_ID,
|
||||
type TechLogFeatureInput,
|
||||
} from "../application/tech-log-feature-input.ts";
|
||||
import {
|
||||
createHttpStudioGateway,
|
||||
type StudioOperationExecutor,
|
||||
} from "./http/http-studio-gateway.ts";
|
||||
import { createMockStudioGateway } from "./mock/mock-studio-gateway.ts";
|
||||
import { publicContentQueries } from "./static/public-query.ts";
|
||||
|
||||
export function createTechLogFeatureInstalledInput() {
|
||||
/**
|
||||
* The HTTP gateway builds no headers of its own — `Idempotency-Key` comes
|
||||
* from the execution intent and credentials (including CSRF) come from the
|
||||
* platform's `attachCredentials` collaborator at the composition root. This
|
||||
* context only has to say which adapter to construct and hand it the
|
||||
* composed contract executor.
|
||||
*/
|
||||
export type TechLogInstallContext = Readonly<{
|
||||
studioSource: "MOCK" | "HTTP";
|
||||
contractOperations: StudioOperationExecutor;
|
||||
}>;
|
||||
|
||||
export function createTechLogFeatureInstalledInput(
|
||||
context: TechLogInstallContext,
|
||||
) {
|
||||
const createStudioGateway = () =>
|
||||
context.studioSource === "MOCK"
|
||||
? createMockStudioGateway()
|
||||
: createHttpStudioGateway({ operations: context.contractOperations });
|
||||
|
||||
const input: TechLogFeatureInput = Object.freeze({
|
||||
publicContent: publicContentQueries,
|
||||
createStudioGateway: () => createMockStudioGateway(),
|
||||
createStudioGateway,
|
||||
});
|
||||
|
||||
return Object.freeze({
|
||||
|
||||
Reference in New Issue
Block a user