Skip to content

fix: use npm Registry API instead of npm search#21

Merged
AliiiBenn merged 7 commits intomainfrom
fix/use-registry-api
Mar 5, 2026
Merged

fix: use npm Registry API instead of npm search#21
AliiiBenn merged 7 commits intomainfrom
fix/use-registry-api

Conversation

@AliiiBenn
Copy link
Member

Summary

  • Replace npm search (via execFileSync) with direct fetch to npm Registry API for template discovery
  • This fixes the issue where newly published templates don't appear in --list due to npm's delayed search indexing
  • The web app already uses this approach, now the CLI matches it

Changes

  1. packages/create/src/registry.ts:

    • Replace execFileSync/npm search with fetch to https://registry.npmjs.org/-/v1/search
    • Use proper TEMPLATE_SCOPE constants for both API and package names
    • Add AbortSignal timeout for reliability
  2. packages/create/package.json:

    • Add @vitest/coverage-v8 for coverage reporting
  3. packages/create/tests/registry.test.ts:

    • Add comprehensive tests for listTemplates function
    • Mock fetch instead of execFileSync

Test plan

  • Run npm test - all tests pass
  • Test npx @nesalia/create --list to verify templates appear
  • Verify newly published templates appear immediately in --list

🤖 Generated with Claude Code

AliiiBenn and others added 3 commits March 5, 2026 10:52
Add coverage dependency for running tests with coverage reports.

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
Replace execFileSync/npm search with direct fetch to npm Registry API
for faster and more reliable template discovery. This fixes the issue
where newly published templates don't appear in --list due to npm's
delayed search indexing.

The web app already uses this approach, now the CLI matches it.

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
Add comprehensive tests for listTemplates function covering:
- Successful template retrieval
- Empty results handling
- Error handling (non-OK status, network failures)
- Package filtering (non-nesalia packages)
- Description parsing
- Edge cases

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
@vercel
Copy link

vercel bot commented Mar 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
create-web Ready Ready Preview, Comment Mar 5, 2026 10:38am


const TEMPLATE_SCOPE = '@nesalia/template-';
// TEMPLATE_SCOPE is used for npm search API (without trailing dash)
const TEMPLATE_SCOPE = '@nesalia/template';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of constants for template scopes. However, there's a subtle inconsistency: TEMPLATE_SCOPE (line 16) is @nesalia/template but the filtering logic (line 65) uses TEMPLATE_SCOPE- (with dash). Consider adding a comment or using a single constant to avoid confusion.


const templates: DiscoveredTemplate[] = packages
.filter((pkg: { name: string }) => pkg.name.startsWith(TEMPLATE_SCOPE))
.filter((pkg: { name: string }) => pkg.name.startsWith(`${TEMPLATE_SCOPE}-`))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This filter correctly checks for TEMPLATE_SCOPE- (with dash), but it's worth noting this relies on the API returning packages with the @nesalia/template- prefix. Consider documenting this expectation or adding a comment explaining why the filter works this way.

