Tools for the Atmosphere tools.slices.network
quickslice atproto html

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 (after getPublishableLexicons function, 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 (after extractExternalRefs)

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

  1. Open lexicon-publisher in browser
  2. Sign in
  3. 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" }
            }
          }
        }
      }
    }
    
  4. Click Validate
  5. Verify: Success message appears, plus yellow warning box showing com.fake.nonexistent as missing (but not app.bsky.actor.defs if it's published)

Step 2: Final commit if needed

git add lexicon-publisher.html
git commit -m "feat(lexicon-publisher): complete external dependency validation"