npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

create-lynx-library-canary

v0.6.1

Published

Create native Lynx libraries

Readme

create-lynx-library

Create native Lynx libraries.

npm create lynx-library

The interactive flow lets you choose one or more library features:

  • Native Module: platform implementations on Android, iOS, and HarmonyOS; a shared Node-API adapter registered as a native module on Lynxtron.
  • NAPI Native Module: one shared C++ Node-API implementation for Android, iOS, HarmonyOS, and Lynxtron.
  • Element: Android, iOS, HarmonyOS, and shared C++ scaffolds.
  • Service

It also lets you choose one or more Native platforms:

  • Android
  • iOS
  • HarmonyOS
  • Lynxtron

For non-interactive usage:

npm create lynx-library -- \
  --dir ./lynx-button \
  --features native-module,napi-native-module,element,service \
  --platforms android,ios,harmony,lynxtron \
  --package-name @example/lynx-button \
  --android-package com.example.button \
  --module-name ButtonModule \
  --element-name x-button \
  --service-name ButtonService

Use --features all to generate a package that contains all supported library features. Use --platforms all to generate native directories for all supported Native platforms. When --platforms is omitted in non-interactive usage, Android, iOS, HarmonyOS, and Lynxtron are generated.

Generated libraries include lynx.lib.json, JS facade sources, selected Native platform examples, an example app skeleton, and a codegen script powered by the current published version of @lynx-js/autolink-codegen.

Native Module declarations live in types/platform-native-module.d.ts. NAPI Native Module declarations live in types/napi-native-module.d.ts.

When both features are selected, the platform module keeps --module-name and the NAPI module adds the Napi suffix. For example, --module-name StorageModule exposes NativeModules.StorageModule and NativeModules.StorageModuleNapi. On Lynxtron both implementations reuse the shared Node-API source shape, but remain separate modules with separate registration paths.

NAPI Native Module workflow

Select the shared implementation with:

create-lynx-library lynx-storage \
  --features napi-native-module \
  --platforms android,ios,harmony,lynxtron

The generated package depends on @lynx-js/weak-node-api and @lynx-js/lynx-library-headers. Shared business sources use the standard Node-API headers from @lynx-js/weak-node-api:

  • Android and iOS use unsuffixed napi_* symbols.
  • HarmonyOS and Lynxtron enable weak suffix remapping.
  • Android, iOS, and HarmonyOS register through napi_module_register.
  • Lynxtron NAPI modules also register through napi_module_register.
  • A Lynxtron adapter generated for the separate native-module feature uses lynx_env_register_native_module.

Edit types/napi-native-module.d.ts to describe the JavaScript API:

/** @lynxmodule */
export declare class StorageModule {
  setValue(key: string, value: string): void;
  getValue(key: string): string | null;
}

Then run:

npm run codegen

The generated files have the following responsibilities:

  • generated/<Module>.ts is the BTS TypeScript facade. It lazily loads the addon through globalThis.getNapiLoader(), globalThis.__lynxNapiLoader, or lynx.getModuleLoader(). For a NAPI Native Module, importing the package installs a JavaScript NativeModules.<Module> shim and forwards all unrelated module names to the original native HostObject. Do not edit it directly; update the declaration file and rerun codegen instead.
  • shared/nativeModule/<Module>.cc is the user-owned shared C++ implementation. Codegen creates it once and preserves it on later runs. Fill in the generated N-API callback method bodies, including argument parsing, validation, return value creation, and error handling. After changing the typings, manually keep this file's callbacks and exports in sync because codegen will not overwrite it.
  • shared/nativeModule/generated/<Module>Registration.cc is overwritten by codegen and owns Android, iOS, and HarmonyOS registration boilerplate. Do not move registration macros into the user-owned implementation.
  • shared/nativeModule/CMakeLists.txt builds the shared N-API sources as an object target that Android, HarmonyOS, and Lynxtron reuse. iOS compiles the same implementation through its generated CocoaPods wrapper.
  • ios/generated/<Module>NapiWrapper.cc is an iOS CocoaPods compile entry that is generated when iOS is selected and includes the shared implementation from inside the iOS pod source root. Do not put business logic in this wrapper; keep it in shared/nativeModule/<Module>.cc.
  • ios/addon_use.h exposes NAPI_USE(<Module>) so the generated iOS autolink registry can keep the Node-API registration symbol from being stripped by the linker.
  • lynxtron/generated_napi_registration.cc is generated when Lynxtron is selected and invokes the generated standard Node-API registration function when the .node binding is required.
  • lynxtron/generated_platform_registration.cc is generated for a platform Native Module on Lynxtron and registers its shared adapter through lynx_env_register_native_module.
  • harmony/src/main/cpp/harmony_entry.cc is the system OHOS N-API entry exposed to ArkTS. It only loads the HAR native library; shared business sources remain on weak Node-API symbols.

