Skip to content

feat: @padosoft/ecr17-node (Node.js API) and a production POSIX transport - #28

Open
47PADO47 wants to merge 3 commits into
chore/monorepofrom
feat/ecr17-node
Open

47PADO47 wants to merge 3 commits into
chore/monorepofrom
feat/ecr17-node

Conversation

@47PADO47

@47PADO47 47PADO47 commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Stacked on #26.

The layering is now one C++ core with thin API packages on top:

@padosoft/ecr17          C++ core: protocol, session, money-safe client, PosixTransport + WinsockTransport
  ├─ @padosoft/ecr17-node          Node.js API (this PR)
  ├─ @padosoft/react-native-ecr17  Nitro binding
  └─ (later) Swift, Kotlin/AAR, C API + .NET

@padosoft/ecr17-node has the same createEcr17Client, methods, requests, results and events as @padosoft/react-native-ecr17. It runs on the same C++ client through Node-API, so the money-safety logic still exists only once.

import { createEcr17Client } from "@padosoft/ecr17-node";
const client = createEcr17Client({ host: "192.168.1.50", terminalId: "12345678", cashRegisterId: "00000001" });
const result = await client.pay({ amountCents: 650 });
  • PosixTransport (in the core, packages/ecr17/posix, macOS/Linux) is a port of WinsockTransport: write-free MSG_PEEK pre-send probe, one drop signal, and no SIGPIPE. It has 14 loopback tests, run by cpp-tests on Linux. The real-terminal test now uses it, and the test-only PosixTcpTransport is removed.
  • Addon (packages/ecr17-node/node/addon.cpp, Node-API 8, cmake-js): requests go in, the core's raw structs come out, and src/mappers.ts mirrors HybridEcr17Client.cpp.
    • Each client owns one worker thread, so the event loop and libuv's pool are never blocked.
    • Results and events share one ordered queue.
    • An idle client doesn't keep the process alive.
    • It finds the core through -DECR17_DIR, Node resolution, or the monorepo sibling.
  • TypeScript (src/): built with tsdown through @padosoft/config (ESM + CJS). The addon is loaded from build/Release/ or prebuilds/<platform>-<arch>/, or from ECR17_NODE_ADDON if set.
  • Tests: 17 Node tests drive TS → addon → core → TCP against a scripted fake terminal. The money-safety test checks that a payment interrupted by a drop goes out exactly once and that sendLastResult recovers it. It was mutation-checked.
  • CI: the new node.yml builds and tests the addon on linux-x64, linux-arm64, darwin-arm64 and win32-x64. It also typechecks with a self-contained tsconfig.ci.json, because CI's token gets 401 on the private @padosoft/config, and builds with tsdown. The release workflow calls it and ships the prebuilds.

Bugs found and fixed while testing:

  • Event ordering: a payment's promise could resolve before its progress event.
  • Exit crash: SIGABRT at process exit, because Node finalizes thread-safe functions before object finalizers.
  • Listener errors: they were swallowed silently.
  • Test hang: a missing addon hung the test suite.

Verified locally on macOS:

  • 114 C++ tests.
  • 17 Node tests, including a build through the monorepo-sibling fallback with no workspace install.
  • Four teardown scenarios, all exit 0.

CI was green on all four platforms on the previous push.

Not done:

Next, per the agreed plan: a separate PR that switches the RN binding to PosixTransport on iOS and Android and removes the Swift/Kotlin transports. It's gated on a real-terminal test.

🤖 Generated with Claude Code

47PADO47 and others added 2 commits October 6, 2026 00:04
…sport

- PosixTransport (packages/ecr17/posix, macOS/Linux): a port of WinsockTransport with the
  same contract (write-free MSG_PEEK pre-send probe, one drop signal, no byte consumed)
  plus no SIGPIPE (MSG_NOSIGNAL / SO_NOSIGPIPE). It has 14 loopback tests, run by
  cpp-tests on Linux. The opt-in real-terminal test now uses the host's production
  transport, and the test-only PosixTcpTransport is gone.
- Node.js API: src/ (TypeScript Ecr17Client with the same API and types as
  @padosoft/react-native-ecr17, built with tsdown through @padosoft/config) over
  node/addon.cpp (Node-API 8, cmake-js). Each client has one worker thread, so commands
  never block the event loop or libuv's thread pool. Results and events share one ordered
  queue, so a command's events always arrive before its result. An idle client doesn't
  keep the process alive. A throwing listener surfaces as uncaughtException.
- 17 Node tests drive TypeScript -> addon -> core -> TCP against a scripted fake terminal.
  The money-safety test (a payment interrupted by a drop goes out exactly once, and
  sendLastResult recovers it) was mutation-checked.
- CI: node.yml builds and tests the addon on linux-x64, linux-arm64, darwin-arm64 and
  win32-x64, and runs typecheck + tsdown. The release workflow calls it and ships
  packages/ecr17/prebuilds/<platform>-<arch>/ecr17.node.
- Docs: apps/docs/docs/nodejs.md, the core README, the main README (feature table,
  roadmap, tests), AGENTS.md, LESSON.md, PROGRESS.md.

Verified locally on macOS: 114 C++ tests, 17 Node tests (30 consecutive clean runs), and
the teardown scenarios (never closed, process.exit with a pending command, close during a
command, throwing listener), which all exit 0. Linux and Windows are verified by CI only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's GESCAT_NPM_TOKEN gets 401 from GitHub Packages, so the TS job now strips the private
deps like ts-checks: it typechecks with a self-contained tsconfig.ci.json (the preset's strict
options) and builds with tsdown --no-config and the preset's flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Deploying react-native-ecr17-protocol with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1365a03
Status:🚫  Build failed.

View logs

…node

The core npm package (@padosoft/ecr17) goes back to pure C++ source: protocol, session,
money-safe client, and the POSIX + Winsock transports, plus its pod, Swift package and
Expo plugin. Every API package layers on it: the React Native binding, and now
@padosoft/ecr17-node (src/, node/, test/, dist/ and prebuilds/), version 2.0.0 in
lockstep with the core.

- node/CMakeLists.txt finds the core through -DECR17_DIR, then Node resolution of
  @padosoft/ecr17, then the monorepo sibling (CI installs no workspace).
- CI, release (prebuilds, dist), strip-private-deps, .gitignore, READMEs, the docs page,
  AGENTS, LESSON and PROGRESS now use the new package.
- A missing addon no longer hangs the Node suite: setup closes the fake terminal when the
  client can't be created.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@47PADO47 47PADO47 changed the title feat(ecr17): Node.js API (Node-API addon) and a production POSIX transport feat: @padosoft/ecr17-node (Node.js API) and a production POSIX transport Oct 5, 2026
@47PADO47
47PADO47 added this pull request to stack #27 October 6, 2026 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant