feat: complete mindspace conversation packages
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
function issue(code, message, details = {}) {
|
||||
return { code, message, ...details };
|
||||
}
|
||||
|
||||
function isReadableUrl(value) {
|
||||
const text = String(value ?? '').trim();
|
||||
return (
|
||||
text.startsWith('http://') ||
|
||||
text.startsWith('https://') ||
|
||||
text.startsWith('/api/') ||
|
||||
text.startsWith('/MindSpace/')
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeStorageKey(value) {
|
||||
return String(value ?? '').trim().replace(/^\/+/, '');
|
||||
}
|
||||
|
||||
export async function verifyConversationPackageManifest(manifest, options = {}) {
|
||||
const issues = [];
|
||||
const statObject = typeof options.statObject === 'function' ? options.statObject : null;
|
||||
const packageId = String(manifest?.packageId ?? '').trim();
|
||||
const storagePrefix = normalizeStorageKey(manifest?.storagePrefix);
|
||||
const artifacts = Array.isArray(manifest?.artifacts) ? manifest.artifacts : null;
|
||||
|
||||
if (!packageId) issues.push(issue('missing_package_id', 'manifest.packageId is required'));
|
||||
if (!String(manifest?.userId ?? '').trim()) issues.push(issue('missing_user_id', 'manifest.userId is required'));
|
||||
if (!String(manifest?.sessionId ?? '').trim()) {
|
||||
issues.push(issue('missing_session_id', 'manifest.sessionId is required'));
|
||||
}
|
||||
if (!storagePrefix) issues.push(issue('missing_storage_prefix', 'manifest.storagePrefix is required'));
|
||||
if (!artifacts) issues.push(issue('invalid_artifacts', 'manifest.artifacts must be an array'));
|
||||
|
||||
const seenArtifactIds = new Set();
|
||||
for (const artifact of artifacts ?? []) {
|
||||
const artifactId = String(artifact?.artifactId ?? '').trim();
|
||||
if (!artifactId) {
|
||||
issues.push(issue('missing_artifact_id', 'artifact.artifactId is required'));
|
||||
continue;
|
||||
}
|
||||
if (seenArtifactIds.has(artifactId)) {
|
||||
issues.push(issue('duplicate_artifact_id', `duplicate artifact id: ${artifactId}`, { artifactId }));
|
||||
}
|
||||
seenArtifactIds.add(artifactId);
|
||||
|
||||
const canonicalUrl = String(artifact?.canonicalUrl ?? '').trim();
|
||||
const storageKey = normalizeStorageKey(artifact?.storageKey);
|
||||
if (!canonicalUrl && !storageKey) {
|
||||
issues.push(
|
||||
issue('artifact_without_backing_reference', 'artifact must have canonicalUrl or storageKey', { artifactId }),
|
||||
);
|
||||
}
|
||||
if (canonicalUrl && !isReadableUrl(canonicalUrl)) {
|
||||
issues.push(issue('invalid_canonical_url', `artifact canonicalUrl is not readable: ${canonicalUrl}`, {
|
||||
artifactId,
|
||||
canonicalUrl,
|
||||
}));
|
||||
}
|
||||
if (storageKey && storagePrefix && !storageKey.startsWith(`${storagePrefix}/`)) {
|
||||
issues.push(issue('storage_key_outside_package', 'artifact storageKey is outside manifest.storagePrefix', {
|
||||
artifactId,
|
||||
storageKey,
|
||||
storagePrefix,
|
||||
}));
|
||||
}
|
||||
if (storageKey && statObject) {
|
||||
const stat = await statObject(storageKey);
|
||||
if (!stat?.exists) {
|
||||
issues.push(issue('missing_backing_object', `artifact backing object is missing: ${storageKey}`, {
|
||||
artifactId,
|
||||
storageKey,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: issues.length === 0, issues };
|
||||
}
|
||||
|
||||
export const conversationPackageVerifyInternals = {
|
||||
isReadableUrl,
|
||||
normalizeStorageKey,
|
||||
};
|
||||
Reference in New Issue
Block a user