@wordpress/abilities 0.2.1-next.8b30e05b0.0 → 0.2.1-next.8fd3f8831.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/README.md +32 -40
- package/build/{api.js → api.cjs} +22 -69
- package/build/api.cjs.map +7 -0
- package/build/{index.js → index.cjs} +4 -4
- package/build/{index.js.map → index.cjs.map} +2 -2
- package/build/store/{actions.js → actions.cjs} +43 -33
- package/build/store/actions.cjs.map +7 -0
- package/build/store/{constants.js → constants.cjs} +7 -16
- package/build/store/constants.cjs.map +7 -0
- package/build/store/{index.js → index.cjs} +6 -32
- package/build/store/index.cjs.map +7 -0
- package/build/store/{reducer.js → reducer.cjs} +4 -24
- package/build/store/reducer.cjs.map +7 -0
- package/build/store/{selectors.js → selectors.cjs} +2 -2
- package/build/store/selectors.cjs.map +7 -0
- package/build/store/types.cjs +19 -0
- package/build/store/types.cjs.map +7 -0
- package/build/{types.js → types.cjs} +1 -1
- package/build/types.cjs.map +7 -0
- package/build/{validation.js → validation.cjs} +3 -3
- package/build-module/api.js +22 -59
- package/build-module/api.js.map +2 -2
- package/build-module/index.js +3 -3
- package/build-module/index.js.map +2 -2
- package/build-module/store/actions.js +44 -33
- 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 +6 -37
- package/build-module/store/index.js.map +2 -2
- package/build-module/store/reducer.js +3 -25
- 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 +8 -10
- 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/api.js.map +0 -7
- package/build/store/actions.js.map +0 -7
- package/build/store/constants.js.map +0 -7
- package/build/store/index.js.map +0 -7
- package/build/store/reducer.js.map +0 -7
- package/build/store/resolvers.js +0 -107
- package/build/store/resolvers.js.map +0 -7
- package/build/store/selectors.js.map +0 -7
- package/build/types.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/build/{validation.js.map → validation.cjs.map} +0 -0
package/build/api.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/api.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { dispatch, resolveSelect } from '@wordpress/data';\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\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 Promise resolving to array of abilities.\n */\nexport async function getAbilities(\n\targs: AbilitiesQueryArgs = {}\n): Promise< Ability[] > {\n\treturn await resolveSelect( store ).getAbilities( args );\n}\n\n/**\n * Get a specific ability by name.\n *\n * @param name The ability name.\n * @return Promise resolving to the ability or null if not found.\n */\nexport async function getAbility( name: string ): Promise< Ability | null > {\n\treturn await resolveSelect( store ).getAbility( name );\n}\n\n/**\n * Get all available ability categories.\n *\n * @return Promise resolving to array of categories.\n */\nexport async function getAbilityCategories(): Promise< AbilityCategory[] > {\n\treturn await resolveSelect( store ).getAbilityCategories();\n}\n\n/**\n * Get a specific ability category by slug.\n *\n * @param slug The category slug.\n * @return Promise resolving to the category or null if not found.\n */\nexport async function getAbilityCategory(\n\tslug: string\n): Promise< AbilityCategory | null > {\n\treturn await resolveSelect( 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 * Categories will be automatically fetched from the REST API if they\n * haven't been loaded yet, so you don't need to call getAbilityCategories()\n * before registering abilities.\n *\n * @param ability The ability definition including callback.\n * @return Promise that resolves when registration is complete.\n * @throws {Error} If the ability fails validation.\n *\n * @example\n * ```js\n * await 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 async function registerAbility( ability: Ability ): Promise< void > {\n\tawait dispatch( 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 * Categories will be automatically fetched from the REST API if they haven't been\n * loaded yet to check for duplicates against server-side categories.\n *\n * @param slug Category slug (lowercase alphanumeric with dashes only).\n * @param args Category arguments (label, description, optional meta).\n * @return Promise that resolves when registration is complete.\n * @throws {Error} If the category fails validation.\n *\n * @example\n * ```js\n * // Register a new category for block editor abilities\n * await 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 * await 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 async function registerAbilityCategory(\n\tslug: string,\n\targs: AbilityCategoryArgs\n): Promise< void > {\n\tawait dispatch( 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 a client-side ability.\n *\n * @param ability The ability to execute.\n * @param input Input parameters for the ability.\n * @return Promise resolving to the ability execution result.\n * @throws Error if validation fails or execution errors.\n */\nasync function executeClientAbility(\n\tability: Ability,\n\tinput: AbilityInput\n): Promise< AbilityOutput > {\n\tif ( ! ability.callback ) {\n\t\tthrow new Error(\n\t\t\tsprintf(\n\t\t\t\t'Client ability %s is missing callback function',\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\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\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(\n\t\t\t`Error executing client ability ${ ability.name }:`,\n\t\t\terror\n\t\t);\n\t\tthrow error;\n\t}\n\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\n/**\n * Execute a server-side ability.\n *\n * @param ability The ability to execute.\n * @param input Input parameters for the ability.\n * @return Promise resolving to the ability execution result.\n * @throws Error if the API call fails.\n */\nasync function executeServerAbility(\n\tability: Ability,\n\tinput: AbilityInput\n): Promise< AbilityOutput > {\n\tlet method = 'POST';\n\tif ( !! ability.meta?.annotations?.readonly ) {\n\t\tmethod = 'GET';\n\t} else if (\n\t\t!! ability.meta?.annotations?.destructive &&\n\t\t!! ability.meta?.annotations?.idempotent\n\t) {\n\t\tmethod = 'DELETE';\n\t}\n\n\tlet path = `/wp-abilities/v1/abilities/${ ability.name }/run`;\n\tconst options: {\n\t\tmethod: string;\n\t\tdata?: { input: AbilityInput };\n\t} = {\n\t\tmethod,\n\t};\n\n\tif ( [ 'GET', 'DELETE' ].includes( method ) && input !== null ) {\n\t\t// For GET and DELETE requests, pass the input directly.\n\t\tpath = addQueryArgs( path, { input } );\n\t} else if ( method === 'POST' && input !== null ) {\n\t\toptions.data = { input };\n\t}\n\n\t// Note: Input and output validation happens on the server side for these abilities.\n\ttry {\n\t\treturn await apiFetch< AbilityOutput >( {\n\t\t\tpath,\n\t\t\t...options,\n\t\t} );\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\n/**\n * Execute an ability.\n *\n * Determines whether to execute locally (client abilities) or remotely (server abilities)\n * based on whether the ability has a callback function.\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 = await 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\treturn executeClientAbility( ability, input );\n\t}\n\n\treturn executeServerAbility( ability, input );\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["apiFetch"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/actions.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { sprintf } from '@wordpress/i18n';\nimport { resolveSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport type { Ability, AbilityCategory, AbilityCategoryArgs } from '../types';\nimport {\n\tRECEIVE_ABILITIES,\n\tREGISTER_ABILITY,\n\tUNREGISTER_ABILITY,\n\tRECEIVE_CATEGORIES,\n\tREGISTER_ABILITY_CATEGORY,\n\tUNREGISTER_ABILITY_CATEGORY,\n\tSTORE_NAME,\n} from './constants';\n\n/**\n * Returns an action object used to receive abilities into the store.\n *\n * @param abilities Array of abilities to store.\n * @return Action object.\n */\nexport function receiveAbilities( abilities: Ability[] ) {\n\treturn {\n\t\ttype: RECEIVE_ABILITIES,\n\t\tabilities,\n\t};\n}\n\n/**\n * Returns an action object used to receive categories into the store.\n *\n * @param categories Array of categories to store.\n * @return Action object.\n */\nexport function receiveCategories( categories: AbilityCategory[] ) {\n\treturn {\n\t\ttype: RECEIVE_CATEGORIES,\n\t\tcategories,\n\t};\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. Categories will be automatically fetched from the\n * REST API if they haven't been loaded yet.\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 async ( { 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 ( ! /^[a-z0-9-]+\\/[a-z0-9-]+$/.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 ( ! /^[a-z0-9]+(?:-[a-z0-9]+)*$/.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// Ensure categories are loaded before validating\n\t\tconst categories =\n\t\t\tawait resolveSelect( STORE_NAME ).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\t// All validation passed, dispatch the registration action\n\t\tdispatch( {\n\t\t\ttype: REGISTER_ABILITY,\n\t\t\tability,\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. Categories will be automatically fetched from the\n * REST API if they haven't been loaded yet to check for duplicates.\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 async ( { 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 ( ! /^[a-z0-9]+(?:-[a-z0-9]+)*$/.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// Ensure categories are loaded before checking for duplicates\n\t\tawait resolveSelect( STORE_NAME ).getAbilityCategories();\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 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\t\t...( args.meta || {} ),\n\t\t\t\t// Internal implementation note: Client-registered categories will have `meta._clientRegistered` set to `true` to differentiate them from server-fetched categories.\n\t\t\t\t// This is used internally by the resolver to determine whether to fetch categories from the server.\n\t\t\t\t_clientRegistered: true,\n\t\t\t},\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
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/constants.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Store constants\n */\nexport const STORE_NAME = 'core/abilities';\nexport const ENTITY_KIND = 'root';\nexport const ENTITY_NAME = 'abilities';\nexport const ENTITY_NAME_CATEGORIES = 'ability-categories';\n\n// Action types\nexport const RECEIVE_ABILITIES = 'RECEIVE_ABILITIES';\nexport const REGISTER_ABILITY = 'REGISTER_ABILITY';\nexport const UNREGISTER_ABILITY = 'UNREGISTER_ABILITY';\nexport const RECEIVE_CATEGORIES = 'RECEIVE_CATEGORIES';\nexport const REGISTER_ABILITY_CATEGORY = 'REGISTER_ABILITY_CATEGORY';\nexport const UNREGISTER_ABILITY_CATEGORY = 'UNREGISTER_ABILITY_CATEGORY';\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,IAAM,aAAa;AACnB,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,yBAAyB;AAG/B,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/build/store/index.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { createReduxStore, register, dispatch } from '@wordpress/data';\nimport { store as coreStore } from '@wordpress/core-data';\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport reducer from './reducer';\nimport * as actions from './actions';\nimport * as selectors from './selectors';\nimport * as resolvers from './resolvers';\nimport {\n\tSTORE_NAME,\n\tENTITY_KIND,\n\tENTITY_NAME,\n\tENTITY_NAME_CATEGORIES,\n} from './constants';\n\n/**\n * The abilities store definition.\n */\nexport const store = createReduxStore( STORE_NAME, {\n\treducer,\n\tactions,\n\tselectors,\n\tresolvers,\n} );\n\nregister( store );\n\ndispatch( coreStore ).addEntities( [\n\t{\n\t\tname: ENTITY_NAME,\n\t\tkind: ENTITY_KIND,\n\t\tkey: 'name',\n\t\tbaseURL: '/wp-abilities/v1/abilities',\n\t\tbaseURLParams: { context: 'edit' },\n\t\tplural: 'abilities',\n\t\tlabel: __( 'Abilities' ),\n\t\tsupportsPagination: true,\n\t},\n\t{\n\t\tname: ENTITY_NAME_CATEGORIES,\n\t\tkind: ENTITY_KIND,\n\t\tkey: 'slug',\n\t\tbaseURL: '/wp-abilities/v1/categories',\n\t\tbaseURLParams: { context: 'edit' },\n\t\tplural: 'ability-categories',\n\t\tlabel: __( 'Ability Categories' ),\n\t\tsupportsPagination: true,\n\t},\n] );\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAqD;AACrD,uBAAmC;AACnC,kBAAmB;AAKnB,qBAAoB;AACpB,cAAyB;AACzB,gBAA2B;AAC3B,gBAA2B;AAC3B,uBAKO;AAKA,IAAM,YAAQ,8BAAkB,6BAAY;AAAA,EAClD,wBAAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAE;AAAA,IAEF,sBAAU,KAAM;AAAA,IAEhB,sBAAU,iBAAAC,KAAU,EAAE,YAAa;AAAA,EAClC;AAAA,IACC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,KAAK;AAAA,IACL,SAAS;AAAA,IACT,eAAe,EAAE,SAAS,OAAO;AAAA,IACjC,QAAQ;AAAA,IACR,WAAO,gBAAI,WAAY;AAAA,IACvB,oBAAoB;AAAA,EACrB;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,KAAK;AAAA,IACL,SAAS;AAAA,IACT,eAAe,EAAE,SAAS,OAAO;AAAA,IACjC,QAAQ;AAAA,IACR,WAAO,gBAAI,oBAAqB;AAAA,IAChC,oBAAoB;AAAA,EACrB;AACD,CAAE;",
|
|
6
|
-
"names": ["reducer", "coreStore"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/reducer.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { combineReducers } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport type { Ability, AbilityCategory } from '../types';\nimport {\n\tRECEIVE_ABILITIES,\n\tREGISTER_ABILITY,\n\tUNREGISTER_ABILITY,\n\tRECEIVE_CATEGORIES,\n\tREGISTER_ABILITY_CATEGORY,\n\tUNREGISTER_ABILITY_CATEGORY,\n} from './constants';\n\n/**\n * Valid keys for an Ability object.\n * Used to filter out non-standard properties from server responses.\n */\nconst ABILITY_KEYS = [\n\t'name',\n\t'label',\n\t'description',\n\t'category',\n\t'input_schema',\n\t'output_schema',\n\t'meta',\n\t'callback',\n\t'permissionCallback',\n] as const;\n\n/**\n * Valid keys for an AbilityCategory object.\n * Used to filter out non-standard properties from server responses.\n */\nconst CATEGORY_KEYS = [ 'slug', 'label', 'description', 'meta' ] as const;\n\n/**\n * Sanitizes an ability object to only include valid properties.\n * This ensures consistent shape regardless of source (server/client).\n *\n * @param ability Raw ability object that may contain extra properties.\n * @return Sanitized ability with only valid properties.\n */\nfunction sanitizeAbility( ability: any ): Ability {\n\treturn Object.keys( ability )\n\t\t.filter(\n\t\t\t( key ) =>\n\t\t\t\tABILITY_KEYS.includes( key as any ) &&\n\t\t\t\tability[ key ] !== undefined\n\t\t)\n\t\t.reduce(\n\t\t\t( obj, key ) => ( { ...obj, [ key ]: ability[ key ] } ),\n\t\t\t{} as Ability\n\t\t);\n}\n\n/**\n * Sanitizes a category object to only include valid properties.\n * This ensures consistent shape regardless of source.\n *\n * @param category Raw category object that may contain extra properties.\n * @return Sanitized category with only valid properties.\n */\nfunction sanitizeCategory( category: any ): AbilityCategory {\n\treturn Object.keys( category )\n\t\t.filter(\n\t\t\t( key ) =>\n\t\t\t\tCATEGORY_KEYS.includes( key as any ) &&\n\t\t\t\tcategory[ key ] !== undefined\n\t\t)\n\t\t.reduce(\n\t\t\t( obj, key ) => ( { ...obj, [ key ]: category[ key ] } ),\n\t\t\t{} as AbilityCategory\n\t\t);\n}\n\ninterface AbilitiesAction {\n\ttype: string;\n\tabilities?: Ability[];\n\tability?: Ability;\n\tcategories?: AbilityCategory[];\n\tcategory?: AbilityCategory;\n\tname?: string;\n\tslug?: string;\n}\n\nconst DEFAULT_STATE: Record< string, Ability > = {};\n\n/**\n * Reducer managing the abilities by name.\n *\n * @param state Current state.\n * @param action Dispatched action.\n * @return New state.\n */\nfunction abilitiesByName(\n\tstate: Record< string, Ability > = DEFAULT_STATE,\n\taction: AbilitiesAction\n): Record< string, Ability > {\n\tswitch ( action.type ) {\n\t\tcase RECEIVE_ABILITIES: {\n\t\t\tif ( ! action.abilities ) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst newState: Record< string, Ability > = {};\n\t\t\taction.abilities.forEach( ( ability ) => {\n\t\t\t\tnewState[ ability.name ] = sanitizeAbility( ability );\n\t\t\t} );\n\t\t\treturn newState;\n\t\t}\n\t\tcase REGISTER_ABILITY: {\n\t\t\tif ( ! action.ability ) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.ability.name ]: sanitizeAbility( action.ability ),\n\t\t\t};\n\t\t}\n\t\tcase UNREGISTER_ABILITY: {\n\t\t\tif ( ! action.name || ! state[ action.name ] ) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst { [ action.name ]: _, ...newState } = state;\n\t\t\treturn newState;\n\t\t}\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\nconst DEFAULT_CATEGORIES_STATE: Record< string, AbilityCategory > = {};\n\n/**\n * Reducer managing the categories by slug.\n *\n * @param state Current state.\n * @param action Dispatched action.\n * @return New state.\n */\nfunction categoriesBySlug(\n\tstate: Record< string, AbilityCategory > = DEFAULT_CATEGORIES_STATE,\n\taction: AbilitiesAction\n): Record< string, AbilityCategory > {\n\tswitch ( action.type ) {\n\t\tcase RECEIVE_CATEGORIES: {\n\t\t\tif ( ! action.categories ) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst newState: Record< string, AbilityCategory > = {};\n\t\t\taction.categories.forEach( ( category ) => {\n\t\t\t\tnewState[ category.slug ] = sanitizeCategory( category );\n\t\t\t} );\n\t\t\treturn newState;\n\t\t}\n\t\tcase REGISTER_ABILITY_CATEGORY: {\n\t\t\tif ( ! action.category ) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.category.slug ]: sanitizeCategory( action.category ),\n\t\t\t};\n\t\t}\n\t\tcase UNREGISTER_ABILITY_CATEGORY: {\n\t\t\tif ( ! action.slug || ! state[ action.slug ] ) {\n\t\t\t\treturn state;\n\t\t\t}\n\t\t\tconst { [ action.slug ]: _, ...newState } = state;\n\t\t\treturn newState;\n\t\t}\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\nexport default combineReducers( {\n\tabilitiesByName,\n\tcategoriesBySlug,\n} );\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/build/store/resolvers.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// packages/abilities/src/store/resolvers.ts
|
|
21
|
-
var resolvers_exports = {};
|
|
22
|
-
__export(resolvers_exports, {
|
|
23
|
-
getAbilities: () => getAbilities,
|
|
24
|
-
getAbility: () => getAbility,
|
|
25
|
-
getAbilityCategories: () => getAbilityCategories,
|
|
26
|
-
getAbilityCategory: () => getAbilityCategory
|
|
27
|
-
});
|
|
28
|
-
module.exports = __toCommonJS(resolvers_exports);
|
|
29
|
-
var import_core_data = require("@wordpress/core-data");
|
|
30
|
-
var import_constants = require("./constants");
|
|
31
|
-
var import_actions = require("./actions");
|
|
32
|
-
function getAbilities() {
|
|
33
|
-
return async ({ dispatch, registry, select }) => {
|
|
34
|
-
const existingAbilities = select.getAbilities();
|
|
35
|
-
const hasServerAbilities = existingAbilities.some(
|
|
36
|
-
(ability) => !ability.callback
|
|
37
|
-
);
|
|
38
|
-
if (hasServerAbilities) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const abilities = await registry.resolveSelect(import_core_data.store).getEntityRecords(import_constants.ENTITY_KIND, import_constants.ENTITY_NAME, {
|
|
42
|
-
per_page: -1
|
|
43
|
-
});
|
|
44
|
-
dispatch((0, import_actions.receiveAbilities)(abilities || []));
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function getAbility(name) {
|
|
48
|
-
return async ({ dispatch, registry, select }) => {
|
|
49
|
-
const existingAbility = select.getAbility(name);
|
|
50
|
-
if (existingAbility) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
const ability = await registry.resolveSelect(import_core_data.store).getEntityRecord(import_constants.ENTITY_KIND, import_constants.ENTITY_NAME, name);
|
|
55
|
-
if (ability) {
|
|
56
|
-
await dispatch((0, import_actions.registerAbility)(ability));
|
|
57
|
-
}
|
|
58
|
-
} catch (error) {
|
|
59
|
-
console.debug(`Ability not found: ${name}`);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
function getAbilityCategories() {
|
|
64
|
-
return async ({ dispatch, registry, select }) => {
|
|
65
|
-
const existingCategories = select.getAbilityCategories();
|
|
66
|
-
const hasServerCategories = existingCategories.some(
|
|
67
|
-
(category) => !category.meta?._clientRegistered
|
|
68
|
-
);
|
|
69
|
-
if (hasServerCategories) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const categories = await registry.resolveSelect(import_core_data.store).getEntityRecords(import_constants.ENTITY_KIND, import_constants.ENTITY_NAME_CATEGORIES, {
|
|
73
|
-
per_page: -1
|
|
74
|
-
});
|
|
75
|
-
dispatch((0, import_actions.receiveCategories)(categories || []));
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function getAbilityCategory(slug) {
|
|
79
|
-
return async ({ dispatch, registry, select }) => {
|
|
80
|
-
const existingCategory = select.getAbilityCategory(slug);
|
|
81
|
-
if (existingCategory) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
const category = await registry.resolveSelect(import_core_data.store).getEntityRecord(import_constants.ENTITY_KIND, import_constants.ENTITY_NAME_CATEGORIES, slug);
|
|
86
|
-
if (category) {
|
|
87
|
-
await dispatch(
|
|
88
|
-
(0, import_actions.registerAbilityCategory)(category.slug, {
|
|
89
|
-
label: category.label,
|
|
90
|
-
description: category.description,
|
|
91
|
-
meta: category.meta
|
|
92
|
-
})
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.debug(`Category not found: ${slug}`);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
101
|
-
0 && (module.exports = {
|
|
102
|
-
getAbilities,
|
|
103
|
-
getAbility,
|
|
104
|
-
getAbilityCategories,
|
|
105
|
-
getAbilityCategory
|
|
106
|
-
});
|
|
107
|
-
//# sourceMappingURL=resolvers.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/resolvers.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { store as coreStore } from '@wordpress/core-data';\n\n/**\n * Internal dependencies\n */\nimport type { Ability, AbilityCategory } from '../types';\nimport { ENTITY_KIND, ENTITY_NAME, ENTITY_NAME_CATEGORIES } from './constants';\nimport {\n\treceiveAbilities,\n\treceiveCategories,\n\tregisterAbility,\n\tregisterAbilityCategory,\n} from './actions';\n\n/**\n * Resolver for getAbilities selector.\n * Fetches all abilities from the server.\n *\n * The resolver only fetches once (without query args filter) and stores all abilities.\n * Query args filtering handled client-side by the selector for better performance\n * and to avoid multiple API requests when filtering by different categories.\n */\nexport function getAbilities() {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\tconst existingAbilities = select.getAbilities();\n\n\t\t// Check if we have any server-side abilities (abilities without callbacks)\n\t\t// Client abilities have callbacks and are registered immediately on page load\n\t\t// We only want to skip fetching if we've already fetched server abilities\n\t\tconst hasServerAbilities = existingAbilities.some(\n\t\t\t( ability: Ability ) => ! ability.callback\n\t\t);\n\n\t\tif ( hasServerAbilities ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst abilities = await registry\n\t\t\t.resolveSelect( coreStore )\n\t\t\t.getEntityRecords( ENTITY_KIND, ENTITY_NAME, {\n\t\t\t\tper_page: -1,\n\t\t\t} );\n\n\t\tdispatch( receiveAbilities( abilities || [] ) );\n\t};\n}\n\n/**\n * Resolver for getAbility selector.\n * Fetches a specific ability from the server if not already in store.\n *\n * @param name Ability name.\n */\nexport function getAbility( name: string ) {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\t// Check if ability already exists in store (i.e. client ability or already fetched)\n\t\tconst existingAbility = select.getAbility( name );\n\t\tif ( existingAbility ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst ability = await registry\n\t\t\t\t.resolveSelect( coreStore )\n\t\t\t\t.getEntityRecord( ENTITY_KIND, ENTITY_NAME, name );\n\n\t\t\tif ( ability ) {\n\t\t\t\tawait dispatch( registerAbility( ability ) );\n\t\t\t}\n\t\t} catch ( error ) {\n\t\t\t// If ability doesn't exist or error, we'll return undefined from the selector\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug( `Ability not found: ${ name }` );\n\t\t}\n\t};\n}\n\n/**\n * Resolver for getAbilityCategories selector.\n * Fetches all categories from the server.\n *\n * The resolver only fetches once and stores all categories.\n */\nexport function getAbilityCategories() {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\tconst existingCategories = select.getAbilityCategories();\n\n\t\t// Check if we have any server-side categories (categories without meta._clientRegistered flag)\n\t\t// Client categories have meta._clientRegistered=true and might be registered immediately\n\t\t// We only want to skip fetching if we've already fetched server categories\n\t\tconst hasServerCategories = existingCategories.some(\n\t\t\t( category: AbilityCategory ) => ! category.meta?._clientRegistered\n\t\t);\n\n\t\tif ( hasServerCategories ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst categories = await registry\n\t\t\t.resolveSelect( coreStore )\n\t\t\t.getEntityRecords( ENTITY_KIND, ENTITY_NAME_CATEGORIES, {\n\t\t\t\tper_page: -1,\n\t\t\t} );\n\n\t\tdispatch( receiveCategories( categories || [] ) );\n\t};\n}\n\n/**\n * Resolver for getAbilityCategory selector.\n * Fetches a specific category from the server if not already in store.\n *\n * @param slug Category slug.\n */\nexport function getAbilityCategory( slug: string ) {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\t// Check if category already exists in store (either client-registered or server-fetched).\n\t\t// This prevents unnecessary network requests while allowing client-side categories\n\t\t// to be retrieved immediately without hitting the API.\n\t\tconst existingCategory = select.getAbilityCategory( slug );\n\t\tif ( existingCategory ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst category = await registry\n\t\t\t\t.resolveSelect( coreStore )\n\t\t\t\t.getEntityRecord( ENTITY_KIND, ENTITY_NAME_CATEGORIES, slug );\n\n\t\t\tif ( category ) {\n\t\t\t\tawait dispatch(\n\t\t\t\t\tregisterAbilityCategory( category.slug, {\n\t\t\t\t\t\tlabel: category.label,\n\t\t\t\t\t\tdescription: category.description,\n\t\t\t\t\t\tmeta: category.meta,\n\t\t\t\t\t} )\n\t\t\t\t);\n\t\t\t}\n\t\t} catch ( error ) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug( `Category not found: ${ slug }` );\n\t\t}\n\t};\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,uBAAmC;AAMnC,uBAAiE;AACjE,qBAKO;AAUA,SAAS,eAAe;AAE9B,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAClD,UAAM,oBAAoB,OAAO,aAAa;AAK9C,UAAM,qBAAqB,kBAAkB;AAAA,MAC5C,CAAE,YAAsB,CAAE,QAAQ;AAAA,IACnC;AAEA,QAAK,oBAAqB;AACzB;AAAA,IACD;AAEA,UAAM,YAAY,MAAM,SACtB,cAAe,iBAAAA,KAAU,EACzB,iBAAkB,8BAAa,8BAAa;AAAA,MAC5C,UAAU;AAAA,IACX,CAAE;AAEH,iBAAU,iCAAkB,aAAa,CAAC,CAAE,CAAE;AAAA,EAC/C;AACD;AAQO,SAAS,WAAY,MAAe;AAE1C,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAElD,UAAM,kBAAkB,OAAO,WAAY,IAAK;AAChD,QAAK,iBAAkB;AACtB;AAAA,IACD;AAEA,QAAI;AACH,YAAM,UAAU,MAAM,SACpB,cAAe,iBAAAA,KAAU,EACzB,gBAAiB,8BAAa,8BAAa,IAAK;AAElD,UAAK,SAAU;AACd,cAAM,aAAU,gCAAiB,OAAQ,CAAE;AAAA,MAC5C;AAAA,IACD,SAAU,OAAQ;AAGjB,cAAQ,MAAO,sBAAuB,IAAK,EAAG;AAAA,IAC/C;AAAA,EACD;AACD;AAQO,SAAS,uBAAuB;AAEtC,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAClD,UAAM,qBAAqB,OAAO,qBAAqB;AAKvD,UAAM,sBAAsB,mBAAmB;AAAA,MAC9C,CAAE,aAA+B,CAAE,SAAS,MAAM;AAAA,IACnD;AAEA,QAAK,qBAAsB;AAC1B;AAAA,IACD;AAEA,UAAM,aAAa,MAAM,SACvB,cAAe,iBAAAA,KAAU,EACzB,iBAAkB,8BAAa,yCAAwB;AAAA,MACvD,UAAU;AAAA,IACX,CAAE;AAEH,iBAAU,kCAAmB,cAAc,CAAC,CAAE,CAAE;AAAA,EACjD;AACD;AAQO,SAAS,mBAAoB,MAAe;AAElD,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAIlD,UAAM,mBAAmB,OAAO,mBAAoB,IAAK;AACzD,QAAK,kBAAmB;AACvB;AAAA,IACD;AAEA,QAAI;AACH,YAAM,WAAW,MAAM,SACrB,cAAe,iBAAAA,KAAU,EACzB,gBAAiB,8BAAa,yCAAwB,IAAK;AAE7D,UAAK,UAAW;AACf,cAAM;AAAA,cACL,wCAAyB,SAAS,MAAM;AAAA,YACvC,OAAO,SAAS;AAAA,YAChB,aAAa,SAAS;AAAA,YACtB,MAAM,SAAS;AAAA,UAChB,CAAE;AAAA,QACH;AAAA,MACD;AAAA,IACD,SAAU,OAAQ;AAEjB,cAAQ,MAAO,uBAAwB,IAAK,EAAG;AAAA,IAChD;AAAA,EACD;AACD;",
|
|
6
|
-
"names": ["coreStore"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/selectors.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { createSelector } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tAbility,\n\tAbilityCategory,\n\tAbilitiesQueryArgs,\n\tAbilitiesState,\n} from '../types';\n\n/**\n * Returns all registered abilities.\n * Optionally filters by query arguments.\n *\n * @param state Store state.\n * @param args Optional query arguments to filter. Defaults to empty object.\n * @return Array of abilities.\n */\nexport const getAbilities = createSelector(\n\t(\n\t\tstate: AbilitiesState,\n\t\t{ category }: AbilitiesQueryArgs = {}\n\t): Ability[] => {\n\t\tconst abilities = Object.values( state.abilitiesByName );\n\t\tif ( category ) {\n\t\t\treturn abilities.filter(\n\t\t\t\t( ability ) => ability.category === category\n\t\t\t);\n\t\t}\n\t\treturn abilities;\n\t},\n\t( state: AbilitiesState, category?: string ) => [\n\t\tstate.abilitiesByName,\n\t\tcategory,\n\t]\n);\n\n/**\n * Returns a specific ability by name.\n *\n * @param state Store state.\n * @param name Ability name.\n * @return Ability object or undefined if not found.\n */\nexport function getAbility(\n\tstate: AbilitiesState,\n\tname: string\n): Ability | undefined {\n\treturn state.abilitiesByName[ name ];\n}\n\n/**\n * Returns all registered ability categories.\n *\n * @param state Store state.\n * @return Array of categories.\n */\nexport const getAbilityCategories = createSelector(\n\t( state: AbilitiesState ): AbilityCategory[] => {\n\t\treturn Object.values( state.categoriesBySlug );\n\t},\n\t( state: AbilitiesState ) => [ state.categoriesBySlug ]\n);\n\n/**\n * Returns a specific ability category by slug.\n *\n * @param state Store state.\n * @param slug Category slug.\n * @return Category object or undefined if not found.\n */\nexport function getAbilityCategory(\n\tstate: AbilitiesState,\n\tslug: string\n): AbilityCategory | undefined {\n\treturn state.categoriesBySlug[ slug ];\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA+B;AAoBxB,IAAM,mBAAe;AAAA,EAC3B,CACC,OACA,EAAE,SAAS,IAAwB,CAAC,MACrB;AACf,UAAM,YAAY,OAAO,OAAQ,MAAM,eAAgB;AACvD,QAAK,UAAW;AACf,aAAO,UAAU;AAAA,QAChB,CAAE,YAAa,QAAQ,aAAa;AAAA,MACrC;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EACA,CAAE,OAAuB,aAAuB;AAAA,IAC/C,MAAM;AAAA,IACN;AAAA,EACD;AACD;AASO,SAAS,WACf,OACA,MACsB;AACtB,SAAO,MAAM,gBAAiB,IAAK;AACpC;AAQO,IAAM,2BAAuB;AAAA,EACnC,CAAE,UAA8C;AAC/C,WAAO,OAAO,OAAQ,MAAM,gBAAiB;AAAA,EAC9C;AAAA,EACA,CAAE,UAA2B,CAAE,MAAM,gBAAiB;AACvD;AASO,SAAS,mBACf,OACA,MAC8B;AAC9B,SAAO,MAAM,iBAAkB,IAAK;AACrC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/build/types.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 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 client-side abilities.\n\t * If present, the ability will be executed locally in the browser.\n\t * If not present, the ability will be executed via REST API on the server.\n\t */\n\tcallback?: AbilityCallback;\n\n\t/**\n\t * Client 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 * @see WP_Ability::get_meta()\n\t */\n\tmeta?: {\n\t\tannotations?: {\n\t\t\treadonly?: boolean | null;\n\t\t\tdestructive?: boolean | null;\n\t\t\tidempotent?: boolean | null;\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 * @see WP_Ability_Category::get_meta()\n\t */\n\tmeta?: Record< string, any >;\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 * The state shape for the abilities store.\n */\nexport interface AbilitiesState {\n\t/**\n\t * Map of ability names to ability objects.\n\t */\n\tabilitiesByName: Record< string, Ability >;\n\n\t/**\n\t * Map of category slugs to category objects.\n\t */\n\tcategoriesBySlug: Record< string, AbilityCategory >;\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
|
-
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// packages/abilities/src/store/resolvers.ts
|
|
2
|
-
import { store as coreStore } from "@wordpress/core-data";
|
|
3
|
-
import { ENTITY_KIND, ENTITY_NAME, ENTITY_NAME_CATEGORIES } from "./constants";
|
|
4
|
-
import {
|
|
5
|
-
receiveAbilities,
|
|
6
|
-
receiveCategories,
|
|
7
|
-
registerAbility,
|
|
8
|
-
registerAbilityCategory
|
|
9
|
-
} from "./actions";
|
|
10
|
-
function getAbilities() {
|
|
11
|
-
return async ({ dispatch, registry, select }) => {
|
|
12
|
-
const existingAbilities = select.getAbilities();
|
|
13
|
-
const hasServerAbilities = existingAbilities.some(
|
|
14
|
-
(ability) => !ability.callback
|
|
15
|
-
);
|
|
16
|
-
if (hasServerAbilities) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const abilities = await registry.resolveSelect(coreStore).getEntityRecords(ENTITY_KIND, ENTITY_NAME, {
|
|
20
|
-
per_page: -1
|
|
21
|
-
});
|
|
22
|
-
dispatch(receiveAbilities(abilities || []));
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function getAbility(name) {
|
|
26
|
-
return async ({ dispatch, registry, select }) => {
|
|
27
|
-
const existingAbility = select.getAbility(name);
|
|
28
|
-
if (existingAbility) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
try {
|
|
32
|
-
const ability = await registry.resolveSelect(coreStore).getEntityRecord(ENTITY_KIND, ENTITY_NAME, name);
|
|
33
|
-
if (ability) {
|
|
34
|
-
await dispatch(registerAbility(ability));
|
|
35
|
-
}
|
|
36
|
-
} catch (error) {
|
|
37
|
-
console.debug(`Ability not found: ${name}`);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function getAbilityCategories() {
|
|
42
|
-
return async ({ dispatch, registry, select }) => {
|
|
43
|
-
const existingCategories = select.getAbilityCategories();
|
|
44
|
-
const hasServerCategories = existingCategories.some(
|
|
45
|
-
(category) => !category.meta?._clientRegistered
|
|
46
|
-
);
|
|
47
|
-
if (hasServerCategories) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const categories = await registry.resolveSelect(coreStore).getEntityRecords(ENTITY_KIND, ENTITY_NAME_CATEGORIES, {
|
|
51
|
-
per_page: -1
|
|
52
|
-
});
|
|
53
|
-
dispatch(receiveCategories(categories || []));
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
function getAbilityCategory(slug) {
|
|
57
|
-
return async ({ dispatch, registry, select }) => {
|
|
58
|
-
const existingCategory = select.getAbilityCategory(slug);
|
|
59
|
-
if (existingCategory) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
const category = await registry.resolveSelect(coreStore).getEntityRecord(ENTITY_KIND, ENTITY_NAME_CATEGORIES, slug);
|
|
64
|
-
if (category) {
|
|
65
|
-
await dispatch(
|
|
66
|
-
registerAbilityCategory(category.slug, {
|
|
67
|
-
label: category.label,
|
|
68
|
-
description: category.description,
|
|
69
|
-
meta: category.meta
|
|
70
|
-
})
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.debug(`Category not found: ${slug}`);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
export {
|
|
79
|
-
getAbilities,
|
|
80
|
-
getAbility,
|
|
81
|
-
getAbilityCategories,
|
|
82
|
-
getAbilityCategory
|
|
83
|
-
};
|
|
84
|
-
//# sourceMappingURL=resolvers.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/store/resolvers.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { store as coreStore } from '@wordpress/core-data';\n\n/**\n * Internal dependencies\n */\nimport type { Ability, AbilityCategory } from '../types';\nimport { ENTITY_KIND, ENTITY_NAME, ENTITY_NAME_CATEGORIES } from './constants';\nimport {\n\treceiveAbilities,\n\treceiveCategories,\n\tregisterAbility,\n\tregisterAbilityCategory,\n} from './actions';\n\n/**\n * Resolver for getAbilities selector.\n * Fetches all abilities from the server.\n *\n * The resolver only fetches once (without query args filter) and stores all abilities.\n * Query args filtering handled client-side by the selector for better performance\n * and to avoid multiple API requests when filtering by different categories.\n */\nexport function getAbilities() {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\tconst existingAbilities = select.getAbilities();\n\n\t\t// Check if we have any server-side abilities (abilities without callbacks)\n\t\t// Client abilities have callbacks and are registered immediately on page load\n\t\t// We only want to skip fetching if we've already fetched server abilities\n\t\tconst hasServerAbilities = existingAbilities.some(\n\t\t\t( ability: Ability ) => ! ability.callback\n\t\t);\n\n\t\tif ( hasServerAbilities ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst abilities = await registry\n\t\t\t.resolveSelect( coreStore )\n\t\t\t.getEntityRecords( ENTITY_KIND, ENTITY_NAME, {\n\t\t\t\tper_page: -1,\n\t\t\t} );\n\n\t\tdispatch( receiveAbilities( abilities || [] ) );\n\t};\n}\n\n/**\n * Resolver for getAbility selector.\n * Fetches a specific ability from the server if not already in store.\n *\n * @param name Ability name.\n */\nexport function getAbility( name: string ) {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\t// Check if ability already exists in store (i.e. client ability or already fetched)\n\t\tconst existingAbility = select.getAbility( name );\n\t\tif ( existingAbility ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst ability = await registry\n\t\t\t\t.resolveSelect( coreStore )\n\t\t\t\t.getEntityRecord( ENTITY_KIND, ENTITY_NAME, name );\n\n\t\t\tif ( ability ) {\n\t\t\t\tawait dispatch( registerAbility( ability ) );\n\t\t\t}\n\t\t} catch ( error ) {\n\t\t\t// If ability doesn't exist or error, we'll return undefined from the selector\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug( `Ability not found: ${ name }` );\n\t\t}\n\t};\n}\n\n/**\n * Resolver for getAbilityCategories selector.\n * Fetches all categories from the server.\n *\n * The resolver only fetches once and stores all categories.\n */\nexport function getAbilityCategories() {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\tconst existingCategories = select.getAbilityCategories();\n\n\t\t// Check if we have any server-side categories (categories without meta._clientRegistered flag)\n\t\t// Client categories have meta._clientRegistered=true and might be registered immediately\n\t\t// We only want to skip fetching if we've already fetched server categories\n\t\tconst hasServerCategories = existingCategories.some(\n\t\t\t( category: AbilityCategory ) => ! category.meta?._clientRegistered\n\t\t);\n\n\t\tif ( hasServerCategories ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst categories = await registry\n\t\t\t.resolveSelect( coreStore )\n\t\t\t.getEntityRecords( ENTITY_KIND, ENTITY_NAME_CATEGORIES, {\n\t\t\t\tper_page: -1,\n\t\t\t} );\n\n\t\tdispatch( receiveCategories( categories || [] ) );\n\t};\n}\n\n/**\n * Resolver for getAbilityCategory selector.\n * Fetches a specific category from the server if not already in store.\n *\n * @param slug Category slug.\n */\nexport function getAbilityCategory( slug: string ) {\n\t// @ts-expect-error - registry types are not yet available\n\treturn async ( { dispatch, registry, select } ) => {\n\t\t// Check if category already exists in store (either client-registered or server-fetched).\n\t\t// This prevents unnecessary network requests while allowing client-side categories\n\t\t// to be retrieved immediately without hitting the API.\n\t\tconst existingCategory = select.getAbilityCategory( slug );\n\t\tif ( existingCategory ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst category = await registry\n\t\t\t\t.resolveSelect( coreStore )\n\t\t\t\t.getEntityRecord( ENTITY_KIND, ENTITY_NAME_CATEGORIES, slug );\n\n\t\t\tif ( category ) {\n\t\t\t\tawait dispatch(\n\t\t\t\t\tregisterAbilityCategory( category.slug, {\n\t\t\t\t\t\tlabel: category.label,\n\t\t\t\t\t\tdescription: category.description,\n\t\t\t\t\t\tmeta: category.meta,\n\t\t\t\t\t} )\n\t\t\t\t);\n\t\t\t}\n\t\t} catch ( error ) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug( `Category not found: ${ slug }` );\n\t\t}\n\t};\n}\n"],
|
|
5
|
-
"mappings": ";AAGA,SAAS,SAAS,iBAAiB;AAMnC,SAAS,aAAa,aAAa,8BAA8B;AACjE;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAUA,SAAS,eAAe;AAE9B,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAClD,UAAM,oBAAoB,OAAO,aAAa;AAK9C,UAAM,qBAAqB,kBAAkB;AAAA,MAC5C,CAAE,YAAsB,CAAE,QAAQ;AAAA,IACnC;AAEA,QAAK,oBAAqB;AACzB;AAAA,IACD;AAEA,UAAM,YAAY,MAAM,SACtB,cAAe,SAAU,EACzB,iBAAkB,aAAa,aAAa;AAAA,MAC5C,UAAU;AAAA,IACX,CAAE;AAEH,aAAU,iBAAkB,aAAa,CAAC,CAAE,CAAE;AAAA,EAC/C;AACD;AAQO,SAAS,WAAY,MAAe;AAE1C,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAElD,UAAM,kBAAkB,OAAO,WAAY,IAAK;AAChD,QAAK,iBAAkB;AACtB;AAAA,IACD;AAEA,QAAI;AACH,YAAM,UAAU,MAAM,SACpB,cAAe,SAAU,EACzB,gBAAiB,aAAa,aAAa,IAAK;AAElD,UAAK,SAAU;AACd,cAAM,SAAU,gBAAiB,OAAQ,CAAE;AAAA,MAC5C;AAAA,IACD,SAAU,OAAQ;AAGjB,cAAQ,MAAO,sBAAuB,IAAK,EAAG;AAAA,IAC/C;AAAA,EACD;AACD;AAQO,SAAS,uBAAuB;AAEtC,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAClD,UAAM,qBAAqB,OAAO,qBAAqB;AAKvD,UAAM,sBAAsB,mBAAmB;AAAA,MAC9C,CAAE,aAA+B,CAAE,SAAS,MAAM;AAAA,IACnD;AAEA,QAAK,qBAAsB;AAC1B;AAAA,IACD;AAEA,UAAM,aAAa,MAAM,SACvB,cAAe,SAAU,EACzB,iBAAkB,aAAa,wBAAwB;AAAA,MACvD,UAAU;AAAA,IACX,CAAE;AAEH,aAAU,kBAAmB,cAAc,CAAC,CAAE,CAAE;AAAA,EACjD;AACD;AAQO,SAAS,mBAAoB,MAAe;AAElD,SAAO,OAAQ,EAAE,UAAU,UAAU,OAAO,MAAO;AAIlD,UAAM,mBAAmB,OAAO,mBAAoB,IAAK;AACzD,QAAK,kBAAmB;AACvB;AAAA,IACD;AAEA,QAAI;AACH,YAAM,WAAW,MAAM,SACrB,cAAe,SAAU,EACzB,gBAAiB,aAAa,wBAAwB,IAAK;AAE7D,UAAK,UAAW;AACf,cAAM;AAAA,UACL,wBAAyB,SAAS,MAAM;AAAA,YACvC,OAAO,SAAS;AAAA,YAChB,aAAa,SAAS;AAAA,YACtB,MAAM,SAAS;AAAA,UAChB,CAAE;AAAA,QACH;AAAA,MACD;AAAA,IACD,SAAU,OAAQ;AAEjB,cAAQ,MAAO,uBAAwB,IAAK,EAAG;AAAA,IAChD;AAAA,EACD;AACD;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolver for getAbilities selector.
|
|
3
|
-
* Fetches all abilities from the server.
|
|
4
|
-
*
|
|
5
|
-
* The resolver only fetches once (without query args filter) and stores all abilities.
|
|
6
|
-
* Query args filtering handled client-side by the selector for better performance
|
|
7
|
-
* and to avoid multiple API requests when filtering by different categories.
|
|
8
|
-
*/
|
|
9
|
-
export declare function getAbilities(): ({ dispatch, registry, select }: {
|
|
10
|
-
dispatch: any;
|
|
11
|
-
registry: any;
|
|
12
|
-
select: any;
|
|
13
|
-
}) => Promise<void>;
|
|
14
|
-
/**
|
|
15
|
-
* Resolver for getAbility selector.
|
|
16
|
-
* Fetches a specific ability from the server if not already in store.
|
|
17
|
-
*
|
|
18
|
-
* @param name Ability name.
|
|
19
|
-
*/
|
|
20
|
-
export declare function getAbility(name: string): ({ dispatch, registry, select }: {
|
|
21
|
-
dispatch: any;
|
|
22
|
-
registry: any;
|
|
23
|
-
select: any;
|
|
24
|
-
}) => Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Resolver for getAbilityCategories selector.
|
|
27
|
-
* Fetches all categories from the server.
|
|
28
|
-
*
|
|
29
|
-
* The resolver only fetches once and stores all categories.
|
|
30
|
-
*/
|
|
31
|
-
export declare function getAbilityCategories(): ({ dispatch, registry, select }: {
|
|
32
|
-
dispatch: any;
|
|
33
|
-
registry: any;
|
|
34
|
-
select: any;
|
|
35
|
-
}) => Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* Resolver for getAbilityCategory selector.
|
|
38
|
-
* Fetches a specific category from the server if not already in store.
|
|
39
|
-
*
|
|
40
|
-
* @param slug Category slug.
|
|
41
|
-
*/
|
|
42
|
-
export declare function getAbilityCategory(slug: string): ({ dispatch, registry, select }: {
|
|
43
|
-
dispatch: any;
|
|
44
|
-
registry: any;
|
|
45
|
-
select: any;
|
|
46
|
-
}) => Promise<void>;
|
|
47
|
-
//# sourceMappingURL=resolvers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../src/store/resolvers.ts"],"names":[],"mappings":"AAiBA;;;;;;;GAOG;AACH,wBAAgB,YAAY,KAEZ;;;;CAA8B,mBAsB7C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAE,IAAI,EAAE,MAAM,IAExB;;;;CAA8B,mBAqB7C;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,KAEpB;;;;CAA8B,mBAsB7C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAE,IAAI,EAAE,MAAM,IAEhC;;;;CAA8B,mBA4B7C"}
|
package/src/store/resolvers.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WordPress dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { store as coreStore } from '@wordpress/core-data';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Internal dependencies
|
|
8
|
-
*/
|
|
9
|
-
import type { Ability, AbilityCategory } from '../types';
|
|
10
|
-
import { ENTITY_KIND, ENTITY_NAME, ENTITY_NAME_CATEGORIES } from './constants';
|
|
11
|
-
import {
|
|
12
|
-
receiveAbilities,
|
|
13
|
-
receiveCategories,
|
|
14
|
-
registerAbility,
|
|
15
|
-
registerAbilityCategory,
|
|
16
|
-
} from './actions';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Resolver for getAbilities selector.
|
|
20
|
-
* Fetches all abilities from the server.
|
|
21
|
-
*
|
|
22
|
-
* The resolver only fetches once (without query args filter) and stores all abilities.
|
|
23
|
-
* Query args filtering handled client-side by the selector for better performance
|
|
24
|
-
* and to avoid multiple API requests when filtering by different categories.
|
|
25
|
-
*/
|
|
26
|
-
export function getAbilities() {
|
|
27
|
-
// @ts-expect-error - registry types are not yet available
|
|
28
|
-
return async ( { dispatch, registry, select } ) => {
|
|
29
|
-
const existingAbilities = select.getAbilities();
|
|
30
|
-
|
|
31
|
-
// Check if we have any server-side abilities (abilities without callbacks)
|
|
32
|
-
// Client abilities have callbacks and are registered immediately on page load
|
|
33
|
-
// We only want to skip fetching if we've already fetched server abilities
|
|
34
|
-
const hasServerAbilities = existingAbilities.some(
|
|
35
|
-
( ability: Ability ) => ! ability.callback
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
if ( hasServerAbilities ) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const abilities = await registry
|
|
43
|
-
.resolveSelect( coreStore )
|
|
44
|
-
.getEntityRecords( ENTITY_KIND, ENTITY_NAME, {
|
|
45
|
-
per_page: -1,
|
|
46
|
-
} );
|
|
47
|
-
|
|
48
|
-
dispatch( receiveAbilities( abilities || [] ) );
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Resolver for getAbility selector.
|
|
54
|
-
* Fetches a specific ability from the server if not already in store.
|
|
55
|
-
*
|
|
56
|
-
* @param name Ability name.
|
|
57
|
-
*/
|
|
58
|
-
export function getAbility( name: string ) {
|
|
59
|
-
// @ts-expect-error - registry types are not yet available
|
|
60
|
-
return async ( { dispatch, registry, select } ) => {
|
|
61
|
-
// Check if ability already exists in store (i.e. client ability or already fetched)
|
|
62
|
-
const existingAbility = select.getAbility( name );
|
|
63
|
-
if ( existingAbility ) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const ability = await registry
|
|
69
|
-
.resolveSelect( coreStore )
|
|
70
|
-
.getEntityRecord( ENTITY_KIND, ENTITY_NAME, name );
|
|
71
|
-
|
|
72
|
-
if ( ability ) {
|
|
73
|
-
await dispatch( registerAbility( ability ) );
|
|
74
|
-
}
|
|
75
|
-
} catch ( error ) {
|
|
76
|
-
// If ability doesn't exist or error, we'll return undefined from the selector
|
|
77
|
-
// eslint-disable-next-line no-console
|
|
78
|
-
console.debug( `Ability not found: ${ name }` );
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Resolver for getAbilityCategories selector.
|
|
85
|
-
* Fetches all categories from the server.
|
|
86
|
-
*
|
|
87
|
-
* The resolver only fetches once and stores all categories.
|
|
88
|
-
*/
|
|
89
|
-
export function getAbilityCategories() {
|
|
90
|
-
// @ts-expect-error - registry types are not yet available
|
|
91
|
-
return async ( { dispatch, registry, select } ) => {
|
|
92
|
-
const existingCategories = select.getAbilityCategories();
|
|
93
|
-
|
|
94
|
-
// Check if we have any server-side categories (categories without meta._clientRegistered flag)
|
|
95
|
-
// Client categories have meta._clientRegistered=true and might be registered immediately
|
|
96
|
-
// We only want to skip fetching if we've already fetched server categories
|
|
97
|
-
const hasServerCategories = existingCategories.some(
|
|
98
|
-
( category: AbilityCategory ) => ! category.meta?._clientRegistered
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
if ( hasServerCategories ) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const categories = await registry
|
|
106
|
-
.resolveSelect( coreStore )
|
|
107
|
-
.getEntityRecords( ENTITY_KIND, ENTITY_NAME_CATEGORIES, {
|
|
108
|
-
per_page: -1,
|
|
109
|
-
} );
|
|
110
|
-
|
|
111
|
-
dispatch( receiveCategories( categories || [] ) );
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Resolver for getAbilityCategory selector.
|
|
117
|
-
* Fetches a specific category from the server if not already in store.
|
|
118
|
-
*
|
|
119
|
-
* @param slug Category slug.
|
|
120
|
-
*/
|
|
121
|
-
export function getAbilityCategory( slug: string ) {
|
|
122
|
-
// @ts-expect-error - registry types are not yet available
|
|
123
|
-
return async ( { dispatch, registry, select } ) => {
|
|
124
|
-
// Check if category already exists in store (either client-registered or server-fetched).
|
|
125
|
-
// This prevents unnecessary network requests while allowing client-side categories
|
|
126
|
-
// to be retrieved immediately without hitting the API.
|
|
127
|
-
const existingCategory = select.getAbilityCategory( slug );
|
|
128
|
-
if ( existingCategory ) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const category = await registry
|
|
134
|
-
.resolveSelect( coreStore )
|
|
135
|
-
.getEntityRecord( ENTITY_KIND, ENTITY_NAME_CATEGORIES, slug );
|
|
136
|
-
|
|
137
|
-
if ( category ) {
|
|
138
|
-
await dispatch(
|
|
139
|
-
registerAbilityCategory( category.slug, {
|
|
140
|
-
label: category.label,
|
|
141
|
-
description: category.description,
|
|
142
|
-
meta: category.meta,
|
|
143
|
-
} )
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
} catch ( error ) {
|
|
147
|
-
// eslint-disable-next-line no-console
|
|
148
|
-
console.debug( `Category not found: ${ slug }` );
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
}
|