ugly-app 0.1.616 → 0.1.617

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.617";
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.617";
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;AAyHD,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA2L/D"}
@@ -15,21 +15,89 @@ 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.
24
- *
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.
18
+ * True when this app shares ugly.bot's session cookie i.e. it's served from
19
+ * `ugly.bot` or a `*.ugly.bot` subdomain. Same-site means SameSite=Lax sends the
20
+ * cookie even on a hidden iframe subresource, so the silent-auth iframe below can
21
+ * read the live session. Cross-site apex apps (ugly.chat, andalib.net) don't get
22
+ * the cookie in an iframe and must use the top-level redirect SSO instead.
29
23
  */
30
- function reconcileUglyBotSession(uglyBotUrl, sessionUserId) {
24
+ function sharesUglyBotCookie(uglyBotUrl) {
25
+ if (typeof window === 'undefined')
26
+ return false;
27
+ try {
28
+ const botHost = new URL(uglyBotUrl).hostname;
29
+ const here = window.location.hostname;
30
+ return here === botHost || here.endsWith(`.${botHost}`);
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ /**
37
+ * Load ugly.bot's silent-auth endpoint in a hidden iframe and resolve with the
38
+ * one-time code it postMessages back (or null if there's no ugly.bot session, or
39
+ * on timeout). This is the SAME mechanism as auto-login — a same-site iframe that
40
+ * reads the live ugly.bot cookie — repurposed here so it ALSO serves as the
41
+ * keep-the-token-fresh / account-sync check on every boot.
42
+ */
43
+ function silentAuthViaIframe(uglyBotUrl) {
44
+ return new Promise((resolve) => {
45
+ if (typeof document === 'undefined') {
46
+ resolve(null);
47
+ return;
48
+ }
49
+ const origin = window.location.origin;
50
+ let botOrigin;
51
+ try {
52
+ botOrigin = new URL(uglyBotUrl).origin;
53
+ }
54
+ catch {
55
+ resolve(null);
56
+ return;
57
+ }
58
+ const src = `${botOrigin}/oauth/silent?origin=${encodeURIComponent(origin)}&mode=iframe`;
59
+ const iframe = document.createElement('iframe');
60
+ iframe.style.display = 'none';
61
+ iframe.setAttribute('aria-hidden', 'true');
62
+ iframe.setAttribute('tabindex', '-1');
63
+ let settled = false;
64
+ const finish = (code) => {
65
+ if (settled)
66
+ return;
67
+ settled = true;
68
+ window.removeEventListener('message', onMessage);
69
+ clearTimeout(timer);
70
+ iframe.remove();
71
+ resolve(code);
72
+ };
73
+ const onMessage = (e) => {
74
+ if (e.origin !== botOrigin)
75
+ return;
76
+ const data = e.data;
77
+ if (data && data.type === 'ugly-bot-silent-auth') {
78
+ finish(typeof data.code === 'string' ? data.code : null);
79
+ }
80
+ };
81
+ window.addEventListener('message', onMessage);
82
+ const timer = setTimeout(() => finish(null), 6000);
83
+ iframe.src = src;
84
+ document.body.appendChild(iframe);
85
+ });
86
+ }
87
+ /**
88
+ * Boot-time silent auth + account-sync via the iframe above. One mechanism, three
89
+ * jobs: (1) logged-out → auto-login if a ugly.bot session exists; (2) logged-in,
90
+ * same account → redeem a fresh code so the session cookie/token stays valid;
91
+ * (3) logged-in, DIFFERENT ugly.bot account → reload onto the live account (the
92
+ * child's old JWT never auto-revokes, so without this it would keep acting as the
93
+ * stale account). `sessionUserId` is the current session's user (null if logged
94
+ * out). Guarded once-per-tab so the reload can't loop.
95
+ */
96
+ function silentAuthSync(uglyBotUrl, sessionUserId) {
31
97
  if (typeof window === 'undefined')
32
98
  return;
99
+ if (!sharesUglyBotCookie(uglyBotUrl))
100
+ return; // apex apps use redirect SSO
33
101
  try {
34
102
  if (sessionStorage.getItem(RECONCILE_TRIED_KEY))
35
103
  return;
@@ -39,22 +107,31 @@ function reconcileUglyBotSession(uglyBotUrl, sessionUserId) {
39
107
  return;
40
108
  }
41
109
  void (async () => {
110
+ const code = await silentAuthViaIframe(uglyBotUrl).catch(() => null);
111
+ // No code → no reachable ugly.bot session (logged out there too). Leave the
112
+ // current state as-is.
113
+ if (!code)
114
+ return;
42
115
  try {
43
- const res = await fetch(`${uglyBotUrl}/oauth/me`, { credentials: 'include' });
116
+ const res = await fetch('/auth/verify', {
117
+ method: 'POST',
118
+ headers: { 'Content-Type': 'application/json' },
119
+ body: JSON.stringify({ code }),
120
+ });
44
121
  if (!res.ok)
45
122
  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)
123
+ const { token } = (await res.json());
124
+ if (!token)
51
125
  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())
126
+ const liveUserId = JSON.parse(atob(token.split('.')[1])).sub ?? null;
127
+ // Same account → the cookie was just refreshed; nothing visible to do.
128
+ // Different account (or we were logged out) → reload to adopt the live
129
+ // session the server now holds. Clear the once-per-tab silent-SSO guard so
130
+ // the reloaded page doesn't suppress its own SSO.
131
+ if (liveUserId && liveUserId !== sessionUserId) {
132
+ clearSilentSsoTried();
57
133
  window.location.reload();
134
+ }
58
135
  }
59
136
  catch {
60
137
  /* network hiccup — leave the session as-is */
@@ -144,6 +221,10 @@ export function bootstrapApp(options) {
144
221
  return;
145
222
  }
146
223
  renderWithRouter(false, renderApp());
224
+ // Subdomain apps (share the cookie): silently adopt an existing ugly.bot
225
+ // session via the hidden iframe — same mechanism as auto-login. Renders
226
+ // logged-out first, then reloads logged-in if a session is found.
227
+ silentAuthSync(uglyBotUrl, null);
147
228
  return;
148
229
  }
149
230
  const userId = (JSON.parse(atob(token.split('.')[1]))).sub;
@@ -188,9 +269,9 @@ export function bootstrapApp(options) {
188
269
  ? createUglyBotSocket(effectiveAppToken, uglyBotUrl)
189
270
  : null;
190
271
  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);
272
+ // Background: refresh the session token and make sure it still matches the
273
+ // live ugly.bot account; re-adopt the correct one if the user switched.
274
+ silentAuthSync(uglyBotUrl, userId);
194
275
  })
195
276
  .catch((err) => {
196
277
  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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.616",
3
+ "version": "0.1.617",
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.617";
@@ -61,20 +61,85 @@ 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.
70
- *
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.
64
+ * True when this app shares ugly.bot's session cookie i.e. it's served from
65
+ * `ugly.bot` or a `*.ugly.bot` subdomain. Same-site means SameSite=Lax sends the
66
+ * cookie even on a hidden iframe subresource, so the silent-auth iframe below can
67
+ * read the live session. Cross-site apex apps (ugly.chat, andalib.net) don't get
68
+ * the cookie in an iframe and must use the top-level redirect SSO instead.
75
69
  */
76
- function reconcileUglyBotSession(uglyBotUrl: string, sessionUserId: string): void {
70
+ function sharesUglyBotCookie(uglyBotUrl: string): boolean {
71
+ if (typeof window === 'undefined') return false;
72
+ try {
73
+ const botHost = new URL(uglyBotUrl).hostname;
74
+ const here = window.location.hostname;
75
+ return here === botHost || here.endsWith(`.${botHost}`);
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Load ugly.bot's silent-auth endpoint in a hidden iframe and resolve with the
83
+ * one-time code it postMessages back (or null if there's no ugly.bot session, or
84
+ * on timeout). This is the SAME mechanism as auto-login — a same-site iframe that
85
+ * reads the live ugly.bot cookie — repurposed here so it ALSO serves as the
86
+ * keep-the-token-fresh / account-sync check on every boot.
87
+ */
88
+ function silentAuthViaIframe(uglyBotUrl: string): Promise<string | null> {
89
+ return new Promise((resolve) => {
90
+ if (typeof document === 'undefined') {
91
+ resolve(null);
92
+ return;
93
+ }
94
+ const origin = window.location.origin;
95
+ let botOrigin: string;
96
+ try {
97
+ botOrigin = new URL(uglyBotUrl).origin;
98
+ } catch {
99
+ resolve(null);
100
+ return;
101
+ }
102
+ const src = `${botOrigin}/oauth/silent?origin=${encodeURIComponent(origin)}&mode=iframe`;
103
+ const iframe = document.createElement('iframe');
104
+ iframe.style.display = 'none';
105
+ iframe.setAttribute('aria-hidden', 'true');
106
+ iframe.setAttribute('tabindex', '-1');
107
+
108
+ let settled = false;
109
+ const finish = (code: string | null): void => {
110
+ if (settled) return;
111
+ settled = true;
112
+ window.removeEventListener('message', onMessage);
113
+ clearTimeout(timer);
114
+ iframe.remove();
115
+ resolve(code);
116
+ };
117
+ const onMessage = (e: MessageEvent): void => {
118
+ if (e.origin !== botOrigin) return;
119
+ const data = e.data as { type?: string; code?: string | null } | null;
120
+ if (data && data.type === 'ugly-bot-silent-auth') {
121
+ finish(typeof data.code === 'string' ? data.code : null);
122
+ }
123
+ };
124
+ window.addEventListener('message', onMessage);
125
+ const timer = setTimeout(() => finish(null), 6000);
126
+ iframe.src = src;
127
+ document.body.appendChild(iframe);
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Boot-time silent auth + account-sync via the iframe above. One mechanism, three
133
+ * jobs: (1) logged-out → auto-login if a ugly.bot session exists; (2) logged-in,
134
+ * same account → redeem a fresh code so the session cookie/token stays valid;
135
+ * (3) logged-in, DIFFERENT ugly.bot account → reload onto the live account (the
136
+ * child's old JWT never auto-revokes, so without this it would keep acting as the
137
+ * stale account). `sessionUserId` is the current session's user (null if logged
138
+ * out). Guarded once-per-tab so the reload can't loop.
139
+ */
140
+ function silentAuthSync(uglyBotUrl: string, sessionUserId: string | null): void {
77
141
  if (typeof window === 'undefined') return;
142
+ if (!sharesUglyBotCookie(uglyBotUrl)) return; // apex apps use redirect SSO
78
143
  try {
79
144
  if (sessionStorage.getItem(RECONCILE_TRIED_KEY)) return;
80
145
  sessionStorage.setItem(RECONCILE_TRIED_KEY, '1');
@@ -82,19 +147,28 @@ function reconcileUglyBotSession(uglyBotUrl: string, sessionUserId: string): voi
82
147
  return;
83
148
  }
84
149
  void (async () => {
150
+ const code = await silentAuthViaIframe(uglyBotUrl).catch(() => null);
151
+ // No code → no reachable ugly.bot session (logged out there too). Leave the
152
+ // current state as-is.
153
+ if (!code) return;
85
154
  try {
86
- const res = await fetch(`${uglyBotUrl}/oauth/me`, { credentials: 'include' });
155
+ const res = await fetch('/auth/verify', {
156
+ method: 'POST',
157
+ headers: { 'Content-Type': 'application/json' },
158
+ body: JSON.stringify({ code }),
159
+ });
87
160
  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();
161
+ const { token } = (await res.json()) as { token?: string };
162
+ if (!token) return;
163
+ const liveUserId = (JSON.parse(atob(token.split('.')[1])) as { sub?: string }).sub ?? null;
164
+ // Same account the cookie was just refreshed; nothing visible to do.
165
+ // Different account (or we were logged out) → reload to adopt the live
166
+ // session the server now holds. Clear the once-per-tab silent-SSO guard so
167
+ // the reloaded page doesn't suppress its own SSO.
168
+ if (liveUserId && liveUserId !== sessionUserId) {
169
+ clearSilentSsoTried();
170
+ window.location.reload();
171
+ }
98
172
  } catch {
99
173
  /* network hiccup — leave the session as-is */
100
174
  }
@@ -222,6 +296,10 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
222
296
  return;
223
297
  }
224
298
  renderWithRouter(false, renderApp());
299
+ // Subdomain apps (share the cookie): silently adopt an existing ugly.bot
300
+ // session via the hidden iframe — same mechanism as auto-login. Renders
301
+ // logged-out first, then reloads logged-in if a session is found.
302
+ silentAuthSync(uglyBotUrl, null);
225
303
  return;
226
304
  }
227
305
 
@@ -275,9 +353,9 @@ export function bootstrapApp(options: BootstrapAppOptions): void {
275
353
  {renderApp()}
276
354
  </AppProvider>,
277
355
  );
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);
356
+ // Background: refresh the session token and make sure it still matches the
357
+ // live ugly.bot account; re-adopt the correct one if the user switched.
358
+ silentAuthSync(uglyBotUrl, userId);
281
359
  })
282
360
  .catch((err: unknown) => {
283
361
  console.error('[bootstrapApp] socket.connect failed, clearing auth cookie:', err);