Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
73e85c0
perf(ios): add v8 native api dispatch fast path
DjDeveloperr May 21, 2026
49c9a76
perf(ios): broaden v8 direct dispatch fast path
DjDeveloperr May 21, 2026
e4c133e
perf(ios): tighten generated v8 dispatch
DjDeveloperr May 21, 2026
db605a7
perf(ios): restore generated dispatch baseline
DjDeveloperr May 21, 2026
1aa111d
perf(ios): add engine native dispatch fast paths
DjDeveloperr May 21, 2026
a173af5
perf(ios): add direct gsd backends for engines
DjDeveloperr May 21, 2026
2547d38
perf: add engine-direct native dispatch paths
DjDeveloperr May 21, 2026
3364db5
perf: reduce direct native dispatch overhead
DjDeveloperr May 21, 2026
5bec5ba
perf: tighten engine direct native dispatch
DjDeveloperr May 22, 2026
5e5833b
perf: optimize hermes generated dispatch
DjDeveloperr May 22, 2026
8213dc4
feat: add Hermes JSI native API bridge
DjDeveloperr May 23, 2026
54fd83e
fix(ios-hermes): dispatch RN native calls on main thread
DjDeveloperr May 23, 2026
3f64df8
fix(ios-hermes): install RN globals and preserve unichar returns
DjDeveloperr May 23, 2026
cc0cafd
feat(react-native): simplify NativeScript package API
DjDeveloperr May 23, 2026
ea9ddbc
feat(react-native): expose native constants and enums
DjDeveloperr May 23, 2026
bc1629a
feat(ffi): expand Hermes JSI interop coverage
DjDeveloperr May 23, 2026
b608d7c
test(ffi): add React Native JSI compatibility suite
DjDeveloperr May 23, 2026
c4ef2a7
feat(react-native): support JS-defined UIKit views
DjDeveloperr May 23, 2026
6e3d7b7
fix(runtime): harden console formatting
DjDeveloperr May 23, 2026
abc20cb
feat(react-native): add Expo config plugin
DjDeveloperr May 23, 2026
de6be51
ci(npm): support react-native trusted publishing
DjDeveloperr May 23, 2026
be1abb2
fix(hermes): stabilize native callback dispatch
DjDeveloperr May 24, 2026
387abce
fix: address CodeRabbit review comments
DjDeveloperr May 24, 2026
df472eb
fix: address follow-up CodeRabbit comments
DjDeveloperr May 24, 2026
bbe4745
refactor: organize ffi backend layers
DjDeveloperr May 24, 2026
d0c1176
fix(quickjs): decode unichar string arguments
DjDeveloperr May 24, 2026
ec99893
refactor(ffi): split direct engine backends
DjDeveloperr May 24, 2026
48707a0
test(react-native): reuse ffi compatibility suite
DjDeveloperr May 24, 2026
096e03a
fix(ffi): address direct engine review findings
DjDeveloperr May 24, 2026
55a1f20
refactor(ffi): isolate direct engine backends
DjDeveloperr May 25, 2026
9a4df3d
refactor(ffi): clean direct Hermes backend
DjDeveloperr May 25, 2026
de05a4c
perf(ffi): add direct engine backend entrypoints
DjDeveloperr May 25, 2026
37ceca8
refactor(ffi): split direct engine backends
DjDeveloperr May 25, 2026
4e9355f
ci: allow exact trusted npm preview versions
DjDeveloperr May 25, 2026
bc6267a
fix(ci): stabilize direct ffi test runs
DjDeveloperr May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
- name: Install Dependencies
run: npm install

- name: Check FFI backend boundaries
run: npm run check:ffi-boundaries

- name: Download V8
run: ./scripts/download_v8.sh

