Move the goals to README.md and state the audience
Mirror / push (push) Successful in 5s
Test / lint (pull_request) Successful in 21s
Test / test (18) (pull_request) Successful in 21s
Test / test (20) (pull_request) Successful in 19s
Test / test (22) (pull_request) Successful in 20s
Test / test (24) (pull_request) Successful in 20s
Test / test (26) (pull_request) Successful in 20s
Mirror / push (push) Successful in 5s
Test / lint (pull_request) Successful in 21s
Test / test (18) (pull_request) Successful in 21s
Test / test (20) (pull_request) Successful in 19s
Test / test (22) (pull_request) Successful in 20s
Test / test (24) (pull_request) Successful in 20s
Test / test (26) (pull_request) Successful in 20s
This commit is contained in:
@@ -12,45 +12,11 @@ not for structure or style.
|
||||
|
||||
## Goals
|
||||
|
||||
In priority order, and the order is the point: where two of them pull against each other, the earlier
|
||||
one wins. They do not override the hard rules below.
|
||||
The nine goals, in priority order, live in
|
||||
[README.md](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/README.md#goals) — they say where this library is heading, which an outside
|
||||
reader judges it by. The README states the audience alongside them. Everything below cites a goal by
|
||||
number.
|
||||
|
||||
1. **Correct on the wire.** SMPP 3.4 as SMSCs actually run it. Every other goal yields to this one;
|
||||
the defect table below is what the alternative costs.
|
||||
2. **Never give the application a wrong answer about what happened.** An outcome we cannot determine
|
||||
is reported as undetermined rather than guessed; a report the peer marked as not final settles
|
||||
nothing, so nothing the library concludes may rest on one; a request the peer may already have
|
||||
taken is never re-sent on the library's own initiative; work the peer has no reason to send again
|
||||
is not dropped.
|
||||
3. **Strict in what we send, generous in what we read.** The library's own senders follow 3.4, and
|
||||
the codec parses whatever arrives. Where the letter of the spec would discard traffic a real SMSC
|
||||
sends, keep the traffic.
|
||||
4. **A peer an operator never has to complain about.** No bind flooding, nothing a bind direction
|
||||
forbids, no optional parameters to a peer that declared none, nothing held without a bound.
|
||||
5. **The session layer is in here, and its defaults are what most applications should run.**
|
||||
Keepalive, reconnect, the send window, reassembly and receipt correlation. What the network says
|
||||
about a message the application sent reaches it as a report rather than as an inbound message, and
|
||||
says whether it is final, so nothing has to read the PDU to tell those apart. An option retunes a
|
||||
default or opts out of it; an option does not switch on the thing the caller obviously wanted.
|
||||
6. **Configurable and extendable, never at the defaults' expense.** Where an application needs other
|
||||
than the default and cannot build it from what is exported — a rate limit counted per PDU, an
|
||||
alphabet, a receipt format — it gets an option or a hook rather than a fork. A call that passes no
|
||||
options stays exactly as easy and as safe, and a hook is a seam the library calls, never a way into
|
||||
its internals.
|
||||
7. **A small, stable public surface over reshapeable internals.** Only what `src/index.ts` exports is
|
||||
published. A new option has to beat "the application can do this itself", and has to keep a
|
||||
promise this library can verify. The low-level surface is a passthrough: policy binds what the
|
||||
library composes, never what the caller wrote.
|
||||
8. **State wider than one session goes through one store.** A pool of sessions, a limit shared
|
||||
between processes, and what has to survive a restart — receipts still awaited, a message half
|
||||
reassembled — are held through a store interface and never beside it. Without a store the
|
||||
application supplies, that state is in memory and ends with the process, and the defaults need
|
||||
none. The interface carries the library's own versioned records, never an internal shape handed
|
||||
to the application to persist. Coordinating processes any other way is declined without a fresh
|
||||
argument each time.
|
||||
9. **It builds, tests and runs the same everywhere.** Container-only toolchain, no runtime
|
||||
dependencies, the Node 18 floor verified in CI rather than asserted, every README example executed
|
||||
by the suite.
|
||||
|
||||
## Hard rules
|
||||
|
||||
@@ -245,12 +211,13 @@ decision under [The wire](#the-wire).
|
||||
|
||||
Each file answers one question, and a fact belongs to the file whose question it answers:
|
||||
|
||||
- **README.md — what you can rely on.** Observable behaviour, for someone using the package. It
|
||||
carries a reason only where the reason changes how you would call the thing.
|
||||
- **README.md — what you can rely on, and where this is heading.** Observable behaviour, for
|
||||
someone using the package, plus the goals and the audience. It carries a reason only where the
|
||||
reason changes how you would call the thing.
|
||||
- **MIGRATION.md — what a 0.4.0 consumer has to change.** Renamed and removed surface, and the
|
||||
behaviour that changed on the wire.
|
||||
- **AGENTS.md — what may not change, and why.** Goals, hard rules, architecture, conventions, and the
|
||||
decisions the goals do not already settle. It does not restate behaviour README states.
|
||||
- **AGENTS.md — what may not change, and why.** Hard rules, architecture, conventions, and the
|
||||
decisions the goals do not already settle. It does not restate behaviour or goals README states.
|
||||
- **todo.md** is a working file that sets its own rules; nothing here governs it.
|
||||
|
||||
A sentence living in two of them is a defect: delete the copy in the file whose question it does not
|
||||
|
||||
@@ -22,7 +22,8 @@ window, long messages and delivery receipts. TypeScript, ESM, no dependencies.
|
||||
[Send options](#send-options) · [Session](#session) · [Receiving in depth](#receiving-in-depth) ·
|
||||
[Server in depth](#server-in-depth) · [Logging](#logging) ·
|
||||
[PDUs and the low-level API](#pdus-and-the-low-level-api) ·
|
||||
[Migrating from 0.4.0](#migrating-from-larvitsmpp-040) · [Development](#development)
|
||||
[Migrating from 0.4.0](#migrating-from-larvitsmpp-040) · [Goals](#goals) ·
|
||||
[Audience](#audience) · [Development](#development)
|
||||
|
||||
## Install
|
||||
|
||||
@@ -632,6 +633,72 @@ if (isCommand(pduObj, 'submit_sm')) {
|
||||
|
||||
See [MIGRATION.md](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/MIGRATION.md).
|
||||
|
||||
## Goals
|
||||
|
||||
In priority order, and the order is the point: where two of them pull against each other, the earlier
|
||||
one wins. They do not override the hard rules below.
|
||||
|
||||
1. **Correct on the wire.** SMPP 3.4 as SMSCs actually run it. Every other goal yields to this one;
|
||||
the defect table below is what the alternative costs.
|
||||
2. **Never give the application a wrong answer about what happened.** An outcome we cannot determine
|
||||
is reported as undetermined rather than guessed; a report the peer marked as not final settles
|
||||
nothing, so nothing the library concludes may rest on one; a request the peer may already have
|
||||
taken is never re-sent on the library's own initiative; work the peer has no reason to send again
|
||||
is not dropped.
|
||||
3. **Strict in what we send, generous in what we read.** The library's own senders follow 3.4, and
|
||||
the codec parses whatever arrives. Where the letter of the spec would discard traffic a real SMSC
|
||||
sends, keep the traffic.
|
||||
4. **A peer an operator never has to complain about.** No bind flooding, nothing a bind direction
|
||||
forbids, no optional parameters to a peer that declared none, nothing held without a bound.
|
||||
5. **The session layer is in here, and its defaults are what most applications should run.**
|
||||
Keepalive, reconnect, the send window, reassembly and receipt correlation. What the network says
|
||||
about a message the application sent reaches it as a report rather than as an inbound message, and
|
||||
says whether it is final, so nothing has to read the PDU to tell those apart. An option retunes a
|
||||
default or opts out of it; an option does not switch on the thing the caller obviously wanted.
|
||||
6. **Configurable and extendable, never at the defaults' expense.** Where an application needs other
|
||||
than the default and cannot build it from what is exported — a rate limit counted per PDU, an
|
||||
alphabet, a receipt format — it gets an option or a hook rather than a fork. A call that passes no
|
||||
options stays exactly as easy and as safe, and a hook is a seam the library calls, never a way into
|
||||
its internals.
|
||||
7. **A small, stable public surface over reshapeable internals.** Only what `src/index.ts` exports is
|
||||
published. A new option has to beat "the application can do this itself", and has to keep a
|
||||
promise this library can verify. The low-level surface is a passthrough: policy binds what the
|
||||
library composes, never what the caller wrote.
|
||||
8. **State wider than one session goes through one store.** A pool of sessions, a limit shared
|
||||
between processes, and what has to survive a restart — receipts still awaited, a message half
|
||||
reassembled — are held through a store interface and never beside it. Without a store the
|
||||
application supplies, that state is in memory and ends with the process, and the defaults need
|
||||
none. The interface carries the library's own versioned records, never an internal shape handed
|
||||
to the application to persist. Coordinating processes any other way is declined without a fresh
|
||||
argument each time.
|
||||
9. **It builds, tests and runs the same everywhere.** Container-only toolchain, no runtime
|
||||
dependencies, the Node 18 floor verified in CI rather than asserted, every README example executed
|
||||
by the suite.
|
||||
|
||||
## Audience
|
||||
|
||||
Who depends on this library, and what they may rely on.
|
||||
|
||||
- **The public npm audience, not only larvit's own applications.** Only what `src/index.ts` exports
|
||||
is public; everything behind it is reshaped freely.
|
||||
- **Node 18 and newer, ESM only, no runtime dependencies.** The floor is verified in CI rather than
|
||||
asserted, so the library drops into a service or a container without pulling a tree behind it.
|
||||
- **Real SMSCs and ESMEs as operators actually run them**, not a reference implementation. Jasmin,
|
||||
SMPPSim, Kannel, jsmpp, Cloudhopper, python-smpplib and php-smpp are the interop targets, and what
|
||||
they do in practice outranks what the specification says they should do.
|
||||
- **The SMSC operator on the far end**, who never sees this API but carries what it does to their
|
||||
link. A peer they have to complain about is a defect however well the library reads.
|
||||
- **Pre-1.0, so the minor is the breaking unit** and a patch never breaks. What a 0.4.0 consumer has
|
||||
to change is in [MIGRATION.md](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/MIGRATION.md).
|
||||
|
||||
Personas this README serves, in order:
|
||||
|
||||
1. The application developer sending or receiving SMS on the defaults, who should need no options.
|
||||
2. The application developer who needs one thing retuned — an alphabet, a rate limit, a receipt
|
||||
format — through an option or a hook rather than a fork.
|
||||
3. The operator coordinating sessions across processes through a store.
|
||||
4. The developer migrating from `larvitsmpp` 0.4.0.
|
||||
|
||||
## Development
|
||||
|
||||
Everything runs in the container; nothing is installed on the host.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# todo.md
|
||||
|
||||
Remaining work for `@larvit/smpp`. Read [AGENTS.md](AGENTS.md) first — the goals and hard rules
|
||||
there constrain every item below.
|
||||
Remaining work for `@larvit/smpp`. Read [README.md](README.md)'s goals and [AGENTS.md](AGENTS.md)'s
|
||||
hard rules first — they constrain every item below.
|
||||
|
||||
This is a working file that sets its own rules. The documentation conventions in AGENTS.md do not
|
||||
govern it, and nothing here is a source anything else may cite.
|
||||
@@ -262,7 +262,7 @@ the rewrite, for a dependency added later. Maintainer's call, 2026-09-14.
|
||||
|
||||
From comparing 0.5.0 with `smpp`, `@semyonf/smpp`, `@leissner/node-red-smpp`, `node-smpp-next`,
|
||||
`smpp-js-sdk`, `smppjs`, cloudhopper-smpp, jsmpp, go-smpp, Kannel, Jasmin and php-smpp, 2026-09-14.
|
||||
Each lands under AGENTS.md goal 6: an option or a hook, with the call that passes none unchanged.
|
||||
Each lands under goal 6: an option or a hook, with the call that passes none unchanged.
|
||||
|
||||
### Sending
|
||||
|
||||
@@ -424,7 +424,7 @@ Each lands under AGENTS.md goal 6: an option or a hook, with the call that passe
|
||||
|
||||
- [ ] **Pooling, and state that survives a restart, through an optional store.** Maintainer's call,
|
||||
2026-09-14. It replaces two declines — merge state surviving a restart, and a pool of sessions —
|
||||
and AGENTS.md goal 8 was rewritten for it. Big: design before code.
|
||||
and goal 8 was rewritten for it. Big: design before code.
|
||||
- **What it holds.** Receipts still awaited and the groups `DlrMerger` collects. Segments of a
|
||||
message already answered but not yet whole, which the peer will not send again (goal 2). The
|
||||
concatenation reference, so a restart does not reuse one. For a pool, the ids every session
|
||||
|
||||
Reference in New Issue
Block a user