///
import type { ToolcraftSourceAssetCoordinator } from "../../source-assets/source-asset-coordinator";
import type { ToolcraftExternalStore } from "../../state/toolcraft-external-store";
import type { ToolcraftImageAsset } from "../../state/types";
const TOOLCRAFT_UNAVAILABLE_RESOURCE_PROOF_REQUEST =
"toolcraft.browser-proof.unavailable-resource-request";
const TOOLCRAFT_UNAVAILABLE_RESOURCE_PROOF_ATTRIBUTE =
"data-toolcraft-unavailable-resource-evidence";
const toolcraftUnavailableResourceProofEnabled =
import.meta.env?.MODE === "test" ||
import.meta.env?.VITE_TOOLCRAFT_BROWSER_PROOF_FIXTURES ===
"unavailable-resource";
type ToolcraftUnavailableResourceProofRequest = Readonly<{
action: "activate" | "cleanup";
fileName: string;
requestId: string;
sourceTarget?: string;
}>;
type ActiveUnavailableResourceProof = Readonly<{
assetId: string;
requestId: string;
resourceRef: string;
}>;
type PendingUnavailableResourceProofRequest = Readonly<{
abortController: AbortController;
promise: Promise;
requestId: string;
}>;
const cancelledProofRequest = new Error(
"Unavailable-resource proof request was cancelled.",
);
function readUnavailableResourceProofRequest(
event: Event,
): ToolcraftUnavailableResourceProofRequest | null {
if (!(event instanceof CustomEvent)) return null;
const detail: unknown = event.detail;
if (typeof detail !== "object" || detail === null || Array.isArray(detail)) {
return null;
}
const request = detail as Partial;
if (
(request.action !== "activate" && request.action !== "cleanup") ||
typeof request.fileName !== "string" ||
request.fileName.trim() !== request.fileName ||
request.fileName.length === 0 ||
typeof request.requestId !== "string" ||
request.requestId.trim() !== request.requestId ||
request.requestId.length === 0 ||
(
request.sourceTarget !== undefined &&
(
typeof request.sourceTarget !== "string" ||
request.sourceTarget.trim() !== request.sourceTarget ||
request.sourceTarget.length === 0
)
)
) {
return null;
}
return request as ToolcraftUnavailableResourceProofRequest;
}
export function decorateToolcraftUnavailableResourceProofCoordinator(
coordinator: ToolcraftSourceAssetCoordinator,
store: ToolcraftExternalStore,
): ToolcraftSourceAssetCoordinator {
if (!toolcraftUnavailableResourceProofEnabled) return coordinator;
const resolveResource = coordinator.resolveResource;
if (!resolveResource) return coordinator;
const disposeCoordinator = coordinator.dispose;
const unavailableResourceRefs = new Set();
let active: ActiveUnavailableResourceProof | null = null;
let disposed = false;
let disposePromise: Promise | null = null;
let pendingRequest: PendingUnavailableResourceProofRequest | null = null;
const proofResolveResource = async (
ref: string,
options: Readonly<{ signal: AbortSignal }>,
): Promise =>
unavailableResourceRefs.has(ref)
? null
: resolveResource(ref, options);
const publish = (
requestId: string,
observation: Readonly>,
): void => {
const root = document.querySelector(
'[data-slot="toolcraft-runtime-app"]',
);
if (!root) return;
root.setAttribute(
TOOLCRAFT_UNAVAILABLE_RESOURCE_PROOF_ATTRIBUTE,
JSON.stringify({ requestId, ...observation }),
);
};
const handleRequest = (event: Event): void => {
const request = readUnavailableResourceProofRequest(event);
if (!request || disposed) return;
if (pendingRequest) {
publish(request.requestId, {
message: `Unavailable-resource proof request "${pendingRequest.requestId}" is still pending.`,
status: "error",
});
return;
}
const abortController = new AbortController();
const assertRequestActive = (): void => {
if (disposed || abortController.signal.aborted) {
throw cancelledProofRequest;
}
};
const promise = Promise.resolve().then(async () => {
assertRequestActive();
if (request.action === "cleanup") {
if (!active || active.requestId !== request.requestId) {
throw new Error(
"Unavailable-resource proof cleanup must match the active fixture request.",
);
}
const current = active;
unavailableResourceRefs.delete(current.resourceRef);
const restoredBytes = await proofResolveResource(
current.resourceRef,
{ signal: abortController.signal },
);
assertRequestActive();
if (!restoredBytes?.byteLength) {
throw new Error(
"Unavailable-resource proof cleanup could not restore the real resolver.",
);
}
store.dispatch({
assetId: current.assetId,
expectedResourceRef: current.resourceRef,
lifecycle: "ready",
type: "media.setBinaryResourceState",
});
assertRequestActive();
const restored = store
.getCommittedState()
.mediaAssets.find((asset) => asset.id === current.assetId);
if (
!restored ||
restored.assetKind !== "image" ||
restored.lifecycle !== "ready"
) {
throw new Error(
"Unavailable-resource proof cleanup did not restore the typed resource state.",
);
}
active = null;
assertRequestActive();
publish(request.requestId, {
assetId: current.assetId,
fileName: request.fileName,
lifecycle: "ready",
resolverAvailable: true,
status: "cleaned",
});
return;
}
if (active) {
throw new Error(
"Unavailable-resource proof supports exactly one active resource fixture.",
);
}
const candidates = store
.getCommittedState()
.mediaAssets.filter(
(
asset,
): asset is ToolcraftImageAsset & { lifecycle: "ready" } =>
asset.assetKind === "image" &&
asset.lifecycle === "ready" &&
asset.fileName === request.fileName &&
(
request.sourceTarget === undefined ||
asset.sourceTarget === request.sourceTarget
),
);
if (candidates.length !== 1) {
throw new Error(
`Unavailable-resource proof requires exactly one ready image named "${request.fileName}", received ${candidates.length}.`,
);
}
const asset = candidates[0];
if (!asset) {
throw new Error("Unavailable-resource proof image selection failed.");
}
const initialBytes = await proofResolveResource(
asset.resourceRef,
{ signal: abortController.signal },
);
assertRequestActive();
if (!initialBytes?.byteLength) {
throw new Error(
"Unavailable-resource proof requires a resource available through the real resolver before fault activation.",
);
}
unavailableResourceRefs.add(asset.resourceRef);
const activatedProof: ActiveUnavailableResourceProof = {
assetId: asset.id,
requestId: request.requestId,
resourceRef: asset.resourceRef,
};
try {
const faultedBytes = await proofResolveResource(
asset.resourceRef,
{ signal: abortController.signal },
);
assertRequestActive();
if (faultedBytes !== null) {
throw new Error(
"Unavailable-resource proof did not isolate the requested resolver resource.",
);
}
active = activatedProof;
store.dispatch({
assetId: asset.id,
error: {
code: "browser-proof-resource-unavailable",
message:
"The resource is intentionally unavailable for protected browser proof.",
},
expectedResourceRef: asset.resourceRef,
lifecycle: "unavailable",
type: "media.setBinaryResourceState",
});
assertRequestActive();
const unavailable = store
.getCommittedState()
.mediaAssets.find((candidate) => candidate.id === asset.id);
if (
!unavailable ||
unavailable.assetKind !== "image" ||
unavailable.lifecycle !== "unavailable"
) {
throw new Error(
"Unavailable-resource proof did not reach the typed unavailable state.",
);
}
assertRequestActive();
publish(request.requestId, {
assetId: asset.id,
fileName: asset.fileName,
lifecycle: "unavailable",
resolverAvailable: false,
status: "active",
});
} catch (error) {
unavailableResourceRefs.delete(asset.resourceRef);
if (!disposed && active === activatedProof) active = null;
throw error;
}
});
const trackedRequest: PendingUnavailableResourceProofRequest = {
abortController,
promise,
requestId: request.requestId,
};
pendingRequest = trackedRequest;
void promise
.catch((error: unknown) => {
if (
error === cancelledProofRequest ||
disposed ||
abortController.signal.aborted
) {
return;
}
publish(request.requestId, {
message:
error instanceof Error
? error.message
: "Unavailable-resource proof fixture failed.",
status: "error",
});
})
.finally(() => {
if (pendingRequest === trackedRequest) pendingRequest = null;
});
};
const dispose = (): Promise => {
if (!disposePromise) {
disposed = true;
document.removeEventListener(
TOOLCRAFT_UNAVAILABLE_RESOURCE_PROOF_REQUEST,
handleRequest,
);
const requestAtDisposal = pendingRequest;
disposePromise = Promise.resolve().then(async () => {
const failures: unknown[] = [];
requestAtDisposal?.abortController.abort();
if (requestAtDisposal) {
try {
await requestAtDisposal.promise;
} catch {
// Request failures are fixture observations, not disposal failures.
}
if (pendingRequest === requestAtDisposal) pendingRequest = null;
}
const activeAtDisposal = active;
if (activeAtDisposal) {
unavailableResourceRefs.delete(activeAtDisposal.resourceRef);
try {
store.dispatch({
assetId: activeAtDisposal.assetId,
expectedResourceRef: activeAtDisposal.resourceRef,
lifecycle: "ready",
type: "media.setBinaryResourceState",
});
const restored = store
.getCommittedState()
.mediaAssets.find(
(asset) => asset.id === activeAtDisposal.assetId,
);
if (
!restored ||
restored.assetKind !== "image" ||
restored.lifecycle !== "ready"
) {
throw new Error(
"Unavailable-resource proof disposal did not restore the typed resource state.",
);
}
} catch (error) {
failures.push(error);
} finally {
active = null;
}
}
unavailableResourceRefs.clear();
try {
await disposeCoordinator.call(coordinator);
} catch (error) {
failures.push(error);
}
if (failures.length > 0) {
throw new AggregateError(
failures,
"Toolcraft unavailable-resource proof failed to dispose.",
);
}
});
}
return disposePromise;
};
coordinator.dispose = dispose;
coordinator.resolveResource = proofResolveResource;
document.addEventListener(
TOOLCRAFT_UNAVAILABLE_RESOURCE_PROOF_REQUEST,
handleRequest,
);
return coordinator;
}