@griddo/cx 11.9.7 → 11.9.8-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 (222) hide show
  1. package/README.md +78 -193
  2. package/build/commands/end-render.js +31 -0
  3. package/build/commands/end-render.js.map +7 -0
  4. package/build/commands/prepare-assets-directory.js +9 -0
  5. package/build/commands/prepare-assets-directory.js.map +7 -0
  6. package/build/commands/prepare-domains-render.js +38 -0
  7. package/build/commands/prepare-domains-render.js.map +7 -0
  8. package/build/commands/reset-render.js +31 -0
  9. package/build/commands/reset-render.js.map +7 -0
  10. package/build/commands/start-embeddings.js +31 -0
  11. package/build/commands/start-embeddings.js.map +7 -0
  12. package/build/commands/start-render.js +66 -0
  13. package/build/commands/start-render.js.map +7 -0
  14. package/build/commands/upload-search-content.js +31 -0
  15. package/build/commands/upload-search-content.js.map +7 -0
  16. package/build/core/GriddoLog.d.ts +16 -0
  17. package/build/core/db.d.ts +4 -0
  18. package/build/core/dist-rollback.d.ts +2 -0
  19. package/build/{errors/index.d.ts → core/errors.d.ts} +5 -4
  20. package/build/core/fs.d.ts +69 -0
  21. package/build/core/logger.d.ts +18 -0
  22. package/build/index.d.ts +10 -29
  23. package/build/index.js +406 -73
  24. package/build/services/auth.d.ts +2 -5
  25. package/build/services/manage-store.d.ts +48 -0
  26. package/build/services/render.d.ts +70 -0
  27. package/build/shared/envs.d.ts +19 -0
  28. package/build/{errors/errors-data.d.ts → shared/errors.d.ts} +5 -3
  29. package/build/shared/npm-modules/brush.d.ts +18 -0
  30. package/build/shared/npm-modules/find-up-simple.d.ts +34 -0
  31. package/build/shared/npm-modules/pkg-dir.d.ts +7 -0
  32. package/build/{types → shared/types}/api.d.ts +18 -18
  33. package/build/{types → shared/types}/global.d.ts +15 -16
  34. package/build/{types → shared/types}/navigation.d.ts +5 -5
  35. package/build/{types → shared/types}/pages.d.ts +9 -9
  36. package/build/shared/types/render.d.ts +54 -0
  37. package/build/{types → shared/types}/sites.d.ts +18 -19
  38. package/cli.mjs +239 -0
  39. package/exporter/build-esbuild.noop +42 -0
  40. package/exporter/build.sh +17 -28
  41. package/exporter/commands/README.md +151 -0
  42. package/exporter/commands/end-render.ts +65 -86
  43. package/exporter/commands/prepare-assets-directory.ts +34 -0
  44. package/exporter/commands/prepare-domains-render.ts +143 -35
  45. package/exporter/commands/reset-render.ts +12 -7
  46. package/exporter/commands/single-domain-upload-search-content.noop +206 -0
  47. package/exporter/commands/start-embeddings.ts +29 -0
  48. package/exporter/commands/start-render.ts +26 -64
  49. package/exporter/commands/upload-search-content.ts +201 -26
  50. package/exporter/core/GriddoLog.ts +45 -0
  51. package/exporter/core/check-env-health.ts +200 -0
  52. package/exporter/core/db-class.ts +54 -0
  53. package/exporter/core/db.ts +33 -0
  54. package/exporter/core/dist-rollback.ts +40 -0
  55. package/exporter/core/errors.ts +82 -0
  56. package/exporter/core/fs.ts +385 -0
  57. package/exporter/{utils → core}/images.ts +1 -6
  58. package/exporter/{utils → core}/instance.ts +9 -13
  59. package/exporter/core/life-cycle.ts +73 -0
  60. package/exporter/core/logger.ts +141 -0
  61. package/exporter/core/objects.ts +37 -0
  62. package/exporter/core/print-logos.ts +21 -0
  63. package/exporter/index.ts +14 -56
  64. package/exporter/services/api.ts +306 -0
  65. package/exporter/services/auth.ts +8 -10
  66. package/exporter/services/domains.ts +23 -8
  67. package/exporter/services/manage-sites.ts +116 -0
  68. package/exporter/services/manage-store.ts +235 -0
  69. package/exporter/services/navigation.ts +12 -18
  70. package/exporter/{utils → services}/pages.ts +27 -92
  71. package/exporter/services/reference-fields.ts +14 -32
  72. package/exporter/services/render-artifacts.ts +44 -0
  73. package/exporter/services/render.ts +229 -0
  74. package/exporter/services/robots.ts +33 -61
  75. package/exporter/services/sitemaps.ts +129 -0
  76. package/exporter/services/sites.ts +40 -28
  77. package/exporter/services/store.ts +386 -319
  78. package/exporter/shared/context.ts +49 -0
  79. package/exporter/{constants → shared}/endpoints.ts +12 -11
  80. package/exporter/shared/envs.ts +62 -0
  81. package/exporter/{errors/errors-data.ts → shared/errors.ts} +24 -14
  82. package/exporter/shared/npm-modules/README.md +36 -0
  83. package/exporter/shared/npm-modules/brush.ts +34 -0
  84. package/exporter/shared/npm-modules/find-up-simple.ts +100 -0
  85. package/exporter/shared/npm-modules/pkg-dir.ts +17 -0
  86. package/exporter/shared/npm-modules/xml-parser.ts +57 -0
  87. package/exporter/{types → shared/types}/api.ts +40 -41
  88. package/exporter/{types → shared/types}/global.ts +17 -21
  89. package/exporter/{types → shared/types}/navigation.ts +3 -3
  90. package/exporter/{types → shared/types}/pages.ts +10 -11
  91. package/exporter/shared/types/render.ts +63 -0
  92. package/exporter/{types → shared/types}/sites.ts +18 -19
  93. package/exporter/ssg-adapters/gatsby/actions/clean.ts +26 -0
  94. package/exporter/ssg-adapters/gatsby/actions/close.ts +17 -0
  95. package/exporter/ssg-adapters/gatsby/actions/data.ts +22 -0
  96. package/exporter/ssg-adapters/gatsby/actions/healthCheck.ts +10 -0
  97. package/exporter/ssg-adapters/gatsby/actions/init.ts +12 -0
  98. package/exporter/ssg-adapters/gatsby/actions/logs.ts +10 -0
  99. package/exporter/ssg-adapters/gatsby/actions/meta.ts +13 -0
  100. package/exporter/ssg-adapters/gatsby/actions/prepare.ts +9 -0
  101. package/exporter/ssg-adapters/gatsby/actions/relocation.ts +15 -0
  102. package/exporter/ssg-adapters/gatsby/actions/restore.ts +21 -0
  103. package/exporter/ssg-adapters/gatsby/actions/ssg.ts +12 -0
  104. package/exporter/ssg-adapters/gatsby/actions/sync.ts +65 -0
  105. package/exporter/ssg-adapters/gatsby/index.ts +114 -0
  106. package/exporter/ssg-adapters/gatsby/shared/artifacts.ts +16 -0
  107. package/exporter/ssg-adapters/gatsby/shared/diff-assets.ts +128 -0
  108. package/exporter/ssg-adapters/gatsby/shared/extract-assets.ts +75 -0
  109. package/exporter/ssg-adapters/gatsby/shared/gatsby-build.ts +58 -0
  110. package/exporter/ssg-adapters/gatsby/shared/sync-render.ts +300 -0
  111. package/exporter/ssg-adapters/gatsby/shared/types.ts +35 -0
  112. package/exporter/ssg-adapters/gatsby/shared/utils.ts +33 -0
  113. package/gatsby-browser.tsx +41 -58
  114. package/gatsby-config.ts +10 -17
  115. package/gatsby-node.ts +20 -80
  116. package/gatsby-ssr.tsx +2 -1
  117. package/package.json +41 -92
  118. package/plugins/gatsby-plugin-svgr-loader/gatsby-node.js +55 -0
  119. package/plugins/gatsby-plugin-svgr-loader/package.json +8 -0
  120. package/react/DynamicScript/index.tsx +33 -0
  121. package/{exporter/react/Favicon → react/GriddoFavicon}/index.tsx +3 -9
  122. package/{exporter/react → react}/GriddoIntegrations/index.tsx +17 -23
  123. package/{exporter/react → react}/GriddoIntegrations/utils.ts +24 -12
  124. package/react/GriddoOpenGraph/index.tsx +39 -0
  125. package/src/components/Head.tsx +30 -73
  126. package/src/components/template.tsx +8 -30
  127. package/src/gatsby-node-utils.ts +76 -2
  128. package/src/html.tsx +2 -11
  129. package/src/types.ts +5 -5
  130. package/tsconfig.commands.json +36 -0
  131. package/tsconfig.exporter.json +20 -0
  132. package/tsconfig.json +5 -3
  133. package/build/adapters/gatsby/index.d.ts +0 -4
  134. package/build/adapters/gatsby/utils.d.ts +0 -22
  135. package/build/artifacts/index.d.ts +0 -6
  136. package/build/commands/end-render.d.ts +0 -2
  137. package/build/commands/move-assets.d.ts +0 -1
  138. package/build/commands/prepare-domains-render.d.ts +0 -1
  139. package/build/commands/reset-render.d.ts +0 -2
  140. package/build/commands/start-render.d.ts +0 -2
  141. package/build/commands/upload-search-content.d.ts +0 -2
  142. package/build/constants/envs.d.ts +0 -37
  143. package/build/constants/index.d.ts +0 -57
  144. package/build/end-render.js +0 -74
  145. package/build/end-render.js.map +0 -7
  146. package/build/index.js.map +0 -7
  147. package/build/prepare-domains-render.js +0 -73
  148. package/build/prepare-domains-render.js.map +0 -7
  149. package/build/react/Favicon/index.d.ts +0 -5
  150. package/build/react/Favicon/utils.d.ts +0 -9
  151. package/build/react/GriddoIntegrations/index.d.ts +0 -20
  152. package/build/react/GriddoIntegrations/utils.d.ts +0 -26
  153. package/build/react/index.d.ts +0 -3
  154. package/build/react/index.js +0 -3
  155. package/build/registers/api.d.ts +0 -9
  156. package/build/registers/gatsby.d.ts +0 -9
  157. package/build/registers/index.d.ts +0 -3
  158. package/build/reset-render.js +0 -74
  159. package/build/reset-render.js.map +0 -7
  160. package/build/services/domains.d.ts +0 -6
  161. package/build/services/navigation.d.ts +0 -50
  162. package/build/services/reference-fields.d.ts +0 -20
  163. package/build/services/register.d.ts +0 -36
  164. package/build/services/robots.d.ts +0 -19
  165. package/build/services/settings.d.ts +0 -4
  166. package/build/services/sites.d.ts +0 -29
  167. package/build/services/store.d.ts +0 -6
  168. package/build/start-render.js +0 -100
  169. package/build/start-render.js.map +0 -7
  170. package/build/types/templates.d.ts +0 -8
  171. package/build/upload-search-content.js +0 -74
  172. package/build/upload-search-content.js.map +0 -7
  173. package/build/utils/alerts.d.ts +0 -3
  174. package/build/utils/api.d.ts +0 -23
  175. package/build/utils/cache.d.ts +0 -35
  176. package/build/utils/core-utils.d.ts +0 -107
  177. package/build/utils/create-build-data.d.ts +0 -8
  178. package/build/utils/domains.d.ts +0 -13
  179. package/build/utils/folders.d.ts +0 -53
  180. package/build/utils/health-checks.d.ts +0 -7
  181. package/build/utils/images.d.ts +0 -16
  182. package/build/utils/loggin.d.ts +0 -51
  183. package/build/utils/pages.d.ts +0 -34
  184. package/build/utils/render.d.ts +0 -13
  185. package/build/utils/searches.d.ts +0 -15
  186. package/build/utils/sites.d.ts +0 -31
  187. package/build/utils/store.d.ts +0 -81
  188. package/cx.config.d.ts +0 -5
  189. package/cx.config.js +0 -36
  190. package/exporter/adapters/gatsby/index.ts +0 -162
  191. package/exporter/adapters/gatsby/utils.ts +0 -161
  192. package/exporter/artifacts/README.md +0 -34
  193. package/exporter/artifacts/index.ts +0 -33
  194. package/exporter/commands/move-assets.ts +0 -11
  195. package/exporter/constants/envs.ts +0 -94
  196. package/exporter/constants/index.ts +0 -129
  197. package/exporter/errors/index.ts +0 -40
  198. package/exporter/react/index.tsx +0 -11
  199. package/exporter/registers/api.ts +0 -14
  200. package/exporter/registers/gatsby.ts +0 -14
  201. package/exporter/registers/index.ts +0 -4
  202. package/exporter/services/register.ts +0 -113
  203. package/exporter/services/settings.ts +0 -17
  204. package/exporter/utils/alerts.ts +0 -29
  205. package/exporter/utils/api.ts +0 -243
  206. package/exporter/utils/cache.ts +0 -142
  207. package/exporter/utils/core-utils.ts +0 -458
  208. package/exporter/utils/create-build-data.ts +0 -17
  209. package/exporter/utils/domains.ts +0 -39
  210. package/exporter/utils/folders.ts +0 -320
  211. package/exporter/utils/health-checks.ts +0 -64
  212. package/exporter/utils/loggin.ts +0 -184
  213. package/exporter/utils/render.ts +0 -71
  214. package/exporter/utils/searches.ts +0 -156
  215. package/exporter/utils/sites.ts +0 -312
  216. package/exporter/utils/store.ts +0 -314
  217. package/src/README.md +0 -7
  218. package/start-render.js +0 -7
  219. /package/build/{utils → core}/instance.d.ts +0 -0
  220. /package/build/{constants → shared}/endpoints.d.ts +0 -0
  221. /package/exporter/{types → shared/types}/templates.ts +0 -0
  222. /package/{exporter/react/Favicon → react/GriddoFavicon}/utils.ts +0 -0
