import type {
AssetEnvelopeV2,
AssetPublicationTuple,
AssetRuntimeArtifactDescriptor,
PackV2,
PackV2Error,
Result,
} from '@forgeax/engine-types';
import { err, ok } from '@forgeax/engine-types';
export interface RuntimeAssetProjectionInput
{
readonly guid: string;
readonly kind: string;
readonly payload: P;
readonly refs: readonly string[];
readonly artifacts: Readonly>;
}
export interface RuntimePackProjectionInput extends AssetPublicationTuple {
readonly assets: readonly RuntimeAssetProjectionInput
[];
}
function invalid(observed: string, expected: string): Result {
return err({
code: 'pack-v2-envelope-invalid',
expected,
hint: 'publish one verified Pack v2 envelope with one atomic publication tuple',
detail: { observed, expected },
});
}
function isRecord(value: unknown): value is Record {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
export function isRuntimePublicationTuple(value: unknown): value is AssetPublicationTuple {
return (
isRecord(value) &&
typeof value.scopeId === 'string' &&
value.scopeId.length > 0 &&
typeof value.generation === 'number' &&
Number.isInteger(value.generation) &&
value.generation > 0 &&
typeof value.digest === 'string' &&
value.digest.length > 0 &&
typeof value.outputSetDigest === 'string' &&
value.outputSetDigest.length > 0
);
}
function isAsset(value: unknown): value is RuntimeAssetProjectionInput {
return (
isRecord(value) &&
typeof value.guid === 'string' &&
value.guid.length > 0 &&
typeof value.kind === 'string' &&
value.kind.length > 0 &&
Array.isArray(value.refs) &&
value.refs.every((ref) => typeof ref === 'string') &&
isRecord(value.artifacts)
);
}
/** Project producer facts into the only runtime Pack v2 envelope. */
export function projectRuntimePack(value: unknown): Result, PackV2Error> {
if (
!isRecord(value) ||
(('schemaVersion' in value || 'kind' in value) &&
(value.schemaVersion !== '2.0.0' || value.kind !== 'internal-text-package'))
) {
return invalid('legacy or malformed pack input', 'runtime Pack v2');
}
if (
!isRuntimePublicationTuple(value) ||
!Array.isArray(value.assets) ||
!value.assets.every(isAsset)
) {
return invalid('incomplete publication tuple or asset envelope', 'verified runtime Pack v2');
}
const seen = new Set();
for (const asset of value.assets) {
const guid = asset.guid.toLowerCase();
if (seen.has(guid)) {
return err({
code: 'pack-v2-duplicate-guid',
expected: 'one asset envelope per GUID',
hint: 'publish one producer row and recook the package output set',
detail: { guid: asset.guid, paths: [] },
});
}
seen.add(guid);
}
return ok({
schemaVersion: '2.0.0',
kind: 'internal-text-package',
scopeId: value.scopeId,
generation: value.generation,
digest: value.digest,
outputSetDigest: value.outputSetDigest,
assets: value.assets as readonly AssetEnvelopeV2[],
});
}