{ ...execOptions, maxBuffer: 10 * 1024 * 1024 }
);
// Use npm Registry API directly for faster and more reliable results
const response = await fetch(NPM_REGISTRY_API, {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout is set to 60000ms (1 minute), which is appropriate. However, AbortSignal.timeout() in Node.js may not work in older Node versions. Consider verifying the minimum Node.js version supported (currently specified as >=20 in package.json, which supports this feature).

it('should throw error when npm query fails', async () => {
mockExecFileSync.mockImplementation(() => {
throw new Error('Network error');
it('should throw error when API returns non-OK status', async () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good test coverage. However, there's a minor issue: the mock for ok: false at line 68 should also mock statusText for completeness, as the actual Response object includes this property. Also consider adding a test for pagination if the API might return more than 100 results.

Update pnpm-lock.yaml to include new dependencies.

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
Add explicit type annotation for the npm Registry API response
to fix TypeScript error during build.

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>
expect(templates[0].tags).toEqual([]);
});

it('should handle malformed JSON response', async () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test for malformed JSON response checks response.ok is true but json() rejects. This is correct behavior, but worth noting the test covers JSON parse errors well.

@marty-action
Copy link

marty-action bot commented Mar 5, 2026

Summary

This PR replaces the npm search CLI command with direct fetch to the npm Registry API v1 search endpoint. This is a solid improvement that should provide faster, more reliable template discovery and fixes the issue with delayed npm search indexing for newly published templates.

Critical Issues

  1. Test Coverage Regression: Tests for fetchTemplate and cleanupTemplate functions were removed (lines 83-98 in original). These functions still exist and are used by the codebase. While the new listTemplates tests are comprehensive, removing tests for other exported functions is a coverage regression that should be addressed.

  2. Unused Dependency: @vitest/coverage-v8 was added to package.json but there's no visible coverage configuration or script using it in the PR. If this was added for future use, it should be documented.

Recommendations

  1. Restore or replace tests: Add back tests for fetchTemplate and cleanupTemplate functions, or at minimum add integration tests that verify the full flow from listing to fetching a template.

  2. Clarify coverage dependency: If @vitest/coverage-v8 was added intentionally, consider adding a coverage script or remove it if not needed.

  3. Consider adding tests for error paths in fetchTemplate: The original test verified 404 handling - this is important for user experience when templates don't exist.

Positive Notes

  • Clean separation of TEMPLATE_SCOPE (for API) vs TEMPLATE_SCOPE_PACKAGE (for package names) - good pattern
  • Proper use of AbortSignal.timeout() for request timeout handling
  • Good error message wrapping that preserves context
  • Comprehensive new tests for listTemplates covering edge cases (empty results, non-nesalia packages, malformed responses, description parsing)
  • Removed dependency on shell execution - simpler and more portable

Code Quality

  • No security concerns identified
  • No code duplication
  • Good error handling approach

Review by Claude Code

- Add tests for fetchTemplate validation (invalid ID, path traversal, empty)
- Add test for npm pack failure handling
- Add cleanupTemplate error handling test
- Add test:coverage script to package.json

This addresses the test coverage regression noted in PR review.

Co-Authored-By: martty-code <nesalia.inc@gmail.com>
Co-Authored-By: Claude Sonnet <noreply@anthropic.com>

const TEMPLATE_SCOPE = '@nesalia/template-';
// TEMPLATE_SCOPE is used for npm search API (without trailing dash)
const TEMPLATE_SCOPE = '@nesalia/template';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TEMPLATE_SCOPE here is used correctly for filtering packages in the API response (line 67), but this matches the web app implementation.

@marty-action
Copy link

marty-action bot commented Mar 5, 2026

Summary

This PR replaces the CLI's use of npm search (via execFileSync) with direct fetch to the npm Registry API (https://registry.npmjs.org/-/v1/search), aligning the CLI behavior with the web app which already uses this approach.

Critical Issues

None identified - the implementation is solid and addresses the stated issue of npm's delayed search indexing.

Recommendations

  1. Minor inconsistency in return object (registry.ts:276-278): The return object uses tempDirectory but the variable is named tempDir. Consider using consistent naming:

    return {
      directory: tempDir,
      tempDirectory: tempDir,  // Should match variable name
      manifest,
    };
  2. Type annotation could be more descriptive (registry.ts:60-62): The inline type for the API response works but could be extracted to a named interface for better readability and reusability.

  3. Consider adding retry logic (registry.ts:49-98): The fetch has no retry mechanism. If the initial request fails, users get an error immediately. A single retry could improve reliability without much complexity.

Positive Notes

  • Good security practices: Input validation (validateTemplateId), path traversal protection (validateFilePaths), and blocking dangerous scripts (validateNoScripts)
  • Proper error handling: Descriptive error messages with original error context
  • Comprehensive test coverage: Tests cover success cases, empty results, errors, filtering, and edge cases
  • Performance improvement: Native fetch is significantly faster than spawning subprocess
  • Timeout handling: Proper use of AbortSignal.timeout() for reliability
  • Consistency: Matches web app implementation

Test Coverage

The test suite is thorough:

  • ✅ Successful template retrieval
  • ✅ Empty results handling
  • ✅ Error handling (non-OK status, network failures)
  • ✅ Package filtering (non-nesalia packages)
  • ✅ Description parsing with displayName extraction
  • ✅ Edge cases (missing description, malformed JSON)

Overall: This is a well-implemented fix that addresses the search indexing delay issue. The code is clean, secure, and well-tested. The minor recommendations are optional improvements - the PR is ready for merge.

@AliiiBenn AliiiBenn merged commit 13afb35 into main Mar 5, 2026
10 checks passed
@AliiiBenn AliiiBenn deleted the fix/use-registry-api branch March 5, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant