gent-cli 14.0.0 → 20.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/README.md +1 -1
- package/package.json +7 -4
- package/src/commands/canonical.js +242 -0
- package/src/commands/clone.js +2 -13
- package/src/commands/pet.js +122 -98
- package/src/commands/pull.js +3 -4
- package/src/commands/push.js +4 -5
- package/src/commands/share.js +40 -15
- package/src/commands/web.js +30 -15
- package/src/index.js +70 -40
- package/src/utils/api-client.js +6 -9
- package/src/utils/attributes.js +280 -0
- package/src/utils/canonical-journal.js +122 -0
- package/src/utils/feature-support.js +92 -0
- package/src/utils/feature-support.json +210 -0
- package/src/utils/gent-ops.js +836 -0
- package/src/utils/git-config.js +606 -0
- package/src/utils/git-index.js +581 -0
- package/src/utils/git-objects.js +537 -0
- package/src/utils/ignore.js +365 -0
- package/src/utils/lockfile.js +219 -0
- package/src/utils/merge-ops.js +282 -0
- package/src/utils/migrate.js +257 -0
- package/src/utils/object-store.js +332 -36
- package/src/utils/packfile.js +812 -0
- package/src/utils/refs.js +595 -0
- package/src/utils/repository.js +533 -0
- package/src/utils/smart-http.js +195 -0
- package/src/utils/stash-ops.js +355 -0
- package/src/utils/user-config.js +10 -0
- package/src/utils/web-urls.js +125 -0
- package/src/utils/worktree.js +676 -0
package/src/commands/share.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Share Command - Print a shareable link to current branch/commit.
|
|
3
3
|
*
|
|
4
|
-
* gent share → link to
|
|
5
|
-
* gent share --branch <name> → link
|
|
6
|
-
* gent share --commit <hash> → link
|
|
4
|
+
* gent share → link to the repository
|
|
5
|
+
* gent share --branch <name> → same link, branch reported as context
|
|
6
|
+
* gent share --commit <hash> → same link, commit validated and reported
|
|
7
7
|
*
|
|
8
|
-
* Like `gent web --print`
|
|
9
|
-
*
|
|
8
|
+
* Like `gent web --print` — handy for Slack/PR descriptions. stdout carries
|
|
9
|
+
* only the URL so `gent share | pbcopy` gives a clean link; all context goes
|
|
10
|
+
* to stderr.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: the web app has no branch or commit page today, so every link resolves
|
|
13
|
+
* to the repository page; the branch/commit is reported as context only.
|
|
14
|
+
* See utils/web-urls.js.
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
17
|
const path = require('path');
|
|
13
18
|
const chalk = require('chalk');
|
|
14
19
|
const { getGentPath, readJSON } = require('../utils/fileSystem');
|
|
15
20
|
const { CONFIG_FILE, COMMITS_FILE, parseRemoteUrl } = require('../utils/constants');
|
|
16
|
-
const
|
|
21
|
+
const { getWebBaseUrl, buildRepoLink, BRANCH_COMMIT_UNSUPPORTED } = require('../utils/web-urls');
|
|
17
22
|
|
|
18
23
|
async function share(options = {}) {
|
|
19
24
|
try {
|
|
@@ -33,22 +38,42 @@ async function share(options = {}) {
|
|
|
33
38
|
process.exit(1);
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
|
|
41
|
+
const baseUrl = await getWebBaseUrl();
|
|
42
|
+
const { url, unsupported } = buildRepoLink(baseUrl, info, {
|
|
43
|
+
branch: options.branch,
|
|
44
|
+
commit: options.commit,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// A --commit the repo doesn't know about is a typo, not a link: refuse
|
|
48
|
+
// rather than echo a fabricated reference into a PR description.
|
|
49
|
+
if (options.commit) {
|
|
50
|
+
const known = (repository.commits || [])
|
|
51
|
+
.some((c) => c && typeof c.hash === 'string' && c.hash.startsWith(options.commit));
|
|
52
|
+
if (!known) {
|
|
53
|
+
console.error(chalk.red(`Unknown commit '${options.commit}' in this repository.`));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Only warn when the user actually asked for a link we can't build.
|
|
59
|
+
if (unsupported) {
|
|
60
|
+
console.error(chalk.gray(BRANCH_COMMIT_UNSUPPORTED));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// stdout carries the URL and nothing else, so `gent share | pbcopy`
|
|
64
|
+
// yields a clean link. All human context goes to stderr.
|
|
65
|
+
console.log(url);
|
|
39
66
|
|
|
40
67
|
if (options.commit) {
|
|
41
|
-
console.
|
|
68
|
+
console.error(chalk.gray(`(commit ${String(options.commit).slice(0, 7)})`));
|
|
42
69
|
return;
|
|
43
70
|
}
|
|
44
71
|
const branch = options.branch || repository.currentBranch;
|
|
45
|
-
const tip = repository.branches[branch];
|
|
72
|
+
const tip = (repository.branches || {})[branch];
|
|
46
73
|
if (tip) {
|
|
47
|
-
console.
|
|
48
|
-
console.log(chalk.gray(`(${branch} @ ${tip.slice(0, 7)})`));
|
|
74
|
+
console.error(chalk.gray(`(${branch} @ ${tip.slice(0, 7)})`));
|
|
49
75
|
} else {
|
|
50
|
-
console.
|
|
51
|
-
console.log(chalk.gray(`(${branch} has no commits yet)`));
|
|
76
|
+
console.error(chalk.gray(`(${branch} has no commits yet)`));
|
|
52
77
|
}
|
|
53
78
|
} catch (error) {
|
|
54
79
|
if (error.code === 'ENOENT' && error.message.includes('.gent')) {
|
package/src/commands/web.js
CHANGED
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
* Web Command - Open the current repo (or a specific commit/branch) in browser.
|
|
3
3
|
*
|
|
4
4
|
* gent web → open repo page
|
|
5
|
-
* gent web --branch <name> →
|
|
6
|
-
* gent web --commit <hash> →
|
|
5
|
+
* gent web --branch <name> → repo page (branch context only — see NOTE)
|
|
6
|
+
* gent web --commit <hash> → repo page (commit context only — see NOTE)
|
|
7
7
|
* gent web --print → don't launch, just print the URL
|
|
8
8
|
*
|
|
9
|
-
* Builds the URL from the configured api.base_url
|
|
9
|
+
* Builds the URL from the configured web.base_url (NOT api.base_url — the web
|
|
10
|
+
* app is a separate deployment) and the remote's owner_id/repo_name.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: the web app has no branch or commit page today, so --branch/--commit
|
|
13
|
+
* warn and fall back to the repository page. See utils/web-urls.js.
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
const path = require('path');
|
|
13
|
-
const {
|
|
17
|
+
const { execFile } = require('child_process');
|
|
14
18
|
const chalk = require('chalk');
|
|
15
19
|
const { getGentPath, readJSON } = require('../utils/fileSystem');
|
|
16
20
|
const { CONFIG_FILE, parseRemoteUrl } = require('../utils/constants');
|
|
17
|
-
const
|
|
21
|
+
const { getWebBaseUrl, buildRepoLink, BRANCH_COMMIT_UNSUPPORTED } = require('../utils/web-urls');
|
|
18
22
|
|
|
19
23
|
async function web(options = {}) {
|
|
20
24
|
try {
|
|
@@ -32,13 +36,16 @@ async function web(options = {}) {
|
|
|
32
36
|
process.exit(1);
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
const baseUrl = await getWebBaseUrl();
|
|
40
|
+
const { url, unsupported } = buildRepoLink(baseUrl, info, {
|
|
41
|
+
branch: options.branch,
|
|
42
|
+
commit: options.commit,
|
|
43
|
+
});
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
if (unsupported) {
|
|
46
|
+
console.error(chalk.yellow(`Note: --${unsupported} is not supported yet.`));
|
|
47
|
+
console.error(chalk.gray(BRANCH_COMMIT_UNSUPPORTED));
|
|
48
|
+
}
|
|
42
49
|
|
|
43
50
|
if (options.print) {
|
|
44
51
|
console.log(url);
|
|
@@ -57,11 +64,19 @@ async function web(options = {}) {
|
|
|
57
64
|
}
|
|
58
65
|
}
|
|
59
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Hand the URL to the platform's browser launcher.
|
|
69
|
+
*
|
|
70
|
+
* Uses execFile, NOT exec: the URL is passed as its own argv entry so no shell
|
|
71
|
+
* ever parses it. Interpolating it into a shell string made a `"` in
|
|
72
|
+
* web.base_url a command-injection sink, and broke any legitimate URL
|
|
73
|
+
* containing & or $.
|
|
74
|
+
*/
|
|
60
75
|
function openInBrowser(url) {
|
|
61
|
-
const cmd = process.platform === 'darwin' ? 'open'
|
|
62
|
-
: process.platform === 'win32' ? 'start
|
|
63
|
-
: 'xdg-open';
|
|
64
|
-
|
|
76
|
+
const [cmd, args] = process.platform === 'darwin' ? ['open', [url]]
|
|
77
|
+
: process.platform === 'win32' ? ['cmd', ['/c', 'start', '', url]]
|
|
78
|
+
: ['xdg-open', [url]];
|
|
79
|
+
execFile(cmd, args, (err) => {
|
|
65
80
|
if (err) {
|
|
66
81
|
console.error(chalk.yellow('Could not auto-open. URL:'));
|
|
67
82
|
console.log(url);
|
package/src/index.js
CHANGED
|
@@ -30,33 +30,34 @@ const { program } = require('commander');
|
|
|
30
30
|
const chalk = require('chalk');
|
|
31
31
|
const packageJson = require('../package.json');
|
|
32
32
|
const interactive = require('./utils/interactive');
|
|
33
|
+
const { route } = require('./commands/canonical');
|
|
33
34
|
|
|
34
35
|
// Import core commands
|
|
35
|
-
const autoCommand = require('./commands/auto');
|
|
36
|
-
const initCommand = require('./commands/init');
|
|
36
|
+
const autoCommand = route('auto', require('./commands/auto'));
|
|
37
|
+
const initCommand = route('init', require('./commands/init'));
|
|
37
38
|
const cloneCommand = require('./commands/clone');
|
|
38
|
-
const statusCommand = require('./commands/status');
|
|
39
|
-
const addCommand = require('./commands/add');
|
|
40
|
-
const rmCommand = require('./commands/rm');
|
|
41
|
-
const resetCommand = require('./commands/reset');
|
|
42
|
-
const diffCommand = require('./commands/diff');
|
|
43
|
-
const commitCommand = require('./commands/commit');
|
|
44
|
-
const logCommand = require('./commands/log');
|
|
45
|
-
const showCommand = require('./commands/show');
|
|
46
|
-
const tagCommand = require('./commands/tag');
|
|
47
|
-
const branchCommand = require('./commands/branch');
|
|
48
|
-
const checkoutCommand = require('./commands/checkout');
|
|
49
|
-
const mergeCommand = require('./commands/merge');
|
|
50
|
-
const stashCommand = require('./commands/stash');
|
|
51
|
-
const remoteCommand = require('./commands/remote');
|
|
52
|
-
const pushCommand = require('./commands/push');
|
|
53
|
-
const pullCommand = require('./commands/pull');
|
|
39
|
+
const statusCommand = route('status', require('./commands/status'));
|
|
40
|
+
const addCommand = route('add', require('./commands/add'));
|
|
41
|
+
const rmCommand = route('rm', require('./commands/rm'));
|
|
42
|
+
const resetCommand = route('reset', require('./commands/reset'));
|
|
43
|
+
const diffCommand = route('diff', require('./commands/diff'));
|
|
44
|
+
const commitCommand = route('commit', require('./commands/commit'));
|
|
45
|
+
const logCommand = route('log', require('./commands/log'));
|
|
46
|
+
const showCommand = route('show', require('./commands/show'));
|
|
47
|
+
const tagCommand = route('tag', require('./commands/tag'));
|
|
48
|
+
const branchCommand = route('branch', require('./commands/branch'));
|
|
49
|
+
const checkoutCommand = route('checkout', require('./commands/checkout'));
|
|
50
|
+
const mergeCommand = route('merge', require('./commands/merge'));
|
|
51
|
+
const stashCommand = route('stash', require('./commands/stash'));
|
|
52
|
+
const remoteCommand = route('remote', require('./commands/remote'));
|
|
53
|
+
const pushCommand = route('push', require('./commands/push'));
|
|
54
|
+
const pullCommand = route('pull', require('./commands/pull'));
|
|
54
55
|
const reposCommand = require('./commands/repos');
|
|
55
56
|
const membersCommand = require('./commands/members');
|
|
56
|
-
const undoCommand = require('./commands/undo');
|
|
57
|
-
const resolveCommand = require('./commands/resolve');
|
|
58
|
-
const summaryCommand = require('./commands/summary');
|
|
59
|
-
const explainCommand = require('./commands/explain');
|
|
57
|
+
const undoCommand = route('undo', require('./commands/undo'));
|
|
58
|
+
const resolveCommand = route('resolve', require('./commands/resolve'));
|
|
59
|
+
const summaryCommand = route('summary', require('./commands/summary'));
|
|
60
|
+
const explainCommand = route('explain', require('./commands/explain'));
|
|
60
61
|
|
|
61
62
|
// Import auth commands
|
|
62
63
|
const registerCommand = require('./commands/register');
|
|
@@ -66,16 +67,16 @@ const whoamiCommand = require('./commands/whoami');
|
|
|
66
67
|
const passwordCommand = require('./commands/password');
|
|
67
68
|
|
|
68
69
|
// Import new gent-platform commands
|
|
69
|
-
const configCommand = require('./commands/config');
|
|
70
|
+
const configCommand = route('config', require('./commands/config'));
|
|
70
71
|
const doctorCommand = require('./commands/doctor');
|
|
71
72
|
const setupCommand = require('./commands/setup');
|
|
72
73
|
const aiCommand = require('./commands/ai');
|
|
73
|
-
const askCommand = require('./commands/ask');
|
|
74
|
-
const reviewCommand = require('./commands/review');
|
|
75
|
-
const docsCommand = require('./commands/docs');
|
|
76
|
-
const changelogCommand = require('./commands/changelog');
|
|
74
|
+
const askCommand = route('ask', require('./commands/ask'));
|
|
75
|
+
const reviewCommand = route('review', require('./commands/review'));
|
|
76
|
+
const docsCommand = route('docs', require('./commands/docs'));
|
|
77
|
+
const changelogCommand = route('changelog', require('./commands/changelog'));
|
|
77
78
|
const webCommand = require('./commands/web');
|
|
78
|
-
const shareCommand = require('./commands/share');
|
|
79
|
+
const shareCommand = route('share', require('./commands/share'));
|
|
79
80
|
const searchCommand = require('./commands/search');
|
|
80
81
|
const templateCommand = require('./commands/template');
|
|
81
82
|
const petCommand = require('./commands/pet');
|
|
@@ -97,9 +98,21 @@ program
|
|
|
97
98
|
.command('init')
|
|
98
99
|
.description('Initialize a new gent repository')
|
|
99
100
|
.option('-y, --yes', 'Skip prompts and use defaults')
|
|
101
|
+
.option('--object-format <format>', 'Opt into the canonical SHA-256 engine')
|
|
100
102
|
.option('--remote [name]', 'Create a remote repository on the backend')
|
|
101
103
|
.action(initCommand);
|
|
102
104
|
|
|
105
|
+
program
|
|
106
|
+
.command('migrate')
|
|
107
|
+
.description('Migrate an offline legacy repository with a verified backup')
|
|
108
|
+
.option('--dry-run', 'Inspect and validate without changing repository state')
|
|
109
|
+
.option('--continue', 'Complete an interrupted migration')
|
|
110
|
+
.option('--abort', 'Roll back an interrupted migration if no newer state exists')
|
|
111
|
+
.action(async options => {
|
|
112
|
+
try { console.log(JSON.stringify(await require('./utils/migrate').migrate(process.cwd(), options), null, 2)); }
|
|
113
|
+
catch (error) { console.error(`Error: ${error.message}`); process.exitCode = 1; }
|
|
114
|
+
});
|
|
115
|
+
|
|
103
116
|
program
|
|
104
117
|
.command('clone [url] [directory]')
|
|
105
118
|
.description('Clone a remote repository')
|
|
@@ -111,6 +124,11 @@ program
|
|
|
111
124
|
console.error(chalk.red('error: missing url — usage: gent clone <url> [directory]'));
|
|
112
125
|
process.exit(1);
|
|
113
126
|
}
|
|
127
|
+
if (/^https?:/.test(url) && /\.git\/?$/.test(url)) {
|
|
128
|
+
try { console.log(`Cloned to ${await require('./utils/smart-http').clone(url, directory)}`); }
|
|
129
|
+
catch (error) { console.error(`Error: ${error.message}`); process.exitCode = 1; }
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
114
132
|
return cloneCommand(url, directory, options);
|
|
115
133
|
});
|
|
116
134
|
|
|
@@ -152,8 +170,8 @@ program
|
|
|
152
170
|
program
|
|
153
171
|
.command('reset [files...]')
|
|
154
172
|
.description('Unstage files or reset HEAD to a commit')
|
|
155
|
-
.option('--hard
|
|
156
|
-
.option('--soft
|
|
173
|
+
.option('--hard [hash]', 'Reset HEAD and working tree to commit')
|
|
174
|
+
.option('--soft [hash]', 'Reset HEAD but keep staging')
|
|
157
175
|
.action(resetCommand);
|
|
158
176
|
|
|
159
177
|
program
|
|
@@ -221,13 +239,15 @@ program
|
|
|
221
239
|
.command('checkout [branch]')
|
|
222
240
|
.description('Switch branches or restore working tree files')
|
|
223
241
|
.option('-b, --create', 'Create a new branch')
|
|
242
|
+
.option('--abort', 'Recover an interrupted canonical checkout')
|
|
243
|
+
.option('-f, --force', 'Discard local changes when switching')
|
|
224
244
|
.action(async (branch, options) => {
|
|
225
|
-
if (!branch && interactive.isInteractive()) {
|
|
245
|
+
if (!branch && !options.abort && interactive.isInteractive()) {
|
|
226
246
|
const picked = await interactive.promptCheckout();
|
|
227
247
|
branch = picked.branch;
|
|
228
248
|
options.create = picked.create; // picker decides: existing branch ⇒ switch, not create
|
|
229
249
|
}
|
|
230
|
-
if (!branch) {
|
|
250
|
+
if (!branch && !options.abort) {
|
|
231
251
|
console.error(chalk.red('error: missing branch — usage: gent checkout <branch>'));
|
|
232
252
|
process.exit(1);
|
|
233
253
|
}
|
|
@@ -238,8 +258,10 @@ program
|
|
|
238
258
|
.command('merge [branch]')
|
|
239
259
|
.description('Merge a branch into the current branch (3-way smart merge)')
|
|
240
260
|
.option('-m, --message <message>', 'Merge commit message')
|
|
261
|
+
.option('--continue', 'Finish a resolved canonical merge')
|
|
262
|
+
.option('--abort', 'Abort a canonical merge')
|
|
241
263
|
.action(async (branch, options) => {
|
|
242
|
-
if (!branch && interactive.isInteractive()) {
|
|
264
|
+
if (!branch && !options.continue && !options.abort && interactive.isInteractive()) {
|
|
243
265
|
const picked = await interactive.promptMerge();
|
|
244
266
|
if (!picked.branch) {
|
|
245
267
|
// In a repo with only one branch → nothing to merge; otherwise
|
|
@@ -252,7 +274,7 @@ program
|
|
|
252
274
|
branch = picked.branch;
|
|
253
275
|
}
|
|
254
276
|
}
|
|
255
|
-
if (!branch && !interactive.isInteractive()) {
|
|
277
|
+
if (!branch && !options.continue && !options.abort && !interactive.isInteractive()) {
|
|
256
278
|
console.error(chalk.red('error: missing branch — usage: gent merge <branch>'));
|
|
257
279
|
process.exit(1);
|
|
258
280
|
}
|
|
@@ -268,6 +290,9 @@ program
|
|
|
268
290
|
.command('stash [subcommand]')
|
|
269
291
|
.description('Stash working tree changes (pop|list|drop|apply)')
|
|
270
292
|
.option('-m, --message <message>', 'Stash message')
|
|
293
|
+
.option('--restore-index', 'Restore canonical stash staged state')
|
|
294
|
+
.option('--keep-index', 'Keep staged changes when stashing')
|
|
295
|
+
.option('-u, --include-untracked', 'Include untracked files')
|
|
271
296
|
.option('-i, --index <index>', 'Stash index for pop/apply/drop')
|
|
272
297
|
.action(stashCommand);
|
|
273
298
|
|
|
@@ -311,6 +336,11 @@ program
|
|
|
311
336
|
.option('-f, --force', 'Force push (overwrite remote)')
|
|
312
337
|
.action(pushCommand);
|
|
313
338
|
|
|
339
|
+
program
|
|
340
|
+
.command('fetch [remote]')
|
|
341
|
+
.description('Fetch canonical remote branches and tags')
|
|
342
|
+
.action(route('fetch', async () => { throw new Error('fetch requires a canonical repository'); }));
|
|
343
|
+
|
|
314
344
|
program
|
|
315
345
|
.command('pull [remote] [branch]')
|
|
316
346
|
.description('Pull and merge remote commits')
|
|
@@ -373,17 +403,17 @@ program
|
|
|
373
403
|
|
|
374
404
|
program
|
|
375
405
|
.command('web')
|
|
376
|
-
.description('Open the current repo
|
|
377
|
-
.option('--branch <name>', '
|
|
378
|
-
.option('--commit <hash>', '
|
|
406
|
+
.description('Open the current repo on the gent web app')
|
|
407
|
+
.option('--branch <name>', 'Branch context (opens the repo page — no branch page yet)')
|
|
408
|
+
.option('--commit <hash>', 'Commit context (opens the repo page — no commit page yet)')
|
|
379
409
|
.option('--print', 'Print the URL instead of launching a browser')
|
|
380
410
|
.action(webCommand);
|
|
381
411
|
|
|
382
412
|
program
|
|
383
413
|
.command('share')
|
|
384
|
-
.description('Print a shareable link to current
|
|
385
|
-
.option('--branch <name>', '
|
|
386
|
-
.option('--commit <hash>', '
|
|
414
|
+
.description('Print a shareable link to the current repository')
|
|
415
|
+
.option('--branch <name>', 'Branch context (link resolves to the repo page)')
|
|
416
|
+
.option('--commit <hash>', 'Commit context (link resolves to the repo page)')
|
|
387
417
|
.action(shareCommand);
|
|
388
418
|
|
|
389
419
|
program
|
package/src/utils/api-client.js
CHANGED
|
@@ -80,8 +80,13 @@ apiClient.interceptors.response.use(
|
|
|
80
80
|
async (error) => {
|
|
81
81
|
const originalRequest = error.config;
|
|
82
82
|
|
|
83
|
-
//
|
|
83
|
+
// A public request made without credentials should keep its original
|
|
84
|
+
// 401 response. Commands such as `gent clone` use that response to
|
|
85
|
+
// explain that a private repository needs sign-in.
|
|
84
86
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
87
|
+
const refreshToken = await authStorage.getRefreshToken();
|
|
88
|
+
if (!refreshToken) return Promise.reject(error);
|
|
89
|
+
|
|
85
90
|
if (isRefreshing) {
|
|
86
91
|
// If already refreshing, queue this request
|
|
87
92
|
return new Promise((resolve, reject) => {
|
|
@@ -100,14 +105,6 @@ apiClient.interceptors.response.use(
|
|
|
100
105
|
isRefreshing = true;
|
|
101
106
|
|
|
102
107
|
try {
|
|
103
|
-
const refreshToken = await authStorage.getRefreshToken();
|
|
104
|
-
|
|
105
|
-
if (!refreshToken) {
|
|
106
|
-
// No refresh token, user needs to login again
|
|
107
|
-
await authStorage.clearAuth();
|
|
108
|
-
throw new Error('Session expired. Please login again.');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
108
|
// Call refresh endpoint (raw axios — bypasses our interceptor
|
|
112
109
|
// intentionally so a 401 here doesn't loop back into refresh).
|
|
113
110
|
const baseUrl = await resolveBaseUrl();
|