Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/esm-node-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@monetizationos/proxy': patch
---

Publish an ESM build Node resolves without a bundler. The emitted JavaScript and type declarations previously carried extensionless relative specifiers, so importing the package from plain Node failed with `ERR_UNSUPPORTED_DIR_IMPORT` and a consumer on `moduleResolution: NodeNext` could not resolve its types. Self-hosted Node integrations no longer need a build step.
9 changes: 7 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ pnpm lint
pnpm typecheck
pnpm test:run
pnpm build
pnpm verify:package
```

Notes:

- `pnpm test` starts watch mode; use `pnpm test:run` in agents and CI.
- `pnpm typecheck` covers `src/**/*.ts` and `test/**/*.ts`; `pnpm build` emits only `src/` to `dist/`.
- `pnpm typecheck` covers `src/**/*.ts` and `test/**/*.ts`; `pnpm build` runs `pnpm clean`, emits only `src/` to `dist/`, then rewrites the emitted specifiers with `tsc-alias`.
- `pnpm clean` removes `dist/`. Anything that needs an empty `dist/` calls it rather than deleting the directory itself, so `tsc` never inherits outputs from a source file that has since been renamed or deleted.
- `pnpm verify:package` packs the tarball, installs it into a scratch consumer, then scans the installed `dist` for relative specifiers Node cannot resolve, imports the package from plain Node, and type-checks against it on `moduleResolution: NodeNext`. It does not build; `prepack` does, so the tarball it verifies is produced the same way the published one is. Run it when you touch packaging, `tsconfig*.json`, or the shape of an import; CI runs it on Node 22 and 24, the only versions this package supports.
- If lint fails, run `pnpm format`, then rerun `pnpm lint`.
- Do not commit `dist/`, `node_modules/`, `coverage/`, or lockfile changes unless dependencies changed.

Expand Down Expand Up @@ -54,6 +57,7 @@ Stages 3-6 are HTML-only and auto-skip otherwise. `.withoutHtmlTransformation()`

- Keep `src/` runtime code edge-safe: no Node-only APIs such as `fs`, `path`, `process`, or `Buffer`. This applies to executable code; JSDoc examples may reference consumer-side patterns like `process.env`.
- Use ESM `import`/`export`; no `require`.
- Relative specifiers stay extensionless, including directory imports of a barrel: `'./config'`, `'./adapters'`. `moduleResolution: Bundler` accepts that form, and `tsc-alias --resolveFullPaths` rewrites every emitted `.js` and `.d.ts` to the full path Node needs. `pnpm verify:package` scans the packed `dist` and fails on any relative specifier left without a runtime extension, so the artifact is what enforces this, not the source form.
- Follow Biome formatting: 4-space indent, single quotes, no semicolons, trailing commas, LF line endings.
- `nursery.noFloatingPromises` is an error; always `await` promises or mark them with `void`.
- `noUncheckedIndexedAccess` is enabled; narrow indexed values before use.
Expand All @@ -63,5 +67,6 @@ Stages 3-6 are HTML-only and auto-skip otherwise. `.withoutHtmlTransformation()`

- User-facing changes in `src/` need a Changeset: run `pnpm changeset` and commit the generated `.changeset/*.md`.
- Package version is duplicated in `src/apiRequestHeaders.ts` as `MOS_PROXY_PACKAGE_VERSION`. If manually bumping `package.json`, also update that constant or run `node scripts/sync-version.mjs && pnpm format`.
- `prepublishOnly` runs `typecheck && test:run && build`; do not bypass it.
- `prepack` runs `build`, so every `pnpm pack` and `pnpm publish` produces a freshly built tarball no matter who invokes it. Nothing else needs to build first, which is why `verify:package` does not.
- `prepublishOnly` runs `typecheck && test:run && verify:package`; do not bypass it. It is the whole publish gate: `release.yml` only installs and hands off to the Changesets action. Note that `prepublishOnly` fires before `prepack`, so it validates the working tree rather than the finished tarball. `ci.yml` and `release.yml` are independent workflows on the same push, so a red CI run does not by itself stop a publish.
- `pnpm-workspace.yaml` sets `minimumReleaseAge: 4320`, so very recent dependency versions may be rejected during install. Choose an older version instead of disabling the setting.
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,22 @@ jobs:
- run: pnpm typecheck
- run: pnpm test:run
- run: pnpm build

package-resolution:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [22, 24]
steps:
- uses: actions/checkout@v6

- uses: pnpm/action-setup@v6

- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: pnpm

- run: pnpm install --frozen-lockfile
- run: pnpm verify:package
3 changes: 0 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ jobs:
registry-url: https://registry.npmjs.org

- run: pnpm install --frozen-lockfile
- run: pnpm run typecheck

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we not do these steps on release?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are moved into prepublishOnly, pnpm run release deals with the lifecycle

- run: pnpm run test:run
- run: pnpm run build

- name: Create Release PR or publish
uses: changesets/action@v1
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,19 @@
"access": "public"
},
"scripts": {
"build": "tsc -p tsconfig.build.json",
"clean": "rm -rf dist",
"build": "pnpm run clean && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
"prepack": "pnpm run build",
"test": "vitest",
"test:run": "vitest run",
"typecheck": "tsc --noEmit",
"verify:package": "node scripts/verify-package-resolution.mjs",
"lint": "biome check --diagnostic-level=error --no-errors-on-unmatched",
"format": "biome check --write --no-errors-on-unmatched",
"changeset": "changeset",
"version": "changeset version && node scripts/sync-version.mjs && pnpm run format",
"release": "changeset publish",
"prepublishOnly": "pnpm run typecheck && pnpm run test:run && pnpm run build"
"prepublishOnly": "pnpm run typecheck && pnpm run test:run && pnpm run verify:package"
},
"dependencies": {
"cookie": "^1.1.1"
Expand All @@ -51,6 +54,7 @@
"@changesets/cli": "^2.31.0",
"@types/node": "^24.12.3",
"html-rewriter-wasm": "^0.4.1",
"tsc-alias": "^1.9.1",
"typescript": "^6.0.3",
"vitest": "~4.1.5"
}
Expand Down
109 changes: 109 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading