ugly-app 0.1.590 → 0.1.591

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.590";
1
+ export declare const CLI_VERSION = "0.1.591";
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.590";
2
+ export const CLI_VERSION = "0.1.591";
3
3
  //# sourceMappingURL=version.js.map
@@ -12,18 +12,25 @@ export interface StartLoginOptions {
12
12
  */
13
13
  export declare function startUglyBotLogin(opts?: StartLoginOptions): void;
14
14
  /**
15
- * Non-blocking silent SSO for apex-domain apps (ugly.chat, ugly.press, …) that
16
- * don't share ugly.bot's `auth_token` cookie. Renders nothing and blocks
17
- * nothing: it drops a hidden iframe pointed at ugly.bot's `/oauth/silent`, which
18
- * — if the visitor already has a ugly.bot session — posts back a one-time code
19
- * we redeem via `/auth/verify`, then reloads (so the server re-renders
20
- * authenticated). If the visitor isn't logged into ugly.bot (or it times out),
21
- * the iframe is removed and the page stays as it rendered.
15
+ * Silent SSO for apex-domain apps (ugly.chat, ugly.press, …) that don't share
16
+ * ugly.bot's `auth_token` cookie. Adopts an existing ugly.bot session with NO
17
+ * user interaction via a top-level redirect to ugly.bot's `/oauth/silent`:
22
18
  *
23
- * Replaces the old AutoLoginGate, which blocked first paint ~4s on the handshake.
24
- * Call AFTER the app has rendered. Runs at most once per tab.
19
+ * app ugly.bot/oauth/silent?origin&redirect back to the app with either
20
+ * `?ugly_oauth_code=CODE` (had a session; bootstrap redeems it) or
21
+ * `?ugly_sso=none` (no session; render logged-out).
22
+ *
23
+ * A top-level redirect (not the old AutoLoginGate iframe) is required because
24
+ * ugly.bot's cookie is SameSite=Lax — it isn't sent on cross-site iframe
25
+ * requests, and third-party cookies are widely blocked. Runs at most once per
26
+ * tab (sessionStorage guard) so logged-out visitors bounce only once.
27
+ *
28
+ * Returns true if it kicked off a redirect (caller should render nothing and
29
+ * return); false if it was a no-op (already tried — render normally).
25
30
  */
26
- export declare function attemptSilentSso(): void;
31
+ export declare function attemptSilentSso(): boolean;
32
+ /** Mark silent SSO as already attempted (so it won't redirect again this tab). */
33
+ export declare function markSilentSsoTried(): void;
27
34
  /**
28
35
  * Best-effort check for an existing session (not a validity guarantee). The
29
36
  * `auth_token` cookie is HttpOnly — invisible to `document.cookie` — so the
@@ -1 +1 @@
1
- {"version":3,"file":"startLogin.d.ts","sourceRoot":"","sources":["../../../src/client/auth/startLogin.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,iBAAsB,GAAG,IAAI,CAmCpE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAyDvC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAO1C"}
1
+ {"version":3,"file":"startLogin.d.ts","sourceRoot":"","sources":["../../../src/client/auth/startLogin.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,iBAAsB,GAAG,IAAI,CAmCpE;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAc1C;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,IAAI,IAAI,CAMzC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAO1C"}
@@ -53,81 +53,48 @@ export function startUglyBotLogin(opts = {}) {
53
53
  };
54
54
  window.addEventListener('message', handler);
55
55
  }
56
+ const SILENT_SSO_TRIED_KEY = 'uglySilentSsoTried';
56
57
  /**
57
- * Non-blocking silent SSO for apex-domain apps (ugly.chat, ugly.press, …) that
58
- * don't share ugly.bot's `auth_token` cookie. Renders nothing and blocks
59
- * nothing: it drops a hidden iframe pointed at ugly.bot's `/oauth/silent`, which
60
- * — if the visitor already has a ugly.bot session — posts back a one-time code
61
- * we redeem via `/auth/verify`, then reloads (so the server re-renders
62
- * authenticated). If the visitor isn't logged into ugly.bot (or it times out),
63
- * the iframe is removed and the page stays as it rendered.
58
+ * Silent SSO for apex-domain apps (ugly.chat, ugly.press, …) that don't share
59
+ * ugly.bot's `auth_token` cookie. Adopts an existing ugly.bot session with NO
60
+ * user interaction via a top-level redirect to ugly.bot's `/oauth/silent`:
64
61
  *
65
- * Replaces the old AutoLoginGate, which blocked first paint ~4s on the handshake.
66
- * Call AFTER the app has rendered. Runs at most once per tab.
62
+ * app ugly.bot/oauth/silent?origin&redirect back to the app with either
63
+ * `?ugly_oauth_code=CODE` (had a session; bootstrap redeems it) or
64
+ * `?ugly_sso=none` (no session; render logged-out).
65
+ *
66
+ * A top-level redirect (not the old AutoLoginGate iframe) is required because
67
+ * ugly.bot's cookie is SameSite=Lax — it isn't sent on cross-site iframe
68
+ * requests, and third-party cookies are widely blocked. Runs at most once per
69
+ * tab (sessionStorage guard) so logged-out visitors bounce only once.
70
+ *
71
+ * Returns true if it kicked off a redirect (caller should render nothing and
72
+ * return); false if it was a no-op (already tried — render normally).
67
73
  */
68
74
  export function attemptSilentSso() {
69
- if (typeof window === 'undefined' || typeof document === 'undefined')
70
- return;
75
+ if (typeof window === 'undefined')
76
+ return false;
71
77
  try {
72
- if (sessionStorage.getItem('uglySilentSsoTried'))
73
- return;
74
- sessionStorage.setItem('uglySilentSsoTried', '1');
78
+ if (sessionStorage.getItem(SILENT_SSO_TRIED_KEY))
79
+ return false;
80
+ sessionStorage.setItem(SILENT_SSO_TRIED_KEY, '1');
75
81
  }
76
82
  catch {
77
- /* private mode proceed without the once-per-tab guard */
83
+ return false; // no sessionStorage can't guard against loops; don't risk it
84
+ }
85
+ const origin = encodeURIComponent(window.location.origin);
86
+ const ret = encodeURIComponent(window.location.pathname + window.location.search + window.location.hash);
87
+ window.location.replace(`${UGLY_BOT_URL}/oauth/silent?origin=${origin}&redirect=1&return=${ret}`);
88
+ return true;
89
+ }
90
+ /** Mark silent SSO as already attempted (so it won't redirect again this tab). */
91
+ export function markSilentSsoTried() {
92
+ try {
93
+ sessionStorage.setItem(SILENT_SSO_TRIED_KEY, '1');
94
+ }
95
+ catch {
96
+ /* ignore */
78
97
  }
79
- const origin = window.location.origin;
80
- const iframe = document.createElement('iframe');
81
- iframe.setAttribute('aria-hidden', 'true');
82
- iframe.title = 'auth-check';
83
- iframe.style.cssText =
84
- 'position:absolute;width:0;height:0;border:0;visibility:hidden;pointer-events:none';
85
- iframe.src = `${UGLY_BOT_URL}/oauth/silent?origin=${encodeURIComponent(origin)}`;
86
- let settled = false;
87
- let timer = 0;
88
- const cleanup = () => {
89
- window.removeEventListener('message', handler);
90
- if (timer)
91
- window.clearTimeout(timer);
92
- iframe.remove();
93
- };
94
- const handler = (event) => {
95
- if (event.origin !== UGLY_BOT_URL)
96
- return;
97
- const data = event.data;
98
- if (data?.type !== 'ugly-bot-oauth-silent')
99
- return;
100
- if (settled)
101
- return;
102
- settled = true;
103
- if (!data.code) {
104
- cleanup(); // not logged into ugly.bot — stay as rendered
105
- return;
106
- }
107
- void (async () => {
108
- try {
109
- const res = await fetch('/auth/verify', {
110
- method: 'POST',
111
- headers: { 'Content-Type': 'application/json' },
112
- body: JSON.stringify({ code: data.code }),
113
- });
114
- cleanup();
115
- if (res.ok)
116
- window.location.reload();
117
- }
118
- catch {
119
- cleanup();
120
- }
121
- })();
122
- };
123
- window.addEventListener('message', handler);
124
- timer = window.setTimeout(() => {
125
- if (!settled) {
126
- settled = true;
127
- cleanup();
128
- }
129
- }, 6000);
130
- document.body.appendChild(iframe);
131
98
  }
132
99
  /**
133
100
  * Best-effort check for an existing session (not a validity guarantee). The
@@ -1 +1 @@
1
- {"version":3,"file":"startLogin.js","sourceRoot":"","sources":["../../../src/client/auth/startLogin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"startLogin.js","sourceRoot":"","sources":["../../../src/client/auth/startLogin.ts"],"names":[],"mappings":"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"}
@@ -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;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA8I/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;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA+J/D"}
@@ -5,7 +5,7 @@ import { frameworkRequests } from '../shared/FrameworkRequests.js';
5
5
  import { initAppApi } from './AppApi.js';
6
6
  import { AppProvider } from './AppProvider.js';
7
7
  import { MagicLinkCallback } from './auth/MagicLinkCallback.js';
8
- import { attemptSilentSso } from './auth/startLogin.js';
8
+ import { attemptSilentSso, markSilentSsoTried } from './auth/startLogin.js';
9
9
  import { KeyboardProvider } from './components/KeyboardProvider.js';
10
10
  import { createSocket } from './createSocket.js';
11
11
  import { installInspect } from './inspect/index.js';
@@ -38,6 +38,7 @@ export function bootstrapApp(options) {
38
38
  const params = new URLSearchParams(window.location.search);
39
39
  const oauthCode = params.get('ugly_oauth_code');
40
40
  if (oauthCode) {
41
+ markSilentSsoTried(); // don't re-bounce if this redemption fails
41
42
  void (async () => {
42
43
  try {
43
44
  await fetch('/auth/verify', {
@@ -59,6 +60,14 @@ export function bootstrapApp(options) {
59
60
  root.render(_jsx(_Fragment, {}));
60
61
  return;
61
62
  }
63
+ // Silent-SSO returned with no ugly.bot session — mark it tried (so we don't
64
+ // bounce again) and strip the marker. Falls through to render logged-out.
65
+ if (params.get('ugly_sso') === 'none') {
66
+ markSilentSsoTried();
67
+ params.delete('ugly_sso');
68
+ const qs = params.toString();
69
+ window.history.replaceState(null, '', window.location.pathname + (qs ? `?${qs}` : '') + window.location.hash);
70
+ }
62
71
  }
63
72
  installUglyStudioPreviewBridge();
64
73
  installInspect();
@@ -79,11 +88,14 @@ export function bootstrapApp(options) {
79
88
  : withStrings);
80
89
  }
81
90
  if (!token) {
91
+ // Apex apps: try to adopt an existing ugly.bot session via a one-time
92
+ // top-level redirect BEFORE rendering, so logged-in visitors don't flash the
93
+ // logged-out UI. If it didn't redirect (already tried this tab), render now.
94
+ if (options.silentSso && attemptSilentSso()) {
95
+ root.render(_jsx(_Fragment, {}));
96
+ return;
97
+ }
82
98
  renderWithRouter(false, renderApp());
83
- // Apex apps: try to adopt an existing ugly.bot session in the background
84
- // (non-blocking — the app has already rendered).
85
- if (options.silentSso)
86
- attemptSilentSso();
87
99
  return;
88
100
  }
89
101
  const userId = (JSON.parse(atob(token.split('.')[1]))).sub;
@@ -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,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,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,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,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;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,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACrC,yEAAyE;QACzE,iDAAiD;QACjD,IAAI,OAAO,CAAC,SAAS;YAAE,gBAAgB,EAAE,CAAC;QAC1C,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,MAAM;SACH,OAAO,CAAC,KAAK,CAAC;SACd,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,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;IACJ,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"}
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.590",
3
+ "version": "0.1.591",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.590";
2
+ export const CLI_VERSION = "0.1.591";
@@ -63,75 +63,48 @@ export function startUglyBotLogin(opts: StartLoginOptions = {}): void {
63
63
  window.addEventListener('message', handler);
64
64
  }
65
65
 
66
+ const SILENT_SSO_TRIED_KEY = 'uglySilentSsoTried';
67
+
66
68
  /**
67
- * Non-blocking silent SSO for apex-domain apps (ugly.chat, ugly.press, …) that
68
- * don't share ugly.bot's `auth_token` cookie. Renders nothing and blocks
69
- * nothing: it drops a hidden iframe pointed at ugly.bot's `/oauth/silent`, which
70
- * — if the visitor already has a ugly.bot session — posts back a one-time code
71
- * we redeem via `/auth/verify`, then reloads (so the server re-renders
72
- * authenticated). If the visitor isn't logged into ugly.bot (or it times out),
73
- * the iframe is removed and the page stays as it rendered.
69
+ * Silent SSO for apex-domain apps (ugly.chat, ugly.press, …) that don't share
70
+ * ugly.bot's `auth_token` cookie. Adopts an existing ugly.bot session with NO
71
+ * user interaction via a top-level redirect to ugly.bot's `/oauth/silent`:
72
+ *
73
+ * app ugly.bot/oauth/silent?origin&redirect back to the app with either
74
+ * `?ugly_oauth_code=CODE` (had a session; bootstrap redeems it) or
75
+ * `?ugly_sso=none` (no session; render logged-out).
76
+ *
77
+ * A top-level redirect (not the old AutoLoginGate iframe) is required because
78
+ * ugly.bot's cookie is SameSite=Lax — it isn't sent on cross-site iframe
79
+ * requests, and third-party cookies are widely blocked. Runs at most once per
80
+ * tab (sessionStorage guard) so logged-out visitors bounce only once.
74
81
  *
75
- * Replaces the old AutoLoginGate, which blocked first paint ~4s on the handshake.
76
- * Call AFTER the app has rendered. Runs at most once per tab.
82
+ * Returns true if it kicked off a redirect (caller should render nothing and
83
+ * return); false if it was a no-op (already tried render normally).
77
84
  */
78
- export function attemptSilentSso(): void {
79
- if (typeof window === 'undefined' || typeof document === 'undefined') return;
85
+ export function attemptSilentSso(): boolean {
86
+ if (typeof window === 'undefined') return false;
80
87
  try {
81
- if (sessionStorage.getItem('uglySilentSsoTried')) return;
82
- sessionStorage.setItem('uglySilentSsoTried', '1');
88
+ if (sessionStorage.getItem(SILENT_SSO_TRIED_KEY)) return false;
89
+ sessionStorage.setItem(SILENT_SSO_TRIED_KEY, '1');
83
90
  } catch {
84
- /* private mode proceed without the once-per-tab guard */
91
+ return false; // no sessionStorage can't guard against loops; don't risk it
85
92
  }
93
+ const origin = encodeURIComponent(window.location.origin);
94
+ const ret = encodeURIComponent(
95
+ window.location.pathname + window.location.search + window.location.hash,
96
+ );
97
+ window.location.replace(`${UGLY_BOT_URL}/oauth/silent?origin=${origin}&redirect=1&return=${ret}`);
98
+ return true;
99
+ }
86
100
 
87
- const origin = window.location.origin;
88
- const iframe = document.createElement('iframe');
89
- iframe.setAttribute('aria-hidden', 'true');
90
- iframe.title = 'auth-check';
91
- iframe.style.cssText =
92
- 'position:absolute;width:0;height:0;border:0;visibility:hidden;pointer-events:none';
93
- iframe.src = `${UGLY_BOT_URL}/oauth/silent?origin=${encodeURIComponent(origin)}`;
94
-
95
- let settled = false;
96
- let timer = 0;
97
- const cleanup = (): void => {
98
- window.removeEventListener('message', handler);
99
- if (timer) window.clearTimeout(timer);
100
- iframe.remove();
101
- };
102
- const handler = (event: MessageEvent): void => {
103
- if (event.origin !== UGLY_BOT_URL) return;
104
- const data = event.data as { type?: string; code?: string | null } | null;
105
- if (data?.type !== 'ugly-bot-oauth-silent') return;
106
- if (settled) return;
107
- settled = true;
108
- if (!data.code) {
109
- cleanup(); // not logged into ugly.bot — stay as rendered
110
- return;
111
- }
112
- void (async () => {
113
- try {
114
- const res = await fetch('/auth/verify', {
115
- method: 'POST',
116
- headers: { 'Content-Type': 'application/json' },
117
- body: JSON.stringify({ code: data.code }),
118
- });
119
- cleanup();
120
- if (res.ok) window.location.reload();
121
- } catch {
122
- cleanup();
123
- }
124
- })();
125
- };
126
-
127
- window.addEventListener('message', handler);
128
- timer = window.setTimeout(() => {
129
- if (!settled) {
130
- settled = true;
131
- cleanup();
132
- }
133
- }, 6000);
134
- document.body.appendChild(iframe);
101
+ /** Mark silent SSO as already attempted (so it won't redirect again this tab). */
102
+ export function markSilentSsoTried(): void {
103
+ try {
104
+ sessionStorage.setItem(SILENT_SSO_TRIED_KEY, '1');
105
+ } catch {
106
+ /* ignore */
107
+ }
135
108
  }
136
109
 
137
110
  /**
@@ -6,7 +6,7 @@ import { frameworkRequests } from '../shared/FrameworkRequests.js';
6
6
  import { initAppApi } from './AppApi.js';
7
7
  import { AppProvider } from './AppProvider.js';
8
8
  import { MagicLinkCallback } from './auth/MagicLinkCallback.js';
9
- import { attemptSilentSso } from './auth/startLogin.js';
9
+ import { attemptSilentSso, markSilentSsoTried } from './auth/startLogin.js';
10
10
  import { KeyboardProvider } from './components/KeyboardProvider.js';
11
11
  import { createSocket } from './createSocket.js';
12
12
  import { installInspect } from './inspect/index.js';
@@ -97,6 +97,7 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
97
97
  const params = new URLSearchParams(window.location.search);
98
98
  const oauthCode = params.get('ugly_oauth_code');
99
99
  if (oauthCode) {
100
+ markSilentSsoTried(); // don't re-bounce if this redemption fails
100
101
  void (async () => {
101
102
  try {
102
103
  await fetch('/auth/verify', {
@@ -119,6 +120,18 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
119
120
  root.render(<></>);
120
121
  return;
121
122
  }
123
+ // Silent-SSO returned with no ugly.bot session — mark it tried (so we don't
124
+ // bounce again) and strip the marker. Falls through to render logged-out.
125
+ if (params.get('ugly_sso') === 'none') {
126
+ markSilentSsoTried();
127
+ params.delete('ugly_sso');
128
+ const qs = params.toString();
129
+ window.history.replaceState(
130
+ null,
131
+ '',
132
+ window.location.pathname + (qs ? `?${qs}` : '') + window.location.hash,
133
+ );
134
+ }
122
135
  }
123
136
 
124
137
  installUglyStudioPreviewBridge();
@@ -158,10 +171,14 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
158
171
  }
159
172
 
160
173
  if (!token) {
174
+ // Apex apps: try to adopt an existing ugly.bot session via a one-time
175
+ // top-level redirect BEFORE rendering, so logged-in visitors don't flash the
176
+ // logged-out UI. If it didn't redirect (already tried this tab), render now.
177
+ if (options.silentSso && attemptSilentSso()) {
178
+ root.render(<></>);
179
+ return;
180
+ }
161
181
  renderWithRouter(false, renderApp());
162
- // Apex apps: try to adopt an existing ugly.bot session in the background
163
- // (non-blocking — the app has already rendered).
164
- if (options.silentSso) attemptSilentSso();
165
182
  return;
166
183
  }
167
184