open-notepad 1.0.6 → 1.0.7
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/bin/note.js +92 -78
- package/package.json +1 -1
package/bin/note.js
CHANGED
|
@@ -141,101 +141,115 @@ async function apiFetch(config, endpoint, options = {}) {
|
|
|
141
141
|
|
|
142
142
|
// Commands
|
|
143
143
|
async function handleLogin(apiUrlArg) {
|
|
144
|
-
clearScreen();
|
|
145
|
-
log(`${colors.bgBlue}${colors.white}${colors.bold} Configure Notepad CLI ${colors.reset}\n`);
|
|
146
|
-
|
|
147
144
|
const current = await loadConfig();
|
|
148
145
|
const apiUrl = apiUrlArg || current.apiUrl || 'https://notepad.web.id';
|
|
149
146
|
|
|
150
|
-
//
|
|
151
|
-
const
|
|
147
|
+
// Present choices
|
|
148
|
+
const loginOptions = [
|
|
149
|
+
'🌐 Sign in with Google (Browser Redirect)',
|
|
150
|
+
'🔑 Enter API Key (Manual)'
|
|
151
|
+
];
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
method: 'POST',
|
|
158
|
-
headers: { 'Content-Type': 'application/json' },
|
|
159
|
-
body: JSON.stringify({ code: sessionCode })
|
|
160
|
-
});
|
|
153
|
+
const titleCallback = () => {
|
|
154
|
+
log(`${colors.bgBlue}${colors.white}${colors.bold} Configure Notepad CLI ${colors.reset}`);
|
|
155
|
+
log(`${colors.dim}Select how you want to authenticate with ${colors.reset}${colors.cyan}${apiUrl}${colors.reset}\n`);
|
|
156
|
+
};
|
|
161
157
|
|
|
162
|
-
|
|
163
|
-
throw new Error(`Server returned ${regRes.status}`);
|
|
164
|
-
}
|
|
158
|
+
const choice = await selectMenuOption(loginOptions, titleCallback);
|
|
165
159
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
log(
|
|
170
|
-
log(`${colors.bold}${colors.cyan}${authPageUrl}${colors.reset}\n`);
|
|
171
|
-
|
|
172
|
-
// Platform-specific browser open
|
|
173
|
-
const openCmd = process.platform === 'win32' ? 'start'
|
|
174
|
-
: process.platform === 'darwin' ? 'open'
|
|
175
|
-
: 'xdg-open';
|
|
176
|
-
const child = spawn(openCmd, [authPageUrl], { shell: true, stdio: 'ignore', detached: true });
|
|
177
|
-
child.unref();
|
|
178
|
-
|
|
179
|
-
// Poll for completion
|
|
180
|
-
info('Waiting for browser authorization...');
|
|
181
|
-
const maxAttempts = 120; // 2 minutes (polling every 1.5s)
|
|
182
|
-
let attempts = 0;
|
|
160
|
+
if (choice === 0) {
|
|
161
|
+
// Google Login (Browser flow)
|
|
162
|
+
clearScreen();
|
|
163
|
+
log(`${colors.bgBlue}${colors.white}${colors.bold} Google Authentication ${colors.reset}\n`);
|
|
183
164
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
attempts++;
|
|
165
|
+
// Generate a random session code
|
|
166
|
+
const sessionCode = 'cli_' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
187
167
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
168
|
+
info('Registering CLI session...');
|
|
169
|
+
try {
|
|
170
|
+
const regRes = await fetch(`${apiUrl.replace(/\/$/, '')}/api/cli/session`, {
|
|
171
|
+
method: 'POST',
|
|
172
|
+
headers: { 'Content-Type': 'application/json' },
|
|
173
|
+
body: JSON.stringify({ code: sessionCode })
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (!regRes.ok) {
|
|
177
|
+
throw new Error(`Server returned ${regRes.status}`);
|
|
178
|
+
}
|
|
199
179
|
|
|
200
|
-
|
|
201
|
-
|
|
180
|
+
// Open browser
|
|
181
|
+
const authPageUrl = `${apiUrl.replace(/\/$/, '')}/auth-cli-20260628dontuseforyounote?session=${sessionCode}`;
|
|
182
|
+
info(`Opening browser for authentication...`);
|
|
183
|
+
log(`\n${colors.dim}If browser does not open automatically, visit:${colors.reset}`);
|
|
184
|
+
log(`${colors.bold}${colors.cyan}${authPageUrl}${colors.reset}\n`);
|
|
185
|
+
|
|
186
|
+
// Platform-specific browser open
|
|
187
|
+
const openCmd = process.platform === 'win32' ? 'start'
|
|
188
|
+
: process.platform === 'darwin' ? 'open'
|
|
189
|
+
: 'xdg-open';
|
|
190
|
+
const child = spawn(openCmd, [authPageUrl], { shell: true, stdio: 'ignore', detached: true });
|
|
191
|
+
child.unref();
|
|
192
|
+
|
|
193
|
+
// Poll for completion
|
|
194
|
+
info('Waiting for browser authorization...');
|
|
195
|
+
const maxAttempts = 120; // 2 minutes (polling every 1.5s)
|
|
196
|
+
let attempts = 0;
|
|
197
|
+
|
|
198
|
+
while (attempts < maxAttempts) {
|
|
199
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
200
|
+
attempts++;
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const pollRes = await fetch(`${apiUrl.replace(/\/$/, '')}/api/cli/session/${sessionCode}`);
|
|
202
204
|
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
205
|
+
if (pollRes.status === 404) {
|
|
206
|
+
if (attempts > 10) {
|
|
207
|
+
error('Session expired. Please try again.');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (pollRes.ok) {
|
|
214
|
+
const data = await pollRes.json();
|
|
215
|
+
|
|
216
|
+
if (data.status === 'completed' && data.room_id && data.api_key) {
|
|
217
|
+
clearScreen();
|
|
218
|
+
log(`${colors.bgBlue}${colors.white}${colors.bold} CLI Connected Successfully! ${colors.reset}\n`);
|
|
219
|
+
await saveConfig({
|
|
220
|
+
apiUrl,
|
|
221
|
+
roomId: data.room_id,
|
|
222
|
+
apiKey: data.api_key
|
|
223
|
+
});
|
|
224
|
+
success(`Linked to room: ${colors.bold}${data.room_id}.notepad.web.id${colors.reset}`);
|
|
225
|
+
info('You can now use all CLI commands. Try: note list');
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
214
228
|
}
|
|
229
|
+
} catch (pollErr) {
|
|
230
|
+
// Silently continue polling
|
|
215
231
|
}
|
|
216
|
-
} catch (pollErr) {
|
|
217
|
-
// Silently continue polling
|
|
218
|
-
}
|
|
219
232
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
233
|
+
if (attempts % 4 === 0) {
|
|
234
|
+
process.stdout.write(`\r${colors.dim} Polling... (${attempts}s elapsed, waiting for browser auth)${colors.reset} `);
|
|
235
|
+
}
|
|
223
236
|
}
|
|
237
|
+
|
|
238
|
+
process.stdout.write('\n');
|
|
239
|
+
warning('Browser authorization timed out.');
|
|
240
|
+
} catch (e) {
|
|
241
|
+
error(`Browser login unavailable: ${e.message}`);
|
|
224
242
|
}
|
|
243
|
+
} else {
|
|
244
|
+
// Manual API Key configuration
|
|
245
|
+
clearScreen();
|
|
246
|
+
log(`${colors.bgBlue}${colors.white}${colors.bold} Manual API Key Config ${colors.reset}\n`);
|
|
247
|
+
|
|
248
|
+
const roomId = await ask('Enter Subdomain/Room ID (e.g. "saya")', current.roomId);
|
|
249
|
+
const apiKey = await ask('Enter Room API Token/Key', current.apiKey);
|
|
225
250
|
|
|
226
|
-
|
|
227
|
-
warning('Browser authorization timed out.');
|
|
228
|
-
info('Falling back to manual configuration...\n');
|
|
229
|
-
} catch (e) {
|
|
230
|
-
warning(`Browser login unavailable: ${e.message}`);
|
|
231
|
-
info('Using manual configuration instead...\n');
|
|
251
|
+
await saveConfig({ apiUrl, roomId, apiKey });
|
|
232
252
|
}
|
|
233
|
-
|
|
234
|
-
// Fallback: manual configuration
|
|
235
|
-
const roomId = await ask('Enter Subdomain/Room ID (e.g. "saya")', current.roomId);
|
|
236
|
-
const apiKey = await ask('Enter Room API Token/Key', current.apiKey);
|
|
237
|
-
|
|
238
|
-
await saveConfig({ apiUrl, roomId, apiKey });
|
|
239
253
|
}
|
|
240
254
|
|
|
241
255
|
async function handleList() {
|