@devkitvault/recall 1.0.2 → 1.0.3

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.
@@ -83,10 +83,14 @@ async function loginWithBrowser() {
83
83
  const open = (await Promise.resolve().then(() => __importStar(require('open')))).default;
84
84
  const state = crypto.randomBytes(16).toString('hex');
85
85
  const spinner = (0, ora_1.default)('Opening browser...').start();
86
+ const closeHeaders = { Connection: 'close' };
86
87
  const { token, username } = await new Promise((resolve, reject) => {
88
+ let settled = false;
89
+ const timeoutMs = 5 * 60 * 1000;
87
90
  const server = http.createServer((req, res) => {
88
91
  const url = new URL(req.url, 'http://localhost:9876');
89
92
  if (url.pathname !== '/callback') {
93
+ res.writeHead(404, closeHeaders);
90
94
  res.end();
91
95
  return;
92
96
  }
@@ -94,13 +98,23 @@ async function loginWithBrowser() {
94
98
  const returnedToken = url.searchParams.get('token');
95
99
  const returnedUser = url.searchParams.get('username') ?? '';
96
100
  if (returnedState !== state || !returnedToken) {
97
- res.writeHead(400);
101
+ if (!settled) {
102
+ settled = true;
103
+ clearTimeout(timeoutId);
104
+ }
105
+ res.writeHead(400, closeHeaders);
98
106
  res.end('Invalid callback.');
99
- reject(new Error('Invalid state'));
107
+ const srv = server;
108
+ srv.closeAllConnections?.();
109
+ server.close(() => reject(new Error('Invalid state')));
100
110
  return;
101
111
  }
102
- // Return simple response — browser already shows success UI
103
- res.writeHead(200, { 'Content-Type': 'text/html' });
112
+ if (!settled) {
113
+ settled = true;
114
+ clearTimeout(timeoutId);
115
+ }
116
+ // Loopback callback: tell the browser to close the socket so server.close() can finish promptly.
117
+ res.writeHead(200, { 'Content-Type': 'text/html', ...closeHeaders });
104
118
  res.end(`<!DOCTYPE html>
105
119
  <html>
106
120
  <head><meta charset="utf-8"></head>
@@ -109,18 +123,23 @@ async function loginWithBrowser() {
109
123
  <p style="color:#6b7e94;font-family:monospace;">You can close this tab and return to your terminal.</p>
110
124
  </body>
111
125
  </html>`);
112
- server.close();
113
- resolve({ token: returnedToken, username: returnedUser });
126
+ const srv = server;
127
+ srv.closeAllConnections?.();
128
+ server.close(() => resolve({ token: returnedToken, username: returnedUser }));
114
129
  });
130
+ const timeoutId = setTimeout(() => {
131
+ if (settled)
132
+ return;
133
+ settled = true;
134
+ const to = server;
135
+ to.closeAllConnections?.();
136
+ server.close(() => reject(new Error('Timed out after 5 minutes')));
137
+ }, timeoutMs);
115
138
  server.listen(9876, () => {
116
139
  const authUrl = `https://recall.devkitvault.com/cli-login?state=${state}&redirect=http://localhost:9876/callback`;
117
140
  open(authUrl);
118
141
  spinner.text = 'Waiting for browser authentication...';
119
142
  });
120
- setTimeout(() => {
121
- server.close();
122
- reject(new Error('Timed out after 5 minutes'));
123
- }, 5 * 60 * 1000);
124
143
  });
125
144
  await (0, auth_1.setToken)(token);
126
145
  (0, config_1.saveConfig)({ username });
@@ -138,7 +157,7 @@ exports.loginCommand = new commander_1.Command('login')
138
157
  message: 'How would you like to log in?',
139
158
  choices: [
140
159
  { name: 'Login with credentials (username + password)', value: 'credentials' },
141
- { name: 'Login with browser (opens devkitvault.com)', value: 'browser' },
160
+ { name: 'Login with browser (opens recall.devkitvault.com, then localhost)', value: 'browser' },
142
161
  ],
143
162
  },
144
163
  ]);
@@ -11,7 +11,7 @@ const os_1 = __importDefault(require("os"));
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.recall');
13
13
  const CONFIG_FILE = path_1.default.join(CONFIG_DIR, 'config.json');
14
- exports.APP_VERSION = "1.0.0";
14
+ exports.APP_VERSION = "1.0.1";
15
15
  exports.ENVIRONMENTS = {
16
16
  production: 'https://api.devkitvault.com',
17
17
  local: 'http://127.0.0.1:3001',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devkitvault/recall",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "recall CLI — cloud-synced command vault (JavaScript build for npm; no bundled native binary)",
5
5
  "keywords": [
6
6
  "cli",
@@ -41,7 +41,9 @@
41
41
  "access": "public"
42
42
  },
43
43
  "scripts": {
44
- "prepublishOnly": "node scripts/prepublish.cjs && node --check dist/index.js"
44
+ "prepublishOnly": "node scripts/prepublish.cjs && node --check dist/index.js",
45
+ "check:registry": "npm view @devkitvault/recall version",
46
+ "try:published": "npx --yes --package=@devkitvault/recall@latest recall --version"
45
47
  },
46
48
  "dependencies": {
47
49
  "chalk": "^4.1.2",