@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
@@ -0,0 +1,229 @@
1
+ import type { RenderModeTuple } from "../shared/types/render";
2
+
3
+ import { execSync } from "node:child_process";
4
+ import fsp from "node:fs/promises";
5
+ import path from "node:path";
6
+
7
+ import { readDB, writeDB } from "../core/db";
8
+ import { throwError } from "../core/errors";
9
+ import { pathExists } from "../core/fs";
10
+ import { GriddoLog } from "../core/GriddoLog";
11
+ import { RenderUUIDError } from "../shared/errors";
12
+ import { brush } from "../shared/npm-modules/brush";
13
+ import { RENDER_MODE } from "../shared/types/render";
14
+ import { AuthService } from "./auth";
15
+ import { getBuildMetadata } from "./manage-store";
16
+
17
+ /**
18
+ * Creates a sentinel file with the current date and time.
19
+ * This file is used to track later if node_modules/@griddo/cx was cleaned by a
20
+ * npm install coming from a deploy.
21
+ */
22
+ async function markRenderAsStarted(options: { domain: string; basePath: string }) {
23
+ const { domain } = options;
24
+
25
+ const db = await readDB();
26
+ db.domains[domain].isRendering = true;
27
+ await writeDB(db);
28
+
29
+ // Creamos un archivo centinela, si al terminar el render este archivo no
30
+ // existe es que ha habido un deploy por medio y hay que invalidar el render
31
+ const { __ssg } = await getRenderPathsHydratedWithDomainFromDB();
32
+
33
+ const renderSentinelFile = path.join(__ssg, `.render-sentinel-${domain}`);
34
+ await fsp.writeFile(renderSentinelFile, new Date().toISOString());
35
+ }
36
+
37
+ async function markRenderAsCompleted(domain: string) {
38
+ const db = await readDB();
39
+ db.domains[domain].isRendering = false;
40
+ db.currentRenderingDomain = null;
41
+ db.domains[domain].renderMode = RENDER_MODE.COMPLETED;
42
+ // db.domains[domain].shouldBeRendered = false;
43
+ await writeDB(db);
44
+
45
+ // Borramos finalmente el archivo centinela
46
+ const { __ssg } = await getRenderPathsHydratedWithDomainFromDB();
47
+ const renderSentinelFile = path.join(__ssg, `.render-sentinel-${domain}`);
48
+ await fsp.unlink(renderSentinelFile);
49
+ }
50
+
51
+ async function assertRenderIsValid(domain: string) {
52
+ // Comprobamos que .render-sentinel exista, si no es que un deploy lo borro
53
+ // y hay que invalidar el render.
54
+ const { __ssg } = await getRenderPathsHydratedWithDomainFromDB();
55
+ const renderSentinelFile = path.join(__ssg, `.render-sentinel-${domain}`);
56
+ if (!(await pathExists(renderSentinelFile))) {
57
+ throwError(RenderUUIDError);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Determines the appropriate render mode for a given domain based on its current state,
63
+ * previous render errors, deployment status, and whether rendering is required.
64
+ *
65
+ * @param options - An object containing:
66
+ * - `domain`: The domain name to resolve the render mode for.
67
+ * - `shouldBeRendered`: A boolean indicating if the domain should be rendered.
68
+ * @returns An object with:
69
+ * - `renderMode`: The resolved render mode (`FROM_SCRATCH`, `INCREMENTAL`, or `IDLE`).
70
+ * - `reason`: A string describing the reason for the chosen render mode.
71
+ *
72
+ * @remarks
73
+ * The function checks for missing exports, previous render errors, new deployments,
74
+ * and whether rendering is necessary to decide the render mode.
75
+ *
76
+ * @todo
77
+ * Improve ifs and reason concatenations...
78
+ */
79
+ async function resolveDomainRenderMode(options: { domain: string; shouldBeRendered: boolean }) {
80
+ const { domain, shouldBeRendered } = options;
81
+
82
+ const db = await readDB();
83
+
84
+ const { __cache, __exports } = await getRenderPathsHydratedWithDomainFromDB({ domain });
85
+ const exportsAreMissing = !(await pathExists(path.join(__exports)));
86
+ const previousRenderFailed = db.domains[domain]?.isRendering;
87
+ const newDeployDetected = await hasNewCommit(__cache);
88
+
89
+ if (exportsAreMissing) {
90
+ return {
91
+ renderMode: RENDER_MODE.FROM_SCRATCH,
92
+ reason: "missing exports directory",
93
+ };
94
+ }
95
+
96
+ if (previousRenderFailed) {
97
+ return {
98
+ renderMode: RENDER_MODE.FROM_SCRATCH,
99
+ reason: "error in previous render",
100
+ };
101
+ }
102
+
103
+ if (newDeployDetected) {
104
+ return {
105
+ renderMode: RENDER_MODE.FROM_SCRATCH,
106
+ reason: "new commit hash",
107
+ };
108
+ }
109
+
110
+ if (!shouldBeRendered) {
111
+ return {
112
+ renderMode: RENDER_MODE.IDLE,
113
+ reason: "no activity",
114
+ };
115
+ }
116
+
117
+ return {
118
+ renderMode: RENDER_MODE.INCREMENTAL,
119
+ reason: "has changes",
120
+ };
121
+ }
122
+
123
+ async function hasNewCommit(basePath: string): Promise<boolean> {
124
+ const commitFile = path.join(basePath, "commit");
125
+ const currentCommit = execSync("git rev-parse HEAD").toString().trim();
126
+
127
+ if (await pathExists(commitFile)) {
128
+ const savedCommit = (await fsp.readFile(commitFile, "utf-8")).trim();
129
+ if (savedCommit === currentCommit) {
130
+ return false; // No hay nuevo commit
131
+ }
132
+
133
+ return true;
134
+ }
135
+
136
+ return true;
137
+ }
138
+
139
+ async function updateCommitFile(options: { basePath: string }) {
140
+ const { basePath } = options;
141
+ const currentCommit = execSync("git rev-parse HEAD").toString().trim();
142
+ await fsp.writeFile(path.join(basePath, "commit"), currentCommit);
143
+ }
144
+
145
+ async function getRenderModeFromDB(domain: string): Promise<RenderModeTuple> {
146
+ const db = await readDB();
147
+
148
+ if (!db.domains[domain]) {
149
+ throw new Error(brush.red(`[!] Error: Domain ${domain} not found in DB`));
150
+ }
151
+
152
+ if (!db.domains[domain].renderMode) {
153
+ throw new Error(brush.red(`[!] Error: Render mode not found for domain ${domain}`));
154
+ }
155
+
156
+ return {
157
+ renderMode: db.domains[domain].renderMode,
158
+ reason: db.domains[domain].renderModeReason,
159
+ };
160
+ }
161
+
162
+ async function getRenderPathsHydratedWithDomainFromDB(options?: {
163
+ domain?: string;
164
+ dbFilePath?: string;
165
+ }) {
166
+ const { domain, dbFilePath } = options || {};
167
+
168
+ const db = await readDB(dbFilePath);
169
+ const paths = db.paths;
170
+
171
+ return {
172
+ __root: paths.root,
173
+ __cache: path.join(paths.cxCache, domain || ""),
174
+ __components: paths.components,
175
+ __cx: paths.cx,
176
+ __sites: paths.exportsDir,
177
+ __exports: path.join(paths.exportsDir, domain || ""),
178
+ __exports_backup: path.join(paths.exportsDirBackup, domain || ""),
179
+ __ssg: paths.ssg,
180
+ __exports_dist: path.join(paths.exportsDir, domain || "", "dist"),
181
+ };
182
+ }
183
+
184
+ async function getRenderMetadataFromDB() {
185
+ const db = await readDB();
186
+ return {
187
+ griddoVersion: db.griddoVersion,
188
+ buildReportFileName: db.buildReportFileName,
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Save a file with the end of build process to use as `end-render` signal.
194
+ */
195
+ async function generateBuildReport(domain: string) {
196
+ const authControl = await AuthService.login();
197
+
198
+ const { __root } = await getRenderPathsHydratedWithDomainFromDB();
199
+ const { buildReportFileName } = await getRenderMetadataFromDB();
200
+ const { buildProcessData } = await getBuildMetadata(domain);
201
+
202
+ const buildSitesInfo = Object.keys(buildProcessData).map((siteID) => ({
203
+ ...buildProcessData[siteID],
204
+ siteId: Number.parseInt(siteID),
205
+ }));
206
+
207
+ const report = {
208
+ authControl,
209
+ sites: buildSitesInfo,
210
+ };
211
+
212
+ const reportFilePath = path.join(__root, "current-dist", buildReportFileName);
213
+
214
+ await fsp.writeFile(reportFilePath, JSON.stringify(report));
215
+
216
+ GriddoLog.verbose(`build report saved in ${reportFilePath}`);
217
+ }
218
+
219
+ export {
220
+ assertRenderIsValid,
221
+ generateBuildReport,
222
+ getRenderMetadataFromDB,
223
+ getRenderModeFromDB,
224
+ getRenderPathsHydratedWithDomainFromDB,
225
+ markRenderAsCompleted,
226
+ markRenderAsStarted,
227
+ resolveDomainRenderMode,
228
+ updateCommitFile,
229
+ };
@@ -1,71 +1,43 @@
1
- import type { Robots } from "../types/global";
1
+ import type { Robots } from "../shared/types/global";
2
2
 
3
- import fs from "node:fs";
3
+ import fsp from "node:fs/promises";
4
4
  import path from "node:path";
5
5
 
6
- import { endpoints } from "../constants";
7
- import { get } from "../utils/api";
8
- import { getConfig } from "../utils/core-utils";
9
- import { verboseLog } from "../utils/loggin";
10
-
11
- const config = getConfig();
6
+ import { pathExists } from "../core/fs";
7
+ import { GriddoLog } from "../core/GriddoLog";
8
+ import { ROBOTS } from "../shared/endpoints";
9
+ import { get } from "./api";
10
+ import { getRenderPathsHydratedWithDomainFromDB } from "./render";
11
+
12
+ async function fetchRobots() {
13
+ const apiRobots = await get<Robots>({ endpoint: ROBOTS });
14
+ return (
15
+ apiRobots
16
+ ?.filter((r) => !!r.path)
17
+ .map(({ path, content }) => ({
18
+ path,
19
+ content: content || "User-agent: *\n\r\n\rAllow: /",
20
+ })) || []
21
+ );
22
+ }
12
23
 
13
- /**
14
- * TODO: JSDoc
15
- */
16
- class RobotsService {
17
- robots: Robots;
18
- settings: Record<string, unknown>;
24
+ async function generateRobots(domain: string) {
25
+ const { __root } = await getRenderPathsHydratedWithDomainFromDB({ domain });
26
+ const distDirectory = path.join(__root, "current-dist");
27
+ const robot = (await fetchRobots()).find(({ path }) => path === `/${domain}`);
19
28
 
20
- constructor() {
21
- this.robots = [];
22
- this.settings = {};
29
+ if (!robot) {
30
+ GriddoLog.info(`Robots not found for ${domain}`);
31
+ return;
23
32
  }
24
33
 
25
- /**
26
- * TODO: JSDoc
27
- */
28
- private async getRobots() {
29
- try {
30
- const apiRobots = await get<Robots>({ endpoint: endpoints.ROBOTS });
31
- this.robots =
32
- apiRobots
33
- ?.filter((r) => !!r.path)
34
- .map(({ path, content }) => ({
35
- path,
36
- content: content || "User-agent: *\n\r\n\rAllow: /",
37
- })) || [];
38
- } catch (e) {
39
- console.warn(`${this.constructor.name}: ${(e as Error).message}`);
40
- }
41
- }
42
-
43
- /**
44
- * Write robots.txt files for the domain.
45
- */
46
- async writeFiles(domain: string) {
47
- const { __cx } = config.paths(domain);
48
- const distDirectory = path.join(__cx, "dist");
49
-
50
- await this.getRobots();
51
-
52
- const robot = this.robots.find(({ path }) => path === `/${domain}`);
53
-
54
- if (!robot) {
55
- console.log(`Robots not found for ${domain}`);
56
- return;
57
- }
58
-
59
- if (fs.existsSync(distDirectory)) {
60
- const fileLocation = path.join(distDirectory, "robots.txt");
61
- fs.writeFileSync(fileLocation, robot?.content);
62
- verboseLog(`wrote robots.txt to ${fileLocation}`);
63
- } else {
64
- console.log(`${distDirectory} not found`);
65
- }
34
+ if (await pathExists(distDirectory)) {
35
+ const fileLocation = path.join(distDirectory, "robots.txt");
36
+ await fsp.writeFile(fileLocation, robot?.content);
37
+ GriddoLog.verbose(`wrote robots.txt to ${fileLocation}`);
38
+ } else {
39
+ GriddoLog.info(`${distDirectory} not found`);
66
40
  }
67
41
  }
68
42
 
69
- const robotsService = new RobotsService();
70
-
71
- export { robotsService as RobotsService };
43
+ export { generateRobots };
@@ -0,0 +1,129 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { pathExists } from "../core/fs";
5
+ import { GriddoLog } from "../core/GriddoLog";
6
+ import { generateSitemapIndexXml, generateUrlsetXml } from "../shared/npm-modules/xml-parser";
7
+ import { AuthService } from "./auth";
8
+ import { getBuildMetadata } from "./manage-store";
9
+ import { getRenderPathsHydratedWithDomainFromDB } from "./render";
10
+ import { getSitemap } from "./sites";
11
+
12
+ /**
13
+ * Generate sitemaps and save them into file system.
14
+ */
15
+ async function generateSitemaps(domain: string) {
16
+ const { __root } = await getRenderPathsHydratedWithDomainFromDB();
17
+ const { sitesToPublish } = await getBuildMetadata(domain);
18
+ const distDir = path.join(__root, "current-dist");
19
+ const templateSitemapPrefix = "sitemap-";
20
+
21
+ const isGriddoSitemapFile = (file: string) =>
22
+ file === "sitemap.xml" || (file.startsWith(templateSitemapPrefix) && file.endsWith(".xml"));
23
+
24
+ for (const site of sitesToPublish) {
25
+ const { id, languages } = site;
26
+
27
+ for (const lang of languages) {
28
+ // Local copy of headers to avoid mutating the shared object
29
+ const localHeaders: Record<string, string> = AuthService.headers
30
+ ? { ...AuthService.headers }
31
+ : {};
32
+ localHeaders.lang = lang.id.toString();
33
+
34
+ const response = await getSitemap({ siteId: id, headers: localHeaders });
35
+
36
+ if (!response) {
37
+ continue;
38
+ }
39
+
40
+ const { items: sitemapPagesGroup, url } = response;
41
+ const { home, domain } = url;
42
+
43
+ if (!home) {
44
+ continue;
45
+ }
46
+
47
+ const domainLanguage = site.domains.find(
48
+ (domain) => Object.keys(domain)[0] === lang.id.toString(),
49
+ );
50
+
51
+ if (!domainLanguage) {
52
+ continue;
53
+ }
54
+
55
+ const slug = Object.values(domainLanguage)[0];
56
+ const sitemaps: string[] = [];
57
+ const sitemapPageGroupKeys = Object.keys(sitemapPagesGroup);
58
+ const sitemapBasePath = path.join(distDir, slug.replace(domain, ""));
59
+
60
+ /** delete every griddo sitemap file before create the new ones */
61
+ if (await pathExists(sitemapBasePath)) {
62
+ try {
63
+ const files = await fsp.readdir(sitemapBasePath);
64
+ for (const file of files) {
65
+ if (isGriddoSitemapFile(file)) {
66
+ const filePath = path.join(sitemapBasePath, file);
67
+ try {
68
+ await fsp.rm(filePath);
69
+ } catch (err) {
70
+ GriddoLog.error(`Error deleting file ${filePath}:`, err);
71
+ }
72
+ }
73
+ }
74
+ } catch (err) {
75
+ GriddoLog.error(`Error reading ${sitemapBasePath}:`, err);
76
+ }
77
+ }
78
+
79
+ for (const templateId of sitemapPageGroupKeys) {
80
+ const sitemapPages = sitemapPagesGroup[templateId];
81
+
82
+ if (!sitemapPages.length) {
83
+ continue;
84
+ }
85
+
86
+ const siteMap = generateUrlsetXml(sitemapPages);
87
+
88
+ const sitemapName = `/${templateSitemapPrefix}${templateId.toLowerCase()}.xml`;
89
+ const exactPath = path.join(sitemapBasePath, sitemapName);
90
+
91
+ await saveFile(exactPath, siteMap);
92
+ GriddoLog.verbose(`sitemap generated in ${exactPath}`);
93
+
94
+ sitemaps.push(`${home.endsWith("/") ? home.slice(0, -1) : home}${sitemapName}`);
95
+ }
96
+
97
+ if (!sitemaps.length) {
98
+ continue;
99
+ }
100
+
101
+ const siteMap = generateSitemapIndexXml(sitemaps);
102
+
103
+ const exactPath = path.join(sitemapBasePath, "sitemap.xml");
104
+
105
+ await saveFile(exactPath, siteMap);
106
+ GriddoLog.verbose(`sitemap generated in ${exactPath}`);
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Saves the content to a file specified by its path. If the file exists, it will be overwritten.
113
+ *
114
+ * @param filePath The path of the file to save the content to.
115
+ * @param content The content to save to the file.
116
+ */
117
+ async function saveFile(filePath: string, content: string) {
118
+ try {
119
+ const pathName = path.dirname(filePath);
120
+ if (!(await pathExists(pathName))) {
121
+ await fsp.mkdir(pathName, { recursive: true });
122
+ }
123
+ await fsp.writeFile(filePath, content);
124
+ } catch (_error) {
125
+ throw new Error(`Error saving a file`);
126
+ }
127
+ }
128
+
129
+ export { generateSitemaps };
@@ -1,3 +1,4 @@
1
+ import type { Core } from "@griddo/core";
1
2
  import type {
2
3
  AllSitesReponse,
3
4
  EndPageInfoResponse,
@@ -9,19 +10,28 @@ import type {
9
10
  SitemapAPIResponse,
10
11
  SocialsResponse,
11
12
  StartPageRenderResponse,
12
- } from "../types/api";
13
- import type { Site } from "../types/sites";
14
- import type { Core } from "@griddo/core";
15
-
16
- import { endpoints } from "../constants";
17
- import { get, post } from "../utils/api";
13
+ } from "../shared/types/api";
14
+ import type { Site } from "../shared/types/sites";
15
+
16
+ import {
17
+ BUILD_END,
18
+ BUILD_START,
19
+ GET_ALL,
20
+ GET_PAGE,
21
+ GET_REFERENCE_FIELD_DATA,
22
+ GET_SITEMAP,
23
+ INFO,
24
+ LANGUAGES,
25
+ SOCIALS,
26
+ } from "../shared/endpoints";
27
+ import { get, post } from "./api";
18
28
 
19
29
  /**
20
30
  * Get a list of site objects.
21
31
  */
22
32
  async function getAllSites(domain: string) {
23
- return await get<AllSitesReponse>({
24
- endpoint: `${endpoints.GET_ALL}?domainSlug=${domain}`,
33
+ return get<AllSitesReponse>({
34
+ endpoint: `${GET_ALL}?domainSlug=${domain}`,
25
35
  });
26
36
  }
27
37
 
@@ -29,7 +39,7 @@ async function getAllSites(domain: string) {
29
39
  * Get a list of site objects from a domain.
30
40
  */
31
41
  async function getAllSitesFromDomain(domain: string) {
32
- const allSites = await get<AllSitesReponse>({ endpoint: endpoints.GET_ALL });
42
+ const allSites = await get<AllSitesReponse>({ endpoint: GET_ALL });
33
43
 
34
44
  if (allSites.length) {
35
45
  for (const site of allSites) {
@@ -40,8 +50,7 @@ async function getAllSitesFromDomain(domain: string) {
40
50
  site.domains = items
41
51
  .filter(
42
52
  (item) =>
43
- item.domain &&
44
- (item.domain.slug === domain || item.domain.slug === `/${domain}`),
53
+ item.domain && (item.domain.slug === domain || item.domain.slug === `/${domain}`),
45
54
  )
46
55
  .map((item) => ({ [item.id]: `${item.domain.slug}${item.path}` }));
47
56
  }
@@ -54,8 +63,8 @@ async function getAllSitesFromDomain(domain: string) {
54
63
  * Fetch a page object from API.
55
64
  */
56
65
  async function getPage(id: number, cacheKey: string) {
57
- return await get<PageResponse>({
58
- endpoint: `${endpoints.GET_PAGE}/${id}`,
66
+ return get<PageResponse>({
67
+ endpoint: `${GET_PAGE}/${id}`,
59
68
  cacheKey,
60
69
  });
61
70
  }
@@ -64,27 +73,27 @@ async function getPage(id: number, cacheKey: string) {
64
73
  * Get site info
65
74
  */
66
75
  async function getSiteInfo(id: number, cacheKey = "") {
67
- const [prefix, suffix] = endpoints.INFO;
76
+ const [prefix, suffix] = INFO;
68
77
 
69
- return await get<Site>({
78
+ return get<Site>({
70
79
  endpoint: `${prefix}${id}${suffix}`,
71
80
  cacheKey,
72
81
  });
73
82
  }
74
83
 
75
84
  async function getSiteLanguages(id: number, cacheKey = "") {
76
- const [prefix, suffix] = endpoints.LANGUAGES;
85
+ const [prefix, suffix] = LANGUAGES;
77
86
 
78
- return await get<LanguagesResponse>({
87
+ return get<LanguagesResponse>({
79
88
  endpoint: `${prefix}${id}${suffix}`,
80
89
  cacheKey,
81
90
  });
82
91
  }
83
92
 
84
93
  async function startSiteRender(id: number) {
85
- const [prefix, suffix] = endpoints.BUILD_START;
94
+ const [prefix, suffix] = BUILD_START;
86
95
 
87
- return await get<StartPageRenderResponse>({
96
+ return get<StartPageRenderResponse>({
88
97
  endpoint: `${prefix}${id}${suffix}`,
89
98
  });
90
99
  }
@@ -93,12 +102,13 @@ async function startSiteRender(id: number) {
93
102
  * Send the end signal to API for a render site.
94
103
  */
95
104
  async function endSiteRender(id: number, body: EndSiteRenderBody) {
96
- const [prefix, suffix] = endpoints.BUILD_END;
105
+ const [prefix, suffix] = BUILD_END;
97
106
 
98
- return await post<EndPageInfoResponse>({
107
+ await post<EndPageInfoResponse>({
99
108
  endpoint: `${prefix}${id}${suffix}`,
100
109
  body,
101
110
  useApiCacheDir: false,
111
+ logToFile: false,
102
112
  });
103
113
  }
104
114
 
@@ -109,11 +119,11 @@ async function getReferenceFieldSiteData(
109
119
  dataSiteId?: number,
110
120
  dataLangID?: number,
111
121
  ) {
112
- const [prefix, suffix] = endpoints.GET_REFERENCE_FIELD_DATA;
122
+ const [prefix, suffix] = GET_REFERENCE_FIELD_DATA;
113
123
  const site = dataSiteId || page.site;
114
124
  const lang = dataLangID || page.language;
115
125
 
116
- return await post<ReferenceFieldResponse>({
126
+ return post<ReferenceFieldResponse>({
117
127
  endpoint: `${prefix}${site}${suffix}`,
118
128
  body,
119
129
  headers: { lang },
@@ -121,18 +131,20 @@ async function getReferenceFieldSiteData(
121
131
  });
122
132
  }
123
133
 
124
- async function getSitemap(id: number) {
125
- const [prefix, suffix] = endpoints.GET_SITEMAP;
134
+ async function getSitemap(options: { siteId: number; headers?: Record<string, string> }) {
135
+ const { siteId, headers } = options;
136
+ const [prefix, suffix] = GET_SITEMAP;
126
137
 
127
138
  return get<SitemapAPIResponse>({
128
- endpoint: `${prefix}${id}${suffix}`,
139
+ endpoint: `${prefix}${siteId}${suffix}`,
140
+ headers,
129
141
  });
130
142
  }
131
143
 
132
144
  async function getSiteSocials(id: number, cacheKey = "") {
133
- const [prefix, suffix] = endpoints.SOCIALS;
145
+ const [prefix, suffix] = SOCIALS;
134
146
 
135
- return await get<SocialsResponse>({
147
+ return get<SocialsResponse>({
136
148
  endpoint: `${prefix}${id}${suffix}`,
137
149
  cacheKey,
138
150
  });