wp-content-exporter 0.1.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/dist/cli.js ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ import { program } from "commander";
3
+ import { resolve } from "path";
4
+ import { exportToCSV } from "./index.js";
5
+ const version = "0.1.0";
6
+ program
7
+ .name("wp-content-exporter")
8
+ .description("Export WordPress content to CSV from the command line")
9
+ .version(version);
10
+ program
11
+ .command("export")
12
+ .description("Export WordPress content to CSV")
13
+ .option("-e, --endpoint <url>", "WordPress endpoint URL (required)")
14
+ .option("-t, --post-type <type>", "Post type to export (default: posts)", "posts")
15
+ .option("-f, --fields <fields>", "Fields to export (comma-separated, required)")
16
+ .option("-o, --output <file>", "Output file path (required)")
17
+ .option("-u, --username <username>", "Basic auth username")
18
+ .option("-p, --password <password>", "Basic auth password")
19
+ .option("-b, --bearer <token>", "Bearer token for JWT auth")
20
+ .option("--per-page <number>", "Items per page (default: 100)", "100")
21
+ .action(async (options) => {
22
+ try {
23
+ // Validate required options
24
+ if (!options.endpoint) {
25
+ console.error("❌ Error: --endpoint is required");
26
+ console.log("Usage: wp-content-exporter export --endpoint <url> --fields <fields> --output <file>");
27
+ process.exit(1);
28
+ }
29
+ if (!options.fields) {
30
+ console.error("❌ Error: --fields is required");
31
+ console.log("Example: --fields title.rendered,slug,date");
32
+ process.exit(1);
33
+ }
34
+ if (!options.output) {
35
+ console.error("❌ Error: --output is required");
36
+ console.log("Example: --output posts.csv");
37
+ process.exit(1);
38
+ }
39
+ // Parse fields
40
+ const fields = options.fields
41
+ .split(",")
42
+ .map((f) => f.trim())
43
+ .filter((f) => f.length > 0);
44
+ if (fields.length === 0) {
45
+ console.error("❌ Error: No valid fields provided");
46
+ process.exit(1);
47
+ }
48
+ // Build auth config
49
+ let auth = undefined;
50
+ if (options.username && options.password) {
51
+ auth = {
52
+ type: "basic",
53
+ username: options.username,
54
+ password: options.password
55
+ };
56
+ }
57
+ else if (options.bearer) {
58
+ auth = {
59
+ type: "bearer",
60
+ token: options.bearer
61
+ };
62
+ }
63
+ // Show progress
64
+ console.log("📦 Exporting WordPress content...");
65
+ console.log(` Endpoint: ${options.endpoint}`);
66
+ console.log(` Post type: ${options.postType}`);
67
+ console.log(` Fields: ${fields.join(", ")}`);
68
+ console.log(` Output: ${options.output}`);
69
+ if (auth) {
70
+ console.log(` Auth: ${auth.type}`);
71
+ }
72
+ console.log("");
73
+ // Export
74
+ const csv = await exportToCSV({
75
+ endpoint: options.endpoint,
76
+ postType: options.postType,
77
+ fields,
78
+ auth,
79
+ perPage: parseInt(options.perPage),
80
+ outputFile: resolve(options.output)
81
+ });
82
+ // Count rows
83
+ const rowCount = csv.split("\n").length - 1;
84
+ console.log(`✅ Export complete!`);
85
+ console.log(` Rows: ${rowCount}`);
86
+ console.log(` File: ${resolve(options.output)}`);
87
+ }
88
+ catch (error) {
89
+ console.error("❌ Export failed:");
90
+ console.error(error instanceof Error ? error.message : error);
91
+ process.exit(1);
92
+ }
93
+ });
94
+ // Help for export command
95
+ program
96
+ .command("example")
97
+ .description("Show example usage")
98
+ .action(() => {
99
+ console.log(`
100
+ 📝 EXAMPLES:
101
+
102
+ 1. Export public posts:
103
+ wp-content-exporter export \\
104
+ --endpoint https://example.com \\
105
+ --fields title.rendered,slug \\
106
+ --output posts.csv
107
+
108
+ 2. Export with basic authentication:
109
+ wp-content-exporter export \\
110
+ --endpoint https://example.com \\
111
+ --post-type posts \\
112
+ --fields title.rendered,content.rendered \\
113
+ --username admin \\
114
+ --password app-password \\
115
+ --output posts.csv
116
+
117
+ 3. Export with bearer token:
118
+ wp-content-exporter export \\
119
+ --endpoint https://example.com \\
120
+ --bearer your-jwt-token \\
121
+ --fields title.rendered,slug \\
122
+ --output posts.csv
123
+
124
+ 4. Export with nested fields (ACF):
125
+ wp-content-exporter export \\
126
+ --endpoint https://example.com \\
127
+ --fields title.rendered,acf.price,acf.product.name \\
128
+ --output products.csv
129
+
130
+ 5. Use with npx (no installation):
131
+ npx wp-content-exporter export \\
132
+ --endpoint https://example.com \\
133
+ --fields title.rendered,slug \\
134
+ --output posts.csv
135
+ `);
136
+ });
137
+ program.parse(process.argv);
138
+ // Show help if no command provided
139
+ if (process.argv.length < 3) {
140
+ program.help();
141
+ }
142
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/csv.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Converts an array of objects to CSV format using specified fields
3
+ * Supports nested fields using dot notation
4
+ *
5
+ * @param {any[]} items - Array of objects to convert
6
+ * @param {string[]} fields - Field names to include in CSV (supports dot notation for nested fields)
7
+ * @returns {string} CSV string
8
+ *
9
+ * @throws {Error} If json2csv parsing fails
10
+ *
11
+ * @example
12
+ * const posts = [
13
+ * { title: { rendered: "Post 1" }, slug: "post-1" },
14
+ * { title: { rendered: "Post 2" }, slug: "post-2" }
15
+ * ]
16
+ *
17
+ * const csv = toCSV(posts, ["title.rendered", "slug"])
18
+ * // Returns CSV with headers: title.rendered,slug
19
+ */
20
+ export declare function toCSV(items: any[], fields: string[]): string;
21
+ //# sourceMappingURL=csv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../src/csv.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAsB5D"}
package/dist/csv.js ADDED
@@ -0,0 +1,57 @@
1
+ import { Parser } from "json2csv";
2
+ /**
3
+ * Gets a nested value from an object using dot notation
4
+ *
5
+ * @param {any} obj - Object to retrieve value from
6
+ * @param {string} path - Dot-separated path (e.g., "title.rendered", "acf.price")
7
+ * @returns {any} The value at the path, or undefined if not found
8
+ *
9
+ * @example
10
+ * const post = { title: { rendered: "Hello World" } }
11
+ * getValue(post, "title.rendered") // => "Hello World"
12
+ */
13
+ function getValue(obj, path) {
14
+ return path.split(".").reduce((o, k) => o?.[k], obj);
15
+ }
16
+ /**
17
+ * Converts an array of objects to CSV format using specified fields
18
+ * Supports nested fields using dot notation
19
+ *
20
+ * @param {any[]} items - Array of objects to convert
21
+ * @param {string[]} fields - Field names to include in CSV (supports dot notation for nested fields)
22
+ * @returns {string} CSV string
23
+ *
24
+ * @throws {Error} If json2csv parsing fails
25
+ *
26
+ * @example
27
+ * const posts = [
28
+ * { title: { rendered: "Post 1" }, slug: "post-1" },
29
+ * { title: { rendered: "Post 2" }, slug: "post-2" }
30
+ * ]
31
+ *
32
+ * const csv = toCSV(posts, ["title.rendered", "slug"])
33
+ * // Returns CSV with headers: title.rendered,slug
34
+ */
35
+ export function toCSV(items, fields) {
36
+ if (!items || items.length === 0) {
37
+ return "";
38
+ }
39
+ const rows = items.map(item => {
40
+ const row = {};
41
+ for (const field of fields) {
42
+ row[field] = getValue(item, field);
43
+ }
44
+ return row;
45
+ });
46
+ try {
47
+ const parser = new Parser({ fields });
48
+ return parser.parse(rows);
49
+ }
50
+ catch (error) {
51
+ if (error instanceof Error) {
52
+ throw new Error(`CSV parsing failed: ${error.message}`);
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ //# sourceMappingURL=csv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv.js","sourceRoot":"","sources":["../src/csv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC;;;;;;;;;;GAUG;AACH,SAAS,QAAQ,CAAC,GAAQ,EAAE,IAAY;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AACtD,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,KAAK,CAAC,KAAY,EAAE,MAAgB;IAClD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC5B,MAAM,GAAG,GAAwB,EAAE,CAAA;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,GAAG,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACrC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { AuthConfig } from "./auth.js";
2
+ /**
3
+ * Fetches all posts/pages/custom post types from WordPress REST API with automatic pagination
4
+ *
5
+ * @param {string} endpoint - WordPress site URL (e.g., "https://example.com")
6
+ * @param {string} postType - Post type to fetch (e.g., "posts", "pages", "custom-type")
7
+ * @param {AuthConfig} [auth] - Optional authentication configuration
8
+ * @param {number} [perPage=100] - Number of items per page (max 100)
9
+ * @returns {Promise<any[]>} Array of all posts across all pages
10
+ *
11
+ * @throws {Error} If the fetch request fails or returns non-ok status
12
+ *
13
+ * @example
14
+ * const posts = await fetchAllPosts(
15
+ * "https://example.com",
16
+ * "posts",
17
+ * { type: "basic", username: "admin", password: "xxx" }
18
+ * )
19
+ */
20
+ export declare function fetchAllPosts(endpoint: string, postType: string, auth?: AuthConfig, perPage?: number): Promise<any[]>;
21
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,UAAU,EAAE,MAAM,WAAW,CAAA;AAEpD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,UAAU,EACjB,OAAO,SAAM,GACZ,OAAO,CAAC,GAAG,EAAE,CAAC,CA6BhB"}
package/dist/fetch.js ADDED
@@ -0,0 +1,45 @@
1
+ import { buildHeaders } from "./auth.js";
2
+ /**
3
+ * Fetches all posts/pages/custom post types from WordPress REST API with automatic pagination
4
+ *
5
+ * @param {string} endpoint - WordPress site URL (e.g., "https://example.com")
6
+ * @param {string} postType - Post type to fetch (e.g., "posts", "pages", "custom-type")
7
+ * @param {AuthConfig} [auth] - Optional authentication configuration
8
+ * @param {number} [perPage=100] - Number of items per page (max 100)
9
+ * @returns {Promise<any[]>} Array of all posts across all pages
10
+ *
11
+ * @throws {Error} If the fetch request fails or returns non-ok status
12
+ *
13
+ * @example
14
+ * const posts = await fetchAllPosts(
15
+ * "https://example.com",
16
+ * "posts",
17
+ * { type: "basic", username: "admin", password: "xxx" }
18
+ * )
19
+ */
20
+ export async function fetchAllPosts(endpoint, postType, auth, perPage = 100) {
21
+ let page = 1;
22
+ let results = [];
23
+ while (true) {
24
+ const url = `${endpoint}/wp-json/wp/v2/${postType}?per_page=${perPage}&page=${page}`;
25
+ try {
26
+ const res = await fetch(url, { headers: buildHeaders(auth) });
27
+ if (!res.ok) {
28
+ throw new Error(`WordPress REST API error: ${res.status} ${res.statusText}`);
29
+ }
30
+ const data = await res.json();
31
+ if (!Array.isArray(data) || data.length === 0)
32
+ break;
33
+ results = results.concat(data);
34
+ page++;
35
+ }
36
+ catch (error) {
37
+ if (error instanceof Error) {
38
+ throw new Error(`Failed to fetch from ${url}: ${error.message}`);
39
+ }
40
+ throw error;
41
+ }
42
+ }
43
+ return results;
44
+ }
45
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAc,MAAM,WAAW,CAAA;AAEpD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,QAAgB,EAChB,IAAiB,EACjB,OAAO,GAAG,GAAG;IAEb,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,OAAO,GAAU,EAAE,CAAA;IAEvB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,GAAG,QAAQ,kBAAkB,QAAQ,aAAa,OAAO,SAAS,IAAI,EAAE,CAAA;QAEpF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAE7D,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAA;YAC9E,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAW,CAAA;YAEtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAK;YAEpD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC9B,IAAI,EAAE,CAAA;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;YAClE,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { AuthConfig } from "./auth.js";
2
+ /**
3
+ * Options for exporting WordPress content to CSV
4
+ *
5
+ * @typedef {Object} ExportOptions
6
+ * @property {string} endpoint - WordPress site URL
7
+ * @property {string} postType - Post type (posts, pages, custom types)
8
+ * @property {string[]} fields - Fields to export (supports dot notation)
9
+ * @property {AuthConfig} [auth] - Optional authentication config
10
+ * @property {number} [perPage=100] - Items per API request
11
+ * @property {string} [outputFile] - Optional file path to save CSV (if not provided, returns string)
12
+ */
13
+ export type ExportOptions = {
14
+ endpoint: string;
15
+ postType: string;
16
+ fields: string[];
17
+ auth?: AuthConfig;
18
+ perPage?: number;
19
+ outputFile?: string;
20
+ };
21
+ /**
22
+ * Main function to export WordPress content to CSV
23
+ *
24
+ * Fetches posts/pages/custom post types from WordPress REST API and converts to CSV format
25
+ * Automatically handles pagination and flattens nested fields
26
+ *
27
+ * @param {ExportOptions} options - Export configuration
28
+ * @returns {Promise<string>} CSV string with headers and data rows
29
+ *
30
+ * @throws {Error} If fetch fails, auth is invalid, or CSV generation fails
31
+ *
32
+ * @example
33
+ * // Return CSV as string
34
+ * const csv = await exportToCSV({
35
+ * endpoint: "https://example.com",
36
+ * postType: "posts",
37
+ * fields: ["title.rendered", "slug", "date"]
38
+ * })
39
+ * console.log(csv)
40
+ *
41
+ * @example
42
+ * // Save to file
43
+ * await exportToCSV({
44
+ * endpoint: "https://example.com",
45
+ * postType: "posts",
46
+ * fields: ["title.rendered", "slug"],
47
+ * outputFile: "./posts.csv"
48
+ * })
49
+ * console.log("Saved to posts.csv")
50
+ */
51
+ export declare function exportToCSV(options: ExportOptions): Promise<string>;
52
+ export type { AuthConfig } from "./auth.js";
53
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA+CzE;AAGD,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,64 @@
1
+ import { fetchAllPosts } from "./fetch.js";
2
+ import { toCSV } from "./csv.js";
3
+ /**
4
+ * Main function to export WordPress content to CSV
5
+ *
6
+ * Fetches posts/pages/custom post types from WordPress REST API and converts to CSV format
7
+ * Automatically handles pagination and flattens nested fields
8
+ *
9
+ * @param {ExportOptions} options - Export configuration
10
+ * @returns {Promise<string>} CSV string with headers and data rows
11
+ *
12
+ * @throws {Error} If fetch fails, auth is invalid, or CSV generation fails
13
+ *
14
+ * @example
15
+ * // Return CSV as string
16
+ * const csv = await exportToCSV({
17
+ * endpoint: "https://example.com",
18
+ * postType: "posts",
19
+ * fields: ["title.rendered", "slug", "date"]
20
+ * })
21
+ * console.log(csv)
22
+ *
23
+ * @example
24
+ * // Save to file
25
+ * await exportToCSV({
26
+ * endpoint: "https://example.com",
27
+ * postType: "posts",
28
+ * fields: ["title.rendered", "slug"],
29
+ * outputFile: "./posts.csv"
30
+ * })
31
+ * console.log("Saved to posts.csv")
32
+ */
33
+ export async function exportToCSV(options) {
34
+ const { endpoint, postType, fields, auth, perPage, outputFile } = options;
35
+ if (!endpoint) {
36
+ throw new Error("Endpoint is required");
37
+ }
38
+ if (!postType) {
39
+ throw new Error("Post type is required");
40
+ }
41
+ if (!fields || fields.length === 0) {
42
+ throw new Error("At least one field is required");
43
+ }
44
+ const items = await fetchAllPosts(endpoint, postType, auth, perPage);
45
+ if (items.length === 0) {
46
+ console.warn("No items found for export");
47
+ }
48
+ const csv = toCSV(items, fields);
49
+ // Save to file if outputFile is specified
50
+ if (outputFile) {
51
+ try {
52
+ const fs = await import("fs/promises");
53
+ await fs.writeFile(outputFile, csv, "utf-8");
54
+ }
55
+ catch (error) {
56
+ if (error instanceof Error) {
57
+ throw new Error(`Failed to write to file ${outputFile}: ${error.message}`);
58
+ }
59
+ throw error;
60
+ }
61
+ }
62
+ return csv;
63
+ }
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAuBhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAsB;IACtD,MAAM,EACJ,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,OAAO,EACP,UAAU,EACX,GAAG,OAAO,CAAA;IAEX,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;IACzC,CAAC;IACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;IAC1C,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,aAAa,CAC/B,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,OAAO,CACR,CAAA;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;IAC3C,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAEhC,0CAA0C;IAC1C,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;YACtC,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;YAC5E,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Authentication configuration options for WordPress REST API
3
+ *
4
+ * @typedef {Object} AuthConfig
5
+ * @property {string} type - Authentication type: "none", "basic", "bearer", or "headers"
6
+ */
7
+ export type AuthConfig = {
8
+ type: "none";
9
+ } | {
10
+ type: "basic";
11
+ username: string;
12
+ password: string;
13
+ } | {
14
+ type: "bearer";
15
+ token: string;
16
+ } | {
17
+ type: "headers";
18
+ headers: Record<string, string>;
19
+ };
20
+ /**
21
+ * Builds HTTP headers including authentication if provided
22
+ *
23
+ * @param {AuthConfig} [auth] - Optional authentication configuration
24
+ * @returns {HeadersInit} Headers object with authentication applied
25
+ *
26
+ * @example
27
+ * // Basic auth
28
+ * const headers = buildHeaders({
29
+ * type: "basic",
30
+ * username: "admin",
31
+ * password: "password"
32
+ * })
33
+ *
34
+ * @example
35
+ * // Bearer token
36
+ * const headers = buildHeaders({
37
+ * type: "bearer",
38
+ * token: "eyJhbGc..."
39
+ * })
40
+ */
41
+ export declare function buildHeaders(auth?: AuthConfig): HeadersInit;
42
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,WAAW,CAuB3D"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Builds HTTP headers including authentication if provided
3
+ *
4
+ * @param {AuthConfig} [auth] - Optional authentication configuration
5
+ * @returns {HeadersInit} Headers object with authentication applied
6
+ *
7
+ * @example
8
+ * // Basic auth
9
+ * const headers = buildHeaders({
10
+ * type: "basic",
11
+ * username: "admin",
12
+ * password: "password"
13
+ * })
14
+ *
15
+ * @example
16
+ * // Bearer token
17
+ * const headers = buildHeaders({
18
+ * type: "bearer",
19
+ * token: "eyJhbGc..."
20
+ * })
21
+ */
22
+ export function buildHeaders(auth) {
23
+ const headers = {
24
+ "Content-Type": "application/json"
25
+ };
26
+ if (!auth || auth.type === "none")
27
+ return headers;
28
+ if (auth.type === "basic") {
29
+ const token = Buffer
30
+ .from(`${auth.username}:${auth.password}`)
31
+ .toString("base64");
32
+ headers.Authorization = `Basic ${token}`;
33
+ }
34
+ if (auth.type === "bearer") {
35
+ headers.Authorization = `Bearer ${auth.token}`;
36
+ }
37
+ if (auth.type === "headers") {
38
+ Object.assign(headers, auth.headers);
39
+ }
40
+ return headers;
41
+ }
42
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,YAAY,CAAC,IAAiB;IAC5C,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAA;IAED,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,OAAO,CAAA;IAEjD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM;aACjB,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;aACzC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACrB,OAAO,CAAC,aAAa,GAAG,SAAS,KAAK,EAAE,CAAA;IAC1C,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,CAAC,aAAa,GAAG,UAAU,IAAI,CAAC,KAAK,EAAE,CAAA;IAChD,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Converts an array of objects to CSV format using specified fields
3
+ * Supports nested fields using dot notation
4
+ *
5
+ * @param {any[]} items - Array of objects to convert
6
+ * @param {string[]} fields - Field names to include in CSV (supports dot notation for nested fields)
7
+ * @returns {string} CSV string
8
+ *
9
+ * @throws {Error} If json2csv parsing fails
10
+ *
11
+ * @example
12
+ * const posts = [
13
+ * { title: { rendered: "Post 1" }, slug: "post-1" },
14
+ * { title: { rendered: "Post 2" }, slug: "post-2" }
15
+ * ]
16
+ *
17
+ * const csv = toCSV(posts, ["title.rendered", "slug"])
18
+ * // Returns CSV with headers: title.rendered,slug
19
+ */
20
+ export declare function toCSV(items: any[], fields: string[]): string;
21
+ //# sourceMappingURL=csv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../src/csv.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAsB5D"}
@@ -0,0 +1,57 @@
1
+ import { Parser } from "json2csv";
2
+ /**
3
+ * Gets a nested value from an object using dot notation
4
+ *
5
+ * @param {any} obj - Object to retrieve value from
6
+ * @param {string} path - Dot-separated path (e.g., "title.rendered", "acf.price")
7
+ * @returns {any} The value at the path, or undefined if not found
8
+ *
9
+ * @example
10
+ * const post = { title: { rendered: "Hello World" } }
11
+ * getValue(post, "title.rendered") // => "Hello World"
12
+ */
13
+ function getValue(obj, path) {
14
+ return path.split(".").reduce((o, k) => o?.[k], obj);
15
+ }
16
+ /**
17
+ * Converts an array of objects to CSV format using specified fields
18
+ * Supports nested fields using dot notation
19
+ *
20
+ * @param {any[]} items - Array of objects to convert
21
+ * @param {string[]} fields - Field names to include in CSV (supports dot notation for nested fields)
22
+ * @returns {string} CSV string
23
+ *
24
+ * @throws {Error} If json2csv parsing fails
25
+ *
26
+ * @example
27
+ * const posts = [
28
+ * { title: { rendered: "Post 1" }, slug: "post-1" },
29
+ * { title: { rendered: "Post 2" }, slug: "post-2" }
30
+ * ]
31
+ *
32
+ * const csv = toCSV(posts, ["title.rendered", "slug"])
33
+ * // Returns CSV with headers: title.rendered,slug
34
+ */
35
+ export function toCSV(items, fields) {
36
+ if (!items || items.length === 0) {
37
+ return "";
38
+ }
39
+ const rows = items.map(item => {
40
+ const row = {};
41
+ for (const field of fields) {
42
+ row[field] = getValue(item, field);
43
+ }
44
+ return row;
45
+ });
46
+ try {
47
+ const parser = new Parser({ fields });
48
+ return parser.parse(rows);
49
+ }
50
+ catch (error) {
51
+ if (error instanceof Error) {
52
+ throw new Error(`CSV parsing failed: ${error.message}`);
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ //# sourceMappingURL=csv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv.js","sourceRoot":"","sources":["../../src/csv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC;;;;;;;;;;GAUG;AACH,SAAS,QAAQ,CAAC,GAAQ,EAAE,IAAY;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AACtD,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,KAAK,CAAC,KAAY,EAAE,MAAgB;IAClD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC5B,MAAM,GAAG,GAAwB,EAAE,CAAA;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,GAAG,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACrC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,uBAAuB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { AuthConfig } from "./auth.js";
2
+ /**
3
+ * Fetches all posts/pages/custom post types from WordPress REST API with automatic pagination
4
+ *
5
+ * @param {string} endpoint - WordPress site URL (e.g., "https://example.com")
6
+ * @param {string} postType - Post type to fetch (e.g., "posts", "pages", "custom-type")
7
+ * @param {AuthConfig} [auth] - Optional authentication configuration
8
+ * @param {number} [perPage=100] - Number of items per page (max 100)
9
+ * @returns {Promise<any[]>} Array of all posts across all pages
10
+ *
11
+ * @throws {Error} If the fetch request fails or returns non-ok status
12
+ *
13
+ * @example
14
+ * const posts = await fetchAllPosts(
15
+ * "https://example.com",
16
+ * "posts",
17
+ * { type: "basic", username: "admin", password: "xxx" }
18
+ * )
19
+ */
20
+ export declare function fetchAllPosts(endpoint: string, postType: string, auth?: AuthConfig, perPage?: number): Promise<any[]>;
21
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,UAAU,EAAE,MAAM,WAAW,CAAA;AAEpD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,UAAU,EACjB,OAAO,SAAM,GACZ,OAAO,CAAC,GAAG,EAAE,CAAC,CA6BhB"}