@multiplatform.one/core
v7.31.0
Published
Core framework shell, provider composition, and layout factories for multiplatform.one
Readme
@multiplatform.one/core
App shell for multiplatform.one: provider composition (createApp), root
layout factories, and default screen layouts — so an app wires TanStack Query,
Keycloak, Frappe, Web3, and theming in one declaration.
Install
pnpm add @multiplatform.one/coreHeavy integrations (@multiplatform.one/keycloak, frappe, frappe-ui,
web3, @tanstack/react-query, one, tamagui, …) are peer dependencies
and lazy-loaded — install only the ones your app enables.
What it owns
createApp(config)— returns{ AppProvider, withApp, useAppConfig }; composes providers outermost → innermost: config → TanStack → Web3 → Keycloak → Frappe → custom providers → ThemecreateRootLayout(config)— platform-split root layout (web/native) with head, Sentry, and loader-data handlingcreateDefaultLayout(options)/createTanstackProvider— screen layout and query-client factories
What it must not do
- No screens and no UI catalog — this package is wiring, not widgets
- No direct Frappe/Keycloak/Web3 implementations — it composes the dedicated packages behind lazy provider boundaries
Usage
import { createApp } from "@multiplatform.one/core";
import { themeConfig } from "@package/config";
const { AppProvider } = createApp({
theme: themeConfig,
tanstack: true, // TanStack Query with defaults (devtools in dev)
keycloak: true, // read settings from env config
frappe: true,
});
export function App({ children }) {
return <AppProvider>{children}</AppProvider>;
}Pass true to a provider slot to read all settings from env config, or an
object (TanstackConfig, KeycloakConfig, FrappeConfig, Web3AppConfig)
to configure explicitly. Disabled slots add zero bundle weight.
Frappe catch-up and the live app
After a reconnect, focus or online, the Frappe provider catches up on what it
missed. The default, CDC, calls live.live.api.backfill, which exists only
when the bench carries the live Frappe app (apps/frappe/apps/live). A bench
without it answers 417 ("App live is not installed") on every catch-up.
Such a deployment sets FRAPPE_CATCH_UP_STRATEGY=snapshot in the web
container's environment. Catch-up then re-reads each mounted collection through
/api/resource and makes no live.* request, for signed-in users and visitors
alike. The key is public config, so the SSR document publishes it per request:
one image serves a bench with live and one without, no rebuild. Unset, or
cdc, keeps CDC. Snapshot mode also refuses progressive subscriptions, so a
screen built on useFrappeInfiniteList fails under it.
Writes (createDoc, updateDoc, deleteDoc, a FrappeForm save) call live
too. The same deployment sets FRAPPE_WRITE_STRATEGY=resource, and they go to
POST, PUT and DELETE /api/resource instead. Unset, or live, keeps the
live app. Resource writes carry no idempotency key; the @multiplatform.one/frappe
README lists what else differs.
An app can fix either choice in code instead, through frappe.syncOptions,
which createApp hands to FrappeProvider as is. A catchUpStrategy or
writeStrategy set there wins over the env.
createApp({ frappe: { syncOptions: { catchUpStrategy: "snapshot", writeStrategy: "resource" } } });License
Apache-2.0
