Skip to content

v2.0.0: TypeScript rewrite with full v1 compatibility#36

Merged
gdespirito merged 2 commits into
masterfrom
v2
Jul 11, 2026
Merged

v2.0.0: TypeScript rewrite with full v1 compatibility#36
gdespirito merged 2 commits into
masterfrom
v2

Conversation

@gdespirito

@gdespirito gdespirito commented Jul 11, 2026

Copy link
Copy Markdown
Member

Summary

Complete rewrite of the library in strict TypeScript (Node >= 18.17), keeping the entire v1 API working unchanged through a deprecated compatibility layer. Existing v1 code runs as-is; the only hard break is the Node version requirement.

Fixes long-standing issues

What's inside

  • Typed events (loginRequest, ping, alarm, parseError, ...) with a GpsPosition payload
  • Dual ESM/CJS build with tsup; types included
  • 61 tests: parser fixtures from official protocol docs (Concox GK309 V1.8, HuaSunTeK H02 V1.0.5, Traccar test suite) + real-TCP integration tests (fragmentation, RST resilience, timeouts) + v1 compat tests (the v1 README example runs verbatim)
  • ESLint 9 + typescript-eslint, CI matrix (Node 18/20/22), release workflow with npm provenance
  • New README + MIGRATION.md with the full v1→v2 mapping and behaviour notes

Compatibility

gps.server(options, callback), snake_case events, login_authorized(true), string adapter names and custom v1 adapter modules all keep working, marked @deprecated (one DeprecationWarning per process). Documented behaviour changes (GT06 ids without the leading BCD zero, TK510 dates read as DDMMYY, UTC timestamps) are listed in MIGRATION.md.

Release plan

Publish as 2.0.0-beta.1 (npm publish --tag beta) before the final 2.0.0. Requires the NPM_TOKEN secret for the release workflow.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KUhDLb7eGUBraFsnhBoRGm

Summary by CodeRabbit

  • New Features
    • Introduced a TypeScript v2 API for GPS tracking servers and connected devices, including typed events, improved TCP framing, CRC validation, geo utilities, and structured error handling.
    • Added built-in adapters for TK103, TK510, GT06/GK309, GT02A, and ST-901 (H02).
    • Added a deprecated v1 compatibility layer and published dual ESM/CommonJS builds with TypeScript declarations.
  • Documentation
    • Added a comprehensive README and a v1-to-v2 MIGRATION guide; removed the legacy README.
  • Tests / Chores
    • Added CI + automated lint/typecheck/build/test and release publishing workflows, along with extensive unit and integration tests.

Complete rewrite of the library in strict TypeScript (Node >= 18.17),
keeping the entire v1 API working through a deprecated compat layer.

