Skip to content

Commit f0e0170

Browse files
committed
Merge remote-tracking branch 'upstream/main' into W-21112167-Replications-API
2 parents 3f52441 + 824d83c commit f0e0170

File tree

184 files changed

+14113
-1478
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

184 files changed

+14113
-1478
lines changed

.changeset/docs-mcp-preview-update.md

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-cli': patch
3+
---
4+
5+
Fix GitHub Actions for external repository usage by replacing relative `./actions/setup` and `./actions/run` references with fully qualified `SalesforceCommerceCloud/b2c-developer-tooling/actions/setup@v1` and `SalesforceCommerceCloud/b2c-developer-tooling/actions/run@v1` in all composite actions.

.changeset/mcp-tool-reference-docs.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/unregister-placeholder-tools.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

.claude/skills/api-client-development/SKILL.md

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -172,19 +172,22 @@ SCAPI APIs use an `organizationId` path parameter with the `f_ecom_` prefix, but
172172

173173
```typescript
174174
// From @salesforce/b2c-tooling-sdk (or clients/custom-apis.ts)
175-
import {toOrganizationId, toTenantId, buildTenantScope} from '@salesforce/b2c-tooling-sdk';
175+
import {toOrganizationId, normalizeTenantId, buildTenantScope} from '@salesforce/b2c-tooling-sdk';
176176

177-
// Convert tenant ID to organization ID (adds f_ecom_ prefix)
177+
// Convert tenant ID to organization ID (normalizes + adds f_ecom_ prefix)
178178
toOrganizationId('zzxy_prd') // Returns 'f_ecom_zzxy_prd'
179179
toOrganizationId('f_ecom_zzxy_prd') // Returns 'f_ecom_zzxy_prd' (unchanged)
180+
toOrganizationId('zzxy-prd') // Returns 'f_ecom_zzxy_prd' (hyphen normalized)
180181

181-
// Extract raw tenant ID (strips f_ecom_ prefix)
182-
toTenantId('f_ecom_zzxy_prd') // Returns 'zzxy_prd'
183-
toTenantId('zzxy_prd') // Returns 'zzxy_prd' (unchanged)
182+
// Normalize any tenant/org ID form to canonical underscore format
183+
normalizeTenantId('f_ecom_zzxy_prd') // Returns 'zzxy_prd'
184+
normalizeTenantId('zzxy-prd') // Returns 'zzxy_prd'
185+
normalizeTenantId('zzxy-prd.dx.commercecloud.salesforce.com') // Returns 'zzxy_prd'
184186

185-
// Build tenant-specific OAuth scope
187+
// Build tenant-specific OAuth scope (normalizes input)
186188
buildTenantScope('zzxy_prd') // Returns 'SALESFORCE_COMMERCE_API:zzxy_prd'
187189
buildTenantScope('f_ecom_zzxy_prd') // Returns 'SALESFORCE_COMMERCE_API:zzxy_prd'
190+
buildTenantScope('zzxy-prd') // Returns 'SALESFORCE_COMMERCE_API:zzxy_prd'
188191
```
189192

