requireAuth() now redirects on user.error so SSR catches stale sessions
that the cookie-presence middleware can't see. New SessionExpirationGuard
(client) listens on useSession() and calls signIn("keycloak") when the
JWT carries RefreshAccessTokenError or RefreshTokenMissing. Without it,
a tab idle past the Keycloak SSO lifetime sat on a dead accessToken
until a downstream API 401'd, with no UI-level redirect.
Bumps to 0.4.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New `./chrome` entrypoint exporting `<AdminShell>` and the header
components (Search, SearchHistory, SearchOptions, Messages, BrowseApps,
HeaderCustomers, HeaderContacts, LogoutButton). Refactored from the
Chronos-style AdminShell that gscCRM was vendoring byte-for-byte —
header/footer/sidebar are now a single shared surface across apps.
Explicit props contract (no site-informations.json, no internal data
sources): `menus`, `apps`, `user`, `brand` are required; `features.*`
flags gate every section (search/browseApps/messages/notifications/
subbar*/pageHeader*/activityPanel/chat/footer); `slots.*` lets apps
inject content; `labels` overrides the next-intl "chrome" namespace.
Locale-aware navigation: chrome calls useLocale() and prepends
/{locale} to internal menu URLs, leaving externals (http(s)://…) and
the "#" sentinel alone. Breadcrumbs and the path-derived page title
strip the leading locale segment so they read "Contacts" not
"En › Contacts". Necessary for `localePrefix: 'always'` consumers like
gscCRM.
Phosphor 2.x icons: `normalizeIconClass` prepends the base `ph` class
(compound selectors `.ph.ph-house:before` require both). All hardcoded
`<i className="ph-…">` sites switched to `ph ph-…`.
`next-intl` and `next-auth` moved to peerDependencies (with devDep
copies for the kit's own typecheck/build). Consumers must symlink their
installed copies into the kit's node_modules at build time — otherwise
useTranslations()/useSession() bind to a separate React context and
next-intl throws Error(void 0) on render.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Curated re-exports from @limitless/ui through /forms, /data,
/feedback, /navigation, /utils sub-paths so apps stop importing
from the lower layer.
- /forms also re-exports the full @limitless/ui validation surface
(hooks, format/security/address validators, types).
- AppLayout is now a thin wrapper over @limitless/ui's <AppShell> —
same ShellConfig DTO, no duplicated chrome code.
- shell/types + shell/index re-export from @limitless/ui to keep one
canonical type and one shared context.
- auth middleware: loose NextRequestLike typing to avoid two-copies-
of-next conflict with the consumer's next.
- postbuild: rewrite ../images/ to ./images/ in copied CSS so refs
resolve in dist/styles/.
Widget family in /data is the intersection of limitless's two
Widget files (Widget.d.ts vs Widget/index.d.ts collision in dist);
upstream fix needed before exposing IconWidget/UserWidget/etc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gsc/web-kit v0.2.0. Three modules turn from stubs into the working
surface apps need to render a chrome-wrapped Next.js page with one
import per concern.
auth/server:
- createAuth({ keycloak: { clientId, clientSecret, issuer } }) factory
returns { handlers, signIn, signOut, auth, requireAuth, signInPath }.
Canonical SessionUser shape (id, keycloakId, tenantId, email,
displayName, givenName, familyName, roles, accessToken, idToken)
baked into the session callback. Apps drop their hand-rolled
src/auth.ts (~80 lines) for a 6-line factory call.
- requireAuth() — server-only. await it at the top of an RSC layout
or page; redirects to signInPath if no session.
auth/middleware:
- createAuthMiddleware({ publicRoutes? }) returns a Next.js middleware
that redirects unauth'd requests to /api/auth/signin/keycloak with
?callbackUrl=<original>. Bypasses /api/auth/*, /_next/*, /images/*,
favicon, robots.txt always.
auth (client):
- signInRedirect(callbackUrl?) — hard-nav from any client component.
shell/server:
- fetchShellConfig({ appKey, accessToken, apiUrl?, timeoutMs? }).
Server-only fetcher. 3s default timeout. Graceful fallback config
on any error — shell-api outages can't blank-screen a host app.
shell (client):
- <ShellProvider> + useShell() — read the resolved config from any
descendant of <AppLayout>.
layout:
- <AppLayout config currentPath translate onSignOut navbarExtras>.
Renders the chronos-style Bootstrap-Layout-3 chrome (navbar-static,
sidebar-light sidebar-main with collapse + persistence in
localStorage, navbar-footer). Wraps children with the kit's
ShellProvider so useShell() works.
devDep: @types/node for the server-side process.env read.
All 14 sub-exports still resolve under dist/. Phase 3 (data + forms)
and the gscCRM pilot cutover come next.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The kit. Drop into any GSC Next.js frontend; everything that's not
domain content lives here. Wraps @limitless/ui primitives with the
app-shaped patterns we keep reimplementing: layout, auth, data
display, forms, feedback, navigation.
Phase 1 ships the package skeleton:
- package.json with 14 sub-exports (./layout · ./auth · ./auth/server
· ./auth/middleware · ./shell · ./shell/server · ./data · ./forms ·
./feedback · ./navigation · ./api · ./utils + the root and ./css).
- Empty module stubs so the import map resolves while later phases
fill in real surface area.
- Canonical CSS bundle at @gsc/web-kit/css — all.min.css +
sidebar-overrides.css + the seven layout-3 background images,
copied from chronos and committed in one place so no app has to
ship the 1MB sidecar on its own anymore.
- tsc-based build + a postbuild script that mirrors @limitless/ui:
emits .js + .d.ts, copies styles/, rewrites bare ESM imports to
include .js extensions.
- Peer deps on next, react, react-dom, bootstrap.
- Hard deps on @limitless/ui (file: dep), next-auth, next-intl, zod.
Build verified: tsc emits, all 14 export paths resolve under dist/.
No functional code yet — Phase 2 lands AppLayout / createAuth /
fetchShellConfig and the gscCRM pilot cuts over.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>