If the module class is renamed, also rename or remove the old user-owned shared C++ file and update the addon name in lynx.lib.json. Codegen does not delete stale C++ files or rewrite the manifest.

For Android, the generated library project can build the addon from source via its externalNativeBuild configuration. The project resolves org.lynxsdk.lynx:primjs with the Gradle property lynx.primjs.version, defaulting to 4.+, extracts its native libraries, and links the addon against libnapi_adapter.so and libnapi.so. libnapi_adapter.so contains the non-suffixed weak-node-api implementation and injects a PrimJS-backed host table, so shared source continues to call the standard Node-API functions. Host apps that need a pinned PrimJS runtime should set lynx.primjs.version from the root build so the addon and host resolve the same AAR. The default manifest omits jniLibsDir, which tells Android AutoLink that the generated Android library project builds the addon. Packages that distribute prebuilt artifacts instead can set jniLibsDir explicitly; AutoLink then copies lib<Module>.so from each ABI subdirectory.

For iOS, the generated podspec compiles the generated wrapper and uses ios/addon_use.h for the registration-symbol reference. The iOS autolink step adds the addon pod and a generated registry pod automatically. The addon compiles against the standard headers and implementation from LynxWeakNodeAPI/core; the generated registry owns the one-time PrimJS bridge initialization before it uses any addon registration. The podspec file is generated as ios/<pod-name>.podspec, matching its CocoaPods s.name.

For HarmonyOS, the package contains a source HAR, links the shared weak Node-API implementation, and exports an idempotent initializer. Harmony AutoLink imports and calls that initializer during AppStartup before registering any optional platform provider from the same package.

Import the package root in BTS on every selected platform, then use one call shape:

import '@example/storage-library';

NativeModules.StorageModule.getValue('key');

When the lynxtron platform is selected for a Native Module, NAPI Native Module, or Element project, generated libraries also include shared C++ sources under shared/, a Lynxtron loader under lynxtron/, and a build:lynxtron script. The script writes the current OS/architecture .node artifact to dist/<platform>/<arch>/. The shared CMake entry lives at shared/CMakeLists.txt; generated packages do not create a top-level CMakeLists.txt. The generated ./lynxtron entry loads the dynamic library and runs the registration entry for each selected feature.

Build dist/<platform>/<arch>/ on every Lynxtron OS/architecture that the npm package supports before publishing. npm pack and npm publish do not compile native artifacts. Install the published package as a normal application dependency. A Lynxtron host configured with pluginLynxtron() discovers its manifest, stages the matching target, and loads ./lynxtron automatically. Application code does not import that subpath, copy native artifacts, or add per-library packaging rules.

Lynxtron BTS imports the package root like the other platforms and calls the registered runtime module directly:

import '@example/storage-library';

NativeModules.StorageModule.getValue('key');

Run npm pack --dry-run before publishing. Generated packages exclude the local shared/third_party/ CMake header cache, but authors should still verify that dist/ contains every intended Lynxtron artifact and that no other local build outputs are included.