Expand Down Expand Up @@ -49,4 +52,6 @@ jobs:
IOS_BUILD_TIMEOUT_MS: "600000"
IOS_TEST_TIMEOUT_MS: "600000"
IOS_TEST_INACTIVITY_TIMEOUT_MS: "180000"
IOS_TEST_VERBOSE_SPECS: "1"
IOS_SIMCTL_QUERY_TIMEOUT_MS: "10000"
run: npm run test:ios
190 changes: 137 additions & 53 deletions .github/workflows/npm_trusted_release.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
name: NPM Trusted Release (iOS engines)
name: NPM Trusted Release

# Publishes one or more engine-specific NativeScript iOS runtime packages
# Publishes one or more NativeScript iOS npm packages
# (@nativescript/ios-v8, @nativescript/ios-hermes, @nativescript/ios-jsc,
# @nativescript/ios-quickjs) via npm trusted publishing (OIDC).
# @nativescript/ios-quickjs, @nativescript/react-native) via npm trusted
# publishing (OIDC).
#
# Each package must be configured on npmjs.com with a trusted publisher that
# points at this repository + workflow + environment. With `engine: all`, the
# workflow fans out across all four engines via a matrix.
# workflow fans out across the four iOS engine packages via a matrix; use
# `engine: react-native` to publish @nativescript/react-native.

on:
workflow_dispatch:
inputs:
engine:
description: "Engine to release (or 'all' to publish every engine)"
description: "Package to release (engine package, react-native, or 'all' for every iOS engine)"
required: true
type: choice
default: v8
Expand All @@ -21,6 +23,7 @@ on:
- hermes
- jsc
- quickjs
- react-native
- all
release-type:
description: "Version bump (patch/minor/major publish to 'latest'; prerelease uses 'preid' as the dist-tag)"
Expand All @@ -32,6 +35,10 @@ on:
- patch
- minor
- major
version:
description: "Exact npm version to publish; overrides release-type/preid. Use a prerelease version for preview publishes, e.g. 9.0.0-preview.0"
required: false
type: string
preid:
description: "Prerelease identifier (used only when release-type=prerelease; also becomes the npm dist-tag, e.g. next | canary)"
required: false
Expand All @@ -44,7 +51,7 @@ on:
default: true

concurrency:
# Avoid overlapping publishes on the same ref/engine selection.
# Avoid overlapping publishes on the same ref/package selection.
group: npm-trusted-release-${{ github.ref }}-${{ inputs.engine }}
cancel-in-progress: false

Expand All @@ -53,34 +60,45 @@ env:

jobs:
matrix:
name: Resolve engine matrix
name: Resolve package matrix
runs-on: ubuntu-latest
permissions: {}
outputs:
engines: ${{ steps.compute.outputs.engines }}
targets: ${{ steps.compute.outputs.targets }}
steps:
- name: Compute matrix
id: compute
env:
ENGINE: ${{ inputs.engine }}
run: |
if [ "${{ inputs.engine }}" = "all" ]; then
echo 'engines=["v8","hermes","jsc","quickjs"]' >> "$GITHUB_OUTPUT"
else
echo "engines=[\"${{ inputs.engine }}\"]" >> "$GITHUB_OUTPUT"
fi
set -euo pipefail
case "$ENGINE" in
all)
echo 'targets=["v8","hermes","jsc","quickjs"]' >> "$GITHUB_OUTPUT"
;;
v8|hermes|jsc|quickjs|react-native)
printf 'targets=["%s"]\n' "$ENGINE" >> "$GITHUB_OUTPUT"
;;
*)
echo "Unsupported engine: $ENGINE" >&2
exit 1
;;
esac

