Skip to content

feat: eliminate runtime npm install from binary installer#13514

Merged
czubocha merged 8 commits into
mainfrom
eliminate-npm-install
May 12, 2026
Merged

feat: eliminate runtime npm install from binary installer#13514
czubocha merged 8 commits into
mainfrom
eliminate-npm-install

Conversation

@czubocha
Copy link
Copy Markdown
Contributor

@czubocha czubocha commented Apr 16, 2026

Summary

Eliminates the runtime npm install from the Go binary installer by bundling all dependencies into the universal archive. The binary no longer needs npm to install the framework.

  • Bundle all pure JS dependencies into sf-core.js (esbuild JS API, ajv, ajv-formats, AWS SDK signature-v4a, CloudFront KVS client)
  • Remove @aws-sdk/signature-v4-crt native dependency — pure JS @aws-sdk/signature-v4a fallback handles SigV4A signing for CloudFront KeyValueStore
  • Ship esbuild platform binaries for all 5 platforms in the archive (~20MB compressed)
  • Ship ajv runtime files (~14KB) needed by cached standalone validators
  • Replace npm pack with tar czf (npm pack strips node_modules/ directories)
  • Go binary: skip npm install when package.json has no dependencies, clean up unused esbuild platform binaries after extraction

Backward compatibility

All four combinations work — phases are independently deployable:

Scenario Behavior
Old binary + Old archive npm install runs as before (unchanged)
Old binary + New archive npm install is a no-op (empty deps), esbuild binaries already in archive
New binary + Old archive Detects dependencies in package.json → runs npm install
New binary + New archive Skips npm install, cleans up unused platform binaries (keeps 1 of 5)

Archive size

Before After
Archive download ~14 MB ~37 MB
Runtime npm install download ~21 MB (182 packages) None
Total download per install ~35 MB ~37 MB
Disk after install 173 MB 110 MB (after platform cleanup)
npm required Yes No
Network calls S3 + npm registry S3 only

Changes

JS build pipeline

  • esbuild.js — Remove all external entries; everything bundled into sf-core.js
  • injects-shim.js — Detect esbuild platform binary at dist/node_modules/@esbuild/<platform>/ and set ESBUILD_BINARY_PATH before esbuild module initialization
  • resolve-ajv-validate.js — Remove __dirname redirect so cached standalone validators resolve ajv runtime files from dist/node_modules/
  • prepareDistributionTarballs.js — Copy ajv runtime files + download esbuild binaries for all 5 platforms (parallel downloads, secure temp dirs)
  • prepareReleaseTars.sh — Replace npm pack with tar czf (GNU + BSD compatible, normalized uid/gid ownership)
  • framework-dist/package.json — Empty dependencies
  • npm-shrinkwrap.json — Deleted

Engine

  • cloudfront-kv.js — Remove import '@aws-sdk/signature-v4-crt'
  • deploy-dynamic-routing.js — Remove import '@aws-sdk/signature-v4-crt'

The AWS SDK falls back to pure JS @aws-sdk/signature-v4a for SigV4A signing. This eliminates the aws-crt native dependency (33MB).

