@helloleo/plugins 0.2.22 → 0.2.24

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/index.js CHANGED
@@ -25857,6 +25857,9 @@ export async function netsuiteFetch(sid: string, path: string, init: RequestInit
25857
25857
  const headers = new Headers(init.headers)
25858
25858
  headers.set('Authorization', \`Bearer \${session.accessToken}\`)
25859
25859
  if (init.body && !headers.has('Content-Type')) headers.set('Content-Type', 'application/json')
25860
+ // NetSuite's suiteql endpoint requires Prefer: transient (400s without it on
25861
+ // some accounts). Set centrally so no call site can forget it.
25862
+ if (url.includes('/suiteql') && !headers.has('Prefer')) headers.set('Prefer', 'transient')
25860
25863
  return fetch(url, { ...init, headers })
25861
25864
  }
25862
25865
  `;
@@ -25966,6 +25969,21 @@ export const Route = createFileRoute('/auth/netsuite/callback')({
25966
25969
  })
25967
25970
 
25968
25971
  const dest = new URL(flow.returnTo)
25972
+
25973
+ // Popup flow: signInWithNetSuite appended popup=1 to return_to. Hand
25974
+ // the sid back to the opener via postMessage and close -- the preview
25975
+ // iframe never navigates. Target the app's own origin, never '*'.
25976
+ if (dest.searchParams.get('popup') === '1') {
25977
+ dest.searchParams.delete('popup')
25978
+ const html = \`<!DOCTYPE html><html><body><p>Signed in. You can close this window.</p><script>
25979
+ (function(){
25980
+ try{window.opener && window.opener.postMessage({type:'netsuite_auth',sid:\${JSON.stringify(sid)}},\${JSON.stringify(dest.origin)});}catch(e){}
25981
+ window.close();
25982
+ })();
25983
+ <\\/script></body></html>\`
25984
+ return new Response(html, { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } })
25985
+ }
25986
+
25969
25987
  dest.hash = \`nssid=\${sid}\`
25970
25988
  return new Response(null, { status: 302, headers: { Location: dest.toString() } })
25971
25989
  },
@@ -26088,23 +26106,58 @@ export function getSessionToken(): string | null {
26088
26106
  }
26089
26107
 
26090
26108
  export function signInWithNetSuite(returnTo: string = window.location.href) {
26091
- const url = new URL('/auth/netsuite/start', window.location.origin)
26092
- url.searchParams.set('return_to', returnTo)
26093
- // The app renders inside the HelloLeo preview iframe; /start 302s to
26094
- // NetSuite, whose OAuth page sends X-Frame-Options: DENY. Navigate the TOP
26095
- // frame so the flow runs at top level and the callback lands there to read
26096
- // #nssid=. Assign .href (NOT .assign(): reading .assign off a cross-origin
26097
- // window.top.location throws, dropping us into the iframe fallback ->
26098
- // "refused to connect").
26109
+ const startUrl = new URL('/auth/netsuite/start', window.location.origin)
26110
+
26111
+ // Open OAuth in a POPUP -- not the iframe (NetSuite's OAuth page sends
26112
+ // X-Frame-Options: DENY and can never render there), and not the top frame
26113
+ // (that kicks the whole HelloLeo preview out to the raw app and strands the
26114
+ // session in a different browsing context). The callback sees popup=1 on
26115
+ // return_to and postMessages the sid back to this exact window.
26116
+ const popupReturnTo = new URL(returnTo)
26117
+ popupReturnTo.searchParams.set('popup', '1')
26118
+ startUrl.searchParams.set('return_to', popupReturnTo.toString())
26119
+
26120
+ const width = 600
26121
+ const height = 760
26122
+ const left = Math.max(0, Math.round(window.screenX + (window.outerWidth - width) / 2))
26123
+ const top = Math.max(0, Math.round(window.screenY + (window.outerHeight - height) / 2))
26124
+ const popup = window.open(
26125
+ startUrl.toString(),
26126
+ 'netsuite_oauth',
26127
+ \`width=\${width},height=\${height},left=\${left},top=\${top},toolbar=0,menubar=0,location=1,status=0,scrollbars=1,resizable=1\`,
26128
+ )
26129
+
26130
+ if (popup && !popup.closed) {
26131
+ const onMessage = (ev: MessageEvent) => {
26132
+ if (ev.origin !== window.location.origin) return
26133
+ const data = ev.data as { type?: string; sid?: string } | null
26134
+ if (!data || data.type !== 'netsuite_auth' || !data.sid) return
26135
+ window.removeEventListener('message', onMessage)
26136
+ try {
26137
+ sessionStorage.setItem(TOKEN_KEY, data.sid)
26138
+ } catch {}
26139
+ // Re-render as signed-in -- the auth provider re-checks /api/me on load.
26140
+ window.location.reload()
26141
+ }
26142
+ window.addEventListener('message', onMessage)
26143
+ return
26144
+ }
26145
+
26146
+ // Popup blocked -> previous behavior: navigate the top frame (or same frame)
26147
+ // with a CLEAN return_to (no popup flag) so the callback uses the #nssid=
26148
+ // redirect. Assign .href (NOT .assign(): reading .assign off a cross-origin
26149
+ // window.top.location throws, dropping us into the same-frame fallback).
26150
+ const fallbackUrl = new URL('/auth/netsuite/start', window.location.origin)
26151
+ fallbackUrl.searchParams.set('return_to', returnTo)
26099
26152
  try {
26100
26153
  if (window.top && window.top !== window) {
26101
- window.top.location.href = url.toString()
26154
+ window.top.location.href = fallbackUrl.toString()
26102
26155
  return
26103
26156
  }
26104
26157
  } catch {
26105
26158
  /* top window unreachable -- fall through to same-frame navigation */
26106
26159
  }
26107
- window.location.href = url.toString()
26160
+ window.location.href = fallbackUrl.toString()
26108
26161
  }
26109
26162
 
26110
26163
  export interface NetSuiteSession {
@@ -0,0 +1,5 @@
1
+ # Supply-chain guard: refuse npm package versions published less than 3 days
2
+ # ago (compromised-release window). Versions already in bun.lock install
3
+ # normally. Escape hatch: minimumReleaseAgeExcludes = ["pkg"].
4
+ [install]
5
+ minimumReleaseAge = 259200
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helloleo/plugins",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "description": "OpenCode plugins for HelloLeo",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",