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.
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.616";
1
+ export declare const CLI_VERSION = "0.1.618";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.616";
2
+ export const CLI_VERSION = "0.1.618";
3
3
  //# sourceMappingURL=version.js.map
@@ -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;AA+CD,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAuL/D"}
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
- * Reconcile the child app's (possibly stale) session against the LIVE ugly.bot
19
- * account. The child holds a session JWT minted for whatever account was active
20
- * at login; if the user later signs into ugly.bot as a different account, that
21
- * token stays valid (no revocation), so the app would silently keep acting as
22
- * the old account. Here we ask ugly.bot who the cookie session is now and, on a
23
- * mismatch, drop the stale session and re-adopt the live account.
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
- * Detection works only where the ugly.bot cookie is actually sent — same-site
26
- * `*.ugly.bot` subdomains. Cross-site apex apps get `{ userId: null }` (SameSite
27
- * =Lax strips the cookie), which is a safe no-op. Guarded once-per-tab so the
28
- * re-adopt bounce can't loop.
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 reconcileUglyBotSession(uglyBotUrl, sessionUserId) {
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(`${uglyBotUrl}/oauth/me`, { credentials: 'include' });
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 data = (await res.json());
47
- const liveId = data.userId;
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
- // Stale session for a DIFFERENT ugly.bot account — drop it and re-adopt
53
- // the live one via a one-time silent-SSO bounce.
54
- clearSilentSsoTried();
55
- document.cookie = 'auth_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
56
- if (!attemptSilentSso())
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 this session still matches the live ugly.bot
192
- // account; re-adopt the correct one if the user switched accounts.
193
- reconcileUglyBotSession(uglyBotUrl, userId);
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":"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"}
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;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,UAAkB;IAC7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACtC,IAAI,SAAiB,CAAC;QACtB,IAAI,CAAC;YACH,SAAS,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,SAAS,wBAAwB,kBAAkB,CAAC,MAAM,CAAC,cAAc,CAAC;QACzF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAC9B,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAEtC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAQ,EAAE;YAC3C,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACjD,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC;QACF,MAAM,SAAS,GAAG,CAAC,CAAe,EAAQ,EAAE;YAC1C,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO;YACnC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAsD,CAAC;YACtE,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;gBACjD,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,cAAc,CAAC,UAAkB,EAAE,aAA4B;IACtE,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO;IAC1C,IAAI,CAAC;QACH,IAAI,cAAc,CAAC,OAAO,CAAC,mBAAmB,CAAC;YAAE,OAAO;QACxD,cAAc,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IACD,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrE,4EAA4E;QAC5E,uBAAuB;QACvB,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;gBACtC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;aAC/B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,OAAO;YACpB,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAuB,CAAC;YAC3D,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,MAAM,UAAU,GAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAsB,CAAC,GAAG,IAAI,IAAI,CAAC;YAC3F,uEAAuE;YACvE,uEAAuE;YACvE,2EAA2E;YAC3E,kDAAkD;YAClD,IAAI,UAAU,IAAI,UAAU,KAAK,aAAa,EAAE,CAAC;gBAC/C,mBAAmB,EAAE,CAAC;gBACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,8CAA8C;QAChD,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;AACP,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,MAAM,EACJ,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,WAAW,GAAG,EAAE,EAC1B,cAAc,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,OAAO,GAAG,OAAO,EACvB,QAAQ,GAAG,sDAA+B,EAC1C,SAAS,GAAG,MAAM,EAClB,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,WAAW,GACtB,GAAG,OAAO,CAAC;IACZ,MAAM,cAAc,GAAG,WAAW,KAAK,KAAK,CAAC;IAE7C,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAE,CAAC,CAAC,CAAC,OAAO,CAAC;IAC3E,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAEhC,uEAAuE;IACvE,sEAAsE;IACtE,iEAAiE;IACjE,uEAAuE;IACvE,iEAAiE;IACjE,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,yBAAyB,EAAE,CAAC;QAC5F,IAAI,CAAC,MAAM,CAAC,KAAC,iBAAiB,KAAG,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,sEAAsE;IACtE,8EAA8E;IAC9E,2EAA2E;IAC3E,qEAAqE;IACrE,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAChD,IAAI,SAAS,EAAE,CAAC;YACd,kBAAkB,EAAE,CAAC,CAAC,2CAA2C;YACjE,KAAK,CAAC,KAAK,IAAI,EAAE;gBACf,IAAI,CAAC;oBACH,MAAM,KAAK,CAAC,cAAc,EAAE;wBAC1B,MAAM,EAAE,MAAM;wBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;wBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;qBAC1C,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,uEAAuE;gBACzE,CAAC;gBACD,yEAAyE;gBACzE,qEAAqE;gBACrE,mCAAmC;gBACnC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;gBACjC,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC7B,MAAM,CAAC,QAAQ,CAAC,OAAO,CACrB,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CACvE,CAAC;YACJ,CAAC,CAAC,EAAE,CAAC;YACL,IAAI,CAAC,MAAM,CAAC,mBAAK,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QACD,4EAA4E;QAC5E,0EAA0E;QAC1E,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,MAAM,EAAE,CAAC;YACtC,kBAAkB,EAAE,CAAC;YACrB,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC7B,MAAM,CAAC,OAAO,CAAC,YAAY,CACzB,IAAI,EACJ,EAAE,EACF,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CACvE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,8BAA8B,EAAE,CAAC;IACjC,cAAc,EAAE,CAAC;IAEjB,sCAAsC;IACtC,MAAM,UAAU,GAAG,CAAC,CAAC,kBAAkB,CAAC,IAAI,kBAAkB,CAAC;IAC/D,MAAM,gBAAgB,GAAG,CAAC,CAAC,yBAAyB,CAAC,IAAI,EAAE,CAAC;IAC5D,IAAI,gBAAgB,EAAE,CAAC;QACrB,UAAU,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAElC,SAAS,gBAAgB,CACvB,eAAwB,EACxB,QAAsB;QAEtB,MAAM,IAAI,GAAG,CACX,KAAC,cAAc,IACb,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,GAAG,EAAE,CAAC,eAAe,YAErC,QAAQ,GACM,CAClB,CAAC;QAEF,MAAM,WAAW,GAAG,aAAa;YAC/B,CAAC,CAAC,KAAC,eAAe,IAAC,MAAM,EAAE,aAAa,YAAG,IAAI,GAAmB;YAClE,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,CAAC,MAAM,CACT,cAAc;YACZ,CAAC,CAAC,KAAC,gBAAgB,cAAE,WAAW,GAAoB;YACpD,CAAC,CAAC,WAAW,CAChB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,sEAAsE;QACtE,6EAA6E;QAC7E,6EAA6E;QAC7E,IAAI,OAAO,CAAC,SAAS,IAAI,gBAAgB,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,mBAAK,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QACD,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACrC,2EAA2E;QAC3E,8EAA8E;QAC9E,4EAA4E;QAC5E,4EAA4E;QAC5E,6EAA6E;QAC7E,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,CACb,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACtC,CAAC,GAAG,CAAC;IACN,MAAM,MAAM,GAAG,YAAY,CAAC;QAC1B,QAAQ,EAAE,EAAE,GAAG,iBAAiB,EAAE,GAAG,WAAW,EAAE;QAClD,QAAQ,EAAE,EAAE,GAAG,iBAAiB,EAAE,GAAG,WAAW,EAAE;QAClD,GAAG,EAAE,SAAS;KACf,CAAC,CAAC;IAEH,8EAA8E;IAC9E,0EAA0E;IAC1E,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,yEAAyE;IACzE,6EAA6E;IAC7E,qDAAqD;IACrD,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE;QAC1C,IAAI,eAAe;YAAE,OAAO;QAC5B,eAAe,GAAG,IAAI,CAAC;QACvB,mBAAmB,EAAE,CAAC;QACtB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,MAAM;SACH,OAAO,CAAC,KAAK,CAAC;SACd,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,uEAAuE;QACvE,sEAAsE;QACtE,sEAAsE;QACtE,8DAA8D;QAC9D,YAAY,CAAC,MAAM,CAAC,CAAC;QACrB,yDAAyD;QACzD,0DAA0D;QAC1D,uDAAuD;QACvD,0DAA0D;QAC1D,2DAA2D;QAC3D,2DAA2D;QAC3D,6DAA6D;QAC7D,MAAM,iBAAiB,GAAG,QAAQ,IAAI,KAAK,CAAC;QAC5C,MAAM,aAAa,GAAG,iBAAiB;YACrC,CAAC,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,UAAU,CAAC;YACpD,CAAC,CAAC,IAAI,CAAC;QACT,gBAAgB,CACd,IAAI,EACJ,KAAC,WAAW,IAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,YAClF,SAAS,EAAE,GACA,CACf,CAAC;QACF,2EAA2E;QAC3E,wEAAwE;QACxE,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACtB,OAAO,CAAC,KAAK,CAAC,6DAA6D,EAAE,GAAG,CAAC,CAAC;QAClF,QAAQ,CAAC,MAAM,GAAG,4DAA4D,CAAC;QAC/E,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACP,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.616",
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": [
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.616";
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
- * Reconcile the child app's (possibly stale) session against the LIVE ugly.bot
65
- * account. The child holds a session JWT minted for whatever account was active
66
- * at login; if the user later signs into ugly.bot as a different account, that
67
- * token stays valid (no revocation), so the app would silently keep acting as
68
- * the old account. Here we ask ugly.bot who the cookie session is now and, on a
69
- * mismatch, drop the stale session and re-adopt the live account.
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
- * Detection works only where the ugly.bot cookie is actually sent — same-site
72
- * `*.ugly.bot` subdomains. Cross-site apex apps get `{ userId: null }` (SameSite
73
- * =Lax strips the cookie), which is a safe no-op. Guarded once-per-tab so the
74
- * re-adopt bounce can't loop.
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 reconcileUglyBotSession(uglyBotUrl: string, sessionUserId: string): void {
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(`${uglyBotUrl}/oauth/me`, { credentials: 'include' });
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 data = (await res.json()) as { userId?: string | null };
89
- const liveId = data.userId;
90
- // null cookie not sent (cross-site apex, or logged out at ugly.bot):
91
- // nothing to reconcile, leave the session untouched.
92
- if (!liveId || liveId === sessionUserId) return;
93
- // Stale session for a DIFFERENT ugly.bot account drop it and re-adopt
94
- // the live one via a one-time silent-SSO bounce.
95
- clearSilentSsoTried();
96
- document.cookie = 'auth_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
97
- if (!attemptSilentSso()) window.location.reload();
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 this session still matches the live ugly.bot
279
- // account; re-adopt the correct one if the user switched accounts.
280
- reconcileUglyBotSession(uglyBotUrl, userId);
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);