@griddo/cx 11.9.11-rc.9 → 11.9.12-rc.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.
Files changed (254) hide show
  1. package/README.md +13 -240
  2. package/build/commands/end-render.d.ts +0 -1
  3. package/build/commands/end-render.js +31 -0
  4. package/build/commands/end-render.js.map +7 -0
  5. package/build/commands/prepare-assets-directory.js +9 -0
  6. package/build/commands/prepare-assets-directory.js.map +7 -0
  7. package/build/commands/prepare-domains-render.js +38 -0
  8. package/build/commands/prepare-domains-render.js.map +7 -0
  9. package/build/commands/reset-render.d.ts +0 -1
  10. package/build/commands/reset-render.js +31 -0
  11. package/build/commands/reset-render.js.map +7 -0
  12. package/build/commands/single-domain-upload-search-content.d.ts +1 -0
  13. package/build/commands/start-render.d.ts +0 -1
  14. package/build/commands/start-render.js +66 -0
  15. package/build/commands/start-render.js.map +7 -0
  16. package/build/commands/upload-search-content.d.ts +0 -1
  17. package/build/commands/upload-search-content.js +32 -0
  18. package/build/commands/upload-search-content.js.map +7 -0
  19. package/build/core/GriddoLog.d.ts +16 -0
  20. package/build/{utils/health-checks.d.ts → core/check-env-health.d.ts} +4 -2
  21. package/build/core/db-class.d.ts +11 -0
  22. package/build/core/db.d.ts +4 -0
  23. package/build/core/dist-rollback.d.ts +11 -0
  24. package/build/core/errors.d.ts +26 -0
  25. package/build/core/fs.d.ts +69 -0
  26. package/build/core/life-cycle.d.ts +26 -0
  27. package/build/core/logger.d.ts +18 -0
  28. package/build/core/objects.d.ts +11 -0
  29. package/build/core/print-logos.d.ts +5 -0
  30. package/build/index.d.ts +10 -29
  31. package/build/index.js +406 -73
  32. package/build/react/DynamicScript/index.d.ts +4 -0
  33. package/build/react/GriddoFavicon/index.d.ts +4 -0
  34. package/build/react/GriddoIntegrations/index.d.ts +3 -4
  35. package/build/react/GriddoIntegrations/utils.d.ts +7 -6
  36. package/build/react/GriddoOpenGraph/index.d.ts +10 -0
  37. package/build/react/index.d.ts +3 -2
  38. package/build/react/index.js +1 -3
  39. package/build/{utils → services}/api.d.ts +1 -1
  40. package/build/services/auth.d.ts +2 -5
  41. package/build/services/domains.d.ts +3 -4
  42. package/build/services/manage-sites.d.ts +22 -0
  43. package/build/services/manage-store.d.ts +32 -0
  44. package/build/services/navigation.d.ts +16 -16
  45. package/build/{utils → services}/pages.d.ts +3 -3
  46. package/build/services/reference-fields.d.ts +3 -3
  47. package/build/services/render-artifacts.d.ts +6 -0
  48. package/build/services/render.d.ts +70 -0
  49. package/build/services/robots.d.ts +2 -19
  50. package/build/services/sitemaps.d.ts +5 -0
  51. package/build/services/sites.d.ts +8 -5
  52. package/build/services/store.d.ts +10 -1
  53. package/build/shared/context.d.ts +36 -0
  54. package/build/shared/envs.d.ts +19 -0
  55. package/build/{errors/errors-data.d.ts → shared/errors.d.ts} +5 -3
  56. package/build/shared/npm-modules/brush.d.ts +18 -0
  57. package/build/shared/npm-modules/find-up-simple.d.ts +34 -0
  58. package/build/shared/npm-modules/pkg-dir.d.ts +7 -0
  59. package/build/shared/npm-modules/xml-parser.d.ts +4 -0
  60. package/build/{types → shared/types}/api.d.ts +18 -18
  61. package/build/{types → shared/types}/global.d.ts +15 -16
  62. package/build/{types → shared/types}/navigation.d.ts +5 -5
  63. package/build/{types → shared/types}/pages.d.ts +9 -9
  64. package/build/shared/types/render.d.ts +54 -0
  65. package/build/{types → shared/types}/sites.d.ts +18 -19
  66. package/build/shared/types.d.ts +15 -0
  67. package/build/ssg-adapters/gatsby/actions/clean.d.ts +3 -0
  68. package/build/ssg-adapters/gatsby/actions/close.d.ts +3 -0
  69. package/build/ssg-adapters/gatsby/actions/data.d.ts +2 -0
  70. package/build/ssg-adapters/gatsby/actions/healthCheck.d.ts +2 -0
  71. package/build/ssg-adapters/gatsby/actions/init.d.ts +2 -0
  72. package/build/ssg-adapters/gatsby/actions/logs.d.ts +3 -0
  73. package/build/ssg-adapters/gatsby/actions/meta.d.ts +2 -0
  74. package/build/ssg-adapters/gatsby/actions/prepare.d.ts +2 -0
  75. package/build/ssg-adapters/gatsby/actions/relocation.d.ts +2 -0
  76. package/build/ssg-adapters/gatsby/actions/restore.d.ts +3 -0
  77. package/build/ssg-adapters/gatsby/actions/ssg.d.ts +3 -0
  78. package/build/ssg-adapters/gatsby/actions/sync.d.ts +3 -0
  79. package/build/ssg-adapters/gatsby/index.d.ts +9 -0
  80. package/build/ssg-adapters/gatsby/shared/artifacts.d.ts +4 -0
  81. package/build/ssg-adapters/gatsby/shared/diff-assets.d.ts +15 -0
  82. package/build/ssg-adapters/gatsby/shared/extract-assets.d.ts +7 -0
  83. package/build/ssg-adapters/gatsby/shared/gatsby-build.d.ts +7 -0
  84. package/build/ssg-adapters/gatsby/shared/render-rollback.d.ts +18 -0
  85. package/build/ssg-adapters/gatsby/shared/sync-render.d.ts +26 -0
  86. package/build/ssg-adapters/gatsby/shared/types.d.ts +34 -0
  87. package/cli.mjs +231 -0
  88. package/exporter/build-esbuild.noop +42 -0
  89. package/exporter/build.sh +16 -24
  90. package/exporter/commands/README.md +151 -0
  91. package/exporter/commands/end-render.ts +65 -86
  92. package/exporter/commands/prepare-assets-directory.ts +35 -0
  93. package/exporter/commands/prepare-domains-render.ts +132 -35
  94. package/exporter/commands/reset-render.ts +13 -8
  95. package/exporter/commands/single-domain-upload-search-content.ts +206 -0
  96. package/exporter/commands/start-render.ts +26 -64
  97. package/exporter/commands/upload-search-content.ts +204 -26
  98. package/exporter/core/GriddoLog.ts +45 -0
  99. package/exporter/core/check-env-health.ts +204 -0
  100. package/exporter/core/db-class.ts +54 -0
  101. package/exporter/core/db.ts +33 -0
  102. package/exporter/core/dist-rollback.ts +49 -0
  103. package/exporter/core/errors.ts +93 -0
  104. package/exporter/core/fs.ts +385 -0
  105. package/exporter/{utils → core}/images.ts +1 -6
  106. package/exporter/{utils → core}/instance.ts +9 -13
  107. package/exporter/core/life-cycle.ts +73 -0
  108. package/exporter/core/logger.ts +141 -0
  109. package/exporter/core/objects.ts +37 -0
  110. package/exporter/core/print-logos.ts +21 -0
  111. package/exporter/index.ts +14 -56
  112. package/exporter/react/DynamicScript/index.tsx +33 -0
  113. package/exporter/react/{Favicon → GriddoFavicon}/index.tsx +3 -9
  114. package/exporter/react/GriddoIntegrations/index.tsx +17 -23
  115. package/exporter/react/GriddoIntegrations/utils.ts +24 -12
  116. package/exporter/react/GriddoOpenGraph/index.tsx +39 -0
  117. package/exporter/react/index.tsx +3 -9
  118. package/exporter/services/api.ts +306 -0
  119. package/exporter/services/auth.ts +8 -10
  120. package/exporter/services/domains.ts +23 -8
  121. package/exporter/services/manage-sites.ts +116 -0
  122. package/exporter/services/manage-store.ts +173 -0
  123. package/exporter/services/navigation.ts +12 -18
  124. package/exporter/{utils → services}/pages.ts +27 -92
  125. package/exporter/services/reference-fields.ts +14 -32
  126. package/exporter/services/render-artifacts.ts +44 -0
  127. package/exporter/services/render.ts +229 -0
  128. package/exporter/services/robots.ts +33 -61
  129. package/exporter/services/sitemaps.ts +129 -0
  130. package/exporter/services/sites.ts +40 -28
  131. package/exporter/services/store.ts +354 -321
  132. package/exporter/shared/context.ts +49 -0
  133. package/exporter/{constants → shared}/endpoints.ts +12 -11
  134. package/exporter/shared/envs.ts +62 -0
  135. package/exporter/{errors/errors-data.ts → shared/errors.ts} +24 -14
  136. package/exporter/shared/npm-modules/README.md +36 -0
  137. package/exporter/shared/npm-modules/brush.ts +34 -0
  138. package/exporter/shared/npm-modules/find-up-simple.ts +100 -0
  139. package/exporter/shared/npm-modules/pkg-dir.ts +17 -0
  140. package/exporter/shared/npm-modules/xml-parser.ts +57 -0
  141. package/exporter/{types → shared/types}/api.ts +40 -41
  142. package/exporter/{types → shared/types}/global.ts +17 -21
  143. package/exporter/{types → shared/types}/navigation.ts +3 -3
  144. package/exporter/{types → shared/types}/pages.ts +10 -11
  145. package/exporter/shared/types/render.ts +63 -0
  146. package/exporter/{types → shared/types}/sites.ts +18 -19
  147. package/exporter/shared/types.ts +15 -0
  148. package/exporter/ssg-adapters/gatsby/actions/clean.ts +26 -0
  149. package/exporter/ssg-adapters/gatsby/actions/close.ts +17 -0
  150. package/exporter/ssg-adapters/gatsby/actions/data.ts +22 -0
  151. package/exporter/ssg-adapters/gatsby/actions/healthCheck.ts +10 -0
  152. package/exporter/ssg-adapters/gatsby/actions/init.ts +12 -0
  153. package/exporter/ssg-adapters/gatsby/actions/logs.ts +10 -0
  154. package/exporter/ssg-adapters/gatsby/actions/meta.ts +13 -0
  155. package/exporter/ssg-adapters/gatsby/actions/prepare.ts +9 -0
  156. package/exporter/ssg-adapters/gatsby/actions/relocation.ts +15 -0
  157. package/exporter/ssg-adapters/gatsby/actions/restore.ts +21 -0
  158. package/exporter/ssg-adapters/gatsby/actions/ssg.ts +12 -0
  159. package/exporter/ssg-adapters/gatsby/actions/sync.ts +65 -0
  160. package/exporter/ssg-adapters/gatsby/index.ts +114 -0
  161. package/exporter/ssg-adapters/gatsby/shared/artifacts.ts +17 -0
  162. package/exporter/ssg-adapters/gatsby/shared/diff-assets.ts +128 -0
  163. package/exporter/ssg-adapters/gatsby/shared/extract-assets.ts +75 -0
  164. package/exporter/ssg-adapters/gatsby/shared/gatsby-build.ts +58 -0
  165. package/exporter/ssg-adapters/gatsby/shared/render-rollback.ts +33 -0
  166. package/exporter/ssg-adapters/gatsby/shared/sync-render.ts +298 -0
  167. package/exporter/ssg-adapters/gatsby/shared/types.ts +35 -0
  168. package/gatsby-browser.tsx +41 -58
  169. package/gatsby-config.ts +10 -17
  170. package/gatsby-node.ts +20 -79
  171. package/gatsby-ssr.tsx +2 -1
  172. package/package.json +41 -80
  173. package/plugins/gatsby-plugin-svgr-loader/gatsby-node.js +55 -0
  174. package/plugins/gatsby-plugin-svgr-loader/package.json +8 -0
  175. package/src/components/Head.tsx +28 -73
  176. package/src/components/template.tsx +6 -29
  177. package/src/gatsby-node-utils.ts +76 -2
  178. package/src/html.tsx +2 -11
  179. package/src/types.ts +3 -3
  180. package/tsconfig.commands.json +36 -0
  181. package/tsconfig.exporter.json +21 -0
  182. package/tsconfig.json +5 -3
  183. package/build/adapters/gatsby/index.d.ts +0 -4
  184. package/build/adapters/gatsby/utils.d.ts +0 -22
  185. package/build/artifacts/index.d.ts +0 -6
  186. package/build/constants/envs.d.ts +0 -37
  187. package/build/constants/index.d.ts +0 -57
  188. package/build/end-render.js +0 -74
  189. package/build/end-render.js.map +0 -7
  190. package/build/errors/index.d.ts +0 -15
  191. package/build/index.js.map +0 -7
  192. package/build/prepare-domains-render.js +0 -73
  193. package/build/prepare-domains-render.js.map +0 -7
  194. package/build/react/Favicon/index.d.ts +0 -5
  195. package/build/registers/api.d.ts +0 -9
  196. package/build/registers/gatsby.d.ts +0 -9
  197. package/build/registers/index.d.ts +0 -3
  198. package/build/reset-render.js +0 -74
  199. package/build/reset-render.js.map +0 -7
  200. package/build/services/register.d.ts +0 -36
  201. package/build/services/settings.d.ts +0 -4
  202. package/build/start-render.js +0 -100
  203. package/build/start-render.js.map +0 -7
  204. package/build/upload-search-content.js +0 -74
  205. package/build/upload-search-content.js.map +0 -7
  206. package/build/utils/alerts.d.ts +0 -3
  207. package/build/utils/cache.d.ts +0 -35
  208. package/build/utils/core-utils.d.ts +0 -107
  209. package/build/utils/create-build-data.d.ts +0 -8
  210. package/build/utils/domains.d.ts +0 -13
  211. package/build/utils/folders.d.ts +0 -53
  212. package/build/utils/loggin.d.ts +0 -51
  213. package/build/utils/render.d.ts +0 -13
  214. package/build/utils/searches.d.ts +0 -15
  215. package/build/utils/sites.d.ts +0 -31
  216. package/build/utils/store.d.ts +0 -81
  217. package/cx.config.d.ts +0 -5
  218. package/cx.config.js +0 -36
  219. package/exporter/adapters/gatsby/index.ts +0 -162
  220. package/exporter/adapters/gatsby/utils.ts +0 -161
  221. package/exporter/artifacts/README.md +0 -34
  222. package/exporter/artifacts/index.ts +0 -33
  223. package/exporter/commands/move-assets.ts +0 -11
  224. package/exporter/constants/envs.ts +0 -94
  225. package/exporter/constants/index.ts +0 -129
  226. package/exporter/errors/index.ts +0 -40
  227. package/exporter/registers/api.ts +0 -14
  228. package/exporter/registers/gatsby.ts +0 -14
  229. package/exporter/registers/index.ts +0 -4
  230. package/exporter/services/register.ts +0 -113
  231. package/exporter/services/settings.ts +0 -17
  232. package/exporter/utils/alerts.ts +0 -29
  233. package/exporter/utils/api.ts +0 -243
  234. package/exporter/utils/cache.ts +0 -142
  235. package/exporter/utils/core-utils.ts +0 -458
  236. package/exporter/utils/create-build-data.ts +0 -17
  237. package/exporter/utils/domains.ts +0 -39
  238. package/exporter/utils/folders.ts +0 -320
  239. package/exporter/utils/health-checks.ts +0 -64
  240. package/exporter/utils/loggin.ts +0 -184
  241. package/exporter/utils/render.ts +0 -71
  242. package/exporter/utils/searches.ts +0 -156
  243. package/exporter/utils/sites.ts +0 -312
  244. package/exporter/utils/store.ts +0 -314
  245. package/src/README.md +0 -7
  246. package/start-render.js +0 -7
  247. /package/build/commands/{move-assets.d.ts → prepare-assets-directory.d.ts} +0 -0
  248. /package/build/{utils → core}/images.d.ts +0 -0
  249. /package/build/{utils → core}/instance.d.ts +0 -0
  250. /package/build/react/{Favicon → GriddoFavicon}/utils.d.ts +0 -0
  251. /package/build/{constants → shared}/endpoints.d.ts +0 -0
  252. /package/build/{types → shared/types}/templates.d.ts +0 -0
  253. /package/exporter/react/{Favicon → GriddoFavicon}/utils.ts +0 -0
  254. /package/exporter/{types → shared/types}/templates.ts +0 -0
