| name | sdk-module-development |
| description | Adding new modules and exports to the @salesforce/b2c-tooling-sdk package. Use when creating a new SDK module, adding barrel file exports, configuring package.json exports, or building client factory functions. |
| metadata | {"internal":true} |
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:
export type { AuthStrategy, AuthConfig } from './types.js';
export { BasicAuthStrategy } from './basic.js';
export { OAuthStrategy, decodeJWT } from './oauth.js';
export { resolveAuthStrategy, checkAvailableAuthMethods } from './resolve.js';
Key points:
- Module-level JSDoc with
@module tag 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 (via bin/dev.js)
- Enables hot-reloading during development without rebuilding
Client Factory Pattern
HTTP clients follow a consistent factory function pattern:
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';
export type { paths, components };
export type NewApiClient = Client<paths>;
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}`,
});
client.use(createAuthMiddleware(auth));
client.(());
client;
}
Then export from the clients barrel:
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:
import type { NewApiClient } from '../../clients/newapi.js';
export interface ListOptions {
filter?: string;
limit?: number;
}
export interface ListResult {
items: Item[];
total: number;
}
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) {
();
}
{
: data.,
: data.,
};
}
Barrel file:
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)
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
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:
export { Feature } from './newmodule/index.js';
export type { FeatureConfig } from './newmodule/index.js';
6. Add to TypeDoc entry points
Add the new module's barrel file to docs/typedoc.json so API documentation is generated:
{
"entryPoints": [
"...",
"../packages/b2c-tooling-sdk/src/newmodule/index.ts"
]
}
7. 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 settings
tsconfig.esm.json - ESM build to dist/esm/
tsconfig.cjs.json - CJS build to dist/cjs/
Import Patterns
For consumers of the SDK:
import { B2CInstance } from '@salesforce/b2c-tooling-sdk';
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):
import { WebDavClient } from '@salesforce/b2c-tooling-sdk/clients';
import { WebDavClient } from '../../src/clients/webdav.js';
Refreshing Bundled Platform Data (Docs, Schemas, Job Steps)
The SDK ships several corpora derived from the B2C Commerce platform under
packages/b2c-tooling-sdk/data/:
| Directory | Contents | Consumed by |
|---|
data/script-api/ | Script API reference markdown + index.json | docs search / docs read, MCP docs_* |
data/content-schemas/ | Page Designer / content metadefinition JSON schemas | content validate |
data/xsd/ | Import/export XSD schemas + index.json | docs schema *, XML validation |
data/job-steps/ | Standard job-step markdown + dataset + index.json | docs search / docs read |
All of these originate from the same documentation archive (demandware-mock.zip)
that b2c docs download fetches from an instance — the inner DWAPP-<version>-API-doc.zip
contains sfdocs/script-api/, content/, xsd/, and jobstepapi/. Note that the
user-facing docs download command only extracts the Script API markdown; it does not
update the bundled data files.
Refresh all data at once
Run the maintainer script against a current instance (uses your default instance/auth
via the CLI, so no extra setup):
pnpm --filter @salesforce/b2c-tooling-sdk run refresh:docs-data
B2C_INSTANCE=my-sandbox KEEP_WORKDIR=1 pnpm --filter @salesforce/b2c-tooling-sdk run refresh:docs-data
scripts/refresh-docs-data.ts downloads the archive via b2c docs download, repopulates
every data/ directory above from the inner API-doc zip, then regenerates the derived
datasets and search indexes (build:job-steps-dataset, generate:job-steps-docs,
generate:docs-index). It prints the detected platform version (e.g. DWAPP 26.7).
After refreshing
- Review the diff under
packages/b2c-tooling-sdk/data/. Index files change their
generatedAt timestamp every run; look for substantive schema/doc changes.
- The refresh overwrites files wholesale — there are no hand-maintained local patches
to preserve today. If a platform schema change alters validation behavior (e.g. a
content-schemas/*.json rule), update the affected tests to match the new platform rule.
- Run
pnpm --filter @salesforce/b2c-tooling-sdk run test:agent and add a changeset when
the refresh changes user-facing behavior (bump the platform version, note the change).
The individual generation scripts can still be run standalone (see each script's header
comment), but refresh:docs-data is the one-step path that keeps every corpus in sync
with a single platform release.
New Module Checklist
- Create module directory under
src/
- Implement feature in separate files
- Create
index.ts barrel with module-level JSDoc
- Add export to
package.json with development condition
- Optionally add to main
src/index.ts exports
- Add entry point to
docs/typedoc.json for API doc generation
- Write tests in
test/ mirroring the src structure
- Run
pnpm run build to verify compilation
- Run
pnpm run test to verify tests pass