@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.
@@ -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 the rotated `nextDeviceSecret` BEFORE planting the
135
- // token, and returns a classified outcome — so this step can never
136
- // double-rotate the server against the scheduler/transport/401 lanes, and
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 the rotated secret and planted the token.
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` (rotation-in-use)
64
- * and the projected device-session `state`.
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 rotating device-secret mint, run under the owning client's
36
- * PROCESS-WIDE single-flight (`httpService.runSingleFlightDeviceSecretMint`).
35
+ * Arm 1 — the device-secret mint, run under the owning client's PROCESS-WIDE
36
+ * single-flight (`httpService.runSingleFlightDeviceSecretMint`).
37
37
  *
38
- * The server ROTATES the presented `deviceSecret` on every successful mint and
39
- * the just-presented secret is valid only for a short grace window. If two lanes
40
- * (cold boot, the proactive scheduler, a request-time preflight, a 401 retry,
41
- * the socket token transport, or a tab-focus reconcile) minted concurrently they
42
- * would double-rotate the server and the durable store could converge on the
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
- // Rotation-in-use anti-loss: persist the NEXT secret and read-back-VERIFY it
119
- // landed BEFORE planting the token. A failed durable persist must NOT plant.
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' };