@@ -1,39 +1,217 @@
1
- #!/usr/bin/env node
1
+ import type { PostSearchInfoResponse } from "../shared/types/api";
2
+ import type { AIEmbeddingsResponse, PostSearchInfoProps } from "../shared/types/global";
3
+ import type { GatsbyPageData } from "../ssg-adapters/gatsby/shared/types";
2
4
 
3
- import fs from "node:fs";
5
+ import fsp from "node:fs/promises";
6
+ import path from "node:path";
4
7
 
5
- import { envs } from "../constants";
6
- import { getConfig } from "../utils/core-utils";
7
- import { getInstanceDomains } from "../utils/domains";
8
- import {
9
- startAIEmbeddings,
10
- uploadRenderedSearchContentToAPI,
11
- } from "../utils/searches";
8
+ import { throwError, withErrorHandler } from "../core/errors";
9
+ import { pathExists } from "../core/fs";
10
+ import { GriddoLog } from "../core/GriddoLog";
11
+ import { post } from "../services/api";
12
+ import { AuthService } from "../services/auth";
13
+ import { getInstanceDomains } from "../services/domains";
14
+ import { getRenderPathsHydratedWithDomainFromDB } from "../services/render";
15
+ import { AI_EMBEDDINGS, SEARCH } from "../shared/endpoints";
16
+ import { GRIDDO_AI_EMBEDDINGS, GRIDDO_SEARCH_FEATURE } from "../shared/envs";
17
+ import { ReadFromStoreError, UploadSearchError } from "../shared/errors";
18
+
19
+ /**
20
+ * Save in the BBDD the content of a page parsed without HTML tags.
21
+ *
22
+ * @param props Object with parts of the final page object to be saved in the BBDD.
23
+ */
24
+ async function postSearchInfo(props: PostSearchInfoProps) {
25
+ const { title, description, image, pageId, languageId, siteId, url, content, template } = props;
26
+
27
+ const response = await post<PostSearchInfoResponse>({
28
+ endpoint: SEARCH,
29
+ body: {
30
+ title,
31
+ description,
32
+ image,
33
+ pageId,
34
+ languageId,
35
+ siteId,
36
+ url,
37
+ template,
38
+ content,
39
+ },
40
+ useApiCacheDir: false,
41
+ logToFile: false,
42
+ });
43
+
44
+ return response;
45
+ }
46
+
47
+ function prepareHTMLContentForSearch(content: string): string {
48
+ // 1. Remove script, style, and other unwanted block tags and their content.
49
+ // The regex looks for <tag...>...</tag> where tag is one of the specified ones.
50
+ const tagsToRemove = ["meta", "link", "style", "script", "noscript", "nav", "header", "footer"];
51
+ const removeTagsRegex = new RegExp(`<(${tagsToRemove.join("|")})\\b[^>]*>.*?<\\/\\1>`, "gis");
52
+ let processedContent = content.replace(removeTagsRegex, "");
53
+
54
+ // 2. Strip all remaining HTML tags.
55
+ processedContent = processedContent.replace(/<[^>]+>/g, " ");
56
+
57
+ // 3. Normalize whitespace: replace multiple spaces/newlines with a single space and trim.
58
+ processedContent = processedContent.replace(/\s+/g, " ").trim();
59
+
60
+ return processedContent;
61
+ }
62
+
63
+ /**
64
+ * Function that search in the `/public` dir the content info of the pages and
65
+ * send it to the search table in the ddbb using the API.
66
+ * @todo Utilizar la carpeta page-data en lugar de la carpeta store puesto que
67
+ * esta ya no es persistente.
68
+ */
69
+ async function uploadRenderedSearchContentToAPI(options: {
70
+ htmlContentDir: string;
71
+ jsonContentDir: string;
72
+ }) {
73
+ const { htmlContentDir, jsonContentDir } = options;
74
+
75
+ if (!(await pathExists(jsonContentDir)) || !(await pathExists(htmlContentDir))) {
76
+ GriddoLog.info(
77
+ `Skipping uploading content to the search endpoint because it has not exported sites.`,
78
+ );
12
79
 
13
- async function main() {
14
- if (!envs.GRIDDO_SEARCH_FEATURE) {
15
80
  return;
16
81
  }
17
82
 
18
- const domains = await getInstanceDomains();
19
- const config = getConfig();
20
- for (const domain of domains) {
21
- const { __exports_dist } = config.paths(domain);
83
+ // Get pages from gatsby page-data dir
84
+ const gatsbyPageDataPages = getPageDataPagesFromExports(jsonContentDir);
85
+
86
+ let pagesUploadedCounter = 0;
87
+ for await (const pageData of gatsbyPageDataPages) {
88
+ const { result } = pageData;
89
+ const { pageContext } = result;
90
+ const { page, openGraph, pageMetadata } = pageContext;
91
+
92
+ const { compose } = page.fullPath;
93
+
94
+ const htmlPath = path.resolve(`${htmlContentDir}/${compose}/index.html`);
95
+ const htmlContent = await fsp.readFile(htmlPath, "utf-8");
96
+
97
+ const pageObject: PostSearchInfoProps = {
98
+ siteId: page.site,
99
+ pageId: page.id,
100
+ // `pageMetadata.title` has already a fallback `metatitle ||
101
+ // pageTitle` so probably `title` never will be take the
102
+ // `openGraph?.title` value. Only when the `metatitle` and
103
+ // `pageTitle` are empty.
104
+ title: pageMetadata?.title || openGraph?.title,
105
+ languageId: page.language,
106
+ url: page.fullUrl,
107
+ template: page.template.templateType || page.templateId,
108
+ description: pageMetadata?.description || openGraph?.description,
109
+ image: openGraph.image,
110
+ content: prepareHTMLContentForSearch(htmlContent),
111
+ };
22
112
 
23
- // If __exports_dist has not exported sites (directories), it does not
24
- // upload search content.
25
- if (fs.existsSync(__exports_dist)) {
26
- await uploadRenderedSearchContentToAPI(__exports_dist, domain);
113
+ try {
114
+ await postSearchInfo(pageObject);
115
+ } catch (error) {
116
+ throwError(UploadSearchError, error);
27
117
  }
118
+
119
+ GriddoLog.verbose(`Uploaded content of: ${page.fullUrl}`);
120
+ pagesUploadedCounter++;
28
121
  }
29
122
 
30
- // Solo una vez en cada render de todos los dominios...
31
- if (envs.GRIDDO_AI_EMBEDDINGS) {
32
- await startAIEmbeddings();
123
+ GriddoLog.info(`Uploaded ${pagesUploadedCounter} pages.\n`);
124
+ }
125
+
126
+ /**
127
+ * Walk recursively in a basePath and return an array of pages with json
128
+ * extension with the full absolute path and the path includes "page-data".
129
+ *
130
+ * @param basePath The path to walk recursively.
131
+ * @returns An array of pages with json extension with the full absolute path
132
+ * and the path includes "page-data".
133
+ */
134
+ async function* walkRecursively(basePath: string): AsyncGenerator<string> {
135
+ const filesHandle = await fsp.opendir(basePath);
136
+
137
+ for await (const fileDirent of filesHandle) {
138
+ if (fileDirent.isDirectory()) {
139
+ yield* walkRecursively(path.join(basePath, fileDirent.name));
140
+ } else if (
141
+ fileDirent.isFile() &&
142
+ path.extname(fileDirent.name) === ".json" &&
143
+ fileDirent.name.includes("page-data")
144
+ ) {
145
+ yield path.join(basePath, fileDirent.name);
146
+ }
33
147
  }
34
148
  }
35
149
 
36
- main().catch((err) => {
37
- console.error("Error", err?.stdout?.toString() || err);
38
- process.exit(1);
39
- });
150
+ /**
151
+ * Walk recursively in a basePath and return an array of pages with json
152
+ * extension with the full absolute path and the path includes "page-data".
153
+ *
154
+ * @param basePath The path to walk recursively.
155
+ * @returns An array of pages with json extension with the full absolute path
156
+ * and the path includes "page-data".
157
+ */
158
+ async function* getPageDataPagesFromExports<PageType extends GatsbyPageData>(
159
+ basePath: string,
160
+ ): AsyncGenerator<PageType> {
161
+ const jsonFiles = walkRecursively(basePath);
162
+
163
+ for await (const filePath of jsonFiles) {
164
+ try {
165
+ const fileContent = await fsp.readFile(filePath, "utf8");
166
+ const page = JSON.parse(fileContent) as PageType;
167
+
168
+ if (page.path) {
169
+ yield page;
170
+ }
171
+ } catch (error) {
172
+ throwError(ReadFromStoreError, error);
173
+ }
174
+ }
175
+ }
176
+
177
+ async function getContentDirectories(domain: string) {
178
+ const { __exports } = await getRenderPathsHydratedWithDomainFromDB({ domain });
179
+
180
+ return {
181
+ htmlContentDir: path.join(__exports, "dist"),
182
+ jsonContentDir: path.join(__exports, "dist", "page-data"),
183
+ };
184
+ }
185
+
186
+ async function uploadSearchContent() {
187
+ if (GRIDDO_SEARCH_FEATURE) {
188
+ const domains = await getInstanceDomains();
189
+ for (const domain of domains) {
190
+ const { htmlContentDir, jsonContentDir } = await getContentDirectories(domain);
191
+
192
+ GriddoLog.info(`Uploading search content for ${domain}`);
193
+ await uploadRenderedSearchContentToAPI({
194
+ htmlContentDir,
195
+ jsonContentDir,
196
+ });
197
+ }
198
+ }
199
+ }
200
+
201
+ async function aiEmbeddings() {
202
+ if (GRIDDO_SEARCH_FEATURE && GRIDDO_AI_EMBEDDINGS) {
203
+ GriddoLog.info(`Triggering AI embeddings...`);
204
+ await post<AIEmbeddingsResponse>({
205
+ endpoint: AI_EMBEDDINGS,
206
+ useApiCacheDir: false,
207
+ });
208
+ }
209
+ }
210
+
211
+ async function main() {
212
+ await AuthService.login();
213
+ await uploadSearchContent();
214
+ await aiEmbeddings();
215
+ }
216
+
217
+ withErrorHandler(main);
@@ -0,0 +1,45 @@
1
+ import { GRIDDO_BUILD_LOGS, GRIDDO_VERBOSE_LOGS } from "../shared/envs";
2
+ import { brush } from "../shared/npm-modules/brush";
3
+
4
+ /**
5
+ * Clase estática para gestionar los logs de la aplicación.
6
+ * No se puede instanciar, se usa directamente: GriddoLogs.info("mensaje").
7
+ */
8
+ class GriddoLog {
9
+ /** El constructor es privado para prevenir la instanciación de la clase. */
10
+ private constructor() {}
11
+
12
+ public static verbose(...str: unknown[]): void {
13
+ if (GRIDDO_VERBOSE_LOGS) {
14
+ console.log(brush.yellow("verbose"), brush.dim(str.join(" ")));
15
+ }
16
+ }
17
+
18
+ public static build(...str: unknown[]): void {
19
+ if (GRIDDO_BUILD_LOGS) {
20
+ GriddoLog.log(...str);
21
+ }
22
+ }
23
+
24
+ public static info(...str: unknown[]): void {
25
+ console.log(`${brush.blue("info")} ${str.join(" ")}`);
26
+ }
27
+
28
+ public static success(...str: unknown[]): void {
29
+ console.log(`${brush.green("success")} ${str.join(" ")}`);
30
+ }
31
+
32
+ public static error(...str: unknown[]): void {
33
+ console.error(`${brush.red("error")} ${str.join(" ")}`);
34
+ }
35
+
36
+ public static warn(...str: unknown[]): void {
37
+ console.warn(`${brush.yellow("warn")} ${str.join(" ")}`);
38
+ }
39
+
40
+ public static log(...args: Parameters<typeof console.log>): void {
41
+ console.log(...args);
42
+ }
43
+ }
44
+
45
+ export { GriddoLog };
@@ -0,0 +1,204 @@
1
+ import { CheckHealthError } from "../shared/errors";
2
+ import { throwError } from "./errors";
3
+ import { GriddoLog } from "./GriddoLog";
4
+
5
+ // Environment variables that must be present (but value doesn't matter)
6
+ const REQUIRED_ENV_VARS: readonly string[] = [];
7
+
8
+ // Environment variables that must have specific values
9
+ const REQUIRED_ENV_VALUES: readonly {
10
+ key: string;
11
+ expected: string;
12
+ description?: string;
13
+ }[] = [
14
+ // {
15
+ // key: "GRIDDO_RENDER_BY_DOMAINS",
16
+ // expected: "true",
17
+ // description: "Must be set to 'true' for domain-based rendering",
18
+ // },
19
+ ];
20
+
21
+ // Environment variables that are recommended but not required
22
+ // These will show warnings if missing but won't fail the health check
23
+ const RECOMMENDED_ENV_VARS: readonly { key: string; description?: string }[] = [
24
+ {
25
+ key: "GRIDDO_BUILD_LOGS",
26
+ description: "Recommended for detailed render logs",
27
+ },
28
+ {
29
+ key: "GRIDDO_BUILD_LOGS_TO_FILE",
30
+ description: "Recommended for performance gain and simplify render logs",
31
+ },
32
+ {
33
+ key: "GRIDDO_API_CONCURRENCY_COUNT",
34
+ description: "Recommended for better performance and memory management",
35
+ },
36
+ ];
37
+
38
+ // Environment variables that must be present (but value doesn't matter)
39
+ const DEPRECATED_ENV_VARS: readonly { key: string; description?: string }[] = [
40
+ {
41
+ key: "GRIDDO_RENDER_SITE",
42
+ description:
43
+ "This environment variable no longer has any effect because it is incompatible with incremental rendering.",
44
+ },
45
+ {
46
+ key: "GRIDDO_RENDER_PAGES",
47
+ description:
48
+ "This environment variable no longer has any effect because it is incompatible with incremental rendering.",
49
+ },
50
+ {
51
+ key: "REACT_APP_API_ENDPOINT",
52
+ description: "Use GRIDDO_API_URL",
53
+ },
54
+ {
55
+ key: "REACT_APP_PUBLIC_API_ENDPOINT",
56
+ description: "Use GRIDDO_PUBLIC_API_URL",
57
+ },
58
+ {
59
+ key: "GRIDDO_RENDER_ALL_SITES",
60
+ description: "This environment variable is deprecated, remove it",
61
+ },
62
+ ];
63
+
64
+ /**
65
+ * Check if required environment variables exist with any value.
66
+ *
67
+ * @returns An object containing:
68
+ * - isValid: boolean indicating if all required environment variables are present.
69
+ * - missing: an array of missing environment variable names.
70
+ */
71
+ function checkRequiredEnvVars(): { isValid: boolean; missing: string[] } {
72
+ const missing = REQUIRED_ENV_VARS.filter((envName) => !process.env[envName]);
73
+
74
+ if (missing.length > 0) {
75
+ GriddoLog.error(`Missing required environment variables: ${missing.join(", ")}`);
76
+ return { isValid: false, missing };
77
+ }
78
+
79
+ return { isValid: true, missing: [] };
80
+ }
81
+
82
+ /**
83
+ * Check if environment variables have the expected values.
84
+ *
85
+ * @returns An object containing:
86
+ * - isValid: boolean indicating if all required environment variables have the expected values.
87
+ * - mismatches: an array of mismatched environment variable names and their expected and actual values.
88
+ */
89
+ function checkEnvVarValues(): {
90
+ isValid: boolean;
91
+ mismatches: { key: string; expected: string; actual: string }[];
92
+ } {
93
+ const mismatches: { key: string; expected: string; actual: string }[] = [];
94
+
95
+ for (const { key, expected } of REQUIRED_ENV_VALUES) {
96
+ const actual = process.env[key];
97
+
98
+ if (actual !== expected) {
99
+ mismatches.push({ key, expected, actual: actual || "(undefined)" });
100
+ }
101
+ }
102
+
103
+ if (mismatches.length > 0) {
104
+ return { isValid: false, mismatches };
105
+ }
106
+
107
+ return { isValid: true, mismatches: [] };
108
+ }
109
+
110
+ /**
111
+ * Check recommended environment variables and show warnings for missing ones.
112
+ *
113
+ * @returns An object containing:
114
+ * - isValid: boolean indicating if all recommended environment variables are set.
115
+ * - missing: an array of missing recommended environment variable names.
116
+ */
117
+ function checkRecommendedEnvVars() {
118
+ const missing = RECOMMENDED_ENV_VARS.filter(({ key }) => !process.env[key]);
119
+
120
+ if (missing.length > 0) {
121
+ GriddoLog.warn("Recommended environment variables not set:");
122
+
123
+ for (const { key, description } of missing) {
124
+ const desc = description ? ` # ${description}` : "";
125
+ GriddoLog.log(` -> ${key}${desc}`);
126
+ }
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Check if set enviroment variables have been deprecated
132
+ *
133
+ * @returns An object containing:
134
+ * - deprecated: an array of deprecated environment variable names.
135
+ */
136
+ function checkDeprecatedEnvVars() {
137
+ const deprecated = DEPRECATED_ENV_VARS.filter(({ key }) => process.env[key]);
138
+
139
+ if (deprecated.length > 0) {
140
+ const deprecatedMessages = deprecated.map(({ key, description }) => {
141
+ const desc = description ? ` # ${description}` : "";
142
+ return ` ${key}${desc}`;
143
+ });
144
+
145
+ GriddoLog.warn("Deprecated environment variables set:");
146
+ GriddoLog.warn(`${deprecatedMessages.join("\n")}\n`);
147
+ }
148
+
149
+ return { deprecated: deprecated.map((key) => key) };
150
+ }
151
+
152
+ /**
153
+ * Check if the environment is secure to launch a render.
154
+ * If something fails then log an error message and exit from the process.
155
+ * Otherwise just return true.
156
+ *
157
+ * @returns A boolean indicating if the environment is secure to launch a render.
158
+ */
159
+ function checkEnvironmentHealth() {
160
+ // Check required environment variables
161
+ const envVarsCheck = checkRequiredEnvVars();
162
+ const envValuesCheck = checkEnvVarValues();
163
+
164
+ // (warnings only)
165
+ checkRecommendedEnvVars();
166
+ checkDeprecatedEnvVars();
167
+
168
+ // Render is safe if all required checks pass
169
+ const isSafeToRender = envVarsCheck.isValid && envValuesCheck.isValid;
170
+
171
+ if (isSafeToRender) {
172
+ GriddoLog.info("Build health check passed");
173
+ return true;
174
+ }
175
+
176
+ // Generate consolidated error message
177
+ const allIssues: string[] = [];
178
+
179
+ if (!envVarsCheck.isValid) {
180
+ allIssues.push(`Missing: ${envVarsCheck.missing.join(", ")}`);
181
+ }
182
+
183
+ if (!envValuesCheck.isValid) {
184
+ const mismatchMessages = envValuesCheck.mismatches.map(
185
+ ({ key, expected, actual }) => `${key}="${actual || "undefined"}" (expected "${expected}")`,
186
+ );
187
+ allIssues.push(`Incorrect values:\n ${mismatchMessages.join("\n ")}`);
188
+ }
189
+
190
+ // Show what needs to be set
191
+ const requiredVarsMessage = REQUIRED_ENV_VALUES.map(({ key, expected, description }) => {
192
+ const desc = description ? ` # ${description}` : "";
193
+ return ` ${key}="${expected}"${desc}`;
194
+ }).join("\n");
195
+
196
+ GriddoLog.error(`Environment health check failed:`);
197
+ GriddoLog.error(` ${allIssues.join("\n ")}`);
198
+ GriddoLog.warn("\nRequired environment variables:");
199
+ GriddoLog.error(requiredVarsMessage);
200
+
201
+ throwError(CheckHealthError);
202
+ }
203
+
204
+ export { checkEnvironmentHealth };
@@ -0,0 +1,54 @@
1
+ import type { RenderDB } from "../shared/types/render";
2
+
3
+ import fsp from "node:fs/promises";
4
+ import path from "node:path";
5
+
6
+ import { pkgDirSync } from "../shared/npm-modules/pkg-dir";
7
+ import { GriddoLog } from "./GriddoLog";
8
+
9
+ // Interfaz para abstraer la DB
10
+ export interface Database {
11
+ read(): Promise<RenderDB>;
12
+ write(renderDB: RenderDB): Promise<void>;
13
+ }
14
+
15
+ export class JsonDatabase implements Database {
16
+ private readonly dbFilePath: string;
17
+
18
+ constructor(customDBPath?: string) {
19
+ this.dbFilePath =
20
+ customDBPath ??
21
+ path.join(
22
+ pkgDirSync({ cwd: path.resolve(__dirname, "../../..") }) ?? "",
23
+ ".griddo/cache/db.json",
24
+ );
25
+ }
26
+
27
+ async read(customDBFilePath?: string): Promise<RenderDB> {
28
+ try {
29
+ const raw = await fsp.readFile(customDBFilePath || this.dbFilePath, "utf-8");
30
+ return JSON.parse(raw) as RenderDB;
31
+ } catch (error) {
32
+ if (error instanceof Error) {
33
+ GriddoLog.error(`Error reading DB file at ${this.dbFilePath}:`, error.message);
34
+ } else {
35
+ GriddoLog.error(`Unknown error reading DB file at ${this.dbFilePath}:`, error);
36
+ }
37
+ throw error;
38
+ }
39
+ }
40
+
41
+ async write(renderDB: RenderDB): Promise<void> {
42
+ try {
43
+ await fsp.mkdir(path.dirname(this.dbFilePath), { recursive: true });
44
+ await fsp.writeFile(this.dbFilePath, JSON.stringify(renderDB, null, "\t"));
45
+ } catch (error) {
46
+ if (error instanceof Error) {
47
+ GriddoLog.error(`Error writing to DB file at ${this.dbFilePath}:`, error.message);
48
+ } else {
49
+ GriddoLog.error(`Unknown error writing to DB file at ${this.dbFilePath}:`, error);
50
+ }
51
+ throw error;
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,33 @@
1
+ import type { RenderDB } from "../shared/types/render";
2
+
3
+ import fsp from "node:fs/promises";
4
+ import path from "node:path";
5
+
6
+ import { pkgDirSync } from "../shared/npm-modules/pkg-dir";
7
+ import { GriddoLog } from "./GriddoLog";
8
+
9
+ const root = pkgDirSync({ cwd: path.resolve(__dirname, "../../..") }) || "";
10
+ const cache = path.join(root, ".griddo/cache");
11
+ const dbFilePath = path.join(cache, "db.json");
12
+
13
+ async function readDB(customDBPath = "") {
14
+ const file = customDBPath || dbFilePath;
15
+ try {
16
+ return JSON.parse(await fsp.readFile(file, "utf-8")) as RenderDB;
17
+ } catch (error) {
18
+ GriddoLog.error(`Failed to read DB file at ${file}:`, error);
19
+ throw error;
20
+ }
21
+ }
22
+
23
+ async function writeDB(renderDB: RenderDB, customDBPath = "") {
24
+ const file = customDBPath || dbFilePath;
25
+ try {
26
+ await fsp.writeFile(file, JSON.stringify(renderDB, null, "\t"));
27
+ } catch (error) {
28
+ GriddoLog.error(`Failed to write DB file at ${file}:`, error);
29
+ throw error;
30
+ }
31
+ }
32
+
33
+ export { readDB, writeDB };
@@ -0,0 +1,49 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { readDB } from "./db";
5
+ import { pathExists } from "./fs";
6
+ import { GriddoLog } from "./GriddoLog";
7
+
8
+ /**
9
+ * Rolls back the exports directory for the given domain.
10
+ *
11
+ * - Deletes the potentially corrupt exports directory for the domain.
12
+ * - If a backup exists, it restores the directory from the backup location.
13
+ * - If no backup is found, it informs that a fresh exports directory will be created on the next render.
14
+ *
15
+ * @param domain The domain for which to rollback the exports directory.
16
+ */
17
+ async function distRollback(domain: string): Promise<void> {
18
+ const data = await readDB();
19
+ const { exportsDir, exportsDirBackup } = data.paths;
20
+
21
+ GriddoLog.info(`Cleaning exports dir for the domain ${domain}`);
22
+ GriddoLog.verbose(`Deleting ${path.join(exportsDir, domain)}...`);
23
+
24
+ // TODO: Probar rsync en lugar de borrar y copiar
25
+
26
+ // 1 - Borrar dist corrupto
27
+ await fsp.rm(path.join(exportsDir, domain), {
28
+ recursive: true,
29
+ force: true,
30
+ });
31
+
32
+ // 2 - Si hay backup, restaurar
33
+ if (await pathExists(path.join(exportsDirBackup, domain))) {
34
+ await fsp.cp(path.join(exportsDirBackup, domain), path.join(exportsDir, domain), {
35
+ recursive: true,
36
+ });
37
+
38
+ GriddoLog.info(`export-backup dir for the domain ${domain} found. Restoring before exit...`);
39
+ GriddoLog.verbose(
40
+ `Copying ${path.join(exportsDirBackup, domain)} -> ${path.join(exportsDir, domain)}...`,
41
+ );
42
+ } else {
43
+ GriddoLog.info(
44
+ "No export-backup found, skipping rollback. Next render will create a new exports dir from scratch...",
45
+ );
46
+ }
47
+ }
48
+
49
+ export { distRollback };