@pocketcoder/host 0.0.7 → 0.0.8
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/dist/auth/oauth-server.d.ts.map +1 -1
- package/dist/auth/oauth-server.js +10 -534
- package/dist/auth/oauth-server.js.map +1 -1
- package/dist/auth/templates/error.html +575 -0
- package/dist/auth/templates/index.d.ts +12 -0
- package/dist/auth/templates/index.d.ts.map +1 -0
- package/dist/auth/templates/index.js +16 -0
- package/dist/auth/templates/index.js.map +1 -0
- package/dist/auth/templates/loading.html +636 -0
- package/dist/auth/templates/success.html +537 -0
- package/dist/cli/commands/__tests__/cli-daemon.test.js +83 -10
- package/dist/cli/commands/__tests__/cli-daemon.test.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +28 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-server.d.ts","sourceRoot":"","sources":["../../src/auth/oauth-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"oauth-server.d.ts","sourceRoot":"","sources":["../../src/auth/oauth-server.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,eAAe,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACpD,yDAAyD;IACzD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,WAAW,CAAC,CAyH7D"}
|
|
@@ -1,534 +1,7 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
|
+
import { SUCCESS_HTML, ERROR_HTML, FRAGMENT_EXTRACTOR_HTML } from "./templates/index.js";
|
|
2
3
|
/** Timeout for waiting for the OAuth callback (5 minutes). */
|
|
3
4
|
const OAUTH_TIMEOUT_MS = 5 * 60 * 1000;
|
|
4
|
-
const SUCCESS_HTML = `<!DOCTYPE html>
|
|
5
|
-
<html lang="en">
|
|
6
|
-
<head>
|
|
7
|
-
<meta charset="UTF-8">
|
|
8
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
9
|
-
<title>PocketCoder - Success</title>
|
|
10
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
11
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
12
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Inter:wght@600;700&display=swap" rel="stylesheet">
|
|
13
|
-
<style>
|
|
14
|
-
:root {
|
|
15
|
-
--bg-primary: #000000;
|
|
16
|
-
--text-primary: #ffffff;
|
|
17
|
-
--text-secondary: #a1a1a6;
|
|
18
|
-
--accent: #c9a87c;
|
|
19
|
-
--success: #34c759;
|
|
20
|
-
}
|
|
21
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
22
|
-
html, body {
|
|
23
|
-
height: 100%;
|
|
24
|
-
font-family: "DM Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
25
|
-
background: var(--bg-primary);
|
|
26
|
-
color: var(--text-primary);
|
|
27
|
-
-webkit-font-smoothing: antialiased;
|
|
28
|
-
}
|
|
29
|
-
.container {
|
|
30
|
-
display: flex;
|
|
31
|
-
flex-direction: column;
|
|
32
|
-
align-items: center;
|
|
33
|
-
justify-content: center;
|
|
34
|
-
min-height: 100vh;
|
|
35
|
-
padding: 24px;
|
|
36
|
-
position: relative;
|
|
37
|
-
overflow: hidden;
|
|
38
|
-
}
|
|
39
|
-
.stars, .stars-near {
|
|
40
|
-
position: absolute;
|
|
41
|
-
top: 0; left: 0;
|
|
42
|
-
width: 100%; height: 100%;
|
|
43
|
-
pointer-events: none;
|
|
44
|
-
}
|
|
45
|
-
.stars::before {
|
|
46
|
-
content: "";
|
|
47
|
-
position: absolute;
|
|
48
|
-
top: 30%; left: 50%;
|
|
49
|
-
width: 2px; height: 2px;
|
|
50
|
-
background: transparent;
|
|
51
|
-
border-radius: 50%;
|
|
52
|
-
box-shadow:
|
|
53
|
-
-180px -120px 0 0 rgba(186, 85, 211, 0.6),
|
|
54
|
-
160px -100px 0 0 rgba(135, 206, 250, 0.65),
|
|
55
|
-
-220px 80px 0 0 rgba(255, 182, 193, 0.6),
|
|
56
|
-
200px 120px 0 0 rgba(255, 160, 122, 0.55),
|
|
57
|
-
-120px 180px 0 0 rgba(147, 112, 219, 0.65),
|
|
58
|
-
140px 200px 0 0 rgba(135, 206, 250, 0.6),
|
|
59
|
-
-280px -60px 0 0 rgba(255, 182, 193, 0.55),
|
|
60
|
-
260px -80px 0 0 rgba(186, 85, 211, 0.65),
|
|
61
|
-
-160px -200px 0 0 rgba(255, 160, 122, 0.6),
|
|
62
|
-
180px -180px 0 0 rgba(147, 112, 219, 0.55);
|
|
63
|
-
animation: twinkle 3.5s ease-in-out infinite;
|
|
64
|
-
}
|
|
65
|
-
.stars-near::before {
|
|
66
|
-
content: "";
|
|
67
|
-
position: absolute;
|
|
68
|
-
top: 30%; left: 50%;
|
|
69
|
-
width: 2px; height: 2px;
|
|
70
|
-
background: transparent;
|
|
71
|
-
border-radius: 50%;
|
|
72
|
-
box-shadow:
|
|
73
|
-
-80px -60px 0 0 rgba(186, 85, 211, 0.9),
|
|
74
|
-
70px -50px 0 1px rgba(255, 160, 122, 1),
|
|
75
|
-
-90px 40px 0 0 rgba(135, 206, 250, 0.85),
|
|
76
|
-
85px 55px 0 1px rgba(255, 182, 193, 0.9),
|
|
77
|
-
-50px 80px 0 0 rgba(147, 112, 219, 0.95),
|
|
78
|
-
60px 90px 0 1px rgba(186, 85, 211, 0.85),
|
|
79
|
-
-110px -30px 0 0 rgba(255, 160, 122, 0.9),
|
|
80
|
-
105px -35px 0 1px rgba(135, 206, 250, 0.95);
|
|
81
|
-
animation: twinkle 2s ease-in-out infinite;
|
|
82
|
-
}
|
|
83
|
-
@keyframes twinkle {
|
|
84
|
-
0%, 100% { opacity: 1; }
|
|
85
|
-
50% { opacity: 0.6; }
|
|
86
|
-
}
|
|
87
|
-
.content {
|
|
88
|
-
text-align: center;
|
|
89
|
-
position: relative;
|
|
90
|
-
z-index: 10;
|
|
91
|
-
}
|
|
92
|
-
.icon-wrapper {
|
|
93
|
-
width: 80px; height: 80px;
|
|
94
|
-
margin: 0 auto 24px;
|
|
95
|
-
position: relative;
|
|
96
|
-
display: flex;
|
|
97
|
-
align-items: center;
|
|
98
|
-
justify-content: center;
|
|
99
|
-
}
|
|
100
|
-
.icon-glow {
|
|
101
|
-
position: absolute;
|
|
102
|
-
width: 100%; height: 100%;
|
|
103
|
-
border-radius: 50%;
|
|
104
|
-
background: radial-gradient(circle, rgba(52, 199, 89, 0.4) 0%, transparent 70%);
|
|
105
|
-
animation: iconGlow 2s ease-in-out infinite;
|
|
106
|
-
}
|
|
107
|
-
@keyframes iconGlow {
|
|
108
|
-
0%, 100% { transform: scale(1); opacity: 0.8; }
|
|
109
|
-
50% { transform: scale(1.2); opacity: 1; }
|
|
110
|
-
}
|
|
111
|
-
.icon {
|
|
112
|
-
width: 48px; height: 48px;
|
|
113
|
-
color: var(--success);
|
|
114
|
-
position: relative;
|
|
115
|
-
z-index: 1;
|
|
116
|
-
}
|
|
117
|
-
.app-name {
|
|
118
|
-
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
119
|
-
font-size: 24px;
|
|
120
|
-
font-weight: 700;
|
|
121
|
-
letter-spacing: -0.5px;
|
|
122
|
-
margin-bottom: 8px;
|
|
123
|
-
}
|
|
124
|
-
.title {
|
|
125
|
-
font-size: 20px;
|
|
126
|
-
font-weight: 600;
|
|
127
|
-
margin-bottom: 8px;
|
|
128
|
-
color: var(--success);
|
|
129
|
-
}
|
|
130
|
-
.subtitle {
|
|
131
|
-
font-size: 16px;
|
|
132
|
-
color: var(--text-secondary);
|
|
133
|
-
}
|
|
134
|
-
</style>
|
|
135
|
-
</head>
|
|
136
|
-
<body>
|
|
137
|
-
<div class="container">
|
|
138
|
-
<div class="stars"></div>
|
|
139
|
-
<div class="stars-near"></div>
|
|
140
|
-
<div class="content">
|
|
141
|
-
<div class="icon-wrapper">
|
|
142
|
-
<div class="icon-glow"></div>
|
|
143
|
-
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
144
|
-
<polyline points="20 6 9 17 4 12"></polyline>
|
|
145
|
-
</svg>
|
|
146
|
-
</div>
|
|
147
|
-
<h1 class="app-name">PocketCoder</h1>
|
|
148
|
-
<p class="title">Authentication successful!</p>
|
|
149
|
-
<p class="subtitle">You can close this window.</p>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
</body>
|
|
153
|
-
</html>`;
|
|
154
|
-
const ERROR_HTML = `<!DOCTYPE html>
|
|
155
|
-
<html lang="en">
|
|
156
|
-
<head>
|
|
157
|
-
<meta charset="UTF-8">
|
|
158
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
159
|
-
<title>PocketCoder - Error</title>
|
|
160
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
161
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
162
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Inter:wght@600;700&display=swap" rel="stylesheet">
|
|
163
|
-
<style>
|
|
164
|
-
:root {
|
|
165
|
-
--bg-primary: #000000;
|
|
166
|
-
--text-primary: #ffffff;
|
|
167
|
-
--text-secondary: #a1a1a6;
|
|
168
|
-
--error: #ff3b30;
|
|
169
|
-
}
|
|
170
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
171
|
-
html, body {
|
|
172
|
-
height: 100%;
|
|
173
|
-
font-family: "DM Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
174
|
-
background: var(--bg-primary);
|
|
175
|
-
color: var(--text-primary);
|
|
176
|
-
-webkit-font-smoothing: antialiased;
|
|
177
|
-
}
|
|
178
|
-
.container {
|
|
179
|
-
display: flex;
|
|
180
|
-
flex-direction: column;
|
|
181
|
-
align-items: center;
|
|
182
|
-
justify-content: center;
|
|
183
|
-
min-height: 100vh;
|
|
184
|
-
padding: 24px;
|
|
185
|
-
position: relative;
|
|
186
|
-
overflow: hidden;
|
|
187
|
-
}
|
|
188
|
-
.stars, .stars-near {
|
|
189
|
-
position: absolute;
|
|
190
|
-
top: 0; left: 0;
|
|
191
|
-
width: 100%; height: 100%;
|
|
192
|
-
pointer-events: none;
|
|
193
|
-
}
|
|
194
|
-
.stars::before {
|
|
195
|
-
content: "";
|
|
196
|
-
position: absolute;
|
|
197
|
-
top: 30%; left: 50%;
|
|
198
|
-
width: 2px; height: 2px;
|
|
199
|
-
background: transparent;
|
|
200
|
-
border-radius: 50%;
|
|
201
|
-
box-shadow:
|
|
202
|
-
-180px -120px 0 0 rgba(186, 85, 211, 0.6),
|
|
203
|
-
160px -100px 0 0 rgba(135, 206, 250, 0.65),
|
|
204
|
-
-220px 80px 0 0 rgba(255, 182, 193, 0.6),
|
|
205
|
-
200px 120px 0 0 rgba(255, 160, 122, 0.55),
|
|
206
|
-
-120px 180px 0 0 rgba(147, 112, 219, 0.65),
|
|
207
|
-
140px 200px 0 0 rgba(135, 206, 250, 0.6),
|
|
208
|
-
-280px -60px 0 0 rgba(255, 182, 193, 0.55),
|
|
209
|
-
260px -80px 0 0 rgba(186, 85, 211, 0.65),
|
|
210
|
-
-160px -200px 0 0 rgba(255, 160, 122, 0.6),
|
|
211
|
-
180px -180px 0 0 rgba(147, 112, 219, 0.55);
|
|
212
|
-
animation: twinkle 3.5s ease-in-out infinite;
|
|
213
|
-
}
|
|
214
|
-
.stars-near::before {
|
|
215
|
-
content: "";
|
|
216
|
-
position: absolute;
|
|
217
|
-
top: 30%; left: 50%;
|
|
218
|
-
width: 2px; height: 2px;
|
|
219
|
-
background: transparent;
|
|
220
|
-
border-radius: 50%;
|
|
221
|
-
box-shadow:
|
|
222
|
-
-80px -60px 0 0 rgba(186, 85, 211, 0.9),
|
|
223
|
-
70px -50px 0 1px rgba(255, 160, 122, 1),
|
|
224
|
-
-90px 40px 0 0 rgba(135, 206, 250, 0.85),
|
|
225
|
-
85px 55px 0 1px rgba(255, 182, 193, 0.9),
|
|
226
|
-
-50px 80px 0 0 rgba(147, 112, 219, 0.95),
|
|
227
|
-
60px 90px 0 1px rgba(186, 85, 211, 0.85),
|
|
228
|
-
-110px -30px 0 0 rgba(255, 160, 122, 0.9),
|
|
229
|
-
105px -35px 0 1px rgba(135, 206, 250, 0.95);
|
|
230
|
-
animation: twinkle 2s ease-in-out infinite;
|
|
231
|
-
}
|
|
232
|
-
@keyframes twinkle {
|
|
233
|
-
0%, 100% { opacity: 1; }
|
|
234
|
-
50% { opacity: 0.6; }
|
|
235
|
-
}
|
|
236
|
-
.content {
|
|
237
|
-
text-align: center;
|
|
238
|
-
position: relative;
|
|
239
|
-
z-index: 10;
|
|
240
|
-
}
|
|
241
|
-
.icon-wrapper {
|
|
242
|
-
width: 80px; height: 80px;
|
|
243
|
-
margin: 0 auto 24px;
|
|
244
|
-
position: relative;
|
|
245
|
-
display: flex;
|
|
246
|
-
align-items: center;
|
|
247
|
-
justify-content: center;
|
|
248
|
-
}
|
|
249
|
-
.icon-glow {
|
|
250
|
-
position: absolute;
|
|
251
|
-
width: 100%; height: 100%;
|
|
252
|
-
border-radius: 50%;
|
|
253
|
-
background: radial-gradient(circle, rgba(255, 59, 48, 0.4) 0%, transparent 70%);
|
|
254
|
-
animation: iconGlow 2s ease-in-out infinite;
|
|
255
|
-
}
|
|
256
|
-
@keyframes iconGlow {
|
|
257
|
-
0%, 100% { transform: scale(1); opacity: 0.8; }
|
|
258
|
-
50% { transform: scale(1.2); opacity: 1; }
|
|
259
|
-
}
|
|
260
|
-
.icon {
|
|
261
|
-
width: 48px; height: 48px;
|
|
262
|
-
color: var(--error);
|
|
263
|
-
position: relative;
|
|
264
|
-
z-index: 1;
|
|
265
|
-
}
|
|
266
|
-
.app-name {
|
|
267
|
-
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
268
|
-
font-size: 24px;
|
|
269
|
-
font-weight: 700;
|
|
270
|
-
letter-spacing: -0.5px;
|
|
271
|
-
margin-bottom: 8px;
|
|
272
|
-
}
|
|
273
|
-
.title {
|
|
274
|
-
font-size: 20px;
|
|
275
|
-
font-weight: 600;
|
|
276
|
-
margin-bottom: 8px;
|
|
277
|
-
color: var(--error);
|
|
278
|
-
}
|
|
279
|
-
.subtitle {
|
|
280
|
-
font-size: 16px;
|
|
281
|
-
color: var(--text-secondary);
|
|
282
|
-
}
|
|
283
|
-
</style>
|
|
284
|
-
</head>
|
|
285
|
-
<body>
|
|
286
|
-
<div class="container">
|
|
287
|
-
<div class="stars"></div>
|
|
288
|
-
<div class="stars-near"></div>
|
|
289
|
-
<div class="content">
|
|
290
|
-
<div class="icon-wrapper">
|
|
291
|
-
<div class="icon-glow"></div>
|
|
292
|
-
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
293
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
294
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
295
|
-
</svg>
|
|
296
|
-
</div>
|
|
297
|
-
<h1 class="app-name">PocketCoder</h1>
|
|
298
|
-
<p class="title">Login Failed</p>
|
|
299
|
-
<p class="subtitle">You can close this window.</p>
|
|
300
|
-
</div>
|
|
301
|
-
</div>
|
|
302
|
-
</body>
|
|
303
|
-
</html>`;
|
|
304
|
-
/**
|
|
305
|
-
* HTML page that extracts tokens from URL fragment and posts them back.
|
|
306
|
-
* Supabase implicit flow returns tokens in the fragment (#access_token=...).
|
|
307
|
-
*/
|
|
308
|
-
const FRAGMENT_EXTRACTOR_HTML = `<!DOCTYPE html>
|
|
309
|
-
<html lang="en">
|
|
310
|
-
<head>
|
|
311
|
-
<meta charset="UTF-8">
|
|
312
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
313
|
-
<title>PocketCoder - Completing Login...</title>
|
|
314
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
315
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
316
|
-
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Inter:wght@600;700&display=swap" rel="stylesheet">
|
|
317
|
-
<style>
|
|
318
|
-
:root {
|
|
319
|
-
--bg-primary: #000000;
|
|
320
|
-
--text-primary: #ffffff;
|
|
321
|
-
--text-secondary: #a1a1a6;
|
|
322
|
-
--accent: #c9a87c;
|
|
323
|
-
--success: #34c759;
|
|
324
|
-
--error: #ff3b30;
|
|
325
|
-
}
|
|
326
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
327
|
-
html, body {
|
|
328
|
-
height: 100%;
|
|
329
|
-
font-family: "DM Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
330
|
-
background: var(--bg-primary);
|
|
331
|
-
color: var(--text-primary);
|
|
332
|
-
-webkit-font-smoothing: antialiased;
|
|
333
|
-
}
|
|
334
|
-
.container {
|
|
335
|
-
display: flex;
|
|
336
|
-
flex-direction: column;
|
|
337
|
-
align-items: center;
|
|
338
|
-
justify-content: center;
|
|
339
|
-
min-height: 100vh;
|
|
340
|
-
padding: 24px;
|
|
341
|
-
position: relative;
|
|
342
|
-
overflow: hidden;
|
|
343
|
-
}
|
|
344
|
-
.stars, .stars-near {
|
|
345
|
-
position: absolute;
|
|
346
|
-
top: 0; left: 0;
|
|
347
|
-
width: 100%; height: 100%;
|
|
348
|
-
pointer-events: none;
|
|
349
|
-
}
|
|
350
|
-
.stars::before {
|
|
351
|
-
content: "";
|
|
352
|
-
position: absolute;
|
|
353
|
-
top: 30%; left: 50%;
|
|
354
|
-
width: 2px; height: 2px;
|
|
355
|
-
background: transparent;
|
|
356
|
-
border-radius: 50%;
|
|
357
|
-
box-shadow:
|
|
358
|
-
-180px -120px 0 0 rgba(186, 85, 211, 0.6),
|
|
359
|
-
160px -100px 0 0 rgba(135, 206, 250, 0.65),
|
|
360
|
-
-220px 80px 0 0 rgba(255, 182, 193, 0.6),
|
|
361
|
-
200px 120px 0 0 rgba(255, 160, 122, 0.55),
|
|
362
|
-
-120px 180px 0 0 rgba(147, 112, 219, 0.65),
|
|
363
|
-
140px 200px 0 0 rgba(135, 206, 250, 0.6),
|
|
364
|
-
-280px -60px 0 0 rgba(255, 182, 193, 0.55),
|
|
365
|
-
260px -80px 0 0 rgba(186, 85, 211, 0.65),
|
|
366
|
-
-160px -200px 0 0 rgba(255, 160, 122, 0.6),
|
|
367
|
-
180px -180px 0 0 rgba(147, 112, 219, 0.55);
|
|
368
|
-
animation: twinkle 3.5s ease-in-out infinite;
|
|
369
|
-
}
|
|
370
|
-
.stars-near::before {
|
|
371
|
-
content: "";
|
|
372
|
-
position: absolute;
|
|
373
|
-
top: 30%; left: 50%;
|
|
374
|
-
width: 2px; height: 2px;
|
|
375
|
-
background: transparent;
|
|
376
|
-
border-radius: 50%;
|
|
377
|
-
box-shadow:
|
|
378
|
-
-80px -60px 0 0 rgba(186, 85, 211, 0.9),
|
|
379
|
-
70px -50px 0 1px rgba(255, 160, 122, 1),
|
|
380
|
-
-90px 40px 0 0 rgba(135, 206, 250, 0.85),
|
|
381
|
-
85px 55px 0 1px rgba(255, 182, 193, 0.9),
|
|
382
|
-
-50px 80px 0 0 rgba(147, 112, 219, 0.95),
|
|
383
|
-
60px 90px 0 1px rgba(186, 85, 211, 0.85),
|
|
384
|
-
-110px -30px 0 0 rgba(255, 160, 122, 0.9),
|
|
385
|
-
105px -35px 0 1px rgba(135, 206, 250, 0.95);
|
|
386
|
-
animation: twinkle 2s ease-in-out infinite;
|
|
387
|
-
}
|
|
388
|
-
@keyframes twinkle {
|
|
389
|
-
0%, 100% { opacity: 1; }
|
|
390
|
-
50% { opacity: 0.6; }
|
|
391
|
-
}
|
|
392
|
-
.content {
|
|
393
|
-
text-align: center;
|
|
394
|
-
position: relative;
|
|
395
|
-
z-index: 10;
|
|
396
|
-
}
|
|
397
|
-
.icon-wrapper {
|
|
398
|
-
width: 80px; height: 80px;
|
|
399
|
-
margin: 0 auto 24px;
|
|
400
|
-
position: relative;
|
|
401
|
-
display: flex;
|
|
402
|
-
align-items: center;
|
|
403
|
-
justify-content: center;
|
|
404
|
-
}
|
|
405
|
-
.icon-glow {
|
|
406
|
-
position: absolute;
|
|
407
|
-
width: 100%; height: 100%;
|
|
408
|
-
border-radius: 50%;
|
|
409
|
-
background: radial-gradient(circle, rgba(201, 168, 124, 0.4) 0%, transparent 70%);
|
|
410
|
-
animation: iconGlow 2s ease-in-out infinite;
|
|
411
|
-
}
|
|
412
|
-
.icon-glow.success {
|
|
413
|
-
background: radial-gradient(circle, rgba(52, 199, 89, 0.4) 0%, transparent 70%);
|
|
414
|
-
}
|
|
415
|
-
.icon-glow.error {
|
|
416
|
-
background: radial-gradient(circle, rgba(255, 59, 48, 0.4) 0%, transparent 70%);
|
|
417
|
-
}
|
|
418
|
-
@keyframes iconGlow {
|
|
419
|
-
0%, 100% { transform: scale(1); opacity: 0.8; }
|
|
420
|
-
50% { transform: scale(1.2); opacity: 1; }
|
|
421
|
-
}
|
|
422
|
-
.spinner {
|
|
423
|
-
width: 48px; height: 48px;
|
|
424
|
-
border: 3px solid rgba(201, 168, 124, 0.2);
|
|
425
|
-
border-top-color: var(--accent);
|
|
426
|
-
border-radius: 50%;
|
|
427
|
-
animation: spin 1s linear infinite;
|
|
428
|
-
}
|
|
429
|
-
@keyframes spin {
|
|
430
|
-
to { transform: rotate(360deg); }
|
|
431
|
-
}
|
|
432
|
-
.icon {
|
|
433
|
-
width: 48px; height: 48px;
|
|
434
|
-
position: relative;
|
|
435
|
-
z-index: 1;
|
|
436
|
-
display: none;
|
|
437
|
-
}
|
|
438
|
-
.icon.success { color: var(--success); }
|
|
439
|
-
.icon.error { color: var(--error); }
|
|
440
|
-
.app-name {
|
|
441
|
-
font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
442
|
-
font-size: 24px;
|
|
443
|
-
font-weight: 700;
|
|
444
|
-
letter-spacing: -0.5px;
|
|
445
|
-
margin-bottom: 8px;
|
|
446
|
-
}
|
|
447
|
-
.title {
|
|
448
|
-
font-size: 20px;
|
|
449
|
-
font-weight: 600;
|
|
450
|
-
margin-bottom: 8px;
|
|
451
|
-
color: var(--accent);
|
|
452
|
-
}
|
|
453
|
-
.title.success { color: var(--success); }
|
|
454
|
-
.title.error { color: var(--error); }
|
|
455
|
-
.subtitle {
|
|
456
|
-
font-size: 16px;
|
|
457
|
-
color: var(--text-secondary);
|
|
458
|
-
}
|
|
459
|
-
</style>
|
|
460
|
-
</head>
|
|
461
|
-
<body>
|
|
462
|
-
<div class="container">
|
|
463
|
-
<div class="stars"></div>
|
|
464
|
-
<div class="stars-near"></div>
|
|
465
|
-
<div class="content">
|
|
466
|
-
<div class="icon-wrapper">
|
|
467
|
-
<div class="icon-glow" id="iconGlow"></div>
|
|
468
|
-
<div class="spinner" id="spinner"></div>
|
|
469
|
-
<svg class="icon success" id="successIcon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
470
|
-
<polyline points="20 6 9 17 4 12"></polyline>
|
|
471
|
-
</svg>
|
|
472
|
-
<svg class="icon error" id="errorIcon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
473
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
474
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
475
|
-
</svg>
|
|
476
|
-
</div>
|
|
477
|
-
<h1 class="app-name">PocketCoder</h1>
|
|
478
|
-
<p class="title" id="title">Completing login...</p>
|
|
479
|
-
<p class="subtitle" id="subtitle">Please wait</p>
|
|
480
|
-
</div>
|
|
481
|
-
</div>
|
|
482
|
-
<script>
|
|
483
|
-
const iconGlow = document.getElementById('iconGlow');
|
|
484
|
-
const spinner = document.getElementById('spinner');
|
|
485
|
-
const successIcon = document.getElementById('successIcon');
|
|
486
|
-
const errorIcon = document.getElementById('errorIcon');
|
|
487
|
-
const title = document.getElementById('title');
|
|
488
|
-
const subtitle = document.getElementById('subtitle');
|
|
489
|
-
|
|
490
|
-
function showSuccess() {
|
|
491
|
-
spinner.style.display = 'none';
|
|
492
|
-
iconGlow.classList.add('success');
|
|
493
|
-
successIcon.style.display = 'block';
|
|
494
|
-
title.textContent = 'Authentication successful!';
|
|
495
|
-
title.classList.add('success');
|
|
496
|
-
subtitle.textContent = 'You can close this window.';
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
function showError(message) {
|
|
500
|
-
spinner.style.display = 'none';
|
|
501
|
-
iconGlow.classList.add('error');
|
|
502
|
-
errorIcon.style.display = 'block';
|
|
503
|
-
title.textContent = 'Login Failed';
|
|
504
|
-
title.classList.add('error');
|
|
505
|
-
subtitle.textContent = message || 'You can close this window.';
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const hash = window.location.hash.substring(1);
|
|
509
|
-
const params = new URLSearchParams(hash);
|
|
510
|
-
const accessToken = params.get('access_token');
|
|
511
|
-
const refreshToken = params.get('refresh_token');
|
|
512
|
-
const error = params.get('error');
|
|
513
|
-
|
|
514
|
-
if (error) {
|
|
515
|
-
showError(error);
|
|
516
|
-
} else if (accessToken && refreshToken) {
|
|
517
|
-
fetch('/auth/tokens', {
|
|
518
|
-
method: 'POST',
|
|
519
|
-
headers: { 'Content-Type': 'application/json' },
|
|
520
|
-
body: JSON.stringify({ access_token: accessToken, refresh_token: refreshToken })
|
|
521
|
-
}).then(() => {
|
|
522
|
-
showSuccess();
|
|
523
|
-
}).catch(err => {
|
|
524
|
-
showError(err.message);
|
|
525
|
-
});
|
|
526
|
-
} else {
|
|
527
|
-
showError('Missing tokens in response');
|
|
528
|
-
}
|
|
529
|
-
</script>
|
|
530
|
-
</body>
|
|
531
|
-
</html>`;
|
|
532
5
|
/**
|
|
533
6
|
* Start a temporary HTTP server on a random port to receive the OAuth callback.
|
|
534
7
|
* The server listens only on 127.0.0.1 and closes automatically after the
|
|
@@ -550,18 +23,20 @@ export async function startOAuthServer() {
|
|
|
550
23
|
const errorParam = reqUrl.searchParams.get("error");
|
|
551
24
|
if (errorParam) {
|
|
552
25
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
553
|
-
res.end(ERROR_HTML);
|
|
554
26
|
error = new Error(errorParam);
|
|
555
|
-
|
|
27
|
+
// Wait for response to be fully sent before settling
|
|
28
|
+
res.on("finish", settle);
|
|
29
|
+
res.end(ERROR_HTML);
|
|
556
30
|
return;
|
|
557
31
|
}
|
|
558
32
|
// Check for code flow (code in query string)
|
|
559
33
|
const code = reqUrl.searchParams.get("code");
|
|
560
34
|
if (code) {
|
|
561
35
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
562
|
-
res.end(SUCCESS_HTML);
|
|
563
36
|
result = { code };
|
|
564
|
-
|
|
37
|
+
// Wait for response to be fully sent before settling
|
|
38
|
+
res.on("finish", settle);
|
|
39
|
+
res.end(SUCCESS_HTML);
|
|
565
40
|
return;
|
|
566
41
|
}
|
|
567
42
|
// No code - serve HTML to extract tokens from fragment (implicit flow)
|
|
@@ -580,9 +55,10 @@ export async function startOAuthServer() {
|
|
|
580
55
|
const data = JSON.parse(body);
|
|
581
56
|
if (data.access_token && data.refresh_token) {
|
|
582
57
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
583
|
-
res.end(JSON.stringify({ success: true }));
|
|
584
58
|
result = { access_token: data.access_token, refresh_token: data.refresh_token };
|
|
585
|
-
|
|
59
|
+
// Wait for response to be fully sent before settling
|
|
60
|
+
res.on("finish", settle);
|
|
61
|
+
res.end(JSON.stringify({ success: true }));
|
|
586
62
|
}
|
|
587
63
|
else {
|
|
588
64
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-server.js","sourceRoot":"","sources":["../../src/auth/oauth-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAKzC,
|
|
1
|
+
{"version":3,"file":"oauth-server.js","sourceRoot":"","sources":["../../src/auth/oauth-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAKzC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEzF,8DAA8D;AAC9D,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAmBvC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,MAAM,GAA+B,IAAI,CAAC;IAC9C,IAAI,KAAK,GAAiB,IAAI,CAAC;IAC/B,IAAI,QAAQ,GAAwB,IAAI,CAAC;IAEzC,SAAS,MAAM;QACb,OAAO,GAAG,IAAI,CAAC;QACf,QAAQ,EAAE,EAAE,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAW,YAAY,CAAC,CAAC,GAAoB,EAAE,GAAmB,EAAE,EAAE;QAChF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAE3D,uEAAuE;QACvE,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,QAAQ,KAAK,gBAAgB,EAAE,CAAC;YACjE,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpD,IAAI,UAAU,EAAE,CAAC;gBACf,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC9B,qDAAqD;gBACrD,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBACzB,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACpB,OAAO;YACT,CAAC;YAED,6CAA6C;YAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,IAAI,EAAE,CAAC;gBACT,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC;gBAClB,qDAAqD;gBACrD,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBACzB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,uEAAuE;YACvE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,4DAA4D;QAC5D,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;YAChE,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;gBACvB,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3B,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsD,CAAC;oBACnF,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;wBAC5C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBAC3D,MAAM,GAAG,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;wBAChF,qDAAqD;wBACrD,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;wBACzB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;oBAC7C,CAAC;yBAAM,CAAC;wBACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;QACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAC;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1B,MAAM,WAAW,GAAG,oBAAoB,IAAI,gBAAgB,CAAC;IAE7D,iBAAiB;IACjB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,KAAK,GAAG,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAErB,SAAS,KAAK;QACZ,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;IAED,KAAK,UAAU,eAAe;QAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,QAAQ,GAAG,OAAO,CAAC;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,CAAC;QACd,CAAC;QAED,OAAO,MAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,IAAI;QACJ,WAAW;QACX,eAAe;QACf,KAAK;KACN,CAAC;AACJ,CAAC"}
|