knowless 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +30 -78
- package/knowless.context.md +3 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,47 @@ v1.0.0 are:
|
|
|
30
30
|
- Documentation corrections
|
|
31
31
|
- Helper exports that pull existing mechanism back into the library
|
|
32
32
|
|
|
33
|
+
## [1.1.6] — 2026-05-09
|
|
34
|
+
|
|
35
|
+
Documentation-only release. README was routing adopters into
|
|
36
|
+
internal-only docs (PRD §16) for the "why we refuse X" rationale,
|
|
37
|
+
which collapsed two audiences (adopters reading the README;
|
|
38
|
+
agents/contributors litigating design decisions) into one trail.
|
|
39
|
+
PRD isn't shipped via npm anyway, so npm consumers clicking those
|
|
40
|
+
links got dead repo-relative paths. Restructured the README as a
|
|
41
|
+
self-contained explainer (philosophy → mechanism → modes →
|
|
42
|
+
deployment shapes → refusals → operator commitments → threat model
|
|
43
|
+
→ adopters → going-further footer) and moved the deeper refusal
|
|
44
|
+
rationale into a new repo-root `CLAUDE.md` for future agents
|
|
45
|
+
working on the library. No code changes.
|
|
46
|
+
|
|
47
|
+
### Documented
|
|
48
|
+
|
|
49
|
+
- `README.md` — dropped the "Required reading" routing table that
|
|
50
|
+
pointed adopters at internal docs (PRD, knowless.context.md).
|
|
51
|
+
Five `PRD §16.x` references in the refusals bullets replaced with
|
|
52
|
+
inline one-liner reasoning. "Hardcoded login form" bullet now
|
|
53
|
+
carries a brief inline reason ("templating is a slope") in place
|
|
54
|
+
of the `PRD §16.12` pointer. Detailed observability code block
|
|
55
|
+
removed — the philosophy stays as a refusals bullet ("wire it or
|
|
56
|
+
be silent"), the worked example lives in `GUIDE.md`. Threat model
|
|
57
|
+
paragraph trimmed (removed trailing `knowless.context.md`
|
|
58
|
+
pointer). New "Going further" footer at the end pointing at
|
|
59
|
+
`GUIDE.md`, `OPS.md`, `CHANGELOG.md`. Walk-away bullet now
|
|
60
|
+
mirrors the four PRD §6.3 carve-outs verbatim.
|
|
61
|
+
- `CLAUDE.md` (new, repo-root, **not shipped via npm**) — agent
|
|
62
|
+
context with the walk-away doctrine, two-test lens for "should X
|
|
63
|
+
go in knowless," README-discoverability triage for adopter
|
|
64
|
+
feature requests, the most-litigated refusals (each with its PRD
|
|
65
|
+
§16 anchor for long-form reasoning), pointers to PRD / SPEC /
|
|
66
|
+
TASKS / AGENT_RULES, the decision-revisit protocol, and a
|
|
67
|
+
condensed code-standards block.
|
|
68
|
+
- `knowless.context.md` — dropped the bare `(PRD §16.2)`
|
|
69
|
+
parenthetical from the Postfix-on-localhost gotcha. The inline
|
|
70
|
+
reasoning that follows ("vendor mailers invite 'while we're at
|
|
71
|
+
it'…") carries the same point without routing readers into a
|
|
72
|
+
doc that isn't shipped.
|
|
73
|
+
|
|
33
74
|
## [1.1.5] — 2026-05-09
|
|
34
75
|
|
|
35
76
|
Documentation-only release. plato (Mode A adopter) hit a real seam
|
package/README.md
CHANGED
|
@@ -9,21 +9,6 @@ npm install knowless
|
|
|
9
9
|
|
|
10
10
|
> v1.0.0 (walk-away release) | Node.js >= 22.5 | **1 production dep (nodemailer)** | Apache-2.0
|
|
11
11
|
|
|
12
|
-
## Required reading (before integrating or filing an issue)
|
|
13
|
-
|
|
14
|
-
This README is the front door, not the manual. Most "missing feature"
|
|
15
|
-
questions about knowless turn out to be answered in the docs below —
|
|
16
|
-
hooks that already exist, refusals that are deliberate, operator
|
|
17
|
-
setup steps already documented. **Read these before assuming a gap.**
|
|
18
|
-
|
|
19
|
-
| Read this | Why you need it |
|
|
20
|
-
|---|---|
|
|
21
|
-
| [`GUIDE.md`](GUIDE.md) | Integration walkthrough, **observability hooks** (`onMailerSubmit` / `onTransportFailure` / `onSuppressionWindow`), edge cases, FAQ, troubleshooting. |
|
|
22
|
-
| [`OPS.md`](OPS.md) | Operator setup — Postfix install, **SPF / DKIM / PTR / DMARC at your domain registrar** (§5), null-route, systemd, Caddy/nginx/Traefik forward-auth, MailHog dev, fail2ban. |
|
|
23
|
-
| [`docs/01-product/PRD.md`](docs/01-product/PRD.md) §16 | Why knowless refuses what it refuses. Decisions log — read §16.2 before asking for vendor SMTP, §16.7 before asking for built-in DKIM, §16.12 before asking for a templatable login form. |
|
|
24
|
-
| [`knowless.context.md`](knowless.context.md) | Dense single-file reference for AI agents and quick lookups. Public API table, every option with defaults, 19 gotchas, threat model. Fits one context window. |
|
|
25
|
-
| [`CHANGELOG.md`](CHANGELOG.md) | Version history. |
|
|
26
|
-
|
|
27
12
|
## What it does
|
|
28
13
|
|
|
29
14
|
The simpler answer that always worked: **magic link in, session
|
|
@@ -31,8 +16,8 @@ cookie out, nothing else stored.** Email is HMAC-hashed at the
|
|
|
31
16
|
boundary and discarded. The library refuses, by API shape, to send
|
|
32
17
|
anything but the sign-in link or store anything identifying.
|
|
33
18
|
|
|
34
|
-
Most auth libraries default to maximum identity collection: full
|
|
35
|
-
in plaintext, profile fields, recovery email, federation. Even
|
|
19
|
+
Most auth libraries default to maximum identity collection: full
|
|
20
|
+
email in plaintext, profile fields, recovery email, federation. Even
|
|
36
21
|
nominally privacy-focused options store enough that a breach is
|
|
37
22
|
materially harmful. knowless inverts the default.
|
|
38
23
|
|
|
@@ -80,8 +65,6 @@ The same sham-work flow runs underneath either mode, so unknown
|
|
|
80
65
|
emails, rate-limit hits, and real sends look identical to an external
|
|
81
66
|
observer.
|
|
82
67
|
|
|
83
|
-
Worked code for both in [`GUIDE.md`](GUIDE.md).
|
|
84
|
-
|
|
85
68
|
## Two deployment shapes
|
|
86
69
|
|
|
87
70
|
| Shape | When |
|
|
@@ -91,69 +74,35 @@ Worked code for both in [`GUIDE.md`](GUIDE.md).
|
|
|
91
74
|
|
|
92
75
|
## What knowless refuses (by design)
|
|
93
76
|
|
|
94
|
-
These are closed doors, not omissions.
|
|
95
|
-
|
|
96
|
-
[`docs/01-product/PRD.md`](docs/01-product/PRD.md) §16. If any
|
|
97
|
-
break your case, knowless isn't the right tool — look at
|
|
77
|
+
These are closed doors, not omissions. If any break your case,
|
|
78
|
+
knowless isn't the right tool — look at
|
|
98
79
|
[Lucia](https://lucia-auth.com/), [Auth.js](https://authjs.dev/),
|
|
99
80
|
or commercial offerings.
|
|
100
81
|
|
|
101
82
|
- **Localhost SMTP only.** No Mailgun / Postmark / SES / Resend.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
invariant.
|
|
83
|
+
Vendor relationships invite reusing the mailer for non-auth mail,
|
|
84
|
+
which collapses the "one mail purpose" invariant.
|
|
105
85
|
- **One mail purpose: the sign-in link.** No `sendNotification()` to
|
|
106
86
|
be tempted by.
|
|
107
87
|
- **Plain-text 7-bit email.** No HTML, no tracking pixels, no
|
|
108
88
|
click-rewriting, no read-receipts.
|
|
109
|
-
- **No DKIM/SPF in the library.**
|
|
110
|
-
|
|
111
|
-
Setup steps in [`OPS.md`](OPS.md) §5.
|
|
89
|
+
- **No DKIM/SPF in the library.** That's the MTA's job; knowless
|
|
90
|
+
emits clean RFC822 and your Postfix + opendkim signs it.
|
|
112
91
|
- **No OAuth / OIDC / SAML.** Different audience.
|
|
113
92
|
- **No 2FA / WebAuthn / TOTP / passkeys.** Compose with a separate
|
|
114
93
|
library if you need them.
|
|
115
94
|
- **No admin UI.** `sqlite3 knowless.db` is the admin UI.
|
|
116
|
-
- **Hardcoded login form.**
|
|
117
|
-
|
|
95
|
+
- **Hardcoded login form.** Templating is a slope — today "let me
|
|
96
|
+
put my logo," tomorrow "let me theme the page," eventually "let me
|
|
97
|
+
embed a JS framework." Fork, override the route entirely, or live
|
|
98
|
+
with it.
|
|
118
99
|
- **No telemetry, analytics, or error reporting.** No phone-home of
|
|
119
|
-
any kind.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
knowless emits **three operator-visibility hooks** on the mail-send
|
|
127
|
-
path. They're the only API for SMTP outcomes — there is no internal
|
|
128
|
-
logging the library does on your behalf beyond an unwired-default
|
|
129
|
-
stderr line on transport failure. If you want metrics, alerting, or
|
|
130
|
-
an admin UI showing send results, you wire these.
|
|
131
|
-
|
|
132
|
-
```js
|
|
133
|
-
const auth = knowless({
|
|
134
|
-
secret, baseUrl, from,
|
|
135
|
-
|
|
136
|
-
onMailerSubmit: ({ messageId, handle, timestamp }) => {
|
|
137
|
-
// Real (non-sham) submission succeeded. Safe per-event — fires
|
|
138
|
-
// ONLY on registered handles, so no enumeration oracle.
|
|
139
|
-
},
|
|
140
|
-
onTransportFailure: ({ error, timestamp }) => {
|
|
141
|
-
// SMTP submission failed. Carries no identity data. Wire to
|
|
142
|
-
// your alerting / admin "last 10 sends" panel.
|
|
143
|
-
},
|
|
144
|
-
onSuppressionWindow: ({ sham, rateLimited, windowMs }) => {
|
|
145
|
-
// Aggregate counters for the silent-202 branches (sham + rate-
|
|
146
|
-
// limit hits). Windowed, NOT per-event — per-event would reopen
|
|
147
|
-
// the enumeration oracle that sham-work exists to prevent.
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Threat-model reasoning for why three hooks (and not a fourth
|
|
153
|
-
per-event sham hook) lives in [`GUIDE.md`](GUIDE.md) Step 8 and
|
|
154
|
-
`knowless.context.md` § "Why three hooks, not four". **Read it
|
|
155
|
-
before logging payloads** — careless aggregation can leak handles
|
|
156
|
-
into log lines.
|
|
100
|
+
any kind. Operator-side observability is opt-in via three hooks
|
|
101
|
+
(`onMailerSubmit` / `onTransportFailure` / `onSuppressionWindow`) —
|
|
102
|
+
wire them or be silent.
|
|
103
|
+
- **Walks away at v1.0.0.** Maintenance mode after that — security
|
|
104
|
+
fixes, bug fixes that don't change the API surface, doc fixes,
|
|
105
|
+
helper exports.
|
|
157
106
|
|
|
158
107
|
## Operator commitments
|
|
159
108
|
|
|
@@ -165,8 +114,6 @@ By choosing knowless, you commit to running:
|
|
|
165
114
|
- A **null-route** for the configured `shamRecipient` so silent-miss
|
|
166
115
|
sham mail drops, not bounces
|
|
167
116
|
|
|
168
|
-
Step-by-step in [`OPS.md`](OPS.md).
|
|
169
|
-
|
|
170
117
|
## Threat model — one paragraph
|
|
171
118
|
|
|
172
119
|
**Defends well:** DB-only leaks (handles are HMAC-salted),
|
|
@@ -184,13 +131,9 @@ fake site, but a phished mailbox still receives links).
|
|
|
184
131
|
|
|
185
132
|
**Does NOT defend against:** sophisticated bots that bypass the
|
|
186
133
|
honeypot, distributed floods from many IPs, full server compromise,
|
|
187
|
-
compromised email accounts, social engineering, insider threat at
|
|
188
|
-
operator. Layer-2 defences (Cloudflare, fail2ban, reverse-proxy
|
|
189
|
-
rate-limits) belong above the library
|
|
190
|
-
[`OPS.md`](OPS.md).
|
|
191
|
-
|
|
192
|
-
Full detail in [`knowless.context.md`](knowless.context.md) §
|
|
193
|
-
"Threat model summary."
|
|
134
|
+
compromised email accounts, social engineering, insider threat at
|
|
135
|
+
the operator. Layer-2 defences (Cloudflare, fail2ban, reverse-proxy
|
|
136
|
+
rate-limits) belong above the library.
|
|
194
137
|
|
|
195
138
|
## Adopters
|
|
196
139
|
|
|
@@ -208,6 +151,15 @@ If you're picking knowless up: the addypin and gitdone callsites are
|
|
|
208
151
|
both Mode A and good worked references for the use-first / claim-later
|
|
209
152
|
shape.
|
|
210
153
|
|
|
154
|
+
## Going further
|
|
155
|
+
|
|
156
|
+
- [`GUIDE.md`](GUIDE.md) — integration walkthrough, observability
|
|
157
|
+
hooks, edge cases, FAQ, troubleshooting.
|
|
158
|
+
- [`OPS.md`](OPS.md) — operator setup (Postfix install, SPF/DKIM/PTR/
|
|
159
|
+
DMARC at your registrar, null-route, systemd, forward-auth wiring,
|
|
160
|
+
fail2ban).
|
|
161
|
+
- [`CHANGELOG.md`](CHANGELOG.md) — version history.
|
|
162
|
+
|
|
211
163
|
## License
|
|
212
164
|
|
|
213
165
|
[Apache 2.0](LICENSE) with [`NOTICE`](NOTICE) preservation. Forks
|
package/knowless.context.md
CHANGED
|
@@ -649,10 +649,9 @@ rate-limits) belongs above the library.
|
|
|
649
649
|
|
|
650
650
|
2. **Postfix on localhost is required.** No remote SMTP, no
|
|
651
651
|
Mailgun / Postmark / SES. The localhost requirement is
|
|
652
|
-
intentional
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
library.
|
|
652
|
+
intentional: vendor mailers invite "while we're at it, let's
|
|
653
|
+
send a welcome email," which contradicts the philosophy. If
|
|
654
|
+
you can't run Postfix, knowless isn't your library.
|
|
656
655
|
|
|
657
656
|
3. **`shamRecipient` MUST be discarded without external delivery.**
|
|
658
657
|
Default is `null@knowless.invalid`. With the default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knowless",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "Small, opinionated, full-stack passwordless auth for Node.js services that don't need to email their users for anything but the sign-in link.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|