orizu 0.1.2 → 0.1.4

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.
Files changed (3) hide show
  1. package/dist/index.js +113 -3
  2. package/package.json +1 -1
  3. package/src/index.ts +115 -3
package/dist/index.js CHANGED
@@ -360,6 +360,113 @@ function resolveAuthCallbackPort() {
360
360
  }
361
361
  return parsed;
362
362
  }
363
+ function renderCliAuthBrowserPage(status) {
364
+ const isSuccess = status === 'success';
365
+ const eyebrow = isSuccess ? '// cli login complete' : '// cli login';
366
+ const title = isSuccess ? 'Browser authorization complete' : 'Missing authorization code';
367
+ const detail = isSuccess
368
+ ? 'Your terminal will finish connecting the Orizu CLI. You can close this tab.'
369
+ : 'Close this tab and run orizu login again to start a fresh browser request.';
370
+ const accent = isSuccess ? '#E8923C' : '#C8442A';
371
+ return `<!doctype html>
372
+ <html lang="en">
373
+ <head>
374
+ <meta charset="utf-8">
375
+ <meta name="viewport" content="width=device-width, initial-scale=1">
376
+ <title>Orizu CLI Login</title>
377
+ <style>
378
+ @import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;700&display=swap');
379
+ :root {
380
+ color-scheme: light;
381
+ --paper: #F4EFE3;
382
+ --border: #E6DFCE;
383
+ --ink: #353535;
384
+ --muted: #6B6358;
385
+ }
386
+ * { box-sizing: border-box; }
387
+ body {
388
+ margin: 0;
389
+ min-height: 100vh;
390
+ background: #FFFFFF;
391
+ color: #4B4B4B;
392
+ font-family: 'Geist Mono', Menlo, Monaco, Consolas, monospace;
393
+ letter-spacing: -0.025em;
394
+ }
395
+ main {
396
+ min-height: 100vh;
397
+ display: flex;
398
+ align-items: center;
399
+ justify-content: center;
400
+ padding: 48px 24px;
401
+ }
402
+ section {
403
+ width: min(100%, 520px);
404
+ text-align: center;
405
+ }
406
+ .brand {
407
+ display: flex;
408
+ flex-direction: column;
409
+ align-items: center;
410
+ gap: 12px;
411
+ margin-bottom: 28px;
412
+ }
413
+ .brand svg {
414
+ width: 42px;
415
+ height: 42px;
416
+ color: #202124;
417
+ }
418
+ .brand span {
419
+ color: #000000;
420
+ font-size: 16px;
421
+ font-weight: 700;
422
+ }
423
+ .eyebrow {
424
+ margin: 0 0 12px;
425
+ color: ${accent};
426
+ font-size: 12px;
427
+ text-transform: lowercase;
428
+ }
429
+ h1 {
430
+ margin: 0 0 8px;
431
+ color: var(--ink);
432
+ font-size: 24px;
433
+ line-height: 1.15;
434
+ letter-spacing: -0.05em;
435
+ }
436
+ .detail {
437
+ margin: 0;
438
+ color: var(--muted);
439
+ font-size: 13px;
440
+ line-height: 1.6;
441
+ }
442
+ </style>
443
+ </head>
444
+ <body>
445
+ <main>
446
+ <section>
447
+ <div class="brand" aria-hidden="true">
448
+ <svg viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg">
449
+ <g fill="currentColor">
450
+ <polygon points="1545,879 787,1195 1189,1577"></polygon>
451
+ <polygon points="992,624 444,1104 688,1338"></polygon>
452
+ <polygon points="602,1593 1180,1594 768,1202"></polygon>
453
+ <polygon points="1650,1195 1398,1203 1204,1594 1229,1593"></polygon>
454
+ <polygon points="807,413 751,509 823,744 980,608"></polygon>
455
+ <polygon points="441,1127 592,1572 681,1356"></polygon>
456
+ <polygon points="793,399 611,457 604,471 658,602"></polygon>
457
+ <polygon points="593,493 498,667 636,600"></polygon>
458
+ </g>
459
+ </svg>
460
+ <span>orizu</span>
461
+ </div>
462
+ <p class="eyebrow">${eyebrow}</p>
463
+ <h1>${title}</h1>
464
+ <p class="detail">${detail}</p>
465
+ </section>
466
+ </main>
467
+ </body>
468
+ </html>`;
469
+ }
363
470
  async function login() {
364
471
  const baseUrl = resolveLoginBaseUrl();
365
472
  const codeVerifier = createCodeVerifier();
@@ -372,12 +479,13 @@ async function login() {
372
479
  const code = url.searchParams.get('code');
373
480
  if (!code) {
374
481
  response.statusCode = 400;
375
- response.end('Missing code');
482
+ response.setHeader('content-type', 'text/html; charset=utf-8');
483
+ response.end(renderCliAuthBrowserPage('error'));
376
484
  return;
377
485
  }
378
486
  response.statusCode = 200;
379
- response.setHeader('content-type', 'text/html');
380
- response.end('<html><body><h3>CLI login complete. You can close this tab.</h3></body></html>');
487
+ response.setHeader('content-type', 'text/html; charset=utf-8');
488
+ response.end(renderCliAuthBrowserPage('success'));
381
489
  server.close();
382
490
  resolve(code);
383
491
  }
@@ -453,8 +561,10 @@ async function logout() {
453
561
  await fetch(`${baseUrl}/api/cli/auth/logout`, {
454
562
  method: 'POST',
455
563
  headers: {
564
+ 'Content-Type': 'application/json',
456
565
  Authorization: `Bearer ${credentials.accessToken}`,
457
566
  },
567
+ body: JSON.stringify({ refreshToken: credentials.refreshToken }),
458
568
  }).catch(() => undefined);
459
569
  clearServerCredentials(baseUrl);
460
570
  console.log(`Logged out from ${baseUrl}.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizu",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -637,6 +637,115 @@ function resolveAuthCallbackPort(): number {
637
637
  return parsed
638
638
  }
639
639
 
640
+ function renderCliAuthBrowserPage(status: 'success' | 'error'): string {
641
+ const isSuccess = status === 'success'
642
+ const eyebrow = isSuccess ? '// cli login complete' : '// cli login'
643
+ const title = isSuccess ? 'Browser authorization complete' : 'Missing authorization code'
644
+ const detail = isSuccess
645
+ ? 'Your terminal will finish connecting the Orizu CLI. You can close this tab.'
646
+ : 'Close this tab and run orizu login again to start a fresh browser request.'
647
+ const accent = isSuccess ? '#E8923C' : '#C8442A'
648
+
649
+ return `<!doctype html>
650
+ <html lang="en">
651
+ <head>
652
+ <meta charset="utf-8">
653
+ <meta name="viewport" content="width=device-width, initial-scale=1">
654
+ <title>Orizu CLI Login</title>
655
+ <style>
656
+ @import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;700&display=swap');
657
+ :root {
658
+ color-scheme: light;
659
+ --paper: #F4EFE3;
660
+ --border: #E6DFCE;
661
+ --ink: #353535;
662
+ --muted: #6B6358;
663
+ }
664
+ * { box-sizing: border-box; }
665
+ body {
666
+ margin: 0;
667
+ min-height: 100vh;
668
+ background: #FFFFFF;
669
+ color: #4B4B4B;
670
+ font-family: 'Geist Mono', Menlo, Monaco, Consolas, monospace;
671
+ letter-spacing: -0.025em;
672
+ }
673
+ main {
674
+ min-height: 100vh;
675
+ display: flex;
676
+ align-items: center;
677
+ justify-content: center;
678
+ padding: 48px 24px;
679
+ }
680
+ section {
681
+ width: min(100%, 520px);
682
+ text-align: center;
683
+ }
684
+ .brand {
685
+ display: flex;
686
+ flex-direction: column;
687
+ align-items: center;
688
+ gap: 12px;
689
+ margin-bottom: 28px;
690
+ }
691
+ .brand svg {
692
+ width: 42px;
693
+ height: 42px;
694
+ color: #202124;
695
+ }
696
+ .brand span {
697
+ color: #000000;
698
+ font-size: 16px;
699
+ font-weight: 700;
700
+ }
701
+ .eyebrow {
702
+ margin: 0 0 12px;
703
+ color: ${accent};
704
+ font-size: 12px;
705
+ text-transform: lowercase;
706
+ }
707
+ h1 {
708
+ margin: 0 0 8px;
709
+ color: var(--ink);
710
+ font-size: 24px;
711
+ line-height: 1.15;
712
+ letter-spacing: -0.05em;
713
+ }
714
+ .detail {
715
+ margin: 0;
716
+ color: var(--muted);
717
+ font-size: 13px;
718
+ line-height: 1.6;
719
+ }
720
+ </style>
721
+ </head>
722
+ <body>
723
+ <main>
724
+ <section>
725
+ <div class="brand" aria-hidden="true">
726
+ <svg viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg">
727
+ <g fill="currentColor">
728
+ <polygon points="1545,879 787,1195 1189,1577"></polygon>
729
+ <polygon points="992,624 444,1104 688,1338"></polygon>
730
+ <polygon points="602,1593 1180,1594 768,1202"></polygon>
731
+ <polygon points="1650,1195 1398,1203 1204,1594 1229,1593"></polygon>
732
+ <polygon points="807,413 751,509 823,744 980,608"></polygon>
733
+ <polygon points="441,1127 592,1572 681,1356"></polygon>
734
+ <polygon points="793,399 611,457 604,471 658,602"></polygon>
735
+ <polygon points="593,493 498,667 636,600"></polygon>
736
+ </g>
737
+ </svg>
738
+ <span>orizu</span>
739
+ </div>
740
+ <p class="eyebrow">${eyebrow}</p>
741
+ <h1>${title}</h1>
742
+ <p class="detail">${detail}</p>
743
+ </section>
744
+ </main>
745
+ </body>
746
+ </html>`
747
+ }
748
+
640
749
  async function login() {
641
750
  const baseUrl = resolveLoginBaseUrl()
642
751
  const codeVerifier = createCodeVerifier()
@@ -651,13 +760,14 @@ async function login() {
651
760
 
652
761
  if (!code) {
653
762
  response.statusCode = 400
654
- response.end('Missing code')
763
+ response.setHeader('content-type', 'text/html; charset=utf-8')
764
+ response.end(renderCliAuthBrowserPage('error'))
655
765
  return
656
766
  }
657
767
 
658
768
  response.statusCode = 200
659
- response.setHeader('content-type', 'text/html')
660
- response.end('<html><body><h3>CLI login complete. You can close this tab.</h3></body></html>')
769
+ response.setHeader('content-type', 'text/html; charset=utf-8')
770
+ response.end(renderCliAuthBrowserPage('success'))
661
771
 
662
772
  server.close()
663
773
  resolve(code)
@@ -748,8 +858,10 @@ async function logout() {
748
858
  await fetch(`${baseUrl}/api/cli/auth/logout`, {
749
859
  method: 'POST',
750
860
  headers: {
861
+ 'Content-Type': 'application/json',
751
862
  Authorization: `Bearer ${credentials.accessToken}`,
752
863
  },
864
+ body: JSON.stringify({ refreshToken: credentials.refreshToken }),
753
865
  }).catch(() => undefined)
754
866
 
755
867
  clearServerCredentials(baseUrl)