brustjs 0.1.41-alpha → 0.1.43-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Brust
4
4
 
5
- ### **B**un + **Rust** an SSR framework that brusts.
5
+ ### The unified framework for the web.
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/brustjs/alpha?logo=npm&logoColor=white&label=brustjs&color=cb3837)](https://www.npmjs.com/package/brustjs)
8
8
  [![CI](https://github.com/AssetsArt/brust/actions/workflows/ci.yml/badge.svg)](https://github.com/AssetsArt/brust/actions/workflows/ci.yml)
@@ -11,23 +11,23 @@
11
11
  [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.4-fbf0df?logo=bun&logoColor=black)](https://bun.sh)
12
12
  [![React](https://img.shields.io/badge/React-19-149eca?logo=react&logoColor=white)](https://react.dev)
13
13
 
14
+ **[brust.assetsart.com](https://brust.assetsart.com/)** — docs, guides, and a live demo of everything below.
15
+
14
16
  </div>
15
17
 
16
- React on the server, Rust everywhere else. One Bun host process; the HTTP server
17
- (hyper 1.x, HTTP/1.1 + HTTP/2) and worker pool are pure Rust, loaded as a `.node`
18
- native module (napi-rs). Renders cross into Bun Worker threads via
19
- `ThreadsafeFunction` (request as inline JSON) and return over a per-worker
20
- `SharedArrayBuffer`. One worker can hold several renders in-flight
21
- (`renderSlots`), overlapping I/O-bound (Suspense) renders. Multi-thread tokio
22
- runtime — runs the same everywhere (no io_uring / seccomp caveat).
18
+ Brust serves compiled pages with **zero JavaScript by default** and gives
19
+ server templates, React islands, and native interactions **one shared store**
20
+ the moment you add interactivity. Like unified memory: a single state substrate
21
+ every kind of component addresses directly. No bridges, no event buses, no
22
+ syncing two worlds. The [home page demo](https://brust.assetsart.com/) is real —
23
+ a hydrated React island and a zero-React native component move together through
24
+ the same store.
23
25
 
24
26
  > Published on npm as [`brustjs`](https://www.npmjs.com/package/brustjs) (the
25
27
  > `brust` name is taken). Alpha — see **Status**.
26
28
 
27
29
  ## Quick start
28
30
 
29
- **Scaffold a new project** (prebuilt native binary per platform — no Rust toolchain):
30
-
31
31
  ```bash
32
32
  bun create brustjs my-app
33
33
  cd my-app
@@ -52,83 +52,76 @@ bun add brustjs
52
52
  > version. Pin the prerelease channel explicitly with `@alpha`
53
53
  > (`bun add brustjs@alpha`) if you want to stay on alpha once a stable ships.
54
54
 
55
- **Or run from source:**
55
+ Full walkthrough: [Getting started](https://brust.assetsart.com/docs/introduction).
56
56
 
57
- ```bash
58
- git clone https://github.com/AssetsArt/brust && cd brust
59
- bun install
60
- cd runtime && bun run build && cd .. # release addon; NOT build:debug (~2× slower)
61
- bun run runtime/cli/index.ts build example/pokedex/index.ts # compile native routes → .brust/jinja
62
- BRUST_PORT=3100 bun run example/pokedex/index.ts # → http://127.0.0.1:3100
63
- ```
57
+ ## One store. Every paradigm reads it live.
64
58
 
65
- ```bash
66
- curl 127.0.0.1:3100/ping # pong (pure Rust)
67
- curl 127.0.0.1:3100/ # native list page, no server React
68
- curl 127.0.0.1:3100/pokemon/pikachu # → native detail, dynamic param
69
- curl 127.0.0.1:3100/type-chart # → native 18×18 effectiveness grid
70
- ```
59
+ The center of Brust is a store that resolves to a **single instance** wherever
60
+ it's read a hydrated React island, a zero-React native behavior, or the
61
+ server during render. Components from different worlds share state with no
62
+ bridge code:
71
63
 
72
- The [`example/pokedex/`](./example/pokedex) app dogfoods `native: true` across
73
- every route; see its [`FRAMEWORK-GAPS.md`](./example/pokedex/FRAMEWORK-GAPS.md) for
74
- the empirically-found limits.
75
-
76
- ## CLI
64
+ ```ts
65
+ // lib/counter.ts one definition
66
+ import { defineStore, signal } from 'brustjs/store'
67
+ export const counter = defineStore('counter', () => ({ count: signal(0) }))
68
+ ```
77
69
 
70
+ ```tsx
71
+ // A React island reads and writes it…
72
+ import { useStore } from 'brustjs/client'
73
+ const { count } = useStore(counter)
78
74
  ```
79
- brustjs dev <entry> # dev mode: watcher + WS reload + browser auto-reload
80
- brustjs build <entry> --out-dir D # prebuilt ./dist/ — run from the project (bun run dist/index.js)
81
- --target <auto|all|TARGET[,…]> # which native binary to bundle (default: auto = host platform)
82
- --ssg [--ssg-out D] # prerender static routes (incl. markdown pages) to HTML
83
- brustjs new <name> # scaffold a project (partial — see Status)
75
+
76
+ ```tsx
77
+ // …and a native behavior component (no React shipped) reads the SAME instance
78
+ export const behavior = () => ({
79
+ count: computed(() => String(counter.count())),
80
+ bump() { counter.count.set(counter.count() + 1) },
81
+ })
84
82
  ```
85
83
 
86
- ## Features
87
-
88
- - **React 19 SSR** via `renderToPipeableStream` (auto-Suspense → chunked streaming).
89
- - **Islands** — opt-in client hydration with `<Island>`; the rest ships zero JS.
90
- SSR islands can opt into **ISR caching** (`isr={{ key, tags, revalidate }}`) so
91
- `renderToString` runs once per key, then serves a frozen pair from Rust.
92
- - **`native: true` routes** JSX compiled to a jinja template at build time and
93
- rendered Rust-side (`minijinja`), skipping React on the server entirely.
94
- - **Native interactivity without islands** — Alpine.js-style `x-*` DOM directives
95
- (`x-data`/`x-text`/`x-show`/`x-bind-*`/`x-on-*`/`x-for`) on a `native` page,
96
- bound to the store by a small react-free runtime. Logic lives in a co-located
97
- `export const behavior` (single-file component); each component's JS is a
98
- separate chunk loaded **on demand** — a page never downloads a component it
99
- doesn't render.
100
- - **Static lucide icons** — `lucide-react` icons on a `native` route compile to
101
- inline `<svg>` at build time: **zero React**, no `renderToString`, no factory or
102
- `{{ slot }}`. Static props bake into the markup; dynamic props (loader / `.map()`
103
- item) become escaped jinja substitutions; `className` merges with the icon class.
104
- Unsupported shapes (spread props, etc.) soft-fall to the React SSR path.
105
- - **Isomorphic store** `brustjs/store`: `signal`/`computed`/`effect` +
106
- `defineStore(name, factory)`. One `window` singleton per name on the client (so
107
- separate island/directive chunks share state), a per-request `AsyncLocalStorage`
108
- instance on the server. `useStore` adapter for React islands; a native directive
109
- button and a React island reactively share the same store.
110
- - **Typed actions** `defineActions().get/post/put/patch/delete/head(path, ctx => R, { body, query })`
111
- on the server; `client<typeof actions>()` is an Eden-Treaty-style proxy that
112
- infers the whole API from the server types (no codegen) and returns
113
- `{ data, error, status, headers }` (never throws). Standard Schema (zod)
114
- validation, JSON / urlencoded / multipart bodies.
115
- - **Markdown pages** `mdRoutes()` compiles a directory of `.md` files
116
- (GFM + frontmatter, optional shiki highlighting) into native jinja routes at
117
- build time, with React islands and behavior components embeddable straight
118
- from markdown.
119
- - **SSE & WebSockets** as first-class route shapes.
120
- - Nested routes + dynamic params, per-route typed loaders, request-scoped middleware,
121
- SPA-style navigation, in-process LRU response cache + island ISR cache, Tailwind v4 + CSS Modules.
122
- - **Agent-first** — `defineActions` endpoints become MCP **tools** and route
123
- loaders become **resources** at `/_brust/mcp`; `tools/call` runs through the
124
- same validation + middleware as an HTTP request, so agents drive the app
125
- without scraping.
84
+ Click either one — both update. [See it live](https://brust.assetsart.com/) ·
85
+ [Store docs](https://brust.assetsart.com/docs/store).
86
+
87
+ ## Built in, not bolted on
88
+
89
+ - **Native rendering** pages compile ahead of time and are served as plain
90
+ HTML: no hydration pass, no framework runtime in the response. One compiled
91
+ page sustains **84,119 req/s** versus 28,938 for the same page through a
92
+ JavaScript pipeline about 2.9× ([bench/RESULTS.md](./bench/RESULTS.md)).
93
+ → [Rendering](https://brust.assetsart.com/docs/rendering)
94
+ - **React islands** hydrate one component, not the page. React 19 streaming
95
+ SSR with auto-Suspense; SSR islands can opt into **ISR caching**
96
+ (`isr={{ key, tags, revalidate }}`).
97
+ [Islands](https://brust.assetsart.com/docs/rendering#islands)
98
+ - **Native interactivity** — counters, toggles, live text: `x-*` DOM directives
99
+ bound to the store by a small react-free runtime, with logic in a co-located
100
+ `export const behavior`. Each component's JS is a separate on-demand chunk.
101
+ [Native interactivity](https://brust.assetsart.com/docs/native-interactivity)
102
+ - **Typed actions end-to-end** — `defineActions()` on the server; the treaty
103
+ client infers the whole API from server types (no codegen) and returns
104
+ `{ data, error, status, headers }` it never throws. Standard Schema (zod)
105
+ validation; JSON / urlencoded / multipart.
106
+ [Actions](https://brust.assetsart.com/docs/actions)
107
+ - **Markdown pages + SSG** drop `.md` files in a folder for routed pages with
108
+ nav, embed islands and behaviors straight from markdown, and prerender the
109
+ whole site to static HTML with `brust build --ssg`. The
110
+ [docs site](https://brust.assetsart.com/) is built this way.
111
+ [Markdown pages](https://brust.assetsart.com/docs/markdown-pages)
112
+ - **MCP for agents** actions double as MCP **tools** and loaders as
113
+ **resources** at `/_brust/mcp`; `tools/call` runs through the same validation
114
+ and middleware as HTTP, so agents drive the app without scraping.
115
+ [Agents](https://brust.assetsart.com/docs/agents)
116
+ - Plus: nested routes + dynamic params, typed loaders, request-scoped
117
+ middleware, SPA-style navigation, SSE & WebSockets as first-class route
118
+ shapes, response + ISR caches, Tailwind v4 + CSS Modules, static
119
+ `lucide-react` icons compiled to inline SVG on native routes.
126
120
 
127
121
  ## Markdown pages
128
122
 
129
- Mount a content directory as routes — each `.md` file becomes a `native: true`
130
- page compiled to a jinja template at build time (no React on the server, no
131
- markdown parsing at request time):
123
+ Mount a content directory as routes — each `.md` file becomes a compiled page
124
+ (no markdown parsing at request time):
132
125
 
133
126
  ```tsx
134
127
  // routes.tsx
@@ -153,13 +146,47 @@ optional `shiki` peer dependency is installed. `brust build` freezes the pages
153
146
  into the dist (`md-manifest.json` — the content dir isn't needed at runtime),
154
147
  and `brust build --ssg` prerenders them to static HTML.
155
148
 
156
- ## Performance
149
+ ## CLI
150
+
151
+ ```
152
+ brustjs dev <entry> # dev mode: watcher + WS reload + browser auto-reload
153
+ brustjs build <entry> --out-dir D # prebuilt ./dist/ — run from the project (bun run dist/index.js)
154
+ --target <auto|all|TARGET[,…]> # which native binary to bundle (default: auto = host platform)
155
+ --ssg [--ssg-out D] # prerender static routes (incl. markdown pages) to HTML
156
+ # + per-route SPA payloads — client-side nav works statically
157
+ brustjs new <name> # scaffold a project (partial — see Status)
158
+ ```
159
+
160
+ Full reference: [CLI](https://brust.assetsart.com/docs/cli).
161
+
162
+ ## Under the hood
157
163
 
158
- Two tiers, split by the napi crossing: pure-Rust paths (`/ping`, native jinja
159
- routes) run far faster than routes that cross into a Bun worker for React SSR.
160
- Full numbers, methodology, and the latency table are in
161
- [`bench/RESULTS.md`](./bench/RESULTS.md) (`bun run bench`); the request lifecycle
162
- and SAB protocol are in [`architecture.md`](./architecture.md).
164
+ A detail you mostly never have to think about: Brust runs as one Bun host
165
+ process whose HTTP server (hyper 1.x, HTTP/1.1 + HTTP/2, optional in-process
166
+ TLS), routing, caches, and native-template rendering are pure Rust, loaded as a
167
+ napi `.node` module. React renders cross into Bun Worker threads and return
168
+ over a per-worker `SharedArrayBuffer`; a worker can hold several renders
169
+ in-flight (`renderSlots`) to overlap Suspense-bound requests. `native: true`
170
+ routes compile JSX to templates at build time and never touch React on the
171
+ server. Multi-thread tokio runtime — runs the same everywhere (no io_uring /
172
+ seccomp caveat). The full request lifecycle and protocol live in
173
+ [`architecture.md`](./architecture.md); numbers and methodology in
174
+ [`bench/RESULTS.md`](./bench/RESULTS.md).
175
+
176
+ ## Run from source
177
+
178
+ ```bash
179
+ git clone https://github.com/AssetsArt/brust && cd brust
180
+ bun install
181
+ cd runtime && bun run build && cd .. # release addon; NOT build:debug (~2× slower)
182
+ bun run runtime/cli/index.ts build example/pokedex/index.ts # compile native routes → .brust/jinja
183
+ BRUST_PORT=3100 bun run example/pokedex/index.ts # → http://127.0.0.1:3100
184
+ ```
185
+
186
+ The [`example/pokedex/`](./example/pokedex) app dogfoods `native: true` across
187
+ every route, and [`example/docs/`](./example/docs) is the documentation site
188
+ itself — markdown pages, SSG, and the unified-store demo, deployed to
189
+ [brust.assetsart.com](https://brust.assetsart.com/).
163
190
 
164
191
  ## Development
165
192
 
@@ -174,21 +201,19 @@ crates/brust-core/ Rust core (pure, zero napi): hyper server, worker pool
174
201
  crates/brust/ Thin napi cdylib over brust-core (the .node)
175
202
  crates/jsx-rust-compiler/ JSX → jinja compiler for native: true routes
176
203
  runtime/ Bun-side: routing, render, actions, store, native directives, CLI
177
- example/ pokedex native-first demo
204
+ example/ pokedex (native-first demo) · docs (the documentation site)
178
205
  bench/ · docs/ · architecture.md
179
206
  ```
180
207
 
181
208
  ## Status
182
209
 
183
210
  Alpha, solo-developed. Linux is tier-1 (glibc + musl, 6 prebuilt platform
184
- binaries); the multi-thread tokio server runs under default container seccomp
185
- no `io_uring` exception needed. The server speaks **HTTP/1.1 + HTTP/2** with
186
- optional in-process **TLS**, and a worker can hold several renders in-flight
187
- (**`renderSlots`**) to overlap Suspense / loader-bound requests. Known partials:
211
+ binaries) and runs under default container seccomp. Known partials:
188
212
  `brustjs dev` reload is a full worker-respawn (not state-preserving HMR) — TS,
189
- islands, and `.module.css` all reload that way. Tailwind is opt-in — the scaffold
190
- adds it as a project dependency; `@import "tailwindcss"` resolves from your own
191
- `node_modules`. Roadmap and limitations in [`architecture.md`](./architecture.md).
213
+ islands, and `.module.css` all reload that way. Tailwind is opt-in — the
214
+ scaffold adds it as a project dependency; `@import "tailwindcss"` resolves from
215
+ your own `node_modules`. Roadmap and limitations in
216
+ [`architecture.md`](./architecture.md).
192
217
 
193
218
  MIT.
194
219
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brustjs",
3
- "version": "0.1.41-alpha",
3
+ "version": "0.1.43-alpha",
4
4
  "description": "Bun + Rust SSR framework — React on the server, Rust everywhere else (napi cdylib + per-worker SharedArrayBuffer).",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,12 +41,12 @@
41
41
  "typescript": "^6.0.3"
42
42
  },
43
43
  "optionalDependencies": {
44
- "brustjs-darwin-x64": "0.1.41-alpha",
45
- "brustjs-darwin-arm64": "0.1.41-alpha",
46
- "brustjs-linux-x64-gnu": "0.1.41-alpha",
47
- "brustjs-linux-arm64-gnu": "0.1.41-alpha",
48
- "brustjs-linux-x64-musl": "0.1.41-alpha",
49
- "brustjs-linux-arm64-musl": "0.1.41-alpha"
44
+ "brustjs-darwin-x64": "0.1.43-alpha",
45
+ "brustjs-darwin-arm64": "0.1.43-alpha",
46
+ "brustjs-linux-x64-gnu": "0.1.43-alpha",
47
+ "brustjs-linux-arm64-gnu": "0.1.43-alpha",
48
+ "brustjs-linux-x64-musl": "0.1.43-alpha",
49
+ "brustjs-linux-arm64-musl": "0.1.43-alpha"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "react": "^19.2.6",
@@ -581,7 +581,7 @@ export async function runBuild(args: string[]): Promise<void> {
581
581
  )
582
582
  const staticOut = parsed.ssgOut ?? path.join(outDir, 'static')
583
583
  try {
584
- const { written, skipped } = await exportStatic({
584
+ const { written, navWritten, skipped } = await exportStatic({
585
585
  distDir: outDir,
586
586
  entryDir,
587
587
  staticOut,
@@ -597,7 +597,9 @@ export async function runBuild(args: string[]): Promise<void> {
597
597
  .map((r) => `${r}=${counts.get(r)}`)
598
598
  .join(', ')
599
599
  const skippedDesc = skipped.length > 0 ? ` (skipped ${skipped.length}: ${reasons})` : ''
600
- console.log(`[brust build] ssg: ${written.length} pages → ${staticOut}${skippedDesc}`)
600
+ console.log(
601
+ `[brust build] ssg: ${written.length} pages + ${navWritten.length} spa payloads → ${staticOut}${skippedDesc}`,
602
+ )
601
603
  } catch (err) {
602
604
  console.error(`[brust build] ssg: ${err instanceof Error ? err.message : String(err)}`)
603
605
  process.exit(1)
@@ -41,6 +41,16 @@ function outFileFor(normalized: string): string {
41
41
  return `${normalized.slice(1)}/index.html`
42
42
  }
43
43
 
44
+ /** Where a route's SPA navigation payload lands on disk. The client navigator
45
+ * fetches `/_brust/page${pathname}` (bootstrap.ts navigate()), so the payload
46
+ * must be reachable at that exact URL on a dumb static host — which means
47
+ * `<url>/index.html`, the same directory-index shape the pages use:
48
+ * '/' → '_brust/page/index.html'; '/docs/intro' → '_brust/page/docs/intro/index.html'. */
49
+ export function navPayloadFileFor(normalized: string): string {
50
+ if (normalized === '/') return join('_brust', 'page', 'index.html')
51
+ return join('_brust', 'page', normalized.slice(1), 'index.html')
52
+ }
53
+
44
54
  /** Decide, for every flattened route, whether it can be statically prerendered
45
55
  * and which file it maps to. Deterministic: trailing-slash duplicates collapse
46
56
  * to one decision (first occurrence wins) and output is sorted by fullPath. */
@@ -165,6 +175,14 @@ async function waitForListening(
165
175
  /** Boot the just-built dist on a free port, crawl every included route, and
166
176
  * write the static site to `staticOut` (clobbered first). ANY non-200 fails
167
177
  * the whole export — the partial output is removed and the error rethrown.
178
+ *
179
+ * Each route is crawled TWICE: the full document (→ outFile) and its SPA
180
+ * navigation payload `/_brust/page<path>` (→ navPayloadFileFor), the same
181
+ * JSON `{html,title,store}` the live server returns. With the payloads on
182
+ * disk at the URLs the client navigator already fetches, internal links on
183
+ * the static site navigate SPA-style instead of full-reloading; any host
184
+ * 404/redirect-to-HTML still lands in the navigator's full-reload fallback.
185
+ *
168
186
  * Asset copy preserves the live server's URL shape: islands + css under
169
187
  * /_brust/, public/ root-mapped (runtime/index.ts configurePublicDir). */
170
188
  export async function exportStatic(opts: {
@@ -172,7 +190,7 @@ export async function exportStatic(opts: {
172
190
  entryDir: string // app dir (for public/)
173
191
  staticOut: string // e.g. dist/static (clobbered first)
174
192
  routes: SsgRouteDecision[]
175
- }): Promise<{ written: string[]; skipped: SsgRouteDecision[] }> {
193
+ }): Promise<{ written: string[]; navWritten: string[]; skipped: SsgRouteDecision[] }> {
176
194
  const { distDir, entryDir, staticOut, routes } = opts
177
195
  const included = routes.filter((r) => r.include)
178
196
  const skipped = routes.filter((r) => !r.include)
@@ -181,6 +199,7 @@ export async function exportStatic(opts: {
181
199
  await mkdir(staticOut, { recursive: true })
182
200
 
183
201
  const written: string[] = []
202
+ const navWritten: string[] = []
184
203
  if (included.length > 0) {
185
204
  const port = await freePort()
186
205
  const proc = Bun.spawn(['bun', join(distDir, 'index.js')], {
@@ -202,6 +221,31 @@ export async function exportStatic(opts: {
202
221
  await mkdir(dirname(outPath), { recursive: true })
203
222
  await Bun.write(outPath, body)
204
223
  written.push(d.outFile)
224
+
225
+ // SPA navigation payload — the document crawl above just proved this
226
+ // route renders 200, so a failing payload is a real bug, not a host
227
+ // quirk: fail the export rather than silently shipping full reloads.
228
+ const navUrl = `/_brust/page${d.fullPath}`
229
+ const navResp = await fetch(`http://127.0.0.1:${port}${navUrl}`, {
230
+ headers: { Accept: 'application/json' },
231
+ })
232
+ const navBody = await navResp.text()
233
+ if (navResp.status !== 200) {
234
+ throw new Error(`GET ${navUrl} → ${navResp.status}\n${navBody.slice(0, 500)}`)
235
+ }
236
+ // Guard the payload contract the client navigator parses — a non-JSON
237
+ // body would otherwise surface only as a runtime full-reload fallback.
238
+ try {
239
+ const parsed = JSON.parse(navBody) as { html?: unknown }
240
+ if (typeof parsed.html !== 'string') throw new Error('missing "html" field')
241
+ } catch (e) {
242
+ throw new Error(`GET ${navUrl} → invalid SPA payload: ${(e as Error).message}`)
243
+ }
244
+ const navFile = navPayloadFileFor(d.fullPath)
245
+ const navPath = join(staticOut, navFile)
246
+ await mkdir(dirname(navPath), { recursive: true })
247
+ await Bun.write(navPath, navBody)
248
+ navWritten.push(navFile)
205
249
  }
206
250
  const workers = Array.from(
207
251
  { length: Math.min(CRAWL_CONCURRENCY, included.length) },
@@ -253,5 +297,6 @@ export async function exportStatic(opts: {
253
297
  }
254
298
 
255
299
  written.sort()
256
- return { written, skipped }
300
+ navWritten.sort()
301
+ return { written, navWritten, skipped }
257
302
  }
package/runtime/index.js CHANGED
@@ -77,8 +77,8 @@ function requireNative() {
77
77
  try {
78
78
  const binding = require('brustjs-android-arm64')
79
79
  const bindingPackageVersion = require('brustjs-android-arm64/package.json').version
80
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
81
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
80
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
81
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
82
82
  }
83
83
  return binding
84
84
  } catch (e) {
@@ -93,8 +93,8 @@ function requireNative() {
93
93
  try {
94
94
  const binding = require('brustjs-android-arm-eabi')
95
95
  const bindingPackageVersion = require('brustjs-android-arm-eabi/package.json').version
96
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
97
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
96
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
97
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
98
98
  }
99
99
  return binding
100
100
  } catch (e) {
@@ -114,8 +114,8 @@ function requireNative() {
114
114
  try {
115
115
  const binding = require('brustjs-win32-x64-gnu')
116
116
  const bindingPackageVersion = require('brustjs-win32-x64-gnu/package.json').version
117
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
118
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
117
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
118
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
119
119
  }
120
120
  return binding
121
121
  } catch (e) {
@@ -130,8 +130,8 @@ function requireNative() {
130
130
  try {
131
131
  const binding = require('brustjs-win32-x64-msvc')
132
132
  const bindingPackageVersion = require('brustjs-win32-x64-msvc/package.json').version
133
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
134
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
133
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
134
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
135
135
  }
136
136
  return binding
137
137
  } catch (e) {
@@ -147,8 +147,8 @@ function requireNative() {
147
147
  try {
148
148
  const binding = require('brustjs-win32-ia32-msvc')
149
149
  const bindingPackageVersion = require('brustjs-win32-ia32-msvc/package.json').version
150
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
151
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
150
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
151
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
152
152
  }
153
153
  return binding
154
154
  } catch (e) {
@@ -163,8 +163,8 @@ function requireNative() {
163
163
  try {
164
164
  const binding = require('brustjs-win32-arm64-msvc')
165
165
  const bindingPackageVersion = require('brustjs-win32-arm64-msvc/package.json').version
166
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
167
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
166
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
167
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
168
168
  }
169
169
  return binding
170
170
  } catch (e) {
@@ -182,8 +182,8 @@ function requireNative() {
182
182
  try {
183
183
  const binding = require('brustjs-darwin-universal')
184
184
  const bindingPackageVersion = require('brustjs-darwin-universal/package.json').version
185
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
186
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
185
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
186
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
187
187
  }
188
188
  return binding
189
189
  } catch (e) {
@@ -198,8 +198,8 @@ function requireNative() {
198
198
  try {
199
199
  const binding = require('brustjs-darwin-x64')
200
200
  const bindingPackageVersion = require('brustjs-darwin-x64/package.json').version
201
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
202
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
201
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
202
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
203
203
  }
204
204
  return binding
205
205
  } catch (e) {
@@ -214,8 +214,8 @@ function requireNative() {
214
214
  try {
215
215
  const binding = require('brustjs-darwin-arm64')
216
216
  const bindingPackageVersion = require('brustjs-darwin-arm64/package.json').version
217
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
218
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
217
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
218
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
219
219
  }
220
220
  return binding
221
221
  } catch (e) {
@@ -234,8 +234,8 @@ function requireNative() {
234
234
  try {
235
235
  const binding = require('brustjs-freebsd-x64')
236
236
  const bindingPackageVersion = require('brustjs-freebsd-x64/package.json').version
237
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
238
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
237
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
238
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
239
239
  }
240
240
  return binding
241
241
  } catch (e) {
@@ -250,8 +250,8 @@ function requireNative() {
250
250
  try {
251
251
  const binding = require('brustjs-freebsd-arm64')
252
252
  const bindingPackageVersion = require('brustjs-freebsd-arm64/package.json').version
253
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
254
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
253
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
254
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
255
255
  }
256
256
  return binding
257
257
  } catch (e) {
@@ -271,8 +271,8 @@ function requireNative() {
271
271
  try {
272
272
  const binding = require('brustjs-linux-x64-musl')
273
273
  const bindingPackageVersion = require('brustjs-linux-x64-musl/package.json').version
274
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
275
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
274
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
275
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
276
276
  }
277
277
  return binding
278
278
  } catch (e) {
@@ -287,8 +287,8 @@ function requireNative() {
287
287
  try {
288
288
  const binding = require('brustjs-linux-x64-gnu')
289
289
  const bindingPackageVersion = require('brustjs-linux-x64-gnu/package.json').version
290
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
291
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
290
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
291
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
292
292
  }
293
293
  return binding
294
294
  } catch (e) {
@@ -305,8 +305,8 @@ function requireNative() {
305
305
  try {
306
306
  const binding = require('brustjs-linux-arm64-musl')
307
307
  const bindingPackageVersion = require('brustjs-linux-arm64-musl/package.json').version
308
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
309
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
308
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
309
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
310
310
  }
311
311
  return binding
312
312
  } catch (e) {
@@ -321,8 +321,8 @@ function requireNative() {
321
321
  try {
322
322
  const binding = require('brustjs-linux-arm64-gnu')
323
323
  const bindingPackageVersion = require('brustjs-linux-arm64-gnu/package.json').version
324
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
325
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
324
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
325
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
326
326
  }
327
327
  return binding
328
328
  } catch (e) {
@@ -339,8 +339,8 @@ function requireNative() {
339
339
  try {
340
340
  const binding = require('brustjs-linux-arm-musleabihf')
341
341
  const bindingPackageVersion = require('brustjs-linux-arm-musleabihf/package.json').version
342
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
343
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
342
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
343
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
344
344
  }
345
345
  return binding
346
346
  } catch (e) {
@@ -355,8 +355,8 @@ function requireNative() {
355
355
  try {
356
356
  const binding = require('brustjs-linux-arm-gnueabihf')
357
357
  const bindingPackageVersion = require('brustjs-linux-arm-gnueabihf/package.json').version
358
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
359
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
358
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
359
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
360
360
  }
361
361
  return binding
362
362
  } catch (e) {
@@ -373,8 +373,8 @@ function requireNative() {
373
373
  try {
374
374
  const binding = require('brustjs-linux-loong64-musl')
375
375
  const bindingPackageVersion = require('brustjs-linux-loong64-musl/package.json').version
376
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
377
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
376
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
377
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
378
378
  }
379
379
  return binding
380
380
  } catch (e) {
@@ -389,8 +389,8 @@ function requireNative() {
389
389
  try {
390
390
  const binding = require('brustjs-linux-loong64-gnu')
391
391
  const bindingPackageVersion = require('brustjs-linux-loong64-gnu/package.json').version
392
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
393
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
392
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
393
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
394
394
  }
395
395
  return binding
396
396
  } catch (e) {
@@ -407,8 +407,8 @@ function requireNative() {
407
407
  try {
408
408
  const binding = require('brustjs-linux-riscv64-musl')
409
409
  const bindingPackageVersion = require('brustjs-linux-riscv64-musl/package.json').version
410
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
411
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
410
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
411
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
412
412
  }
413
413
  return binding
414
414
  } catch (e) {
@@ -423,8 +423,8 @@ function requireNative() {
423
423
  try {
424
424
  const binding = require('brustjs-linux-riscv64-gnu')
425
425
  const bindingPackageVersion = require('brustjs-linux-riscv64-gnu/package.json').version
426
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
427
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
426
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
427
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
428
428
  }
429
429
  return binding
430
430
  } catch (e) {
@@ -440,8 +440,8 @@ function requireNative() {
440
440
  try {
441
441
  const binding = require('brustjs-linux-ppc64-gnu')
442
442
  const bindingPackageVersion = require('brustjs-linux-ppc64-gnu/package.json').version
443
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
444
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
443
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
444
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
445
445
  }
446
446
  return binding
447
447
  } catch (e) {
@@ -456,8 +456,8 @@ function requireNative() {
456
456
  try {
457
457
  const binding = require('brustjs-linux-s390x-gnu')
458
458
  const bindingPackageVersion = require('brustjs-linux-s390x-gnu/package.json').version
459
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
460
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
459
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
460
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
461
461
  }
462
462
  return binding
463
463
  } catch (e) {
@@ -476,8 +476,8 @@ function requireNative() {
476
476
  try {
477
477
  const binding = require('brustjs-openharmony-arm64')
478
478
  const bindingPackageVersion = require('brustjs-openharmony-arm64/package.json').version
479
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
480
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
479
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
480
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
481
481
  }
482
482
  return binding
483
483
  } catch (e) {
@@ -492,8 +492,8 @@ function requireNative() {
492
492
  try {
493
493
  const binding = require('brustjs-openharmony-x64')
494
494
  const bindingPackageVersion = require('brustjs-openharmony-x64/package.json').version
495
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
496
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
495
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
496
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
497
497
  }
498
498
  return binding
499
499
  } catch (e) {
@@ -508,8 +508,8 @@ function requireNative() {
508
508
  try {
509
509
  const binding = require('brustjs-openharmony-arm')
510
510
  const bindingPackageVersion = require('brustjs-openharmony-arm/package.json').version
511
- if (bindingPackageVersion !== '0.1.41-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
512
- throw new Error(`Native binding package version mismatch, expected 0.1.41-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
511
+ if (bindingPackageVersion !== '0.1.43-alpha' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
512
+ throw new Error(`Native binding package version mismatch, expected 0.1.43-alpha but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
513
513
  }
514
514
  return binding
515
515
  } catch (e) {
@@ -8,6 +8,14 @@
8
8
  import { effect } from '../store/signal.ts'
9
9
  import { nav, type NavPhase } from './store.ts'
10
10
 
11
+ /** Drop a trailing slash (root '/' stays). Mirrors store.ts canonicalPath —
12
+ * kept local so this module stays a leaf with no extra import surface. */
13
+ function canonicalPath(p: string): string {
14
+ let out = p
15
+ while (out.length > 1 && out.endsWith('/')) out = out.slice(0, -1)
16
+ return out
17
+ }
18
+
11
19
  // The install guard lives on globalThis (like __BRUST_NAV__), NOT as a module
12
20
  // `let`: every Bun.build island chunk inlines its own copy of this module, so a
13
21
  // module-local flag would not stop a second chunk from installing a duplicate
@@ -55,10 +63,15 @@ function reconcileActiveLinks(currentPath: string): void {
55
63
  const prefix = el.dataset.brustActiveMatch === 'prefix'
56
64
  const links = el.querySelectorAll<HTMLAnchorElement>('a[href]')
57
65
  for (const a of Array.from(links)) {
58
- const linkPath = new URL(a.href, location.href).pathname
66
+ // Canonicalize both sides (drop trailing '/', root stays '/') so a link
67
+ // href and a current path that differ only by a trailing slash — e.g. a
68
+ // full load served via a trailing-slash redirect — still match. nav.path
69
+ // is already canonical (store.ts), but the link href may not be.
70
+ const linkPath = canonicalPath(new URL(a.href, location.href).pathname)
71
+ const cur = canonicalPath(currentPath)
59
72
  const isActive = prefix
60
- ? currentPath === linkPath || currentPath.startsWith(`${linkPath.replace(/\/$/, '')}/`)
61
- : currentPath === linkPath
73
+ ? cur === linkPath || cur.startsWith(`${linkPath}/`)
74
+ : cur === linkPath
62
75
  a.classList.toggle(activeClass, isActive)
63
76
  if (isActive) a.setAttribute('aria-current', 'page')
64
77
  else a.removeAttribute('aria-current')
@@ -73,6 +73,21 @@ function store(): NavInternal {
73
73
  return G.__BRUST_NAV__
74
74
  }
75
75
 
76
+ /** Canonicalize a pathname to the form routes match on: no trailing slash
77
+ * (root stays '/'). A full document load served via a trailing-slash redirect
78
+ * (e.g. Cloudflare Pages 308 `/docs/x` → `/docs/x/`) hands the bootstrap a
79
+ * `location.pathname` ending in `/`, while link hrefs and the server-rendered
80
+ * active state use the bare path — so without this, the active-nav reconciler
81
+ * and NavLink behaviors would compare `/docs/x/` against `/docs/x` and treat
82
+ * the current page as inactive. Normalizing here keeps every consumer of
83
+ * `nav.path()` aligned with the canonical route. Search/hash never reach this
84
+ * (the setters take a pathname only). */
85
+ function canonicalPath(path: string): string {
86
+ let p = path
87
+ while (p.length > 1 && p.endsWith('/')) p = p.slice(0, -1)
88
+ return p
89
+ }
90
+
76
91
  // Public reactive handle. A Proxy resolves the singleton on each property access
77
92
  // so (a) every chunk's `nav` points at the one globalThis bag, and (b) tests that
78
93
  // reset the singleton see the fresh signals.
@@ -145,7 +160,7 @@ export function onNavigateError(cb: ErrorCb): () => void {
145
160
  export function __navInit(path: string, search: string): void {
146
161
  const s = store()
147
162
  batch(() => {
148
- s.path.set(path)
163
+ s.path.set(canonicalPath(path))
149
164
  s.search.set(search)
150
165
  s.phase.set('idle')
151
166
  s.from.set(null)
@@ -162,21 +177,22 @@ export function __navInit(path: string, search: string): void {
162
177
  export function __navStart(toPath: string, _toSearch: string): void {
163
178
  const s = store()
164
179
  const from = s.path()
180
+ const to = canonicalPath(toPath)
165
181
  batch(() => {
166
182
  s.from.set(from)
167
- s.to.set(toPath)
183
+ s.to.set(to)
168
184
  s.error.set(null)
169
185
  s.phase.set('loading')
170
186
  })
171
187
  bumpVersion(s)
172
- for (const cb of [...s._before]) cb({ from, to: toPath })
188
+ for (const cb of [...s._before]) cb({ from, to })
173
189
  emit(s)
174
190
  }
175
191
 
176
192
  export function __navCommit(toPath: string, toSearch: string): void {
177
193
  const s = store()
178
194
  batch(() => {
179
- s.path.set(toPath)
195
+ s.path.set(canonicalPath(toPath))
180
196
  s.search.set(toSearch)
181
197
  s.to.set(null)
182
198
  s.error.set(null)