Highlights:
- Zero runtime dependencies: own CRC-16/X-25 replaces crc,
  crc16-ccitt-node, node.extend and the undeclared crc-itu (#25, #30)
- Proper TCP framing: fragmented/coalesced packets are reassembled
  (v1 assumed 1 socket event = 1 packet)
- Socket errors no longer crash the process (#12); idle connections
  are destroyed after a configurable timeout (#31)
- New protocols: SinoTrack ST-901 / H02 (#19) and Concox GK309 (#26),
  which also fixes the wrong CRC variant used for GT06 acks
- Typed events, dual ESM/CJS build (tsup), vitest suite (61 tests with
  fixtures from official protocol docs + real TCP integration tests),
  ESLint, CI matrix for Node 18/20/22 and npm publish with provenance
- v1 API (gps.server, snake_case events, custom v1 adapters) still
  works unchanged; using it emits one DeprecationWarning per process.
  See MIGRATION.md for the mapping and behaviour notes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KUhDLb7eGUBraFsnhBoRGm
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6841122b-e3c9-4ff8-8c20-7e295fb1a562

📥 Commits

Reviewing files that changed from the base of the PR and between 3f9d453 and 42a61d4.

📒 Files selected for processing (15)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • README.md
  • eslint.config.js
  • examples/simple.ts
  • src/adapters/tk103.ts
  • src/adapters/tk510.ts
  • src/compat.ts
  • src/framing/delimiter-framer.ts
  • src/lib/geo.ts
  • src/lib/protocol.ts
  • src/server.ts
  • test/integration/compat.test.ts
  • test/unit/framers.test.ts
  • test/unit/geo.test.ts
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (13)
  • test/unit/geo.test.ts
  • examples/simple.ts
  • eslint.config.js
  • .github/workflows/release.yml
  • src/lib/geo.ts
  • test/unit/framers.test.ts
  • test/integration/compat.test.ts
  • src/framing/delimiter-framer.ts
  • src/server.ts
  • src/lib/protocol.ts
  • src/compat.ts
  • src/adapters/tk510.ts
  • src/adapters/tk103.ts

📝 Walkthrough

Walkthrough

Changes

This change introduces a TypeScript v2 GPS tracking server with TCP framing, typed events, five built-in protocol adapters, a deprecated v1 compatibility layer, ESM/CJS packaging, migration documentation, CI/release workflows, and unit and integration tests.

GPS tracking server v2

Layer / File(s) Summary
Packaging, tooling, and migration documentation
.github/workflows/*, package.json, tsconfig.json, eslint.config.js, README.md, MIGRATION.md, examples/*
Adds build, lint, typecheck, test, CI, release, packaging, migration, and usage documentation for the v2 implementation.
Public contracts, framing, and shared utilities
src/types.ts, src/framing/*, src/lib/*, src/errors.ts, src/typed-emitter.ts, src/index.ts
Defines the public API, typed events, error hierarchy, stream framers, CRC/geographic/protocol helpers, and package exports.
TCP server and device lifecycle
src/server.ts, src/device.ts
Adds TCP listening, device tracking, framing, authentication, packet dispatch, acknowledgements, timeouts, disconnect handling, and device messaging.
Built-in protocol adapters
src/adapters/*
Adds TK103, TK510, GT06/GK309, GT02A, and ST901 protocol parsing, framing, GPS/alarm decoding, and responses.
Legacy v1 compatibility layer
src/compat.ts
Bridges legacy server, device, events, adapter modules, options, and methods onto the v2 implementation with deprecation warnings.
Protocol and integration validation
test/unit/*, test/integration/*, test/helpers/*
Adds tests for utilities, framers, adapters, TCP behavior, compatibility behavior, and cleanup helpers.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GPSClient
  participant GpsServer
  participant Device
  participant Adapter
  GPSClient->>GpsServer: Open TCP connection
  GpsServer->>Device: Create device connection
  GPSClient->>Device: Send protocol frame
  Device->>Adapter: Parse frame
  Adapter-->>Device: Return parsed packet
  Device-->>GpsServer: Emit device or packet event
  Adapter->>GPSClient: Send login or packet acknowledgement
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a TypeScript v2 rewrite while preserving v1 compatibility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v2

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (1)
.github/workflows/release.yml (1)

20-25: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid running the release checks twice.

package.json defines prepublishOnly to run typecheck, lint, build, and tests; npm publish invokes that lifecycle hook. Lines 21–24 therefore repeat the same work before publishing. Remove the explicit duplicates or narrow prepublishOnly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 20 - 25, Update the release
workflow steps surrounding npm publish to remove the explicit typecheck, lint,
build, and test commands, since npm publish invokes package.json’s
prepublishOnly hook. Keep npm ci and the publish command unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 15: Update the actions/checkout@v4 step in the CI workflow to set
persist-credentials to false, preventing the checkout token from remaining in
local Git configuration before later npm scripts execute.

In @.github/workflows/release.yml:
- Line 14: Update the actions/checkout@v4 step in the release workflow to set
persist-credentials to false, ensuring the checkout does not retain the GitHub
token in local Git configuration while preserving the existing checkout
behavior.

In `@eslint.config.js`:
- Around line 11-12: Update the ESLint configuration’s tsconfigRootDir setting
to use a Node 18-compatible directory lookup via fileURLToPath(new URL('.',
import.meta.url)), adding the required URL-to-path import if needed, and
preserve projectService: true.

In `@examples/simple.ts`:
- Line 3: Update the run instruction comment in examples/simple.ts to remove the
plain tsc compilation note, leaving only the npx tsx command or replacing it
with a verified emitting build command.

In `@package.json`:
- Around line 62-65: Align the eslint toolchain with the project’s advertised
Node 18.17 minimum by downgrading both eslint and `@eslint/js` from version 10 to
compatible versions. Keep the package runtime metadata and CI minimum unchanged
unless intentionally raising them together.

In `@README.md`:
- Around line 7-8: Update the README project description to state Node.js
>=18.17 instead of Node.js >=18, matching the minimum version required by
package.json and MIGRATION.md.

In `@src/adapters/tk103.ts`:
- Around line 93-116: Update `#parsePosition` to require the complete course field
before constructing the GpsPosition: increase the minimum payload-length
validation to cover the data.slice(39, 45) range, while preserving the existing
coordinate and position parsing behavior.

In `@src/adapters/tk510.ts`:
- Around line 74-76: In the `9999` case, validate that `data.length` is at least
one before calling `data.readUInt8(0)`, and throw the adapter’s
`PacketParseError` for an empty payload so corrupt packets follow the
established contract.

In `@src/compat.ts`:
- Around line 112-146: Preserve the parsed login packet separately in the
frame-handling logic around `#lastParts` and the login_request case, rather than
allowing subsequent frames to replace it. Update authorize() to pass the stored
login packet to `#instance.authorize`, while retaining the existing parsing
behavior for other packet types.

In `@src/framing/delimiter-framer.ts`:
- Around line 42-50: Update the delimiter-processing loop around the buffer
length check and frames.push so completed frames are also limited by
`#maxFrameLength`: when the segment through the detected end delimiter exceeds the
cap, discard it instead of emitting it. Preserve normal emission and buffer
advancement for frames within the limit.

In `@src/lib/geo.ts`:
- Around line 16-21: Update minuteToDecimal to validate the parsed minutes
component before returning a coordinate: reject values where minutes are outside
the valid NMEA range of 0–59, including malformed values such as 1260.000, by
returning the existing invalid-coordinate representation expected by downstream
NaN checks. Preserve the hemisphere sign handling for valid inputs.

In `@src/lib/protocol.ts`:
- Around line 17-22: Update digits2 and the timestamp parsing flow to reject
malformed two-character fields instead of accepting partial parseInt results,
and validate all parsed date/time components before constructing the Date.
Ensure invalid or overflowing values, including out-of-range months and
normalized dates, are rejected rather than passed to Date.UTC.

In `@src/server.ts`:
- Around line 113-115: Update the device event handling in the server connection
setup so the `identified` listener does not add sockets to `#devices`; keep
those sockets tracked only in `#connections`. Register the device in `#devices`
from its authenticated `login` event, after `acceptLogin()` succeeds, preserving
`sendTo()` routing exclusively for authenticated connections.

In `@test/integration/compat.test.ts`:
- Around line 75-82: Update the test around startLegacyServer to install the
process.emitWarning spy before the first legacy-server creation in the worker,
or isolate the module so the warning is observable. Change the final assertion
to require exactly one DeprecationWarning call while preserving the two
server-creation checks.

---

Nitpick comments:
In @.github/workflows/release.yml:
- Around line 20-25: Update the release workflow steps surrounding npm publish
to remove the explicit typecheck, lint, build, and test commands, since npm
publish invokes package.json’s prepublishOnly hook. Keep npm ci and the publish
command unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64b9b455-912b-4e4f-b270-bd9aa31b94d1

📥 Commits

Reviewing files that changed from the base of the PR and between 0844102 and 3f9d453.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (53)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .gitignore
  • .jscsrc
  • MIGRATION.md
  • README.md
  • eslint.config.js
  • examples/legacy-v1.cjs
  • examples/simple.js
  • examples/simple.ts
  • index.js
  • lib/adapters/gt02a.js
  • lib/adapters/gt06.js
  • lib/adapters/tk103.js
  • lib/adapters/tk510.js
  • lib/device.js
  • lib/functions.js
  • lib/server.js
  • package.json
  • readme.md
  • src/adapters/base-adapter.ts
  • src/adapters/gt02a.ts
  • src/adapters/gt06.ts
  • src/adapters/index.ts
  • src/adapters/st901.ts
  • src/adapters/tk103.ts
  • src/adapters/tk510.ts
  • src/compat.ts
  • src/device.ts
  • src/errors.ts
  • src/framing/delimiter-framer.ts
  • src/framing/framer.ts
  • src/framing/length-prefixed-framer.ts
  • src/index.ts
  • src/lib/crc.ts
  • src/lib/geo.ts
  • src/lib/protocol.ts
  • src/server.ts
  • src/typed-emitter.ts
  • src/types.ts
  • test/helpers/fake-device.ts
  • test/helpers/tcp.ts
  • test/integration/compat.test.ts
  • test/integration/server.test.ts
  • test/unit/crc.test.ts
  • test/unit/framers.test.ts
  • test/unit/geo.test.ts
  • test/unit/gt02a.test.ts
  • test/unit/gt06.test.ts
  • test/unit/st901.test.ts
  • test/unit/tk103.test.ts
  • test/unit/tk510.test.ts
  • tsconfig.json
💤 Files with no reviewable changes (11)
  • index.js
  • examples/simple.js
  • lib/adapters/tk510.js
  • readme.md
  • lib/device.js
  • .jscsrc
  • lib/adapters/tk103.js
  • lib/adapters/gt02a.js
  • lib/functions.js
  • lib/server.js
  • lib/adapters/gt06.js

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/release.yml
Comment thread eslint.config.js Outdated
Comment thread examples/simple.ts Outdated
Comment thread package.json
Comment on lines +62 to +65
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/node": "^18.19.0",
"eslint": "^10.7.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/sh
npm view eslint@10 engines --json
npm view `@eslint/js`@10 engines --json

Repository: freshworkstudio/gps-tracking-nodejs

Length of output: 1260


🏁 Script executed:

#!/bin/sh
set -eu

printf '\n== package.json ==\n'
cat -n package.json | sed -n '1,140p'

printf '\n== package-lock candidates ==\n'
git ls-files 'package-lock.json' 'npm-shrinkwrap.json' || true

printf '\n== eslint package metadata ==\n'
npm view eslint@10 version engines --json
printf '\n== `@eslint/js` package metadata ==\n'
npm view `@eslint/js`@10 version engines --json

Repository: freshworkstudio/gps-tracking-nodejs

Length of output: 4382


🏁 Script executed:

#!/bin/sh
set -eu

python3 - <<'PY'
import json, subprocess

for pkg in ["eslint@10", "`@eslint/js`@10"]:
    out = subprocess.check_output(["npm","view",pkg,"version","engines","--json"], text=True)
    print(f"\n## {pkg}\n{out}")
PY

Repository: freshworkstudio/gps-tracking-nodejs

Length of output: 2044


🏁 Script executed:

#!/bin/sh
set -eu

# Show just the dependency declarations around the reported lines.
sed -n '55,75p' package.json

Repository: freshworkstudio/gps-tracking-nodejs

Length of output: 654


Keep the lint toolchain aligned with the Node 18.17 floor. eslint@10 requires Node >=20.19.0, and @eslint/js@10.0.1 matches that requirement, so lint/prepublishOnly won’t work on the advertised runtime range. Downgrade both to a Node-18-compatible line or raise the package and CI minimum together.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 62 - 65, Align the eslint toolchain with the
project’s advertised Node 18.17 minimum by downgrading both eslint and
`@eslint/js` from version 10 to compatible versions. Keep the package runtime
metadata and CI minimum unchanged unless intentionally raising them together.

Comment thread src/framing/delimiter-framer.ts
Comment thread src/lib/geo.ts
Comment thread src/lib/protocol.ts Outdated
Comment thread src/server.ts Outdated
Comment thread test/integration/compat.test.ts Outdated
- CI/release: set persist-credentials: false on checkout (zizmor artipacked)
- CI: run ESLint in a separate Node 22 job (eslint@10 needs Node >= 20.19,
  above the package's 18.17 runtime floor)
- eslint.config: Node 18-compatible dirname via fileURLToPath
- Server: register devices in the routable map only after login, so an
  unauthenticated peer cannot hijack an existing id via getDevice()/sendTo()
- DelimiterFramer: drop oversized frames even when properly terminated
- minuteToDecimal/utcDate/digits2: reject malformed coordinates and
  overflowing timestamps instead of emitting bogus fixes
- TK103: require the course field in position payloads (min length 45)
- TK510: explicit PacketParseError for empty alarm payloads
- Compat: preserve the pending login parts for authorize() even if other
  frames are parsed in between
- Tests: assert exactly one DeprecationWarning on a fresh module registry;
  regression tests for the framer cap and coordinate validation
- README/examples: Node >= 18.17 wording, drop the tsc compile note

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KUhDLb7eGUBraFsnhBoRGm
@gdespirito
gdespirito merged commit 8937096 into master Jul 11, 2026
6 checks passed
@gdespirito
gdespirito deleted the v2 branch July 11, 2026 07:50
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