Skip to content

Commit 00b9e88

Browse files
committed
Refresh MRT admin schema and add env clone, bundle delete, org members, org certs
- Update OpenAPI spec from cloud-soak.mrt-soak.com (target clone, certificates, org members, bundle delete + bulk-delete endpoints) and regenerate types. - SDK: add cloneEnv, deleteBundle/bulkDeleteBundles, organization-member operations, certificate operations. - CLI: b2c mrt env clone, b2c mrt bundle delete, b2c mrt org member list/add/get/update/remove, b2c mrt org cert list/get/create/delete/restart-validation. - Docs and b2c-mrt skill updated; changesets included.
1 parent 18471af commit 00b9e88

31 files changed

Lines changed: 5824 additions & 96 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@salesforce/b2c-agent-plugins': patch
3+
---
4+
5+
Document new MRT environment clone, bundle delete, organization member, and organization certificate commands in the `b2c-mrt` skill.

.changeset/mrt-schema-refresh.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@salesforce/b2c-cli': minor
3+
'@salesforce/b2c-tooling-sdk': minor
4+
---
5+
6+
Refresh the MRT admin API schema and add new commands:
7+
8+
- `b2c mrt env clone` — clone an environment from an existing source, optionally copying redirects, environment variables, and B2C target info
9+
- `b2c mrt bundle delete` — delete one or more bundles (uses bulk-delete when more than one ID is supplied)
10+
- `b2c mrt org member list|add|get|update|remove` — manage organization-level members
11+
- `b2c mrt org cert list|get|create|delete|restart-validation` — manage custom domain certificates referenced by environments

docs/cli/mrt.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,33 @@ b2c mrt env delete staging --project my-storefront
314314
b2c mrt env delete old-env -p my-storefront --force
315315
```
316316

317+
### b2c mrt env clone
318+
319+
Clone an environment from an existing source environment. The new target receives the source's configuration (excluding proxies and the production flag) and is automatically deployed with the source target's current bundle (if any). Optionally clones redirects, environment variables, and B2C target info.
320+
321+
```bash
322+
# Clone an environment with default settings
323+
b2c mrt env clone staging-copy --from staging --project my-storefront
324+
325+
# Clone with redirects and environment variables
326+
b2c mrt env clone qa --from staging -p my-storefront --clone-redirects --clone-env-vars
327+
328+
# Clone using a custom domain certificate
329+
b2c mrt env clone qa --from staging -p my-storefront \
330+
--external-hostname qa.example.com --certificate-id 123 --wait
331+
```
332+
333+
| Flag | Description |
334+
|------|-------------|
335+
| `--from`, `-f` | Source environment slug to clone from (required) |
336+
| `--external-hostname` | Full external hostname (required for non-MRT-managed certificates) |
337+
| `--external-domain` | External domain for Universal PWA SSR |
338+
| `--certificate-id` | Certificate ID for custom domain (use `b2c mrt org cert list` to find) |
339+
| `--clone-redirects` | Clone redirects from the source environment |
340+
| `--clone-env-vars` | Clone environment variables from the source environment |
341+
| `--clone-b2c-info` | Clone B2C target info from the source environment |
342+
| `--wait`, `-w` | Wait for the new environment to reach a terminal state |
343+
317344
### b2c mrt env invalidate
318345

319346
Invalidate CDN cache for an environment.
@@ -508,6 +535,105 @@ b2c mrt bundle download 12345 -p my-storefront -o ./artifacts/bundle.tgz
508535
b2c mrt bundle download 12345 -p my-storefront --url-only
509536
```
510537

