@the-portland-company/shell 0.7.0 → 0.8.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 — 2026-07-02
4
+
5
+ ### Added (backward-compatible)
6
+
7
+ - **Host-driven auth for non-Supabase apps**: `ShellProviderProps.supabaseClient` is now optional, and a new optional `auth: ShellInjectedAuth` prop (`{ status, user, signOut }`, exported type) takes precedence over Supabase session tracking. This lets OIDC apps (e.g. the standalone Contacts app) mount the full Chakra chrome — `ShellProvider` → `ShellChrome` → `AppLayout` — with their own identity feeding `useShellAuth`/`UserMenu`. The host builds a Supabase-shaped `user.raw` (`id`/`email`/`user_metadata.full_name`) so chrome components render identically. With neither prop, auth resolves to `unauthenticated`. Existing `supabaseClient` consumers are unaffected.
8
+
9
+ ### Tests
10
+
11
+ - Injected auth: precedence over Supabase (no `getSession`/`onAuthStateChange`/`auth.signOut` calls), client-less mounting, neither-prop fallback (3 tests).
12
+
3
13
  ## 0.7.0 — 2026-07-01
4
14
 
5
15
  ### Added (native chrome — all backward-compatible)
package/dist/index.cjs CHANGED
@@ -1126,6 +1126,7 @@ function toShellUser(session) {
1126
1126
  function ShellProvider({
1127
1127
  children,
1128
1128
  supabaseClient,
1129
+ auth,
1129
1130
  currentApp,
1130
1131
  appRegistry,
1131
1132
  basename,
@@ -1139,6 +1140,11 @@ function ShellProvider({
1139
1140
  const [status, setStatus] = react$1.useState("loading");
1140
1141
  const [session, setSession] = react$1.useState(null);
1141
1142
  react$1.useEffect(() => {
1143
+ if (auth || !supabaseClient) {
1144
+ setSession(null);
1145
+ if (!auth) setStatus("unauthenticated");
1146
+ return;
1147
+ }
1142
1148
  let cancelled = false;
1143
1149
  supabaseClient.auth.getSession().then(({ data }) => {
1144
1150
  if (cancelled) return;
@@ -1153,18 +1159,27 @@ function ShellProvider({
1153
1159
  cancelled = true;
1154
1160
  sub.data.subscription.unsubscribe();
1155
1161
  };
1156
- }, [supabaseClient]);
1157
- const value = react$1.useMemo(
1158
- () => ({
1162
+ }, [supabaseClient, auth]);
1163
+ const value = react$1.useMemo(() => {
1164
+ if (auth) {
1165
+ return {
1166
+ status: auth.status,
1167
+ session: null,
1168
+ user: auth.user,
1169
+ signOut: async () => {
1170
+ await auth.signOut();
1171
+ }
1172
+ };
1173
+ }
1174
+ return {
1159
1175
  status,
1160
1176
  session,
1161
1177
  user: toShellUser(session),
1162
1178
  signOut: async () => {
1163
- await supabaseClient.auth.signOut();
1179
+ await supabaseClient?.auth.signOut();
1164
1180
  }
1165
- }),
1166
- [status, session, supabaseClient]
1167
- );
1181
+ };
1182
+ }, [auth, status, session, supabaseClient]);
1168
1183
  const meta = react$1.useMemo(
1169
1184
  () => ({
1170
1185
  currentApp,