Skip to content

Managing Modules

s edited this page Sep 30, 2026 · 16 revisions

Managing Modules

In 0.1.3, you own the authored packages and the package-manager/build workflow. The generator owns disposable output. Each module can contain C/C++ and JVM source; all local modules are regenerated and validated together.

Know which files are yours

An authored package normally contains:

local_modules/document/
├── .supernote-module.json          authored identity metadata, scaffolded once
├── package.json                   author-owned package metadata
├── CMakeLists.txt                 author-owned native compilation choices
├── android/src/main/cpp/          authored C/C++
├── android/src/main/java/         authored Kotlin/Java
└── .supernote-generated/          disposable generated output
    ├── index.js
    ├── index.d.ts
    ├── README.md
    ├── package-manifest.json
    └── android/                  native/JVM adapters and package CMake

Only selected source families need to exist initially. Scoped packages retain their scope directory, for example local_modules/@acme/document/. Update does not rewrite authored metadata, package.json, lockfiles or author CMake. It also preserves intentionally modified or deleted starter source.

The author's shared generated analysis/runtime tree still lives at android/.supernote-module/runtime/. Do not confuse it with the module's package-local .supernote-generated/ payload or the consumer's installed @supernote/runtime package. The consumer uses packaged inputs, not the publisher's shared working tree.

A safe Update workflow

Save or commit your own work before a large edit, then inspect the changes:

git status --short
git diff
sn-module-gen update --yes
sn-module-gen validate --verbose

Update always discovers every local module, runs bounded compiler/KSP analysis when needed, and rewrites generated files. It does not offer a selective or no-op/preview mode. Manual edits beneath generated ownership are overwritten. Inspect each package's .supernote-generated/index.d.ts after an API change.

Validation is project-wide and read-only over authored and generated inputs. Its bounded compiler/KSP scratch is separate. It does not run an app build. Run your app's build, package checks and target-device tests yourself.

Add another environment later

An existing native module may gain Kotlin or Java below its JVM source root; a JVM module may gain ordinary C/C++ source. There is no conversion command or backend switch. Mark the intended declarations and run plain Update/Validate.

For C/C++, update your author CMakeLists.txt to select new implementation files. Recursive export discovery is not recursive compilation: vendor, test and alternate-backend files compile only when author CMake selects them. The generated target is supplied as SUPERNOTE_MODULE_TARGET; use normal target_sources, add_subdirectory and target_link_libraries calls.

See Using Both Environments for generated C++-to-JVM routes.

Package installation belongs to the author

Add scaffolds a new module and prints an install command. It does not change the parent package.json, lockfiles or installed dependencies. Update never runs a package manager. Choose npm or Yarn and maintain those files yourself.

For distribution, generate first, then use ordinary packaging:

sn-module-gen update --yes
npm pack ./local_modules/document

The package includes .supernote-generated/package-manifest.json, hashes of authored and generated consumer inputs, native registration/CMake, TypeScript, and publisher-generated JVM adapters where applicable. Do not patch files in a packed or installed package: regenerate and repack at the publisher instead.

Consume copied module packages

The consumer declares each module and exactly one compatible @supernote/runtime in its direct dependencies. For example, with both matching tarballs already available in the consumer root:

npm install ./document-0.1.0.tgz ./supernote-runtime-0.1.0.tgz

Or use your Yarn version's ordinary tarball installation. npm, Yarn classic and modern Yarn with nodeLinker: node-modules are supported. Yarn Plug'n'Play and external linked author-source directories are unsupported. Use copied module packages; supported linking of the shared runtime is not permission to link external authored modules.

Use a runtime package matching the release's protocol/native ABI. Its maintained source is npm/supernote-runtime/ in the generator repository; it can be packed with ordinary npm pack. This page does not assume the runtime has been published to a public registry.

Consumers do not run sn-module-gen or KSP. React Native autolinks the runtime; its build adapter validates declared direct packages and composes their existing bindings in the consumer build tree. Installed package contents stay read-only. Undeclared leftovers, transitive-only and dev-only modules are not activated.

The current metadata schema and module/runtime protocol are exactly 2.0; the native ABI is supernote-jsi-v1. Compatibility, containment, registration and payload hashes are checked before use. See the package contract for the complete author/consumer boundary.

Remove a module

Removal is manual: preserve any source you need, delete the intended authored module directory, and remove its dependency using npm or Yarn. Then run:

sn-module-gen update --yes
sn-module-gen validate

Update rebuilds the complete current feature set, including an empty set, and removes obsolete output only within verified generated ownership. There is no generator removal command, removal transaction or build-directory cleanup. Do not use a broad clean/reset to remove one module.

Feature versions and plugin versions

A module's package.json version is independent of the complete plugin version. Add's --package-version initializes only that module. The generator does not bump package or PluginConfig.json versions for you.

When shipping a changed plugin, follow the plugin template's versioning and packaging rules and inspect the actual JavaScript/native payload. A successful generator run or a new .snplg filename is not proof of installed native code.

Interrupted generation

Update does not restore the previous generated tree. An interrupted or partial write is detected by completion/integrity checks. Fix the immediate cause, keep authored files intact, and rerun plain Update before Validate or packaging.

Add has separate authored-scaffold activation safeguards. If it reports an incomplete activation or staging path, inspect that exact path and follow the reported instructions. Do not blindly delete a folder containing source or assume that another command rolls it back.

Exit code 3 means partial generated output needs attention, not that a legacy transaction journal will recover the previous project automatically. There is no public generator recovery command. Template/device recovery is separate and can be destructive; see Troubleshooting.

Earlier layouts and custom integration

Do not reuse an obsolete generated tree or expect a migration/compatibility alias for pre-public layouts. Keep reviewed author source and deliberately recreate the supported package structure if necessary.

Keep custom library dependencies and build selection in authored CMake/source. Do not store durable logic in generated bindings or edit installed runtime payloads. Shared-library linking does not automatically copy or package arbitrary runtime libraries for Android; verify that separate app/device path explicitly.

Clone this wiki locally