ptech-shell-dev
v2.15.0
Published
Standalone/mock shell service implementations for Module Federation apps.
Maintainers
Readme
ptech-shell-dev
Standalone and development implementations for the contracts exported by ptech-shell-sdk.
Install
npm i ptech-shell-dev ptech-shell-sdkReact is a peer dependency through ptech-shell-sdk.
What This Package Owns
initStandaloneServices: registers a complete local shell service set.createTestServices: creates the standalone services without registration.createDevPreset: creates reusable standalone bootstrap defaults.- Standalone services for i18n, user, tenant, portal context, theme, app runtime/settings, onboarding, config, permissions, shared state, navigation, realtime, observability, notification, analytics, request context, and API client.
createObservableServicefor reusable synchronous standalone state andcreateNoopOnboardingServicefor an explicit tours-unavailable implementation.- API error mapping with
mapApiErrorToUiError.
The standalone realtime factory is a compatibility wrapper around
ptech-shell-runtime/createRealtimeService. Without realtime.createTransport it
uses a transport-less fallback; with a transport it gets the same serialized
lifecycle, target retention, token/origin policy, tenant context, and safe errors as
the production-neutral runtime. Standalone bootstrap registers both
TOKENS.realtime and the additive REALTIME_MANAGER_TOKEN export.
Standalone Bootstrap
Use this in a remote that must run without a real host.
import { initStandaloneServices } from 'ptech-shell-dev';
initStandaloneServices();Default bootstrap values:
apiBase:http://localhost:4000apiBaseRoutes:{}lang:viuser:{ id: 'dev', name: 'Dev User' }navigationPath:/standaloneregisterMode:if-missingappRuntime: permissive in-memory runtime access for the active standalone tenantportalContext:{ portalId: 'standalone', capabilities: {} }theme:{ mode: 'light' }
Override defaults per remote:
import { initStandaloneServices } from 'ptech-shell-dev';
initStandaloneServices({
apiBase: 'http://localhost:5010',
apiBaseRoutes: {
audit: '/audit/api',
ats: { url: 'http://localhost:5020/api' },
},
originPolicy: {
trustedOrigins: ['http://localhost:5020'],
},
lang: 'en',
navigationPath: '/remote-a',
featureFlags: {
'ui.experimental': true,
},
});Use registerMode: 'always' only when intentionally replacing existing services. In host-composed mode, the default if-missing protects real host services from being overwritten by standalone mocks.
Production migration policy
By default, the 2.x release line warns once when standalone/mock services are created in a production build; it deliberately does not throw. Existing production standalone consumers such as PtechTemplate therefore keep working while they migrate or explicitly acknowledge the deployment:
initStandaloneServices({ allowInProduction: true });For browser configuration, expose
PUBLIC_PTECH_SHELL_DEV_ALLOW_IN_PRODUCTION=true at build time. Node-based
tooling may also set PTECH_SHELL_DEV_ALLOW_IN_PRODUCTION=true. A direct call to
createStandaloneUserService has the same defense-in-depth warning and accepts
the same allowInProduction option.
Opt-in fail-closed mode
3.0 is planned to flip the default above to fail-closed. You do not have to
wait for that major: pass productionPolicy: 'fail-closed' now to get the 3.0
behavior early, at any standalone init entry point
(initStandaloneServices, createTestServices, initStandaloneApp) or
directly on createStandaloneUserService:
initStandaloneServices({ productionPolicy: 'fail-closed' });To migrate every standalone entry without editing each call site, set
PTECH_POLICY_MODE=strict for Node execution or expose
PUBLIC_PTECH_POLICY_MODE=strict to the browser bundle. The unified switch
only upgrades omitted policies; an explicit call-site productionPolicy
remains the reviewed exception. Values other than strict are ignored, so a
global environment variable cannot downgrade production enforcement.
With productionPolicy: 'fail-closed' set, running in production without
allowInProduction: true throws StandaloneProductionError before any
mock service — including the mock user service's fake standalone-token-*
bearer tokens — is constructed or registered. allowInProduction: true still
wins over any policy: it suppresses both the warning and the throw, since it
is the explicit acknowledgement that the deployment is intentional.
The PUBLIC_PTECH_SHELL_DEV_ALLOW_IN_PRODUCTION /
PTECH_SHELL_DEV_ALLOW_IN_PRODUCTION escape hatch is an emergency operational
override: under 'fail-closed' it downgrades the throw to a distinct console
warning instead of blocking. Note the contrast with the default 'warn'
policy, where the escape hatch suppresses the warning entirely — only
'fail-closed' guarantees a visible trail in the logs when the hatch is set.
That keeps an unplanned production standalone deployment running under
pressure without losing the evidence that it happened.
productionPolicy defaults to 'warn', so omitting it keeps 2.x behavior
byte-for-byte unchanged. Non-production runtimes never throw regardless of
productionPolicy.
Creating Services Without Registration
import { createTestServices } from 'ptech-shell-dev';
const services = createTestServices({
apiBase: 'http://localhost:4000',
});
const result = await services.apiClient.request<{ id: string }>({
url: '/v1/items/1',
});createTestServices() also returns appRuntime and
initStandaloneServices() registers it as TOKENS.appRuntime. With no seed or
fetcher it grants app.admin, app.data.read, and app.data.write so existing
standalone screens stay usable. Tests can use an appRuntime.seed or
appRuntime.fetcher to return a complete blocked AppRuntimeContext and model
not-entitled, not-installed, or another contract-defined state.
Standalone onboarding accepts optional campaign seeds. With no campaign, a registered page tour remains available for manual replay but never auto-starts.
const services = createTestServices({
onboarding: {
campaigns: [{
campaignId: 'local-audit-intro',
tourKey: 'audit-tool.evidence',
appKey: 'audit-tool',
contentVersion: '3',
revision: 1,
scope: 'app',
enabled: true,
autoShow: true,
progress: 'pending',
}],
},
});API Client Behavior
createStandaloneApiClient implements the ApiClient contract from ptech-shell-sdk.
It provides:
- base URL resolution with optional
apiBaseRoutesand per-requestappKey, - JSON body handling for plain objects,
- request context headers (
traceparent,x-correlation-id), - tenant header propagation through
X-Tenant-Id, - optional Authorization header propagation from
UserService.acquireAccessToken, - destination trust enforcement from
ptech-shell-runtime: arbitrary cross-origin URLs receive no shell credentials, tenant, or trace context, - timeout and caller abort handling,
- retry for idempotent methods by default,
- ProblemDetails/error normalization into
ApiError, - invalid JSON handling for explicit
responseType: 'json', - safe POST failure notifications that never expose raw payload/request URL data or interrupt error propagation,
- per-request localized notification override/suppression through
errorNotification.
UI code should map normalized errors with mapApiErrorToUiError and translate the returned i18n key.
import { TOKENS, getService } from 'ptech-shell-sdk';
import { mapApiErrorToUiError } from 'ptech-shell-dev';
const api = getService(TOKENS.apiClient);
try {
await api?.request({ url: '/v1/items', method: 'POST', body: { name: 'A' } });
} catch (error) {
const uiError = mapApiErrorToUiError(error as Parameters<typeof mapApiErrorToUiError>[0]);
console.error(uiError.i18nKey, uiError.supportTraceId);
}Production React adapters
MSAL and React Router adapters moved to ptech-shell-react in 2.3. Import
createMsalUserService from its root entry and router components from the
ptech-shell-react/react-router subpath. This package intentionally contains
only standalone/mock navigation and user services.
Standalone base path
The mock navigation service keeps getPath() app-relative and applies
navigationBasename only when creating an href. This lets a remote rehearse a
host mount prefix without installing or binding React Router:
initStandaloneServices({ navigationBasename: '/audit-tool' });Production React Router ownership, app-owned and host-owned topologies, and
Module Federation guidance are documented in ptech-shell-react/README.md.
Build and Test
npm run build -w ptech-shell-dev
npm run test -w ptech-shell-dev
npm run test:coverage -w ptech-shell-devnpm run test -w ptech-shell-dev builds the package and runs node --test tests/*.test.mjs.