@@ -0,0 +1,21 @@
1
+ import fsp from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { brush } from "../shared/npm-modules/brush";
5
+ import { GriddoLog } from "./GriddoLog";
6
+
7
+ /**
8
+ * Console log the Griddo exporter version.
9
+ */
10
+ async function showExporterVersion() {
11
+ // console.clear();
12
+ const { version } = JSON.parse(
13
+ await fsp.readFile(path.resolve(__dirname, "../..", "package.json"), "utf-8"),
14
+ ) as { version: string };
15
+ const logo = `\n${brush.yellow(`Griddo Exporter ${version}`)}
16
+ ${brush.dim(`Node ${process.version.slice(1)}`)}\n`;
17
+
18
+ GriddoLog.log(logo);
19
+ }
20
+
21
+ export { showExporterVersion };
package/exporter/index.ts CHANGED
@@ -1,22 +1,4 @@
1
- /**
2
- *
3
- * Griddo CX library main export file.
4
- *
5
- * This file exports functions to use in both: adapters and SSG's frameworks.
6
- * Turning CX basically in a javascript library.
7
- *
8
- * # React
9
- * There is another export in the `/react` directory to use exclusivelly in
10
- * the browser context where nodejs (path, fs, etc..) is not available.
11
- *
12
- * # Separate scripts.
13
- * There are some separate .ts files as end-render.ts or reset-render.ts
14
- * that are intended to be used by infra via npm script like `npm run
15
- * end-render`
16
- *
17
- */
18
-
19
- import type { SocialsResponse } from "./types/api";
1
+ import type { SocialsResponse } from "./shared/types/api";
20
2
  import type {
21
3
  AdditionalInfo,
22
4
  Dimensions,
@@ -24,53 +6,29 @@ import type {
24
6
  GriddoMultiPage,
25
7
  GriddoPageObject,
26
8
  GriddoSinglePage,
27
- } from "./types/pages";
28
- import type { Site } from "./types/sites";
9
+ } from "./shared/types/pages";
10
+ import type { Site } from "./shared/types/sites";
29
11
 
