open-notepad 1.0.5 → 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 +95 -82
- package/package.json +1 -1
package/bin/note.js
CHANGED
|
@@ -140,103 +140,116 @@ async function apiFetch(config, endpoint, options = {}) {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
// Commands
|
|
143
|
-
async function handleLogin() {
|
|
144
|
-
clearScreen();
|
|
145
|
-
log(`${colors.bgBlue}${colors.white}${colors.bold} Configure Notepad CLI ${colors.reset}\n`);
|
|
146
|
-
|
|
143
|
+
async function handleLogin(apiUrlArg) {
|
|
147
144
|
const current = await loadConfig();
|
|
145
|
+
const apiUrl = apiUrlArg || current.apiUrl || 'https://notepad.web.id';
|
|
148
146
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
// Present choices
|
|
148
|
+
const loginOptions = [
|
|
149
|
+
'🌐 Sign in with Google (Browser Redirect)',
|
|
150
|
+
'🔑 Enter API Key (Manual)'
|
|
151
|
+
];
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
method: 'POST',
|
|
159
|
-
headers: { 'Content-Type': 'application/json' },
|
|
160
|
-
body: JSON.stringify({ code: sessionCode })
|
|
161
|
-
});
|
|
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
|
+
};
|
|
162
157
|
|
|
163
|
-
|
|
164
|
-
throw new Error(`Server returned ${regRes.status}`);
|
|
165
|
-
}
|
|
158
|
+
const choice = await selectMenuOption(loginOptions, titleCallback);
|
|
166
159
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
log(
|
|
171
|
-
log(`${colors.bold}${colors.cyan}${authPageUrl}${colors.reset}\n`);
|
|
172
|
-
|
|
173
|
-
// Platform-specific browser open
|
|
174
|
-
const openCmd = process.platform === 'win32' ? 'start'
|
|
175
|
-
: process.platform === 'darwin' ? 'open'
|
|
176
|
-
: 'xdg-open';
|
|
177
|
-
const child = spawn(openCmd, [authPageUrl], { shell: true, stdio: 'ignore', detached: true });
|
|
178
|
-
child.unref();
|
|
179
|
-
|
|
180
|
-
// Poll for completion
|
|
181
|
-
info('Waiting for browser authorization...');
|
|
182
|
-
const maxAttempts = 120; // 2 minutes (polling every 1s)
|
|
183
|
-
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`);
|
|
184
164
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
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);
|
|
188
167
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
+
}
|
|
200
179
|
|
|
201
|
-
|
|
202
|
-
|
|
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}`);
|
|
203
204
|
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
+
}
|
|
215
228
|
}
|
|
229
|
+
} catch (pollErr) {
|
|
230
|
+
// Silently continue polling
|
|
216
231
|
}
|
|
217
|
-
} catch (pollErr) {
|
|
218
|
-
// Silently continue polling
|
|
219
|
-
}
|
|
220
232
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
233
|
+
if (attempts % 4 === 0) {
|
|
234
|
+
process.stdout.write(`\r${colors.dim} Polling... (${attempts}s elapsed, waiting for browser auth)${colors.reset} `);
|
|
235
|
+
}
|
|
224
236
|
}
|
|
237
|
+
|
|
238
|
+
process.stdout.write('\n');
|
|
239
|
+
warning('Browser authorization timed out.');
|
|
240
|
+
} catch (e) {
|
|
241
|
+
error(`Browser login unavailable: ${e.message}`);
|
|
225
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);
|
|
226
250
|
|
|
227
|
-
|
|
228
|
-
warning('Browser authorization timed out.');
|
|
229
|
-
info('Falling back to manual configuration...\n');
|
|
230
|
-
} catch (e) {
|
|
231
|
-
warning(`Browser login unavailable: ${e.message}`);
|
|
232
|
-
info('Using manual configuration instead...\n');
|
|
251
|
+
await saveConfig({ apiUrl, roomId, apiKey });
|
|
233
252
|
}
|
|
234
|
-
|
|
235
|
-
// Fallback: manual configuration
|
|
236
|
-
const roomId = await ask('Enter Subdomain/Room ID (e.g. "saya")', current.roomId);
|
|
237
|
-
const apiKey = await ask('Enter Room API Token/Key', current.apiKey);
|
|
238
|
-
|
|
239
|
-
await saveConfig({ apiUrl, roomId, apiKey });
|
|
240
253
|
}
|
|
241
254
|
|
|
242
255
|
async function handleList() {
|
|
@@ -739,7 +752,7 @@ async function main() {
|
|
|
739
752
|
} else {
|
|
740
753
|
switch (command) {
|
|
741
754
|
case 'login':
|
|
742
|
-
await handleLogin();
|
|
755
|
+
await handleLogin(subArg);
|
|
743
756
|
break;
|
|
744
757
|
case 'list':
|
|
745
758
|
await handleList();
|