538+
### b2c mrt bundle delete
539+
540+
Delete one or more bundles. Bundles are deleted asynchronously by the server and only project admins can run this command. With more than one bundle ID the CLI uses the bulk-delete endpoint and reports any rejected bundles (e.g. bundles in use by an active deployment).
541+
542+
```bash
543+
# Delete a single bundle
544+
b2c mrt bundle delete 12345 -p my-storefront
545+
546+
# Delete several at once
547+
b2c mrt bundle delete 12345 12346 12347 -p my-storefront
548+
549+
# Skip the confirmation prompt
550+
b2c mrt bundle delete 12345 -p my-storefront --force
551+
```
552+
553+
---
554+
555+
## Organization Member Commands
556+
557+
Organization members are distinct from project members: they hold a role at the organization level and can optionally be granted permission to view all projects and manage custom domain certificates.
558+
559+
### b2c mrt org member list
560+
561+
```bash
562+
b2c mrt org member list --org my-org
563+
b2c mrt org member list --org my-org --search alice
564+
```
565+
566+
### b2c mrt org member add
567+
568+
Roles: `owner` or `member`.
569+
570+
```bash
571+
b2c mrt org member add alice@example.com --org my-org --role member
572+
b2c mrt org member add bob@example.com --org my-org --role owner --view-all-projects
573+
```
574+
575+
### b2c mrt org member get
576+
577+
```bash
578+
b2c mrt org member get alice@example.com --org my-org
579+
```
580+
581+
### b2c mrt org member update
582+
583+
```bash
584+
b2c mrt org member update alice@example.com --org my-org --view-all-projects
585+
b2c mrt org member update alice@example.com --org my-org --no-cert-permission
586+
```
587+
588+
### b2c mrt org member remove
589+
590+
```bash
591+
b2c mrt org member remove alice@example.com --org my-org
592+
```
593+
594+
---
595+
596+
## Organization Certificate Commands
597+
598+
Manage custom domain certificates for environments that use a non-MRT-managed hostname. Certificates are organization-scoped; reference a certificate from `env create`, `env update`, or `env clone` via `--certificate-id`.
599+
600+
### b2c mrt org cert list
601+
602+
```bash
603+
b2c mrt org cert list --org my-org
604+
b2c mrt org cert list --org my-org --custom-only
605+
```
606+
607+
### b2c mrt org cert get
608+
609+
Returns the validation record (the DNS entry the customer must add to validate the certificate).
610+
611+
```bash
612+
b2c mrt org cert get 123 --org my-org
613+
```
614+
615+
### b2c mrt org cert create
616+
617+
```bash
618+
b2c mrt org cert create shop.example.com --org my-org
619+
```
620+
621+
The output includes the validation record. Add it to your DNS to complete validation.
622+
623+
### b2c mrt org cert delete
624+
625+
```bash
626+
b2c mrt org cert delete 123 --org my-org
627+
```
628+
629+
### b2c mrt org cert restart-validation
630+
631+
Restart validation for a certificate that has not yet been validated. The response includes a fresh validation record.
632+
633+
```bash
634+
b2c mrt org cert restart-validation 123 --org my-org
635+
```
636+
511637
---
512638

513639
## Tail Logs

