Skip to content

Commit 36a72b4

Browse files
committed
feat(build): leverage socket-btm releases for pre-compiled assets
- Create shared socket-btm-releases utility module - Dynamically fetch latest releases from GitHub API - Support env var overrides (SOCKET_BTM_*_TAG) - Cache downloads in build/.cache instead of ~/.socket - Add extract-node-smol.mjs for on-demand SEA binary extraction - Add extract-models.mjs for AI models (MiniLM-L6-v2, CodeT5) - Refactor extract-yoga-wasm.mjs to use shared utilities - Update build.mjs to extract yoga and models (node-smol on-demand only) - Rename SOCKET_CLI_NODE_DOWNLOAD_URL to PREBUILT_NODE_DOWNLOAD_URL - Default to socket-btm smol binaries instead of nodejs.org archives - Add ES module export to yoga-sync.mjs for esbuild compatibility
1 parent 8a94878 commit 36a72b4

32 files changed

+834
-225
lines changed

.config/esbuild-inject-import-meta.mjs

Lines changed: 0 additions & 10 deletions
This file was deleted.

.github/workflows/build-sea.yml

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,14 @@ jobs:
136136
platform: linux
137137
arch: arm64
138138

139-
# Alpine Linux builds - use musl binaries from unofficial-builds.nodejs.org.
139+
# Alpine Linux builds - use musl binaries.
140140
- runner: ubuntu-latest
141141
os: linux
142-
platform: alpine
142+
platform: linux-musl
143143
arch: x64
144144
- runner: ubuntu-24.04-arm
145145
os: linux
146-
platform: alpine
146+
platform: linux-musl
147147
arch: arm64
148148

149149
# macOS builds.
@@ -172,7 +172,7 @@ jobs:
172172
shell: bash
173173
run: |
174174
SHOULD_RUN="false"
175-
if [ "${{ matrix.platform }}" = "linux" ] || [ "${{ matrix.platform }}" = "alpine" ]; then
175+
if [ "${{ matrix.platform }}" = "linux" ] || [ "${{ matrix.platform }}" = "linux-musl" ]; then
176176
if [ "${{ inputs.build-linux }}" != "false" ]; then
177177
SHOULD_RUN="true"
178178
fi
@@ -345,10 +345,10 @@ jobs:
345345
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
346346
with:
347347
# Use 3.11 to match Alpine 3.19 (Docker builds) which ships Python 3.11.14.
348-
# Python 3.13 breaks gyp with: TypeError: Strings must be encoded before hashing
349-
# At: tools/gyp/pylib/gyp/generator/ninja.py:813 hashlib.md5(outputs[0])
348+
# Python 3.13 breaks gyp with: TypeError: Strings must be encoded before hashing.
349+
# At: tools/gyp/pylib/gyp/generator/ninja.py:813 hashlib.md5(outputs[0]).
350350
# Python 3.13 requires .encode() for hashlib, but gyp doesn't support it yet.
351-
# Using 3.11 ensures consistency across standard and Alpine builds.
351+
# Using 3.11 ensures consistency across standard and musl libc builds.
352352
python-version: '3.11'
353353

354354
- name: Cache Emscripten SDK (non-Windows)
@@ -465,7 +465,7 @@ jobs:
465465
id: sea-cache-key
466466
shell: bash
467467
run: |
468-
SEA_HASH=$(find packages/node-sea-builder packages/cli/src -type f \( -name "*.mts" -o -name "*.ts" -o -name "*.mjs" -o -name "*.js" \) | sort | xargs sha256sum | sha256sum | cut -d' ' -f1)
468+
SEA_HASH=$(find packages/cli/src packages/cli/scripts/build-sea.mjs -type f \( -name "*.mts" -o -name "*.ts" -o -name "*.mjs" -o -name "*.js" \) | sort | xargs sha256sum | sha256sum | cut -d' ' -f1)
469469
# Include bootstrap/socket/cli dependencies in cache key to invalidate when they change.
470470
COMBINED_HASH=$(echo "$SEA_HASH-${NEEDS_BUILD_DEPS_OUTPUTS_DEPS_HASH}" | sha256sum | cut -d' ' -f1)
471471
echo "hash=$COMBINED_HASH" >> $GITHUB_OUTPUT
@@ -477,7 +477,7 @@ jobs:
477477
id: sea-cache
478478
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
479479
with:
480-
path: packages/node-sea-builder/dist/sea/
480+
path: packages/cli/dist/sea/
481481
key: node-sea-${{ matrix.platform }}-${{ matrix.arch }}-${{ steps.sea-cache-key.outputs.hash }}
482482
restore-keys: node-sea-${{ matrix.platform }}-${{ matrix.arch }}-
483483

