build: d73775f9-b787-4b17-921e-f13c97d46940
This commit is contained in:
+112
@@ -0,0 +1,112 @@
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { setupIonicReact } from '@ionic/react';
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import App from './App';
|
||||
|
||||
// ── Ionic initialisation ──────────────────────────────────────────────────────
|
||||
// ?mode=md|ios overrides (used by AppSuite preview); otherwise follow the platform.
|
||||
const _urlMode = new URLSearchParams(window.location.search).get('mode');
|
||||
const _platform = Capacitor.getPlatform(); // 'ios' | 'android' | 'web'
|
||||
setupIonicReact({
|
||||
mode: (_urlMode === 'md' ? 'md' : _urlMode === 'ios' ? 'ios' : _platform === 'android' ? 'md' : 'ios'),
|
||||
});
|
||||
|
||||
// Derive the studio parent origin dynamically so this works in both dev
|
||||
// (parent at localhost:3000) and production (parent at appcakes.qqura.com).
|
||||
const studioOrigin = (() => {
|
||||
try {
|
||||
if (document.referrer) return new URL(document.referrer).origin;
|
||||
} catch {}
|
||||
return 'http://localhost:3000';
|
||||
})();
|
||||
|
||||
// ── Safe area bridge ──────────────────────────────────────────────────────────
|
||||
// Priority: URL params (first load) → sessionStorage (HMR full-reloads) → postMessage.
|
||||
// Capacitor sets env() natively in compiled apps; these paths cover the browser preview.
|
||||
function _applyInsets(sat: string | null, sab: string | null) {
|
||||
if (sat) { document.documentElement.style.setProperty('--ion-safe-area-top', `${sat}px`); sessionStorage.setItem('__apsuite_sat', sat); }
|
||||
if (sab) { document.documentElement.style.setProperty('--ion-safe-area-bottom', `${sab}px`); sessionStorage.setItem('__apsuite_sab', sab); }
|
||||
}
|
||||
|
||||
const _sp = new URLSearchParams(window.location.search);
|
||||
_applyInsets(
|
||||
_sp.get('sat') ?? sessionStorage.getItem('__apsuite_sat'),
|
||||
_sp.get('sab') ?? sessionStorage.getItem('__apsuite_sab'),
|
||||
);
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
if (e.data?.type !== '__apsuite_insets') return;
|
||||
const { sat, sab } = e.data as { sat?: number; sab?: number };
|
||||
_applyInsets(sat != null ? String(sat) : null, sab != null ? String(sab) : null);
|
||||
});
|
||||
|
||||
// Re-apply after React Fast Refresh so insets survive soft HMR cycles.
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.on('vite:beforeUpdate', () => {
|
||||
const c = (window as any).Ionic?.config;
|
||||
if (c) c.animated = false;
|
||||
});
|
||||
import.meta.hot.on('vite:afterUpdate', () => {
|
||||
_applyInsets(sessionStorage.getItem('__apsuite_sat'), sessionStorage.getItem('__apsuite_sab'));
|
||||
const c = (window as any).Ionic?.config;
|
||||
if (c) c.animated = true;
|
||||
});
|
||||
}
|
||||
|
||||
// ── Session bridge ────────────────────────────────────────────────────────────
|
||||
// Post auth session to the AppSuite parent frame so the AI can test auth-protected
|
||||
// Edge Functions. Uses import.meta.glob so Vite never errors if supabase.ts is absent.
|
||||
(async () => {
|
||||
const mods = import.meta.glob('./supabase.ts', { eager: false });
|
||||
if ('./supabase.ts' in mods) {
|
||||
try {
|
||||
const { supabase } = await mods['./supabase.ts']() as { supabase: any };
|
||||
supabase.auth.onAuthStateChange((_event: unknown, session: any) => {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: '__apsuite_session',
|
||||
access_token: session?.access_token ?? null,
|
||||
email: session?.user?.email ?? null,
|
||||
},
|
||||
studioOrigin,
|
||||
);
|
||||
});
|
||||
} catch {
|
||||
// supabase client failed to initialise — session bridge unavailable
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// ── Runtime error reporting ───────────────────────────────────────────────────
|
||||
// Forward uncaught errors to the AppSuite dev server so the AI can read them.
|
||||
function reportError(message: string, stack?: string) {
|
||||
fetch(`${studioOrigin}/api/agent/runtime-error`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ message, stack }),
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
window.onerror = (_msg, _src, _line, _col, err) => {
|
||||
reportError(String(_msg), err?.stack);
|
||||
return false;
|
||||
};
|
||||
|
||||
window.addEventListener('unhandledrejection', (e) => {
|
||||
const err = e.reason as Error | undefined;
|
||||
reportError(err?.message ?? String(e.reason), err?.stack);
|
||||
});
|
||||
|
||||
// ── PWA Elements (Action Sheet, Camera, Toast etc. in browser preview) ────────
|
||||
import { defineCustomElements } from '@ionic/pwa-elements/loader';
|
||||
defineCustomElements(window);
|
||||
|
||||
// ── App bootstrap ─────────────────────────────────────────────────────────────
|
||||
const container = document.getElementById('root');
|
||||
const root = createRoot(container!);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
Reference in New Issue
Block a user