@rnaga/wp-node 1.1.3 → 1.1.4

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 CHANGED
@@ -11,7 +11,7 @@ WP-Node is a Node.js project written in TypeScript that mirrors the WordPress da
11
11
  Key benefits include:
12
12
 
13
13
  - No need to run WordPress PHP
14
- - Type-safe interaction with WordPress tables (`posts`, `users`, `terms`, etc.)
14
+ - Type-safe interaction with WordPress tables (`posts`, `users`, `terms`, `comments`, `etc.`)
15
15
  - Utility classes for querying posts, terms, users, comments, and metadata
16
16
  - Supports both Single Site and Multi Site WordPress setups
17
17
  - CLI tools to seed databases and run custom commands
@@ -33,20 +33,11 @@ WP-Node is ideal for scenarios where you need direct access to WordPress databas
33
33
  - **Debugging or inspecting database records** from a modern TypeScript environment
34
34
  - **Creating a web app** (e.g., using Next.js) that needs to pull or push data from a WordPress database, without relying on PHP codebase
35
35
 
36
- ## Limitations
37
-
38
- **WP-Node Core** is designed specifically to interact with the WordPress database. It does not support traditional WordPress features such as:
39
-
40
- - Themes and appearance settings, including updating styling
41
- - WordPress Template rendering or theming APIs
42
- - WordPress plugins
43
-
44
- Its scope is intentionally limited to providing a type-safe, programmatic interface to WordPress data — not replicating the full behavior of the WordPress runtime.
45
-
46
36
  ## Requirements
47
37
 
48
38
  - **Node.js** `>=22.0.0`
49
39
  - **MySQL** or **MariaDB**
