fix: correct package entry points and publish contents

Five packaging defects, all pre-existing:

1. dist/esm/index.js held ESM syntax while the package is not
   "type": "module", so Node classified it as CommonJS. It failed
   outright on Node 18 ("Unexpected token 'export'") and only worked on
   Node >= 22 because Node re-parses after guessing the module type,
   paying that cost on every import. Bundles now carry explicit
   extensions: .mjs for ES output, .cjs/.js for CommonJS. The browser
   build gained a real CommonJS output too — the exports map previously
   pointed the browser "require" condition at an ES module.
   The exports map now also leads with "types" and ends with a "default"
   fallback for resolvers matching neither "node" nor "browser".

2. files: ["native"] published the local build directory: a 94.6 kB
   Linux-x64 .node binary, a 148 kB object file and generated Makefiles.
   node-gyp-build checks build/Release before prebuilds, so every
   consumer on every platform would have found this machine's binary,
   skipped compiling, and failed to load it. It fails safe (native/
   index.js catches and returns null), but the addon could never work
   for anyone else. Narrowed to the four source files.

3. binding.gyp resolves node-addon-api at build time, but nothing
   declared it: it was a devDependency of the root, absent from
   native/package.json. The build only succeeded here because a dev
   install populates the root node_modules. Declared as a dependency of
   the native package, where it is actually needed.

4. No clean step, so stale output shipped — the tarball carried both
   dist/types/core/** and a dist/types/src/** tree left over from before
   rootDir was set. build now runs clean first.

5. test:browser ran `karma start` with no karma.conf.js anywhere in the
   repo, and tests/browser is an empty directory. Removed the script and
   the karma devDependency rather than leave a script that cannot run.

Verified: CommonJS require and ESM import both resolve on Node 18.19.1
and 24.18.0; TypeScript resolves types under both bundler and node16;
npm pack now produces 35 files / 103.8 kB with no build artefacts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Alpha Nerd 2026-07-19 12:39:09 +02:00
parent eafab3d9ac
commit 111335d7ff
Signed by: alpha-nerd
SSH key fingerprint: SHA256:QkkAgVoYi9TQ0UKPkiKSfnerZy2h4qhi3SVPXJmBN+M
8 changed files with 43 additions and 2514 deletions

View file

@ -38,7 +38,7 @@ client.dispose();
```html
<script type="module">
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.js';
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.mjs';
const client = new SecureChatCompletion({
baseUrl: 'https://api.nomyo.ai',

View file

@ -305,7 +305,7 @@ console.log('Answer:', content); // final answer to the user
<div id="output"></div>
<script type="module">
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.js';
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.mjs';
// In production, proxy through your backend instead of exposing the API key
const client = new SecureChatCompletion({

View file

@ -244,7 +244,7 @@ In browsers, keys are kept in memory only (no file system). Everything else is i
```html
<script type="module">
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.js';
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.mjs';
const client = new SecureChatCompletion({
baseUrl: 'https://api.nomyo.ai',

View file

@ -24,7 +24,7 @@ pnpm add nomyo-js
```html
<script type="module">
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.js';
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.mjs';
// ...
</script>
```

View file

@ -11,6 +11,7 @@
},
"gypfile": true,
"dependencies": {
"node-addon-api": "^8.6.0",
"node-gyp-build": "^4.8.0"
},
"devDependencies": {

2495
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,35 +3,39 @@
"version": "0.3.0",
"description": "OpenAI-compatible secure chat client with end-to-end encryption",
"main": "dist/node/index.js",
"browser": "dist/browser/index.js",
"module": "dist/esm/index.js",
"browser": "dist/browser/index.mjs",
"module": "dist/esm/index.mjs",
"types": "dist/types/index.d.ts",
"exports": {
".": {
"node": {
"require": "./dist/node/index.js",
"import": "./dist/esm/index.js"
},
"types": "./dist/types/index.d.ts",
"browser": {
"import": "./dist/browser/index.js",
"require": "./dist/browser/index.js"
"import": "./dist/browser/index.mjs",
"require": "./dist/browser/index.cjs"
},
"types": "./dist/types/index.d.ts"
"node": {
"import": "./dist/esm/index.mjs",
"require": "./dist/node/index.js"
},
"default": "./dist/browser/index.mjs"
}
},
"files": [
"dist",
"native",
"native/binding.gyp",
"native/index.js",
"native/package.json",
"native/src",
"README.md",
"LICENSE"
],
"scripts": {
"build": "npm run build:node && npm run build:browser && npm run build:types",
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
"build": "npm run clean && npm run build:node && npm run build:browser && npm run build:types",
"build:node": "rollup -c --environment TARGET:node",
"build:browser": "rollup -c --environment TARGET:browser",
"build:types": "tsc --emitDeclarationOnly",
"test": "jest",
"test:browser": "karma start",
"prepublishOnly": "npm run build && npm test"
},
"keywords": [
@ -55,7 +59,6 @@
"@types/jest": "^30.0.0",
"@types/node": "^24.0.0",
"jest": "^30.0.0",
"karma": "^6.4.0",
"node-addon-api": "^8.6.0",
"node-gyp": "^13.0.0",
"node-gyp-build": "^4.8.0",

View file

@ -17,6 +17,10 @@ const config = {
]
};
// Extensions are explicit rather than bare `.js`: the package is not
// "type": "module", so Node treats a .js file as CommonJS. An ES-format bundle
// named .js therefore fails to import on Node < 22, and only works above that
// because Node re-parses it after guessing — at a cost on every import.
if (target === 'node') {
config.output = [
{
@ -25,17 +29,25 @@ if (target === 'node') {
exports: 'named'
},
{
file: 'dist/esm/index.js',
file: 'dist/esm/index.mjs',
format: 'es'
}
];
config.external = ['crypto', 'https', 'fs', 'path'];
} else if (target === 'browser') {
config.output = {
file: 'dist/browser/index.js',
format: 'es',
name: 'Nomyo'
};
config.output = [
{
file: 'dist/browser/index.mjs',
format: 'es',
name: 'Nomyo'
},
{
file: 'dist/browser/index.cjs',
format: 'cjs',
exports: 'named',
name: 'Nomyo'
}
];
}
export default config;