move resolveReauth

This commit is contained in:
Neal Shah
2026-07-22 18:18:52 -04:00
parent d03363f2f1
commit 5aeed62d22
2 changed files with 71 additions and 61 deletions
+69 -2
View File
@@ -17,7 +17,74 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { createDeferred, resolveReauth } from './utils.js';
const createDeferred = () => {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
/**
* Shared 401 reauth policy for a parsed response body. Drives the env-specific
* reauth flow on the Puter class and tells the caller what to do next, so the
* fetch replacement (`fetchUrl`) and the generic XHR path (`handle_resp` in
* utils.js) apply the exact same policy. The driver-call handler (`driverCall_`)
* keeps its own replay because it must preserve streaming/transform semantics
* on retry.
*
* Recognised backend signals:
* - `reauth_required` (v2 `authProbe`): legacy v1 tokens, revoked sessions,
* and expired sessions beyond the silent re-mint window.
* - `token_auth_failed` (legacy `APIError.create('token_auth_failed')`):
* token no longer valid, prompt re-login (web env only).
*
* @param {Object} resp - The parsed response body.
* @returns {Promise<{action: 'replay'}|{action: 'reject', error: Object}|null>}
* `replay` when the caller should re-issue the request once with the fresh
* token, `reject` with the error to surface, or `null` when this is not a
* reauth-recoverable 401 and the caller should handle it normally.
*/
async function resolveReauth (resp) {
if ( resp?.code === 'reauth_required' ) {
try {
await puter.triggerReauth({
reason: resp.reason,
auth_id: resp.auth_id,
});
return { action: 'replay' };
} catch ( e ) {
return {
action: 'reject',
error: {
status: 401,
code: 'reauth_required',
reason: resp.reason,
auth_id: resp.auth_id,
message: e?.message || 'Reauthentication required',
},
};
}
}
if ( resp?.code === 'token_auth_failed' && puter.env === 'web' ) {
try {
puter.resetAuthToken();
await puter.ui.authenticateWithPuter();
} catch (e) {
return {
action: 'reject',
error: {
error: {
code: 'auth_canceled', message: 'Authentication canceled',
},
},
};
}
}
return null;
}
/**
* The single HTTP core for puter.js. `fetchUrl` is an XHR-based replacement for
@@ -277,4 +344,4 @@ function fetchUrl (url, opts = {}) {
});
}
export { fetchUrl };
export { fetchUrl, resolveReauth };
+2 -59
View File
@@ -1,4 +1,5 @@
import { FileReaderPoly } from './polyfills/fileReaderPoly.js';
import { resolveReauth } from './PuterClient.js';
import { showUsageLimitDialog } from '../modules/UsageLimitDialog.js';
import { showEmailConfirmationDialog } from '../modules/EmailConfirmationDialog.js';
@@ -155,64 +156,6 @@ function replayXhrAfterReauth (response, success_cb, error_cb, resolve_func, rej
return true;
}
/**
* Shared 401 reauth policy for a parsed response body. Drives the env-specific
* reauth flow on the Puter class and tells the caller what to do next, so the
* generic XHR path (`handle_resp`) and the fetch replacement (`fetchUrl`) apply
* the exact same policy. The driver-call handler (`driverCall_`) keeps its own
* replay because it must preserve streaming/transform semantics on retry.
*
* Recognised backend signals:
* - `reauth_required` (v2 `authProbe`): legacy v1 tokens, revoked sessions,
* and expired sessions beyond the silent re-mint window.
* - `token_auth_failed` (legacy `APIError.create('token_auth_failed')`):
* token no longer valid, prompt re-login (web env only).
*
* @param {Object} resp - The parsed response body.
* @returns {Promise<{action: 'replay'}|{action: 'reject', error: Object}|null>}
* `replay` when the caller should re-issue the request once with the fresh
* token, `reject` with the error to surface, or `null` when this is not a
* reauth-recoverable 401 and the caller should handle it normally.
*/
async function resolveReauth (resp) {
if ( resp?.code === 'reauth_required' ) {
try {
await puter.triggerReauth({
reason: resp.reason,
auth_id: resp.auth_id,
});
return { action: 'replay' };
} catch ( e ) {
return {
action: 'reject',
error: {
status: 401,
code: 'reauth_required',
reason: resp.reason,
auth_id: resp.auth_id,
message: e?.message || 'Reauthentication required',
},
};
}
}
if ( resp?.code === 'token_auth_failed' && puter.env === 'web' ) {
try {
puter.resetAuthToken();
await puter.ui.authenticateWithPuter();
} catch (e) {
return {
action: 'reject',
error: {
error: {
code: 'auth_canceled', message: 'Authentication canceled',
},
},
};
}
}
return null;
}
/**
* Handles an HTTP response by invoking appropriate callback functions and resolving or rejecting a promise.
*
@@ -811,5 +754,5 @@ const isVideoInput = (url) => {
};
export {
arrayBufferToDataUri, blob_to_url, blobToDataUri, createDeferred, driverCall, handle_error, handle_resp, initXhr, isVideoInput, make_driver_method, parseResponse, resolveReauth, setupXhrEventHandlers, uuidv4,
arrayBufferToDataUri, blob_to_url, blobToDataUri, driverCall, handle_error, handle_resp, initXhr, isVideoInput, make_driver_method, parseResponse, setupXhrEventHandlers, uuidv4,
};