@api-now/cli 1.3.0 → 1.4.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.
@@ -0,0 +1,414 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>API NOW! CLI Login</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;700;800&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ /* Typography */
13
+ --font-display: 'Space Grotesk', system-ui, -apple-system, sans-serif;
14
+ --font-mono: 'JetBrains Mono', 'SFMono-Regular', Consolas, monospace;
15
+
16
+ /* Color Story (Dominant Dark + Cyber Accent) */
17
+ --color-bg: #080b11;
18
+ --color-card-bg: rgba(15, 20, 32, 0.6);
19
+ --color-border: rgba(255, 255, 255, 0.08);
20
+ --color-text-main: #f1f5f9;
21
+ --color-text-muted: #94a3b8;
22
+
23
+ /* Accents and States */
24
+ --color-accent: #00f2fe;
25
+ --color-accent-gradient: linear-gradient(135deg, #00f2fe 0%, #4facfe 100%);
26
+
27
+ --color-success: #04d361;
28
+ --color-success-bg: rgba(4, 211, 97, 0.1);
29
+ --color-success-border: rgba(4, 211, 97, 0.3);
30
+
31
+ --color-error: #f75a68;
32
+ --color-error-bg: rgba(247, 90, 104, 0.1);
33
+ --color-error-border: rgba(247, 90, 104, 0.3);
34
+
35
+ /* Motion */
36
+ --transition-speed: 0.2s;
37
+ --transition-bezier: cubic-bezier(0.16, 1, 0.3, 1);
38
+ }
39
+
40
+ body, div, h1, p, button, svg, circle, path, pre {
41
+ box-sizing: border-box;
42
+ }
43
+ body {
44
+ font-family: var(--font-mono);
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ min-height: 100vh;
49
+ margin: 0;
50
+ background: var(--color-bg);
51
+ background-image:
52
+ radial-gradient(circle at 50% 0%, rgba(79, 172, 254, 0.12) 0%, transparent 60%),
53
+ radial-gradient(circle at 100% 100%, rgba(0, 242, 254, 0.04) 0%, transparent 40%);
54
+ color: var(--color-text-main);
55
+ overflow-x: hidden;
56
+ }
57
+ .card {
58
+ position: relative;
59
+ overflow: hidden;
60
+ background: var(--color-card-bg);
61
+ backdrop-filter: blur(20px) saturate(180%);
62
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
63
+ border: 1px solid var(--color-border);
64
+ border-radius: 24px;
65
+ padding: 3.5rem 2.5rem;
66
+ width: 100%;
67
+ max-width: 460px;
68
+ text-align: center;
69
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
70
+ animation: slideIn 0.6s var(--transition-bezier) forwards;
71
+ opacity: 0;
72
+ transform: translateY(20px);
73
+ }
74
+
75
+ /* Technical Scanline HUD Overlay (Differentiation Anchor) */
76
+ .card::before {
77
+ content: "";
78
+ position: absolute;
79
+ inset: 0;
80
+ background: linear-gradient(
81
+ rgba(18, 16, 16, 0) 50%,
82
+ rgba(0, 0, 0, 0.2) 50%
83
+ );
84
+ background-size: 100% 4px;
85
+ z-index: 10;
86
+ pointer-events: none;
87
+ opacity: 0.15;
88
+ border-radius: 24px;
89
+ }
90
+
91
+ h1 {
92
+ font-family: var(--font-display);
93
+ font-size: 2.2rem;
94
+ font-weight: 800;
95
+ margin: 0 0 1.5rem 0;
96
+ background: var(--color-accent-gradient);
97
+ background-clip: text;
98
+ -webkit-background-clip: text;
99
+ -webkit-text-fill-color: transparent;
100
+ letter-spacing: -0.03em;
101
+ }
102
+
103
+ /* Status Icon Container */
104
+ .icon-wrapper {
105
+ position: relative;
106
+ width: 80px;
107
+ height: 80px;
108
+ margin: 0 auto 2rem auto;
109
+ display: flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ }
113
+
114
+ .status-icon {
115
+ position: absolute;
116
+ width: 100%;
117
+ height: 100%;
118
+ border-radius: 50%;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
123
+ }
124
+
125
+ /* Spinner Loader */
126
+ .spinner {
127
+ border: 4px solid rgba(79, 172, 254, 0.1);
128
+ border-top: 4px solid var(--color-accent);
129
+ animation: spin 1s linear infinite;
130
+ }
131
+
132
+ /* Success Icon */
133
+ .icon-success {
134
+ background: var(--color-success-bg);
135
+ border: 2px solid var(--color-success-border);
136
+ color: var(--color-success);
137
+ transform: scale(0);
138
+ opacity: 0;
139
+ }
140
+ .icon-success svg {
141
+ width: 38px;
142
+ height: 38px;
143
+ }
144
+
145
+ /* Error Icon */
146
+ .icon-error {
147
+ background: var(--color-error-bg);
148
+ border: 2px solid var(--color-error-border);
149
+ color: var(--color-error);
150
+ transform: scale(0);
151
+ opacity: 0;
152
+ }
153
+ .icon-error svg {
154
+ width: 38px;
155
+ height: 38px;
156
+ }
157
+
158
+ /* Active Icon States */
159
+ .state-loading .spinner {
160
+ transform: scale(1);
161
+ opacity: 1;
162
+ }
163
+
164
+ .state-success .spinner {
165
+ transform: scale(0.8);
166
+ opacity: 0;
167
+ }
168
+ .state-success .icon-success {
169
+ transform: scale(1);
170
+ opacity: 1;
171
+ box-shadow: 0 0 20px rgba(4, 211, 97, 0.2);
172
+ }
173
+
174
+ .state-error .spinner {
175
+ transform: scale(0.8);
176
+ opacity: 0;
177
+ }
178
+ .state-error .icon-error {
179
+ transform: scale(1);
180
+ opacity: 1;
181
+ box-shadow: 0 0 20px rgba(247, 90, 104, 0.2);
182
+ }
183
+
184
+ /* Status Label */
185
+ .status {
186
+ font-family: var(--font-display);
187
+ font-size: 1.15rem;
188
+ font-weight: 500;
189
+ color: var(--color-text-muted);
190
+ margin: 0 0 2rem 0;
191
+ line-height: 1.5;
192
+ min-height: 54px;
193
+ transition: color 0.3s ease;
194
+ }
195
+
196
+ .state-success .status {
197
+ color: var(--color-text-main);
198
+ }
199
+ .state-error .status {
200
+ color: #fca5a5;
201
+ }
202
+
203
+ /* Diagnostics accordion */
204
+ .diagnostics-btn {
205
+ font-family: var(--font-mono);
206
+ background: rgba(255, 255, 255, 0.03);
207
+ border: 1px solid rgba(255, 255, 255, 0.08);
208
+ color: var(--color-text-muted);
209
+ padding: 0.75rem 1.25rem;
210
+ border-radius: 12px;
211
+ font-size: 0.85rem;
212
+ font-weight: 500;
213
+ cursor: pointer;
214
+ display: inline-flex;
215
+ align-items: center;
216
+ gap: 0.5rem;
217
+ transition: all var(--transition-speed) ease;
218
+ outline: none;
219
+ }
220
+ .diagnostics-btn:focus-visible {
221
+ outline: 2px solid var(--color-accent);
222
+ outline-offset: 2px;
223
+ }
224
+ .diagnostics-btn:hover {
225
+ background: rgba(255, 255, 255, 0.06);
226
+ border-color: rgba(255, 255, 255, 0.15);
227
+ color: var(--color-text-main);
228
+ }
229
+ .diagnostics-btn svg {
230
+ width: 16px;
231
+ height: 16px;
232
+ transition: transform 0.3s ease;
233
+ }
234
+ .diagnostics-btn.active svg {
235
+ transform: rotate(180deg);
236
+ }
237
+
238
+ .diagnostics-container {
239
+ max-height: 0;
240
+ overflow: hidden;
241
+ transition: max-height 0.4s var(--transition-bezier);
242
+ margin-top: 1.5rem;
243
+ }
244
+
245
+ .diagnostics {
246
+ text-align: left;
247
+ padding: 1.25rem;
248
+ background: #0b0f19;
249
+ border: 1px solid rgba(255, 255, 255, 0.05);
250
+ border-radius: 12px;
251
+ font-size: 0.8rem;
252
+ font-family: var(--font-mono);
253
+ white-space: pre-wrap;
254
+ word-break: break-all;
255
+ border-left: 4px solid var(--color-error);
256
+ color: #cbd5e1;
257
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
258
+ }
259
+
260
+ .diagnostics-title {
261
+ font-weight: 600;
262
+ color: var(--color-text-main);
263
+ margin-bottom: 0.5rem;
264
+ font-size: 0.85rem;
265
+ }
266
+
267
+ /* Animations */
268
+ @keyframes spin {
269
+ to { transform: rotate(360deg); }
270
+ }
271
+ @keyframes slideIn {
272
+ to {
273
+ opacity: 1;
274
+ transform: translateY(0);
275
+ }
276
+ }
277
+
278
+ /* Checkmark Draw Animation */
279
+ .checkmark__check {
280
+ transform-origin: 50% 50%;
281
+ stroke-dasharray: 48;
282
+ stroke-dashoffset: 48;
283
+ animation: stroke 0.4s cubic-bezier(0.65, 0, 0.45, 1) 0.3s forwards;
284
+ }
285
+
286
+ @keyframes stroke {
287
+ to {
288
+ stroke-dashoffset: 0;
289
+ }
290
+ }
291
+ @media (prefers-reduced-motion: reduce) {
292
+ .card {
293
+ animation: none;
294
+ opacity: 1;
295
+ transform: translateY(0);
296
+ }
297
+ .spinner {
298
+ animation: spin 8s linear infinite;
299
+ }
300
+ .checkmark__check {
301
+ animation: none;
302
+ stroke-dashoffset: 0;
303
+ }
304
+ }
305
+ </style>
306
+ </head>
307
+ <body class="state-loading">
308
+ <div class="card">
309
+ <h1>API NOW!</h1>
310
+
311
+ <div class="icon-wrapper" id="icon-container">
312
+ <div class="status-icon spinner"></div>
313
+
314
+ <div class="status-icon icon-success">
315
+ <svg viewBox="0 0 52 52" fill="none" stroke="currentColor" stroke-width="4">
316
+ <circle cx="26" cy="26" r="25" fill="none" style="opacity: 0.1;"/>
317
+ <path class="checkmark__check" d="M14.1 27.2l7.1 7.2 16.7-16.8" stroke-linecap="round" stroke-linejoin="round"/>
318
+ </svg>
319
+ </div>
320
+
321
+ <div class="status-icon icon-error">
322
+ <svg viewBox="0 0 52 52" fill="none" stroke="currentColor" stroke-width="4">
323
+ <circle cx="26" cy="26" r="25" fill="none" style="opacity: 0.1;"/>
324
+ <path d="M16 16l20 20M36 16L16 36" stroke-linecap="round" stroke-linejoin="round"/>
325
+ </svg>
326
+ </div>
327
+ </div>
328
+
329
+ <p class="status" id="status">Retrieving authentication token from server...</p>
330
+
331
+ <div id="diagnostics-section" style="display: none;">
332
+ <button class="diagnostics-btn" id="diagnostics-toggle">
333
+ View Diagnostic Details
334
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
335
+ <polyline points="6 9 12 15 18 9"/>
336
+ </svg>
337
+ </button>
338
+
339
+ <div class="diagnostics-container" id="diagnostics-wrapper">
340
+ <div class="diagnostics-title">Error Diagnostics:</div>
341
+ <div class="diagnostics" id="diagnostics-content"></div>
342
+ </div>
343
+ </div>
344
+ </div>
345
+
346
+ <script>
347
+ const statusText = document.getElementById('status');
348
+ const bodyClass = document.body.classList;
349
+ const diagSection = document.getElementById('diagnostics-section');
350
+ const diagContent = document.getElementById('diagnostics-content');
351
+ const diagToggle = document.getElementById('diagnostics-toggle');
352
+ const diagWrapper = document.getElementById('diagnostics-wrapper');
353
+
354
+ diagToggle.addEventListener('click', () => {
355
+ diagToggle.classList.toggle('active');
356
+ if (diagWrapper.style.maxHeight && diagWrapper.style.maxHeight !== '0px') {
357
+ diagWrapper.style.maxHeight = '0px';
358
+ } else {
359
+ diagWrapper.style.maxHeight = diagWrapper.scrollHeight + 'px';
360
+ }
361
+ });
362
+
363
+ fetch('{{API_URL}}/auth/token', { credentials: 'include' })
364
+ .then(r => {
365
+ if (!r.ok) {
366
+ throw new Error('Token request failed: ' + r.statusText + ' (status: ' + r.status + ')');
367
+ }
368
+ return r.json();
369
+ })
370
+ .then(data => {
371
+ const token = data.token || data.data?.token || data.data;
372
+ if (!token) {
373
+ throw new Error('Token not found in API response structure');
374
+ }
375
+
376
+ return fetch('/token', {
377
+ method: 'POST',
378
+ headers: { 'Content-Type': 'application/json' },
379
+ body: JSON.stringify({ token })
380
+ });
381
+ })
382
+ .then(r => {
383
+ if (!r.ok) {
384
+ throw new Error('Failed to save token in CLI server (status: ' + r.status + ')');
385
+ }
386
+ bodyClass.remove('state-loading');
387
+ bodyClass.add('state-success');
388
+ statusText.innerHTML = 'Authentication successful!<br><span style="font-size: 0.9rem; color: var(--color-text-muted); font-weight: 400;">You can close this tab now.</span>';
389
+ })
390
+ .catch(err => {
391
+ console.error("[ERROR]", err);
392
+ bodyClass.remove('state-loading');
393
+ bodyClass.add('state-error');
394
+ statusText.innerText = 'Authentication failed.';
395
+
396
+ diagSection.style.display = 'block';
397
+ diagContent.innerText =
398
+ 'Error Message: ' + err.message + '\n\n' +
399
+ 'Originating URL: ' + window.location.href + '\n' +
400
+ 'Target API URL: {{API_URL}}/auth/token\n\n' +
401
+ 'TIP: If you get "Unauthorized (status: 401)", make sure that:\n' +
402
+ '1. You completed the login flow on the browser window that opened.\n' +
403
+ '2. The host of the page you are on (' + window.location.hostname + ') matches the host of the API (' + new URL('{{API_URL}}').hostname + ') to satisfy SameSite cookie policy.\n' +
404
+ '3. Check browser developer console (F12) for detailed CORS/Network errors.';
405
+
406
+ fetch('/error', {
407
+ method: 'POST',
408
+ headers: { 'Content-Type': 'application/json' },
409
+ body: JSON.stringify({ message: err.message })
410
+ }).catch(console.error);
411
+ });
412
+ </script>
413
+ </body>
414
+ </html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@api-now/cli",
3
3
  "description": "API Now! CLI",
4
- "version": "1.3.0",
4
+ "version": "1.4.0",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "registry": "https://registry.npmjs.org/",