@@ -515,44 +515,74 @@ jobs:
515515

516516
- name: Build SEA binary
517517
if: steps.check-platform.outputs.should-run == 'true' && (steps.sea-cache.outputs.cache-hit != 'true' || inputs.force)
518-
run: pnpm --filter @socketbin/node-sea-builder run build -- --platform=${{ matrix.platform }} --arch=${{ matrix.arch }}
518+
run: pnpm --filter @socketsecurity/cli run build:sea -- --platform=${{ matrix.platform }} --arch=${{ matrix.arch }}
519519

520520
- name: Verify SEA binary
521521
if: steps.check-platform.outputs.should-run == 'true'
522522
shell: bash
523523
run: |
524524
echo "=== SEA Binary Build Artifacts ==="
525-
mkdir -p packages/node-sea-builder/dist/sea
526-
ls -lh packages/node-sea-builder/dist/sea/ || true
525+
mkdir -p packages/cli/dist/sea
526+
ls -lh packages/cli/dist/sea/ || true
527527
echo ""
528528
529-
# Determine binary name based on platform
529+
# Determine binary name based on platform (Node.js official naming).
530530
if [ "${{ matrix.platform }}" = "win32" ]; then
531531
BINARY_NAME="socket-win-${{ matrix.arch }}.exe"
532532
elif [ "${{ matrix.platform }}" = "darwin" ]; then
533-
BINARY_NAME="socket-macos-${{ matrix.arch }}"
533+
BINARY_NAME="socket-darwin-${{ matrix.arch }}"
534+
elif [ "${{ matrix.platform }}" = "linux-musl" ]; then
535+
BINARY_NAME="socket-linux-${{ matrix.arch }}-musl"
534536
else
535537
BINARY_NAME="socket-${{ matrix.platform }}-${{ matrix.arch }}"
536538
fi
537539
538-
BINARY_PATH="packages/node-sea-builder/dist/sea/$BINARY_NAME"
540+
BINARY_PATH="packages/cli/dist/sea/$BINARY_NAME"
539541
if [ -f "$BINARY_PATH" ]; then
540542
echo "$BINARY_NAME size: $(du -h $BINARY_PATH | cut -f1)"
541543
else
542544
echo "⚠️ Binary not found at expected path: $BINARY_PATH"
543545
echo "Contents of dist/sea:"
544-
ls -la packages/node-sea-builder/dist/sea/ || echo "Directory does not exist"
546+
ls -la packages/cli/dist/sea/ || echo "Directory does not exist"
545547
fi
546548
549+
- name: Copy binary to socketbin package
550+
if: steps.check-platform.outputs.should-run == 'true'
551+
shell: bash
552+
run: |
553+
# Determine binary name and target package (Node.js official naming).
554+
if [ "${{ matrix.platform }}" = "win32" ]; then
555+
BINARY_NAME="socket-win-${{ matrix.arch }}.exe"
556+
PACKAGE_NAME="socketbin-cli-win32-${{ matrix.arch }}"
557+
TARGET_NAME="socket.exe"
558+
elif [ "${{ matrix.platform }}" = "darwin" ]; then
559+
BINARY_NAME="socket-darwin-${{ matrix.arch }}"
560+
PACKAGE_NAME="socketbin-cli-darwin-${{ matrix.arch }}"
561+
TARGET_NAME="socket"
562+
elif [ "${{ matrix.platform }}" = "linux-musl" ]; then
563+
BINARY_NAME="socket-linux-${{ matrix.arch }}-musl"
564+
PACKAGE_NAME="socketbin-cli-linux-musl-${{ matrix.arch }}"
565+
TARGET_NAME="socket"
566+
else
567+
BINARY_NAME="socket-${{ matrix.platform }}-${{ matrix.arch }}"
568+
PACKAGE_NAME="socketbin-cli-${{ matrix.platform }}-${{ matrix.arch }}"
569+
TARGET_NAME="socket"
570+
fi
571+
572+
# Copy binary to package bin directory.
573+
mkdir -p "packages/$PACKAGE_NAME/bin"
574+
cp "packages/cli/dist/sea/$BINARY_NAME" "packages/$PACKAGE_NAME/bin/$TARGET_NAME"
575+
chmod +x "packages/$PACKAGE_NAME/bin/$TARGET_NAME"
576+
577+
echo "✓ Copied $BINARY_NAME to packages/$PACKAGE_NAME/bin/$TARGET_NAME"
578+
ls -lh "packages/$PACKAGE_NAME/bin/$TARGET_NAME"
579+
547580
- name: Upload SEA binary
548581
if: steps.check-platform.outputs.should-run == 'true'
549582
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
550583
with:
551584
name: socket-sea-${{ matrix.platform }}-${{ matrix.arch }}
552-
path: |
553-
packages/node-sea-builder/dist/sea/socket-win-${{ matrix.arch }}.exe
554-
packages/node-sea-builder/dist/sea/socket-macos-${{ matrix.arch }}
555-
packages/node-sea-builder/dist/sea/socket-${{ matrix.platform }}-${{ matrix.arch }}
585+
path: packages/cli/dist/sea/socket-*
556586
retention-days: 7
557587
if-no-files-found: warn
558588

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Shared esbuild configuration helpers.
3+
*/
4+
5+
/**
6+
* Banner code to inject import.meta.url polyfill for CommonJS bundles.
7+
*
8+
* Usage:
9+
* ```javascript
10+
* import { IMPORT_META_URL_BANNER } from 'build-infra/lib/esbuild-helpers'
11+
*
12+
* export default {
13+
* // ... other config
14+
* banner: IMPORT_META_URL_BANNER,
15+
* define: {
16+
* 'import.meta.url': '__importMetaUrl',
17+
* },
18+
* }
19+
* ```
20+
*
21+
* This injects a simple const statement at the top of the bundle that converts
22+
* __filename to a proper file:// URL using Node.js pathToFileURL().
23+
* Handles all edge cases (spaces, special chars, proper URL encoding, Windows paths).
24+
*/
25+
export const IMPORT_META_URL_BANNER = {
26+
js: 'const __importMetaUrl = require("node:url").pathToFileURL(__filename).href;',
27+
}

