5 Commits

Author SHA1 Message Date
lilleman 0f14ca85c2 Plan 0.5.0 in todo.md, holding the GitHub work until it is published
Test / lint (pull_request) Successful in 21s
Test / test (18) (pull_request) Successful in 19s
Test / test (20) (pull_request) Successful in 24s
Test / test (22) (pull_request) Successful in 19s
Test / test (24) (pull_request) Successful in 18s
Test / test (26) (pull_request) Successful in 19s
Release / publish (push) Successful in 37s
2026-09-14 14:09:58 +02:00
lilleman e8558aa471 Release as 0.5.0, and file issues on the GitHub mirror 2026-09-14 14:09:58 +02:00
lilleman 773db43305 Record the move to Gitea and the GitHub retirement in todo.md
Test / lint (pull_request) Successful in 20s
Test / test (18) (pull_request) Successful in 18s
Test / test (20) (pull_request) Successful in 17s
Test / test (22) (pull_request) Successful in 17s
Test / test (24) (pull_request) Successful in 18s
Test / test (26) (pull_request) Successful in 19s
2026-09-13 17:57:10 +02:00
lilleman 793839d0e0 Point the package and README at Gitea 2026-09-13 17:57:10 +02:00
lilleman 68cd8e3f31 Run CI, releases and Renovate on Gitea 2026-09-13 17:57:10 +02:00
10 changed files with 107 additions and 94 deletions
@@ -6,7 +6,6 @@ on:
permissions:
contents: read
id-token: write
jobs:
publish:
@@ -31,6 +30,6 @@ jobs:
}
- run: npm run lint
- run: npm test
- run: npm publish --provenance --access public
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+25
View File
@@ -0,0 +1,25 @@
name: Renovate
on:
schedule:
- cron: '43 4 * * *'
workflow_dispatch:
jobs:
renovate:
runs-on: docker-host
steps:
- name: Run Renovate against this repo
env:
GITHUB_COM_TOKEN: ${{ secrets.RENOVATE_GITHUB_TOKEN }}
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
run: |
docker run --rm \
-e GITHUB_COM_TOKEN \
-e LOG_LEVEL=info \
-e RENOVATE_ENDPOINT=https://gitea.larvit.se/api/v1 \
-e RENOVATE_GIT_AUTHOR="Renovate Bot <renovate@larvit.se>" \
-e RENOVATE_PLATFORM=gitea \
-e RENOVATE_REPOSITORIES=${{ github.repository }} \
-e RENOVATE_TOKEN \
renovate/renovate:44.39.2
@@ -1,8 +1,6 @@
name: Test
on:
push:
branches-ignore: ['main']
pull_request:
permissions:
+10 -9
View File
@@ -5,7 +5,7 @@ Guidance for LLM agents working in this repository. What each file in it is for
## What this is
A ground-up TypeScript rewrite of `larvitsmpp` 0.4.0, published as `@larvit/smpp` 1.0.0. The branch
A ground-up TypeScript rewrite of `larvitsmpp` 0.4.0, published as `@larvit/smpp` 0.5.0. The branch
started from an orphan commit — no history from 0.4.0 is carried over. The 0.4.0 source is still
readable on the `v0.4.0` branch of the same repository and is the reference for protocol behaviour,
not for structure or style.
@@ -338,14 +338,15 @@ Grouped by what each one constrains.
What settles it here is the resolved text rather than the parameter, because `writeParams()`
substitutes the field's own default: a peer that omits `message_id` and one that writes it empty
build the same octets, leaving a raw-parameter test nothing to tell apart. Rejected: keeping `''`
and documenting it, which leaves the published type promising what the value does not keep —
goal 2, a wrong answer about what the peer named. Rejected: dropping the unnamed entries, which
breaks the positional correspondence with `pduObjs` that README promises and loses which segment a
PDU belongs to. Rejected: `{ id?: string; pduObj: PduObject }[]`, which makes that positional
promise structural where today the compiler cannot check it; deferred to the next major, the first
place two documented fields may become one. Accepted: every consumer reading `smsIds` narrows,
including the majority whose SMSC names every id; indexing narrows too, except for the consumer
who sets `noUncheckedIndexedAccess`, which typed `smsIds[0]` as `string | undefined` already.
and documenting it, which leaves the published type promising what the value does not keep — goal
2, a wrong answer about what the peer named. Rejected: dropping the unnamed entries, which breaks
the positional correspondence with `pduObjs` that README promises and loses which segment a PDU
belongs to. Rejected: `{ id?: string; pduObj: PduObject }[]`, which makes that positional promise
structural where today the compiler cannot check it; deferred to the next breaking release, the
first place two documented fields may become one. Accepted: every consumer reading `smsIds`
narrows, including the majority whose SMSC names every id; indexing narrows too, except for the
consumer who sets `noUncheckedIndexedAccess`, which typed `smsIds[0]` as `string | undefined`
already.
### The wire
+1 -1
View File
@@ -1,6 +1,6 @@
# Migrating from larvitsmpp 0.4.0
`@larvit/smpp` 1.0.0 succeeds [larvitsmpp](https://www.npmjs.com/package/larvitsmpp) 0.4.0. The
`@larvit/smpp` 0.5.0 succeeds [larvitsmpp](https://www.npmjs.com/package/larvitsmpp) 0.4.0. The
shape is the same, connect, send, listen for delivery reports, with callbacks replaced by promises.
## API changes
+3 -3
View File
@@ -1,7 +1,6 @@
# @larvit/smpp
[![npm](https://img.shields.io/npm/v/@larvit/smpp)](https://www.npmjs.com/package/@larvit/smpp)
[![Test](https://github.com/larvit/larvitsmpp/actions/workflows/test.yaml/badge.svg)](https://github.com/larvit/larvitsmpp/actions/workflows/test.yaml)
SMPP 3.4 client and server for Node.js with the session layer built in: keepalive, reconnect, send
window, long messages and delivery receipts. TypeScript, ESM, no dependencies.
@@ -14,7 +13,8 @@ window, long messages and delivery receipts. TypeScript, ESM, no dependencies.
- **Graceful shutdown.** `close()` waits for what is in flight, so neither end has to guess.
- **Never throws.** Every fallible call resolves to `{ err?, … }`.
- **Interoperable.** Tested as a client against Jasmin and SMPPSim, and as a server against Kannel,
jsmpp, Cloudhopper, python-smpplib and php-smpp: [interop-tests/](interop-tests/README.md).
jsmpp, Cloudhopper, python-smpplib and php-smpp:
[interop-tests/](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/interop-tests/README.md).
[Install](#install) · [Send an SMS](#send-an-sms) · [Delivery reports](#delivery-reports) ·
[Receive SMS](#receive-sms) · [Run an SMPP server](#run-an-smpp-server) · [Errors](#errors) ·
@@ -630,7 +630,7 @@ if (isCommand(pduObj, 'submit_sm')) {
## Migrating from larvitsmpp 0.4.0
See [MIGRATION.md](MIGRATION.md).
See [MIGRATION.md](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/MIGRATION.md).
## Development
+1 -1
View File
@@ -96,6 +96,6 @@ ways the next experiment must see. One fix per defect class, as its own change:
then the implementation; then the decision record in the root `AGENTS.md` where the fix settles
a question of the wire or the session's life.
3. `/larv-review` on the branch, with the pull request based on `main`. When it marks the PR
ready, squash-merge it.
ready, fast-forward it.
4. Back in the experiments worktree: fast-forward `main`, rerun the experiment that found the
defect, delete the workaround its test carried, and note the fix in the findings file.
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@larvit/smpp",
"version": "1.0.0",
"version": "0.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@larvit/smpp",
"version": "1.0.0",
"version": "0.5.0",
"license": "MIT",
"devDependencies": {
"@eslint/js": "10.0.1",
+6 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@larvit/smpp",
"version": "1.0.0",
"version": "0.5.0",
"description": "SMPP 3.4 client and server for Node.js with the session layer built in: keepalive, reconnect, send window, long messages and delivery receipts",
"keywords": [
"esm",
@@ -9,19 +9,19 @@
"smpp",
"typescript"
],
"homepage": "https://github.com/larvit/larvitsmpp",
"homepage": "https://gitea.larvit.se/larvit/smpp-js",
"bugs": {
"url": "https://github.com/larvit/larvitsmpp/issues"
"url": "https://github.com/larvit/smpp-js/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/larvit/larvitsmpp.git"
"url": "git+https://gitea.larvit.se/larvit/smpp-js.git"
},
"license": "MIT",
"author": {
"name": "Mikael 'Lilleman' Göransson",
"email": "lilleman@larvit.se",
"url": "http://github.com/larvit/larvitsmpp"
"url": "https://gitea.larvit.se/larvit/smpp-js"
},
"type": "module",
"exports": {
@@ -37,8 +37,7 @@
"node": ">=18.0.0"
},
"publishConfig": {
"access": "public",
"provenance": true
"access": "public"
},
"scripts": {
"build": "tsc --project tsconfig.build.json",
+58 -67
View File
@@ -9,7 +9,7 @@ govern it, and nothing here is a source anything else may cite.
## Status
The rewrite is **feature complete and green**: the suite, lint and typecheck are clean on Node 18
to 26. What is left is release work and a few things worth adding before or after 1.0.0.
to 26. What is left is release work and a few things worth adding before or after 0.5.0.
## The agreed API
@@ -67,34 +67,58 @@ Rules the API follows:
| A transient state sent under the marker the spec gives it, off the same list the reader uses | `test/session-extras.test.ts` |
| A listener that throws, or rejects, reaching `sessionError`/`serverError` rather than the process | `test/session.test.ts`, `test/error-from.test.ts` |
| Cross-checked against node-smpp both ways and over a live session | `test/interop.test.ts` |
| CI on Node 18 to 26, Renovate, tag-triggered publish | `.github/workflows/` |
| CI on Node 18 to 26, Renovate, tag-triggered publish | `.gitea/workflows/` |
Every defect listed in the AGENTS.md table has a regression test naming the behaviour.
## Before publishing 1.0.0
## Move the repository to Gitea
- [x] `NPM_TOKEN`, which `.github/workflows/release.yaml` needs, is set as an organization secret.
- [ ] Tag `v1.0.0` to publish. The first publish creates `@larvit/smpp` on npm, provided the token
can publish under `@larvit`.
`gitea.larvit.se/larvit/smpp-js` is the repository. `github.com/larvit/smpp-js` becomes a push mirror
of it and the place issues are filed. Maintainer's calls, 2026-09-13 and 2026-09-14.
- [x] `larvit/smpp-js` holds `main`, from `typescript`, and `v0.4.0`, from `master`. `rewrite-base`
and the `renovate/*` branches stayed behind.
- [x] Fast-forward is the only merge style. `main` takes no pushes, requires `Test / lint
(pull_request)` and `Test / test (*) (pull_request)`, blocks an outdated branch, and gives
admins no override. Every other branch takes force pushes.
- [x] The workflows are in `.gitea/workflows/`. Tests run on pull requests only, the event the gate
reads; Renovate runs as a scheduled workflow, as on adf-codec.
- [x] The release publishes without provenance, which npm generates only on GitHub Actions and
GitLab CI/CD.
- [x] `package.json` names Gitea, and the GitHub mirror's issues as `bugs`. The README links
absolutely: npmjs.com resolves a relative link against itself when the `repository` is not on
GitHub. Its test badge is gone, since Gitea reports a workflow's status per branch and no
workflow runs on `main`.
- `RENOVATE_GITHUB_TOKEN` exists nowhere, so Renovate queries github.com unauthenticated, as
adf-codec's nightly run already does without a warning. `RENOVATE_TOKEN` is the Gitea token and
cannot stand in for it. Add a github.com token only if lookups hit the rate limit.
## Before publishing 0.5.0
- [x] 0.5.0 rather than 1.0.0, while usage is this low. Maintainer's call, 2026-09-14.
- [x] `NPM_TOKEN`, which `.gitea/workflows/release.yaml` needs, is a Gitea organization secret.
- [ ] Tag `v0.5.0` on Gitea to publish. The first publish creates `@larvit/smpp` on npm, provided the
token can publish under `@larvit`.
- [ ] `npm deprecate larvitsmpp` pointing at `@larvit/smpp`. Maintainer's call to run it; not
something CI should do.
- [ ] **Rename the branches, once everything above is done.** Maintainer's call, 2026-09-04:
`master` becomes `v0.4.0`, `typescript` becomes `main`, and `main` is the repository's default
branch. Renaming rather than merging is what the orphan commit leaves available — the two
histories share no ancestor, so a merge refuses them outright.
- [ ] Rename `master` to `v0.4.0`.
- [ ] Rename `typescript` to `main`, and make it the default branch.
- [ ] Retarget what still points at an old name: [#71](https://github.com/larvit/larvitsmpp/pull/71),
and the open PRs based on `master`, which a rename carries over rather than closes.
- [ ] Delete `rewrite-base` once [#71](https://github.com/larvit/larvitsmpp/pull/71) is
resolved; it exists only to give that PR a reviewable diff.
## Close the GitHub backlog, once this branch is `main`
## Retire the GitHub repository
Nothing below is closed while the default branch is still 0.4.0 — declining a security bump on a
live default branch is worse than leaving it open. Work through this immediately after the rename.
Nothing here starts before 0.5.0 is published. Maintainer's call, 2026-09-14. Then in this order:
the push mirror replaces GitHub's branches with Gitea's, which closes every pull request based on
`master` without a reply, and GitHub refuses to delete the default branch it syncs over.
**Answer and close as fixed by 1.0.0**, the reply naming what fixed it:
- [ ] Close the backlog below.
- [ ] Close [#71](https://github.com/larvit/larvitsmpp/pull/71), pointing at Gitea.
- [ ] Rename `larvit/larvitsmpp` to `larvit/smpp-js`. GitHub redirects the old URLs, and the `bugs`
URL in `package.json` resolves from then on.
- [ ] Push `main` and make it GitHub's default branch.
- [ ] Remove Renovate and CodeRabbit from the GitHub repository.
- [ ] Add it to Gitea as a push mirror, with a GitHub credential that can write to it.
## Close the GitHub backlog
**Answer and close as fixed by 0.5.0**, the reply naming what fixed it:
- [ ] [#2](https://github.com/larvit/larvitsmpp/issues/2) Tests for the README examples:
`test/readme.test.ts`.
@@ -136,48 +160,13 @@ live default branch is worse than leaving it open. Work through this immediately
[#70](https://github.com/larvit/larvitsmpp/pull/70) is the open `uuid` advisory GitHub reports
on the default branch; it disappears with the runtime dependencies rather than being fixed.
[#60](https://github.com/larvit/larvitsmpp/issues/60) is Renovate's dashboard — leave it, it
re-baselines itself against the new `package.json`.
[#60](https://github.com/larvit/larvitsmpp/issues/60) is Renovate's dashboard — close it with
Renovate's removal from GitHub.
**Leave open:** [#8](https://github.com/larvit/larvitsmpp/issues/8), the socket's remote host and
port on log messages. Only `server - incoming connection` carries them today; putting them on every
session message is a change to every call site.
## Move the repository to Gitea
`gitea.larvit.se/larvit/smpp-js` becomes the repository and `github.com/larvit/smpp-js` a push mirror
of it. Maintainer's call, 2026-09-13. `@larvit/adf-codec` already runs from Gitea, without a mirror.
Decide first:
- [ ] **Before or after 1.0.0.** Before: 1.0.0's `repository`, `homepage` and `bugs` name the final
home. After: 1.0.0 ships now from the pipeline that is already green, and the renamed GitHub
repository redirects the links it carries.
- [ ] **Provenance.** npm generates it only on GitHub Actions and GitLab CI/CD. Publishing from Gitea
drops it, as adf-codec's publishing does; publishing from the mirror keeps it, but makes every
release depend on the mirror being in sync.
- [ ] **Where issues and pull requests are filed**, Gitea or the GitHub mirror. adf-codec has Gitea
issues switched off.
- [ ] **Review bot.** CodeRabbit does not support Gitea.
Then:
- [ ] Migrate `larvit/larvitsmpp` into `larvit/smpp-js` with Gitea's GitHub migration, as a regular
repository rather than a pull mirror.
- [ ] Fast-forward as the only merge style, as on adf-codec, plus what adf-codec lacks: a protection
rule on `main` requiring a pull request and a green CI status. That is what makes the commit on
`main` the commit CI tested; GitHub's merge buttons always write a new commit.
- [ ] Rename the GitHub repository to `larvit/smpp-js` and add it to Gitea as a push mirror.
- [ ] Move `.github/workflows/` to `.gitea/workflows/` on the `docker-host` runner, with Renovate as a
scheduled workflow like adf-codec's. Gitea reads `.gitea/workflows/` and falls back to
`.github/workflows/`; left where they are, the mirror runs every workflow a second time on
GitHub, the release included.
- [ ] Point `package.json`, the README badges and links, AGENTS.md and MIGRATION.md at Gitea, and change
`interop-tests/AGENTS.md` step 3 from squash-merge to fast-forward.
- [ ] Check how npmjs.com renders the README's relative links (`MIGRATION.md`,
`interop-tests/README.md`) for a Gitea `repository`; for a GitHub one it resolves them against the
default branch.
## Worth doing, not blocking
- [ ] **A send the codec will refuse waits for a link and a window slot first.** `refuse()` in
@@ -197,18 +186,20 @@ Then:
- [ ] **A gate that refuses a floating version anywhere in the repo.** Maintainer's ask on
[#71](https://github.com/larvit/larvitsmpp/pull/71), 2026-09-06, on the `release.yaml`
pinning thread, which stays open until this lands. Pinning every action and runner by hand is
what the ask followed; the gate is what keeps them pinned. It has to cover workflow `uses:`
and `runs-on:`, compose `image:`, and Dockerfile `FROM`, and the conventions differ per kind —
actions take a semver tag, images the full patch version — so one grep for `latest` is not it.
pinning thread. Pinning every action and runner by hand is what the ask followed; the gate is
what keeps them pinned. It has to cover workflow `uses:` and `runs-on:`, compose `image:`, and
Dockerfile `FROM`, and the conventions differ per kind — actions take a semver tag, images the
full patch version — so one grep for `latest` is not it.
- [ ] **A gate that fails when the test matrix misses the current Node.** Maintainer's ask on
[#71](https://github.com/larvit/larvitsmpp/pull/71), 2026-09-06, on the Node 26 thread, which
stays open until this lands. Node 26 was added by hand; nothing notices when 27 ships. Needs a
source for what Current is — the Node release schedule is published as JSON — and a decision
on whether a new Current fails the build or opens a PR, which is what Renovate already does
for everything else here.
[#71](https://github.com/larvit/larvitsmpp/pull/71), 2026-09-06, on the Node 26 thread. Node
26 was added by hand; nothing notices when 27 ships. Needs a source for what Current is — the
Node release schedule is published as JSON — and a decision on whether a new Current fails the
build or opens a PR, which is what Renovate already does for everything else here.
- [ ] **CodeRabbit reviews through the GitHub mirror.** CodeRabbit does not support Gitea, so mirror
each Gitea pull request to GitHub for it to review there. Maintainer's ask, 2026-09-14; not
started until asked.
- [ ] **Group the session's collaborators under `src/session/`.** `session.ts` imports
`dlr-merger`, `incoming-requests`, `link-timers`, `outgoing-requests`, `pdu-transport`,
@@ -260,7 +251,7 @@ Then:
already had answered, so the loss is real — but surviving it means handing the application the merge
state to persist, which the scope floor covers as squarely as holding the state here would, and
which publishes the shape of `DlrMerger`'s groups against goal 6. Nothing is foreclosed: the seam
can still be added after 1.0.0 as a minor.
can still be added after 0.5.0 as a minor.
- **Throughput throttling — a TPS cap, and backing off on `ESME_RTHROTTLED`.** Declined by AGENTS.md
goal 7: an operator's rate limit is scoped to the account, while the widest thing this library owns