@wordpress/abilities 0.4.1-next.v.0 → 0.5.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/build/store/actions.cjs +8 -2
- package/build/store/actions.cjs.map +2 -2
- package/build/types.cjs.map +1 -1
- package/build-module/store/actions.mjs +8 -2
- package/build-module/store/actions.mjs.map +2 -2
- package/build-types/store/actions.d.ts.map +1 -1
- package/build-types/types.d.ts +2 -0
- package/build-types/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/store/actions.ts +8 -2
- package/src/store/tests/actions.test.ts +29 -0
- package/src/types.ts +2 -0
package/CHANGELOG.md
CHANGED
package/build/store/actions.cjs
CHANGED
|
@@ -110,7 +110,10 @@ function registerAbility(ability) {
|
|
|
110
110
|
if (!annotations.serverRegistered) {
|
|
111
111
|
annotations.clientRegistered = true;
|
|
112
112
|
}
|
|
113
|
-
const meta = {
|
|
113
|
+
const meta = {
|
|
114
|
+
...ability.meta || {},
|
|
115
|
+
annotations
|
|
116
|
+
};
|
|
114
117
|
dispatch({
|
|
115
118
|
type: import_constants.REGISTER_ABILITY,
|
|
116
119
|
ability: {
|
|
@@ -164,7 +167,10 @@ function registerAbilityCategory(slug, args) {
|
|
|
164
167
|
if (!annotations.serverRegistered) {
|
|
165
168
|
annotations.clientRegistered = true;
|
|
166
169
|
}
|
|
167
|
-
const meta = {
|
|
170
|
+
const meta = {
|
|
171
|
+
...args.meta || {},
|
|
172
|
+
annotations
|
|
173
|
+
};
|
|
168
174
|
const category = {
|
|
169
175
|
slug,
|
|
170
176
|
label: args.label,
|
|
@@ -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';\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 = {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAwB;AAMxB,uBAOO;AAWP,SAAS,kBACR,mBACA,aACoC;AACpC,QAAM,cAAiD,CAAC;AAExD,MAAK,mBAAoB;AACxB,eAAY,OAAO,aAAc;AAChC,UAAK,kBAAmB,GAAI,MAAM,QAAY;AAC7C,oBAAa,GAAI,IAAI,kBAAmB,GAAI;AAAA,MAC7C;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAYO,SAAS,gBAAiB,SAAmB;AAEnD,SAAO,CAAE,EAAE,QAAQ,SAAS,MAAO;AAClC,QAAK,CAAE,QAAQ,MAAO;AACrB,YAAM,IAAI,MAAO,0BAA2B;AAAA,IAC7C;AAGA,QAAK,CAAE,sCAAqB,KAAM,QAAQ,IAAK,GAAI;AAClD,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAEA,QAAK,CAAE,QAAQ,OAAQ;AACtB,YAAM,IAAI;AAAA,YACT,qBAAS,kCAAkC,QAAQ,IAAK;AAAA,MACzD;AAAA,IACD;AAEA,QAAK,CAAE,QAAQ,aAAc;AAC5B,YAAM,IAAI;AAAA,YACT,qBAAS,wCAAwC,QAAQ,IAAK;AAAA,MAC/D;AAAA,IACD;AAEA,QAAK,CAAE,QAAQ,UAAW;AACzB,YAAM,IAAI;AAAA,YACT,qBAAS,qCAAqC,QAAQ,IAAK;AAAA,MAC5D;AAAA,IACD;AAGA,QAAK,CAAE,uCAAsB,KAAM,QAAQ,QAAS,GAAI;AACvD,YAAM,IAAI;AAAA,YACT;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,UAAM,aAAa,OAAO,qBAAqB;AAC/C,UAAM,mBAAmB,WAAW;AAAA,MACnC,CAAE,QAA0B,IAAI,SAAS,QAAQ;AAAA,IAClD;AACA,QAAK,CAAE,kBAAmB;AACzB,YAAM,IAAI;AAAA,YACT;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,QAAK,QAAQ,YAAY,OAAO,QAAQ,aAAa,YAAa;AACjE,YAAM,IAAI;AAAA,YACT;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,UAAM,kBAAkB,OAAO,WAAY,QAAQ,IAAK;AACxD,QAAK,iBAAkB;AACtB,YAAM,IAAI;AAAA,YACT,qBAAS,sCAAsC,QAAQ,IAAK;AAAA,MAC7D;AAAA,IACD;AAEA,UAAM,cAAc,kBAAmB,QAAQ,MAAM,aAAa;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAE;AAEF,QAAK,CAAE,YAAY,kBAAmB;AACrC,kBAAY,mBAAmB;AAAA,IAChC;AAEA,UAAM,OAAO,
|
|
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 = {\n\t\t\t...( ability.meta || {} ),\n\t\t\tannotations,\n\t\t};\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 = {\n\t\t\t...( args.meta || {} ),\n\t\t\tannotations,\n\t\t};\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/types.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/types.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress Abilities API Types\n */\n\n/**\n * Callback function for client-side abilities.\n */\nexport type AbilityCallback = (\n\tinput: AbilityInput\n) => AbilityOutput | Promise< AbilityOutput >;\n\n/**\n * Permission callback function for client-side abilities.\n * Returns true if the ability can be executed, false otherwise.\n */\nexport type PermissionCallback = (\n\tinput?: AbilityInput\n) => boolean | Promise< boolean >;\n\n/**\n * Represents an ability in the WordPress Abilities API.\n *\n * @see WP_Ability\n */\nexport interface Ability {\n\t/**\n\t * The unique name/identifier of the ability, with its namespace.\n\t * Example: 'my-plugin/my-ability'\n\t * @see WP_Ability::get_name()\n\t */\n\tname: string;\n\n\t/**\n\t * The human-readable label for the ability.\n\t * @see WP_Ability::get_label()\n\t */\n\tlabel: string;\n\n\t/**\n\t * The detailed description of the ability.\n\t * @see WP_Ability::get_description()\n\t */\n\tdescription: string;\n\n\t/**\n\t * The category this ability belongs to.\n\t * Must be a valid category slug (lowercase alphanumeric with dashes).\n\t * Example: 'data-retrieval', 'user-management'\n\t * @see WP_Ability::get_category()\n\t */\n\tcategory: string;\n\n\t/**\n\t * JSON Schema for the ability's input parameters.\n\t * @see WP_Ability::get_input_schema()\n\t */\n\tinput_schema?: Record< string, any >;\n\n\t/**\n\t * JSON Schema for the ability's output format.\n\t * @see WP_Ability::get_output_schema()\n\t */\n\toutput_schema?: Record< string, any >;\n\n\t/**\n\t * Callback function for ability execution.\n\t * This property is required for all abilities.\n\t */\n\tcallback?: AbilityCallback;\n\n\t/**\n\t * Permission callback for abilities.\n\t * Called before executing the ability to check if it's allowed.\n\t * If it returns false, the ability execution will be denied.\n\t */\n\tpermissionCallback?: PermissionCallback;\n\n\t/**\n\t * Metadata about the ability.\n\t */\n\tmeta?: {\n\t\tannotations?: {\n\t\t\tclientRegistered?: boolean;\n\t\t\tserverRegistered?: boolean;\n\t\t\treadonly?: boolean;\n\t\t\tdestructive?: boolean;\n\t\t\tidempotent?: boolean;\n\t\t};\n\t};\n}\n\n/**\n * The shape of the arguments for querying abilities.\n */\nexport interface AbilitiesQueryArgs {\n\t/**\n\t * Optional category slug to filter abilities.\n\t */\n\tcategory?: string;\n}\n\n/**\n * Represents an ability category in the WordPress Abilities API.\n *\n * @see WP_Ability_Category\n */\nexport interface AbilityCategory {\n\t/**\n\t * The unique slug identifier for the category.\n\t * Must be lowercase alphanumeric with dashes only.\n\t * Example: 'data-retrieval', 'user-management'\n\t * @see WP_Ability_Category::get_slug()\n\t */\n\tslug: string;\n\n\t/**\n\t * The human-readable label for the category.\n\t * @see WP_Ability_Category::get_label()\n\t */\n\tlabel: string;\n\n\t/**\n\t * The detailed description of the category.\n\t * @see WP_Ability_Category::get_description()\n\t */\n\tdescription: string;\n\n\t/**\n\t * Metadata about the category.\n\t */\n\tmeta?: {\n\t\tannotations?: {\n\t\t\tclientRegistered?: boolean;\n\t\t\tserverRegistered?: boolean;\n\t\t};\n\t};\n}\n\n/**\n * Arguments for registering an ability category.\n * Matches the server-side wp_register_ability_category() $args parameter.\n *\n * @see wp_register_ability_category()\n */\nexport interface AbilityCategoryArgs {\n\t/**\n\t * The human-readable label for the category.\n\t */\n\tlabel: string;\n\n\t/**\n\t * The detailed description of the category.\n\t */\n\tdescription: string;\n\n\t/**\n\t * Optional metadata about the category.\n\t */\n\tmeta?: Record< string, any >;\n}\n\n/**\n * Input parameters for ability execution.\n * Can be any JSON-serializable value: primitive, array, object, or null.\n */\nexport type AbilityInput = any;\n\n/**\n * Result from ability execution.\n * The actual shape depends on the ability's output schema.\n */\nexport type AbilityOutput = any;\n\n/**\n * Validation error - just a message string.\n * The Abilities API wraps this with the appropriate error code.\n */\nexport type ValidationError = string;\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress Abilities API Types\n */\n\n/**\n * Callback function for client-side abilities.\n */\nexport type AbilityCallback = (\n\tinput: AbilityInput\n) => AbilityOutput | Promise< AbilityOutput >;\n\n/**\n * Permission callback function for client-side abilities.\n * Returns true if the ability can be executed, false otherwise.\n */\nexport type PermissionCallback = (\n\tinput?: AbilityInput\n) => boolean | Promise< boolean >;\n\n/**\n * Represents an ability in the WordPress Abilities API.\n *\n * @see WP_Ability\n */\nexport interface Ability {\n\t/**\n\t * The unique name/identifier of the ability, with its namespace.\n\t * Example: 'my-plugin/my-ability'\n\t * @see WP_Ability::get_name()\n\t */\n\tname: string;\n\n\t/**\n\t * The human-readable label for the ability.\n\t * @see WP_Ability::get_label()\n\t */\n\tlabel: string;\n\n\t/**\n\t * The detailed description of the ability.\n\t * @see WP_Ability::get_description()\n\t */\n\tdescription: string;\n\n\t/**\n\t * The category this ability belongs to.\n\t * Must be a valid category slug (lowercase alphanumeric with dashes).\n\t * Example: 'data-retrieval', 'user-management'\n\t * @see WP_Ability::get_category()\n\t */\n\tcategory: string;\n\n\t/**\n\t * JSON Schema for the ability's input parameters.\n\t * @see WP_Ability::get_input_schema()\n\t */\n\tinput_schema?: Record< string, any >;\n\n\t/**\n\t * JSON Schema for the ability's output format.\n\t * @see WP_Ability::get_output_schema()\n\t */\n\toutput_schema?: Record< string, any >;\n\n\t/**\n\t * Callback function for ability execution.\n\t * This property is required for all abilities.\n\t */\n\tcallback?: AbilityCallback;\n\n\t/**\n\t * Permission callback for abilities.\n\t * Called before executing the ability to check if it's allowed.\n\t * If it returns false, the ability execution will be denied.\n\t */\n\tpermissionCallback?: PermissionCallback;\n\n\t/**\n\t * Metadata about the ability.\n\t */\n\tmeta?: {\n\t\tannotations?: {\n\t\t\tclientRegistered?: boolean;\n\t\t\tserverRegistered?: boolean;\n\t\t\treadonly?: boolean;\n\t\t\tdestructive?: boolean;\n\t\t\tidempotent?: boolean;\n\t\t};\n\t\t[ key: string ]: any;\n\t};\n}\n\n/**\n * The shape of the arguments for querying abilities.\n */\nexport interface AbilitiesQueryArgs {\n\t/**\n\t * Optional category slug to filter abilities.\n\t */\n\tcategory?: string;\n}\n\n/**\n * Represents an ability category in the WordPress Abilities API.\n *\n * @see WP_Ability_Category\n */\nexport interface AbilityCategory {\n\t/**\n\t * The unique slug identifier for the category.\n\t * Must be lowercase alphanumeric with dashes only.\n\t * Example: 'data-retrieval', 'user-management'\n\t * @see WP_Ability_Category::get_slug()\n\t */\n\tslug: string;\n\n\t/**\n\t * The human-readable label for the category.\n\t * @see WP_Ability_Category::get_label()\n\t */\n\tlabel: string;\n\n\t/**\n\t * The detailed description of the category.\n\t * @see WP_Ability_Category::get_description()\n\t */\n\tdescription: string;\n\n\t/**\n\t * Metadata about the category.\n\t */\n\tmeta?: {\n\t\tannotations?: {\n\t\t\tclientRegistered?: boolean;\n\t\t\tserverRegistered?: boolean;\n\t\t};\n\t\t[ key: string ]: any;\n\t};\n}\n\n/**\n * Arguments for registering an ability category.\n * Matches the server-side wp_register_ability_category() $args parameter.\n *\n * @see wp_register_ability_category()\n */\nexport interface AbilityCategoryArgs {\n\t/**\n\t * The human-readable label for the category.\n\t */\n\tlabel: string;\n\n\t/**\n\t * The detailed description of the category.\n\t */\n\tdescription: string;\n\n\t/**\n\t * Optional metadata about the category.\n\t */\n\tmeta?: Record< string, any >;\n}\n\n/**\n * Input parameters for ability execution.\n * Can be any JSON-serializable value: primitive, array, object, or null.\n */\nexport type AbilityInput = any;\n\n/**\n * Result from ability execution.\n * The actual shape depends on the ability's output schema.\n */\nexport type AbilityOutput = any;\n\n/**\n * Validation error - just a message string.\n * The Abilities API wraps this with the appropriate error code.\n */\nexport type ValidationError = string;\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -90,7 +90,10 @@ function registerAbility(ability) {
|
|
|
90
90
|
if (!annotations.serverRegistered) {
|
|
91
91
|
annotations.clientRegistered = true;
|
|
92
92
|
}
|
|
93
|
-
const meta = {
|
|
93
|
+
const meta = {
|
|
94
|
+
...ability.meta || {},
|
|
95
|
+
annotations
|
|
96
|
+
};
|
|
94
97
|
dispatch({
|
|
95
98
|
type: REGISTER_ABILITY,
|
|
96
99
|
ability: {
|
|
@@ -144,7 +147,10 @@ function registerAbilityCategory(slug, args) {
|
|
|
144
147
|
if (!annotations.serverRegistered) {
|
|
145
148
|
annotations.clientRegistered = true;
|
|
146
149
|
}
|
|
147
|
-
const meta = {
|
|
150
|
+
const meta = {
|
|
151
|
+
...args.meta || {},
|
|
152
|
+
annotations
|
|
153
|
+
};
|
|
148
154
|
const category = {
|
|
149
155
|
slug,
|
|
150
156
|
label: args.label,
|
|
@@ -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';\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 = {
|
|
5
|
-
"mappings": ";AAGA,SAAS,eAAe;AAMxB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAWP,SAAS,kBACR,mBACA,aACoC;AACpC,QAAM,cAAiD,CAAC;AAExD,MAAK,mBAAoB;AACxB,eAAY,OAAO,aAAc;AAChC,UAAK,kBAAmB,GAAI,MAAM,QAAY;AAC7C,oBAAa,GAAI,IAAI,kBAAmB,GAAI;AAAA,MAC7C;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAYO,SAAS,gBAAiB,SAAmB;AAEnD,SAAO,CAAE,EAAE,QAAQ,SAAS,MAAO;AAClC,QAAK,CAAE,QAAQ,MAAO;AACrB,YAAM,IAAI,MAAO,0BAA2B;AAAA,IAC7C;AAGA,QAAK,CAAE,qBAAqB,KAAM,QAAQ,IAAK,GAAI;AAClD,YAAM,IAAI;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAEA,QAAK,CAAE,QAAQ,OAAQ;AACtB,YAAM,IAAI;AAAA,QACT,QAAS,kCAAkC,QAAQ,IAAK;AAAA,MACzD;AAAA,IACD;AAEA,QAAK,CAAE,QAAQ,aAAc;AAC5B,YAAM,IAAI;AAAA,QACT,QAAS,wCAAwC,QAAQ,IAAK;AAAA,MAC/D;AAAA,IACD;AAEA,QAAK,CAAE,QAAQ,UAAW;AACzB,YAAM,IAAI;AAAA,QACT,QAAS,qCAAqC,QAAQ,IAAK;AAAA,MAC5D;AAAA,IACD;AAGA,QAAK,CAAE,sBAAsB,KAAM,QAAQ,QAAS,GAAI;AACvD,YAAM,IAAI;AAAA,QACT;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,UAAM,aAAa,OAAO,qBAAqB;AAC/C,UAAM,mBAAmB,WAAW;AAAA,MACnC,CAAE,QAA0B,IAAI,SAAS,QAAQ;AAAA,IAClD;AACA,QAAK,CAAE,kBAAmB;AACzB,YAAM,IAAI;AAAA,QACT;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,QAAK,QAAQ,YAAY,OAAO,QAAQ,aAAa,YAAa;AACjE,YAAM,IAAI;AAAA,QACT;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD;AAGA,UAAM,kBAAkB,OAAO,WAAY,QAAQ,IAAK;AACxD,QAAK,iBAAkB;AACtB,YAAM,IAAI;AAAA,QACT,QAAS,sCAAsC,QAAQ,IAAK;AAAA,MAC7D;AAAA,IACD;AAEA,UAAM,cAAc,kBAAmB,QAAQ,MAAM,aAAa;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAE;AAEF,QAAK,CAAE,YAAY,kBAAmB;AACrC,kBAAY,mBAAmB;AAAA,IAChC;AAEA,UAAM,OAAO,
|
|
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 = {\n\t\t\t...( ability.meta || {} ),\n\t\t\tannotations,\n\t\t};\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 = {\n\t\t\t...( args.meta || {} ),\n\t\t\tannotations,\n\t\t};\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
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAmB,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAmC9E;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAE,OAAO,EAAE,OAAO,IAEvC;;;CAAoB,
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/store/actions.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAmB,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAmC9E;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAE,OAAO,EAAE,OAAO,IAEvC;;;CAAoB,UAoG7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAE,IAAI,EAAE,MAAM;;;EAK9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,mBAAmB,IAGhB;;;CAAoB,UAoE7B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAE,IAAI,EAAE,MAAM;;;EAKtD"}
|
package/build-types/types.d.ts
CHANGED
|
@@ -71,6 +71,7 @@ export interface Ability {
|
|
|
71
71
|
destructive?: boolean;
|
|
72
72
|
idempotent?: boolean;
|
|
73
73
|
};
|
|
74
|
+
[key: string]: any;
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
@@ -113,6 +114,7 @@ export interface AbilityCategory {
|
|
|
113
114
|
clientRegistered?: boolean;
|
|
114
115
|
serverRegistered?: boolean;
|
|
115
116
|
};
|
|
117
|
+
[key: string]: any;
|
|
116
118
|
};
|
|
117
119
|
}
|
|
118
120
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,KAAK,EAAE,YAAY,KACf,aAAa,GAAG,OAAO,CAAE,aAAa,CAAE,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAChC,KAAK,CAAC,EAAE,YAAY,KAChB,OAAO,GAAG,OAAO,CAAE,OAAO,CAAE,CAAC;AAElC;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACvB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,CAAC;IAErC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;IAE3B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC;;OAEG;IACH,IAAI,CAAC,EAAE;QACN,WAAW,CAAC,EAAE;YACb,gBAAgB,CAAC,EAAE,OAAO,CAAC;YAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;YAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,WAAW,CAAC,EAAE,OAAO,CAAC;YACtB,UAAU,CAAC,EAAE,OAAO,CAAC;SACrB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,KAAK,EAAE,YAAY,KACf,aAAa,GAAG,OAAO,CAAE,aAAa,CAAE,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAChC,KAAK,CAAC,EAAE,YAAY,KAChB,OAAO,GAAG,OAAO,CAAE,OAAO,CAAE,CAAC;AAElC;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACvB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,CAAC;IAErC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;IAE3B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC;;OAEG;IACH,IAAI,CAAC,EAAE;QACN,WAAW,CAAC,EAAE;YACb,gBAAgB,CAAC,EAAE,OAAO,CAAC;YAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;YAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,WAAW,CAAC,EAAE,OAAO,CAAC;YACtB,UAAU,CAAC,EAAE,OAAO,CAAC;SACrB,CAAC;QACF,CAAE,GAAG,EAAE,MAAM,GAAI,GAAG,CAAC;KACrB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,IAAI,CAAC,EAAE;QACN,WAAW,CAAC,EAAE;YACb,gBAAgB,CAAC,EAAE,OAAO,CAAC;YAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;SAC3B,CAAC;QACF,CAAE,GAAG,EAAE,MAAM,GAAI,GAAG,CAAC;KACrB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,GAAG,CAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC;AAE/B;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAEhC;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/abilities",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "JavaScript client for WordPress Abilities API.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
},
|
|
46
46
|
"types": "build-types",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@wordpress/data": "^10.
|
|
49
|
-
"@wordpress/i18n": "^6.
|
|
48
|
+
"@wordpress/data": "^10.39.0",
|
|
49
|
+
"@wordpress/i18n": "^6.12.0",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
51
51
|
"ajv-draft-04": "^1.0.0",
|
|
52
52
|
"ajv-formats": "^3.0.1"
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public"
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "eee1cfb1472f11183e40fb77465a5f13145df7ad"
|
|
58
58
|
}
|
package/src/store/actions.ts
CHANGED
|
@@ -139,7 +139,10 @@ export function registerAbility( ability: Ability ) {
|
|
|
139
139
|
annotations.clientRegistered = true;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
const meta = {
|
|
142
|
+
const meta = {
|
|
143
|
+
...( ability.meta || {} ),
|
|
144
|
+
annotations,
|
|
145
|
+
};
|
|
143
146
|
|
|
144
147
|
// All validation passed, dispatch the registration action
|
|
145
148
|
dispatch( {
|
|
@@ -233,7 +236,10 @@ export function registerAbilityCategory(
|
|
|
233
236
|
annotations.clientRegistered = true;
|
|
234
237
|
}
|
|
235
238
|
|
|
236
|
-
const meta = {
|
|
239
|
+
const meta = {
|
|
240
|
+
...( args.meta || {} ),
|
|
241
|
+
annotations,
|
|
242
|
+
};
|
|
237
243
|
const category: AbilityCategory = {
|
|
238
244
|
slug,
|
|
239
245
|
label: args.label,
|
|
@@ -398,6 +398,35 @@ describe( 'Store Actions', () => {
|
|
|
398
398
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
399
399
|
} );
|
|
400
400
|
|
|
401
|
+
it( 'should preserve arbitrary meta properties like scope', () => {
|
|
402
|
+
const ability: Ability = {
|
|
403
|
+
name: 'test/ability-with-scope',
|
|
404
|
+
label: 'Test Ability',
|
|
405
|
+
description: 'Test ability with custom scope',
|
|
406
|
+
category: 'test-category',
|
|
407
|
+
callback: jest.fn(),
|
|
408
|
+
meta: {
|
|
409
|
+
scope: 'editor',
|
|
410
|
+
customProperty: 'customValue',
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const action = registerAbility( ability );
|
|
415
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
416
|
+
|
|
417
|
+
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
418
|
+
type: REGISTER_ABILITY,
|
|
419
|
+
ability: {
|
|
420
|
+
...ability,
|
|
421
|
+
meta: {
|
|
422
|
+
scope: 'editor',
|
|
423
|
+
customProperty: 'customValue',
|
|
424
|
+
annotations: { clientRegistered: true },
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
} );
|
|
428
|
+
} );
|
|
429
|
+
|
|
401
430
|
it( 'should validate and reject already registered ability', () => {
|
|
402
431
|
const existingAbility: Ability = {
|
|
403
432
|
name: 'test/ability',
|
package/src/types.ts
CHANGED
|
@@ -86,6 +86,7 @@ export interface Ability {
|
|
|
86
86
|
destructive?: boolean;
|
|
87
87
|
idempotent?: boolean;
|
|
88
88
|
};
|
|
89
|
+
[ key: string ]: any;
|
|
89
90
|
};
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -133,6 +134,7 @@ export interface AbilityCategory {
|
|
|
133
134
|
clientRegistered?: boolean;
|
|
134
135
|
serverRegistered?: boolean;
|
|
135
136
|
};
|
|
137
|
+
[ key: string ]: any;
|
|
136
138
|
};
|
|
137
139
|
}
|
|
138
140
|
|