build:
name: Build ${{ matrix.engine }}
name: Build ${{ matrix.target }}
needs: matrix
runs-on: macos-26
permissions:
contents: read
strategy:
fail-fast: false
matrix:
engine: ${{ fromJson(needs.matrix.outputs.engines) }}
target: ${{ fromJson(needs.matrix.outputs.targets) }}
outputs:
# Per-engine outputs aren't natively supported with matrices, so each job
# Per-target outputs aren't natively supported with matrices, so each job
# uploads its computed metadata alongside the tarball artifact.
placeholder: noop
Comment thread
coderabbitai[bot] marked this conversation as resolved.
env:
IOS_VARIANT: ios-${{ matrix.engine }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
Expand Down Expand Up @@ -118,55 +136,102 @@ jobs:
- name: Bump version
id: bump
shell: bash
env:
RELEASE_TYPE: ${{ inputs.release-type }}
PACKAGE_VERSION: ${{ inputs.version }}
PREID: ${{ inputs.preid }}
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
release_type='${{ inputs.release-type }}'
preid='${{ inputs.preid }}'
pkg_dir="packages/${IOS_VARIANT}"
release_type="$RELEASE_TYPE"
package_version="$PACKAGE_VERSION"
preid="$PREID"
target="$TARGET"
if [ "$target" = "react-native" ]; then
pkg_dir="packages/react-native"
package_name="@nativescript/react-native"
tarball_basename="nativescript-react-native"
npm_tag_target="react-native"
else
pkg_dir="packages/ios-${target}"
package_name="@nativescript/ios-${target}"
tarball_basename="nativescript-ios-${target}"
npm_tag_target="ios-${target}"
echo "IOS_VARIANT=ios-${target}" >> "$GITHUB_ENV"
fi

pushd "$pkg_dir" >/dev/null
if [ "$release_type" = "prerelease" ]; then
if [ -n "$package_version" ]; then
npm version "$package_version" --no-git-tag-version >/dev/null
elif [ "$release_type" = "prerelease" ]; then
npm version prerelease --preid "$preid" --no-git-tag-version >/dev/null
else
npm version "$release_type" --no-git-tag-version >/dev/null
fi
NPM_VERSION=$(node -e "console.log(require('./package.json').version)")
popd >/dev/null

NPM_TAG=$(NPM_VERSION="$NPM_VERSION" node ./scripts/get-npm-tag.js "$IOS_VARIANT")
NPM_TAG=$(NPM_VERSION="$NPM_VERSION" node ./scripts/get-npm-tag.js "$npm_tag_target")
if [ -n "$package_version" ] && [ "$release_type" = "prerelease" ] && [ "$NPM_TAG" = "latest" ]; then
echo "Exact prerelease publishes must include a prerelease identifier (for example 9.0.0-preview.0)." >&2
exit 1
fi
echo "NPM_VERSION=$NPM_VERSION" >> "$GITHUB_OUTPUT"
echo "NPM_TAG=$NPM_TAG" >> "$GITHUB_OUTPUT"
echo "Resolved $IOS_VARIANT@$NPM_VERSION (tag: $NPM_TAG)"
- name: Build (--${{ matrix.engine }})
run: ./scripts/build_all_ios.sh --${{ matrix.engine }}
echo "PACKAGE_DIR=$pkg_dir" >> "$GITHUB_OUTPUT"
echo "PACKAGE_NAME=$package_name" >> "$GITHUB_OUTPUT"
echo "TARBALL_BASENAME=$tarball_basename" >> "$GITHUB_OUTPUT"
echo "Resolved $package_name@$NPM_VERSION (tag: $NPM_TAG)"
- name: Build iOS engine (--${{ matrix.target }})
if: ${{ matrix.target != 'react-native' }}
env:
TARGET: ${{ matrix.target }}
run: ./scripts/build_all_ios.sh "--${TARGET}"
- name: Build @nativescript/react-native
if: ${{ matrix.target == 'react-native' }}
run: |
./scripts/build_all_react_native.sh
./scripts/build_react_native_turbomodule.sh
- name: Record metadata
shell: bash
env:
TARGET: ${{ matrix.target }}
PACKAGE_DIR: ${{ steps.bump.outputs.PACKAGE_DIR }}
PACKAGE_NAME: ${{ steps.bump.outputs.PACKAGE_NAME }}
NPM_VERSION: ${{ steps.bump.outputs.NPM_VERSION }}
NPM_TAG: ${{ steps.bump.outputs.NPM_TAG }}
TARBALL_BASENAME: ${{ steps.bump.outputs.TARBALL_BASENAME }}
run: |
mkdir -p packages/${IOS_VARIANT}/dist
cat > packages/${IOS_VARIANT}/dist/release-meta.json <<EOF
set -euo pipefail
package_dir="$PACKAGE_DIR"
tarball_file="${TARBALL_BASENAME}-${NPM_VERSION}.tgz"
mkdir -p "$package_dir/dist"
cat > "$package_dir/dist/release-meta.json" <<EOF
{
"engine": "${{ matrix.engine }}",
"variant": "${IOS_VARIANT}",
"package_name": "@nativescript/ios-${{ matrix.engine }}",
"version": "${{ steps.bump.outputs.NPM_VERSION }}",
"tag": "${{ steps.bump.outputs.NPM_TAG }}"
"target": "$TARGET",
"package_dir": "$package_dir",
"package_name": "$PACKAGE_NAME",
"version": "$NPM_VERSION",
"tag": "$NPM_TAG",
"tarball": "$tarball_file"
}
EOF
- name: Upload npm package artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: npm-package-${{ matrix.engine }}
name: npm-package-${{ matrix.target }}
path: |
packages/ios-${{ matrix.engine }}/dist/nativescript-ios-${{ matrix.engine }}-${{ steps.bump.outputs.NPM_VERSION }}.tgz
packages/ios-${{ matrix.engine }}/dist/release-meta.json
${{ steps.bump.outputs.PACKAGE_DIR }}/dist/${{ steps.bump.outputs.TARBALL_BASENAME }}-${{ steps.bump.outputs.NPM_VERSION }}.tgz
${{ steps.bump.outputs.PACKAGE_DIR }}/dist/release-meta.json
- name: Upload dSYMs artifact
if: ${{ matrix.target != 'react-native' }}
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: NativeScript-dSYMs-${{ matrix.engine }}
name: NativeScript-dSYMs-${{ matrix.target }}
path: dist/dSYMs

publish:
name: Publish ${{ matrix.engine }}
name: Publish ${{ matrix.target }}
needs:
- matrix
- build
Expand All @@ -176,7 +241,7 @@ jobs:
strategy:
fail-fast: false
matrix:
engine: ${{ fromJson(needs.matrix.outputs.engines) }}
target: ${{ fromJson(needs.matrix.outputs.targets) }}
permissions:
contents: read
id-token: write
Expand All @@ -191,8 +256,8 @@ jobs:
registry-url: "https://registry.npmjs.org"
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: npm-package-${{ matrix.engine }}
path: packages/ios-${{ matrix.engine }}/dist
name: npm-package-${{ matrix.target }}
path: npm-package/${{ matrix.target }}
- name: Update npm (required for OIDC trusted publishing)
run: |
corepack enable npm
Expand All @@ -202,32 +267,38 @@ jobs:
- name: Read release metadata
id: meta
shell: bash
env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
meta="packages/ios-${{ matrix.engine }}/dist/release-meta.json"
meta="npm-package/${TARGET}/release-meta.json"
if [ ! -f "$meta" ]; then
echo "Missing release metadata at $meta" >&2
exit 1
fi
NPM_VERSION=$(node -e "console.log(require('./$meta').version)")
NPM_TAG=$(node -e "console.log(require('./$meta').tag)")
PACKAGE_NAME=$(node -e "console.log(require('./$meta').package_name)")
TARBALL=$(node -e "console.log(require('./$meta').tarball)")
echo "NPM_VERSION=$NPM_VERSION" >> "$GITHUB_OUTPUT"
echo "NPM_TAG=$NPM_TAG" >> "$GITHUB_OUTPUT"
echo "PACKAGE_NAME=$PACKAGE_NAME" >> "$GITHUB_OUTPUT"
echo "TARBALL=$TARBALL" >> "$GITHUB_OUTPUT"
- name: Publish package (OIDC trusted publishing)
if: ${{ vars.USE_NPM_TOKEN != 'true' }}
shell: bash
env:
NPM_VERSION: ${{ steps.meta.outputs.NPM_VERSION }}
NPM_TAG: ${{ steps.meta.outputs.NPM_TAG }}
PACKAGE_NAME: ${{ steps.meta.outputs.PACKAGE_NAME }}
TARBALL: ${{ steps.meta.outputs.TARBALL }}
TARGET: ${{ matrix.target }}
DRY_RUN: ${{ inputs.dry-run }}
NODE_AUTH_TOKEN: ""
run: |
set -euo pipefail
TARBALL="packages/ios-${{ matrix.engine }}/dist/nativescript-ios-${{ matrix.engine }}-${NPM_VERSION}.tgz"
PUBLISH_ARGS=("$TARBALL" --tag "$NPM_TAG" --access public --provenance)
TARBALL_PATH="npm-package/${TARGET}/${TARBALL}"
PUBLISH_ARGS=("$TARBALL_PATH" --tag "$NPM_TAG" --access public --provenance)
if [ "$DRY_RUN" = "true" ]; then
PUBLISH_ARGS+=(--dry-run)
fi
Expand All @@ -245,12 +316,14 @@ jobs:
NPM_VERSION: ${{ steps.meta.outputs.NPM_VERSION }}
NPM_TAG: ${{ steps.meta.outputs.NPM_TAG }}
PACKAGE_NAME: ${{ steps.meta.outputs.PACKAGE_NAME }}
TARBALL: ${{ steps.meta.outputs.TARBALL }}
TARGET: ${{ matrix.target }}
DRY_RUN: ${{ inputs.dry-run }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
run: |
set -euo pipefail
TARBALL="packages/ios-${{ matrix.engine }}/dist/nativescript-ios-${{ matrix.engine }}-${NPM_VERSION}.tgz"
PUBLISH_ARGS=("$TARBALL" --tag "$NPM_TAG" --access public --provenance)
TARBALL_PATH="npm-package/${TARGET}/${TARBALL}"
PUBLISH_ARGS=("$TARBALL_PATH" --tag "$NPM_TAG" --access public --provenance)
if [ "$DRY_RUN" = "true" ]; then
PUBLISH_ARGS+=(--dry-run)
fi
Expand All @@ -265,13 +338,24 @@ jobs:
- build
- publish
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Print summary
env:
PACKAGE_SELECTION: ${{ inputs.engine }}
RELEASE_TYPE: ${{ inputs.release-type }}
PACKAGE_VERSION: ${{ inputs.version }}
PREID: ${{ inputs.preid }}
DRY_RUN: ${{ inputs.dry-run }}
TARGETS: ${{ needs.matrix.outputs.targets }}
BUILD_RESULT: ${{ needs.build.result }}
PUBLISH_RESULT: ${{ needs.publish.result }}
run: |
echo "Engine selection: ${{ inputs.engine }}"
echo "Release type: ${{ inputs.release-type }}"
echo "Preid: ${{ inputs.preid }}"
echo "Dry run: ${{ inputs.dry-run }}"
echo "Engines: ${{ needs.matrix.outputs.engines }}"
echo "Build result: ${{ needs.build.result }}"
echo "Publish result: ${{ needs.publish.result }}"
echo "Package selection: $PACKAGE_SELECTION"
echo "Release type: $RELEASE_TYPE"
echo "Exact version: $PACKAGE_VERSION"
echo "Preid: $PREID"
echo "Dry run: $DRY_RUN"
echo "Targets: $TARGETS"
echo "Build result: $BUILD_RESULT"
echo "Publish result: $PUBLISH_RESULT"
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,11 @@ packages/*/types
SwiftBindgen

# Generated Objective-C/C dispatch wrappers
NativeScript/ffi/GeneratedSignatureDispatch.inc
NativeScript/ffi/napi/GeneratedSignatureDispatch.inc
NativeScript/ffi/napi/GeneratedSignatureDispatch.inc.stamp

# React Native TurboModule package staging
packages/react-native/dist/
packages/react-native/ios/vendor/
packages/react-native/metadata/
packages/react-native/native-api-jsi/
Loading
Loading