packages/build-infra/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"type": "module",
66
"private": true,
77
"exports": {
8+
"./lib/esbuild-helpers": "./lib/esbuild-helpers.mjs",
89
"./lib/esbuild-plugin-dead-code-elimination": "./lib/esbuild-plugin-dead-code-elimination.mjs",
910
"./lib/esbuild-plugin-unicode-transform": "./lib/esbuild-plugin-unicode-transform.mjs",
1011
"./lib/extraction-cache": "./lib/extraction-cache.mjs",

packages/cli-with-sentry/.config/esbuild-inject-import-meta.mjs

Lines changed: 0 additions & 10 deletions
This file was deleted.

packages/cli-with-sentry/.config/esbuild.inject.config.mjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { writeFileSync } from 'node:fs'
99
import path from 'node:path'
1010
import { fileURLToPath } from 'node:url'
1111

12+
import { IMPORT_META_URL_BANNER } from 'build-infra/lib/esbuild-helpers'
1213
import { build } from 'esbuild'
1314

1415
const __dirname = path.dirname(fileURLToPath(import.meta.url))
@@ -55,8 +56,8 @@ const config = {
5556
'import.meta.url': '__importMetaUrl',
5657
},
5758

58-
// Inject import.meta.url polyfill for CJS.
59-
inject: [path.join(__dirname, 'esbuild-inject-import-meta.mjs')],
59+
// Inject import.meta.url polyfill at top of bundle.
60+
banner: IMPORT_META_URL_BANNER,
6061
}
6162