190193
### Constants
@@ -272,20 +275,19 @@ export function createCustomApisClient(
272275
export const ORGANIZATION_ID_PREFIX = 'f_ecom_';
273276
export const SCAPI_TENANT_SCOPE_PREFIX = 'SALESFORCE_COMMERCE_API:';
274277

275-
export function toOrganizationId(tenantId: string): string {
276-
return tenantId.startsWith(ORGANIZATION_ID_PREFIX)
277-
? tenantId
278-
: `${ORGANIZATION_ID_PREFIX}${tenantId}`;
278+
export function normalizeTenantId(value: string): string {
279+
let id = value.trim();
280+
if (id.includes('.')) id = id.split('.')[0];
281+
if (id.startsWith(ORGANIZATION_ID_PREFIX)) id = id.slice(ORGANIZATION_ID_PREFIX.length);
282+
return id.replaceAll('-', '_');
279283
}
280284

281-
export function toTenantId(value: string): string {
282-
return value.startsWith(ORGANIZATION_ID_PREFIX)
283-
? value.slice(ORGANIZATION_ID_PREFIX.length)
284-
: value;
285+
export function toOrganizationId(tenantId: string): string {
286+
return `${ORGANIZATION_ID_PREFIX}${normalizeTenantId(tenantId)}`;
285287
}
286288

287289
export function buildTenantScope(tenantId: string): string {
288-
return `${SCAPI_TENANT_SCOPE_PREFIX}${toTenantId(tenantId)}`;
290+
return `${SCAPI_TENANT_SCOPE_PREFIX}${normalizeTenantId(tenantId)}`;
289291
}
290292
```
291293

@@ -440,13 +442,13 @@ const {data, error} = await client.GET('/endpoint', {...});
440442

441443
## Troubleshooting
442444

443-
**OAuth scope errors (401/403 from SCAPI)**: Ensure the client factory calls `auth.withAdditionalScopes()` with both the domain scope (e.g., `sfcc.custom-apis`) and the tenant-specific scope (`SALESFORCE_COMMERCE_API:<tenantId>`). Use `buildTenantScope()` to strip the `f_ecom_` prefix from tenant IDs before building scopes.
445+
**OAuth scope errors (401/403 from SCAPI)**: Ensure the client factory calls `auth.withAdditionalScopes()` with both the domain scope (e.g., `sfcc.custom-apis`) and the tenant-specific scope (`SALESFORCE_COMMERCE_API:<tenantId>`). Use `buildTenantScope()` which normalizes any tenant ID form (hyphenated, hostname, org ID) to canonical underscores before building scopes.
444446

445447
**Type generation failures**: Check that the OpenAPI spec in `specs/` is valid YAML/JSON. Run `pnpm --filter @salesforce/b2c-tooling-sdk run generate:types` and inspect the output. Common issues: spec references external files that aren't present, or uses OpenAPI features not supported by openapi-typescript.
446448

447449
**Middleware ordering issues**: Auth middleware should be added first (`client.use(createAuthMiddleware(...))`), then logging. In openapi-fetch, middleware runs in reverse registration order for requests, so auth registered first means it runs last — ensuring the logging middleware sees the final request with auth headers.
448450

449-
**`organizationId` mismatch**: SCAPI path parameters need the `f_ecom_` prefix (use `toOrganizationId()`), while OAuth scopes need the raw tenant ID (use `toTenantId()`). Mixing these up causes 404s or scope errors.
451+
**`organizationId` mismatch**: SCAPI path parameters need the `f_ecom_` prefix (use `toOrganizationId()`), while OAuth scopes need the raw tenant ID (use `normalizeTenantId()`). Both functions accept any parseable form (hyphenated, hostname, org ID). Mixing these up causes 404s or scope errors.
450452

451453
## Checklist: New SCAPI Client
452454

.github/workflows/publish.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ jobs:
259259
echo "No tags to create"
260260
fi
261261
262+
- name: Update v1 Actions tag
263+
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true'
264+
run: |
265+
git tag -f v1
266+
git push origin v1 --force
267+
echo "Updated v1 tag to $(git rev-parse HEAD)"
268+
262269
- name: Create docs tag if version changed
263270
if: steps.release-type.outputs.type == 'stable' && steps.changesets.outputs.skip != 'true' && steps.quick-check.outputs.skip != 'true' && steps.packages.outputs.publish_docs == 'true'
264271
run: |

.github/workflows/test-actions.yml

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -194,32 +194,3 @@ jobs:
194194
with:
195195
command: 'webdav put --help'
196196
json: 'false'
197-
198-
# E2E tests — only on main, requires e2e-dev environment with real credentials
199-
e2e:
200-
name: 'E2E'
201-
if: github.ref == 'refs/heads/main'
202-
runs-on: ubuntu-latest
203-
environment: e2e-dev
204-
steps:
205-
- uses: actions/checkout@v4
206-
207-
- name: Setup with real credentials
208-
uses: ./actions/setup
209-
with:
210-
client-id: ${{ secrets.SFCC_CLIENT_ID }}
211-
client-secret: ${{ secrets.SFCC_CLIENT_SECRET }}
212-
server: ${{ vars.SFCC_SERVER }}
213-
username: ${{ secrets.SFCC_USERNAME }}
214-
password: ${{ secrets.SFCC_PASSWORD }}
215-
216-
- name: List code versions
217-
id: code-list
218-
uses: ./actions/run
219-
with:
220-
command: 'code list'
221-
222-
- name: Verify code list output
223-
run: |
224-
echo "Result: ${{ steps.code-list.outputs.result }}"
225-
[ "${{ steps.code-list.outputs.exit-code }}" = "0" ] || exit 1

action.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ inputs:
4949
description: 'Tenant ID → SFCC_TENANT_ID'
5050
required: false
5151
mrt-api-key:
52-
description: 'MRT API key → SFCC_MRT_API_KEY'
52+
description: 'MRT API key → MRT_API_KEY'
5353
required: false
5454
mrt-project:
55-
description: 'MRT project slug → SFCC_MRT_PROJECT'
55+
description: 'MRT project slug → MRT_PROJECT'
5656
required: false
5757
mrt-environment:
58-
description: 'MRT environment → SFCC_MRT_ENVIRONMENT'
58+
description: 'MRT environment → MRT_ENVIRONMENT'
5959
required: false
6060
account-manager-host:
6161
description: 'Account Manager hostname → SFCC_ACCOUNT_MANAGER_HOST'
@@ -77,7 +77,7 @@ runs:
7777
steps:
7878
- name: Setup B2C CLI
7979
id: setup
80-
uses: ./actions/setup
80+
uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/setup@v1
8181
with:
8282
version: ${{ inputs.version }}
8383
node-version: ${{ inputs.node-version }}
@@ -97,7 +97,7 @@ runs:
9797
- name: Run command
9898
id: command
9999
if: inputs.command != ''
100-
uses: ./actions/run
100+
uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/run@v1
101101
with:
102102
command: ${{ inputs.command }}
103103
json: ${{ inputs.json }}

actions/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ GitHub Actions for automating Salesforce B2C Commerce operations with the [`@sal
6363
username: ${{ secrets.SFCC_USERNAME }}
6464
password: ${{ secrets.SFCC_PASSWORD }}
6565
target: './export/site-import.zip'
66-
timeout: 300
66+
timeout: 600
6767
```
6868
6969
### Raw CLI command
@@ -96,9 +96,9 @@ All actions accept auth inputs directly or read from `SFCC_*` environment variab
9696
| `password` | `SFCC_PASSWORD` | WebDAV operations |
9797
| `short-code` | `SFCC_SHORTCODE` | SCAPI operations |
9898
| `tenant-id` | `SFCC_TENANT_ID` | SCAPI operations |
99-
| `mrt-api-key` | `SFCC_MRT_API_KEY` | MRT operations |
100-
| `mrt-project` | `SFCC_MRT_PROJECT` | MRT operations |
101-
| `mrt-environment` | `SFCC_MRT_ENVIRONMENT` | MRT operations |
99+
| `mrt-api-key` | `MRT_API_KEY` | MRT operations |
100+
| `mrt-project` | `MRT_PROJECT` | MRT operations |
101+
| `mrt-environment` | `MRT_ENVIRONMENT` | MRT operations |
102102
| `account-manager-host` | `SFCC_ACCOUNT_MANAGER_HOST` | Account Manager |
103103

104104
## Plugins
@@ -156,3 +156,5 @@ When `json: true` (default), the `result` output contains the parsed JSON from t
156156
with:
157157
version: '0.4.1' # Pin CLI version
158158
```
159+
160+
> **Note:** High-level actions (`code-deploy`, `data-import`, `job-run`, `mrt-deploy`, `webdav-upload`) and the root action internally reference `actions/setup@v1` and `actions/run@v1`. This means even if you pin the outer action to a specific SHA or tag, the setup and run steps resolve to the latest `v1` release. For full SHA-level reproducibility, use `actions/setup` + `actions/run` directly — each can be pinned independently to an exact SHA. For most users, `@v1` on the high-level actions is the recommended approach.

actions/code-deploy/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ runs:
6464
using: 'composite'
6565
steps:
6666
- name: Ensure CLI is installed
67-
uses: ./actions/setup
67+
uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/setup@v1
6868
with:
6969
version: ${{ inputs.version }}
7070
node-version: ${{ inputs.node-version }}
@@ -113,7 +113,7 @@ runs:
113113
114114
- name: Deploy cartridges
115115
id: deploy
116-
uses: ./actions/run
116+
uses: SalesforceCommerceCloud/b2c-developer-tooling/actions/run@v1
117117
with:
118118
command: ${{ steps.build-cmd.outputs.cmd }}
119119
json: 'true'

0 commit comments

Comments
 (0)