🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@kolbo/app-sdk

Package Overview
Dependencies
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kolbo/app-sdk - npm Package Compare versions

Comparing version
2.0.15
to
2.0.16
+1
-1
package.json
{
"name": "@kolbo/app-sdk",
"version": "2.0.15",
"version": "2.0.16",
"description": "Kolbo App Builder SDK — auth, data, storage and AI for generated apps",

@@ -5,0 +5,0 @@ "type": "module",

@@ -240,10 +240,23 @@ // Kolbo-native adapter.

if (inPopup) {
// Three-channel handoff so at least one reaches the opener even
// if the browser severs window.opener across cross-origin hops
// (COOP) or suppresses storage events on tab-close.
try { window.opener.postMessage({ type: '__kolbo_oauth_done__', ok: true }, '*'); } catch (_) {}
// Three-channel handoff so at least one reaches the opener. The
// tokens themselves are sent inline because popup and opener are
// often on DIFFERENT origins (popup = snapshot host media-dev,
// opener = p-preview proxy on the backend origin). localStorage
// is per-origin, so the opener CANNOT read the session we just
// wrote in the popup — postMessage is the only cross-origin
// transport that carries the tokens through.
const payload = {
type: '__kolbo_oauth_done__',
ok: true,
session: {
access_token: session.access_token,
refresh_token: session.refresh_token,
expires_at: session.expires_at,
},
};
try { window.opener.postMessage(payload, '*'); } catch (_) {}
try {
if (typeof BroadcastChannel === 'function') {
const ch = new BroadcastChannel(`kolbo-oauth:${this._appId || ''}`);
ch.postMessage({ type: '__kolbo_oauth_done__', ok: true });
ch.postMessage(payload);
// Close channel on next tick so the message actually ships.

@@ -253,5 +266,5 @@ setTimeout(() => { try { ch.close(); } catch (_) {} }, 50);

} catch (_) {}
// Give the opener a tick to read all three channels (postMessage,
// storage event from _writeStored above, BroadcastChannel).
setTimeout(() => { try { window.close(); } catch (_) {} }, 120);
// Give the opener a tick to consume the message + write its own
// localStorage (postMessage delivery is microtask-scheduled).
setTimeout(() => { try { window.close(); } catch (_) {} }, 150);
}

@@ -670,7 +683,22 @@ } else if (hashError && inPopup) {

// Popup auto-wrote the session to our scoped localStorage key
// before posting. Hydrate user via /me if missing BEFORE firing
// SIGNED_IN — otherwise React subscribers see user=null and
// AuthGuard redirects to /login.
// Cross-origin case: popup sent its tokens inline because our
// localStorage is isolated from the popup's. Write them into our
// OWN scoped storage key first — otherwise hydrate reads back
// the pre-existing admin/empty session and the user is stranded
// on /login even though Google sign-in succeeded.
try {
if (event.data.ok && event.data.session && event.data.session.access_token) {
_writeStored(self._storageKey, {
access_token: event.data.session.access_token,
refresh_token: event.data.session.refresh_token || null,
expires_at: event.data.session.expires_at || null,
user: null, // hydrated via /me next
});
}
} catch (_) { /* non-fatal */ }
// Hydrate user via /me if missing BEFORE firing SIGNED_IN —
// otherwise React subscribers see user=null and AuthGuard
// redirects to /login.
try {
if (event.data.ok) {

@@ -716,2 +744,19 @@ await self._hydrateAndDispatchSignIn();

if (ev.data.ok) {
// Write tokens carried in the message payload into our own
// scoped localStorage — needed when popup + opener are on
// different origins and localStorage/storage-events can't
// bridge the gap. BroadcastChannel itself is same-origin
// so this path only fires when both share an origin, but
// keeping the write here guards against future changes
// to the popup's origin.
try {
if (ev.data.session && ev.data.session.access_token) {
_writeStored(self._storageKey, {
access_token: ev.data.session.access_token,
refresh_token: ev.data.session.refresh_token || null,
expires_at: ev.data.session.expires_at || null,
user: null,
});
}
} catch (_) { /* non-fatal */ }
const hydrated = await self._hydrateAndDispatchSignIn();

@@ -718,0 +763,0 @@ done({ data: { user: hydrated?.user || null }, error: null });