@wordpress/abilities 0.1.1-next.dc3f6d3c1.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 +9 -0
- package/LICENSE.md +788 -0
- package/README.md +302 -0
- package/build/api.js +189 -0
- package/build/api.js.map +7 -0
- package/build/index.js +53 -0
- package/build/index.js.map +7 -0
- package/build/store/actions.js +183 -0
- package/build/store/actions.js.map +7 -0
- package/build/store/constants.js +58 -0
- package/build/store/constants.js.map +7 -0
- package/build/store/index.js +77 -0
- package/build/store/index.js.map +7 -0
- package/build/store/reducer.js +126 -0
- package/build/store/reducer.js.map +7 -0
- package/build/store/resolvers.js +107 -0
- package/build/store/resolvers.js.map +7 -0
- package/build/store/selectors.js +64 -0
- package/build/store/selectors.js.map +7 -0
- package/build/store/tests/actions.test.js +792 -0
- package/build/store/tests/actions.test.js.map +7 -0
- package/build/store/tests/reducer.test.js +743 -0
- package/build/store/tests/reducer.test.js.map +7 -0
- package/build/store/tests/resolvers.test.js +520 -0
- package/build/store/tests/resolvers.test.js.map +7 -0
- package/build/store/tests/selectors.test.js +349 -0
- package/build/store/tests/selectors.test.js.map +7 -0
- package/build/tests/api.test.js +546 -0
- package/build/tests/api.test.js.map +7 -0
- package/build/tests/validation.test.js +453 -0
- package/build/tests/validation.test.js.map +7 -0
- package/build/types.js +19 -0
- package/build/types.js.map +7 -0
- package/build/validation.js +144 -0
- package/build/validation.js.map +7 -0
- package/build-module/api.js +146 -0
- package/build-module/api.js.map +7 -0
- package/build-module/index.js +28 -0
- package/build-module/index.js.map +7 -0
- package/build-module/store/actions.js +161 -0
- package/build-module/store/actions.js.map +7 -0
- package/build-module/store/constants.js +24 -0
- package/build-module/store/constants.js.map +7 -0
- package/build-module/store/index.js +47 -0
- package/build-module/store/index.js.map +7 -0
- package/build-module/store/reducer.js +112 -0
- package/build-module/store/reducer.js.map +7 -0
- package/build-module/store/resolvers.js +84 -0
- package/build-module/store/resolvers.js.map +7 -0
- package/build-module/store/selectors.js +36 -0
- package/build-module/store/selectors.js.map +7 -0
- package/build-module/store/tests/actions.test.js +804 -0
- package/build-module/store/tests/actions.test.js.map +7 -0
- package/build-module/store/tests/reducer.test.js +726 -0
- package/build-module/store/tests/reducer.test.js.map +7 -0
- package/build-module/store/tests/resolvers.test.js +523 -0
- package/build-module/store/tests/resolvers.test.js.map +7 -0
- package/build-module/store/tests/selectors.test.js +352 -0
- package/build-module/store/tests/selectors.test.js.map +7 -0
- package/build-module/tests/api.test.js +530 -0
- package/build-module/tests/api.test.js.map +7 -0
- package/build-module/tests/validation.test.js +451 -0
- package/build-module/tests/validation.test.js.map +7 -0
- package/build-module/types.js +1 -0
- package/build-module/types.js.map +7 -0
- package/build-module/validation.js +109 -0
- package/build-module/validation.js.map +7 -0
- package/build-types/api.d.ts +138 -0
- package/build-types/api.d.ts.map +1 -0
- package/build-types/index.d.ts +41 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/store/actions.d.ts +76 -0
- package/build-types/store/actions.d.ts.map +1 -0
- package/build-types/store/constants.d.ts +14 -0
- package/build-types/store/constants.d.ts.map +1 -0
- package/build-types/store/index.d.ts +7 -0
- package/build-types/store/index.d.ts.map +1 -0
- package/build-types/store/reducer.d.ts +22 -0
- package/build-types/store/reducer.d.ts.map +1 -0
- package/build-types/store/resolvers.d.ts +47 -0
- package/build-types/store/resolvers.d.ts.map +1 -0
- package/build-types/store/selectors.d.ts +37 -0
- package/build-types/store/selectors.d.ts.map +1 -0
- package/build-types/types.d.ts +163 -0
- package/build-types/types.d.ts.map +1 -0
- package/build-types/validation.d.ts +23 -0
- package/build-types/validation.d.ts.map +1 -0
- package/package.json +52 -0
- package/src/api.ts +339 -0
- package/src/index.ts +65 -0
- package/src/store/actions.ts +247 -0
- package/src/store/constants.ts +15 -0
- package/src/store/index.ts +55 -0
- package/src/store/reducer.ts +184 -0
- package/src/store/resolvers.ts +151 -0
- package/src/store/selectors.ts +82 -0
- package/src/store/tests/actions.test.ts +950 -0
- package/src/store/tests/reducer.test.ts +861 -0
- package/src/store/tests/resolvers.test.ts +642 -0
- package/src/store/tests/selectors.test.ts +412 -0
- package/src/tests/api.test.ts +655 -0
- package/src/tests/validation.test.ts +532 -0
- package/src/types.ts +190 -0
- package/src/validation.ts +207 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// packages/abilities/src/validation.ts
|
|
31
|
+
var validation_exports = {};
|
|
32
|
+
__export(validation_exports, {
|
|
33
|
+
validateValueFromSchema: () => validateValueFromSchema
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(validation_exports);
|
|
36
|
+
var import_ajv_draft_04 = __toESM(require("ajv-draft-04"));
|
|
37
|
+
var import_ajv_formats = __toESM(require("ajv-formats"));
|
|
38
|
+
var ajv = new import_ajv_draft_04.default({
|
|
39
|
+
coerceTypes: false,
|
|
40
|
+
// No type coercion - AI should send proper JSON
|
|
41
|
+
useDefaults: true,
|
|
42
|
+
removeAdditional: false,
|
|
43
|
+
// Keep additional properties
|
|
44
|
+
allErrors: true,
|
|
45
|
+
verbose: true,
|
|
46
|
+
allowUnionTypes: true
|
|
47
|
+
// Allow anyOf without explicit type
|
|
48
|
+
});
|
|
49
|
+
(0, import_ajv_formats.default)(ajv, ["date-time", "email", "hostname", "ipv4", "ipv6", "uuid"]);
|
|
50
|
+
function formatAjvError(ajvError, param) {
|
|
51
|
+
const instancePath = ajvError.instancePath ? ajvError.instancePath.replace(/\//g, "][").replace(/^\]\[/, "[") + "]" : "";
|
|
52
|
+
const fullParam = param + instancePath;
|
|
53
|
+
switch (ajvError.keyword) {
|
|
54
|
+
case "type":
|
|
55
|
+
return `${fullParam} is not of type ${ajvError.params.type}.`;
|
|
56
|
+
case "required":
|
|
57
|
+
return `${ajvError.params.missingProperty} is a required property of ${fullParam}.`;
|
|
58
|
+
case "additionalProperties":
|
|
59
|
+
return `${ajvError.params.additionalProperty} is not a valid property of Object.`;
|
|
60
|
+
case "enum":
|
|
61
|
+
const enumValues = ajvError.params.allowedValues.map(
|
|
62
|
+
(v) => typeof v === "string" ? v : JSON.stringify(v)
|
|
63
|
+
).join(", ");
|
|
64
|
+
return ajvError.params.allowedValues.length === 1 ? `${fullParam} is not ${enumValues}.` : `${fullParam} is not one of ${enumValues}.`;
|
|
65
|
+
case "pattern":
|
|
66
|
+
return `${fullParam} does not match pattern ${ajvError.params.pattern}.`;
|
|
67
|
+
case "format":
|
|
68
|
+
const format = ajvError.params.format;
|
|
69
|
+
const formatMessages = {
|
|
70
|
+
email: "Invalid email address.",
|
|
71
|
+
"date-time": "Invalid date.",
|
|
72
|
+
uuid: `${fullParam} is not a valid UUID.`,
|
|
73
|
+
ipv4: `${fullParam} is not a valid IP address.`,
|
|
74
|
+
ipv6: `${fullParam} is not a valid IP address.`,
|
|
75
|
+
hostname: `${fullParam} is not a valid hostname.`
|
|
76
|
+
};
|
|
77
|
+
return formatMessages[format] || `Invalid ${format}.`;
|
|
78
|
+
case "minimum":
|
|
79
|
+
case "exclusiveMinimum":
|
|
80
|
+
return ajvError.keyword === "exclusiveMinimum" ? `${fullParam} must be greater than ${ajvError.params.limit}` : `${fullParam} must be greater than or equal to ${ajvError.params.limit}`;
|
|
81
|
+
case "maximum":
|
|
82
|
+
case "exclusiveMaximum":
|
|
83
|
+
return ajvError.keyword === "exclusiveMaximum" ? `${fullParam} must be less than ${ajvError.params.limit}` : `${fullParam} must be less than or equal to ${ajvError.params.limit}`;
|
|
84
|
+
case "multipleOf":
|
|
85
|
+
return `${fullParam} must be a multiple of ${ajvError.params.multipleOf}.`;
|
|
86
|
+
case "anyOf":
|
|
87
|
+
case "oneOf":
|
|
88
|
+
return `${fullParam} is invalid (failed ${ajvError.keyword} validation).`;
|
|
89
|
+
case "minLength":
|
|
90
|
+
return `${fullParam} must be at least ${ajvError.params.limit} character${ajvError.params.limit === 1 ? "" : "s"} long.`;
|
|
91
|
+
case "maxLength":
|
|
92
|
+
return `${fullParam} must be at most ${ajvError.params.limit} character${ajvError.params.limit === 1 ? "" : "s"} long.`;
|
|
93
|
+
case "minItems":
|
|
94
|
+
return `${fullParam} must contain at least ${ajvError.params.limit} item${ajvError.params.limit === 1 ? "" : "s"}.`;
|
|
95
|
+
case "maxItems":
|
|
96
|
+
return `${fullParam} must contain at most ${ajvError.params.limit} item${ajvError.params.limit === 1 ? "" : "s"}.`;
|
|
97
|
+
case "uniqueItems":
|
|
98
|
+
return `${fullParam} has duplicate items.`;
|
|
99
|
+
case "minProperties":
|
|
100
|
+
return `${fullParam} must contain at least ${ajvError.params.limit} propert${ajvError.params.limit === 1 ? "y" : "ies"}.`;
|
|
101
|
+
case "maxProperties":
|
|
102
|
+
return `${fullParam} must contain at most ${ajvError.params.limit} propert${ajvError.params.limit === 1 ? "y" : "ies"}.`;
|
|
103
|
+
default:
|
|
104
|
+
return ajvError.message || `${fullParam} is invalid (failed ${ajvError.keyword} validation).`;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function validateValueFromSchema(value, args, param = "") {
|
|
108
|
+
if (!args || typeof args !== "object") {
|
|
109
|
+
console.warn(`Schema must be an object. Received ${typeof args}.`);
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (!args.type && !args.anyOf && !args.oneOf) {
|
|
113
|
+
console.warn(
|
|
114
|
+
`The "type" schema keyword for ${param || "value"} is required.`
|
|
115
|
+
);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const { default: defaultValue, ...schemaWithoutDefault } = args;
|
|
120
|
+
const validate = ajv.compile(schemaWithoutDefault);
|
|
121
|
+
const valid = validate(value === void 0 ? defaultValue : value);
|
|
122
|
+
if (valid) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (validate.errors && validate.errors.length > 0) {
|
|
126
|
+
const anyOfError = validate.errors.find(
|
|
127
|
+
(e) => e.keyword === "anyOf" || e.keyword === "oneOf"
|
|
128
|
+
);
|
|
129
|
+
if (anyOfError) {
|
|
130
|
+
return formatAjvError(anyOfError, param);
|
|
131
|
+
}
|
|
132
|
+
return formatAjvError(validate.errors[0], param);
|
|
133
|
+
}
|
|
134
|
+
return `${param} is invalid.`;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error("Schema compilation error:", error);
|
|
137
|
+
return "Invalid schema provided for validation.";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
141
|
+
0 && (module.exports = {
|
|
142
|
+
validateValueFromSchema
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/validation.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Schema validation for client-side ability input and output schemas using AJV and ajv-formats.\n *\n * This utility provides validation for JSON Schema draft-04.\n * Rules are configured to support the intersection of common rules between JSON Schema draft-04, WordPress (a subset of JSON Schema draft-04),\n * and various providers like OpenAI and Anthropic.\n *\n * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/#json-schema-basics\n */\n\n/**\n * External dependencies\n */\nimport Ajv from 'ajv-draft-04';\nimport addFormats from 'ajv-formats';\n\n/**\n * Internal dependencies\n */\nimport type { ValidationError } from './types';\n\nconst ajv = new Ajv( {\n\tcoerceTypes: false, // No type coercion - AI should send proper JSON\n\tuseDefaults: true,\n\tremoveAdditional: false, // Keep additional properties\n\tallErrors: true,\n\tverbose: true,\n\tallowUnionTypes: true, // Allow anyOf without explicit type\n} );\n\naddFormats( ajv, [ 'date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uuid' ] );\n\n/**\n * Formats AJV errors into a simple error message.\n * The Abilities API will wrap this with ability_invalid_input/output to match the server side format.\n *\n * @param ajvError The AJV validation error.\n * @param param The base parameter name.\n * @return Simple error message string.\n */\nfunction formatAjvError( ajvError: any, param: string ): string {\n\t// Convert AJV's instancePath format (/0/prop) to an array like format to better match WordPress ([0][prop])\n\tconst instancePath = ajvError.instancePath\n\t\t? ajvError.instancePath.replace( /\\//g, '][' ).replace( /^\\]\\[/, '[' ) +\n\t\t ']'\n\t\t: '';\n\tconst fullParam = param + instancePath;\n\n\tswitch ( ajvError.keyword ) {\n\t\tcase 'type':\n\t\t\treturn `${ fullParam } is not of type ${ ajvError.params.type }.`;\n\n\t\tcase 'required':\n\t\t\treturn `${ ajvError.params.missingProperty } is a required property of ${ fullParam }.`;\n\n\t\tcase 'additionalProperties':\n\t\t\treturn `${ ajvError.params.additionalProperty } is not a valid property of Object.`;\n\n\t\tcase 'enum':\n\t\t\tconst enumValues = ajvError.params.allowedValues\n\t\t\t\t.map( ( v: any ) =>\n\t\t\t\t\ttypeof v === 'string' ? v : JSON.stringify( v )\n\t\t\t\t)\n\t\t\t\t.join( ', ' );\n\t\t\treturn ajvError.params.allowedValues.length === 1\n\t\t\t\t? `${ fullParam } is not ${ enumValues }.`\n\t\t\t\t: `${ fullParam } is not one of ${ enumValues }.`;\n\n\t\tcase 'pattern':\n\t\t\treturn `${ fullParam } does not match pattern ${ ajvError.params.pattern }.`;\n\n\t\tcase 'format':\n\t\t\tconst format = ajvError.params.format;\n\t\t\tconst formatMessages: Record< string, string > = {\n\t\t\t\temail: 'Invalid email address.',\n\t\t\t\t'date-time': 'Invalid date.',\n\t\t\t\tuuid: `${ fullParam } is not a valid UUID.`,\n\t\t\t\tipv4: `${ fullParam } is not a valid IP address.`,\n\t\t\t\tipv6: `${ fullParam } is not a valid IP address.`,\n\t\t\t\thostname: `${ fullParam } is not a valid hostname.`,\n\t\t\t};\n\t\t\treturn formatMessages[ format ] || `Invalid ${ format }.`;\n\n\t\tcase 'minimum':\n\t\tcase 'exclusiveMinimum':\n\t\t\treturn ajvError.keyword === 'exclusiveMinimum'\n\t\t\t\t? `${ fullParam } must be greater than ${ ajvError.params.limit }`\n\t\t\t\t: `${ fullParam } must be greater than or equal to ${ ajvError.params.limit }`;\n\n\t\tcase 'maximum':\n\t\tcase 'exclusiveMaximum':\n\t\t\treturn ajvError.keyword === 'exclusiveMaximum'\n\t\t\t\t? `${ fullParam } must be less than ${ ajvError.params.limit }`\n\t\t\t\t: `${ fullParam } must be less than or equal to ${ ajvError.params.limit }`;\n\n\t\tcase 'multipleOf':\n\t\t\treturn `${ fullParam } must be a multiple of ${ ajvError.params.multipleOf }.`;\n\n\t\tcase 'anyOf':\n\t\tcase 'oneOf':\n\t\t\treturn `${ fullParam } is invalid (failed ${ ajvError.keyword } validation).`;\n\n\t\tcase 'minLength':\n\t\t\treturn `${ fullParam } must be at least ${\n\t\t\t\tajvError.params.limit\n\t\t\t} character${ ajvError.params.limit === 1 ? '' : 's' } long.`;\n\n\t\tcase 'maxLength':\n\t\t\treturn `${ fullParam } must be at most ${\n\t\t\t\tajvError.params.limit\n\t\t\t} character${ ajvError.params.limit === 1 ? '' : 's' } long.`;\n\n\t\tcase 'minItems':\n\t\t\treturn `${ fullParam } must contain at least ${\n\t\t\t\tajvError.params.limit\n\t\t\t} item${ ajvError.params.limit === 1 ? '' : 's' }.`;\n\n\t\tcase 'maxItems':\n\t\t\treturn `${ fullParam } must contain at most ${\n\t\t\t\tajvError.params.limit\n\t\t\t} item${ ajvError.params.limit === 1 ? '' : 's' }.`;\n\n\t\tcase 'uniqueItems':\n\t\t\treturn `${ fullParam } has duplicate items.`;\n\n\t\tcase 'minProperties':\n\t\t\treturn `${ fullParam } must contain at least ${\n\t\t\t\tajvError.params.limit\n\t\t\t} propert${ ajvError.params.limit === 1 ? 'y' : 'ies' }.`;\n\n\t\tcase 'maxProperties':\n\t\t\treturn `${ fullParam } must contain at most ${\n\t\t\t\tajvError.params.limit\n\t\t\t} propert${ ajvError.params.limit === 1 ? 'y' : 'ies' }.`;\n\n\t\tdefault:\n\t\t\t// Fallback for any unhandled validation keywords\n\t\t\treturn (\n\t\t\t\tajvError.message ||\n\t\t\t\t`${ fullParam } is invalid (failed ${ ajvError.keyword } validation).`\n\t\t\t);\n\t}\n}\n\n/**\n * Validates a value against a JSON Schema.\n *\n * @param value The value to validate.\n * @param args The JSON Schema to validate against.\n * @param param Optional parameter name for error messages.\n * @return True if valid, error message string if invalid.\n */\nexport function validateValueFromSchema(\n\tvalue: any,\n\targs: Record< string, any >,\n\tparam = ''\n): true | ValidationError {\n\t// WordPress server expects schema to be an array/object\n\tif ( ! args || typeof args !== 'object' ) {\n\t\t// WordPress issues a _doing_it_wrong for invalid schema\n\t\t// Match this behavior with console.warn on client-side\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn( `Schema must be an object. Received ${ typeof args }.` );\n\t\t// Continue validation, treating as valid (matching server behavior)\n\t\treturn true;\n\t}\n\n\t// Type validation - WordPress REST API requires type to be set\n\tif ( ! args.type && ! args.anyOf && ! args.oneOf ) {\n\t\t// WordPress issues a _doing_it_wrong but continues\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(\n\t\t\t`The \"type\" schema keyword for ${ param || 'value' } is required.`\n\t\t);\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst { default: defaultValue, ...schemaWithoutDefault } = args;\n\t\tconst validate = ajv.compile( schemaWithoutDefault );\n\t\tconst valid = validate( value === undefined ? defaultValue : value );\n\n\t\tif ( valid ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Return the first error as a simple message string\n\t\t// The API will wrap this with ability_invalid_input/output\n\t\tif ( validate.errors && validate.errors.length > 0 ) {\n\t\t\t// For anyOf/oneOf, look for the more specific error\n\t\t\tconst anyOfError = validate.errors.find(\n\t\t\t\t( e ) => e.keyword === 'anyOf' || e.keyword === 'oneOf'\n\t\t\t);\n\t\t\tif ( anyOfError ) {\n\t\t\t\treturn formatAjvError( anyOfError, param );\n\t\t\t}\n\t\t\treturn formatAjvError( validate.errors[ 0 ], param );\n\t\t}\n\n\t\treturn `${ param } is invalid.`;\n\t} catch ( error ) {\n\t\t// Handle schema compilation errors\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error( 'Schema compilation error:', error );\n\t\treturn 'Invalid schema provided for validation.';\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Ajv", "addFormats"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// packages/abilities/src/api.ts
|
|
2
|
+
import { dispatch, resolveSelect } from "@wordpress/data";
|
|
3
|
+
import apiFetch from "@wordpress/api-fetch";
|
|
4
|
+
import { addQueryArgs } from "@wordpress/url";
|
|
5
|
+
import { sprintf } from "@wordpress/i18n";
|
|
6
|
+
import { store } from "./store";
|
|
7
|
+
import { validateValueFromSchema } from "./validation";
|
|
8
|
+
async function getAbilities(args = {}) {
|
|
9
|
+
return await resolveSelect(store).getAbilities(args);
|
|
10
|
+
}
|
|
11
|
+
async function getAbility(name) {
|
|
12
|
+
return await resolveSelect(store).getAbility(name);
|
|
13
|
+
}
|
|
14
|
+
async function getAbilityCategories() {
|
|
15
|
+
return await resolveSelect(store).getAbilityCategories();
|
|
16
|
+
}
|
|
17
|
+
async function getAbilityCategory(slug) {
|
|
18
|
+
return await resolveSelect(store).getAbilityCategory(slug);
|
|
19
|
+
}
|
|
20
|
+
async function registerAbility(ability) {
|
|
21
|
+
await dispatch(store).registerAbility(ability);
|
|
22
|
+
}
|
|
23
|
+
function unregisterAbility(name) {
|
|
24
|
+
dispatch(store).unregisterAbility(name);
|
|
25
|
+
}
|
|
26
|
+
async function registerAbilityCategory(slug, args) {
|
|
27
|
+
await dispatch(store).registerAbilityCategory(slug, args);
|
|
28
|
+
}
|
|
29
|
+
function unregisterAbilityCategory(slug) {
|
|
30
|
+
dispatch(store).unregisterAbilityCategory(slug);
|
|
31
|
+
}
|
|
32
|
+
async function executeClientAbility(ability, input) {
|
|
33
|
+
if (!ability.callback) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
sprintf(
|
|
36
|
+
"Client ability %s is missing callback function",
|
|
37
|
+
ability.name
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (ability.permissionCallback) {
|
|
42
|
+
const hasPermission = await ability.permissionCallback(input);
|
|
43
|
+
if (!hasPermission) {
|
|
44
|
+
const error = new Error(
|
|
45
|
+
sprintf("Permission denied for ability: %s", ability.name)
|
|
46
|
+
);
|
|
47
|
+
error.code = "ability_permission_denied";
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (ability.input_schema) {
|
|
52
|
+
const inputValidation = validateValueFromSchema(
|
|
53
|
+
input,
|
|
54
|
+
ability.input_schema,
|
|
55
|
+
"input"
|
|
56
|
+
);
|
|
57
|
+
if (inputValidation !== true) {
|
|
58
|
+
const error = new Error(
|
|
59
|
+
sprintf(
|
|
60
|
+
'Ability "%1$s" has invalid input. Reason: %2$s',
|
|
61
|
+
ability.name,
|
|
62
|
+
inputValidation
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
error.code = "ability_invalid_input";
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let result;
|
|
70
|
+
try {
|
|
71
|
+
result = await ability.callback(input);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(
|
|
74
|
+
`Error executing client ability ${ability.name}:`,
|
|
75
|
+
error
|
|
76
|
+
);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
if (ability.output_schema) {
|
|
80
|
+
const outputValidation = validateValueFromSchema(
|
|
81
|
+
result,
|
|
82
|
+
ability.output_schema,
|
|
83
|
+
"output"
|
|
84
|
+
);
|
|
85
|
+
if (outputValidation !== true) {
|
|
86
|
+
const error = new Error(
|
|
87
|
+
sprintf(
|
|
88
|
+
'Ability "%1$s" has invalid output. Reason: %2$s',
|
|
89
|
+
ability.name,
|
|
90
|
+
outputValidation
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
error.code = "ability_invalid_output";
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
async function executeServerAbility(ability, input) {
|
|
100
|
+
let method = "POST";
|
|
101
|
+
if (!!ability.meta?.annotations?.readonly) {
|
|
102
|
+
method = "GET";
|
|
103
|
+
} else if (!!ability.meta?.annotations?.destructive && !!ability.meta?.annotations?.idempotent) {
|
|
104
|
+
method = "DELETE";
|
|
105
|
+
}
|
|
106
|
+
let path = `/wp-abilities/v1/abilities/${ability.name}/run`;
|
|
107
|
+
const options = {
|
|
108
|
+
method
|
|
109
|
+
};
|
|
110
|
+
if (["GET", "DELETE"].includes(method) && input !== null) {
|
|
111
|
+
path = addQueryArgs(path, { input });
|
|
112
|
+
} else if (method === "POST" && input !== null) {
|
|
113
|
+
options.data = { input };
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return await apiFetch({
|
|
117
|
+
path,
|
|
118
|
+
...options
|
|
119
|
+
});
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`Error executing ability ${ability.name}:`, error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function executeAbility(name, input) {
|
|
126
|
+
const ability = await getAbility(name);
|
|
127
|
+
if (!ability) {
|
|
128
|
+
throw new Error(sprintf("Ability not found: %s", name));
|
|
129
|
+
}
|
|
130
|
+
if (ability.callback) {
|
|
131
|
+
return executeClientAbility(ability, input);
|
|
132
|
+
}
|
|
133
|
+
return executeServerAbility(ability, input);
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
executeAbility,
|
|
137
|
+
getAbilities,
|
|
138
|
+
getAbility,
|
|
139
|
+
getAbilityCategories,
|
|
140
|
+
getAbilityCategory,
|
|
141
|
+
registerAbility,
|
|
142
|
+
registerAbilityCategory,
|
|
143
|
+
unregisterAbility,
|
|
144
|
+
unregisterAbilityCategory
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
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": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// packages/abilities/src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
getAbilities,
|
|
4
|
+
getAbility,
|
|
5
|
+
getAbilityCategories,
|
|
6
|
+
getAbilityCategory,
|
|
7
|
+
executeAbility,
|
|
8
|
+
registerAbility,
|
|
9
|
+
unregisterAbility,
|
|
10
|
+
registerAbilityCategory,
|
|
11
|
+
unregisterAbilityCategory
|
|
12
|
+
} from "./api";
|
|
13
|
+
import { store } from "./store";
|
|
14
|
+
import { validateValueFromSchema } from "./validation";
|
|
15
|
+
export {
|
|
16
|
+
executeAbility,
|
|
17
|
+
getAbilities,
|
|
18
|
+
getAbility,
|
|
19
|
+
getAbilityCategories,
|
|
20
|
+
getAbilityCategory,
|
|
21
|
+
registerAbility,
|
|
22
|
+
registerAbilityCategory,
|
|
23
|
+
store,
|
|
24
|
+
unregisterAbility,
|
|
25
|
+
unregisterAbilityCategory,
|
|
26
|
+
validateValueFromSchema
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress Abilities API Client\n *\n * This package provides a client for interacting with the\n * WordPress Abilities API, allowing you to list, retrieve, and execute\n * abilities from client-side code.\n *\n * @package\n */\n\n/**\n * Public API functions\n */\nexport {\n\tgetAbilities,\n\tgetAbility,\n\tgetAbilityCategories,\n\tgetAbilityCategory,\n\texecuteAbility,\n\tregisterAbility,\n\tunregisterAbility,\n\tregisterAbilityCategory,\n\tunregisterAbilityCategory,\n} from './api';\n\n/**\n * The store can be used directly with @wordpress/data via selectors\n * in React components with useSelect.\n *\n * @example\n * ```js\n * import { useSelect } from '@wordpress/data';\n * import { store as abilitiesStore } from '@wordpress/abilities';\n *\n * function MyComponent() {\n * const abilities = useSelect(\n * (select) => select(abilitiesStore).getAbilities(),\n * []\n * );\n * // Use abilities...\n * }\n * ```\n */\nexport { store } from './store';\n\n/**\n * Type definitions\n */\nexport type {\n\tAbility,\n\tAbilityCategory,\n\tAbilityCategoryArgs,\n\tAbilitiesState,\n\tAbilitiesQueryArgs,\n\tAbilityCallback,\n\tPermissionCallback,\n\tAbilityInput,\n\tAbilityOutput,\n\tValidationError,\n} from './types';\n\n/**\n * Validation utilities\n */\nexport { validateValueFromSchema } from './validation';\n"],
|
|
5
|
+
"mappings": ";AAaA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAoBP,SAAS,aAAa;AAqBtB,SAAS,+BAA+B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// packages/abilities/src/store/actions.ts
|
|
2
|
+
import { sprintf } from "@wordpress/i18n";
|
|
3
|
+
import { resolveSelect } from "@wordpress/data";
|
|
4
|
+
import {
|
|
5
|
+
RECEIVE_ABILITIES,
|
|
6
|
+
REGISTER_ABILITY,
|
|
7
|
+
UNREGISTER_ABILITY,
|
|
8
|
+
RECEIVE_CATEGORIES,
|
|
9
|
+
REGISTER_ABILITY_CATEGORY,
|
|
10
|
+
UNREGISTER_ABILITY_CATEGORY,
|
|
11
|
+
STORE_NAME
|
|
12
|
+
} from "./constants";
|
|
13
|
+
function receiveAbilities(abilities) {
|
|
14
|
+
return {
|
|
15
|
+
type: RECEIVE_ABILITIES,
|
|
16
|
+
abilities
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function receiveCategories(categories) {
|
|
20
|
+
return {
|
|
21
|
+
type: RECEIVE_CATEGORIES,
|
|
22
|
+
categories
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function registerAbility(ability) {
|
|
26
|
+
return async ({ select, dispatch }) => {
|
|
27
|
+
if (!ability.name) {
|
|
28
|
+
throw new Error("Ability name is required");
|
|
29
|
+
}
|
|
30
|
+
if (!/^[a-z0-9-]+\/[a-z0-9-]+$/.test(ability.name)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
'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.'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
if (!ability.label) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
sprintf('Ability "%s" must have a label', ability.name)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if (!ability.description) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
sprintf('Ability "%s" must have a description', ability.name)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (!ability.category) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
sprintf('Ability "%s" must have a category', ability.name)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(ability.category)) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
sprintf(
|
|
53
|
+
'Ability "%1$s" has an invalid category. Category must be lowercase alphanumeric with dashes only Got: "%2$s"',
|
|
54
|
+
ability.name,
|
|
55
|
+
ability.category
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const categories = await resolveSelect(STORE_NAME).getAbilityCategories();
|
|
60
|
+
const existingCategory = categories.find(
|
|
61
|
+
(cat) => cat.slug === ability.category
|
|
62
|
+
);
|
|
63
|
+
if (!existingCategory) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
sprintf(
|
|
66
|
+
'Ability "%1$s" references non-existent category "%2$s". Please register the category first.',
|
|
67
|
+
ability.name,
|
|
68
|
+
ability.category
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (ability.callback && typeof ability.callback !== "function") {
|
|
73
|
+
throw new Error(
|
|
74
|
+
sprintf(
|
|
75
|
+
'Ability "%s" has an invalid callback. Callback must be a function',
|
|
76
|
+
ability.name
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const existingAbility = select.getAbility(ability.name);
|
|
81
|
+
if (existingAbility) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
sprintf('Ability "%s" is already registered', ability.name)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
dispatch({
|
|
87
|
+
type: REGISTER_ABILITY,
|
|
88
|
+
ability
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function unregisterAbility(name) {
|
|
93
|
+
return {
|
|
94
|
+
type: UNREGISTER_ABILITY,
|
|
95
|
+
name
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function registerAbilityCategory(slug, args) {
|
|
99
|
+
return async ({ select, dispatch }) => {
|
|
100
|
+
if (!slug) {
|
|
101
|
+
throw new Error("Category slug is required");
|
|
102
|
+
}
|
|
103
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"Category slug must contain only lowercase alphanumeric characters and dashes."
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
await resolveSelect(STORE_NAME).getAbilityCategories();
|
|
109
|
+
const existingCategory = select.getAbilityCategory(slug);
|
|
110
|
+
if (existingCategory) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
sprintf('Category "%s" is already registered.', slug)
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (!args.label || typeof args.label !== "string") {
|
|
116
|
+
throw new Error(
|
|
117
|
+
"The category properties must contain a `label` string."
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (!args.description || typeof args.description !== "string") {
|
|
121
|
+
throw new Error(
|
|
122
|
+
"The category properties must contain a `description` string."
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
if (args.meta !== void 0 && (typeof args.meta !== "object" || Array.isArray(args.meta))) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
"The category properties should provide a valid `meta` object."
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
const category = {
|
|
131
|
+
slug,
|
|
132
|
+
label: args.label,
|
|
133
|
+
description: args.description,
|
|
134
|
+
meta: {
|
|
135
|
+
...args.meta || {},
|
|
136
|
+
// Internal implementation note: Client-registered categories will have `meta._clientRegistered` set to `true` to differentiate them from server-fetched categories.
|
|
137
|
+
// This is used internally by the resolver to determine whether to fetch categories from the server.
|
|
138
|
+
_clientRegistered: true
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
dispatch({
|
|
142
|
+
type: REGISTER_ABILITY_CATEGORY,
|
|
143
|
+
category
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function unregisterAbilityCategory(slug) {
|
|
148
|
+
return {
|
|
149
|
+
type: UNREGISTER_ABILITY_CATEGORY,
|
|
150
|
+
slug
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
receiveAbilities,
|
|
155
|
+
receiveCategories,
|
|
156
|
+
registerAbility,
|
|
157
|
+
registerAbilityCategory,
|
|
158
|
+
unregisterAbility,
|
|
159
|
+
unregisterAbilityCategory
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=actions.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// packages/abilities/src/store/constants.ts
|
|
2
|
+
var STORE_NAME = "core/abilities";
|
|
3
|
+
var ENTITY_KIND = "root";
|
|
4
|
+
var ENTITY_NAME = "abilities";
|
|
5
|
+
var ENTITY_NAME_CATEGORIES = "ability-categories";
|
|
6
|
+
var RECEIVE_ABILITIES = "RECEIVE_ABILITIES";
|
|
7
|
+
var REGISTER_ABILITY = "REGISTER_ABILITY";
|
|
8
|
+
var UNREGISTER_ABILITY = "UNREGISTER_ABILITY";
|
|
9
|
+
var RECEIVE_CATEGORIES = "RECEIVE_CATEGORIES";
|
|
10
|
+
var REGISTER_ABILITY_CATEGORY = "REGISTER_ABILITY_CATEGORY";
|
|
11
|
+
var UNREGISTER_ABILITY_CATEGORY = "UNREGISTER_ABILITY_CATEGORY";
|
|
12
|
+
export {
|
|
13
|
+
ENTITY_KIND,
|
|
14
|
+
ENTITY_NAME,
|
|
15
|
+
ENTITY_NAME_CATEGORIES,
|
|
16
|
+
RECEIVE_ABILITIES,
|
|
17
|
+
RECEIVE_CATEGORIES,
|
|
18
|
+
REGISTER_ABILITY,
|
|
19
|
+
REGISTER_ABILITY_CATEGORY,
|
|
20
|
+
STORE_NAME,
|
|
21
|
+
UNREGISTER_ABILITY,
|
|
22
|
+
UNREGISTER_ABILITY_CATEGORY
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
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": ";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
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// packages/abilities/src/store/index.ts
|
|
2
|
+
import { createReduxStore, register, dispatch } from "@wordpress/data";
|
|
3
|
+
import { store as coreStore } from "@wordpress/core-data";
|
|
4
|
+
import { __ } from "@wordpress/i18n";
|
|
5
|
+
import reducer from "./reducer";
|
|
6
|
+
import * as actions from "./actions";
|
|
7
|
+
import * as selectors from "./selectors";
|
|
8
|
+
import * as resolvers from "./resolvers";
|
|
9
|
+
import {
|
|
10
|
+
STORE_NAME,
|
|
11
|
+
ENTITY_KIND,
|
|
12
|
+
ENTITY_NAME,
|
|
13
|
+
ENTITY_NAME_CATEGORIES
|
|
14
|
+
} from "./constants";
|
|
15
|
+
var store = createReduxStore(STORE_NAME, {
|
|
16
|
+
reducer,
|
|
17
|
+
actions,
|
|
18
|
+
selectors,
|
|
19
|
+
resolvers
|
|
20
|
+
});
|
|
21
|
+
register(store);
|
|
22
|
+
dispatch(coreStore).addEntities([
|
|
23
|
+
{
|
|
24
|
+
name: ENTITY_NAME,
|
|
25
|
+
kind: ENTITY_KIND,
|
|
26
|
+
key: "name",
|
|
27
|
+
baseURL: "/wp-abilities/v1/abilities",
|
|
28
|
+
baseURLParams: { context: "edit" },
|
|
29
|
+
plural: "abilities",
|
|
30
|
+
label: __("Abilities"),
|
|
31
|
+
supportsPagination: true
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: ENTITY_NAME_CATEGORIES,
|
|
35
|
+
kind: ENTITY_KIND,
|
|
36
|
+
key: "slug",
|
|
37
|
+
baseURL: "/wp-abilities/v1/categories",
|
|
38
|
+
baseURLParams: { context: "edit" },
|
|
39
|
+
plural: "ability-categories",
|
|
40
|
+
label: __("Ability Categories"),
|
|
41
|
+
supportsPagination: true
|
|
42
|
+
}
|
|
43
|
+
]);
|
|
44
|
+
export {
|
|
45
|
+
store
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=index.js.map
|