sdk-module-development
SDK Module Development
This skill covers adding new modules and exports to the @salesforce/b2c-tooling-sdk package.
Package Structure
The SDK is organized into functional layers:
packages/b2c-tooling-sdk/src/
├── auth/ # Authentication strategies
├── instance/ # B2CInstance entry point
├── clients/ # HTTP clients (WebDAV, OCAPI, SLAS, ODS, MRT)
├── platform/ # Platform APIs
├── operations/ # High-level business operations
│ ├── code/ # Code deployment
│ ├── jobs/ # Job execution
│ ├── sites/ # Site management
│ └── mrt/ # MRT deployments
├── cli/ # Base command classes for oclif
├── logging/ # Pino-based logging
├── errors/ # Error types
├── config/ # Configuration loading
└── i18n/ # Internationalization
Barrel File Pattern
Each module uses an index.ts barrel file that exports the public API:
/**
* Authentication strategies for B2C Commerce APIs.
*
* This module provides various authentication mechanisms for B2C Commerce:
* - OAuth 2.0 client credentials flow
* - Basic authentication for WebDAV
* - API key authentication
*
* @example
* ```typescript
* import { OAuthStrategy } from '@salesforce/b2c-tooling-sdk/auth';
*
* const auth = new OAuthStrategy({
* clientId: 'my-client',
* clientSecret: 'my-secret',
* });
* ```
*
* @module auth
*/
// Types
export type { AuthStrategy, AuthConfig } from './types.js';
// Strategies
export { BasicAuthStrategy } from './basic.js';
export { OAuthStrategy, decodeJWT } from './oauth.js';
// Resolution helpers
export { resolveAuthStrategy, checkAvailableAuthMethods } from './resolve.js';
Key points:
- Module-level JSDoc with
@moduletag for TypeDoc - Include usage examples in the JSDoc
- Group exports logically (types, classes, functions)
- Only export public API items
Package.json Exports
The exports field in packages/b2c-tooling-sdk/package.json uses a development condition pattern:
{
"exports": {
"./newmodule": {
"development": "./src/newmodule/index.ts",
"import": {
"types": "./dist/esm/newmodule/index.d.ts",
"default": "./dist/esm/newmodule/index.js"
},
"require": {
"types": "./dist/cjs/newmodule/index.d.ts",
"default": "./dist/cjs/newmodule/index.js"
}
}
}
}
The development condition:
- Points directly to TypeScript source files
- Used when running with
--conditions=development(viabin/dev.js) - Enables hot-reloading during development without rebuilding
Client Factory Pattern
HTTP clients follow a consistent factory function pattern:
// src/clients/newapi.ts
import createClient, { type Client } from 'openapi-fetch';
import type { AuthStrategy } from '../auth/types.js';
import type { paths, components } from './newapi.generated.js';
import { createAuthMiddleware, createLoggingMiddleware } from './middleware.js';
// Re-export generated types for consumers
export type { paths, components };
// Define client type alias
export type NewApiClient = Client<paths>;
// Factory function (not class)
export function createNewApiClient(
hostname: string,
auth: AuthStrategy,
options?: { apiVersion?: string }
): NewApiClient {
const { apiVersion = 'v1' } = options ?? {};
const client = createClient<paths>({
baseUrl: `https://${hostname}/api/newapi/${apiVersion}`,
});
// Middleware order: auth first (runs last), logging last (sees complete request)
client.use(createAuthMiddleware(auth));
client.use(createLoggingMiddleware('NEWAPI'));
return client;
}
Then export from the clients barrel:
// src/clients/index.ts
export { createNewApiClient } from './newapi.js';
export type { NewApiClient, paths as NewApiPaths, components as NewApiComponents } from './newapi.js';
For SCAPI clients with OAuth scope requirements, see API Client Development for advanced patterns including scope injection and tenant ID handling.
OpenAPI Type Generation
For APIs with OpenAPI specs, generate TypeScript types:
-
Add the spec file to
packages/b2c-tooling-sdk/specs/ -
Update the generate script in
package.json:
{
"scripts": {
"generate:types": "openapi-typescript specs/data-api.json -o src/clients/ocapi.generated.ts && openapi-typescript specs/newapi-v1.yaml -o src/clients/newapi.generated.ts"
}
}
- Run generation:
pnpm --filter @salesforce/b2c-tooling-sdk run generate:types
- Import the generated types in your client:
import type { paths, components } from './newapi.generated.js';
Operations Module Pattern
Operations group related business logic:
src/operations/newfeature/
├── index.ts # Barrel file with module JSDoc
├── list.ts # List operation
├── create.ts # Create operation
└── types.ts # Shared types (if needed)
Example operation:
// src/operations/newfeature/list.ts
import type { NewApiClient } from '../../clients/newapi.js';
export interface ListOptions {
filter?: string;
limit?: number;
}
export interface ListResult {
items: Item[];
total: number;
}
/**
* Lists items from the new feature API.
*
* @param client - The NewApi client instance
* @param options - List options
* @returns List result with items and total count
*
* @example
* ```typescript
* const result = await listItems(client, { limit: 10 });
* console.log(result.items);
* ```
*/
export async function listItems(
client: NewApiClient,
options?: ListOptions
): Promise<ListResult> {
const { data, error } = await client.GET('/items', {
params: {
query: {
filter: options?.filter,
limit: options?.limit,
},
},
});
if (error) {
throw new Error(`Failed to list items: ${error.message}`);
}
return {
items: data.items,
total: data.total,
};
}
Barrel file:
// src/operations/newfeature/index.ts
/**
* Operations for the new feature.
*
* @example
* ```typescript
* import { listItems, createItem } from '@salesforce/b2c-tooling-sdk/operations/newfeature';
* ```
*
* @module operations/newfeature
*/
export { listItems, type ListOptions, type ListResult } from './list.js';
export { createItem, type CreateOptions } from './create.js';
Adding a New Module - Step by Step
1. Create the module directory
mkdir -p packages/b2c-tooling-sdk/src/newmodule
2. Create the implementation file(s)
// src/newmodule/feature.ts
export interface FeatureConfig {
setting: string;
}
export class Feature {
constructor(private config: FeatureConfig) {}
doSomething(): string {
return this.config.setting;
}
}
3. Create the barrel file with module JSDoc
// src/newmodule/index.ts
/**
* New module for feature X.
*
* @example
* ```typescript
* import { Feature } from '@salesforce/b2c-tooling-sdk/newmodule';
* const f = new Feature({ setting: 'value' });
* ```
*
* @module newmodule
*/
export { Feature, type FeatureConfig } from './feature.js';
4. Add to package.json exports
{
"exports": {
"./newmodule": {
"development": "./src/newmodule/index.ts",
"import": {
"types": "./dist/esm/newmodule/index.d.ts",
"default": "./dist/esm/newmodule/index.js"
},
"require": {
"types": "./dist/cjs/newmodule/index.d.ts",
"default": "./dist/cjs/newmodule/index.js"
}
}
}
}
5. Optionally export from main index
If the module should be accessible from the main package export:
// src/index.ts
export { Feature } from './newmodule/index.js';
export type { FeatureConfig } from './newmodule/index.js';
6. Build and test
pnpm --filter @salesforce/b2c-tooling-sdk run build
pnpm --filter @salesforce/b2c-tooling-sdk run test
Build System
The SDK builds to both ESM and CommonJS:
{
"scripts": {
"build": "pnpm run generate:types && pnpm run build:esm && pnpm run build:cjs",
"build:esm": "tsc -p tsconfig.esm.json",
"build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json"
}
}
TypeScript configs:
tsconfig.json- Base config with strict settingstsconfig.esm.json- ESM build todist/esm/tsconfig.cjs.json- CJS build todist/cjs/
Import Patterns
For consumers of the SDK:
// Main export
import { B2CInstance } from '@salesforce/b2c-tooling-sdk';
// Sub-module exports
import { OAuthStrategy } from '@salesforce/b2c-tooling-sdk/auth';
import { WebDavClient } from '@salesforce/b2c-tooling-sdk/clients';
import { findAndDeployCartridges } from '@salesforce/b2c-tooling-sdk/operations/code';
import { createLogger } from '@salesforce/b2c-tooling-sdk/logging';
import { CartridgeCommand } from '@salesforce/b2c-tooling-sdk/cli';
In tests, always use package imports (not relative paths):
// Good - uses package exports
import { WebDavClient } from '@salesforce/b2c-tooling-sdk/clients';
// Avoid - relative paths
import { WebDavClient } from '../../src/clients/webdav.js';
New Module Checklist
- Create module directory under
src/ - Implement feature in separate files
- Create
index.tsbarrel with module-level JSDoc - Add export to
package.jsonwith development condition - Optionally add to main
src/index.tsexports - Write tests in
test/mirroring the src structure - Run
pnpm run buildto verify compilation - Run
pnpm run testto verify tests pass - Update TypeDoc entry points in
typedoc.jsonif needed
More from salesforcecommercecloud/b2c-developer-tooling
b2c-config
Inspect and debug CLI configuration, instance connections, and authentication. Use this skill whenever the user needs to check which dw.json or credentials are active, manage multiple instance profiles, retrieve OAuth tokens for scripting, troubleshoot authentication failures or connection errors, or integrate with VS Code or other editors. Also use when environment variables override config or the wrong sandbox is being targeted -- even if they just say 'why is it connecting to the wrong instance' or 'get me an access token'.
90b2c-scapi-schemas
Browse and retrieve SCAPI OpenAPI schema specifications. Use this skill whenever the user needs to list available SCAPI APIs, inspect endpoint paths or request/response shapes, explore data models for products or orders, check which fields an API returns, or understand SCAPI versioning. Also use when looking up API details before building an integration -- even if they just say 'what fields does the product API return' or 'show me the SCAPI endpoints'.
84b2c-business-manager-extensions
Build Business Manager extension cartridges with custom admin tools, menu items, and dialog actions. Use this skill whenever the user needs to create bm_* cartridges, add menu actions or dialog buttons in BM, configure bm_extensions.xml, or extend admin pages with form overlays. Also use when customizing the BM interface for back-office workflows -- even if they just say 'add a button to BM' or 'custom admin page'.
78b2c-sandbox
Create and manage on-demand sandboxes (ODS) for B2C Commerce using the b2c CLI. Use this skill whenever the user needs to spin up a new development sandbox, list running sandboxes, start/stop/restart an instance, or manage sandbox lifecycle — even if they just say "I need a sandbox" or "restart my instance".
77b2c-custom-objects
Store and query custom business data using CustomObjectMgr, OCAPI Data API, and Shopper Custom Objects API. Use this skill whenever the user needs to create, read, update, or search custom object instances, build processing queues with status fields, choose between site-scoped and organization-scoped storage, or query custom objects with bool/term filters. Also use when persisting non-standard data -- even if they just say 'store config per site' or 'query my custom data'.
77b2c-custom-api-development
Develop Custom SCAPI REST endpoints with api.json routes, schema.yaml definitions, and OAuth scope configuration. Use this skill whenever the user needs to create a custom API on the Commerce platform, define OpenAPI 3.0 schemas for request/response, structure the rest-apis cartridge folder, or debug endpoint registration and 404 issues. Also use when building headless commerce integrations -- even if they just say 'custom REST endpoint' or 'expose my script as an API'.
76