From 66ab161a55ee8fdd7346f85db1c6acc527d47dad Mon Sep 17 00:00:00 2001 From: Arechi Date: Thu, 30 Apr 2026 13:32:03 +0200 Subject: [PATCH 1/5] build: convert TypeScript package to ESM-only Switches the npm package from CommonJS to ESM-only output. - tsconfig.json: module/moduleResolution NodeNext, target ES2022 - package.json: adds "type": "module" and "exports" map; drops "main" - CI Generate: adds esModuleInterop=true and importSuffix=.js so ts-proto emits relative imports with .js extensions for NodeNext Breaking change for CommonJS consumers (require() is blocked by the exports map); a major version bump should accompany this before publishing. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci-typescript.yaml | 4 +++- package.json | 10 ++++++++-- tsconfig.json | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-typescript.yaml b/.github/workflows/ci-typescript.yaml index 1c174753..9d382b1a 100644 --- a/.github/workflows/ci-typescript.yaml +++ b/.github/workflows/ci-typescript.yaml @@ -45,7 +45,9 @@ jobs: --ts_proto_out=./out \ --ts_proto_opt=outputIndex=true \ --ts_proto_opt=globalThisPolyfill=true \ - --ts_proto_opt=useExactTypes=false + --ts_proto_opt=useExactTypes=false \ + --ts_proto_opt=esModuleInterop=true \ + --ts_proto_opt=importSuffix=.js - name: Compile run: pnpm run build diff --git a/package.json b/package.json index aa763b88..e5dbd325 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,14 @@ "type": "git", "url": "https://github.com/BluEye-Robotics/ProtocolDefinitions.git" }, - "main": "dist/index.js", - "types": "dist/index.d.ts", + "type": "module", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "types": "./dist/index.d.ts", "files": [ "dist" ], diff --git a/tsconfig.json b/tsconfig.json index fc30754e..54339cbc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,8 @@ { "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", "declaration": true, "outDir": "dist", "strict": true, From 8fc95c5b2ef5092a1e4fd9c0ca928915c01a8a01 Mon Sep 17 00:00:00 2001 From: Arechi Date: Tue, 18 Aug 2026 21:00:22 +0200 Subject: [PATCH 2/5] build: address review feedback on ESM conversion - Bump to 4.0.0: the output format change is breaking, and the `3.2.0-` prerelease scheme means a `^3.2.0-` range would otherwise let `npm update` move consumers onto the ESM build silently. - Use a `default` export condition instead of `import`, so `require()` still resolves on Node 22.12+ via `require(esm)` instead of failing with ERR_PACKAGE_PATH_NOT_EXPORTED. - Restore deep imports via a `./dist/*` subpath export, preserving the specifiers that worked before the `exports` map was introduced. - Move the protoc invocation into a `generate` npm script so CI and the docs cannot drift; CLAUDE.md documented flags that no longer compiled under NodeNext. - Add a CI step that packs the tarball and verifies both the ESM import and the CJS require against the real `exports` map. - Document the module format in README.npm.md and ignore `dist/`. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci-typescript.yaml | 30 ++++++++++++++++++---------- .gitignore | 3 +++ CLAUDE.md | 20 +++++++++---------- README.npm.md | 23 +++++++++++++++++++++ package.json | 8 +++++--- 5 files changed, 60 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci-typescript.yaml b/.github/workflows/ci-typescript.yaml index 9d382b1a..c2cae32c 100644 --- a/.github/workflows/ci-typescript.yaml +++ b/.github/workflows/ci-typescript.yaml @@ -37,21 +37,29 @@ jobs: pnpm install - name: Generate - run: | - mkdir -p ./out/ && - protoc protobuf_definitions/*.proto \ - --plugin=./node_modules/.bin/protoc-gen-ts_proto \ - --proto_path=protobuf_definitions \ - --ts_proto_out=./out \ - --ts_proto_opt=outputIndex=true \ - --ts_proto_opt=globalThisPolyfill=true \ - --ts_proto_opt=useExactTypes=false \ - --ts_proto_opt=esModuleInterop=true \ - --ts_proto_opt=importSuffix=.js + run: pnpm run generate - name: Compile run: pnpm run build + - name: Verify package entrypoints + run: | + SMOKE=$(mktemp -d) + TARBALL=$(pnpm pack --pack-destination "$SMOKE" | tail -1) + cd "$SMOKE" + npm init -y > /dev/null + npm install "$TARBALL" > /dev/null + node --input-type=module -e " + import { blueye } from '@blueyerobotics/protocol-definitions'; + if (!blueye.protocol.GetBatteryReq) throw new Error('missing expected export'); + console.log('ESM import OK'); + " + node --input-type=commonjs -e " + const { blueye } = require('@blueyerobotics/protocol-definitions'); + if (!blueye.protocol.GetBatteryReq) throw new Error('missing expected export'); + console.log('CJS require OK'); + " + - name: Publish to npm run: | cp README.npm.md README.md diff --git a/.gitignore b/.gitignore index a4b51f5d..afc52765 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ bin obj out +# typescript outputs +dist + # Other build build_imx diff --git a/CLAUDE.md b/CLAUDE.md index 3f3ae27d..c6e44e63 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,17 +22,17 @@ cmake --install build --prefix /usr/local ### TypeScript ``` pnpm install -# Generate TypeScript from proto files: -mkdir -p ./out/ && protoc protobuf_definitions/*.proto \ - --plugin=./node_modules/.bin/protoc-gen-ts_proto \ - --proto_path=protobuf_definitions \ - --ts_proto_out=./out \ - --ts_proto_opt=outputIndex=true \ - --ts_proto_opt=globalThisPolyfill=true \ - --ts_proto_opt=useExactTypes=false -# Compile TypeScript: -pnpm run build +pnpm run generate # generate TypeScript from proto files into ./out (requires protoc) +pnpm run build # compile ./out into ./dist ``` +The protoc flags live in the `generate` script in `package.json`; CI runs the same +script, so keep changes in one place. `--ts_proto_opt=importSuffix=.js` is required — +the package compiles as ESM with `moduleResolution: NodeNext`, which needs explicit +file extensions on relative imports. + +The npm package is ESM-only (`"type": "module"` plus an `exports` map). The `.` entry +uses a `default` condition rather than `import`, so `require()` still resolves on +Node.js 22.12+ via `require(esm)`. ### C#/.NET ``` diff --git a/README.npm.md b/README.npm.md index 95bd9896..68938c10 100644 --- a/README.npm.md +++ b/README.npm.md @@ -8,6 +8,29 @@ TypeScript protobuf definitions for Blueye Robotics protocols generated using [t npm install @blueyerobotics/protocol-definitions ``` +## Module format + +This package is published as **ESM only**. `import` works natively: + +```ts +import { blueye } from "@blueyerobotics/protocol-definitions"; +``` + +CommonJS consumers can still `require()` it on Node.js 22.12+ (or 20.19+), which +supports `require()` of ES modules: + +```js +const { blueye } = require("@blueyerobotics/protocol-definitions"); +``` + +On older Node.js versions `require()` fails with `ERR_REQUIRE_ESM` — use `import` +or a dynamic `await import()` instead. + +The package root is the supported entry point. Individual generated modules stay +reachable under `./dist/` (for example +`@blueyerobotics/protocol-definitions/dist/telemetry.js`) if you want to import a +single protocol file to keep bundles small. + ## Usage ```ts diff --git a/package.json b/package.json index e5dbd325..73988db1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@blueyerobotics/protocol-definitions", - "version": "3.2.0", + "version": "4.0.0", "license": "LGPL-3.0-only", "description": "TypeScript definitions for Blueye Robotics protocols", "repository": { @@ -11,14 +11,16 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js" - } + "default": "./dist/index.js" + }, + "./dist/*": "./dist/*" }, "types": "./dist/index.d.ts", "files": [ "dist" ], "scripts": { + "generate": "rm -rf out && mkdir -p out && protoc protobuf_definitions/*.proto --plugin=./node_modules/.bin/protoc-gen-ts_proto --proto_path=protobuf_definitions --ts_proto_out=./out --ts_proto_opt=outputIndex=true --ts_proto_opt=globalThisPolyfill=true --ts_proto_opt=useExactTypes=false --ts_proto_opt=esModuleInterop=true --ts_proto_opt=importSuffix=.js", "build": "tsc" }, "dependencies": { From eae27cda4200287f2be4315903a34aaea6056371 Mon Sep 17 00:00:00 2001 From: Arechi Date: Tue, 18 Aug 2026 21:04:01 +0200 Subject: [PATCH 3/5] docs: clarify module format in npm README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "ESM only" reads as "you cannot require this", which is not true here — require() resolves on Node 22.12+ via require(esm). Lead with what both loaders actually do instead. Co-Authored-By: Claude Opus 5 --- README.npm.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.npm.md b/README.npm.md index 68938c10..df805664 100644 --- a/README.npm.md +++ b/README.npm.md @@ -10,14 +10,15 @@ npm install @blueyerobotics/protocol-definitions ## Module format -This package is published as **ESM only**. `import` works natively: +This package ships ES modules only — there is no separate CommonJS build. Both +`import` and `require()` work on current Node.js releases. ```ts import { blueye } from "@blueyerobotics/protocol-definitions"; ``` -CommonJS consumers can still `require()` it on Node.js 22.12+ (or 20.19+), which -supports `require()` of ES modules: +`require()` is supported on Node.js 22.12+ (or 20.19+), which can load an ES +module from CommonJS: ```js const { blueye } = require("@blueyerobotics/protocol-definitions"); From c56e02382cf85c119e52828104b8a095cb502b96 Mon Sep 17 00:00:00 2001 From: Arechi Date: Tue, 18 Aug 2026 21:04:21 +0200 Subject: [PATCH 4/5] docs: clarify module format in CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match the README wording — "ESM-only" implies require() is unavailable, which it is not. Also record why the exports map uses a `default` condition, so it does not get "corrected" back to `import` later. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c6e44e63..0440ca9d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,9 +30,11 @@ script, so keep changes in one place. `--ts_proto_opt=importSuffix=.js` is requi the package compiles as ESM with `moduleResolution: NodeNext`, which needs explicit file extensions on relative imports. -The npm package is ESM-only (`"type": "module"` plus an `exports` map). The `.` entry -uses a `default` condition rather than `import`, so `require()` still resolves on -Node.js 22.12+ via `require(esm)`. +The npm package ships ES modules only — `"type": "module"` plus an `exports` map, +with no separate CommonJS build. The `.` entry uses a `default` condition rather +than `import`, so `require()` still resolves on Node.js 22.12+ via `require(esm)`; +an `import` condition would match ESM callers only and fail everything else with +`ERR_PACKAGE_PATH_NOT_EXPORTED`. The `./dist/*` subpath keeps deep imports working. ### C#/.NET ``` From 24b386b83ddd83bd8575abeffd6efb365aec9c0e Mon Sep 17 00:00:00 2001 From: Arechi Date: Fri, 21 Aug 2026 12:03:01 +0200 Subject: [PATCH 5/5] docs: state the protocol version in the npm README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The published README (README.npm.md, copied over README.md at publish time) never mentioned that this implements protocol v3, so npm consumers had no signal beyond inferring it from the leading version digit. That inference was never reliable — the NuGet package sits at 5.4.0 for the same protocol v3 — so state it explicitly and note that the package version is a separate axis. Co-Authored-By: Claude Opus 5 --- README.npm.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.npm.md b/README.npm.md index df805664..efb261c5 100644 --- a/README.npm.md +++ b/README.npm.md @@ -2,6 +2,16 @@ TypeScript protobuf definitions for Blueye Robotics protocols generated using [ts-proto](https://github.com/stephenh/ts-proto). +## Protocol version + +This package implements **version 3** of the Blueye communication protocol, used by +drones running Blunux 3.0 and newer. Older drones use the separate +[legacy protocol](https://github.com/BluEye-Robotics/blueye.legacyprotocol). + +The npm version above tracks releases of *this package* — packaging, module format +and generated API surface — and is independent of the protocol version. A major +version bump here does not indicate a new protocol generation. + ## Installation ```bash