@studiocms/devapps 0.1.0-beta.10

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.
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Removes all HTML tags from a given string.
3
+ *
4
+ * @param string - The input string containing HTML tags.
5
+ * @returns The input string with all HTML tags removed.
6
+ */
7
+ export declare function stripHtml(string: string): string;
8
+ /**
9
+ * Cleans up the provided HTML string by removing certain attributes from images
10
+ * and modifying specific elements related to WordPress polls.
11
+ *
12
+ * @param html - The HTML string to be cleaned up.
13
+ * @returns The cleaned-up HTML string.
14
+ */
15
+ export declare const cleanUpHtml: (html: string) => string;
16
+ /**
17
+ * Downloads an image from the specified URL and saves it to the given destination.
18
+ *
19
+ * @param {string | URL} imageUrl - The URL of the image to download.
20
+ * @param {string | URL} destination - The file path where the image should be saved.
21
+ * @returns {Promise<boolean>} - A promise that resolves to true if the image was successfully downloaded,
22
+ * or false if the download failed or the file already exists.
23
+ *
24
+ * @throws {Error} - Throws an error if there is an issue with the fetch request or file writing.
25
+ */
26
+ export declare function downloadImage(imageUrl: string | URL, destination: string | URL): Promise<boolean>;
27
+ /**
28
+ * Downloads an image from the given source URL and saves it to the specified folder.
29
+ *
30
+ * @param src - The URL of the image to download.
31
+ * @param pathToFolder - The path to the folder where the image should be saved.
32
+ * @returns The file name of the downloaded image if successful, otherwise `undefined`.
33
+ *
34
+ * @remarks
35
+ * - If the `src` or `pathToFolder` parameters are not provided, the function will return immediately.
36
+ * - If the specified folder does not exist, it will be created recursively.
37
+ * - If the image already exists in the specified folder, the function will log a message and skip the download.
38
+ * - If the image download fails, the source URL will be added to the `imagesNotDownloaded` array.
39
+ */
40
+ export declare const downloadPostImage: (src: string, pathToFolder: string) => Promise<string | undefined>;
41
+ /**
42
+ * Downloads and updates the image sources in the provided HTML string.
43
+ *
44
+ * This function parses the given HTML string, finds all image elements,
45
+ * downloads the images to the specified folder, and updates the image
46
+ * sources to point to the downloaded images.
47
+ *
48
+ * @param html - The HTML string containing image elements to be processed.
49
+ * @param pathToFolder - The path to the folder where images should be downloaded.
50
+ * @returns A promise that resolves to the updated HTML string with new image sources.
51
+ */
52
+ export declare const downloadAndUpdateImages: (html: string, pathToFolder: string) => Promise<string>;
53
+ /**
54
+ * Constructs a WordPress API endpoint URL based on the provided parameters.
55
+ *
56
+ * @param endpoint - The base URL of the WordPress website.
57
+ * @param type - The type of resource to access. Can be 'posts', 'pages', 'media', 'categories', 'tags', or 'settings'.
58
+ * @param path - An optional path to append to the endpoint.
59
+ * @returns The constructed URL object pointing to the desired API endpoint.
60
+ * @throws {AstroError} If the `endpoint` argument is missing.
61
+ */
62
+ export declare const apiEndpoint: (endpoint: string, type: "posts" | "pages" | "media" | "categories" | "tags" | "settings", path?: string) => URL;
63
+ /**
64
+ * Fetch all pages for a paginated WP endpoint.
65
+ */
66
+ export declare function fetchAll(url: URL, page?: number, results?: any[]): Promise<any[]>;
@@ -0,0 +1,138 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { AstroError } from "astro/errors";
4
+ import * as cheerio from "cheerio";
5
+ const imagesNotDownloaded = [];
6
+ function stripHtml(string) {
7
+ return string.replace(/<[^>]*>/g, "");
8
+ }
9
+ const cleanUpHtml = (html) => {
10
+ const $ = cheerio.load(html);
11
+ const images = $("img");
12
+ for (const image of images) {
13
+ $(image).removeAttr("class width height data-recalc-dims sizes srcset");
14
+ }
15
+ $(".wp-polls").html(
16
+ "<em>Polls have been temporarily removed while we migrate to a new platform.</em>"
17
+ );
18
+ $(".wp-polls-loading").remove();
19
+ return $.html();
20
+ };
21
+ async function downloadImage(imageUrl, destination) {
22
+ if (fs.existsSync(destination)) {
23
+ console.error("File already exists:", destination);
24
+ return true;
25
+ }
26
+ try {
27
+ const response = await fetch(imageUrl);
28
+ if (response.ok && response.body) {
29
+ const reader = response.body.getReader();
30
+ const chunks = [];
31
+ let done = false;
32
+ while (!done) {
33
+ const { done: readerDone, value } = await reader.read();
34
+ if (value) {
35
+ chunks.push(value);
36
+ }
37
+ done = readerDone;
38
+ }
39
+ const fileBuffer = Buffer.concat(chunks);
40
+ fs.writeFileSync(destination, fileBuffer, { flag: "wx" });
41
+ console.log("Downloaded image:", imageUrl);
42
+ return true;
43
+ }
44
+ console.error("Failed to download image:", imageUrl);
45
+ return false;
46
+ } catch (error) {
47
+ console.error("Failed to download image:", imageUrl, error);
48
+ return false;
49
+ }
50
+ }
51
+ const downloadPostImage = async (src, pathToFolder) => {
52
+ if (!src || !pathToFolder) {
53
+ return;
54
+ }
55
+ if (!fs.existsSync(pathToFolder)) {
56
+ fs.mkdirSync(pathToFolder, { recursive: true });
57
+ }
58
+ const fileName = path.basename(src).split("?")[0];
59
+ const destinationFile = path.resolve(pathToFolder, fileName);
60
+ if (fs.existsSync(destinationFile)) {
61
+ console.log(`Post/Page image "${destinationFile}" already exists, skipping...`);
62
+ return fileName;
63
+ }
64
+ const imageDownloaded = await downloadImage(src, destinationFile);
65
+ if (!imageDownloaded) {
66
+ imagesNotDownloaded.push(src);
67
+ }
68
+ return imageDownloaded ? fileName : void 0;
69
+ };
70
+ const downloadAndUpdateImages = async (html, pathToFolder) => {
71
+ const $ = cheerio.load(html);
72
+ const images = $("img");
73
+ for (const image of images) {
74
+ const src = $(image).attr("src");
75
+ if (src) {
76
+ const newSrc = await downloadPostImage(src, pathToFolder);
77
+ $(image).attr("src", newSrc);
78
+ }
79
+ }
80
+ return $.html();
81
+ };
82
+ const apiEndpoint = (endpoint, type, path2) => {
83
+ if (!endpoint) {
84
+ throw new AstroError(
85
+ "Missing `endpoint` argument.",
86
+ "Please pass a URL to your WordPress website as the `endpoint` option to the WordPress importer. Most commonly this looks something like `https://example.com/`"
87
+ );
88
+ }
89
+ let newEndpoint = endpoint;
90
+ if (!newEndpoint.endsWith("/")) newEndpoint += "/";
91
+ const apiBase = new URL(newEndpoint);
92
+ if (type === "settings") {
93
+ apiBase.pathname = "wp-json/";
94
+ return apiBase;
95
+ }
96
+ apiBase.pathname = `wp-json/wp/v2/${type}/${path2 ? `${path2}/` : ""}`;
97
+ return apiBase;
98
+ };
99
+ async function fetchAll(url, page = 1, results = []) {
100
+ url.searchParams.set("per_page", "100");
101
+ url.searchParams.set("page", String(page));
102
+ const response = await fetch(url);
103
+ let data = await response.json();
104
+ if (!Array.isArray(data)) {
105
+ if (typeof data === "object") {
106
+ data = Object.entries(data).map(([id, val]) => {
107
+ if (typeof val === "object") return { id, ...val };
108
+ return { id };
109
+ });
110
+ } else {
111
+ throw new AstroError(
112
+ "Expected WordPress API to return an array of items.",
113
+ `Received ${typeof data}:
114
+
115
+ \`\`\`json
116
+ ${JSON.stringify(data, null, 2)}
117
+ \`\`\``
118
+ );
119
+ }
120
+ }
121
+ results.push(...data);
122
+ const totalPages = Number.parseInt(response.headers.get("X-WP-TotalPages") || "1");
123
+ console.log("Fetched page", page, "of", totalPages);
124
+ if (page < totalPages) {
125
+ console.log("Fetching next page...");
126
+ return fetchAll(url, page + 1, results);
127
+ }
128
+ return results;
129
+ }
130
+ export {
131
+ apiEndpoint,
132
+ cleanUpHtml,
133
+ downloadAndUpdateImages,
134
+ downloadImage,
135
+ downloadPostImage,
136
+ fetchAll,
137
+ stripHtml
138
+ };
package/dist/virt.d.js ADDED
File without changes
package/dist/virt.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ /// <reference types="@astrojs/db" />
2
+
3
+ declare module 'virtual:studiocms-devapps/endpoints' {
4
+ export const wpAPIEndpoint: string;
5
+ }
6
+
7
+ declare module 'virtual:studiocms-devapps/config' {
8
+ export const userProjectRoot: string;
9
+ export const dbEnv: {
10
+ remoteUrl: string;
11
+ token: string;
12
+ };
13
+ }
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@studiocms/devapps",
3
+ "version": "0.1.0-beta.10",
4
+ "description": "A dedicated CMS for Astro DB. Built from the ground up by the Astro community.",
5
+ "author": {
6
+ "name": "Adam Matthiesen | Jacob Jenkins | Paul Valladares",
7
+ "url": "https://studiocms.dev"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/withstudiocms/studiocms.git",
12
+ "directory": "packages/studiocms_devapps"
13
+ },
14
+ "contributors": [
15
+ "Adammatthiesen",
16
+ "jdtjenkins",
17
+ "dreyfus92"
18
+ ],
19
+ "license": "MIT",
20
+ "keywords": [
21
+ "astro",
22
+ "astrodb",
23
+ "astrolicious",
24
+ "astro-integration",
25
+ "studiocms",
26
+ "withastro",
27
+ "wordpress",
28
+ "wordpress-import",
29
+ "wordpress-importer",
30
+ "libsql",
31
+ "libsql-viewer",
32
+ "libsql-client",
33
+ "libsqlstudio",
34
+ "devapp",
35
+ "astro-devapp",
36
+ "astro-devtoolbarapp"
37
+ ],
38
+ "homepage": "https://studiocms.dev",
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "provenance": true
42
+ },
43
+ "sideEffects": false,
44
+ "files": [
45
+ "dist",
46
+ "assets"
47
+ ],
48
+ "exports": {
49
+ ".": {
50
+ "types": "./dist/index.d.ts",
51
+ "default": "./dist/index.js"
52
+ }
53
+ },
54
+ "type": "module",
55
+ "dependencies": {
56
+ "astro-integration-kit": "^0.18",
57
+ "@libsql/client": "^0.14.0",
58
+ "cheerio": "^1.0.0",
59
+ "turndown": "^7.2.0",
60
+ "html-entities": "^2.5.2",
61
+ "@outerbase/sdk-transform": "^1.0.5"
62
+ },
63
+ "devDependencies": {
64
+ "@types/cheerio": "^0.22.35",
65
+ "@types/turndown": "^5.0.5",
66
+ "typescript": "^5.7"
67
+ },
68
+ "peerDependencies": {
69
+ "@astrojs/db": "^0.14.7",
70
+ "astro": "^5.4.0",
71
+ "vite": "^6.2.0",
72
+ "studiocms": "0.1.0-beta.10"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "studiocms": {
76
+ "optional": true
77
+ }
78
+ },
79
+ "scripts": {
80
+ "build": "build-scripts build 'src/**/*.ts'",
81
+ "dev": "build-scripts dev 'src/**/*.ts'"
82
+ }
83
+ }