packages/b2c-cli/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@
147147
"mrt:org": {
148148
"description": "List organizations and view B2C Commerce instance connections\n\nDocs: https://salesforcecommercecloud.github.io/b2c-developer-tooling/cli/mrt.html#organization-commands"
149149
},
150+
"mrt:org:member": {
151+
"description": "Manage organization-level members and their permissions\n\nDocs: https://salesforcecommercecloud.github.io/b2c-developer-tooling/cli/mrt.html#organization-member-commands"
152+
},
153+
"mrt:org:cert": {
154+
"description": "Manage custom domain certificates for organization environments\n\nDocs: https://salesforcecommercecloud.github.io/b2c-developer-tooling/cli/mrt.html#organization-certificate-commands"
155+
},
150156
"mrt:project": {
151157
"description": "Create, update, delete, and configure MRT projects\n\nDocs: https://salesforcecommercecloud.github.io/b2c-developer-tooling/cli/mrt.html#project-commands"
152158
},
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* SPDX-License-Identifier: Apache-2
4+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
import {Args, Flags} from '@oclif/core';
7+
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
8+
import {
9+
bulkDeleteBundles,
10+
deleteBundle,
11+
type BulkDeleteBundlesResult,
12+
} from '@salesforce/b2c-tooling-sdk/operations/mrt';
13+
import {t, withDocs} from '../../../i18n/index.js';
14+
import {confirm} from '../../../prompts.js';
15+
16+
interface DeleteBundleResult {
17+
queued: number[];
18+
rejected: BulkDeleteBundlesResult['rejected'];
19+
}
20+
21+
export default class MrtBundleDelete extends MrtCommand<typeof MrtBundleDelete> {
22+
static args = {
23+
bundleId: Args.integer({
24+
description: 'Bundle ID to delete (additional IDs may follow)',
25+
required: true,
26+
}),
27+
};
28+
29+
static description = withDocs(
30+
t('commands.mrt.bundle.delete.description', 'Delete one or more bundles from a Managed Runtime project'),
31+
'/cli/mrt.html#b2c-mrt-bundle-delete',
32+
);
33+
34+
static enableJsonFlag = true;
35+
36+
static examples = [
37+
'<%= config.bin %> <%= command.id %> 12345 --project my-storefront',
38+
'<%= config.bin %> <%= command.id %> 12345 12346 12347 -p my-storefront',
39+
'<%= config.bin %> <%= command.id %> 12345 -p my-storefront --force',
40+
];
41+
42+
static flags = {
43+
...MrtCommand.baseFlags,
44+
force: Flags.boolean({
45+
char: 'f',
46+
description: 'Skip confirmation prompt',
47+
default: false,
48+
}),
49+
};
50+
51+
// Allow multiple positional bundle IDs
52+
static strict = false;
53+
54+
protected operations = {
55+
deleteBundle,
56+
bulkDeleteBundles,
57+
};
58+
59+
async run(): Promise<DeleteBundleResult> {
60+
this.requireMrtCredentials();
61+
62+
const {argv, flags} = await this.parse(MrtBundleDelete);
63+
const {mrtProject: project} = this.resolvedConfig.values;
64+
65+
if (!project) {
66+
this.error('MRT project is required. Provide --project flag, set MRT_PROJECT, or set mrtProject in dw.json.');
67+
}
68+
69+
const bundleIds: number[] = [];
70+
for (const arg of argv as Array<number | string>) {
71+
const n = typeof arg === 'number' ? arg : Number.parseInt(String(arg), 10);
72+
if (!Number.isInteger(n) || n <= 0) {
73+
this.error(t('commands.mrt.bundle.delete.invalidId', 'Invalid bundle ID: {{arg}}', {arg: String(arg)}));
74+
}
75+
bundleIds.push(n);
76+
}
77+
78+
if (!flags.force && !this.jsonEnabled()) {
79+
const message =
80+
bundleIds.length === 1
81+
? t('commands.mrt.bundle.delete.confirmOne', 'Delete bundle {{id}} from {{project}}?', {
82+
id: String(bundleIds[0]),
83+
project,
84+
})
85+
: t('commands.mrt.bundle.delete.confirmMany', 'Delete {{n}} bundles from {{project}}?', {
86+
n: String(bundleIds.length),
87+
project,
88+
});
89+
const confirmed = await confirm(message);
90+
if (!confirmed) {
91+
this.log(t('commands.mrt.bundle.delete.cancelled', 'Delete cancelled.'));
92+
return {queued: [], rejected: []};
93+
}
94+
}
95+
96+
try {
97+
if (bundleIds.length === 1) {
98+
const [bundleId] = bundleIds;
99+
await this.operations.deleteBundle(
100+
{
101+
projectSlug: project,
102+
bundleId,
103+
origin: this.resolvedConfig.values.mrtOrigin,
104+
},
105+
this.getMrtAuth(),
106+
);
107+
108+
if (!this.jsonEnabled()) {
109+
this.log(
110+
t('commands.mrt.bundle.delete.queuedOne', 'Bundle {{id}} queued for deletion.', {id: String(bundleId)}),
111+
);
112+
}
113+
114+
return {queued: [bundleId], rejected: []};
115+
}
116+
117+
const result = await this.operations.bulkDeleteBundles(
118+
{
119+
projectSlug: project,
120+
bundleIds,
121+
origin: this.resolvedConfig.values.mrtOrigin,
122+
},
123+
this.getMrtAuth(),
124+
);
125+
126+
if (!this.jsonEnabled()) {
127+
this.log(
128+
t('commands.mrt.bundle.delete.queuedMany', '{{n}} bundle(s) queued for deletion.', {
129+
n: String(result.queued.length),
130+
}),
131+
);
132+
if (result.rejected.length > 0) {
133+
this.log(t('commands.mrt.bundle.delete.rejectedHeader', 'Rejected bundles:'));
134+
for (const r of result.rejected) {
135+
this.log(` - ${r.bundleId ?? '?'}: ${r.reason}`);
136+
}
137+
}
138+
}
139+
140+
return result;
141+
} catch (error) {
142+
if (error instanceof Error) {
143+
this.error(
144+
t('commands.mrt.bundle.delete.failed', 'Failed to delete bundle(s): {{message}}', {message: error.message}),
145+
);
146+
}
147+
throw error;
148+
}
149+
}
150+
}

0 commit comments

Comments
 (0)