30
- import { endpoints, envs } from "./constants";
31
- import { apiRegister } from "./registers/index";
32
- import { FileRegister, MemoryRegister, Register } from "./services/register";
33
- import { insertAlert } from "./utils/alerts";
34
- import { getConfig, walk } from "./utils/core-utils";
12
+ import { throwError } from "./core/errors";
13
+ import { walkStore } from "./core/fs";
35
14
  import {
36
15
  componentLibraryPathAlias,
37
16
  isComponentLibrary,
38
17
  resolveComponentsPath,
39
- } from "./utils/instance";
40
- import {
41
- buildLog,
42
- debugLog,
43
- infoLog,
44
- pageSizeLog,
45
- verboseLog,
46
- } from "./utils/loggin";
47
- import {
48
- getBuildPagesFromCachedStore,
49
- getBuildPagesFromStore,
50
- getBuildPagesPath,
51
- } from "./utils/store";
18
+ } from "./core/instance";
19
+ import { addLogToBuffer } from "./core/logger";
20
+ import { getRenderPathsHydratedWithDomainFromDB } from "./services/render";
21
+ import { ReadFromStoreError } from "./shared/errors";
52
22
 
53
23
  export {
54
- apiRegister,
55
- buildLog,
24
+ addLogToBuffer,
56
25
  componentLibraryPathAlias,
57
- debugLog,
58
- endpoints,
59
- envs,
60
- FileRegister,
61
- getBuildPagesFromCachedStore,
62
- getBuildPagesFromStore,
63
- getBuildPagesPath,
64
- getConfig,
65
- infoLog,
66
- insertAlert,
26
+ getRenderPathsHydratedWithDomainFromDB,
67
27
  isComponentLibrary,
68
- MemoryRegister,
69
- pageSizeLog,
70
- Register,
28
+ ReadFromStoreError,
71
29
  resolveComponentsPath,
72
- verboseLog,
73
- walk,
30
+ throwError,
31
+ walkStore,
74
32
  type AdditionalInfo,
75
33
  type Dimensions,
76
34
  type GriddoListPage,
@@ -0,0 +1,306 @@
1
+ import type {
2
+ APIRequest,
3
+ APIResponses,
4
+ GetAPI,
5
+ PostAPI,
6
+ PutAPI,
7
+ ShowApiErrorOptions,
8
+ } from "../shared/types/api";
9
+ import type { Petition } from "../shared/types/global";
10
+
11
+ import crypto from "node:crypto";
12
+ import fsp from "node:fs/promises";
13
+ import path from "node:path";
14
+
15
+ import { RenderError } from "../core/errors";
16
+ import { pathExists } from "../core/fs";
17
+ import { GriddoLog } from "../core/GriddoLog";
18
+ import { addLogToBuffer } from "../core/logger";
19
+ import { brush } from "../shared/npm-modules/brush";
20
+ import { AuthService } from "./auth";
21
+ import { getRenderPathsHydratedWithDomainFromDB } from "./render";
22
+
23
+ // Envs
24
+ const { env } = process;
25
+ const { RETRY_WAIT_SECONDS = "4", RETRY_ATTEMPTS = "4" } = env;
26
+
27
+ /**
28
+ * Make a GET/PUT/POST request to the Griddo API.
29
+ *
30
+ * @template T Response Type returned.
31
+ * @returns {Promise<T>} A promise that is resolved with the data from the API response.
32
+ *
33
+ * @example
34
+ * const response = await requestAPI<Site>(
35
+ * { endpoint: "...", cacheKey: "...", ... },
36
+ * "get",
37
+ * "..."
38
+ * );
39
+ */
40
+ async function requestAPI<T extends APIResponses>(
41
+ props: APIRequest,
42
+ method: string,
43
+ appendToLog = "",
44
+ ): Promise<T> {
45
+ const {
46
+ endpoint,
47
+ body,
48
+ cacheKey = "",
49
+ attempt = 1,
50
+ headers,
51
+ useApiCacheDir = true,
52
+ logToFile = true,
53
+ } = props;
54
+ const cacheOptions = { endpoint, body, headers, cacheKey };
55
+
56
+ // Cache
57
+ if (cacheKey && useApiCacheDir) {
58
+ const start = new Date();
59
+ const cacheData = await searchCacheData<T>(cacheOptions);
60
+
61
+ if (cacheData) {
62
+ if (logToFile) {
63
+ const siteId = getSafeSiteId(cacheData);
64
+ const siteIdMsg = siteId ? `site: ${siteId}` : "";
65
+ const duration = msToSec(Date.now() - start.getTime());
66
+ addLogToBuffer(`${method} (cache) ${siteIdMsg} ${endpoint} - ${duration}s ${appendToLog}`);
67
+ }
68
+ return cacheData;
69
+ }
70
+ }
71
+
72
+ // Network
73
+ try {
74
+ const start = new Date();
75
+
76
+ // Prepare fetch options
77
+ const fetchOptions: RequestInit = {
78
+ method: method.toUpperCase(),
79
+ headers: Object.assign({}, headers, AuthService.headers) as Record<string, string>,
80
+ };
81
+
82
+ // Add body for non-GET requests
83
+ if (method.toLowerCase() !== "get" && body) {
84
+ fetchOptions.body = JSON.stringify(body);
85
+ if (!fetchOptions.headers) fetchOptions.headers = {};
86
+ (fetchOptions.headers as Record<string, string>)["Content-Type"] = "application/json";
87
+ }
88
+
89
+ const response = await fetch(endpoint, fetchOptions);
90
+
91
+ // Handle non-2xx responses
92
+ if (!response.ok) {
93
+ if (response.status === 404) {
94
+ // @ts-expect-error page maybe will be 404
95
+ return null;
96
+ }
97
+
98
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
99
+ }
100
+
101
+ const data: T = await response.json();
102
+
103
+ if (logToFile) {
104
+ const siteId = getSafeSiteId(data);
105
+ const siteIdMsg = siteId ? `site: ${siteId}` : "";
106
+ const duration = msToSec(Date.now() - start.getTime());
107
+ addLogToBuffer(`${method} (fetch) ${siteIdMsg} ${endpoint} - ${duration}s ${appendToLog}`);
108
+ }
109
+
110
+ if (useApiCacheDir) {
111
+ await saveCache(cacheOptions, data);
112
+ }
113
+
114
+ return data;
115
+ } catch (e) {
116
+ const error = e as Error;
117
+
118
+ if (attempt > parseInt(RETRY_ATTEMPTS)) {
119
+ GriddoLog.log(`
120
+ Max attempts ${RETRY_ATTEMPTS} reached
121
+ --------------------------------------
122
+ - ${method.toUpperCase()} ${endpoint}
123
+ - BODY: ${JSON.stringify(body)}
124
+ - HEADERS: ${JSON.stringify(headers)}
125
+ - ERROR: ${error.message}
126
+ --------------------------------------
127
+ `);
128
+ throw new RenderError(error);
129
+ }
130
+
131
+ showApiError(error, {
132
+ callInfo: { endpoint, body },
133
+ });
134
+
135
+ GriddoLog.warn(`Waiting for retry: ${method}`, endpoint);
136
+
137
+ await delay(parseInt(RETRY_WAIT_SECONDS) * 1000);
138
+
139
+ return requestAPI<T>(
140
+ {
141
+ endpoint,
142
+ body,
143
+ headers,
144
+ cacheKey,
145
+ attempt: attempt + 1,
146
+ },
147
+ method,
148
+ appendToLog,
149
+ );
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Make a GET request to the Griddo API.
155
+ *
156
+ * @template T Response Type returned.
157
+ * @returns A promise that is resolved with the data from the API response.
158
+ */
159
+ async function getApi<T extends APIResponses>(props: GetAPI) {
160
+ return requestAPI<T>(props, "get");
161
+ }
162
+
163
+ /**
164
+ * Make a PUT request to the Griddo API.
165
+ *
166
+ * @template T Response Type returned.
167
+ * @returns A promise that is resolved with the data from the API response.
168
+ */
169
+ async function putApi<T extends APIResponses>(props: PutAPI) {
170
+ return requestAPI<T>(props, "put");
171
+ }
172
+
173
+ /**
174
+ * Make a POST request to the Griddo API.
175
+ *
176
+ * @template T Response Type returned.
177
+ * @returns A promise that is resolved with the data from the API response.
178
+ */
179
+ async function postApi<T extends APIResponses>(props: PostAPI) {
180
+ const { endpoint, body, headers } = props;
181
+ const referenceFieldBodyParams =
182
+ endpoint.endsWith("/distributor") &&
183
+ `# ReferenceField body: ${JSON.stringify(body)} lang: ${JSON.stringify(headers?.lang)}`;
184
+
185
+ return requestAPI<T>(props, "post", referenceFieldBodyParams || "");
186
+ }
187
+
188
+ /**
189
+ * Shows an API error through the terminal.
190
+ */
191
+ function showApiError(error: Error, options: ShowApiErrorOptions) {
192
+ const { message, stack } = error;
193
+ const { callInfo } = options;
194
+ const callInfoArray = [];
195
+
196
+ for (const item of Object.keys(callInfo) as (keyof typeof callInfo)[]) {
197
+ callInfoArray.push(
198
+ `${item}: ${
199
+ typeof callInfo[item] === "object" ? JSON.stringify(callInfo[item]) : callInfo[item]
200
+ }`,
201
+ );
202
+ }
203
+
204
+ // Compose the errors output
205
+ const callInfoStr = callInfoArray.join("\n");
206
+ const errorDetailsStr = `${message}\n${stack}`;
207
+
208
+ // Print the error
209
+ GriddoLog.warn(
210
+ brush.red(`
211
+ =============
212
+
213
+ { Call info }
214
+ ${callInfoStr}
215
+
216
+ { Error details }
217
+ ${errorDetailsStr}
218
+
219
+ =============
220
+ `),
221
+ );
222
+ }
223
+
224
+ /**
225
+ * Return a siteID from a response object if exist
226
+ * @param response A response object
227
+ */
228
+ function getSafeSiteId(response: APIResponses) {
229
+ if (typeof response !== "object" || response === null || Array.isArray(response)) {
230
+ return undefined;
231
+ }
232
+
233
+ return "site" in response && response.site ? response.site : undefined;
234
+ }
235
+
236
+ /**
237
+ * Custom delay using the "promise hack",
238
+ *
239
+ * @param ms Amount of miliseconds to be delayed
240
+ */
241
+ function delay(ms: number): Promise<void> {
242
+ return new Promise((res) => setTimeout(res, ms));
243
+ }
244
+
245
+ /**
246
+ * Converts milliseconds to seconds with a fixed number of decimals.
247
+ *
248
+ * @param ms The number in milliseconds.
249
+ * @param fixed The amount of fixed decimals.
250
+ * @returns The converted number in seconds with the fixed number of decimals.
251
+ */
252
+ function msToSec(ms: number, decimals = 3): number {
253
+ return Number.parseFloat((ms / 1000).toFixed(decimals));
254
+ }
255
+
256
+ /**
257
+ * Generate a filename with a hash using a Petition object
258
+ * @param petition An object
259
+ */
260
+ async function generateFilenameWithHash(petition: Petition) {
261
+ const { __root } = await getRenderPathsHydratedWithDomainFromDB();
262
+ const apiCacheDir = path.join(__root, "apiCache");
263
+
264
+ const hashSum = crypto.createHash("sha256");
265
+ hashSum.update(JSON.stringify(petition));
266
+
267
+ return `${apiCacheDir}/${hashSum.digest("hex")}`;
268
+ }
269
+
270
+ /**
271
+ * Save a file using a hash name.
272
+ *
273
+ * @param petition An object.
274
+ * @param content Content to be saved.
275
+ */
276
+ async function saveCache<T>(petition: Petition, content: T) {
277
+ const stringContent = typeof content === "string" ? content : JSON.stringify(content);
278
+ const filename = await generateFilenameWithHash(petition);
279
+ const filepath = path.dirname(filename);
280
+
281
+ if (!(await pathExists(filepath))) {
282
+ await fsp.mkdir(filepath, { recursive: true });
283
+ }
284
+
285
+ await fsp.writeFile(filename, stringContent, "utf8");
286
+ }
287
+
288
+ /**
289
+ * Search in the `apiCache` dir for a file using the petition as hash generator.
290
+ * Return the file content if found or null if not.
291
+ *
292
+ * @param petition An object
293
+ */
294
+ async function searchCacheData<T>(petition: Petition) {
295
+ try {
296
+ const file = await generateFilenameWithHash(petition);
297
+ const fileContent = await fsp.readFile(file, "utf8");
298
+ const jsonData = JSON.parse(fileContent) as T;
299
+
300
+ return jsonData;
301
+ } catch {
302
+ return null;
303
+ }
304
+ }
305
+
306
+ export { getApi as get, postApi as post, putApi as put };
@@ -1,23 +1,21 @@
1
- import type { AuthHeaders } from "../types/api";
1
+ import type { AuthHeaders } from "../shared/types/api";
2
2
 
3
- import { endpoints, envs } from "../constants";
4
- import { throwError } from "../errors";
5
- import { LoginError } from "../errors/errors-data";
3
+ import { throwError } from "../core/errors";
4
+ import { LOGIN } from "../shared/endpoints";
5
+ import { GRIDDO_BOT_PASSWORD, GRIDDO_BOT_USER } from "../shared/envs";
6
+ import { LoginError } from "../shared/errors";
6
7
 
7
- /**
8
- * Service for authentication in the Griddo Private API
9
- */
10
8
  class AuthService {
11
9
  headers: AuthHeaders | undefined;
12
10
 
13
11
  async login() {
14
12
  try {
15
- const response = await fetch(endpoints.LOGIN, {
13
+ const response = await fetch(LOGIN, {
16
14
  method: "POST",
17
15
  headers: { "Content-Type": "application/json", Connection: "close" },
18
16
  body: JSON.stringify({
19
- username: envs.GRIDDO_BOT_USER,
20
- password: envs.GRIDDO_BOT_PASSWORD,
17
+ username: GRIDDO_BOT_USER,
18
+ password: GRIDDO_BOT_PASSWORD,
21
19
  }),
22
20
  });
23
21
 
@@ -1,16 +1,31 @@
1
- import type { Domains } from "../types/global";
1
+ import type { Domains } from "../shared/types/global";
2
2
 
3
- import { endpoints } from "../constants";
4
- import { get } from "../utils/api";
3
+ import { throwError } from "../core/errors";
4
+ import { GriddoLog } from "../core/GriddoLog";
5
+ import { DOMAINS } from "../shared/endpoints";
6
+ import { NoDomainsFoundError } from "../shared/errors";
7
+ import { get } from "./api";
5
8
 
6
9
  /**
7
- * Get an array of available domain.
10
+ * Return an array of domains name (string) of the current instance.
8
11
  */
9
- async function getAllDomains() {
10
- return get<Domains>({
11
- endpoint: endpoints.DOMAINS,
12
+ async function getInstanceDomains() {
13
+ const domains = await get<Domains>({
14
+ endpoint: DOMAINS,
12
15
  useApiCacheDir: false,
13
16
  });
17
+
18
+ if (!domains.length) {
19
+ throwError(NoDomainsFoundError);
20
+ }
21
+
22
+ GriddoLog.verbose(`getting domains names (${domains.length})`);
23
+
24
+ const filteredDomains = domains
25
+ .filter(({ slug }) => !!slug)
26
+ .map(({ slug }) => slug.replace("/", ""));
27
+
28
+ return [...new Set(filteredDomains)];
14
29
  }
15
30
 
16
- export { getAllDomains };
31
+ export { getInstanceDomains };
@@ -0,0 +1,116 @@
1
+ import type { Site, SiteData } from "../shared/types/sites";
2
+
3
+ import fsp from "node:fs/promises";
4
+ import path from "node:path";
5
+
6
+ import { getRenderPathsHydratedWithDomainFromDB } from "./render";
7
+ import {
8
+ endSiteRender,
9
+ getAllSites,
10
+ getSiteInfo,
11
+ getSiteLanguages,
12
+ getSiteSocials,
13
+ startSiteRender,
14
+ } from "./sites";
15
+
16
+ /**
17
+ * Check the instance sites and returns site prepared to be published and unpublished.
18
+ */
19
+ async function getSitesToRender(domain: string) {
20
+ // Get all sites. An array of Site
21
+ const allSites = await getAllSites(domain);
22
+
23
+ // If there are valid sites...
24
+ // En este paso se añade al objeto `Site` la información de los dominios
25
+ // utilizando los idiomas.
26
+ if (allSites.length) {
27
+ for (const site of allSites) {
28
+ const { items } = await getSiteLanguages(site.id);
29
+
30
+ // Añadimos la prop site.domains con el dominio "cocinado" con
31
+ // los idiomas y teniendo en cuenta solo el dominio actual.
32
+ site.domains = items
33
+ .filter(
34
+ (item) =>
35
+ item.domain && (item.domain.slug === domain || item.domain.slug === `/${domain}`),
36
+ )
37
+ .map((item) => ({ [item.id]: `${item.domain.slug}${item.path}` }));
38
+ }
39
+ }
40
+
41
+ // Save sites object to publish
42
+ const sitesToPublish = allSites.filter((site) => !!site.isPublished);
43
+
44
+ // Save sites object to unpublish
45
+ const sitesToUnpublish = allSites.filter((site) => !site.isPublished && site.shouldBeUpdated);
46
+
47
+ return {
48
+ sitesToPublish,
49
+ sitesToUnpublish,
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Unpublish an array of sites sending the information to the API.
55
+ *
56
+ * @param sites An array of sites
57
+ */
58
+ async function unpublishSites(sites: Site[]) {
59
+ const { __root } = await getRenderPathsHydratedWithDomainFromDB();
60
+
61
+ for (const site of sites) {
62
+ // API
63
+ const buildInfo = await startSiteRender(site.id);
64
+ const { siteHash } = buildInfo;
65
+ const body = {
66
+ siteHash,
67
+ publishHashes: [],
68
+ unpublishHashes: [],
69
+ publishPagesIds: [],
70
+ };
71
+
72
+ await endSiteRender(site.id, body);
73
+
74
+ // STORE
75
+ // Remove site directory from the Store to prevent rendering
76
+ await fsp.rm(path.join(__root, "store", site.id.toString()), {
77
+ force: true,
78
+ recursive: true,
79
+ });
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Return a single site generic data.
85
+ *
86
+ * @param siteID The site id.
87
+ * @see SiteData
88
+ */
89
+ async function getSiteData(siteID: number) {
90
+ const buildData = await startSiteRender(siteID);
91
+ const siteInfo = await getSiteInfo(siteID);
92
+ const siteLangs = await getSiteLanguages(siteID);
93
+ const socials = await getSiteSocials(siteID);
94
+ const siteLangsInfo = siteLangs.items;
95
+ const defaultLang = siteLangsInfo.find((lang) => lang.isDefault);
96
+
97
+ const { siteHash, unpublishHashes, publishIds } = buildData;
98
+ const { headers, footers } = siteInfo;
99
+ const validPagesIds = publishIds;
100
+
101
+ const siteData: SiteData = {
102
+ siteInfo,
103
+ validPagesIds,
104
+ siteHash,
105
+ unpublishHashes,
106
+ siteLangs: siteLangsInfo,
107
+ defaultLang,
108
+ headers,
109
+ footers,
110
+ socials,
111
+ };
112
+
113
+ return siteData;
114
+ }
115
+
116
+ export { getSiteData, getSitesToRender, unpublishSites };