External Dependency Validation Implementation Plan#
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Warn users when their lexicons reference external dependencies that aren't published.
Architecture: After honk validation passes, extract all ref properties pointing to external NSIDs, batch-query the lexicons quickslice to check which exist, show yellow warnings for missing ones.
Tech Stack: JavaScript, GraphQL (lexicons quickslice)
Task 1: Add missingDependencies to state#
Files:
- Modify:
lexicon-publisher.html:642-644
Step 1: Add the new state property
Find this block:
// New: DNS instructions
dnsInstructions: [], // [{ domain, record, lexicons }]
};
Change to:
// New: DNS instructions
dnsInstructions: [], // [{ domain, record, lexicons }]
// New: External dependency check
missingDependencies: [], // [nsid, ...]
};
Step 2: Commit
git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): add missingDependencies state"
Task 2: Add extractExternalRefs function#
Files:
- Modify:
lexicon-publisher.html(aftergetPublishableLexiconsfunction, around line 1097)
Step 1: Add the function
After the getPublishableLexicons function closing brace, add:
function extractExternalRefs(lexicons, userDomain) {
const refs = new Set();
function walk(obj) {
if (!obj || typeof obj !== 'object') return;
if (obj.ref && typeof obj.ref === 'string') {
const nsid = obj.ref.split('#')[0];
const domain = getDomainAuthority(nsid);
if (domain !== userDomain && !domain.endsWith('.' + userDomain)) {
refs.add(nsid);
}
}
for (const val of Object.values(obj)) walk(val);
}
for (const lex of lexicons) walk(lex);
return [...refs];
}
Step 2: Commit
git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): add extractExternalRefs function"
Task 3: Add checkExternalDependencies function#
Files:
- Modify:
lexicon-publisher.html(afterextractExternalRefs)
Step 1: Add the function
After extractExternalRefs, add:
async function checkExternalDependencies(externalNsids) {
if (externalNsids.length === 0) return { found: [], missing: [] };
try {
const result = await state.client.query(`
query CheckDeps($nsids: [String!]!) {
comAtprotoLexiconSchema(
first: 100,
where: { id: { in: $nsids } }
) {
edges {
node { id }
}
}
}
`, { nsids: externalNsids });
const foundIds = (result?.comAtprotoLexiconSchema?.edges || [])
.map(e => e.node.id);
return {
found: externalNsids.filter(n => foundIds.includes(n)),
missing: externalNsids.filter(n => !foundIds.includes(n)),
};
} catch (err) {
console.error("External dependency check failed:", err);
return { found: [], missing: [] };
}
}
Step 2: Commit
git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): add checkExternalDependencies function"
Task 4: Integrate into validateLexicons#
Files:
- Modify:
lexicon-publisher.html:1396-1440(validateLexicons function)
Step 1: Reset missingDependencies at start
Find:
state.result = null;
state.validationPassed = false;
state.conflicts = [];
Change to:
state.result = null;
state.validationPassed = false;
state.conflicts = [];
state.missingDependencies = [];
Step 2: Add external dependency check after honk passes
Find:
// Check for conflicts if authenticated
if (state.viewer) {
await checkConflicts();
}
Change to:
// Check for external dependencies and conflicts if authenticated
if (state.viewer) {
const userDomain = getUserDomain(state.viewer.handle);
const externalRefs = extractExternalRefs(parseResult.lexicons, userDomain);
const { missing } = await checkExternalDependencies(externalRefs);
state.missingDependencies = missing;
await checkConflicts();
}
Step 3: Commit
git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): check external deps during validation"
Task 5: Update renderResult to show warnings#
Files:
- Modify:
lexicon-publisher.html:1251-1266(renderResult function)
Step 1: Add warning display after success message
Find:
section.innerHTML = `
<div class="result ${cls}" style="margin-top: 0.75rem;">${icon} ${esc(state.result.message)}</div>
`;
}
Change to:
let html = `<div class="result ${cls}" style="margin-top: 0.75rem;">${icon} ${esc(state.result.message)}</div>`;
if (state.missingDependencies.length > 0) {
html += `
<div class="warning-box" style="margin-top: 0.75rem;">
<strong>Missing external dependencies:</strong>
<ul style="margin: 0.5rem 0 0 1.25rem;">
${state.missingDependencies.map(d => `<li>${esc(d)}</li>`).join('')}
</ul>
</div>
`;
}
section.innerHTML = html;
}
Step 2: Commit
git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): display missing dependency warnings"
Task 6: Manual test#
Step 1: Test with external refs
- Open lexicon-publisher in browser
- Sign in
- Upload or paste a lexicon that references an external type, e.g.:
{ "lexicon": 1, "id": "slices.network.test", "defs": { "main": { "type": "record", "record": { "type": "object", "properties": { "actor": { "type": "ref", "ref": "app.bsky.actor.defs#profileViewBasic" }, "fake": { "type": "ref", "ref": "com.fake.nonexistent#thing" } } } } } } - Click Validate
- Verify: Success message appears, plus yellow warning box showing
com.fake.nonexistentas missing (but notapp.bsky.actor.defsif it's published)
Step 2: Final commit if needed
git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): complete external dependency validation"