6263
// Run build if invoked directly.

packages/cli/.config/esbuild-inject-import-meta.mjs

Lines changed: 0 additions & 10 deletions
This file was deleted.

packages/cli/.config/esbuild.cli.build.mjs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
88
import path from 'node:path'
99
import { fileURLToPath } from 'node:url'
1010

11+
import { IMPORT_META_URL_BANNER } from 'build-infra/lib/esbuild-helpers'
1112
import { unicodeTransformPlugin } from 'build-infra/lib/esbuild-plugin-unicode-transform'
1213
import { build } from 'esbuild'
1314

@@ -109,11 +110,6 @@ const config = {
109110
'.cs': 'empty',
110111
},
111112

112-
// Add shebang.
113-
banner: {
114-
js: '#!/usr/bin/env node\n"use strict";',
115-
},
116-
117113
// Source maps off for production.
118114
sourcemap: false,
119115

@@ -137,8 +133,10 @@ const config = {
137133
...createDefineEntries(inlinedEnvVars),
138134
},
139135

140-
// Inject import.meta.url polyfill for CJS.
141-
inject: [path.join(__dirname, 'esbuild-inject-import-meta.mjs')],
136+
// Add shebang and import.meta.url polyfill at top of bundle.
137+
banner: {
138+
js: `#!/usr/bin/env node\n"use strict";\n${IMPORT_META_URL_BANNER.js}`,
139+
},
142140

143141
// Handle special cases with plugins.
144142
plugins: [
@@ -351,7 +349,7 @@ const config = {
351349
// Redirect yoga-layout to our custom synchronous implementation.
352350
build.onResolve({ filter: /^yoga-layout$/ }, () => {
353351
return {
354-
path: path.join(rootPath, 'build/yoga-sync.mjs'),
352+
path: path.join(rootPath, 'build/yoga-sync.js'),
355353
}
356354
})
357355
},

packages/cli/.config/esbuild.inject.config.mjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { writeFileSync } from 'node:fs'
99
import path from 'node:path'
1010
import { fileURLToPath } from 'node:url'
1111

12+
import { IMPORT_META_URL_BANNER } from 'build-infra/lib/esbuild-helpers'
1213
import { build } from 'esbuild'
1314

1415
import {
@@ -67,8 +68,8 @@ const config = {
6768
...createDefineEntries(inlinedEnvVars),
6869
},
6970

70-
// Inject import.meta.url polyfill for CJS.
71-
inject: [path.join(__dirname, 'esbuild-inject-import-meta.mjs')],
71+
// Inject import.meta.url polyfill at top of bundle.
72+
banner: IMPORT_META_URL_BANNER,
7273

7374
// Handle special cases with plugins.
7475
plugins: [envVarReplacementPlugin(inlinedEnvVars)],

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"build:force": "node --max-old-space-size=8192 --import=./scripts/load.mjs scripts/build.mjs --force",
2525
"build:watch": "node --max-old-space-size=8192 --import=./scripts/load.mjs scripts/build.mjs --watch",
2626
"restore-cache": "node --import=./scripts/load.mjs scripts/restore-cache.mjs",
27+
"build:sea": "node --max-old-space-size=8192 --import=./scripts/load.mjs scripts/build-sea.mjs",
2728
"build:sea:internal:bootstrap": "node --max-old-space-size=8192 .config/esbuild.sea-bootstrap.build.mjs",
2829
"build:js": "node scripts/build-js.mjs",
2930
"dev:watch": "pnpm run build:watch",

0 commit comments

Comments
 (0)