Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0ef0a94
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 4, 2026
a182244
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 4, 2026
ea14acd
Merge branch 'main' into CEXT-6151
oshmyheliuk May 5, 2026
dcc5c57
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 5, 2026
9342478
Merge branch 'CEXT-6151' of github.com:adobe/aio-commerce-sdk into CE…
oshmyheliuk May 5, 2026
02f79b2
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 5, 2026
cef1831
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 5, 2026
6cf97a8
CEXT-6151: Fix require() JSDoc and add 401 test
oshmyheliuk May 6, 2026
f83ad7a
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 6, 2026
16efa4c
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 6, 2026
14c8d2a
Merge branch 'main' into CEXT-6151
oshmyheliuk May 15, 2026
38c6595
Merge branch 'main' into CEXT-6151
oshmyheliuk May 18, 2026
407d8cf
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 18, 2026
f42a608
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 18, 2026
92f523d
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 18, 2026
a17ddd4
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 18, 2026
d33ae24
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 19, 2026
8142c69
CEXT-6151: [SDK] Add ACL admin UI schema and helper to check permissions
oshmyheliuk May 19, 2026
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
7 changes: 7 additions & 0 deletions .changeset/add-admin-ui-sdk-library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@adobe/aio-commerce-lib-admin-ui-sdk": minor
"@adobe/aio-commerce-sdk": minor
---

Add `@adobe/aio-commerce-lib-admin-ui-sdk` library for checking Admin UI SDK ACL resource permissions.
Add Admin UI SDK API exports to `@adobe/aio-commerce-sdk`.
5 changes: 5 additions & 0 deletions .changeset/menu-item-acl-resource.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@adobe/aio-commerce-lib-app": minor
---

Add optional `aclResource` support to Admin UI SDK menu item configuration.
21 changes: 21 additions & 0 deletions packages/aio-commerce-lib-admin-ui-sdk/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",

"root": false,
"extends": "//",

"overrides": [
{
"includes": ["source/**/endpoints.ts"],
"linter": {
"rules": {
"suspicious": {
// Endpoint functions must be async for consistent error handling —
// sync throws would not be catchable via .catch() on the returned Promise.
"useAwait": "off"
}
}
}
}
]
}
111 changes: 111 additions & 0 deletions packages/aio-commerce-lib-admin-ui-sdk/docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# `@adobe/aio-commerce-lib-admin-ui-sdk` Documentation
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add experimental warning


## Overview

This package provides utilities for interacting with the Admin UI SDK API:

- **[Permission Checking](#permission-checking)**: Check whether the current user has access to an ACL resource, with built-in caching and request deduplication
- **[API Client](#api-client)**: Create typed HTTP clients for the Admin UI SDK API

## API Reference

For a complete list of all available types, functions, and classes, see the [API Reference](./api-reference/README.md).

## Quick Start

### Permission Checking

Use `getAdminUiSdkPermissionClient` to verify whether the current user has been granted a given ACL resource. Results are cached for 5 minutes by default, and concurrent requests for the same resource are deduplicated automatically.

```typescript
import { AdobeCommerceHttpClient } from "@adobe/aio-commerce-lib-api";
import { getAdminUiSdkPermissionClient } from "@adobe/aio-commerce-lib-admin-ui-sdk/api";

const httpClient = new AdobeCommerceHttpClient({
/* CommerceHttpClientParams */
});
const permissions = getAdminUiSdkPermissionClient({ httpClient });

// Returns true if granted, false if denied or on error (fail-closed by default)
const allowed = await permissions.check("Vendor_Module::resource_name");

// Throws AdminUiSdkPermissionDeniedError if denied, or AdminUiSdkPermissionError if the check fails
await permissions.require("Vendor_Module::resource_name");

// Invalidate a cached result (e.g. after a role change)
permissions.invalidate("Vendor_Module::resource_name");

// Invalidate all cached results
permissions.invalidate();
```

By default, `check()` fails closed and returns `false` on network or response parsing errors. To opt out of fail-closed behavior for `check()` and receive the underlying error:

```typescript
const permissions = getAdminUiSdkPermissionClient({
httpClient,
denyOnError: false,
});
```

To adjust the cache TTL or disable caching entirely:

```typescript
const permissions = getAdminUiSdkPermissionClient({
httpClient,
cacheTtlMs: 60_000, // 1 minute
});

const permissionsNoCache = getAdminUiSdkPermissionClient({
httpClient,
cacheTtlMs: 0, // disabled
});
```

#### Error handling

```typescript
import {
AdminUiSdkPermissionError,
AdminUiSdkPermissionDeniedError,
} from "@adobe/aio-commerce-lib-admin-ui-sdk/api";

try {
await permissions.require("Vendor_Module::resource_name");
} catch (error) {
if (error instanceof AdminUiSdkPermissionDeniedError) {
console.error(`Access denied for resource: ${error.resource}`);
} else if (error instanceof AdminUiSdkPermissionError) {
// Unauthorized, network, or response parsing error
console.error("Permission check failed", error);
}
}
```

### API Client

Use `createAdminUiSdkApiClient` for full access to the Admin UI SDK API:

```typescript
import { createAdminUiSdkApiClient } from "@adobe/aio-commerce-lib-admin-ui-sdk/api";

const client = createAdminUiSdkApiClient({
baseUrl: "https://commerce.example.com",
// ...other CommerceHttpClientParams
});
```

In install/uninstall actions where only a subset of operations is needed, prefer `createCustomAdminUiSdkApiClient` to keep the bundle lean:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I understand this is to be more performant I don't think it is an issue in the app-management endpoints since they're not in the critical path of the applications. Therefore I'd remove it for the sake of simplicity.


```typescript
import {
createCustomAdminUiSdkApiClient,
registerExtension,
unregisterExtension,
} from "@adobe/aio-commerce-lib-admin-ui-sdk/api";

const client = createCustomAdminUiSdkApiClient(params, {
registerExtension,
unregisterExtension,
});
```
96 changes: 96 additions & 0 deletions packages/aio-commerce-lib-admin-ui-sdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"name": "@adobe/aio-commerce-lib-admin-ui-sdk",
"type": "module",
"author": "Adobe Inc.",
"version": "0.0.0",
"private": false,
"engines": {
"node": ">=22 <=24"
},
"license": "Apache-2.0",
"description": "A library to interact with the Adobe Commerce Admin UI SDK API",
"keywords": [
"aio",
"adobe-io",
"commerce",
"adobe-commerce",
"adobe-commerce-sdk",
"aio-commerce-sdk",
"admin-ui-sdk",
"app-builder"
],
"bugs": {
"url": "https://github.com/adobe/aio-commerce-sdk/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/adobe/aio-commerce-sdk.git",
"directory": "packages/aio-commerce-lib-admin-ui-sdk"
},
"publishConfig": {
"exports": {
"./api": {
"import": {
"types": "./dist/es/index.d.mts",
"default": "./dist/es/index.mjs"
},
"require": {
"types": "./dist/cjs/index.d.cts",
"default": "./dist/cjs/index.cjs"
}
},
"./package.json": "./package.json"
}
},
"exports": {
"./api": "./source/index.ts",
"./package.json": "./package.json"
},
"imports": {
"#*": "./source/*.ts",
"#test/*": "./test/*.ts"
},
"files": [
"dist",
"package.json",
"CHANGELOG.md",
"README.md"
],
"scripts": {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing docs script and @aio-commerce-sdk/config-typedoc devDependency

"publint": "publint",
"build": "tsdown",
"prepack": "sdk-prepack",
"pack": "pnpm pack",
"postpack": "sdk-postpack",
"assist": "biome check --formatter-enabled=false --linter-enabled=false --assist-enabled=true --no-errors-on-unmatched",
"assist:apply": "biome check --write --formatter-enabled=false --linter-enabled=false --assist-enabled=true --no-errors-on-unmatched",
"check:ci": "biome ci --formatter-enabled=true --linter-enabled=true --assist-enabled=true --no-errors-on-unmatched",
"code:fix": "pnpm run lint:fix && pnpm run assist:apply && pnpm run format && pnpm run format:markdown",
"format": "biome format --write --no-errors-on-unmatched",
"format:markdown": "prettier --no-error-on-unmatched-pattern --write '**/*.md' \"!**/{CODE_OF_CONDUCT.md,COPYRIGHT,LICENSE,SECURITY.md,CONTRIBUTING.md}\"",
"format:check": "biome format --no-errors-on-unmatched",
"lint": "biome lint --no-errors-on-unmatched",
"lint:fix": "biome lint --write --no-errors-on-unmatched",
"typecheck": "tsc --noEmit && echo '✅ No type errors found.'",
"test": "vitest run --coverage",
"test:ui": "vitest --ui --coverage",
"test:watch": "vitest --watch --coverage"
},
"dependencies": {
"@adobe/aio-commerce-lib-api": "workspace:*",
"@adobe/aio-commerce-lib-core": "workspace:*",
"ky": "catalog:",
"valibot": "catalog:"
},
"devDependencies": {
"@aio-commerce-sdk/common-utils": "workspace:*",
"@aio-commerce-sdk/config-tsdown": "workspace:*",
"@aio-commerce-sdk/config-typescript": "workspace:*",
"@aio-commerce-sdk/config-vitest": "workspace:*",
"@aio-commerce-sdk/scripting-utils": "workspace:*",
"@aio-commerce-sdk/scripts": "workspace:*",
"msw": "catalog:",
"typescript": "catalog:"
},
"sideEffects": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2026 Adobe. All rights reserved.
* This file is licensed to you 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 REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import { parseOrThrow } from "@aio-commerce-sdk/common-utils/valibot";

import {
ExtensionRegistrationParamsSchema,
UnregisterExtensionParamsSchema,
} from "./schema";

import type { AdobeCommerceHttpClient } from "@adobe/aio-commerce-lib-api";
import type { Options } from "ky";
import type {
ExtensionRegistrationParams,
UnregisterExtensionParams,
} from "./schema";

/**
* Registers an Admin UI SDK extension with Commerce via POST /V1/adminuisdk/extension.
*
* @param httpClient - The {@link AdobeCommerceHttpClient} to use to make the request.
* @param params - The extension registration parameters.
* @param fetchOptions - Optional Ky fetch options.
*
* @throws An `HTTPError` if the status code is not 2XX.
*/
export async function registerExtension(
httpClient: AdobeCommerceHttpClient,
params: ExtensionRegistrationParams,
fetchOptions?: Options,
): Promise<void> {
const extension = parseOrThrow(ExtensionRegistrationParamsSchema, params);

await httpClient.post("adminuisdk/extension", {
...fetchOptions,
json: { extension },
});
}

/**
* Unregisters an Admin UI SDK extension from Commerce via DELETE /V1/adminuisdk/extension/{workspaceName}/{extensionName}.
*
* @param httpClient - The {@link AdobeCommerceHttpClient} to use to make the request.
* @param params - The workspace and extension names.
* @param fetchOptions - Optional Ky fetch options.
*
* @throws An `HTTPError` if the status code is not 2XX.
*/
export async function unregisterExtension(
httpClient: AdobeCommerceHttpClient,
params: UnregisterExtensionParams,
fetchOptions?: Options,
): Promise<void> {
const { workspaceName, extensionName } = parseOrThrow(
UnregisterExtensionParamsSchema,
params,
);

await httpClient.delete(
`adminuisdk/extension/${workspaceName}/${extensionName}`,
fetchOptions,
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2026 Adobe. All rights reserved.
* This file is licensed to you 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 REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import * as v from "valibot";

/** Parameters for POST /V1/adminuisdk/extension. */
export const ExtensionRegistrationParamsSchema = v.object({
extensionName: v.string(),
extensionTitle: v.string(),
extensionUrl: v.string(),
extensionWorkspace: v.string(),
});

/** Parameters for DELETE /V1/adminuisdk/extension/{workspaceName}/{extensionName}. */
export const UnregisterExtensionParamsSchema = v.object({
workspaceName: v.string(),
extensionName: v.string(),
});

/** The parameters accepted by POST /V1/adminuisdk/extension. */
export type ExtensionRegistrationParams = v.InferInput<
typeof ExtensionRegistrationParamsSchema
>;

/** The parameters accepted by DELETE /V1/adminuisdk/extension/{workspaceName}/{extensionName}. */
export type UnregisterExtensionParams = v.InferInput<
typeof UnregisterExtensionParamsSchema
>;
19 changes: 19 additions & 0 deletions packages/aio-commerce-lib-admin-ui-sdk/source/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2026 Adobe. All rights reserved.
* This file is licensed to you 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 REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

/** biome-ignore-all lint/performance/noBarrelFile: api sub-barrel */

export * from "./extensions/endpoints";
export * from "./permissions/endpoints";

export type * from "./extensions/schema";
export type * from "./permissions/schema";
Loading