Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@
"flags": ["api-version", "flags-dir", "json", "loglevel", "package-id", "target-org"],
"plugin": "@salesforce/plugin-packaging"
},
{
"alias": [],
"command": "package:authorize:list",
"flagAliases": ["apiversion", "targetusername", "u"],
"flagChars": ["o", "p"],
"flags": ["api-version", "flags-dir", "json", "loglevel", "package", "target-org"],
"plugin": "@salesforce/plugin-packaging"
},
{
"alias": [],
"command": "package:bundle:create",
Expand Down
41 changes: 41 additions & 0 deletions messages/package_authorize_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# summary

List package authorization records.

# description

Display subscriber org authorization records. Optionally specify --package to filter the results by package.

# examples

- List all subscriber org authorizations:

<%= config.bin %> <%= command.id %> --target-org AuthoringOrg

- List subscriber org authorizations for a package:

<%= config.bin %> <%= command.id %> --package MyPackage --target-org AuthoringOrg

# flags.package.summary

Optional ID or alias of the package used to filter the authorization records.

# columns.subscriber-org

Subscriber Org

# columns.subscriber-package

Subscriber Package

# columns.status

Status

# columns.created-date

Authorized Date

# columns.created-by

Authorizing User
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"@oclif/core": "^4",
"@salesforce/core": "^9.1.0",
"@salesforce/kit": "^4.0.0",
"@salesforce/packaging": "^5.0.4",
"@salesforce/packaging": "5.0.9-spi-dev.0",
"@salesforce/sf-plugins-core": "^13.0.0",
"@salesforce/ts-types": "^3.0.1",
"chalk": "^5.6.2"
Expand Down Expand Up @@ -109,6 +109,9 @@
},
"installed": {
"description": "Command to list installed packages."
},
"authorize": {
"description": "Commands to manage authorized subscriber orgs for a package."
}
}
}
Expand Down
49 changes: 49 additions & 0 deletions schemas/package-authorize-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/PackageAuthorizeListCommandResult",
"definitions": {
"PackageAuthorizeListCommandResult": {
"type": "array",
"items": {
"$ref": "#/definitions/PackageAuthorizationRecord"
}
},
"PackageAuthorizationRecord": {
"type": "object",
"properties": {
"Id": {
"type": "string"
},
"SubscriberOrg": {
"type": "string"
},
"SubscriberPackageId": {
"type": ["string", "null"]
},
"Status": {
"type": "string",
"enum": ["Active", "Revoked"]
},
"CreatedDate": {
"type": "string"
},
"CreatedById": {
"type": "string"
},
"CreatedByUsername": {
"type": "string"
}
},
"required": [
"Id",
"SubscriberOrg",
"SubscriberPackageId",
"Status",
"CreatedDate",
"CreatedById",
"CreatedByUsername"
],
"additionalProperties": false
}
}
}
70 changes: 70 additions & 0 deletions src/commands/package/authorize/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Messages } from '@salesforce/core/messages';
import { PackageAuthorization, PackageAuthorizationRecord } from '@salesforce/packaging';
import {
Flags,
loglevel,
orgApiVersionFlagWithDeprecations,
requiredOrgFlagWithDeprecations,
SfCommand,
} from '@salesforce/sf-plugins-core';
import { maybeGetProject } from '../../../utils/getProject.js';
import { resolveSubscriberPackageId } from '../../../utils/packageAuthorization.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_authorize_list');

export type PackageAuthorizeListCommandResult = PackageAuthorizationRecord[];

export class PackageAuthorizeListCommand extends SfCommand<PackageAuthorizeListCommandResult> {
public static readonly hidden = true;
public static state = 'beta';
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');
public static readonly flags = {
loglevel,
'target-org': requiredOrgFlagWithDeprecations,
'api-version': orgApiVersionFlagWithDeprecations,
package: Flags.string({
char: 'p',
summary: messages.getMessage('flags.package.summary'),
}),
};

public async run(): Promise<PackageAuthorizeListCommandResult> {
const { flags } = await this.parse(PackageAuthorizeListCommand);
const connection = flags['target-org'].getConnection(flags['api-version']);
const project = flags.package ? await maybeGetProject() : undefined;
const subscriberPackageId = flags.package
? await resolveSubscriberPackageId({ packageAliasOrId: flags.package, connection, project })
: undefined;
const records = await new PackageAuthorization({ connection, subscriberPackageId }).list();

this.table({
data: records,
columns: [
{ key: 'SubscriberOrg', name: messages.getMessage('columns.subscriber-org') },
{ key: 'SubscriberPackageId', name: messages.getMessage('columns.subscriber-package') },
{ key: 'Status', name: messages.getMessage('columns.status') },
{ key: 'CreatedDate', name: messages.getMessage('columns.created-date') },
{ key: 'CreatedByUsername', name: messages.getMessage('columns.created-by') },
],
});
return records;
}
}
43 changes: 43 additions & 0 deletions src/utils/packageAuthorization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Connection, SfError, SfProject, validateSalesforceId } from '@salesforce/core';
import { Package } from '@salesforce/packaging';

export const resolveSubscriberPackageId = async ({
packageAliasOrId,
connection,
project,
}: {
packageAliasOrId: string;
connection: Connection;
project?: SfProject;
}): Promise<string> => {
const resolvedPackageId = project?.getPackageIdFromAlias(packageAliasOrId) ?? packageAliasOrId;
if (
(resolvedPackageId.startsWith('033') || resolvedPackageId.startsWith('0Ho')) &&
!validateSalesforceId(resolvedPackageId)
) {
throw new SfError(
`The package ID ${resolvedPackageId} is invalid. It must be a 15- or 18-character Salesforce ID.`
);
}
if (resolvedPackageId.startsWith('033')) {
return resolvedPackageId;
}

const pkg = new Package({ packageAliasOrId, connection, project });
return pkg.getSubscriberPackageId();
};
27 changes: 27 additions & 0 deletions src/utils/subscriberOrg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { readFile } from 'node:fs/promises';

export const parseSubscriberOrgList = (subscriberOrgs: string): string[] =>
subscriberOrgs.split(',').map((subscriberOrg) => subscriberOrg.trim());

export const parseSubscriberOrgFile = async (filePath: string): Promise<string[]> => {
const contents = await readFile(filePath, 'utf8');
return contents
.split(/\r?\n/)
.map((line) => line.replace(/#.*/, '').trim())
.filter(Boolean);
};
Loading