Go binary installer

  • version.go — After archive extraction, read package.json dependencies:
    • If dependencies present → run npm install as before (old archive compatibility)
    • If empty → skip npm install, delete unused @esbuild/* platform directories
    • If missing or corrupted → fail the install (deferred cleanup removes partial release)
    • Platform cleanup uses an allowlist of known esbuild directory names (path traversal safe)
  • version_test.go — Unit tests for helpers + 4-scenario compatibility matrix with realistic archive structures

Summary by CodeRabbit

Release Notes

  • New Features

    • Optimized installation process with conditional dependency setup and cleanup of unused platform-specific binaries.
  • Chores

    • Updated framework version to 4.35.1.
    • Restructured framework dependencies for improved bundling efficiency.
    • Enhanced esbuild binary handling for platform-specific deployments.

…taller

Bundle all dependencies into the universal archive so the Go binary
installer no longer needs to run `npm install` at runtime.

Changes:
- Bundle pure JS deps into sf-core.js (ajv, ajv-formats, esbuild JS API,
  @aws-sdk/signature-v4a, @aws-sdk/client-cloudfront-keyvaluestore)
- Remove @aws-sdk/signature-v4-crt side-effect imports (pure JS fallback)
- Ship ajv runtime files in dist/node_modules/ for cached validators
- Ship all 5 esbuild platform binaries in dist/node_modules/@esbuild/
- Set ESBUILD_BINARY_PATH in injects-shim.js before esbuild module init
- Replace npm pack with tar czf (npm pack strips node_modules/)
- Go binary: skip npm install when package.json has no dependencies,
  clean up unused esbuild platform binaries (keeps only current platform)

Backward compatible:
- Old Go binary + new archive: npm install is a no-op, framework works
- New Go binary + old archive: detects dependencies, runs npm install
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 52fedfb2-1ad9-4c31-8138-a9c45afd05e3

📥 Commits

Reviewing files that changed from the base of the PR and between 097c44d and 9278f5b.

📒 Files selected for processing (7)
  • binary-installer/src/version.go
  • packages/framework-dist/package.json
  • packages/serverless/lib/classes/config-schema-handler/resolve-ajv-validate.js
  • packages/sf-core/package.json
  • packages/sf-core/prepareReleaseTars.sh
  • packages/sf-core/scripts/pack-framework-dist.sh
  • packages/sf-core/scripts/prepareDistributionTarballs.js
✅ Files skipped from review due to trivial changes (1)
  • packages/framework-dist/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/serverless/lib/classes/config-schema-handler/resolve-ajv-validate.js
  • binary-installer/src/version.go
  • packages/sf-core/scripts/prepareDistributionTarballs.js

📝 Walkthrough

Walkthrough

Refactors distribution packaging to embed AJV and platform esbuild binaries into the framework tarball, removes runtime dependencies from the published package.json, updates packaging/pack scripts to produce normalized tarballs, and changes the binary installer to skip npm install for archives without dependencies while cleaning up unused esbuild platform binaries. Tests added for the installer changes.

Changes

Binary installer behavior

Layer / File(s) Summary
Dependency check & conditional install
binary-installer/src/version.go
Adds archiveHasDependencies(packageDir) and gates npm install on the presence of a non-empty dependencies map in package/package.json. Dependency-check errors are returned as checking archive dependencies: ....
Esbuild cleanup helper
binary-installer/src/version.go
Adds cleanupUnusedEsbuildBinaries(esbuildDir) and helpers (goPlatformToEsbuildDir, esbuildPlatformDir, validEsbuildPlatforms) to remove only non-current-platform @esbuild/<platform> subdirectories that are allowlisted.
Installer tests & fixtures
binary-installer/src/version_test.go
Extensive tests for archiveHasDependencies() and cleanupUnusedEsbuildBinaries(), and compatibility-matrix style tests that validate old vs new installer flows using synthesized archive layouts and platform-aware assertions. Includes test helpers/fixtures.

Framework package & bundling

Layer / File(s) Summary
Published package metadata
packages/framework-dist/package.json
Bumps @serverlessinc/framework-alpha version and replaces runtime dependencies with an empty {} in the published package.json.
esbuild bundling config
packages/sf-core/esbuild.js
Removes the external array so previously external modules (esbuild, ajv, aws-sdk pieces, etc.) are bundled into built outputs.
Runtime shim for esbuild
packages/sf-core/injects-shim.js
Adds resolution for process.env.ESBUILD_BINARY_PATH by checking bundled node_modules/@esbuild/<platform>/bin/esbuild under __dirname and setting the env var when present.
AJV resolver adjustment
packages/serverless/lib/classes/config-schema-handler/resolve-ajv-validate.js
Stops rebasing __dirname for bundled layouts; keeps __dirname unchanged and documents intent for requireFromString runtime resolution.

Distribution tarball creation & assets

Layer / File(s) Summary
Prepare distribution & copy AJV runtimes
packages/sf-core/scripts/prepareDistributionTarballs.js
Adds resolution from packages/serverless workspace for ajv/esbuild, creates framework-dist/dist/node_modules subdirectories, copies selected AJV runtime modules and writes minimal package.json files with matching versions.
Download esbuild platform binaries
packages/sf-core/scripts/prepareDistributionTarballs.js
Adds downloadEsbuildBinary(pkg, binary) to download and verify @esbuild/* tarballs (integrity checked against repo package-lock), extract per-platform binaries to framework-dist/dist/node_modules/@esbuild/<platform>/, set exec perms, and run concurrent downloads for five platforms.
Packaging script & release change
packages/sf-core/scripts/pack-framework-dist.sh, packages/sf-core/prepareReleaseTars.sh, packages/sf-core/package.json
Adds pack-framework-dist.sh which builds a versioned tarball with normalized ownership and path rewrite (GNU/BSD tar handling); replaces npm pack invocations in build/release scripts with this packaging step.

Minor cleanup

Layer / File(s) Summary
AWS SDK side-effect import removal
packages/engine/src/lib/aws/cloudfront-kv.js, packages/engine/src/lib/deploymentTypes/aws/deploy-dynamic-routing.js
Removes side-effect import of @aws-sdk/signature-v4-crt from two files; keeps existing @aws-sdk/signature-v4a usage.

Sequence Diagram(s)

sequenceDiagram
    participant Build as BuildScript
    participant FS as FileSystem
    participant Registry as NPMRegistry
    participant Installer as BinaryInstaller
    participant PKG as package.json

    rect rgba(100, 200, 150, 0.5)
    Note over Build,Registry: Build-time bundling
    Build->>Registry: Download `@esbuild/<platform>` tarballs (concurrent)
    Registry-->>Build: Platform tarballs
    Build->>FS: Extract esbuild binaries to framework-dist/dist/node_modules/@esbuild/<platform>/
    Build->>FS: Copy AJV runtime files into framework-dist/dist/node_modules/ajv...
    end

    rect rgba(150, 150, 200, 0.5)
    Note over Installer,FS: Install-time behavior
    Installer->>FS: Extract package archive
    Installer->>PKG: Read/check `dependencies` via archiveHasDependencies()
    alt dependencies present
        Installer->>Registry: Run `npm install`
        Registry-->>Installer: Install results
    else no dependencies
        Installer->>FS: cleanupUnusedEsbuildBinaries() (remove other-platform dirs)
    end
    Installer->>FS: Finalize installation
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • eahefnawy
  • Mmarzex

Poem

🐰 I hopped through dist with careful paws,
Bundled AJV and esbuild without a loss,
Old installs skip installs that they do not need,
I pruned other platforms with nimble speed,
A happy rabbit cheers the packed release 🌸

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main objective of the PR: eliminating the runtime npm install step from the binary installer by bundling dependencies and esbuild binaries.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch eliminate-npm-install

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Mmarzex
Copy link
Copy Markdown
Contributor

Mmarzex commented Apr 16, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@czubocha czubocha changed the title feat(binary-installer): eliminate runtime npm install from binary installer feat: eliminate runtime npm install from binary installer Apr 16, 2026
@czubocha czubocha marked this pull request as ready for review April 16, 2026 13:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@binary-installer/src/version.go`:
- Around line 516-526: Only treat a missing package.json as the compatibility
case; when calling os.ReadFile(filepath.Join(packageDir, "package.json")) check
if the error is an os.IsNotExist error and return (false, nil) only then,
otherwise propagate the read error (return false, err) so failures bubble up;
likewise, when json.Unmarshal(data, &pkg) fails do not swallow the error—return
(false, err) instead of (false, nil). Update the error handling around
os.ReadFile and json.Unmarshal (symbols: os.ReadFile, filepath.Join, packageDir,
"package.json", json.Unmarshal, pkg) so corrupted/unreadable package.json causes
the install to fail and trigger cleanup.

In `@packages/sf-core/scripts/prepareDistributionTarballs.js`:
- Around line 12-17: The two require initializations (serverlessRequire and
sfCoreRequire) use import.meta.dirname which is inconsistent with the codebase;
replace that by deriving a directory from fileURLToPath(import.meta.url) and
using path.dirname so createRequire calls use
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '<relative-path>');
import fileURLToPath from 'url', compute the current file dir with
path.dirname(fileURLToPath(import.meta.url)), then pass that dir into the
existing createRequire/path.resolve calls for serverlessRequire and
sfCoreRequire to match the project's established pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7137417c-9209-4dee-9a95-9b57a6695db4

📥 Commits

Reviewing files that changed from the base of the PR and between cbef22f and 48fddc3.

📒 Files selected for processing (11)
  • binary-installer/src/version.go
  • binary-installer/src/version_test.go
  • packages/engine/src/lib/aws/cloudfront-kv.js
  • packages/engine/src/lib/deploymentTypes/aws/deploy-dynamic-routing.js
  • packages/framework-dist/npm-shrinkwrap.json
  • packages/framework-dist/package.json
  • packages/serverless/lib/classes/config-schema-handler/resolve-ajv-validate.js
  • packages/sf-core/esbuild.js
  • packages/sf-core/injects-shim.js
  • packages/sf-core/prepareReleaseTars.sh
  • packages/sf-core/scripts/prepareDistributionTarballs.js
💤 Files with no reviewable changes (3)
  • packages/engine/src/lib/deploymentTypes/aws/deploy-dynamic-routing.js
  • packages/sf-core/esbuild.js
  • packages/engine/src/lib/aws/cloudfront-kv.js

Comment thread binary-installer/src/version.go Outdated
Comment thread packages/sf-core/scripts/prepareDistributionTarballs.js Outdated
…leURLToPath for Node 18 compat

- archiveHasDependencies: only treat missing package.json as "skip npm
  install". I/O errors and malformed JSON now return errors so the
  deferred cleanup removes the broken release instead of marking it as
  successfully installed.
- prepareDistributionTarballs.js: replace import.meta.dirname (Node 21.2+)
  with fileURLToPath(import.meta.url) for consistency with the rest of
  the codebase. Consolidate two createRequire instances into one
  (resolveFromServerless) since both ajv and esbuild are deps of the
  serverless package.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
binary-installer/src/version_test.go (2)

465-499: Minor inconsistency in Windows binary path structure.

This test creates bin/esbuild for all platforms including win32-x64, but createNewArchive (line 564) correctly uses esbuild.exe directly in the platform directory for Windows. While this doesn't affect the cleanup test (which only checks directory removal), it's inconsistent with the actual archive structure.

Consider aligning the binary creation logic with createNewArchive for consistency:

💡 Suggested fix for consistency
 	platforms := []string{"darwin-arm64", "darwin-x64", "linux-arm64", "linux-x64", "win32-x64"}
 	for _, p := range platforms {
-		dir := filepath.Join(esbuildDir, p, "bin")
-		if err := os.MkdirAll(dir, 0o755); err != nil {
+		var binPath string
+		if p == "win32-x64" {
+			binPath = filepath.Join(esbuildDir, p, "esbuild.exe")
+		} else {
+			binPath = filepath.Join(esbuildDir, p, "bin", "esbuild")
+		}
+		if err := os.MkdirAll(filepath.Dir(binPath), 0o755); err != nil {
 			t.Fatal(err)
 		}
-		_ = os.WriteFile(filepath.Join(dir, "esbuild"), []byte("binary"), 0o755)
+		_ = os.WriteFile(binPath, []byte("binary"), 0o755)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@binary-installer/src/version_test.go` around lines 465 - 499, The test
TestCleanupUnusedEsbuildBinaries creates a Windows artifact under bin/esbuild
but createNewArchive uses esbuild.exe directly in the platform dir; update the
test so when platform == "win32-x64" it writes "esbuild.exe" at
filepath.Join(esbuildDir, p, "esbuild.exe") (matching createNewArchive) instead
of writing under bin/, leaving cleanupUnusedEsbuildBinaries and
esbuildPlatformDir logic unchanged.

827-829: Consider adding an explicit assertion or comment for clarity.

The test validates that cleanupUnusedEsbuildBinaries doesn't panic when the directory doesn't exist, but this intent isn't explicitly documented. Adding a brief comment would improve readability.

💡 Suggested improvement
 func TestCleanupUnusedEsbuildBinaries_MissingDir(t *testing.T) {
+	// Should not panic when esbuild directory doesn't exist
 	cleanupUnusedEsbuildBinaries("/nonexistent/path")
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@binary-installer/src/version_test.go` around lines 827 - 829, The test
TestCleanupUnusedEsbuildBinaries_MissingDir currently calls
cleanupUnusedEsbuildBinaries("/nonexistent/path") without documenting intent;
update the test to either add a brief comment stating "ensures
cleanupUnusedEsbuildBinaries does not panic when directory is missing" or
replace the direct call with an explicit non-panic assertion (e.g., using
require.NotPanics or a defer/recover check) to make the intention clear; refer
to the TestCleanupUnusedEsbuildBinaries_MissingDir test and the
cleanupUnusedEsbuildBinaries function when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@binary-installer/src/version_test.go`:
- Around line 465-499: The test TestCleanupUnusedEsbuildBinaries creates a
Windows artifact under bin/esbuild but createNewArchive uses esbuild.exe
directly in the platform dir; update the test so when platform == "win32-x64" it
writes "esbuild.exe" at filepath.Join(esbuildDir, p, "esbuild.exe") (matching
createNewArchive) instead of writing under bin/, leaving
cleanupUnusedEsbuildBinaries and esbuildPlatformDir logic unchanged.
- Around line 827-829: The test TestCleanupUnusedEsbuildBinaries_MissingDir
currently calls cleanupUnusedEsbuildBinaries("/nonexistent/path") without
documenting intent; update the test to either add a brief comment stating
"ensures cleanupUnusedEsbuildBinaries does not panic when directory is missing"
or replace the direct call with an explicit non-panic assertion (e.g., using
require.NotPanics or a defer/recover check) to make the intention clear; refer
to the TestCleanupUnusedEsbuildBinaries_MissingDir test and the
cleanupUnusedEsbuildBinaries function when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a79ad5eb-fad2-4652-986a-f3976ad050ac

📥 Commits

Reviewing files that changed from the base of the PR and between 48fddc3 and 097c44d.

📒 Files selected for processing (3)
  • binary-installer/src/version.go
  • binary-installer/src/version_test.go
  • packages/sf-core/scripts/prepareDistributionTarballs.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/sf-core/scripts/prepareDistributionTarballs.js
  • binary-installer/src/version.go

@nickskelsey
Copy link
Copy Markdown

Short note here:

This approach bundles esbuild binaries for all 5 platforms into the tarball, bringing it to 65MB. Consider following the pattern used by @biomejs/biome to ship platform-specific packages instead. A consumers would have to download only the binary they need (~14MB).

For example:

@czubocha
Copy link
Copy Markdown
Contributor Author

Short note here:

This approach bundles esbuild binaries for all 5 platforms into the tarball, bringing it to 65MB. Consider following the pattern used by @biomejs/biome to ship platform-specific packages instead. A consumers would have to download only the binary they need (~14MB).

For example:

Thanks for the suggestion! I looked into adopting the biomejs pattern and wanted to share what's blocking it.

Why we can't use optionalDependencies on the serverless npm package:

Without a post-install step, the Go binary would need to locate the npm-installed esbuild binary at runtime. Discovery is complex across install scenarios (npm global, npm local, pnpm, Yarn PnP, etc.) and doesn't work at all for users who install the Go binary via the curl-based install script from install.serverless.com — they have no serverless npm package on their system.

On archive size (the 65MB concern): compressed archive is ~37MB (5 esbuild binaries compress to ~20MB from ~50MB). Total user download is ~37MB vs ~35MB today (14MB archive + ~21MB npm install traffic measured via isolated cache), so net download is nearly unchanged.

On disk: ~110MB after cleanup (Go binary deletes 4 unused platform binaries), vs 173MB today.

If download size becomes a real concern later, we can switch to platform-specific S3 archives (serverless-<version>-<os>-<arch>.tgz), which keeps the "no runtime npm install" property and drops per-user download to ~22MB. That needs a breaking change to the archive URL format plus a migration window, so it's a separate effort.

czubocha added 6 commits May 5, 2026 21:38
# Conflicts:
#	packages/framework-dist/npm-shrinkwrap.json
#	packages/framework-dist/package.json
# Conflicts:
#	packages/framework-dist/npm-shrinkwrap.json
#	packages/framework-dist/package.json
The framework-dist version had drifted to 4.3.3 on main (likely a typo for
4.33.3 in the original "publish as npm package" commit). Bump to 4.35.1 to
match sf-core, which is the runtime source of truth that prepareDistributionTarballs.js
overwrites this field with at build time anyway.
Extract the framework-dist tarball packaging into a shared script
(pack-framework-dist.sh), called from both prepareReleaseTars.sh and
the sf-core test:build npm script.

test:build previously ended in `npm pack`, which produced a tarball
with different ownership metadata and could include stray files (like
prior tarballs left in the directory). Local builds now mirror what
CI/CD produces.
Pull the SRI hash recorded by npm for each @esbuild/<platform> package
out of the workspace package-lock.json and verify the downloaded tarball
matches before extracting. Same trust anchor as `npm install` —
protects the release build from registry tampering between dependency
install and tarball download.
…mment

- Collapse esbuildPlatformDir and validEsbuildPlatforms onto a single
  source-of-truth map; adding a future platform now touches one place
  instead of two.
- Replace a hardcoded line-number reference in resolve-ajv-validate.js
  with a content-based pointer that won't rot when the file changes.
@czubocha czubocha merged commit 2294877 into main May 12, 2026
15 checks passed
@czubocha czubocha deleted the eliminate-npm-install branch May 12, 2026 13:18
@github-actions github-actions Bot locked and limited conversation to collaborators May 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants