@wordpress/abilities 0.2.1-next.8b30e05b0.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/README.md +32 -40
- package/build/api.js +19 -66
- package/build/api.js.map +3 -3
- package/build/index.js.map +2 -2
- package/build/store/actions.js +41 -31
- package/build/store/actions.js.map +2 -2
- package/build/store/constants.js +6 -15
- package/build/store/constants.js.map +2 -2
- package/build/store/index.js +1 -27
- package/build/store/index.js.map +3 -3
- package/build/store/reducer.js +2 -22
- package/build/store/reducer.js.map +2 -2
- package/build/store/selectors.js +1 -1
- package/build/store/selectors.js.map +2 -2
- package/build/store/types.js +19 -0
- package/build/store/types.js.map +7 -0
- package/build/types.js.map +1 -1
- package/build-module/api.js +20 -57
- package/build-module/api.js.map +2 -2
- package/build-module/index.js.map +2 -2
- package/build-module/store/actions.js +43 -32
- package/build-module/store/actions.js.map +2 -2
- package/build-module/store/constants.js +4 -10
- package/build-module/store/constants.js.map +2 -2
- package/build-module/store/index.js +3 -34
- package/build-module/store/index.js.map +2 -2
- package/build-module/store/reducer.js +2 -24
- package/build-module/store/reducer.js.map +2 -2
- package/build-module/store/selectors.js +1 -1
- package/build-module/store/selectors.js.map +2 -2
- package/build-module/store/types.js +1 -0
- package/build-module/store/types.js.map +7 -0
- package/build-types/api.d.ts +16 -23
- package/build-types/api.d.ts.map +1 -1
- package/build-types/index.d.ts +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/store/actions.d.ts +5 -27
- package/build-types/store/actions.d.ts.map +1 -1
- package/build-types/store/constants.d.ts +2 -5
- package/build-types/store/constants.d.ts.map +1 -1
- package/build-types/store/index.d.ts.map +1 -1
- package/build-types/store/reducer.d.ts +21 -11
- package/build-types/store/reducer.d.ts.map +1 -1
- package/build-types/store/selectors.d.ts +2 -1
- package/build-types/store/selectors.d.ts.map +1 -1
- package/build-types/store/types.d.ts +18 -0
- package/build-types/store/types.d.ts.map +1 -0
- package/build-types/types.d.ts +14 -24
- package/build-types/types.d.ts.map +1 -1
- package/package.json +4 -7
- package/src/api.ts +43 -123
- package/src/index.ts +0 -1
- package/src/store/actions.ts +61 -46
- package/src/store/constants.ts +4 -5
- package/src/store/index.ts +2 -34
- package/src/store/reducer.ts +27 -33
- package/src/store/selectors.ts +3 -7
- package/src/store/tests/actions.test.ts +100 -244
- package/src/store/tests/reducer.test.ts +0 -451
- package/src/store/tests/selectors.test.ts +1 -1
- package/src/store/types.ts +19 -0
- package/src/tests/api.test.ts +112 -158
- package/src/types.ts +14 -26
- package/build/store/resolvers.js +0 -107
- package/build/store/resolvers.js.map +0 -7
- package/build-module/store/resolvers.js +0 -84
- package/build-module/store/resolvers.js.map +0 -7
- package/build-types/store/resolvers.d.ts +0 -47
- package/build-types/store/resolvers.d.ts.map +0 -1
- package/src/store/resolvers.ts +0 -151
- package/src/store/tests/resolvers.test.ts +0 -642
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -25,10 +25,10 @@ const { getAbilities, getAbility, executeAbility } = wp.abilities;
|
|
|
25
25
|
// or import { getAbilities, getAbility, executeAbility } from '@wordpress/abilities'; depending on your setup
|
|
26
26
|
|
|
27
27
|
// Get all abilities
|
|
28
|
-
const abilities =
|
|
28
|
+
const abilities = getAbilities();
|
|
29
29
|
|
|
30
30
|
// Get a specific ability
|
|
31
|
-
const ability =
|
|
31
|
+
const ability = getAbility( 'my-plugin/my-ability' );
|
|
32
32
|
|
|
33
33
|
// Execute an ability
|
|
34
34
|
const result = await executeAbility( 'my-plugin/my-ability', {
|
|
@@ -77,37 +77,37 @@ function MyComponent() {
|
|
|
77
77
|
|
|
78
78
|
### Functions
|
|
79
79
|
|
|
80
|
-
#### `getAbilities( args: AbilitiesQueryArgs = {} ):
|
|
80
|
+
#### `getAbilities( args: AbilitiesQueryArgs = {} ): Ability[]`
|
|
81
81
|
|
|
82
|
-
Returns all registered abilities. Optionally filter by category slug.
|
|
82
|
+
Returns all registered abilities. Optionally filter by category slug.
|
|
83
83
|
|
|
84
84
|
```javascript
|
|
85
85
|
// Get all abilities
|
|
86
|
-
const abilities =
|
|
86
|
+
const abilities = getAbilities();
|
|
87
87
|
console.log( `Found ${ abilities.length } abilities` );
|
|
88
88
|
|
|
89
89
|
// Get abilities in a specific category
|
|
90
|
-
const dataAbilities =
|
|
90
|
+
const dataAbilities = getAbilities( { category: 'data-retrieval' } );
|
|
91
91
|
console.log( `Found ${ dataAbilities.length } data retrieval abilities` );
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
#### `getAbility( name: string ):
|
|
94
|
+
#### `getAbility( name: string ): Ability | undefined`
|
|
95
95
|
|
|
96
|
-
Returns a specific ability by name, or
|
|
96
|
+
Returns a specific ability by name, or undefined if not found.
|
|
97
97
|
|
|
98
98
|
```javascript
|
|
99
|
-
const ability =
|
|
99
|
+
const ability = getAbility( 'my-plugin/create-post' );
|
|
100
100
|
if ( ability ) {
|
|
101
101
|
console.log( `Found ability: ${ ability.label }` );
|
|
102
102
|
}
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
#### `getAbilityCategories():
|
|
105
|
+
#### `getAbilityCategories(): AbilityCategory[]`
|
|
106
106
|
|
|
107
107
|
Returns all registered ability categories. Categories are used to organize abilities into logical groups.
|
|
108
108
|
|
|
109
109
|
```javascript
|
|
110
|
-
const categories =
|
|
110
|
+
const categories = getAbilityCategories();
|
|
111
111
|
console.log( `Found ${ categories.length } categories` );
|
|
112
112
|
|
|
113
113
|
categories.forEach( ( category ) => {
|
|
@@ -115,26 +115,26 @@ categories.forEach( ( category ) => {
|
|
|
115
115
|
} );
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
#### `getAbilityCategory( slug: string ):
|
|
118
|
+
#### `getAbilityCategory( slug: string ): AbilityCategory | undefined`
|
|
119
119
|
|
|
120
|
-
Returns a specific ability category by slug, or
|
|
120
|
+
Returns a specific ability category by slug, or undefined if not found.
|
|
121
121
|
|
|
122
122
|
```javascript
|
|
123
|
-
const category =
|
|
123
|
+
const category = getAbilityCategory( 'data-retrieval' );
|
|
124
124
|
if ( category ) {
|
|
125
125
|
console.log( `Found category: ${ category.label }` );
|
|
126
126
|
console.log( `Description: ${ category.description }` );
|
|
127
127
|
}
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
#### `registerAbility( ability: Ability ):
|
|
130
|
+
#### `registerAbility( ability: Ability ): void`
|
|
131
131
|
|
|
132
132
|
Registers a client-side ability. Client abilities are executed locally in the browser and must include a callback function and a valid category.
|
|
133
133
|
|
|
134
134
|
```javascript
|
|
135
135
|
import { registerAbility } from '@wordpress/abilities';
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
registerAbility( {
|
|
138
138
|
name: 'my-plugin/navigate',
|
|
139
139
|
label: 'Navigate to URL',
|
|
140
140
|
description: 'Navigates to a URL within WordPress admin',
|
|
@@ -153,17 +153,7 @@ await registerAbility( {
|
|
|
153
153
|
} );
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
#### `
|
|
157
|
-
|
|
158
|
-
Unregisters a client-side ability from the store.
|
|
159
|
-
|
|
160
|
-
```javascript
|
|
161
|
-
import { unregisterAbility } from '@wordpress/abilities';
|
|
162
|
-
|
|
163
|
-
unregisterAbility( 'my-plugin/navigate' );
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
#### `registerAbilityCategory( slug: string, args: AbilityCategoryArgs ): Promise<void>`
|
|
156
|
+
#### `registerAbilityCategory( slug: string, args: AbilityCategoryArgs ): void`
|
|
167
157
|
|
|
168
158
|
Registers a client-side ability category. This is useful when registering client-side abilities that introduce new categories not defined by the server.
|
|
169
159
|
|
|
@@ -171,13 +161,13 @@ Registers a client-side ability category. This is useful when registering client
|
|
|
171
161
|
import { registerAbilityCategory } from '@wordpress/abilities';
|
|
172
162
|
|
|
173
163
|
// Register a new category
|
|
174
|
-
|
|
164
|
+
registerAbilityCategory( 'block-editor', {
|
|
175
165
|
label: 'Block Editor',
|
|
176
166
|
description: 'Abilities for interacting with the WordPress block editor',
|
|
177
167
|
} );
|
|
178
168
|
|
|
179
169
|
// Register a category with optional metadata
|
|
180
|
-
|
|
170
|
+
registerAbilityCategory( 'custom-category', {
|
|
181
171
|
label: 'Custom Category',
|
|
182
172
|
description: 'A category for custom abilities',
|
|
183
173
|
meta: {
|
|
@@ -186,7 +176,7 @@ await registerAbilityCategory( 'custom-category', {
|
|
|
186
176
|
} );
|
|
187
177
|
|
|
188
178
|
// Then register abilities using the new category
|
|
189
|
-
|
|
179
|
+
registerAbility( {
|
|
190
180
|
name: 'my-plugin/insert-block',
|
|
191
181
|
label: 'Insert Block',
|
|
192
182
|
description: 'Inserts a block into the editor',
|
|
@@ -208,20 +198,22 @@ import { unregisterAbilityCategory } from '@wordpress/abilities';
|
|
|
208
198
|
unregisterAbilityCategory( 'block-editor' );
|
|
209
199
|
```
|
|
210
200
|
|
|
211
|
-
#### `
|
|
212
|
-
|
|
213
|
-
Executes an ability with optional input parameters. The HTTP method is automatically determined based on the ability's annotations:
|
|
201
|
+
#### `unregisterAbility( name: string ): void`
|
|
214
202
|
|
|
215
|
-
-
|
|
216
|
-
- regular abilities use POST (write operations)
|
|
203
|
+
Unregisters a client-side ability from the store.
|
|
217
204
|
|
|
218
205
|
```javascript
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
206
|
+
import { unregisterAbility } from '@wordpress/abilities';
|
|
207
|
+
|
|
208
|
+
unregisterAbility( 'my-plugin/navigate' );
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### `executeAbility( name: string, input?: Record<string, any> ): Promise<any>`
|
|
223
212
|
|
|
224
|
-
|
|
213
|
+
Executes an ability with optional input parameters.
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
// Execute an ability
|
|
225
217
|
const result = await executeAbility( 'my-plugin/create-item', {
|
|
226
218
|
title: 'New Item',
|
|
227
219
|
content: 'Item content',
|
package/build/api.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// packages/abilities/src/api.ts
|
|
@@ -42,40 +32,42 @@ __export(api_exports, {
|
|
|
42
32
|
});
|
|
43
33
|
module.exports = __toCommonJS(api_exports);
|
|
44
34
|
var import_data = require("@wordpress/data");
|
|
45
|
-
var import_api_fetch = __toESM(require("@wordpress/api-fetch"));
|
|
46
|
-
var import_url = require("@wordpress/url");
|
|
47
35
|
var import_i18n = require("@wordpress/i18n");
|
|
48
36
|
var import_store = require("./store");
|
|
49
37
|
var import_validation = require("./validation");
|
|
50
|
-
|
|
51
|
-
return
|
|
38
|
+
function getAbilities(args = {}) {
|
|
39
|
+
return (0, import_data.select)(import_store.store).getAbilities(args);
|
|
52
40
|
}
|
|
53
|
-
|
|
54
|
-
return
|
|
41
|
+
function getAbility(name) {
|
|
42
|
+
return (0, import_data.select)(import_store.store).getAbility(name);
|
|
55
43
|
}
|
|
56
|
-
|
|
57
|
-
return
|
|
44
|
+
function getAbilityCategories() {
|
|
45
|
+
return (0, import_data.select)(import_store.store).getAbilityCategories();
|
|
58
46
|
}
|
|
59
|
-
|
|
60
|
-
return
|
|
47
|
+
function getAbilityCategory(slug) {
|
|
48
|
+
return (0, import_data.select)(import_store.store).getAbilityCategory(slug);
|
|
61
49
|
}
|
|
62
|
-
|
|
63
|
-
|
|
50
|
+
function registerAbility(ability) {
|
|
51
|
+
(0, import_data.dispatch)(import_store.store).registerAbility(ability);
|
|
64
52
|
}
|
|
65
53
|
function unregisterAbility(name) {
|
|
66
54
|
(0, import_data.dispatch)(import_store.store).unregisterAbility(name);
|
|
67
55
|
}
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
function registerAbilityCategory(slug, args) {
|
|
57
|
+
(0, import_data.dispatch)(import_store.store).registerAbilityCategory(slug, args);
|
|
70
58
|
}
|
|
71
59
|
function unregisterAbilityCategory(slug) {
|
|
72
60
|
(0, import_data.dispatch)(import_store.store).unregisterAbilityCategory(slug);
|
|
73
61
|
}
|
|
74
|
-
async function
|
|
62
|
+
async function executeAbility(name, input) {
|
|
63
|
+
const ability = getAbility(name);
|
|
64
|
+
if (!ability) {
|
|
65
|
+
throw new Error((0, import_i18n.sprintf)("Ability not found: %s", name));
|
|
66
|
+
}
|
|
75
67
|
if (!ability.callback) {
|
|
76
68
|
throw new Error(
|
|
77
69
|
(0, import_i18n.sprintf)(
|
|
78
|
-
"
|
|
70
|
+
'Ability "%s" is missing callback. Please ensure the ability is properly registered.',
|
|
79
71
|
ability.name
|
|
80
72
|
)
|
|
81
73
|
);
|
|
@@ -112,10 +104,7 @@ async function executeClientAbility(ability, input) {
|
|
|
112
104
|
try {
|
|
113
105
|
result = await ability.callback(input);
|
|
114
106
|
} catch (error) {
|
|
115
|
-
console.error(
|
|
116
|
-
`Error executing client ability ${ability.name}:`,
|
|
117
|
-
error
|
|
118
|
-
);
|
|
107
|
+
console.error(`Error executing ability ${ability.name}:`, error);
|
|
119
108
|
throw error;
|
|
120
109
|
}
|
|
121
110
|
if (ability.output_schema) {
|
|
@@ -138,42 +127,6 @@ async function executeClientAbility(ability, input) {
|
|
|
138
127
|
}
|
|
139
128
|
return result;
|
|
140
129
|
}
|
|
141
|
-
async function executeServerAbility(ability, input) {
|
|
142
|
-
let method = "POST";
|
|
143
|
-
if (!!ability.meta?.annotations?.readonly) {
|
|
144
|
-
method = "GET";
|
|
145
|
-
} else if (!!ability.meta?.annotations?.destructive && !!ability.meta?.annotations?.idempotent) {
|
|
146
|
-
method = "DELETE";
|
|
147
|
-
}
|
|
148
|
-
let path = `/wp-abilities/v1/abilities/${ability.name}/run`;
|
|
149
|
-
const options = {
|
|
150
|
-
method
|
|
151
|
-
};
|
|
152
|
-
if (["GET", "DELETE"].includes(method) && input !== null) {
|
|
153
|
-
path = (0, import_url.addQueryArgs)(path, { input });
|
|
154
|
-
} else if (method === "POST" && input !== null) {
|
|
155
|
-
options.data = { input };
|
|
156
|
-
}
|
|
157
|
-
try {
|
|
158
|
-
return await (0, import_api_fetch.default)({
|
|
159
|
-
path,
|
|
160
|
-
...options
|
|
161
|
-
});
|
|
162
|
-
} catch (error) {
|
|
163
|
-
console.error(`Error executing ability ${ability.name}:`, error);
|
|
164
|
-
throw error;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
async function executeAbility(name, input) {
|
|
168
|
-
const ability = await getAbility(name);
|
|
169
|
-
if (!ability) {
|
|
170
|
-
throw new Error((0, import_i18n.sprintf)("Ability not found: %s", name));
|
|
171
|
-
}
|
|
172
|
-
if (ability.callback) {
|
|
173
|
-
return executeClientAbility(ability, input);
|
|
174
|
-
}
|
|
175
|
-
return executeServerAbility(ability, input);
|
|
176
|
-
}
|
|
177
130
|
// Annotate the CommonJS export names for ESM import in node:
|
|
178
131
|
0 && (module.exports = {
|
|
179
132
|
executeAbility,
|
package/build/api.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/api.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { dispatch,
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { dispatch, select } from '@wordpress/data';\nimport { sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport { store } from './store';\nimport type {\n\tAbility,\n\tAbilityCategory,\n\tAbilityCategoryArgs,\n\tAbilitiesQueryArgs,\n\tAbilityInput,\n\tAbilityOutput,\n} from './types';\nimport { validateValueFromSchema } from './validation';\n\n/**\n * Get all available abilities with optional filtering.\n *\n * @param args Optional query arguments to filter. Defaults to empty object.\n * @return Array of abilities.\n */\nexport function getAbilities( args: AbilitiesQueryArgs = {} ): Ability[] {\n\treturn select( store ).getAbilities( args );\n}\n\n/**\n * Get a specific ability by name.\n *\n * @param name The ability name.\n * @return The ability or undefined if not found.\n */\nexport function getAbility( name: string ): Ability | undefined {\n\treturn select( store ).getAbility( name );\n}\n\n/**\n * Get all available ability categories.\n *\n * @return Array of categories.\n */\nexport function getAbilityCategories(): AbilityCategory[] {\n\treturn select( store ).getAbilityCategories();\n}\n\n/**\n * Get a specific ability category by slug.\n *\n * @param slug The category slug.\n * @return The category or undefined if not found.\n */\nexport function getAbilityCategory(\n\tslug: string\n): AbilityCategory | undefined {\n\treturn select( store ).getAbilityCategory( slug );\n}\n\n/**\n * Register a client-side ability.\n *\n * Client abilities are executed locally in the browser and must include\n * a callback function. The ability will be validated by the store action,\n * and an error will be thrown if validation fails.\n *\n * The category must already be registered before registering abilities.\n *\n * @param ability The ability definition including callback.\n * @throws {Error} If the ability fails validation.\n *\n * @example\n * ```js\n * registerAbility({\n * name: 'my-plugin/navigate',\n * label: 'Navigate to URL',\n * description: 'Navigates to a URL within WordPress admin',\n * category: 'navigation',\n * input_schema: {\n * type: 'object',\n * properties: {\n * url: { type: 'string' }\n * },\n * required: ['url']\n * },\n * callback: async ({ url }) => {\n * window.location.href = url;\n * return { success: true };\n * }\n * });\n * ```\n */\nexport function registerAbility( ability: Ability ): void {\n\tdispatch( store ).registerAbility( ability );\n}\n\n/**\n * Unregister an ability from the store.\n *\n * Remove a client-side ability from the store.\n * Note: This will return an error for server-side abilities.\n *\n * @param name The ability name to unregister.\n */\nexport function unregisterAbility( name: string ): void {\n\tdispatch( store ).unregisterAbility( name );\n}\n\n/**\n * Register a client-side ability category.\n *\n * Categories registered on the client are stored alongside server-side categories\n * in the same store and can be used when registering client side abilities.\n * This is useful when registering client-side abilities that introduce new\n * categories not defined by the server.\n *\n * @param slug Category slug (lowercase alphanumeric with dashes only).\n * @param args Category arguments (label, description, optional meta).\n * @throws {Error} If the category fails validation.\n *\n * @example\n * ```js\n * // Register a new category for block editor abilities\n * registerAbilityCategory('block-editor', {\n * label: 'Block Editor',\n * description: 'Abilities for interacting with the WordPress block editor'\n * });\n *\n * // Then register abilities using this category\n * registerAbility({\n * name: 'my-plugin/insert-block',\n * label: 'Insert Block',\n * description: 'Inserts a block into the editor',\n * category: 'block-editor',\n * callback: async ({ blockType }) => {\n * // Implementation\n * return { success: true };\n * }\n * });\n * ```\n */\nexport function registerAbilityCategory(\n\tslug: string,\n\targs: AbilityCategoryArgs\n): void {\n\tdispatch( store ).registerAbilityCategory( slug, args );\n}\n\n/**\n * Unregister an ability category.\n *\n * Removes a category from the store.\n *\n * @param slug The category slug to unregister.\n *\n * @example\n * ```js\n * unregisterAbilityCategory('block-editor');\n * ```\n */\nexport function unregisterAbilityCategory( slug: string ): void {\n\tdispatch( store ).unregisterAbilityCategory( slug );\n}\n\n/**\n * Execute an ability.\n *\n * Executes abilities with validation for client-side abilities only.\n * Server abilities bypass validation as it's handled on the server.\n *\n * @param name The ability name.\n * @param input Optional input parameters for the ability.\n * @return Promise resolving to the ability execution result.\n * @throws Error if the ability is not found or execution fails.\n */\nexport async function executeAbility(\n\tname: string,\n\tinput?: AbilityInput\n): Promise< AbilityOutput > {\n\tconst ability = getAbility( name );\n\tif ( ! ability ) {\n\t\tthrow new Error( sprintf( 'Ability not found: %s', name ) );\n\t}\n\n\tif ( ! ability.callback ) {\n\t\tthrow new Error(\n\t\t\tsprintf(\n\t\t\t\t'Ability \"%s\" is missing callback. Please ensure the ability is properly registered.',\n\t\t\t\tability.name\n\t\t\t)\n\t\t);\n\t}\n\n\t// Check permission callback if defined\n\tif ( ability.permissionCallback ) {\n\t\tconst hasPermission = await ability.permissionCallback( input );\n\t\tif ( ! hasPermission ) {\n\t\t\tconst error = new Error(\n\t\t\t\tsprintf( 'Permission denied for ability: %s', ability.name )\n\t\t\t);\n\t\t\t( error as any ).code = 'ability_permission_denied';\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Validate input\n\tif ( ability.input_schema ) {\n\t\tconst inputValidation = validateValueFromSchema(\n\t\t\tinput,\n\t\t\tability.input_schema,\n\t\t\t'input'\n\t\t);\n\t\tif ( inputValidation !== true ) {\n\t\t\tconst error = new Error(\n\t\t\t\tsprintf(\n\t\t\t\t\t'Ability \"%1$s\" has invalid input. Reason: %2$s',\n\t\t\t\t\tability.name,\n\t\t\t\t\tinputValidation\n\t\t\t\t)\n\t\t\t);\n\t\t\t( error as any ).code = 'ability_invalid_input';\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// Execute the ability\n\tlet result: AbilityOutput;\n\ttry {\n\t\tresult = await ability.callback( input );\n\t} catch ( error ) {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error( `Error executing ability ${ ability.name }:`, error );\n\t\tthrow error;\n\t}\n\n\t// Validate output\n\tif ( ability.output_schema ) {\n\t\tconst outputValidation = validateValueFromSchema(\n\t\t\tresult,\n\t\t\tability.output_schema,\n\t\t\t'output'\n\t\t);\n\t\tif ( outputValidation !== true ) {\n\t\t\tconst error = new Error(\n\t\t\t\tsprintf(\n\t\t\t\t\t'Ability \"%1$s\" has invalid output. Reason: %2$s',\n\t\t\t\t\tability.name,\n\t\t\t\t\toutputValidation\n\t\t\t\t)\n\t\t\t);\n\t\t\t( error as any ).code = 'ability_invalid_output';\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\treturn result;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiC;AACjC,kBAAwB;AAKxB,mBAAsB;AAStB,wBAAwC;AAQjC,SAAS,aAAc,OAA2B,CAAC,GAAe;AACxE,aAAO,oBAAQ,kBAAM,EAAE,aAAc,IAAK;AAC3C;AAQO,SAAS,WAAY,MAAoC;AAC/D,aAAO,oBAAQ,kBAAM,EAAE,WAAY,IAAK;AACzC;AAOO,SAAS,uBAA0C;AACzD,aAAO,oBAAQ,kBAAM,EAAE,qBAAqB;AAC7C;AAQO,SAAS,mBACf,MAC8B;AAC9B,aAAO,oBAAQ,kBAAM,EAAE,mBAAoB,IAAK;AACjD;AAmCO,SAAS,gBAAiB,SAAyB;AACzD,4BAAU,kBAAM,EAAE,gBAAiB,OAAQ;AAC5C;AAUO,SAAS,kBAAmB,MAAqB;AACvD,4BAAU,kBAAM,EAAE,kBAAmB,IAAK;AAC3C;AAmCO,SAAS,wBACf,MACA,MACO;AACP,4BAAU,kBAAM,EAAE,wBAAyB,MAAM,IAAK;AACvD;AAcO,SAAS,0BAA2B,MAAqB;AAC/D,4BAAU,kBAAM,EAAE,0BAA2B,IAAK;AACnD;AAaA,eAAsB,eACrB,MACA,OAC2B;AAC3B,QAAM,UAAU,WAAY,IAAK;AACjC,MAAK,CAAE,SAAU;AAChB,UAAM,IAAI,UAAO,qBAAS,yBAAyB,IAAK,CAAE;AAAA,EAC3D;AAEA,MAAK,CAAE,QAAQ,UAAW;AACzB,UAAM,IAAI;AAAA,UACT;AAAA,QACC;AAAA,QACA,QAAQ;AAAA,MACT;AAAA,IACD;AAAA,EACD;AAGA,MAAK,QAAQ,oBAAqB;AACjC,UAAM,gBAAgB,MAAM,QAAQ,mBAAoB,KAAM;AAC9D,QAAK,CAAE,eAAgB;AACtB,YAAM,QAAQ,IAAI;AAAA,YACjB,qBAAS,qCAAqC,QAAQ,IAAK;AAAA,MAC5D;AACA,MAAE,MAAe,OAAO;AACxB,YAAM;AAAA,IACP;AAAA,EACD;AAGA,MAAK,QAAQ,cAAe;AAC3B,UAAM,sBAAkB;AAAA,MACvB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACD;AACA,QAAK,oBAAoB,MAAO;AAC/B,YAAM,QAAQ,IAAI;AAAA,YACjB;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,QACD;AAAA,MACD;AACA,MAAE,MAAe,OAAO;AACxB,YAAM;AAAA,IACP;AAAA,EACD;AAGA,MAAI;AACJ,MAAI;AACH,aAAS,MAAM,QAAQ,SAAU,KAAM;AAAA,EACxC,SAAU,OAAQ;AAEjB,YAAQ,MAAO,2BAA4B,QAAQ,IAAK,KAAK,KAAM;AACnE,UAAM;AAAA,EACP;AAGA,MAAK,QAAQ,eAAgB;AAC5B,UAAM,uBAAmB;AAAA,MACxB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACD;AACA,QAAK,qBAAqB,MAAO;AAChC,YAAM,QAAQ,IAAI;AAAA,YACjB;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,QACD;AAAA,MACD;AACA,MAAE,MAAe,OAAO;AACxB,YAAM;AAAA,IACP;AAAA,EACD;AAEA,SAAO;AACR;",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
package/build/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress Abilities API Client\n *\n * This package provides a client for interacting with the\n * WordPress Abilities API, allowing you to list, retrieve, and execute\n * abilities from client-side code.\n *\n * @package\n */\n\n/**\n * Public API functions\n */\nexport {\n\tgetAbilities,\n\tgetAbility,\n\tgetAbilityCategories,\n\tgetAbilityCategory,\n\texecuteAbility,\n\tregisterAbility,\n\tunregisterAbility,\n\tregisterAbilityCategory,\n\tunregisterAbilityCategory,\n} from './api';\n\n/**\n * The store can be used directly with @wordpress/data via selectors\n * in React components with useSelect.\n *\n * @example\n * ```js\n * import { useSelect } from '@wordpress/data';\n * import { store as abilitiesStore } from '@wordpress/abilities';\n *\n * function MyComponent() {\n * const abilities = useSelect(\n * (select) => select(abilitiesStore).getAbilities(),\n * []\n * );\n * // Use abilities...\n * }\n * ```\n */\nexport { store } from './store';\n\n/**\n * Type definitions\n */\nexport type {\n\tAbility,\n\tAbilityCategory,\n\tAbilityCategoryArgs,\n\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,iBAUO;AAoBP,mBAAsB;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress Abilities API Client\n *\n * This package provides a client for interacting with the\n * WordPress Abilities API, allowing you to list, retrieve, and execute\n * abilities from client-side code.\n *\n * @package\n */\n\n/**\n * Public API functions\n */\nexport {\n\tgetAbilities,\n\tgetAbility,\n\tgetAbilityCategories,\n\tgetAbilityCategory,\n\texecuteAbility,\n\tregisterAbility,\n\tunregisterAbility,\n\tregisterAbilityCategory,\n\tunregisterAbilityCategory,\n} from './api';\n\n/**\n * The store can be used directly with @wordpress/data via selectors\n * in React components with useSelect.\n *\n * @example\n * ```js\n * import { useSelect } from '@wordpress/data';\n * import { store as abilitiesStore } from '@wordpress/abilities';\n *\n * function MyComponent() {\n * const abilities = useSelect(\n * (select) => select(abilitiesStore).getAbilities(),\n * []\n * );\n * // Use abilities...\n * }\n * ```\n */\nexport { store } from './store';\n\n/**\n * Type definitions\n */\nexport type {\n\tAbility,\n\tAbilityCategory,\n\tAbilityCategoryArgs,\n\tAbilitiesQueryArgs,\n\tAbilityCallback,\n\tPermissionCallback,\n\tAbilityInput,\n\tAbilityOutput,\n\tValidationError,\n} from './types';\n\n/**\n * Validation utilities\n */\nexport { validateValueFromSchema } from './validation';\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,iBAUO;AAoBP,mBAAsB;AAoBtB,wBAAwC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/store/actions.js
CHANGED
|
@@ -20,8 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// packages/abilities/src/store/actions.ts
|
|
21
21
|
var actions_exports = {};
|
|
22
22
|
__export(actions_exports, {
|
|
23
|
-
receiveAbilities: () => receiveAbilities,
|
|
24
|
-
receiveCategories: () => receiveCategories,
|
|
25
23
|
registerAbility: () => registerAbility,
|
|
26
24
|
registerAbilityCategory: () => registerAbilityCategory,
|
|
27
25
|
unregisterAbility: () => unregisterAbility,
|
|
@@ -29,26 +27,24 @@ __export(actions_exports, {
|
|
|
29
27
|
});
|
|
30
28
|
module.exports = __toCommonJS(actions_exports);
|
|
31
29
|
var import_i18n = require("@wordpress/i18n");
|
|
32
|
-
var import_data = require("@wordpress/data");
|
|
33
30
|
var import_constants = require("./constants");
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
31
|
+
function filterAnnotations(sourceAnnotations, allowedKeys) {
|
|
32
|
+
const annotations = {};
|
|
33
|
+
if (sourceAnnotations) {
|
|
34
|
+
for (const key of allowedKeys) {
|
|
35
|
+
if (sourceAnnotations[key] !== void 0) {
|
|
36
|
+
annotations[key] = sourceAnnotations[key];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return annotations;
|
|
45
41
|
}
|
|
46
42
|
function registerAbility(ability) {
|
|
47
|
-
return
|
|
43
|
+
return ({ select, dispatch }) => {
|
|
48
44
|
if (!ability.name) {
|
|
49
45
|
throw new Error("Ability name is required");
|
|
50
46
|
}
|
|
51
|
-
if (
|
|
47
|
+
if (!import_constants.ABILITY_NAME_PATTERN.test(ability.name)) {
|
|
52
48
|
throw new Error(
|
|
53
49
|
'Ability name must be a string containing a namespace prefix, i.e. "my-plugin/my-ability". It can only contain lowercase alphanumeric characters, dashes and the forward slash.'
|
|
54
50
|
);
|
|
@@ -68,16 +64,16 @@ function registerAbility(ability) {
|
|
|
68
64
|
(0, import_i18n.sprintf)('Ability "%s" must have a category', ability.name)
|
|
69
65
|
);
|
|
70
66
|
}
|
|
71
|
-
if (
|
|
67
|
+
if (!import_constants.CATEGORY_SLUG_PATTERN.test(ability.category)) {
|
|
72
68
|
throw new Error(
|
|
73
69
|
(0, import_i18n.sprintf)(
|
|
74
|
-
'Ability "%1$s" has an invalid category. Category must be lowercase alphanumeric with dashes only Got: "%2$s"',
|
|
70
|
+
'Ability "%1$s" has an invalid category. Category must be lowercase alphanumeric with dashes only. Got: "%2$s"',
|
|
75
71
|
ability.name,
|
|
76
72
|
ability.category
|
|
77
73
|
)
|
|
78
74
|
);
|
|
79
75
|
}
|
|
80
|
-
const categories =
|
|
76
|
+
const categories = select.getAbilityCategories();
|
|
81
77
|
const existingCategory = categories.find(
|
|
82
78
|
(cat) => cat.slug === ability.category
|
|
83
79
|
);
|
|
@@ -104,9 +100,23 @@ function registerAbility(ability) {
|
|
|
104
100
|
(0, import_i18n.sprintf)('Ability "%s" is already registered', ability.name)
|
|
105
101
|
);
|
|
106
102
|
}
|
|
103
|
+
const annotations = filterAnnotations(ability.meta?.annotations, [
|
|
104
|
+
"readonly",
|
|
105
|
+
"destructive",
|
|
106
|
+
"idempotent",
|
|
107
|
+
"serverRegistered",
|
|
108
|
+
"clientRegistered"
|
|
109
|
+
]);
|
|
110
|
+
if (!annotations.serverRegistered) {
|
|
111
|
+
annotations.clientRegistered = true;
|
|
112
|
+
}
|
|
113
|
+
const meta = { annotations };
|
|
107
114
|
dispatch({
|
|
108
115
|
type: import_constants.REGISTER_ABILITY,
|
|
109
|
-
ability
|
|
116
|
+
ability: {
|
|
117
|
+
...ability,
|
|
118
|
+
meta
|
|
119
|
+
}
|
|
110
120
|
});
|
|
111
121
|
};
|
|
112
122
|
}
|
|
@@ -117,16 +127,15 @@ function unregisterAbility(name) {
|
|
|
117
127
|
};
|
|
118
128
|
}
|
|
119
129
|
function registerAbilityCategory(slug, args) {
|
|
120
|
-
return
|
|
130
|
+
return ({ select, dispatch }) => {
|
|
121
131
|
if (!slug) {
|
|
122
132
|
throw new Error("Category slug is required");
|
|
123
133
|
}
|
|
124
|
-
if (
|
|
134
|
+
if (!import_constants.CATEGORY_SLUG_PATTERN.test(slug)) {
|
|
125
135
|
throw new Error(
|
|
126
136
|
"Category slug must contain only lowercase alphanumeric characters and dashes."
|
|
127
137
|
);
|
|
128
138
|
}
|
|
129
|
-
await (0, import_data.resolveSelect)(import_constants.STORE_NAME).getAbilityCategories();
|
|
130
139
|
const existingCategory = select.getAbilityCategory(slug);
|
|
131
140
|
if (existingCategory) {
|
|
132
141
|
throw new Error(
|
|
@@ -148,16 +157,19 @@ function registerAbilityCategory(slug, args) {
|
|
|
148
157
|
"The category properties should provide a valid `meta` object."
|
|
149
158
|
);
|
|
150
159
|
}
|
|
160
|
+
const annotations = filterAnnotations(args.meta?.annotations, [
|
|
161
|
+
"serverRegistered",
|
|
162
|
+
"clientRegistered"
|
|
163
|
+
]);
|
|
164
|
+
if (!annotations.serverRegistered) {
|
|
165
|
+
annotations.clientRegistered = true;
|
|
166
|
+
}
|
|
167
|
+
const meta = { annotations };
|
|
151
168
|
const category = {
|
|
152
169
|
slug,
|
|
153
170
|
label: args.label,
|
|
154
171
|
description: args.description,
|
|
155
|
-
meta
|
|
156
|
-
...args.meta || {},
|
|
157
|
-
// Internal implementation note: Client-registered categories will have `meta._clientRegistered` set to `true` to differentiate them from server-fetched categories.
|
|
158
|
-
// This is used internally by the resolver to determine whether to fetch categories from the server.
|
|
159
|
-
_clientRegistered: true
|
|
160
|
-
}
|
|
172
|
+
meta
|
|
161
173
|
};
|
|
162
174
|
dispatch({
|
|
163
175
|
type: import_constants.REGISTER_ABILITY_CATEGORY,
|
|
@@ -173,8 +185,6 @@ function unregisterAbilityCategory(slug) {
|
|
|
173
185
|
}
|
|
174
186
|
// Annotate the CommonJS export names for ESM import in node:
|
|
175
187
|
0 && (module.exports = {
|
|
176
|
-
receiveAbilities,
|
|
177
|
-
receiveCategories,
|
|
178
188
|
registerAbility,
|
|
179
189
|
registerAbilityCategory,
|
|
180
190
|
unregisterAbility,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/store/actions.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { sprintf } from '@wordpress/i18n';\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport type { Ability, AbilityCategory, AbilityCategoryArgs } from '../types';\nimport {\n\tREGISTER_ABILITY,\n\tUNREGISTER_ABILITY,\n\tREGISTER_ABILITY_CATEGORY,\n\tUNREGISTER_ABILITY_CATEGORY,\n\tABILITY_NAME_PATTERN,\n\tCATEGORY_SLUG_PATTERN,\n} from './constants';\n\ntype AbilityAnnotations = NonNullable< Ability[ 'meta' ] >[ 'annotations' ];\n\n/**\n * Filters annotations to only include allowed keys with non-null values.\n *\n * @param sourceAnnotations The source annotations object to filter.\n * @param allowedKeys Array of annotation keys to include.\n * @return Filtered annotations object.\n */\nfunction filterAnnotations< K extends keyof NonNullable< AbilityAnnotations > >(\n\tsourceAnnotations: Record< string, boolean > | undefined,\n\tallowedKeys: readonly K[]\n): NonNullable< AbilityAnnotations > {\n\tconst annotations: NonNullable< AbilityAnnotations > = {};\n\n\tif ( sourceAnnotations ) {\n\t\tfor ( const key of allowedKeys ) {\n\t\t\tif ( sourceAnnotations[ key ] !== undefined ) {\n\t\t\t\tannotations[ key ] = sourceAnnotations[ key ];\n\t\t\t}\n\t\t}\n\t}\n\treturn annotations;\n}\n\n/**\n * Registers an ability in the store.\n *\n * This action validates the ability before registration. If validation fails,\n * an error will be thrown.\n *\n * @param ability The ability to register.\n * @return Action object or function.\n * @throws {Error} If validation fails.\n */\nexport function registerAbility( ability: Ability ) {\n\t// @ts-expect-error - registry types are not yet available\n\treturn ( { select, dispatch } ) => {\n\t\tif ( ! ability.name ) {\n\t\t\tthrow new Error( 'Ability name is required' );\n\t\t}\n\n\t\t// Validate name format matches server implementation\n\t\tif ( ! ABILITY_NAME_PATTERN.test( ability.name ) ) {\n\t\t\tthrow new Error(\n\t\t\t\t'Ability name must be a string containing a namespace prefix, i.e. \"my-plugin/my-ability\". It can only contain lowercase alphanumeric characters, dashes and the forward slash.'\n\t\t\t);\n\t\t}\n\n\t\tif ( ! ability.label ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf( 'Ability \"%s\" must have a label', ability.name )\n\t\t\t);\n\t\t}\n\n\t\tif ( ! ability.description ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf( 'Ability \"%s\" must have a description', ability.name )\n\t\t\t);\n\t\t}\n\n\t\tif ( ! ability.category ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf( 'Ability \"%s\" must have a category', ability.name )\n\t\t\t);\n\t\t}\n\n\t\t// Validate category format\n\t\tif ( ! CATEGORY_SLUG_PATTERN.test( ability.category ) ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf(\n\t\t\t\t\t'Ability \"%1$s\" has an invalid category. Category must be lowercase alphanumeric with dashes only. Got: \"%2$s\"',\n\t\t\t\t\tability.name,\n\t\t\t\t\tability.category\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t// Check that the category exists\n\t\tconst categories = select.getAbilityCategories();\n\t\tconst existingCategory = categories.find(\n\t\t\t( cat: AbilityCategory ) => cat.slug === ability.category\n\t\t);\n\t\tif ( ! existingCategory ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf(\n\t\t\t\t\t'Ability \"%1$s\" references non-existent category \"%2$s\". Please register the category first.',\n\t\t\t\t\tability.name,\n\t\t\t\t\tability.category\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t// Client-side abilities must have a callback\n\t\tif ( ability.callback && typeof ability.callback !== 'function' ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf(\n\t\t\t\t\t'Ability \"%s\" has an invalid callback. Callback must be a function',\n\t\t\t\t\tability.name\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\t// Check if ability is already registered\n\t\tconst existingAbility = select.getAbility( ability.name );\n\t\tif ( existingAbility ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf( 'Ability \"%s\" is already registered', ability.name )\n\t\t\t);\n\t\t}\n\n\t\tconst annotations = filterAnnotations( ability.meta?.annotations, [\n\t\t\t'readonly',\n\t\t\t'destructive',\n\t\t\t'idempotent',\n\t\t\t'serverRegistered',\n\t\t\t'clientRegistered',\n\t\t] );\n\n\t\tif ( ! annotations.serverRegistered ) {\n\t\t\tannotations.clientRegistered = true;\n\t\t}\n\n\t\tconst meta = { annotations };\n\n\t\t// All validation passed, dispatch the registration action\n\t\tdispatch( {\n\t\t\ttype: REGISTER_ABILITY,\n\t\t\tability: {\n\t\t\t\t...ability,\n\t\t\t\tmeta,\n\t\t\t},\n\t\t} );\n\t};\n}\n\n/**\n * Returns an action object used to unregister a client-side ability.\n *\n * @param name The name of the ability to unregister.\n * @return Action object.\n */\nexport function unregisterAbility( name: string ) {\n\treturn {\n\t\ttype: UNREGISTER_ABILITY,\n\t\tname,\n\t};\n}\n\n/**\n * Registers a client-side ability category in the store.\n *\n * This action validates the category before registration. If validation fails,\n * an error will be thrown.\n *\n * @param slug The unique category slug identifier.\n * @param args Category arguments (label, description, optional meta).\n * @return Action object or function.\n * @throws {Error} If validation fails.\n */\nexport function registerAbilityCategory(\n\tslug: string,\n\targs: AbilityCategoryArgs\n) {\n\t// @ts-expect-error - registry types are not yet available\n\treturn ( { select, dispatch } ) => {\n\t\tif ( ! slug ) {\n\t\t\tthrow new Error( 'Category slug is required' );\n\t\t}\n\n\t\t// Validate slug format matches server implementation\n\t\tif ( ! CATEGORY_SLUG_PATTERN.test( slug ) ) {\n\t\t\tthrow new Error(\n\t\t\t\t'Category slug must contain only lowercase alphanumeric characters and dashes.'\n\t\t\t);\n\t\t}\n\n\t\t// Check for duplicates\n\t\tconst existingCategory = select.getAbilityCategory( slug );\n\t\tif ( existingCategory ) {\n\t\t\tthrow new Error(\n\t\t\t\tsprintf( 'Category \"%s\" is already registered.', slug )\n\t\t\t);\n\t\t}\n\n\t\t// Validate label presence and type (matches PHP empty() + is_string())\n\t\tif ( ! args.label || typeof args.label !== 'string' ) {\n\t\t\tthrow new Error(\n\t\t\t\t'The category properties must contain a `label` string.'\n\t\t\t);\n\t\t}\n\n\t\t// Validate description presence and type (matches PHP empty() + is_string())\n\t\tif ( ! args.description || typeof args.description !== 'string' ) {\n\t\t\tthrow new Error(\n\t\t\t\t'The category properties must contain a `description` string.'\n\t\t\t);\n\t\t}\n\n\t\tif (\n\t\t\targs.meta !== undefined &&\n\t\t\t( typeof args.meta !== 'object' || Array.isArray( args.meta ) )\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t'The category properties should provide a valid `meta` object.'\n\t\t\t);\n\t\t}\n\n\t\tconst annotations = filterAnnotations( args.meta?.annotations, [\n\t\t\t'serverRegistered',\n\t\t\t'clientRegistered',\n\t\t] );\n\n\t\tif ( ! annotations.serverRegistered ) {\n\t\t\tannotations.clientRegistered = true;\n\t\t}\n\n\t\tconst meta = { annotations };\n\t\tconst category: AbilityCategory = {\n\t\t\tslug,\n\t\t\tlabel: args.label,\n\t\t\tdescription: args.description,\n\t\t\tmeta,\n\t\t};\n\n\t\tdispatch( {\n\t\t\ttype: REGISTER_ABILITY_CATEGORY,\n\t\t\tcategory,\n\t\t} );\n\t};\n}\n\n/**\n * Returns an action object used to unregister a client-side ability category.\n *\n * @param slug The slug of the category to unregister.\n * @return Action object.\n */\nexport function unregisterAbilityCategory( slug: string ) {\n\treturn {\n\t\ttype: UNREGISTER_ABILITY_CATEGORY,\n\t\tslug,\n\t};\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/store/constants.js
CHANGED
|
@@ -20,11 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// packages/abilities/src/store/constants.ts
|
|
21
21
|
var constants_exports = {};
|
|
22
22
|
__export(constants_exports, {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
ENTITY_NAME_CATEGORIES: () => ENTITY_NAME_CATEGORIES,
|
|
26
|
-
RECEIVE_ABILITIES: () => RECEIVE_ABILITIES,
|
|
27
|
-
RECEIVE_CATEGORIES: () => RECEIVE_CATEGORIES,
|
|
23
|
+
ABILITY_NAME_PATTERN: () => ABILITY_NAME_PATTERN,
|
|
24
|
+
CATEGORY_SLUG_PATTERN: () => CATEGORY_SLUG_PATTERN,
|
|
28
25
|
REGISTER_ABILITY: () => REGISTER_ABILITY,
|
|
29
26
|
REGISTER_ABILITY_CATEGORY: () => REGISTER_ABILITY_CATEGORY,
|
|
30
27
|
STORE_NAME: () => STORE_NAME,
|
|
@@ -33,22 +30,16 @@ __export(constants_exports, {
|
|
|
33
30
|
});
|
|
34
31
|
module.exports = __toCommonJS(constants_exports);
|
|
35
32
|
var STORE_NAME = "core/abilities";
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var ENTITY_NAME_CATEGORIES = "ability-categories";
|
|
39
|
-
var RECEIVE_ABILITIES = "RECEIVE_ABILITIES";
|
|
33
|
+
var ABILITY_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/;
|
|
34
|
+
var CATEGORY_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
40
35
|
var REGISTER_ABILITY = "REGISTER_ABILITY";
|
|
41
36
|
var UNREGISTER_ABILITY = "UNREGISTER_ABILITY";
|
|
42
|
-
var RECEIVE_CATEGORIES = "RECEIVE_CATEGORIES";
|
|
43
37
|
var REGISTER_ABILITY_CATEGORY = "REGISTER_ABILITY_CATEGORY";
|
|
44
38
|
var UNREGISTER_ABILITY_CATEGORY = "UNREGISTER_ABILITY_CATEGORY";
|
|
45
39
|
// Annotate the CommonJS export names for ESM import in node:
|
|
46
40
|
0 && (module.exports = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
ENTITY_NAME_CATEGORIES,
|
|
50
|
-
RECEIVE_ABILITIES,
|
|
51
|
-
RECEIVE_CATEGORIES,
|
|
41
|
+
ABILITY_NAME_PATTERN,
|
|
42
|
+
CATEGORY_SLUG_PATTERN,
|
|
52
43
|
REGISTER_ABILITY,
|
|
53
44
|
REGISTER_ABILITY_CATEGORY,
|
|
54
45
|
STORE_NAME,
|