smartsell-sales-sdk
v0.1.0
Published
Public SDK contract and module build tooling for SmartSell Sales custom modules.
Maintainers
Readme
smartsell-sales-sdk
smartsell-sales-sdk is the public contract for building SmartSell Sales custom modules outside the main SmartSell Sales repository.
It provides:
- public TypeScript types for
sdk, pages, extensions, and hooks SlotRendererfor applying slot overrides from custom modules without reimplementing core logic- helpers such as
defineExtensionManifestanddefineHooksManifest smartsell-sales-build-module, a CLI that builds a module into the single CommonJS bundle expected by the SmartSell Sales runtime
The default import path smartsell-sales-sdk is browser-safe and only exposes runtime APIs. If you need the Node build API programmatically, import it from smartsell-sales-sdk/build-tools.
Installation
npm install react smartsell-sales-sdk
npm install smartsell-themePage example
import type { ModulePageProps } from 'smartsell-sales-sdk';
import { useThemeName, useThemeValue } from 'smartsell-theme';
export default function MyPage({ sdk }: ModulePageProps) {
const user = sdk.auth.getUser();
const theme = useThemeValue();
const themeName = useThemeName();
const isDark = themeName.toLowerCase() === 'dark';
return (
<div
style={{
minHeight: '100vh',
padding: 24,
backgroundColor: theme.colors.background,
color: theme.colors.onBackground,
}}
>
<h1>Hello, {user?.name}</h1>
<p>Current theme: {isDark ? 'dark' : 'light'}</p>
<button
type="button"
onClick={() => sdk.navigation.goBack()}
style={{
backgroundColor: theme.colors.primary,
color: theme.colors.onPrimary,
}}
>
Back
</button>
</div>
);
}Extension example
import type { ExtensionManifest } from 'smartsell-sales-sdk';
import { defineExtensionManifest } from 'smartsell-sales-sdk';
import { useThemeValue, withAlpha } from 'smartsell-theme';
function RevenueCard({ sdk }: { sdk: import('smartsell-sales-sdk').SmartSellSDK }) {
const theme = useThemeValue();
return (
<div
style={{
backgroundColor: withAlpha(theme.colors.surface, 0.72),
border: `1px solid ${withAlpha(theme.colors.positive, 0.3)}`,
color: theme.colors.onSurface,
}}
>
Custom revenue card
</div>
);
}
const manifest: ExtensionManifest = defineExtensionManifest({
slots: {
'dashboard:extra-charts': {
action: 'append',
component: RevenueCard,
},
},
});
export default manifest;Render a slot inside a custom page
Use SlotRenderer when a tenant page wants to expose stable extension points without importing private core files.
import {
SlotRenderer,
type ModulePageProps,
type SlotComponentProps,
} from 'smartsell-sales-sdk';
type OrderReviewContext = {
orderNumber: string;
close: () => void;
};
function DefaultBody() {
return <div>Default modal body</div>;
}
function CustomBody({ context }: SlotComponentProps<OrderReviewContext>) {
return <div>Tenant body for {context?.orderNumber}</div>;
}
export default function MyPage({ sdk }: ModulePageProps) {
return (
<SlotRenderer
id="order-review:modal-body"
sdk={sdk}
context={{
orderNumber: 'SO-1001',
close: () => sdk.navigation.goBack(),
}}
>
<DefaultBody />
</SlotRenderer>
);
}context is optional and stays on the public contract surface. This is the recommended way to share modal payload, callbacks, and local state with tenant overrides.
Hook example
import type { HooksManifest } from 'smartsell-sales-sdk';
import { defineHooksManifest } from 'smartsell-sales-sdk';
const manifest: HooksManifest = defineHooksManifest({
hooks: {
'order:validate': (order) => {
const errors: string[] = [];
if (!order.customerChannel) {
errors.push('Customer channel is required');
}
return errors;
},
},
});
export default manifest;module.json
Create a module.json file in the module folder:
type is required in every module manifest.
{
"id": "my-custom-page",
"name": "My Custom Page",
"version": "1.0.0",
"type": "page",
"entryComponent": "MyPage.tsx",
"routes": [
{
"path": "/my-page",
"label": "My Page",
"icon": "FileText"
}
]
}For extension modules use extensionEntry, and for hooks modules use hooksEntry.
Build a module bundle
npx smartsell-sales-build-module --module-dir ./src/my-custom-page --out-dir ./dist/modulesThe command:
- reads
module.json - builds the module into a single CommonJS bundle
- injects
__moduleConfigmetadata required by the SmartSell Sales runtime - rejects private imports such as
@/core/...
Output example:
dist/modules/my-custom-page.jsTheme helpers
Use smartsell-theme directly inside module components. The SmartSell Sales host shares a single ThemeProvider instance with runtime-loaded modules, so hooks such as useThemeValue() and useThemeName() work across host and custom bundles.
import { useThemeName, useThemeValue, withAlpha } from 'smartsell-theme';
const theme = useThemeValue();
const themeName = useThemeName();
const isDark = themeName.toLowerCase() === 'dark';
const border = withAlpha(theme.colors.backgroundLight, 0.5);This avoids importing private app files such as @/core/theme/useAppTheme and keeps the SDK focused on runtime services, slots, and module contracts.
Publish
npm run typecheck
npm run build
npm publish