@oxyhq/core 17.1.0 → 18.0.0
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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/boot/sessionColdBoot.js +4 -5
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +3 -2
- package/dist/cjs/session/refresh.js +9 -14
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/boot/sessionColdBoot.js +4 -5
- package/dist/esm/mixins/OxyServices.deviceBoot.js +3 -2
- package/dist/esm/session/refresh.js +9 -14
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/mixins/OxyServices.accounts.d.ts +16 -5
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +3 -2
- package/dist/types/session/refresh.d.ts +13 -18
- package/package.json +1 -1
- package/src/boot/sessionColdBoot.ts +4 -5
- package/src/index.ts +0 -1
- package/src/mixins/OxyServices.accounts.ts +16 -6
- package/src/mixins/OxyServices.deviceBoot.ts +3 -2
- package/src/session/refresh.ts +15 -20
|
@@ -131,10 +131,9 @@ export async function runSessionColdBoot(opts) {
|
|
|
131
131
|
// origin persisted a deviceId + deviceSecret, mint a short access token with
|
|
132
132
|
// a single bearer-less POST (no cookie, no navigation). The mint itself runs
|
|
133
133
|
// through `refreshDeviceSecretArm`, which acquires the client's PROCESS-WIDE
|
|
134
|
-
// single-flight, persists
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
// the durable store always converges on the true `current` secret.
|
|
134
|
+
// single-flight, persists `nextDeviceSecret` BEFORE planting the token, and
|
|
135
|
+
// returns a classified outcome — so concurrent mint lanes share one in-flight
|
|
136
|
+
// request and the durable store always converges on the server's credential.
|
|
138
137
|
steps.push({
|
|
139
138
|
id: 'device-secret-mint',
|
|
140
139
|
// Network step — skip entirely when the caller reports the device offline so
|
|
@@ -153,7 +152,7 @@ export async function runSessionColdBoot(opts) {
|
|
|
153
152
|
const result = await refreshDeviceSecretArm({ oxy, store, pin });
|
|
154
153
|
switch (result.status) {
|
|
155
154
|
case 'ok':
|
|
156
|
-
// The arm persisted
|
|
155
|
+
// The arm persisted nextDeviceSecret and planted the token.
|
|
157
156
|
return {
|
|
158
157
|
kind: 'session',
|
|
159
158
|
session: {
|
|
@@ -60,8 +60,9 @@ export function OxyServicesDeviceBootMixin(Base) {
|
|
|
60
60
|
* Zero-cookie mint. Present the first-party `deviceId` + `deviceSecret` to
|
|
61
61
|
* `POST /session/device/token` — NO bearer, NO cookies: possession of the
|
|
62
62
|
* secret IS the device-ownership proof. Returns a fresh short access token
|
|
63
|
-
* for the device's active account plus `nextDeviceSecret` (
|
|
64
|
-
*
|
|
63
|
+
* for the device's active account plus `nextDeviceSecret` (on mint, the same
|
|
64
|
+
* proven secret echoed back — rotation happens on sign-in, not mint) and
|
|
65
|
+
* the projected device-session `state`.
|
|
65
66
|
*
|
|
66
67
|
* `skipAuth`: this call carries no bearer, so a 401 must surface DIRECTLY —
|
|
67
68
|
* never trigger `HttpService`'s 401→refresh→retry dance. The cold boot / re-
|
|
@@ -32,19 +32,14 @@ const MIN_SCHEDULE_DELAY_MS = 1000;
|
|
|
32
32
|
const MIN_FAILURE_BACKOFF_MS = 5000;
|
|
33
33
|
const MAX_FAILURE_BACKOFF_MS = 5 * 60000;
|
|
34
34
|
/**
|
|
35
|
-
* Arm 1 — the
|
|
36
|
-
*
|
|
35
|
+
* Arm 1 — the device-secret mint, run under the owning client's PROCESS-WIDE
|
|
36
|
+
* single-flight (`httpService.runSingleFlightDeviceSecretMint`).
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* SUPERSEDED secret — after the grace window the next cold boot mint 401s and the
|
|
44
|
-
* user is signed out. Routing EVERY lane through this one single-flight makes
|
|
45
|
-
* concurrent callers await the SAME in-flight mint and all receive its result, so
|
|
46
|
-
* there is exactly one rotation and the store always converges on the true
|
|
47
|
-
* `current` secret.
|
|
38
|
+
* Concurrent lanes (cold boot, the proactive scheduler, a request-time preflight,
|
|
39
|
+
* a 401 retry, the socket token transport, or a tab-focus reconcile) must not
|
|
40
|
+
* each persist a different view of the mint response. Routing EVERY lane through
|
|
41
|
+
* this one single-flight makes concurrent callers await the SAME in-flight mint
|
|
42
|
+
* and all receive its result, so the durable store converges on one credential.
|
|
48
43
|
*
|
|
49
44
|
* On success it persists `nextDeviceSecret` (read-back-verified) BEFORE planting
|
|
50
45
|
* the access token; a failed durable persist yields `persist-failed` WITHOUT
|
|
@@ -115,8 +110,8 @@ export async function refreshDeviceSecretArm(deps) {
|
|
|
115
110
|
expiresAt: mint.expiresAt,
|
|
116
111
|
...(bound ? { sessionId: bound.sessionId, userId: bound.accountId } : {}),
|
|
117
112
|
};
|
|
118
|
-
//
|
|
119
|
-
//
|
|
113
|
+
// Persist nextDeviceSecret (read-back-verified) BEFORE planting the token.
|
|
114
|
+
// A failed durable persist must NOT plant.
|
|
120
115
|
const persistedOk = await store.save(next);
|
|
121
116
|
if (!persistedOk) {
|
|
122
117
|
return { status: 'persist-failed' };
|