40
+ - **nvm**: Make sure you have [`nvm`](https://github.com/nvm-sh/nvm) command installed on your local machine.
50
41
  - Optional: Docker for local WordPress database setup
51
42
 
52
43
  ## Installation
@@ -73,15 +64,18 @@ Visit http://localhost:8080 in your browser to complete the WordPress setup.
73
64
 
74
65
  ### Initialize WP-Node Project
75
66
 
76
- WP-Node requires an initialized configuration before use. You can scaffold a new project using the CLI.
67
+ To get started, create a new folder for your project. This folder will serve as the root directory for your WP-Node application.
77
68
 
78
69
  ```sh
79
- mkdir /tmp/test-wp-node
80
- cd /tmp/test-wp-node
81
- npx @rnaga/wp-node-cli -- init
70
+ mkdir wp-node
71
+ cd wp-node
82
72
  ```
83
73
 
84
- Then enter prompts as follows:
74
+ Then, run the command to initialize the project and follow the prompts:
75
+
76
+ ```sh
77
+ npx @rnaga/wp-node-cli -- init
78
+ ```
85
79
 
86
80
  ```sh
87
81
  ✔ Enter your database hostname: · localhost
@@ -229,6 +223,16 @@ export class Post {
229
223
  - **Filter**: Modify data in chainable handlers (similar to `apply_filters`)
230
224
  - **Action**: Fire off side effects (`do_action` equivalent)
231
225
 
226
+ ## Limitations
227
+
228
+ **WP-Node Core** is designed specifically to interact with the WordPress database. It does not support traditional WordPress features such as:
229
+
230
+ - Themes and appearance settings, including updating styling
231
+ - WordPress Template rendering or theming APIs
232
+ - WordPress plugins
233
+
234
+ Its scope is intentionally limited to providing a type-safe, programmatic interface to WordPress data — not replicating the full behavior of the WordPress runtime.
235
+
232
236
  ## Contributing
233
237
 
234
238
  Feel free to fork, open issues, or suggest improvements. This project is in active development.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rnaga/wp-node",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "build": "rm -rf ./dist && tsc --project tsconfig.build.json && npm run copyfiles && cp package.json ./dist/",
@@ -1,4 +1,5 @@
1
1
  import * as val from "../validators";
2
+ import { z } from "zod";
2
3
  export type Parser = {
3
4
  parse: (v: any, ...args: any) => any;
4
5
  safeParse: (v: any, ...args: any) => any;
@@ -6,4 +7,8 @@ export type Parser = {
6
7
  export type ParserReturnType<T> = T extends Parser ? ReturnType<T["parse"]> : any;
7
8
  export type Tables = keyof typeof val.database.wpTables;
8
9
  export type Field<T extends Tables> = keyof (typeof val.database.wpTables)[T]["shape"];
10
+ export type PickZodObjectKey<T extends z.ZodType<any, any, any>, K extends keyof z.infer<T>> = {
11
+ [P in K]: z.infer<T>[P];
12
+ };
13
+ export type PickZodObjectKeyInArray<T extends z.ZodType<any, any, any>, K extends keyof z.infer<T>[number]> = PickZodObjectKey<T, K>[];
9
14
  //# sourceMappingURL=validating.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validating.d.ts","sourceRoot":"","sources":["../../src/types/validating.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AAErC,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;IACrC,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC9C,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GACtB,GAAG,CAAC;AAER,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACxD,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,MAAM,IAChC,MAAM,CAAC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"validating.d.ts","sourceRoot":"","sources":["../../src/types/validating.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;IACrC,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC9C,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GACtB,GAAG,CAAC;AAER,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACxD,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,MAAM,IAChC,MAAM,CAAC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAEnD,MAAM,MAAM,gBAAgB,CAC1B,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAClC,CAAC,SAAS,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IACxB;KACD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,uBAAuB,CACjC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAClC,CAAC,SAAS,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAChC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC"}
@@ -13,4 +13,12 @@ export declare const stringZeroOrOne: z.ZodUnion<[z.ZodDefault<z.ZodOptional<z.Z
13
13
  export declare const stringMetaTable: z.ZodEnum<["post", "comment", "blog", "term", "user", "site"]>;
14
14
  export declare const userRef: z.ZodEffects<z.ZodString, string | number, string>;
15
15
  export declare const blogFlag: z.ZodEnum<["public", "archived", "mature", "spam", "deleted"]>;
16
+ export declare const deepRemoveDefaults: <T>(schema: T) => T;
17
+ export declare const filterRecordByFields: (data: string | Record<string, unknown> | Record<string, unknown>[], fields: string | string[] | undefined) => string | Record<string, any> | Record<string, any>[];
18
+ export declare const recordByField: <T extends z.ZodObject<any, any, any, any, any>>(schema: T, fields: string[]) => z.ZodObject<Record<string, z.ZodTypeAny>, "strip", z.ZodTypeAny, {
19
+ [x: string]: any;
20
+ }, {
21
+ [x: string]: any;
22
+ }>;
23
+ export declare const arrayRecordByField: <T extends z.ZodArray<z.ZodObject<any, any, any, any, any>, any>>(schema: T, fields: string[]) => z.ZodArray<any>;
16
24
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/validators/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACvD,SAAS,EAAE,SAAS,CAAC,EAAE,qEAQxB;AAED,eAAO,MAAM,sBAAsB,GAAI,IAAI,MAAM,GAAG,IAAI,GAAG,SAAS,uBAC/B,CAAC;AAEtC,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,uFAQ1C,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,GAAG,MAAM,GAAG,OAAO,iIAKlD,CAAC;AAEL,eAAO,MAAM,MAAM,sEAMjB,CAAC;AAEH,eAAO,MAAM,SAAS,4FAGpB,CAAC;AAEH,eAAO,MAAM,SAAS,4FAGpB,CAAC;AAEH,eAAO,MAAM,OAAO,yHAKlB,CAAC;AAEH,eAAO,MAAM,IAAI,2CAKkB,CAAC;AAEpC,eAAO,MAAM,MAAM,qCAAmC,CAAC;AAEvD,eAAO,MAAM,eAAe,0LAQ1B,CAAC;AAEH,eAAO,MAAM,eAAe,gEAO1B,CAAC;AAEH,eAAO,MAAM,OAAO,oDAKlB,CAAC;AAEH,eAAO,MAAM,QAAQ,gEAMnB,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/validators/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACvD,SAAS,EAAE,SAAS,CAAC,EAAE,qEAQxB;AAED,eAAO,MAAM,sBAAsB,GAAI,IAAI,MAAM,GAAG,IAAI,GAAG,SAAS,uBAC/B,CAAC;AAEtC,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,uFAQ1C,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,GAAG,MAAM,GAAG,OAAO,iIAKlD,CAAC;AAEL,eAAO,MAAM,MAAM,sEAMjB,CAAC;AAEH,eAAO,MAAM,SAAS,4FAGpB,CAAC;AAEH,eAAO,MAAM,SAAS,4FAGpB,CAAC;AAEH,eAAO,MAAM,OAAO,yHAKlB,CAAC;AAEH,eAAO,MAAM,IAAI,2CAKkB,CAAC;AAEpC,eAAO,MAAM,MAAM,qCAAmC,CAAC;AAEvD,eAAO,MAAM,eAAe,0LAQ1B,CAAC;AAEH,eAAO,MAAM,eAAe,gEAO1B,CAAC;AAEH,eAAO,MAAM,OAAO,oDAKlB,CAAC;AAEH,eAAO,MAAM,QAAQ,gEAMnB,CAAC;AAEH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,QAAQ,CAAC,KAAG,CAgCjD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClE,QAAQ,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,yDAmDtC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAC1E,QAAQ,CAAC,EACT,QAAQ,MAAM,EAAE;;;;EAWjB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAE/D,QAAQ,CAAC,EACT,QAAQ,MAAM,EAAE,KACf,CAAC,CAAC,QAAQ,CAAC,GAAG,CAKhB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.blogFlag = exports.userRef = exports.stringMetaTable = exports.stringZeroOrOne = exports.string = exports.path = exports.boolean = exports.stringArr = exports.numberArr = exports.number = exports.booleanWithDefault = exports.numberWithDefault = exports.undefinedIfEmptyString = void 0;
3
+ exports.arrayRecordByField = exports.recordByField = exports.filterRecordByFields = exports.deepRemoveDefaults = exports.blogFlag = exports.userRef = exports.stringMetaTable = exports.stringZeroOrOne = exports.string = exports.path = exports.boolean = exports.stringArr = exports.numberArr = exports.number = exports.booleanWithDefault = exports.numberWithDefault = exports.undefinedIfEmptyString = void 0;
4
4
  exports.unionOfLiterals = unionOfLiterals;
5
5
  const zod_1 = require("zod");
6
6
  // https://github.com/colinhacks/zod/discussions/2790
@@ -84,3 +84,84 @@ exports.blogFlag = zod_1.z.enum([
84
84
  "spam",
85
85
  "deleted",
86
86
  ]);
87
+ const deepRemoveDefaults = (schema) => {
88
+ if (schema instanceof zod_1.z.ZodDefault)
89
+ return (0, exports.deepRemoveDefaults)(schema.removeDefault());
90
+ if (schema instanceof zod_1.z.ZodObject) {
91
+ const newShape = {};
92
+ for (const key in schema.shape) {
93
+ const fieldSchema = schema.shape[key];
94
+ newShape[key] = zod_1.z.ZodOptional.create((0, exports.deepRemoveDefaults)(fieldSchema));
95
+ }
96
+ return new zod_1.z.ZodObject({
97
+ ...schema._def,
98
+ shape: () => newShape,
99
+ });
100
+ }
101
+ if (schema instanceof zod_1.z.ZodArray)
102
+ return zod_1.z.ZodArray.create((0, exports.deepRemoveDefaults)(schema.element));
103
+ if (schema instanceof zod_1.z.ZodOptional)
104
+ return zod_1.z.ZodOptional.create((0, exports.deepRemoveDefaults)(schema.unwrap()));
105
+ if (schema instanceof zod_1.z.ZodNullable)
106
+ return zod_1.z.ZodNullable.create((0, exports.deepRemoveDefaults)(schema.unwrap()));
107
+ if (schema instanceof zod_1.z.ZodTuple)
108
+ return zod_1.z.ZodTuple.create(schema.items.map((item) => (0, exports.deepRemoveDefaults)(item)));
109
+ return schema;
110
+ };
111
+ exports.deepRemoveDefaults = deepRemoveDefaults;
112
+ const filterRecordByFields = (data, fields) => {
113
+ // If data is a string, return it as is
114
+ if (typeof data === "string") {
115
+ return data;
116
+ }
117
+ const fieldsSchema = zod_1.z
118
+ .string()
119
+ .optional()
120
+ .transform((val) => val
121
+ ? val
122
+ .split(",")
123
+ .map((field) => field.trim())
124
+ .filter((field) => field.length > 0)
125
+ : []);
126
+ const parsedFields = fieldsSchema.parse(Array.isArray(fields) ? fields.join(",") : fields);
127
+ // If fields are specified, filter the result data
128
+ if (0 == parsedFields.length) {
129
+ return data;
130
+ }
131
+ const filterObject = (record) => {
132
+ const filteredRecord = {};
133
+ parsedFields.forEach((field) => {
134
+ if (field in record) {
135
+ filteredRecord[field] = record[field];
136
+ }
137
+ });
138
+ return filteredRecord;
139
+ };
140
+ // If data is an object, filter it
141
+ if (typeof data === "object" && !Array.isArray(data)) {
142
+ return filterObject(data);
143
+ }
144
+ // If data is an array, filter each item
145
+ if (Array.isArray(data)) {
146
+ return data.map((item) => filterObject(item));
147
+ }
148
+ return data;
149
+ };
150
+ exports.filterRecordByFields = filterRecordByFields;
151
+ const recordByField = (schema, fields) => {
152
+ // Filter the schema to only include the specified fields
153
+ const filteredShape = {};
154
+ for (const field of fields) {
155
+ if (field in schema.shape) {
156
+ filteredShape[field] = schema.shape[field];
157
+ }
158
+ }
159
+ return zod_1.z.object(filteredShape);
160
+ };
161
+ exports.recordByField = recordByField;
162
+ const arrayRecordByField = (schema, fields) => {
163
+ // Filter the schema to only include the specified fields
164
+ const filteredShape = (0, exports.recordByField)(schema.element, fields);
165
+ return zod_1.z.array(filteredShape);
166
+ };
167
+ exports.arrayRecordByField = arrayRecordByField;