@estiva-app/identity 0.1.1 → 0.1.2
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 +50 -0
- package/README.md +39 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +159 -44
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +210 -42
- package/src/index.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# @estiva-app/identity
|
|
2
2
|
|
|
3
|
+
## 0.1.2 — 2026-09-07
|
|
4
|
+
|
|
5
|
+
**No wire behaviour, no break.** `scheduleRenewal` is new and the guard on
|
|
6
|
+
`refreshAccessToken` only prevents a call that should never have been made, so a
|
|
7
|
+
consumer on `^0.1.0` needs no change — ADR 0002 §4b puts the break on MINOR
|
|
8
|
+
within `0.x`.
|
|
9
|
+
|
|
10
|
+
Two of SHA-4's five "hard-won behaviour that must survive" items did not, in
|
|
11
|
+
fact, survive — and both for the same reason. They lived in
|
|
12
|
+
`peek-app/src/auth/useEstivaIdAuth.ts`, the `ConvexProviderWithAuth` adapter,
|
|
13
|
+
which is deliberately the one file kept *out* of this package. So Peek kept them
|
|
14
|
+
and Ship, the second consumer whose entire purpose was to catch exactly this,
|
|
15
|
+
silently did not get them. Wiring a second consumer proves a package is not
|
|
16
|
+
shaped like the first app; it does not prove the first app handed everything
|
|
17
|
+
over.
|
|
18
|
+
|
|
19
|
+
- **`refreshAccessToken` now coalesces concurrent callers.** A refresh token is
|
|
20
|
+
single-use and Estiva ID reads a replay as theft, revoking the whole chain — so
|
|
21
|
+
two renewals in the air at once do not waste a round trip, they sign somebody
|
|
22
|
+
out of everything. Two callers is not hypothetical: Ship signs the NIP-98 auth
|
|
23
|
+
event and the content event as separate `POST /sign` calls, and a token that
|
|
24
|
+
expires between them answers `401` to both, each of which renews.
|
|
25
|
+
|
|
26
|
+
Peek has had this since PEEK-108 as a `refreshing` ref in its hook. Ship has
|
|
27
|
+
never had it. It belongs here, where every caller of every consumer gets it
|
|
28
|
+
without having thought about it. Coalescing, not caching: the promise is
|
|
29
|
+
dropped the moment it settles, and a test asserts the *next* expiry renews
|
|
30
|
+
again — a guard that held the promise forever would pass the first test and be
|
|
31
|
+
a worse bug than the one it fixed.
|
|
32
|
+
|
|
33
|
+
- **`scheduleRenewal(handlers)` renews before expiry rather than reacting to
|
|
34
|
+
it.** `tokenFrom` has always stored an expiry 30 seconds early; nothing in the
|
|
35
|
+
package acted on it. Reacting to expiry means somebody's next action is what
|
|
36
|
+
discovers the session ended. Renewing early means they notice nothing, which
|
|
37
|
+
is the whole point of PEEK-108.
|
|
38
|
+
|
|
39
|
+
The timer is injected (`setTimer`/`clearTimer`) for the same reason `fetch` and
|
|
40
|
+
`navigate` are: "we scheduled it" and "we did nothing" are otherwise the same
|
|
41
|
+
observation. The handle type never reaches the published `.d.ts` — it is
|
|
42
|
+
`number` in a browser and an object in Node, and naming either fails
|
|
43
|
+
`check-identity.yml`, correctly.
|
|
44
|
+
|
|
45
|
+
**Known limitation, documented here rather than rediscovered per app:** a
|
|
46
|
+
`setTimeout` is throttled in a background tab — to once a minute in Chrome and
|
|
47
|
+
Safari, and frozen outright after five minutes hidden — so a backgrounded tab
|
|
48
|
+
can miss its window. It degrades safely, because the refresh token long
|
|
49
|
+
outlives the access token: a late renewal is still a renewal, and anything that
|
|
50
|
+
beats the timer takes the existing `401`-and-retry path. The guard above is
|
|
51
|
+
what stops the two racing.
|
|
52
|
+
|
|
3
53
|
## 0.1.1 — 2026-08-28
|
|
4
54
|
|
|
5
55
|
**No wire behaviour**, and no break: `pendingStore` is optional and defaults to
|
package/README.md
CHANGED
|
@@ -42,6 +42,7 @@ package come out Peek-shaped, which is the whole risk SHA-4 names.
|
|
|
42
42
|
| `pendingStore` — in-flight PKCE credentials | defaults to `storage` | `sessionStorage`, because the flow starts and ends in one tab |
|
|
43
43
|
| `keyPrefix` | `peek.estivaId` | `ship.estiva-id` |
|
|
44
44
|
| `navigate` | the one genuinely untestable act, so it is observable | |
|
|
45
|
+
| `setTimer` / `clearTimer` | the timers `scheduleRenewal` runs on, injected for the same reason | |
|
|
45
46
|
|
|
46
47
|
**Do not unify the two stores.** NIP-RS read-state slots (CRO-4) must survive a
|
|
47
48
|
restart and belong in `localStorage`; an access token does not. Different
|
|
@@ -67,6 +68,44 @@ const client = createEstivaId({
|
|
|
67
68
|
export const { validToken, beginSignIn, completeSignIn, beginSignOut } = client
|
|
68
69
|
```
|
|
69
70
|
|
|
71
|
+
## Renewal is scheduled, not reactive
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const schedule = client.scheduleRenewal({
|
|
75
|
+
onRenewed: (token) => setSignedIn(true),
|
|
76
|
+
onEnded: () => setSignedIn(false), // drop to the shell
|
|
77
|
+
})
|
|
78
|
+
// later, on sign-out or unmount
|
|
79
|
+
schedule.cancel()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`tokenFrom` stores an expiry 30 seconds early on purpose, and `scheduleRenewal`
|
|
83
|
+
is what acts on it. Reacting to expiry instead means somebody's *next action* is
|
|
84
|
+
what discovers the session is over — a failed publish, a blank list, at best a
|
|
85
|
+
retry they can feel. Renewing early means they notice nothing, which is the whole
|
|
86
|
+
point of PEEK-108.
|
|
87
|
+
|
|
88
|
+
**Two renewals must never be in the air at once.** A refresh token is single-use
|
|
89
|
+
and Estiva ID reads a replay as evidence of theft, revoking the whole chain — so
|
|
90
|
+
a duplicate renewal does not waste a round trip, it signs somebody out of
|
|
91
|
+
everything. `refreshAccessToken` coalesces concurrent callers into one request,
|
|
92
|
+
and it does so for every caller, not only the scheduler: Ship signs the NIP-98
|
|
93
|
+
auth event and the content event as two separate `POST /sign` calls, and a token
|
|
94
|
+
that expires between them answers `401` to both.
|
|
95
|
+
|
|
96
|
+
**Known limitation: `setTimeout` is throttled in a background tab.** Chrome and
|
|
97
|
+
Safari clamp a hidden tab's timers to roughly once a minute, and may freeze them
|
|
98
|
+
outright after five minutes hidden, so a backgrounded tab can miss its renewal
|
|
99
|
+
window. This is recorded here rather than rediscovered once per app.
|
|
100
|
+
|
|
101
|
+
It degrades safely. The refresh token outlives the access token by a long way, so
|
|
102
|
+
a late renewal is still a renewal, and anything that beats the late timer takes
|
|
103
|
+
the existing `401`-and-retry path — which is exactly why the coalescing guard
|
|
104
|
+
above is not an optimisation. A `visibilitychange` listener that re-armed on
|
|
105
|
+
foreground would tighten it and is deliberately absent: `document` is a global
|
|
106
|
+
this package does not touch (ADR 0002 §4a). An app that wants it can `cancel()`
|
|
107
|
+
and call `scheduleRenewal` again.
|
|
108
|
+
|
|
70
109
|
## The prediction this package falsified
|
|
71
110
|
|
|
72
111
|
Before starting, the expectation on the ticket was that identity **could not**
|
package/dist/client.d.ts
CHANGED
|
@@ -102,6 +102,14 @@ export interface EstivaIdConfig {
|
|
|
102
102
|
navigate?: (url: string) => void;
|
|
103
103
|
now?: () => number;
|
|
104
104
|
fetch?: FetchLike;
|
|
105
|
+
/**
|
|
106
|
+
* The timers `scheduleRenewal` runs on, injected for exactly the reason
|
|
107
|
+
* `fetch` and `navigate` are: a test cannot wait ten minutes to find out
|
|
108
|
+
* whether the renewal was scheduled, and "we scheduled it" and "we did
|
|
109
|
+
* nothing" are otherwise the same observation.
|
|
110
|
+
*/
|
|
111
|
+
setTimer?: (run: () => void, ms: number) => unknown;
|
|
112
|
+
clearTimer?: (handle: unknown) => void;
|
|
105
113
|
}
|
|
106
114
|
export interface StoredToken {
|
|
107
115
|
accessToken: string;
|
|
@@ -123,6 +131,25 @@ export interface StoredToken {
|
|
|
123
131
|
}
|
|
124
132
|
export declare class SignInError extends Error {
|
|
125
133
|
}
|
|
134
|
+
/** What a scheduled renewal reports back. Both optional; neither is required to be useful. */
|
|
135
|
+
export interface RenewalHandlers {
|
|
136
|
+
/** A renewal succeeded. The session continues, on a later expiry. */
|
|
137
|
+
onRenewed?: (token: StoredToken) => void;
|
|
138
|
+
/**
|
|
139
|
+
* A renewal failed, and the session is over.
|
|
140
|
+
*
|
|
141
|
+
* The only honest thing an app can do here is drop to the shell. Note this
|
|
142
|
+
* fires on refusal *and* on an unreachable network — `refreshAccessToken`
|
|
143
|
+
* distinguishes them for the purpose of clearing the stored token, but from a
|
|
144
|
+
* scheduler's point of view a renewal that did not happen is a renewal that
|
|
145
|
+
* did not happen, and the shell's own probe is what sorts out which it was.
|
|
146
|
+
*/
|
|
147
|
+
onEnded?: () => void;
|
|
148
|
+
}
|
|
149
|
+
export interface RenewalSchedule {
|
|
150
|
+
/** Stop renewing. Idempotent, and safe to call after the session has ended. */
|
|
151
|
+
cancel: () => void;
|
|
152
|
+
}
|
|
126
153
|
export interface EstivaIdClient {
|
|
127
154
|
redirectUri: () => string;
|
|
128
155
|
codeChallenge: (verifier: string) => Promise<string>;
|
|
@@ -134,6 +161,7 @@ export interface EstivaIdClient {
|
|
|
134
161
|
returnTo: string;
|
|
135
162
|
}>;
|
|
136
163
|
refreshAccessToken: () => Promise<StoredToken | null>;
|
|
164
|
+
scheduleRenewal: (handlers?: RenewalHandlers) => RenewalSchedule;
|
|
137
165
|
storedToken: () => StoredToken | null;
|
|
138
166
|
validToken: (now?: number) => StoredToken | null;
|
|
139
167
|
hasSession: () => boolean;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAyB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -51,6 +51,11 @@
|
|
|
51
51
|
* observe where the flow *would* go.
|
|
52
52
|
*/
|
|
53
53
|
import { clearGuard, markGuard } from './shell.js';
|
|
54
|
+
/**
|
|
55
|
+
* `setTimeout`'s ceiling. Above 2^31-1 ms the delay overflows to a negative
|
|
56
|
+
* int32 and the timer fires immediately.
|
|
57
|
+
*/
|
|
58
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
54
59
|
export class SignInError extends Error {
|
|
55
60
|
}
|
|
56
61
|
export function createEstivaId(config) {
|
|
@@ -177,6 +182,83 @@ export function createEstivaId(config) {
|
|
|
177
182
|
s?.removeItem(RETURN_KEY);
|
|
178
183
|
return raw ?? null;
|
|
179
184
|
};
|
|
185
|
+
/**
|
|
186
|
+
* Renew the access token without leaving the page (PEEK-108).
|
|
187
|
+
*
|
|
188
|
+
* This is the whole reason the grant exists. Before it, an expired token
|
|
189
|
+
* could only be replaced by a top-level navigation through `/authorize`,
|
|
190
|
+
* which costs whatever the person had on screen.
|
|
191
|
+
*
|
|
192
|
+
* Returns `null` for every failure, and the failures are not worth
|
|
193
|
+
* distinguishing: Estiva ID answers `invalid_grant` for all of them by
|
|
194
|
+
* design, and the caller's only move either way is to fall back to the
|
|
195
|
+
* shell. The stored token is cleared on refusal so a spent refresh token is
|
|
196
|
+
* never presented twice — a replay is what Estiva ID treats as theft.
|
|
197
|
+
*/
|
|
198
|
+
const performRefresh = async () => {
|
|
199
|
+
const s = config.storage();
|
|
200
|
+
const current = storedToken();
|
|
201
|
+
if (!s || !current?.refreshToken)
|
|
202
|
+
return null;
|
|
203
|
+
let response;
|
|
204
|
+
try {
|
|
205
|
+
response = await send()(new URL('/token', config.base).toString(), {
|
|
206
|
+
method: 'POST',
|
|
207
|
+
headers: { 'content-type': 'application/json' },
|
|
208
|
+
body: JSON.stringify({
|
|
209
|
+
grantType: 'refresh_token',
|
|
210
|
+
refreshToken: current.refreshToken,
|
|
211
|
+
clientId: config.clientId,
|
|
212
|
+
}),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Unreachable rather than refused. The token in hand may still be fine,
|
|
217
|
+
// so this deliberately does not clear the session — a flaky network must
|
|
218
|
+
// not sign somebody out.
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
if (!response.ok) {
|
|
222
|
+
clearSession();
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const body = (await response.json());
|
|
226
|
+
if (!body.access_token) {
|
|
227
|
+
clearSession();
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
const next = tokenFrom(body, body.pubkey ?? current.pubkey);
|
|
231
|
+
s.setItem(TOKEN_KEY, JSON.stringify(next));
|
|
232
|
+
return next;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* The renewal in flight, if there is one.
|
|
236
|
+
*
|
|
237
|
+
* **A refresh token is single-use and a replay is read as theft**, which
|
|
238
|
+
* revokes the whole chain — so two renewals must never be in the air at once.
|
|
239
|
+
* Two easily can be: Ship signs the NIP-98 auth event and the content event as
|
|
240
|
+
* separate `POST /sign` calls, and a token that expires between them answers
|
|
241
|
+
* `401` to both, each of which renews.
|
|
242
|
+
*
|
|
243
|
+
* Peek has guarded this since PEEK-108 with a `refreshing` ref in its Convex
|
|
244
|
+
* adapter, and SHA-4 lists the guard as one of the behaviours that must
|
|
245
|
+
* survive the extraction — but the guard is the one part that did not travel,
|
|
246
|
+
* because it lived in the hook rather than the client. So Peek kept it and
|
|
247
|
+
* Ship never had it. It belongs here, where every caller of every consumer
|
|
248
|
+
* gets it whether or not they thought about it.
|
|
249
|
+
*
|
|
250
|
+
* Coalescing rather than caching: the promise is dropped the moment it
|
|
251
|
+
* settles, so the *next* expiry renews again.
|
|
252
|
+
*/
|
|
253
|
+
let refreshing = null;
|
|
254
|
+
const refreshAccessToken = () => {
|
|
255
|
+
if (refreshing)
|
|
256
|
+
return refreshing;
|
|
257
|
+
refreshing = performRefresh().finally(() => {
|
|
258
|
+
refreshing = null;
|
|
259
|
+
});
|
|
260
|
+
return refreshing;
|
|
261
|
+
};
|
|
180
262
|
return {
|
|
181
263
|
redirectUri: config.redirectUri,
|
|
182
264
|
codeChallenge,
|
|
@@ -327,54 +409,87 @@ export function createEstivaId(config) {
|
|
|
327
409
|
clearGuard(s);
|
|
328
410
|
return { token, returnTo };
|
|
329
411
|
},
|
|
412
|
+
refreshAccessToken,
|
|
330
413
|
/**
|
|
331
|
-
* Renew the
|
|
414
|
+
* Renew shortly **before** the token expires, rather than reacting to it
|
|
415
|
+
* having expired.
|
|
332
416
|
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
417
|
+
* SHA-4 lists this as one of the behaviours that must survive the
|
|
418
|
+
* extraction, and it is the one that reads as an optimisation and is not.
|
|
419
|
+
* Reacting to expiry means somebody's next action is the thing that
|
|
420
|
+
* discovers the session is over — a failed publish, a blank list, or at best
|
|
421
|
+
* a retry they can feel. Renewing 30 seconds early (`tokenFrom` already
|
|
422
|
+
* subtracts them) means they notice nothing at all.
|
|
336
423
|
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
424
|
+
* It did not travel with the rest of SHA-4: the timer lived in Peek's Convex
|
|
425
|
+
* adapter, so Peek kept it and Ship, whose whole point was to be the second
|
|
426
|
+
* consumer, silently did not get it. Ship renews only when `POST /sign`
|
|
427
|
+
* answers `401`, which is precisely "on failure".
|
|
428
|
+
*
|
|
429
|
+
* ## The timer is a `setTimeout`, and browsers throttle those
|
|
430
|
+
*
|
|
431
|
+
* A background tab gets its timers clamped — to once a minute in Chrome and
|
|
432
|
+
* Safari, and after five minutes of being hidden they may be frozen outright.
|
|
433
|
+
* So a tab left in the background can miss its renewal window entirely.
|
|
434
|
+
*
|
|
435
|
+
* This is a known limitation rather than a bug, and it is recorded here so
|
|
436
|
+
* it is not rediscovered once per app. It degrades safely: a late renewal is
|
|
437
|
+
* still a valid renewal, because the refresh token outlives the access token
|
|
438
|
+
* by a long way, and a call that beats the late timer gets the existing
|
|
439
|
+
* `401`-and-retry path. What it must not do is renew *twice* in the scramble,
|
|
440
|
+
* which is what the guard on `refreshAccessToken` is for.
|
|
441
|
+
*
|
|
442
|
+
* A `visibilitychange` listener that re-arms on foreground would tighten
|
|
443
|
+
* this, and is deliberately not here: `document` is a global this package
|
|
444
|
+
* does not touch (ADR 0002 §4a), and an app that wants it can `cancel()` and
|
|
445
|
+
* call this again.
|
|
342
446
|
*/
|
|
343
|
-
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
447
|
+
scheduleRenewal(handlers = {}) {
|
|
448
|
+
const setTimer = config.setTimer ?? ((run, ms) => setTimeout(run, ms));
|
|
449
|
+
const clearTimer = config.clearTimer ?? ((handle) => clearTimeout(handle));
|
|
450
|
+
let handle = null;
|
|
451
|
+
let cancelled = false;
|
|
452
|
+
const arm = () => {
|
|
453
|
+
const token = storedToken();
|
|
454
|
+
// Nothing to renew. Not an ending — the caller is simply signed out, and
|
|
455
|
+
// an app that signs in later starts a new schedule.
|
|
456
|
+
if (!token)
|
|
457
|
+
return;
|
|
458
|
+
/*
|
|
459
|
+
Clamped at both ends. A negative delay is a token that already expired
|
|
460
|
+
— renew now rather than never, since the refresh token almost certainly
|
|
461
|
+
has not. The ceiling is `setTimeout`'s: a delay above 2^31-1 ms
|
|
462
|
+
overflows to a negative int32 and fires immediately, so a nonsensical
|
|
463
|
+
`expires_in` would otherwise become a hot loop against `/token` instead
|
|
464
|
+
of one very distant timer.
|
|
465
|
+
*/
|
|
466
|
+
const delay = Math.min(Math.max(0, token.expiresAt - now()), MAX_TIMER_MS);
|
|
467
|
+
handle = setTimer(() => {
|
|
468
|
+
handle = null;
|
|
469
|
+
void refreshAccessToken().then((next) => {
|
|
470
|
+
if (cancelled)
|
|
471
|
+
return;
|
|
472
|
+
if (!next) {
|
|
473
|
+
handlers.onEnded?.();
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
handlers.onRenewed?.(next);
|
|
477
|
+
// Re-armed from the *new* expiry rather than a fixed interval, so
|
|
478
|
+
// the schedule follows whatever lifetime Estiva ID actually issued.
|
|
479
|
+
arm();
|
|
480
|
+
});
|
|
481
|
+
}, delay);
|
|
482
|
+
};
|
|
483
|
+
arm();
|
|
484
|
+
return {
|
|
485
|
+
cancel() {
|
|
486
|
+
cancelled = true;
|
|
487
|
+
if (handle !== null) {
|
|
488
|
+
clearTimer(handle);
|
|
489
|
+
handle = null;
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
};
|
|
378
493
|
},
|
|
379
494
|
/**
|
|
380
495
|
* Leave for Estiva ID to end the session *there* (PEEK-122).
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
* The thing that made it possible was not cleverness — it was that a browser API
|
|
47
47
|
* an app must inject is also a browser API a test can observe.
|
|
48
48
|
*/
|
|
49
|
-
export declare const IDENTITY_VERSION = "0.1.
|
|
49
|
+
export declare const IDENTITY_VERSION = "0.1.2";
|
|
50
50
|
export { type KeyValueStore, type ShellPhase, type ShellReason, type ShellState, type BootObservation, type BootAction, type ShellEvent, isRecoverable, SHELL_COPY, CONTINUE_LABEL, RETRY_LABEL, PROBE_TIMEOUT_MS, GUARD_TTL_MS, GUARD_KEY, decideBoot, reasonForCallbackError, readGuard, markGuard, clearGuard, logShellEvent, } from './shell.js';
|
|
51
|
-
export { type EstivaIdConfig, type EstivaIdClient, type StoredToken, type FetchLike, SignInError, createEstivaId, } from './client.js';
|
|
51
|
+
export { type EstivaIdConfig, type EstivaIdClient, type StoredToken, type FetchLike, type RenewalHandlers, type RenewalSchedule, SignInError, createEstivaId, } from './client.js';
|
|
52
52
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAA;AAEvC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAA;AAEvC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
* The thing that made it possible was not cleverness — it was that a browser API
|
|
47
47
|
* an app must inject is also a browser API a test can observe.
|
|
48
48
|
*/
|
|
49
|
-
export const IDENTITY_VERSION = '0.1.
|
|
49
|
+
export const IDENTITY_VERSION = '0.1.2';
|
|
50
50
|
export { isRecoverable, SHELL_COPY, CONTINUE_LABEL, RETRY_LABEL, PROBE_TIMEOUT_MS, GUARD_TTL_MS, GUARD_KEY, decideBoot, reasonForCallbackError, readGuard, markGuard, clearGuard, logShellEvent, } from './shell.js';
|
|
51
51
|
export { SignInError, createEstivaId, } from './client.js';
|
|
52
52
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAA;AAEvC,OAAO,EAQL,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAA;AAEvC,OAAO,EAQL,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,UAAU,EACV,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,UAAU,EACV,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,OAAO,EAOL,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estiva-app/identity",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Estiva ID sign-in: authorization code + PKCE, token storage, silent renewal, sign-out, and the auth-shell state machine. Knows nothing about any app's data layer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/client.ts
CHANGED
|
@@ -73,6 +73,19 @@ declare const URL: {
|
|
|
73
73
|
}
|
|
74
74
|
declare const URLSearchParams: { new (init: string): { get(name: string): string | null } }
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The timer pair, for {@link EstivaIdClient.scheduleRenewal}.
|
|
78
|
+
*
|
|
79
|
+
* Declared here for the same reason as everything above, and returning
|
|
80
|
+
* `unknown` for one more: the handle's real type is `number` in a browser and an
|
|
81
|
+
* object in Node, and naming either would put an ambient type in the published
|
|
82
|
+
* `.d.ts` — which `check-identity.yml` fails the build over, correctly. Nothing
|
|
83
|
+
* outside this module ever sees a handle; `scheduleRenewal` hands back a
|
|
84
|
+
* `cancel` function instead.
|
|
85
|
+
*/
|
|
86
|
+
declare const setTimeout: (run: () => void, ms: number) => unknown
|
|
87
|
+
declare const clearTimeout: (handle: unknown) => void
|
|
88
|
+
|
|
76
89
|
/** Just enough of `fetch` to redeem a code. A parameter as well as a global. */
|
|
77
90
|
export type FetchLike = (
|
|
78
91
|
url: string,
|
|
@@ -122,6 +135,14 @@ export interface EstivaIdConfig {
|
|
|
122
135
|
navigate?: (url: string) => void
|
|
123
136
|
now?: () => number
|
|
124
137
|
fetch?: FetchLike
|
|
138
|
+
/**
|
|
139
|
+
* The timers `scheduleRenewal` runs on, injected for exactly the reason
|
|
140
|
+
* `fetch` and `navigate` are: a test cannot wait ten minutes to find out
|
|
141
|
+
* whether the renewal was scheduled, and "we scheduled it" and "we did
|
|
142
|
+
* nothing" are otherwise the same observation.
|
|
143
|
+
*/
|
|
144
|
+
setTimer?: (run: () => void, ms: number) => unknown
|
|
145
|
+
clearTimer?: (handle: unknown) => void
|
|
125
146
|
}
|
|
126
147
|
|
|
127
148
|
export interface StoredToken {
|
|
@@ -143,8 +164,35 @@ export interface StoredToken {
|
|
|
143
164
|
refreshToken?: string
|
|
144
165
|
}
|
|
145
166
|
|
|
167
|
+
/**
|
|
168
|
+
* `setTimeout`'s ceiling. Above 2^31-1 ms the delay overflows to a negative
|
|
169
|
+
* int32 and the timer fires immediately.
|
|
170
|
+
*/
|
|
171
|
+
const MAX_TIMER_MS = 2_147_483_647
|
|
172
|
+
|
|
146
173
|
export class SignInError extends Error {}
|
|
147
174
|
|
|
175
|
+
/** What a scheduled renewal reports back. Both optional; neither is required to be useful. */
|
|
176
|
+
export interface RenewalHandlers {
|
|
177
|
+
/** A renewal succeeded. The session continues, on a later expiry. */
|
|
178
|
+
onRenewed?: (token: StoredToken) => void
|
|
179
|
+
/**
|
|
180
|
+
* A renewal failed, and the session is over.
|
|
181
|
+
*
|
|
182
|
+
* The only honest thing an app can do here is drop to the shell. Note this
|
|
183
|
+
* fires on refusal *and* on an unreachable network — `refreshAccessToken`
|
|
184
|
+
* distinguishes them for the purpose of clearing the stored token, but from a
|
|
185
|
+
* scheduler's point of view a renewal that did not happen is a renewal that
|
|
186
|
+
* did not happen, and the shell's own probe is what sorts out which it was.
|
|
187
|
+
*/
|
|
188
|
+
onEnded?: () => void
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface RenewalSchedule {
|
|
192
|
+
/** Stop renewing. Idempotent, and safe to call after the session has ended. */
|
|
193
|
+
cancel: () => void
|
|
194
|
+
}
|
|
195
|
+
|
|
148
196
|
interface TokenResponse {
|
|
149
197
|
access_token?: string
|
|
150
198
|
expires_in?: number
|
|
@@ -158,6 +206,7 @@ export interface EstivaIdClient {
|
|
|
158
206
|
beginSignIn: (returnTo: string, options?: { silent?: boolean }) => Promise<void>
|
|
159
207
|
completeSignIn: (search: string) => Promise<{ token: StoredToken; returnTo: string }>
|
|
160
208
|
refreshAccessToken: () => Promise<StoredToken | null>
|
|
209
|
+
scheduleRenewal: (handlers?: RenewalHandlers) => RenewalSchedule
|
|
161
210
|
storedToken: () => StoredToken | null
|
|
162
211
|
validToken: (now?: number) => StoredToken | null
|
|
163
212
|
hasSession: () => boolean
|
|
@@ -300,6 +349,88 @@ export function createEstivaId(config: EstivaIdConfig): EstivaIdClient {
|
|
|
300
349
|
return raw ?? null
|
|
301
350
|
}
|
|
302
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Renew the access token without leaving the page (PEEK-108).
|
|
354
|
+
*
|
|
355
|
+
* This is the whole reason the grant exists. Before it, an expired token
|
|
356
|
+
* could only be replaced by a top-level navigation through `/authorize`,
|
|
357
|
+
* which costs whatever the person had on screen.
|
|
358
|
+
*
|
|
359
|
+
* Returns `null` for every failure, and the failures are not worth
|
|
360
|
+
* distinguishing: Estiva ID answers `invalid_grant` for all of them by
|
|
361
|
+
* design, and the caller's only move either way is to fall back to the
|
|
362
|
+
* shell. The stored token is cleared on refusal so a spent refresh token is
|
|
363
|
+
* never presented twice — a replay is what Estiva ID treats as theft.
|
|
364
|
+
*/
|
|
365
|
+
const performRefresh = async (): Promise<StoredToken | null> => {
|
|
366
|
+
const s = config.storage()
|
|
367
|
+
const current = storedToken()
|
|
368
|
+
if (!s || !current?.refreshToken) return null
|
|
369
|
+
|
|
370
|
+
let response: Awaited<ReturnType<FetchLike>>
|
|
371
|
+
try {
|
|
372
|
+
response = await send()(new URL('/token', config.base).toString(), {
|
|
373
|
+
method: 'POST',
|
|
374
|
+
headers: { 'content-type': 'application/json' },
|
|
375
|
+
body: JSON.stringify({
|
|
376
|
+
grantType: 'refresh_token',
|
|
377
|
+
refreshToken: current.refreshToken,
|
|
378
|
+
clientId: config.clientId,
|
|
379
|
+
}),
|
|
380
|
+
})
|
|
381
|
+
} catch {
|
|
382
|
+
// Unreachable rather than refused. The token in hand may still be fine,
|
|
383
|
+
// so this deliberately does not clear the session — a flaky network must
|
|
384
|
+
// not sign somebody out.
|
|
385
|
+
return null
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (!response.ok) {
|
|
389
|
+
clearSession()
|
|
390
|
+
return null
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const body = (await response.json()) as TokenResponse
|
|
394
|
+
if (!body.access_token) {
|
|
395
|
+
clearSession()
|
|
396
|
+
return null
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const next = tokenFrom(body, body.pubkey ?? current.pubkey)
|
|
400
|
+
s.setItem(TOKEN_KEY, JSON.stringify(next))
|
|
401
|
+
return next
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* The renewal in flight, if there is one.
|
|
406
|
+
*
|
|
407
|
+
* **A refresh token is single-use and a replay is read as theft**, which
|
|
408
|
+
* revokes the whole chain — so two renewals must never be in the air at once.
|
|
409
|
+
* Two easily can be: Ship signs the NIP-98 auth event and the content event as
|
|
410
|
+
* separate `POST /sign` calls, and a token that expires between them answers
|
|
411
|
+
* `401` to both, each of which renews.
|
|
412
|
+
*
|
|
413
|
+
* Peek has guarded this since PEEK-108 with a `refreshing` ref in its Convex
|
|
414
|
+
* adapter, and SHA-4 lists the guard as one of the behaviours that must
|
|
415
|
+
* survive the extraction — but the guard is the one part that did not travel,
|
|
416
|
+
* because it lived in the hook rather than the client. So Peek kept it and
|
|
417
|
+
* Ship never had it. It belongs here, where every caller of every consumer
|
|
418
|
+
* gets it whether or not they thought about it.
|
|
419
|
+
*
|
|
420
|
+
* Coalescing rather than caching: the promise is dropped the moment it
|
|
421
|
+
* settles, so the *next* expiry renews again.
|
|
422
|
+
*/
|
|
423
|
+
let refreshing: Promise<StoredToken | null> | null = null
|
|
424
|
+
|
|
425
|
+
const refreshAccessToken = (): Promise<StoredToken | null> => {
|
|
426
|
+
if (refreshing) return refreshing
|
|
427
|
+
refreshing = performRefresh().finally(() => {
|
|
428
|
+
refreshing = null
|
|
429
|
+
})
|
|
430
|
+
return refreshing
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
|
|
303
434
|
return {
|
|
304
435
|
redirectUri: config.redirectUri,
|
|
305
436
|
codeChallenge,
|
|
@@ -464,58 +595,95 @@ export function createEstivaId(config: EstivaIdConfig): EstivaIdClient {
|
|
|
464
595
|
return { token, returnTo }
|
|
465
596
|
},
|
|
466
597
|
|
|
598
|
+
refreshAccessToken,
|
|
599
|
+
|
|
467
600
|
/**
|
|
468
|
-
* Renew the
|
|
601
|
+
* Renew shortly **before** the token expires, rather than reacting to it
|
|
602
|
+
* having expired.
|
|
603
|
+
*
|
|
604
|
+
* SHA-4 lists this as one of the behaviours that must survive the
|
|
605
|
+
* extraction, and it is the one that reads as an optimisation and is not.
|
|
606
|
+
* Reacting to expiry means somebody's next action is the thing that
|
|
607
|
+
* discovers the session is over — a failed publish, a blank list, or at best
|
|
608
|
+
* a retry they can feel. Renewing 30 seconds early (`tokenFrom` already
|
|
609
|
+
* subtracts them) means they notice nothing at all.
|
|
610
|
+
*
|
|
611
|
+
* It did not travel with the rest of SHA-4: the timer lived in Peek's Convex
|
|
612
|
+
* adapter, so Peek kept it and Ship, whose whole point was to be the second
|
|
613
|
+
* consumer, silently did not get it. Ship renews only when `POST /sign`
|
|
614
|
+
* answers `401`, which is precisely "on failure".
|
|
469
615
|
*
|
|
470
|
-
*
|
|
471
|
-
* could only be replaced by a top-level navigation through `/authorize`,
|
|
472
|
-
* which costs whatever the person had on screen.
|
|
616
|
+
* ## The timer is a `setTimeout`, and browsers throttle those
|
|
473
617
|
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
618
|
+
* A background tab gets its timers clamped — to once a minute in Chrome and
|
|
619
|
+
* Safari, and after five minutes of being hidden they may be frozen outright.
|
|
620
|
+
* So a tab left in the background can miss its renewal window entirely.
|
|
621
|
+
*
|
|
622
|
+
* This is a known limitation rather than a bug, and it is recorded here so
|
|
623
|
+
* it is not rediscovered once per app. It degrades safely: a late renewal is
|
|
624
|
+
* still a valid renewal, because the refresh token outlives the access token
|
|
625
|
+
* by a long way, and a call that beats the late timer gets the existing
|
|
626
|
+
* `401`-and-retry path. What it must not do is renew *twice* in the scramble,
|
|
627
|
+
* which is what the guard on `refreshAccessToken` is for.
|
|
628
|
+
*
|
|
629
|
+
* A `visibilitychange` listener that re-arms on foreground would tighten
|
|
630
|
+
* this, and is deliberately not here: `document` is a global this package
|
|
631
|
+
* does not touch (ADR 0002 §4a), and an app that wants it can `cancel()` and
|
|
632
|
+
* call this again.
|
|
479
633
|
*/
|
|
480
|
-
|
|
481
|
-
const
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
let
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
634
|
+
scheduleRenewal(handlers: RenewalHandlers = {}): RenewalSchedule {
|
|
635
|
+
const setTimer = config.setTimer ?? ((run, ms) => setTimeout(run, ms))
|
|
636
|
+
const clearTimer = config.clearTimer ?? ((handle) => clearTimeout(handle))
|
|
637
|
+
|
|
638
|
+
let handle: unknown = null
|
|
639
|
+
let cancelled = false
|
|
640
|
+
|
|
641
|
+
const arm = (): void => {
|
|
642
|
+
const token = storedToken()
|
|
643
|
+
// Nothing to renew. Not an ending — the caller is simply signed out, and
|
|
644
|
+
// an app that signs in later starts a new schedule.
|
|
645
|
+
if (!token) return
|
|
646
|
+
|
|
647
|
+
/*
|
|
648
|
+
Clamped at both ends. A negative delay is a token that already expired
|
|
649
|
+
— renew now rather than never, since the refresh token almost certainly
|
|
650
|
+
has not. The ceiling is `setTimeout`'s: a delay above 2^31-1 ms
|
|
651
|
+
overflows to a negative int32 and fires immediately, so a nonsensical
|
|
652
|
+
`expires_in` would otherwise become a hot loop against `/token` instead
|
|
653
|
+
of one very distant timer.
|
|
654
|
+
*/
|
|
655
|
+
const delay = Math.min(Math.max(0, token.expiresAt - now()), MAX_TIMER_MS)
|
|
656
|
+
|
|
657
|
+
handle = setTimer(() => {
|
|
658
|
+
handle = null
|
|
659
|
+
void refreshAccessToken().then((next) => {
|
|
660
|
+
if (cancelled) return
|
|
661
|
+
if (!next) {
|
|
662
|
+
handlers.onEnded?.()
|
|
663
|
+
return
|
|
664
|
+
}
|
|
665
|
+
handlers.onRenewed?.(next)
|
|
666
|
+
// Re-armed from the *new* expiry rather than a fixed interval, so
|
|
667
|
+
// the schedule follows whatever lifetime Estiva ID actually issued.
|
|
668
|
+
arm()
|
|
669
|
+
})
|
|
670
|
+
}, delay)
|
|
501
671
|
}
|
|
502
672
|
|
|
503
|
-
|
|
504
|
-
clearSession()
|
|
505
|
-
return null
|
|
506
|
-
}
|
|
673
|
+
arm()
|
|
507
674
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
675
|
+
return {
|
|
676
|
+
cancel(): void {
|
|
677
|
+
cancelled = true
|
|
678
|
+
if (handle !== null) {
|
|
679
|
+
clearTimer(handle)
|
|
680
|
+
handle = null
|
|
681
|
+
}
|
|
682
|
+
},
|
|
512
683
|
}
|
|
513
|
-
|
|
514
|
-
const next = tokenFrom(body, body.pubkey ?? current.pubkey)
|
|
515
|
-
s.setItem(TOKEN_KEY, JSON.stringify(next))
|
|
516
|
-
return next
|
|
517
684
|
},
|
|
518
685
|
|
|
686
|
+
|
|
519
687
|
/**
|
|
520
688
|
* Leave for Estiva ID to end the session *there* (PEEK-122).
|
|
521
689
|
*
|
package/src/index.ts
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
* The thing that made it possible was not cleverness — it was that a browser API
|
|
47
47
|
* an app must inject is also a browser API a test can observe.
|
|
48
48
|
*/
|
|
49
|
-
export const IDENTITY_VERSION = '0.1.
|
|
49
|
+
export const IDENTITY_VERSION = '0.1.2'
|
|
50
50
|
|
|
51
51
|
export {
|
|
52
52
|
type KeyValueStore,
|
|
@@ -76,6 +76,8 @@ export {
|
|
|
76
76
|
type EstivaIdClient,
|
|
77
77
|
type StoredToken,
|
|
78
78
|
type FetchLike,
|
|
79
|
+
type RenewalHandlers,
|
|
80
|
+
type RenewalSchedule,
|
|
79
81
|
SignInError,
|
|
80
82
|
createEstivaId,
|
|
81
83
|
} from './client.js'
|