feat(npm): npm hosted step 20, part 2 of 3 — unpublish handler + core tests

Part 2 of 3 of the npm hosted planStep 20: whole-package unpublish + inline cascade.

🗂️ Stacked MRs

Split into 3 stacked MRs to keep each within the review size limit (~600 ideal reviewable LoC). Each part targets the previous one (part 1 → main); review and merge bottom-up.

🔌 What this part adds

  • UnpublishPackageHandler for DELETE /{slug}/npm/{repo}/{package}/-rev/{rev}: verifies {rev} (mismatch → 409 rev_mismatch), missing package → 404 package_not_found, missing auth resolution → 500 (AC 58). On success returns 200 {"ok": true} and emits the post-commit bufferedUpdate counter events (repositories.artifacts_count, repositories.size_bytes) off the request path.
  • InstallBufferedWaitGroup test-export shim, so the external npm_test package can await the detached bufferedUpdate goroutines deterministically.
  • Core integration tests plus the shared fixture helpers the whole unpublish suite builds on.

ℹ️ The route is currently wired to a 501 placeholder in handler.go; mounting the real handler is a deliberate later step, the same pattern used for the other npm handlers.

Spec coverage

Acceptance criterion / case Test
AC 59 — happy path (200, package + versions soft-deleted) TestUnpublishPackageIntegration_Success
AC 59 — non-matching {rev} → 409 rev_mismatch TestUnpublishPackageIntegration_RevMismatch
AC 34 — missing package → 404 package_not_found TestUnpublishPackageIntegration_PackageNotFound
AC 58 — auth contract (no resolution → 500) TestUnpublishPackageIntegration_MissingResolution_Returns500
AC 27 — metadata cache invalidated in-tx TestUnpublishPackageIntegration_CacheInvalidated

📚 References

Related to #138 (closed)

Edited by David Fernandez

Merge request reports

Loading
Loading