ugly-app 0.1.616 → 0.1.618
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/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/client/bootstrapApp.d.ts.map +1 -1
- package/dist/client/bootstrapApp.js +93 -25
- package/dist/client/bootstrapApp.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/src/client/bootstrapApp.tsx +92 -25
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.618";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapApp.d.ts","sourceRoot":"","sources":["../../src/client/bootstrapApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAUzE,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAInF,UAAU,mBAAmB;IAC3B,mFAAmF;IACnF,QAAQ,EAAE,eAAe,CAAC;IAE1B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,eAAe,CAAC;IAE3B,uDAAuD;IACvD,cAAc,EAAE,aAAa,CAAC;QAC5B,QAAQ,EAAE,SAAS,CAAC;QACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC;KACjC,CAAC,CAAC;IAEH,+EAA+E;IAC/E,MAAM,EAAE,MAAM,YAAY,CAAC;IAE3B,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAE5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,qFAAqF;IACrF,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAEhC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,KAAK,CAAC;IAEjB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"bootstrapApp.d.ts","sourceRoot":"","sources":["../../src/client/bootstrapApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAUzE,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAInF,UAAU,mBAAmB;IAC3B,mFAAmF;IACnF,QAAQ,EAAE,eAAe,CAAC;IAE1B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,eAAe,CAAC;IAE3B,uDAAuD;IACvD,cAAc,EAAE,aAAa,CAAC;QAC5B,QAAQ,EAAE,SAAS,CAAC;QACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC;KACjC,CAAC,CAAC;IAEH,+EAA+E;IAC/E,MAAM,EAAE,MAAM,YAAY,CAAC;IAE3B,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAE5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,qFAAqF;IACrF,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAEhC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,KAAK,CAAC;IAEjB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA4GD,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA6L/D"}
|
|
@@ -15,19 +15,72 @@ import { createUglyBotSocket } from './uglyBotSocket.js';
|
|
|
15
15
|
const w = typeof window !== 'undefined' ? window : {};
|
|
16
16
|
const RECONCILE_TRIED_KEY = 'ugly_session_reconciled';
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* the
|
|
23
|
-
|
|
18
|
+
* Load ugly.bot's silent-auth endpoint in a hidden iframe and resolve with the
|
|
19
|
+
* one-time code it postMessages back (or null if there's no ugly.bot session, or
|
|
20
|
+
* on timeout). This is the SAME mechanism as auto-login — a same-site iframe that
|
|
21
|
+
* reads the live ugly.bot cookie — repurposed here so it ALSO serves as the
|
|
22
|
+
* keep-the-token-fresh / account-sync check on every boot.
|
|
23
|
+
*/
|
|
24
|
+
function silentAuthViaIframe(uglyBotUrl) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
if (typeof document === 'undefined') {
|
|
27
|
+
resolve(null);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const origin = window.location.origin;
|
|
31
|
+
let botOrigin;
|
|
32
|
+
try {
|
|
33
|
+
botOrigin = new URL(uglyBotUrl).origin;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
resolve(null);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const src = `${botOrigin}/oauth/silent?origin=${encodeURIComponent(origin)}&mode=iframe`;
|
|
40
|
+
const iframe = document.createElement('iframe');
|
|
41
|
+
iframe.style.display = 'none';
|
|
42
|
+
iframe.setAttribute('aria-hidden', 'true');
|
|
43
|
+
iframe.setAttribute('tabindex', '-1');
|
|
44
|
+
let settled = false;
|
|
45
|
+
const finish = (code) => {
|
|
46
|
+
if (settled)
|
|
47
|
+
return;
|
|
48
|
+
settled = true;
|
|
49
|
+
window.removeEventListener('message', onMessage);
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
iframe.remove();
|
|
52
|
+
resolve(code);
|
|
53
|
+
};
|
|
54
|
+
const onMessage = (e) => {
|
|
55
|
+
if (e.origin !== botOrigin)
|
|
56
|
+
return;
|
|
57
|
+
const data = e.data;
|
|
58
|
+
if (data && data.type === 'ugly-bot-silent-auth') {
|
|
59
|
+
finish(typeof data.code === 'string' ? data.code : null);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
window.addEventListener('message', onMessage);
|
|
63
|
+
const timer = setTimeout(() => finish(null), 6000);
|
|
64
|
+
iframe.src = src;
|
|
65
|
+
document.body.appendChild(iframe);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Boot-time silent auth + account-sync via the iframe above. One mechanism, three
|
|
70
|
+
* jobs: (1) logged-out → auto-login if a ugly.bot session exists; (2) logged-in,
|
|
71
|
+
* same account → redeem a fresh code so the session cookie/token stays valid;
|
|
72
|
+
* (3) logged-in, DIFFERENT ugly.bot account → reload onto the live account (the
|
|
73
|
+
* child's old JWT never auto-revokes, so without this it would keep acting as the
|
|
74
|
+
* stale account). `sessionUserId` is the current session's user (null if logged
|
|
75
|
+
* out). Guarded once-per-tab so the reload can't loop.
|
|
24
76
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
77
|
+
* Works for BOTH same-site subdomains (the iframe reads ugly.bot's `Lax`
|
|
78
|
+
* auth_token) and cross-site apex apps (the iframe reads the `SameSite=None`
|
|
79
|
+
* `ugly_sso` companion). On Safari/3p-cookie-blocked browsers the cross-site
|
|
80
|
+
* read can still come back empty — that's a safe no-op; the logged-out path's
|
|
81
|
+
* top-level redirect SSO remains the apex fallback.
|
|
29
82
|
*/
|
|
30
|
-
function
|
|
83
|
+
function silentAuthSync(uglyBotUrl, sessionUserId) {
|
|
31
84
|
if (typeof window === 'undefined')
|
|
32
85
|
return;
|
|
33
86
|
try {
|
|
@@ -39,22 +92,31 @@ function reconcileUglyBotSession(uglyBotUrl, sessionUserId) {
|
|
|
39
92
|
return;
|
|
40
93
|
}
|
|
41
94
|
void (async () => {
|
|
95
|
+
const code = await silentAuthViaIframe(uglyBotUrl).catch(() => null);
|
|
96
|
+
// No code → no reachable ugly.bot session (logged out there too). Leave the
|
|
97
|
+
// current state as-is.
|
|
98
|
+
if (!code)
|
|
99
|
+
return;
|
|
42
100
|
try {
|
|
43
|
-
const res = await fetch(
|
|
101
|
+
const res = await fetch('/auth/verify', {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers: { 'Content-Type': 'application/json' },
|
|
104
|
+
body: JSON.stringify({ code }),
|
|
105
|
+
});
|
|
44
106
|
if (!res.ok)
|
|
45
107
|
return;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
// null → cookie not sent (cross-site apex, or logged out at ugly.bot):
|
|
49
|
-
// nothing to reconcile, leave the session untouched.
|
|
50
|
-
if (!liveId || liveId === sessionUserId)
|
|
108
|
+
const { token } = (await res.json());
|
|
109
|
+
if (!token)
|
|
51
110
|
return;
|
|
52
|
-
|
|
53
|
-
// the
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
111
|
+
const liveUserId = JSON.parse(atob(token.split('.')[1])).sub ?? null;
|
|
112
|
+
// Same account → the cookie was just refreshed; nothing visible to do.
|
|
113
|
+
// Different account (or we were logged out) → reload to adopt the live
|
|
114
|
+
// session the server now holds. Clear the once-per-tab silent-SSO guard so
|
|
115
|
+
// the reloaded page doesn't suppress its own SSO.
|
|
116
|
+
if (liveUserId && liveUserId !== sessionUserId) {
|
|
117
|
+
clearSilentSsoTried();
|
|
57
118
|
window.location.reload();
|
|
119
|
+
}
|
|
58
120
|
}
|
|
59
121
|
catch {
|
|
60
122
|
/* network hiccup — leave the session as-is */
|
|
@@ -144,6 +206,12 @@ export function bootstrapApp(options) {
|
|
|
144
206
|
return;
|
|
145
207
|
}
|
|
146
208
|
renderWithRouter(false, renderApp());
|
|
209
|
+
// Then silently adopt an existing ugly.bot session via the hidden iframe —
|
|
210
|
+
// same mechanism as auto-login. Subdomains read the Lax auth_token; apex apps
|
|
211
|
+
// read the SameSite=None ugly_sso companion. Renders logged-out first, then
|
|
212
|
+
// reloads logged-in if a session is found. (For apex, the redirect above is
|
|
213
|
+
// the no-flash fast path on first boot; this covers later boots / its miss.)
|
|
214
|
+
silentAuthSync(uglyBotUrl, null);
|
|
147
215
|
return;
|
|
148
216
|
}
|
|
149
217
|
const userId = (JSON.parse(atob(token.split('.')[1]))).sub;
|
|
@@ -188,9 +256,9 @@ export function bootstrapApp(options) {
|
|
|
188
256
|
? createUglyBotSocket(effectiveAppToken, uglyBotUrl)
|
|
189
257
|
: null;
|
|
190
258
|
renderWithRouter(true, _jsx(AppProvider, { socket: socket, uglyBotSocket: uglyBotSocket, userId: userId, user: user, children: renderApp() }));
|
|
191
|
-
// Background: make sure
|
|
192
|
-
// account; re-adopt the correct one if the user switched
|
|
193
|
-
|
|
259
|
+
// Background: refresh the session token and make sure it still matches the
|
|
260
|
+
// live ugly.bot account; re-adopt the correct one if the user switched.
|
|
261
|
+
silentAuthSync(uglyBotUrl, userId);
|
|
194
262
|
})
|
|
195
263
|
.catch((err) => {
|
|
196
264
|
console.error('[bootstrapApp] socket.connect failed, clearing auth cookie:', err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrapApp.js","sourceRoot":"","sources":["../../src/client/bootstrapApp.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,eAAe,EAA8B,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AA4CzD,MAAM,CAAC,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAuD,CAAC,CAAC,CAAC,EAAwC,CAAC;AAE7I,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"bootstrapApp.js","sourceRoot":"","sources":["../../src/client/bootstrapApp.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugly-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.618",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
|
|
6
6
|
"files": [
|
package/src/cli/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by prebuild — do not edit manually
|
|
2
|
-
export const CLI_VERSION = "0.1.
|
|
2
|
+
export const CLI_VERSION = "0.1.618";
|
|
@@ -61,19 +61,71 @@ const w = typeof window !== 'undefined' ? window as unknown as Record<string, st
|
|
|
61
61
|
const RECONCILE_TRIED_KEY = 'ugly_session_reconciled';
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* the
|
|
69
|
-
|
|
64
|
+
* Load ugly.bot's silent-auth endpoint in a hidden iframe and resolve with the
|
|
65
|
+
* one-time code it postMessages back (or null if there's no ugly.bot session, or
|
|
66
|
+
* on timeout). This is the SAME mechanism as auto-login — a same-site iframe that
|
|
67
|
+
* reads the live ugly.bot cookie — repurposed here so it ALSO serves as the
|
|
68
|
+
* keep-the-token-fresh / account-sync check on every boot.
|
|
69
|
+
*/
|
|
70
|
+
function silentAuthViaIframe(uglyBotUrl: string): Promise<string | null> {
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
if (typeof document === 'undefined') {
|
|
73
|
+
resolve(null);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const origin = window.location.origin;
|
|
77
|
+
let botOrigin: string;
|
|
78
|
+
try {
|
|
79
|
+
botOrigin = new URL(uglyBotUrl).origin;
|
|
80
|
+
} catch {
|
|
81
|
+
resolve(null);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const src = `${botOrigin}/oauth/silent?origin=${encodeURIComponent(origin)}&mode=iframe`;
|
|
85
|
+
const iframe = document.createElement('iframe');
|
|
86
|
+
iframe.style.display = 'none';
|
|
87
|
+
iframe.setAttribute('aria-hidden', 'true');
|
|
88
|
+
iframe.setAttribute('tabindex', '-1');
|
|
89
|
+
|
|
90
|
+
let settled = false;
|
|
91
|
+
const finish = (code: string | null): void => {
|
|
92
|
+
if (settled) return;
|
|
93
|
+
settled = true;
|
|
94
|
+
window.removeEventListener('message', onMessage);
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
iframe.remove();
|
|
97
|
+
resolve(code);
|
|
98
|
+
};
|
|
99
|
+
const onMessage = (e: MessageEvent): void => {
|
|
100
|
+
if (e.origin !== botOrigin) return;
|
|
101
|
+
const data = e.data as { type?: string; code?: string | null } | null;
|
|
102
|
+
if (data && data.type === 'ugly-bot-silent-auth') {
|
|
103
|
+
finish(typeof data.code === 'string' ? data.code : null);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
window.addEventListener('message', onMessage);
|
|
107
|
+
const timer = setTimeout(() => finish(null), 6000);
|
|
108
|
+
iframe.src = src;
|
|
109
|
+
document.body.appendChild(iframe);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Boot-time silent auth + account-sync via the iframe above. One mechanism, three
|
|
115
|
+
* jobs: (1) logged-out → auto-login if a ugly.bot session exists; (2) logged-in,
|
|
116
|
+
* same account → redeem a fresh code so the session cookie/token stays valid;
|
|
117
|
+
* (3) logged-in, DIFFERENT ugly.bot account → reload onto the live account (the
|
|
118
|
+
* child's old JWT never auto-revokes, so without this it would keep acting as the
|
|
119
|
+
* stale account). `sessionUserId` is the current session's user (null if logged
|
|
120
|
+
* out). Guarded once-per-tab so the reload can't loop.
|
|
70
121
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
122
|
+
* Works for BOTH same-site subdomains (the iframe reads ugly.bot's `Lax`
|
|
123
|
+
* auth_token) and cross-site apex apps (the iframe reads the `SameSite=None`
|
|
124
|
+
* `ugly_sso` companion). On Safari/3p-cookie-blocked browsers the cross-site
|
|
125
|
+
* read can still come back empty — that's a safe no-op; the logged-out path's
|
|
126
|
+
* top-level redirect SSO remains the apex fallback.
|
|
75
127
|
*/
|
|
76
|
-
function
|
|
128
|
+
function silentAuthSync(uglyBotUrl: string, sessionUserId: string | null): void {
|
|
77
129
|
if (typeof window === 'undefined') return;
|
|
78
130
|
try {
|
|
79
131
|
if (sessionStorage.getItem(RECONCILE_TRIED_KEY)) return;
|
|
@@ -82,19 +134,28 @@ function reconcileUglyBotSession(uglyBotUrl: string, sessionUserId: string): voi
|
|
|
82
134
|
return;
|
|
83
135
|
}
|
|
84
136
|
void (async () => {
|
|
137
|
+
const code = await silentAuthViaIframe(uglyBotUrl).catch(() => null);
|
|
138
|
+
// No code → no reachable ugly.bot session (logged out there too). Leave the
|
|
139
|
+
// current state as-is.
|
|
140
|
+
if (!code) return;
|
|
85
141
|
try {
|
|
86
|
-
const res = await fetch(
|
|
142
|
+
const res = await fetch('/auth/verify', {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: { 'Content-Type': 'application/json' },
|
|
145
|
+
body: JSON.stringify({ code }),
|
|
146
|
+
});
|
|
87
147
|
if (!res.ok) return;
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
// the
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
148
|
+
const { token } = (await res.json()) as { token?: string };
|
|
149
|
+
if (!token) return;
|
|
150
|
+
const liveUserId = (JSON.parse(atob(token.split('.')[1])) as { sub?: string }).sub ?? null;
|
|
151
|
+
// Same account → the cookie was just refreshed; nothing visible to do.
|
|
152
|
+
// Different account (or we were logged out) → reload to adopt the live
|
|
153
|
+
// session the server now holds. Clear the once-per-tab silent-SSO guard so
|
|
154
|
+
// the reloaded page doesn't suppress its own SSO.
|
|
155
|
+
if (liveUserId && liveUserId !== sessionUserId) {
|
|
156
|
+
clearSilentSsoTried();
|
|
157
|
+
window.location.reload();
|
|
158
|
+
}
|
|
98
159
|
} catch {
|
|
99
160
|
/* network hiccup — leave the session as-is */
|
|
100
161
|
}
|
|
@@ -222,6 +283,12 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
|
|
|
222
283
|
return;
|
|
223
284
|
}
|
|
224
285
|
renderWithRouter(false, renderApp());
|
|
286
|
+
// Then silently adopt an existing ugly.bot session via the hidden iframe —
|
|
287
|
+
// same mechanism as auto-login. Subdomains read the Lax auth_token; apex apps
|
|
288
|
+
// read the SameSite=None ugly_sso companion. Renders logged-out first, then
|
|
289
|
+
// reloads logged-in if a session is found. (For apex, the redirect above is
|
|
290
|
+
// the no-flash fast path on first boot; this covers later boots / its miss.)
|
|
291
|
+
silentAuthSync(uglyBotUrl, null);
|
|
225
292
|
return;
|
|
226
293
|
}
|
|
227
294
|
|
|
@@ -275,9 +342,9 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
|
|
|
275
342
|
{renderApp()}
|
|
276
343
|
</AppProvider>,
|
|
277
344
|
);
|
|
278
|
-
// Background: make sure
|
|
279
|
-
// account; re-adopt the correct one if the user switched
|
|
280
|
-
|
|
345
|
+
// Background: refresh the session token and make sure it still matches the
|
|
346
|
+
// live ugly.bot account; re-adopt the correct one if the user switched.
|
|
347
|
+
silentAuthSync(uglyBotUrl, userId);
|
|
281
348
|
})
|
|
282
349
|
.catch((err: unknown) => {
|
|
283
350
|
console.error('[bootstrapApp] socket.connect failed, clearing auth cookie:', err);
|