@metricinsights/pp-dev 0.9.0 → 0.10.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 (47) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/README.md +146 -229
  3. package/dist/cjs/cli.js +1 -1200
  4. package/dist/cjs/cli.js.map +1 -1
  5. package/dist/cjs/helpers.js +1 -28
  6. package/dist/cjs/helpers.js.map +1 -1
  7. package/dist/cjs/index-7kvqDDBw.js +2 -0
  8. package/dist/cjs/index-7kvqDDBw.js.map +1 -0
  9. package/dist/cjs/index.js +1 -26
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/package.json +10 -7
  12. package/dist/cjs/plugin-CoHlzIq-.js +2 -0
  13. package/dist/cjs/plugin-CoHlzIq-.js.map +1 -0
  14. package/dist/cjs/plugin.js +1 -25
  15. package/dist/cjs/plugin.js.map +1 -1
  16. package/dist/client/client.css +233 -38
  17. package/dist/client/client.css.map +1 -0
  18. package/dist/client/client.js +110 -14
  19. package/dist/client/client.js.map +1 -1
  20. package/dist/client/index.html +39 -26
  21. package/dist/esm/cli.js +1 -1173
  22. package/dist/esm/cli.js.map +1 -1
  23. package/dist/esm/helpers.js +1 -24
  24. package/dist/esm/helpers.js.map +1 -1
  25. package/dist/esm/index-C2GV98GH.js +2 -0
  26. package/dist/esm/index-C2GV98GH.js.map +1 -0
  27. package/dist/esm/index.js +1 -19
  28. package/dist/esm/index.js.map +1 -1
  29. package/dist/esm/package.json +10 -7
  30. package/dist/esm/plugin-B909lge8.js +2 -0
  31. package/dist/esm/plugin-B909lge8.js.map +1 -0
  32. package/dist/esm/plugin.js +1 -16
  33. package/dist/esm/plugin.js.map +1 -1
  34. package/dist/types/index.d.ts +102 -2
  35. package/package.json +10 -7
  36. package/dist/cjs/index-BE4YF5iw.js +0 -331
  37. package/dist/cjs/index-BE4YF5iw.js.map +0 -1
  38. package/dist/cjs/plugin-DZS4Taov.js +0 -1315
  39. package/dist/cjs/plugin-DZS4Taov.js.map +0 -1
  40. package/dist/client/index.d.ts +0 -2
  41. package/dist/esm/index-7YgmP5z7.js +0 -308
  42. package/dist/esm/index-7YgmP5z7.js.map +0 -1
  43. package/dist/esm/plugin-BeHiwpzF.js +0 -1277
  44. package/dist/esm/plugin-BeHiwpzF.js.map +0 -1
  45. package/dist/types/cli.d.ts +0 -3
  46. package/dist/types/helpers.d.ts +0 -24
  47. package/dist/types/plugin.d.ts +0 -86
@@ -1,1315 +0,0 @@
1
- 'use strict';
2
-
3
- var httpProxyMiddleware = require('http-proxy-middleware');
4
- var url = require('url');
5
- var vite = require('vite');
6
- var picocolors = require('picocolors');
7
- var axios = require('axios');
8
- var jsdom = require('jsdom');
9
- var https = require('https');
10
- var memoryCache = require('memory-cache');
11
- var path = require('path');
12
- var fs = require('fs');
13
- var crypto = require('crypto');
14
- var process$1 = require('process');
15
- var child_process = require('child_process');
16
- var console = require('console');
17
- var zlib = require('zlib');
18
-
19
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
20
- function _interopNamespaceDefault(e) {
21
- var n = Object.create(null);
22
- if (e) {
23
- Object.keys(e).forEach(function (k) {
24
- if (k !== 'default') {
25
- var d = Object.getOwnPropertyDescriptor(e, k);
26
- Object.defineProperty(n, k, d.get ? d : {
27
- enumerable: true,
28
- get: function () { return e[k]; }
29
- });
30
- }
31
- });
32
- }
33
- n.default = e;
34
- return Object.freeze(n);
35
- }
36
-
37
- var memoryCache__namespace = /*#__PURE__*/_interopNamespaceDefault(memoryCache);
38
- var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
39
- var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
40
- var process__namespace = /*#__PURE__*/_interopNamespaceDefault(process$1);
41
- var child_process__namespace = /*#__PURE__*/_interopNamespaceDefault(child_process);
42
- var console__namespace = /*#__PURE__*/_interopNamespaceDefault(console);
43
-
44
- const urlReplacer = (originalHost, destinationHost, content) => {
45
- const urlReplaceRegExp = new RegExp(`(!!)?(https?(:(\\\\)?/(\\\\)?/)${originalHost})`, 'gi');
46
- return content.replace(urlReplaceRegExp, (substring, ...args) => {
47
- if (substring.startsWith('!!')) {
48
- return args[1];
49
- }
50
- return `http${args[2]}${destinationHost}`;
51
- });
52
- };
53
- const urlPathReplacer = (urlPath, destinationPath, content) => {
54
- const urlReplaceRegExp = new RegExp(`${urlPath.replace(/\\*\//gi, '\\\\/')}`, 'gi');
55
- return content.replace(urlReplaceRegExp, destinationPath);
56
- };
57
- const redirect = (res, url, statusCode) => {
58
- res.setHeader('location', url);
59
- res.statusCode = statusCode;
60
- res.end();
61
- };
62
- function cutUrlParams(url) {
63
- const urlParts = url.split('?');
64
- return urlParts[0];
65
- }
66
-
67
- // import pino from 'pino';
68
- // import { PrettyOptions } from 'pino-pretty';
69
- const storage = new Map();
70
- const DEFAULT_LOGGER_KEY = 'default';
71
- const createLogger = (level = 'info', name = DEFAULT_LOGGER_KEY) => {
72
- if (storage.has(name)) {
73
- return storage.get(name);
74
- }
75
- if (name === DEFAULT_LOGGER_KEY) {
76
- const logger = vite.createLogger(level);
77
- storage.set(name, logger);
78
- return logger;
79
- }
80
- const logger = vite.createLogger(level);
81
- storage.set(name, logger);
82
- return logger;
83
- };
84
-
85
- const colors = picocolors.createColors();
86
-
87
- const hostOriginRegExp = /^(https?:\/\/)([^/]+)(\/.*)?$/i;
88
- const PROXY_HEADER = 'X-PP-Proxy';
89
- // TODO: Implement interceptor for streaming responses
90
- function streamResponseInterceptor(interceptor) {
91
- return async (proxyRes, req, res) => {
92
- res.setHeader(PROXY_HEADER, 1);
93
- res.setHeaders(new Map(Object.entries(proxyRes.headers)));
94
- proxyRes.pipe(res);
95
- };
96
- }
97
- function initProxy(opts) {
98
- const { rewritePath = /^\/(?!pt).*/i, baseURL = '', devServer, disableSSLValidation = false } = opts;
99
- if (!baseURL) {
100
- throw new Error('Base url is required');
101
- }
102
- const host = baseURL.replace(hostOriginRegExp, '$2');
103
- const origin = baseURL.replace(hostOriginRegExp, '$1$2');
104
- const fileType = import('file-type');
105
- const logger = createLogger();
106
- return httpProxyMiddleware.createProxyMiddleware({
107
- /**
108
- * IMPORTANT: avoid res.end being called automatically
109
- **/
110
- selfHandleResponse: true, // res.end() will be called internally by responseInterceptor()
111
- pathFilter: (pathname, req) => {
112
- if ((opts.proxyIgnore || []).some((value) => {
113
- if (typeof value === 'string') {
114
- return pathname.startsWith(value);
115
- }
116
- else if (typeof value.test === 'function') {
117
- return value.test(pathname);
118
- }
119
- return true;
120
- })) {
121
- // Ignored paths
122
- return false;
123
- }
124
- if (typeof rewritePath === 'string') {
125
- return pathname.startsWith(rewritePath);
126
- }
127
- else if (Array.isArray(rewritePath)) {
128
- return rewritePath.some((rP) => pathname.startsWith(rP));
129
- }
130
- else if (typeof rewritePath.test === 'function') {
131
- return rewritePath.test(pathname);
132
- }
133
- return false;
134
- },
135
- target: baseURL,
136
- changeOrigin: true,
137
- autoRewrite: true,
138
- cookieDomainRewrite: {
139
- [host]: 'localhost',
140
- },
141
- logger: {
142
- info: () => {
143
- //
144
- },
145
- log: () => {
146
- //
147
- },
148
- error: () => {
149
- //
150
- },
151
- warn: () => {
152
- //
153
- },
154
- },
155
- secure: !disableSSLValidation,
156
- headers: {
157
- host,
158
- origin,
159
- },
160
- on: {
161
- proxyReq(proxyReq, req, res) {
162
- const host = req.headers.host;
163
- const referer = proxyReq.getHeader('referer');
164
- logger.info(`${colors.blue('Proxies request:')} ${colors.green(req.method)} ${req.url} -> ${colors.green(proxyReq.method)} ${proxyReq.protocol}//${proxyReq.host}${proxyReq.path}`);
165
- if (host && referer && typeof referer === 'string') {
166
- proxyReq.setHeader('referer', referer.replace(new RegExp(`https?://${host}`), baseURL));
167
- }
168
- req.socket.on('close', () => {
169
- setTimeout(() => {
170
- if (!proxyReq.destroyed) {
171
- proxyReq.destroy();
172
- }
173
- }, 200);
174
- });
175
- return proxyReq;
176
- },
177
- proxyRes: (serverRes, req, res) => {
178
- if (serverRes.headers['content-type']?.includes('text/event-stream') ||
179
- (serverRes.headers['transfer-encoding']?.includes('chunked') &&
180
- serverRes.headers['x-accel-buffering'] === 'no')) {
181
- logger.info(`${colors.blue('Start streaming for request:')} ${colors.green(req.method)} ${req.url}`);
182
- const streamInterceptor = streamResponseInterceptor();
183
- return streamInterceptor(serverRes, req, res);
184
- }
185
- const rewriteInterceptor = httpProxyMiddleware.responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
186
- res.setHeader(PROXY_HEADER, 1);
187
- const type = await (await fileType).fileTypeFromBuffer(responseBuffer);
188
- if (type) {
189
- return responseBuffer;
190
- }
191
- else {
192
- let response = responseBuffer.toString('utf8'); // convert buffer to string
193
- try {
194
- const reqUrl = new URL(req.url ?? '', `http://${host}`);
195
- if (reqUrl.searchParams && reqUrl.searchParams.has('proxyRedirect')) {
196
- const redirectToFunction = function () {
197
- let url = window.location.href;
198
- const func = function () {
199
- const params = new URLSearchParams(window.location.search);
200
- if (!params.has('proxyRedirect')) {
201
- return;
202
- }
203
- if (url !== window.location.href) {
204
- url = window.location.href;
205
- setTimeout(func, 2000);
206
- }
207
- else {
208
- window.location.href = params.get('proxyRedirect');
209
- }
210
- };
211
- setTimeout(func, 2000);
212
- };
213
- response += '<script>' + `(${redirectToFunction.toString()})()` + '</script>';
214
- }
215
- }
216
- catch {
217
- //
218
- }
219
- const reqHost = req.headers.host ?? '';
220
- // manipulate response and return the result
221
- return urlPathReplacer('/auth/saml/login', '/login', urlReplacer(host, reqHost, response));
222
- }
223
- });
224
- return rewriteInterceptor(serverRes, req, res);
225
- },
226
- error(err, req, res) {
227
- const errorMessage = `Proxy error: "${err.message}" when trying to "${req.method} ${req.url}"\n\n${err.stack}`;
228
- logger.error(errorMessage);
229
- if (res.writable) {
230
- res.writeHead(500, {
231
- 'Content-Type': 'text/plain',
232
- });
233
- }
234
- res.end(errorMessage);
235
- },
236
- },
237
- });
238
- }
239
-
240
- class BaseAPI {
241
- axios;
242
- constructor(axios) {
243
- this.axios = axios;
244
- }
245
- async checkAuth(headers) {
246
- return this.axios
247
- .get('/data/page/index/auth/info', {
248
- headers: Object.assign({}, headers, { accept: 'text/html' }),
249
- maxRedirects: 0,
250
- })
251
- .then(() => true)
252
- .catch(() => false);
253
- }
254
- }
255
-
256
- class AssetsAPI extends BaseAPI {
257
- // Import for CJS and ESM
258
- formdataModulePromise = import('formdata-node');
259
- constructor(axios) {
260
- super(axios);
261
- }
262
- getDownloadUrl(portalPageId) {
263
- return `/admin/page/downloadassets/id/${portalPageId}`;
264
- }
265
- getDownloadTemplateUrl(templateId) {
266
- return `/admin/pagetemplate/downloadassets/id/${templateId}`;
267
- }
268
- getUploadUrl(portalPageId) {
269
- return `/admin/page/uploadassets/id/${portalPageId}`;
270
- }
271
- getUploadTemplateUrl(templateId) {
272
- return `/admin/pagetemplate/uploadassets/id/${templateId}`;
273
- }
274
- async downloadPageAssets(portalPageId, headers) {
275
- return this.axios
276
- .get(this.getDownloadUrl(portalPageId), {
277
- withCredentials: true,
278
- headers: Object.assign({}, headers, { accept: '*/*' }),
279
- responseType: 'arraybuffer',
280
- })
281
- .then((res) => res.data);
282
- }
283
- /**
284
- * Upload page assets.
285
- * @param portalPageId
286
- * @param file - Zip file with assets
287
- * @param headers
288
- */
289
- async uploadPageAssets(portalPageId, file, headers) {
290
- const formData = new (await this.formdataModulePromise).FormData();
291
- const assetFile = new File([file.buffer], 'file.zip', { type: 'application/zip' });
292
- formData.append('file', assetFile);
293
- const url = this.getUploadUrl(portalPageId);
294
- return this.axios
295
- .post(url, formData, {
296
- withCredentials: true,
297
- headers: Object.assign({}, headers, {
298
- accept: 'application/json',
299
- 'Content-Type': 'multipart/form-data',
300
- Referer: this.axios.getUri({ url }),
301
- }),
302
- })
303
- .then((res) => res.data);
304
- }
305
- async downloadTemplateAssets(templateId, headers) {
306
- return this.axios
307
- .get(this.getDownloadTemplateUrl(templateId), {
308
- withCredentials: true,
309
- headers: Object.assign({}, headers, { accept: '*/*' }),
310
- responseType: 'arraybuffer',
311
- })
312
- .then((res) => res.data);
313
- }
314
- /**
315
- * Upload template assets.
316
- * @param templateId
317
- * @param file - Zip file with assets
318
- * @param headers
319
- */
320
- async uploadTemplateAssets(templateId, file, headers) {
321
- const formData = new (await this.formdataModulePromise).FormData();
322
- const assetFile = new (await this.formdataModulePromise).File([file.buffer], 'file.zip', {
323
- type: 'application/zip',
324
- });
325
- formData.append('file', assetFile, 'file.zip');
326
- const url = this.getUploadTemplateUrl(templateId);
327
- return this.axios
328
- .post(url, formData, {
329
- withCredentials: true,
330
- headers: Object.assign({}, headers, {
331
- accept: 'application/json',
332
- 'Content-Type': 'multipart/form-data',
333
- Referer: this.axios.getUri({ url }),
334
- }),
335
- })
336
- .then((res) => res.data);
337
- }
338
- }
339
- class AssetsV7API extends AssetsAPI {
340
- getDownloadUrl(portalPageId) {
341
- return `/api/page/id/${portalPageId}/asset/download`;
342
- }
343
- getDownloadTemplateUrl(templateId) {
344
- return `/api/page_template/id/${templateId}/asset/download`;
345
- }
346
- getUploadUrl(portalPageId) {
347
- return `/api/page/id/${portalPageId}/asset/upload`;
348
- }
349
- getUploadTemplateUrl(templateId) {
350
- return `/api/page_template/id/${templateId}/asset/upload`;
351
- }
352
- }
353
-
354
- class PageAPI extends BaseAPI {
355
- async getAll(headers) {
356
- return (await this.axios.get('/api/page', {
357
- withCredentials: true,
358
- headers: Object.assign({}, headers, {
359
- Accept: 'application/json',
360
- 'Content-Type': 'application/json',
361
- 'Cache-Control': 'no-cache',
362
- Pragma: 'no-cache',
363
- Expires: '0',
364
- }),
365
- })).data.pages;
366
- }
367
- async get(id, headers) {
368
- return (await this.axios.get(`/api/page/id/${id}`, {
369
- withCredentials: true,
370
- headers: Object.assign({}, headers, {
371
- accept: 'application/json',
372
- 'content-type': 'application/json',
373
- }),
374
- })).data.page;
375
- }
376
- async getPageContent(internalPageName, headers) {
377
- return (await this.axios.get(`/p/${internalPageName}`, {
378
- withCredentials: true,
379
- headers: Object.assign({}, headers, {
380
- accept: 'text/html',
381
- 'content-type': 'application/json',
382
- }),
383
- })).data;
384
- }
385
- async create(page, headers) {
386
- return (await this.axios.post('/api/page', page, {
387
- withCredentials: true,
388
- headers: Object.assign({}, headers, {
389
- accept: 'application/json',
390
- 'content-type': 'application/json',
391
- }),
392
- })).data.page;
393
- }
394
- }
395
-
396
- class PageTemplateAPI extends BaseAPI {
397
- async getAll(internal_name, headers) {
398
- return (await this.axios.get(`/api/page_template`, {
399
- withCredentials: true,
400
- headers: Object.assign({}, headers, {
401
- Accept: 'application/json',
402
- 'Content-Type': 'application/json',
403
- 'Cache-Control': 'no-cache',
404
- Pragma: 'no-cache',
405
- Expires: '0',
406
- }),
407
- params: {
408
- internal_name,
409
- },
410
- })).data.page_templates;
411
- }
412
- async get(id, headers) {
413
- return (await this.axios.get(`/api/page_template/id/${id}`, {
414
- withCredentials: true,
415
- headers: Object.assign({}, headers, {
416
- accept: 'application/json',
417
- 'content-type': 'application/json',
418
- }),
419
- })).data.page_template;
420
- }
421
- }
422
-
423
- const TEMPLATE_PAGE_NAME = '[DEV PAGE. DO NOT DELETE]';
424
- class MiAPI {
425
- #headers;
426
- #axios;
427
- #pageTemplate = null;
428
- #pageTitle;
429
- #pageVars;
430
- #v7Features;
431
- #isV710OrHigher;
432
- #templateLoaded;
433
- #templateLoadedResolve;
434
- portalPageId;
435
- templateLess;
436
- assetsApi;
437
- pageApi;
438
- pageTemplateApi;
439
- logger;
440
- constructor(baseURL, opts) {
441
- const { headers = {}, portalPageId, templateLess = true, disableSSLValidation = false, v7Features = false, } = opts || {};
442
- this.#headers = headers;
443
- this.#pageVars = [];
444
- this.#pageTitle = '';
445
- this.#v7Features = v7Features;
446
- this.#isV710OrHigher = false;
447
- this.#templateLoaded = Promise.resolve(false);
448
- if (disableSSLValidation) {
449
- axios.defaults.httpsAgent = new https.Agent({ rejectUnauthorized: false });
450
- }
451
- this.#axios = axios.create({
452
- baseURL,
453
- headers,
454
- });
455
- this.portalPageId = portalPageId;
456
- this.templateLess = templateLess;
457
- this.assetsApi = new (!v7Features ? AssetsAPI : AssetsV7API)(this.#axios);
458
- this.pageApi = new PageAPI(this.#axios);
459
- this.pageTemplateApi = new PageTemplateAPI(this.#axios);
460
- this.logger = createLogger();
461
- }
462
- async isTemplateLoaded() {
463
- return this.#templateLoaded;
464
- }
465
- get isV710OrHigher() {
466
- return this.#isV710OrHigher;
467
- }
468
- #clearHeaders(headers) {
469
- const obj = Object.assign({}, headers, { host: undefined, referer: undefined });
470
- Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]);
471
- this.#headers = obj;
472
- return obj;
473
- }
474
- updateHeaders(headers) {
475
- this.#clearHeaders(headers);
476
- }
477
- get localTemplateHTML() {
478
- return /* HTML */ `<!DOCTYPE html>
479
- <html lang="en">
480
- <head>
481
- <meta charset="UTF-8" />
482
- <title>Local template</title>
483
- <meta charset="UTF-8" />
484
- <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
485
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
486
- </head>
487
- <body>
488
- <div id="mi-react-root"></div>
489
- <script src="/auth/info.js"></script>
490
- <script src="/js/main.js" defer></script>
491
- <link rel="stylesheet" href="/css/main.css" />
492
- </body>
493
- </html>`;
494
- }
495
- /**
496
- * Get page template
497
- * @param headers
498
- */
499
- async getPageTemplate(headers) {
500
- if (!(await this.#templateLoaded) && !this.#pageTemplate) {
501
- this.#templateLoaded = new Promise((resolve) => {
502
- this.#templateLoadedResolve = resolve;
503
- });
504
- }
505
- if (this.#pageTemplate) {
506
- return Promise.resolve(this.#pageTemplate);
507
- }
508
- if (typeof this.templateLess === 'undefined') {
509
- this.templateLess = false;
510
- }
511
- if (this.#v7Features) {
512
- const page = await this.pageApi
513
- .get(this.portalPageId, this.#clearHeaders(headers))
514
- .then((response) => {
515
- this.logger.info(colors.green('Page fetched'));
516
- return response;
517
- })
518
- .catch(async (e) => {
519
- this.#templateLoadedResolve(false);
520
- if (await this.pageApi.checkAuth(this.#clearHeaders(headers))) {
521
- this.logger.error(colors.red(`Error fetching page data: ${e.message}\n${e.stack}`));
522
- throw new Error('Current user does not have access to the page');
523
- }
524
- else {
525
- throw e;
526
- }
527
- });
528
- if (typeof page.template_id !== 'undefined') {
529
- this.#isV710OrHigher = true;
530
- }
531
- this.#pageTemplate = this.localTemplateHTML;
532
- this.logger.info(colors.green('Local page template fetched'));
533
- this.#templateLoadedResolve(true);
534
- return this.#pageTemplate;
535
- }
536
- const pageList = await this.pageApi
537
- .getAll(this.#clearHeaders(headers))
538
- .then((response) => {
539
- this.logger.info(colors.green('Page list fetched'));
540
- return response;
541
- })
542
- .catch(async (e) => {
543
- this.#templateLoadedResolve(false);
544
- if (await this.pageApi.checkAuth(this.#clearHeaders(headers))) {
545
- this.logger.error(colors.red(`Error fetching page list: ${e.message}\n${e.stack}`));
546
- throw new Error('Current user does not have access to page list');
547
- }
548
- else {
549
- throw e;
550
- }
551
- });
552
- let page = pageList.find((p) => p.name === TEMPLATE_PAGE_NAME);
553
- if (!page) {
554
- this.logger.warn(colors.yellow('Creating dev page template...'));
555
- page = await this.pageApi
556
- .create({
557
- enabled: 'Y',
558
- name: TEMPLATE_PAGE_NAME,
559
- internal_name: 'dev-page-template',
560
- visible_in_homepage: 'Y',
561
- }, this.#clearHeaders(headers))
562
- .then((response) => {
563
- this.logger.info(colors.green('Dev page created'));
564
- return response;
565
- })
566
- .catch((e) => {
567
- this.logger.error(colors.red(`Error creating dev page: ${e.message}`));
568
- this.#templateLoadedResolve(false);
569
- throw new Error(`Error when creating dev page.
570
- That can be caused by missing permissions or page with name "${TEMPLATE_PAGE_NAME}" already exists`);
571
- });
572
- }
573
- return await this.pageApi
574
- .getPageContent(page.internal_name, this.#clearHeaders(headers))
575
- .then((response) => {
576
- this.#pageTemplate = response;
577
- return response;
578
- })
579
- .then((response) => {
580
- this.#templateLoadedResolve(true);
581
- this.logger.info(colors.green('Page template fetched'));
582
- return response;
583
- })
584
- .catch((e) => {
585
- this.#templateLoadedResolve(false);
586
- this.logger.error(colors.red(`Error fetching page template: ${e.message}`));
587
- throw new Error('Error fetching page template');
588
- });
589
- }
590
- /**
591
- * Get page template variables
592
- *
593
- * @param pageId
594
- * @param headers
595
- */
596
- async getPageVariables(pageId, headers) {
597
- this.#pageTemplate = await this.getPageTemplate(headers);
598
- if (!this.portalPageId) {
599
- this.portalPageId = pageId;
600
- this.templateLess = false;
601
- }
602
- return await this.pageApi
603
- .get(pageId, this.#clearHeaders(headers))
604
- .then((response) => {
605
- const { tags = '[]', name, template } = response;
606
- if (template && tags) {
607
- const parsed = JSON.parse(tags);
608
- this.#pageVars = parsed;
609
- this.#pageTitle = name;
610
- return parsed;
611
- }
612
- this.#pageVars = [];
613
- this.#pageTitle = name;
614
- return [];
615
- })
616
- .catch((reason) => {
617
- this.logger.error(colors.red(`Error fetching page variables: ${reason.message}`));
618
- if (reason.response?.status === 404) {
619
- throw new Error(`Portal Page with id "${pageId}" not found on instance ${this.#axios.getUri()}`);
620
- }
621
- if (reason.response?.status === 401) {
622
- throw new Error(`Current user does not have access to page with id "${pageId}" on instance ${this.#axios.getUri()}`);
623
- }
624
- throw reason;
625
- });
626
- }
627
- /**
628
- * Build page with variables
629
- *
630
- * @param content
631
- * @param miHudLess
632
- */
633
- buildPage(content, miHudLess = false) {
634
- let result = typeof content === 'string' ? content : content.toString('utf-8');
635
- for (const v of this.#pageVars) {
636
- result = result.replace(new RegExp(`\\[${v.name}\\]`, 'g'), v.value);
637
- }
638
- const dom = new jsdom.JSDOM(miHudLess ? result : this.#pageTemplate);
639
- const placeholderText = '%%PLACEHOLDER%%';
640
- if (!miHudLess) {
641
- const placeholder = dom.window.document.createElement('div');
642
- placeholder.innerHTML = placeholderText;
643
- const container = dom.window.document.querySelector('.main-side');
644
- if (container) {
645
- const scripts = container.querySelectorAll('script');
646
- if (scripts.length) {
647
- container.insertBefore(placeholder, scripts.item(scripts.length - 1));
648
- }
649
- else {
650
- container.append(placeholder);
651
- }
652
- }
653
- else {
654
- const container = dom.window.document.createElement('div');
655
- container.append(placeholder);
656
- dom.window.document.body.append(container);
657
- }
658
- const head = dom.window.document.querySelector('head');
659
- const title = head.querySelector('title');
660
- if (title) {
661
- title.text = this.#pageTitle;
662
- }
663
- else {
664
- head.innerHTML += `<title>${this.#pageTitle}</title>`;
665
- }
666
- }
667
- const serializedDom = dom.serialize();
668
- return serializedDom.replace(new RegExp(`<div>\\s*${placeholderText}\\s*<\\/div>`, 'i'), result);
669
- }
670
- async getAssets() {
671
- if (this.portalPageId) {
672
- if (this.templateLess) {
673
- return await this.assetsApi.downloadPageAssets(this.portalPageId, this.#headers);
674
- }
675
- else {
676
- const pageInfo = await this.pageApi.get(this.portalPageId, this.#headers);
677
- if (this.#isV710OrHigher) {
678
- const templateInfo = await this.pageTemplateApi.get(pageInfo.template_id, this.#headers);
679
- return await this.assetsApi.downloadTemplateAssets(templateInfo.id, this.#headers);
680
- }
681
- else {
682
- if (pageInfo.template) {
683
- return await this.assetsApi.downloadTemplateAssets(pageInfo.template, this.#headers);
684
- }
685
- }
686
- }
687
- }
688
- }
689
- async updateAssets(assets) {
690
- if (this.portalPageId) {
691
- if (this.templateLess) {
692
- return await this.assetsApi.uploadPageAssets(this.portalPageId, assets, this.#headers);
693
- }
694
- else {
695
- const pageInfo = await this.pageApi.get(this.portalPageId, this.#headers);
696
- if (this.#isV710OrHigher) {
697
- const templateInfo = await this.pageTemplateApi.get(pageInfo.template_id, this.#headers);
698
- return await this.assetsApi.uploadTemplateAssets(templateInfo.id, assets, this.#headers);
699
- }
700
- else {
701
- if (pageInfo.template) {
702
- return await this.assetsApi.uploadTemplateAssets(pageInfo.template, assets, this.#headers);
703
- }
704
- }
705
- }
706
- }
707
- }
708
- }
709
-
710
- class ClientService {
711
- server;
712
- opts;
713
- eventMap;
714
- logger;
715
- constructor(server, opts) {
716
- this.server = server;
717
- this.opts = opts || {};
718
- this.eventMap = new Map();
719
- this.eventMap.set('info-data:request', this.onInfoDataRequest.bind(this));
720
- this.eventMap.set('template:sync', this.onTemplateSync.bind(this));
721
- this.logger = createLogger();
722
- this.init();
723
- }
724
- init() {
725
- const { ws } = this.server;
726
- for (const [event, handler] of this.eventMap) {
727
- ws.on(event, handler);
728
- }
729
- }
730
- onInfoDataRequest() {
731
- this.server.ws.send({
732
- type: 'custom',
733
- event: 'info-data:response',
734
- data: {},
735
- });
736
- }
737
- async onTemplateSync() {
738
- if (this.opts.distService && this.opts.miAPI) {
739
- const { distService, miAPI } = this.opts;
740
- if (this.server.config.clientInjectionPlugin?.v7Features) {
741
- if (!miAPI?.isV710OrHigher) {
742
- this.server.ws.send('template:sync:response', {
743
- error: 'This feature is available only for MI v7.1.0 or higher',
744
- config: {
745
- canSync: false,
746
- },
747
- });
748
- return;
749
- }
750
- else {
751
- this.server.ws.send('client:config:update', {
752
- config: {
753
- canSync: true,
754
- },
755
- });
756
- }
757
- }
758
- const currentAssets = await miAPI?.getAssets();
759
- const newAssets = currentAssets
760
- ? await distService?.saveBackupAndBuild(currentAssets)
761
- : await distService?.buildNewAssets();
762
- if (newAssets) {
763
- const updateResult = await miAPI?.updateAssets(newAssets);
764
- if (updateResult?.status === 'OK') {
765
- const backupMeta = distService?.getBackupMeta();
766
- const { lastBackupName: backupFilename, lastBackupHash: currentHash, lastBackupDate: backupDate, } = backupMeta || { lastBackupName: '', lastBackupHash: '', lastBackupDate: new Date().toISOString() };
767
- this.server.ws.send('template:sync:response', {
768
- syncedAt: new Date(backupDate),
769
- currentHash,
770
- backupFilename,
771
- });
772
- this.logger.info(colors.green('Template synced'));
773
- }
774
- else {
775
- this.server.ws.send('template:sync:response', { error: 'Failed to update assets' });
776
- this.logger.error(colors.red('Failed to update assets'));
777
- }
778
- }
779
- else {
780
- this.server.ws.send('template:sync:response', { error: 'Failed to build new assets' });
781
- this.logger.error(colors.red('Failed to build new assets'));
782
- return;
783
- }
784
- }
785
- else {
786
- this.server.ws.send('template:sync:response', { error: 'Dist service or MiAPI is not defined' });
787
- this.logger.error(colors.red('Dist service or MiAPI is not defined'));
788
- return;
789
- }
790
- }
791
- }
792
-
793
- const cache = new memoryCache__namespace.Cache();
794
- const testCacheUrlRegExp = /\.[a-z0-9]+$/i;
795
- function initProxyCache(opts) {
796
- const { devServer, ttl = 10 * 60 * 1000 } = opts;
797
- const logger = createLogger();
798
- devServer.cache = cache;
799
- return (req, res, next) => {
800
- const url = req.originalUrl || req.url || '';
801
- if (testCacheUrlRegExp.test(url.split('?')[0] || '')) {
802
- const cacheItem = cache.get(url);
803
- if (cacheItem) {
804
- logger.info(`${colors.blue('Proxies request:')} ${colors.green(req.method)} ${url} -> ${colors.blue('Cache')} ${url}`);
805
- for (const [header, value] of Object.entries(cacheItem.headers)) {
806
- res.setHeader(header, value);
807
- }
808
- res.write(cacheItem.content);
809
- res.end();
810
- return;
811
- }
812
- const end = res.end;
813
- const write = res.write;
814
- let buffer = Buffer.from('', 'utf8');
815
- // Rewrite response method and get the content.
816
- res.write = function (data, encoding, callback) {
817
- if (!res.hasHeader(PROXY_HEADER)) {
818
- return write.call(this, data, encoding, callback);
819
- }
820
- buffer = Buffer.concat([buffer, data]);
821
- return true;
822
- };
823
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
824
- // @ts-ignore
825
- res.end = function (chunk, encoding, cb) {
826
- if (!res.hasHeader(PROXY_HEADER)) {
827
- return end.call(this, chunk, encoding, cb);
828
- }
829
- if (typeof chunk === 'string') {
830
- buffer = Buffer.concat([buffer, Buffer.from(chunk, encoding)]);
831
- }
832
- if (Buffer.isBuffer(chunk)) {
833
- buffer = Buffer.concat([buffer, chunk]);
834
- }
835
- if (res.hasHeader(PROXY_HEADER)) {
836
- logger.info(`${colors.blue('[Cached]')} ${url}`);
837
- cache.put(url, { headers: res.getHeaders(), content: buffer }, ttl);
838
- }
839
- end.call(this, buffer, encoding, cb);
840
- };
841
- }
842
- next();
843
- };
844
- }
845
-
846
- const TEMPLATE_PART_PAGE_NAME = 'pageName';
847
- const TEMPLATE_PART_DATE = 'date';
848
- const DIRNAME = path__namespace.dirname((typeof __filename !== 'undefined' && __filename) || url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('plugin-DZS4Taov.js', document.baseURI).href))));
849
- const pluginPath = path__namespace.resolve(DIRNAME, '..', '..');
850
- const node_modules_path = path__namespace.resolve(pluginPath, '..', '..');
851
- const metaDirName = '.pp-dev-meta';
852
- const metaDirPath = path__namespace.resolve(node_modules_path, metaDirName);
853
- const metaFilePath = path__namespace.resolve(metaDirPath, 'sync-service.meta.json');
854
- class DistService {
855
- backupFolder;
856
- backupNameTemplate;
857
- dateFormat;
858
- pageName;
859
- currentMeta = null;
860
- distZipFolder;
861
- distZipFilename;
862
- logger;
863
- constructor(pageName, syncOptions) {
864
- this.pageName = pageName;
865
- const { backupFolder = path__namespace.resolve(process__namespace.cwd(), 'backups'), distZipFolder = path__namespace.resolve(process__namespace.cwd(), 'dist-zip'), distZipFilename = `${this.pageName}.zip`, backupNameTemplate = `{${TEMPLATE_PART_PAGE_NAME}}-{${TEMPLATE_PART_DATE}}.zip`, dateFormat = (date) => date.toISOString().replace(/:/g, '-').replace(/\..*$/, ''), } = syncOptions || {};
866
- this.backupFolder = backupFolder;
867
- this.backupNameTemplate = backupNameTemplate;
868
- this.dateFormat = dateFormat;
869
- this.distZipFolder = distZipFolder;
870
- this.distZipFilename = distZipFilename;
871
- this.syncMeta();
872
- this.logger = createLogger();
873
- }
874
- async checkMeta() {
875
- try {
876
- await fs.promises.stat(metaDirPath);
877
- }
878
- catch {
879
- await fs.promises.mkdir(metaDirPath);
880
- }
881
- try {
882
- await fs.promises.stat(this.backupFolder);
883
- }
884
- catch {
885
- await fs.promises.mkdir(this.backupFolder);
886
- }
887
- }
888
- async readMetaFile() {
889
- await this.checkMeta();
890
- return await fs.promises
891
- .readFile(metaFilePath, {
892
- encoding: 'utf-8',
893
- })
894
- .catch(() => '{}');
895
- }
896
- async writeMetaFile(meta) {
897
- await this.checkMeta();
898
- return await fs.promises.writeFile(metaFilePath, JSON.stringify(meta, null, 2), {
899
- encoding: 'utf-8',
900
- });
901
- }
902
- async syncMeta() {
903
- if (!this.currentMeta) {
904
- this.currentMeta = JSON.parse(await this.readMetaFile());
905
- }
906
- else {
907
- await this.writeMetaFile(this.currentMeta);
908
- }
909
- }
910
- async getLatestSavedBackup() {
911
- const { lastBackupName } = this.currentMeta;
912
- if (!lastBackupName) {
913
- return null;
914
- }
915
- const backupPath = path__namespace.resolve(this.backupFolder, lastBackupName);
916
- try {
917
- await fs.promises.stat(backupPath);
918
- return backupPath;
919
- }
920
- catch {
921
- return null;
922
- }
923
- }
924
- backupName(pageName, date = new Date()) {
925
- return this.backupNameTemplate
926
- .replace(`{${TEMPLATE_PART_PAGE_NAME}}`, pageName)
927
- .replace(`{${TEMPLATE_PART_DATE}}`, this.dateFormat(date));
928
- }
929
- getBackupMeta() {
930
- return this.currentMeta;
931
- }
932
- async saveBackup(backupFile) {
933
- const backupFileHash = crypto__namespace.createHash('md5').update(backupFile).digest('hex');
934
- const lastSavedBackup = await this.getLatestSavedBackup();
935
- if (lastSavedBackup) {
936
- const { lastBackupHash } = this.currentMeta;
937
- if (lastBackupHash === backupFileHash) {
938
- return;
939
- }
940
- }
941
- const backupDate = new Date();
942
- const filename = this.backupName(this.pageName, backupDate);
943
- this.currentMeta.lastBackupName = filename;
944
- this.currentMeta.lastBackupHash = backupFileHash;
945
- this.currentMeta.lastBackupDate = backupDate.toISOString();
946
- await this.syncMeta();
947
- return await fs.promises.writeFile(path__namespace.resolve(this.backupFolder, filename), backupFile).finally(() => {
948
- this.logger.info(`Backup saved to ${filename}`);
949
- });
950
- }
951
- async buildNewAssets() {
952
- const buildCommand = new Promise((resolve, reject) => {
953
- let data = '';
954
- // Colorized log output with message about build start
955
- this.logger.info(colors.cyan('[DistService] Build started'));
956
- const proc = child_process__namespace.spawn('node', [path__namespace.resolve(pluginPath, './bin/pp-dev.js'), 'build'], {
957
- cwd: process__namespace.cwd(),
958
- env: Object.assign({}, process__namespace.env, { NODE_ENV: 'production' }),
959
- stdio: 'inherit',
960
- });
961
- proc.on('message', (msg) => {
962
- data += msg;
963
- });
964
- proc.on('close', (code) => {
965
- if (code !== 0) {
966
- reject(new Error(`build command exited with code ${code}`));
967
- return;
968
- }
969
- resolve(data);
970
- });
971
- proc.on('error', (err) => {
972
- reject(err);
973
- });
974
- });
975
- try {
976
- await buildCommand.finally(() => {
977
- // Colorized log output with message about build end
978
- this.logger.info(colors.cyan('[DistService] Build finished'));
979
- });
980
- const assetFile = path__namespace.resolve(process__namespace.cwd(), this.distZipFolder, this.distZipFilename);
981
- if (!(await fs.promises.stat(assetFile))) {
982
- throw new Error(`File ${assetFile} not found`);
983
- }
984
- return await fs.promises.readFile(assetFile);
985
- }
986
- catch (e) {
987
- console__namespace.log(e);
988
- throw e;
989
- }
990
- }
991
- async saveBackupAndBuild(backupFile) {
992
- await this.saveBackup(backupFile);
993
- return await this.buildNewAssets();
994
- }
995
- }
996
-
997
- function decodeContent(content, contentEncoding) {
998
- switch (contentEncoding) {
999
- case 'gzip':
1000
- return zlib.unzipSync(content);
1001
- case 'br':
1002
- return zlib.brotliDecompressSync(content);
1003
- case 'deflate':
1004
- return zlib.deflateSync(content);
1005
- default:
1006
- return content;
1007
- }
1008
- }
1009
- function encodeContent(content, contentEncoding) {
1010
- switch (contentEncoding) {
1011
- case 'gzip':
1012
- return zlib.gzipSync(content);
1013
- case 'br':
1014
- return zlib.brotliCompressSync(content);
1015
- case 'deflate':
1016
- return zlib.inflateSync(content);
1017
- default:
1018
- return content;
1019
- }
1020
- }
1021
-
1022
- /**
1023
- * Rewrite response middleware
1024
- *
1025
- * @param predicate Check if need to rewrite response data
1026
- * @param rewrite Rewrite response content handler
1027
- */
1028
- function initRewriteResponse(predicate, rewrite) {
1029
- return async (req, res, next) => {
1030
- if (await predicate(req.url ?? '', req, res)) {
1031
- const logger = createLogger();
1032
- logger.info(`Rewrite response for ${req.url}`);
1033
- const end = res.end;
1034
- const buffers = [];
1035
- res.write = function (body) {
1036
- buffers.push(body);
1037
- return true;
1038
- };
1039
- res.end = function (chunk, encoding, cb) {
1040
- if (typeof chunk === 'string') {
1041
- buffers.push(Buffer.from(chunk));
1042
- }
1043
- const contentEncoding = res.getHeader('content-encoding');
1044
- const content = decodeContent(Buffer.from(Buffer.concat(buffers)), contentEncoding);
1045
- const bufferEncoding = typeof encoding !== 'function' && encoding ? encoding : 'utf-8';
1046
- const endCallback = typeof encoding === 'function' ? encoding : cb;
1047
- end.call(this, encodeContent(rewrite(content, req, res), contentEncoding), bufferEncoding, endCallback);
1048
- return this;
1049
- };
1050
- }
1051
- next();
1052
- };
1053
- }
1054
-
1055
- function initPPRedirect(base, templateName) {
1056
- base = base.startsWith('/') ? base : `/${base}`;
1057
- base = base.endsWith('/') ? base : `${base}/`;
1058
- const baseWithoutTrailingSlash = base.endsWith('/') ? base.slice(0, -1) : base;
1059
- const logger = createLogger();
1060
- return (req, res, next) => {
1061
- const parsedUrl = new url.URL(req.url ?? '', 'http://localhost');
1062
- const { pathname, search } = parsedUrl;
1063
- const findPaths = ['/', baseWithoutTrailingSlash];
1064
- if (templateName) {
1065
- findPaths.push(`/pt/${templateName}`);
1066
- findPaths.push(`/pl/${templateName}`);
1067
- }
1068
- // Redirect from `/` and `/pt/${templateName}` and `${base}` (without a training slash) to portal page address
1069
- if (findPaths.includes(pathname)) {
1070
- const redirectUrl = `${base}${search}`;
1071
- logger.info(colors.yellow(`Redirecting to: ${redirectUrl}`));
1072
- return redirect(res, redirectUrl, 302);
1073
- }
1074
- next();
1075
- };
1076
- }
1077
-
1078
- function initLoadPPData(applyUrlRegExp, mi, opts) {
1079
- const { templateLess = false, miHudLess = false, portalPageId } = opts;
1080
- const logger = createLogger();
1081
- return (req, res, next) => {
1082
- const isNeedTemplateLoad = !(templateLess && miHudLess);
1083
- const isApplyRequest = applyUrlRegExp.test(cutUrlParams(req.url ?? ''));
1084
- if (isNeedTemplateLoad && isApplyRequest) {
1085
- const headers = (req.headers ?? {});
1086
- logger.info(colors.green(`Start loading page data`));
1087
- const loadPageData = !templateLess && typeof portalPageId !== 'undefined'
1088
- ? mi.getPageVariables(portalPageId, headers)
1089
- : mi.getPageTemplate(headers);
1090
- loadPageData
1091
- .then(() => {
1092
- next();
1093
- })
1094
- .catch((reason) => {
1095
- if (reason.response) {
1096
- logger.info(colors.red('Page data loading failed. Not authorized'));
1097
- const redirectUrl = `/home?proxyRedirect=${encodeURIComponent('/')}`;
1098
- logger.info(colors.yellow(`Redirecting to: ${redirectUrl}`));
1099
- return redirect(res, redirectUrl, 302);
1100
- }
1101
- logger.info(colors.red(`Page data loading failed. Error: ${reason.message}`));
1102
- next(reason);
1103
- });
1104
- }
1105
- else {
1106
- next();
1107
- }
1108
- };
1109
- }
1110
-
1111
- function isVitePPDevOptions(options) {
1112
- return (typeof options === 'object' &&
1113
- typeof options.templateName === 'string' &&
1114
- (typeof options.backendBaseURL === 'string' || options.backendBaseURL === undefined) &&
1115
- (typeof options.portalPageId === 'number' || options.portalPageId === undefined) &&
1116
- (typeof options.templateLess === 'boolean' || options.templateLess === undefined) &&
1117
- (typeof options.miHudLess === 'boolean' || options.miHudLess === undefined) &&
1118
- (typeof options.enableProxyCache === 'boolean' || options.enableProxyCache === undefined) &&
1119
- (typeof options.proxyCacheTTL === 'number' || options.proxyCacheTTL === undefined) &&
1120
- (typeof options.disableSSLValidation === 'boolean' || options.disableSSLValidation === undefined) &&
1121
- (typeof options.imageOptimizer === 'boolean' ||
1122
- typeof options.imageOptimizer === 'object' ||
1123
- options.imageOptimizer === undefined) &&
1124
- (typeof options.outDir === 'string' || options.outDir === undefined) &&
1125
- (typeof options.distZip === 'boolean' || typeof options.distZip === 'object' || options.distZip === undefined) &&
1126
- (typeof options.syncBackupsDir === 'string' || options.syncBackupsDir === undefined) &&
1127
- (typeof options.v7Features === 'boolean' || options.v7Features === undefined));
1128
- }
1129
- function throwConfigError(config) {
1130
- if (typeof config !== 'object') {
1131
- throw new Error('VitePPDevOptions must be an object');
1132
- }
1133
- if (typeof config.templateName !== 'string') {
1134
- throw new Error('VitePPDevOptions.templateName must be a string');
1135
- }
1136
- if (config.backendBaseURL !== undefined && typeof config.backendBaseURL !== 'string') {
1137
- throw new Error('VitePPDevOptions.backendBaseURL must be a string');
1138
- }
1139
- if (config.portalPageId !== undefined && typeof config.portalPageId !== 'number') {
1140
- throw new Error('VitePPDevOptions.portalPageId must be a number');
1141
- }
1142
- if (config.templateLess !== undefined && typeof config.templateLess !== 'boolean') {
1143
- throw new Error('VitePPDevOptions.templateLess must be a boolean');
1144
- }
1145
- if (config.miHudLess !== undefined && typeof config.miHudLess !== 'boolean') {
1146
- throw new Error('VitePPDevOptions.miHudLess must be a boolean');
1147
- }
1148
- if (config.enableProxyCache !== undefined && typeof config.enableProxyCache !== 'boolean') {
1149
- throw new Error('VitePPDevOptions.enableProxyCache must be a boolean');
1150
- }
1151
- if (config.proxyCacheTTL !== undefined && typeof config.proxyCacheTTL !== 'number') {
1152
- throw new Error('VitePPDevOptions.proxyCacheTTL must be a number');
1153
- }
1154
- if (config.disableSSLValidation !== undefined && typeof config.disableSSLValidation !== 'boolean') {
1155
- throw new Error('VitePPDevOptions.disableSSLValidation must be a boolean');
1156
- }
1157
- if (config.imageOptimizer !== undefined &&
1158
- typeof config.imageOptimizer !== 'boolean' &&
1159
- typeof config.imageOptimizer !== 'object') {
1160
- throw new Error('VitePPDevOptions.imageOptimizer must be a boolean or an object');
1161
- }
1162
- if (config.outDir !== undefined && typeof config.outDir !== 'string') {
1163
- throw new Error('VitePPDevOptions.outDir must be a string');
1164
- }
1165
- if (config.distZip !== undefined && typeof config.distZip !== 'boolean' && typeof config.distZip !== 'object') {
1166
- throw new Error('VitePPDevOptions.distZip must be a boolean or an object');
1167
- }
1168
- if (config.syncBackupsDir !== undefined && typeof config.syncBackupsDir !== 'string') {
1169
- throw new Error('VitePPDevOptions.syncBackupsDir must be a string');
1170
- }
1171
- if (config.v7Features !== undefined && typeof config.v7Features !== 'boolean') {
1172
- throw new Error('VitePPDevOptions.v7Features must be a boolean');
1173
- }
1174
- }
1175
- function normalizeVitePPDevConfig(config) {
1176
- !isVitePPDevOptions(config) && throwConfigError(config);
1177
- const { enableProxyCache = true, proxyCacheTTL = 10 * 60 * 1000, disableSSLValidation = false, imageOptimizer = true, miHudLess = false, templateLess = false, outDir = 'dist', distZip = true, syncBackupsDir = 'backups', v7Features = false, } = config || {};
1178
- let distZipConfig = distZip;
1179
- if (distZipConfig === true) {
1180
- distZipConfig = {
1181
- outFileName: `${config.templateName}.zip`,
1182
- outDir: 'dist-zip',
1183
- };
1184
- }
1185
- else if (typeof distZip === 'object') {
1186
- distZipConfig = {
1187
- outFileName: typeof distZip.outFileName === 'string'
1188
- ? distZip.outFileName.replace('[templateName]', config.templateName)
1189
- : `${config.templateName}.zip`,
1190
- outDir: distZip.outDir ?? 'dist-zip',
1191
- };
1192
- }
1193
- else {
1194
- distZipConfig = false;
1195
- }
1196
- let imageOptimizerConfig = imageOptimizer;
1197
- if (typeof imageOptimizer === 'boolean') {
1198
- if (imageOptimizerConfig === true) {
1199
- imageOptimizerConfig = {};
1200
- }
1201
- }
1202
- else if (typeof imageOptimizer !== 'object') {
1203
- imageOptimizerConfig = false;
1204
- }
1205
- return {
1206
- enableProxyCache,
1207
- proxyCacheTTL,
1208
- disableSSLValidation,
1209
- imageOptimizer: imageOptimizerConfig,
1210
- templateLess,
1211
- miHudLess,
1212
- outDir,
1213
- distZip: distZipConfig,
1214
- syncBackupsDir,
1215
- v7Features,
1216
- ...config,
1217
- };
1218
- }
1219
- function vitePPDev(options) {
1220
- const { templateName, templateLess, backendBaseURL, miHudLess, portalPageId, enableProxyCache, proxyCacheTTL, disableSSLValidation, distZip, syncBackupsDir, v7Features, } = options || {};
1221
- // Avoid server caching for index.html file when first loading
1222
- let isFirstRequest = true;
1223
- process.cwd();
1224
- return {
1225
- name: 'vite-pp-dev',
1226
- apply: 'serve',
1227
- config: (config) => {
1228
- config.clientInjectionPlugin = { backendBaseURL, portalPageId, templateLess, v7Features };
1229
- if (v7Features) {
1230
- config.base = `/pl/${templateName}`;
1231
- }
1232
- if (config.root) {
1233
- config.root;
1234
- }
1235
- return config;
1236
- },
1237
- transformIndexHtml: async (html, ctx) => {
1238
- const result = { html, tags: [] };
1239
- if (isFirstRequest) {
1240
- isFirstRequest = false;
1241
- result.tags.push({
1242
- tag: 'script',
1243
- injectTo: 'body',
1244
- children: `${Math.random()}`,
1245
- });
1246
- }
1247
- return result;
1248
- },
1249
- configureServer: (server) => {
1250
- let base = server.config.base;
1251
- if (!base.endsWith('/')) {
1252
- base += '/';
1253
- }
1254
- const baseWithoutTrailingSlash = base.substring(0, base.lastIndexOf('/'));
1255
- server.middlewares.use(initPPRedirect(base, templateName));
1256
- if (backendBaseURL) {
1257
- const baseUrlHost = new URL(backendBaseURL).host;
1258
- const mi = new MiAPI(backendBaseURL, {
1259
- headers: {
1260
- host: baseUrlHost,
1261
- referer: backendBaseURL,
1262
- origin: backendBaseURL.replace(/^(https?:\/\/)([^/]+)(\/.*)?$/i, '$1$2'),
1263
- },
1264
- portalPageId,
1265
- templateLess,
1266
- disableSSLValidation,
1267
- v7Features,
1268
- });
1269
- if (enableProxyCache) {
1270
- let ttl = +proxyCacheTTL;
1271
- if (!ttl || Number.isNaN(ttl) || ttl < 0) {
1272
- ttl = 10 * 60 * 1000; // 10 minutes
1273
- }
1274
- server.middlewares.use(initProxyCache({ devServer: server, ttl }));
1275
- }
1276
- server.middlewares.use(initProxy({
1277
- devServer: server,
1278
- baseURL: backendBaseURL,
1279
- proxyIgnore: ['/@vite', '/@metricinsights', '/@', baseWithoutTrailingSlash],
1280
- disableSSLValidation,
1281
- }));
1282
- const isIndexRegExp = new RegExp(`^((${base})|/)$`);
1283
- // Get portal page variables from the backend (also, redirect magic)
1284
- server.middlewares.use(initLoadPPData(isIndexRegExp, mi, options));
1285
- const distService = distZip !== false
1286
- ? new DistService(templateName, Object.assign({ backupDir: syncBackupsDir }, typeof distZip === 'object'
1287
- ? { distZipFolder: distZip.outDir, distZipFilename: distZip.outFileName }
1288
- : undefined))
1289
- : undefined;
1290
- new ClientService(server, { distService, miAPI: mi });
1291
- return () => {
1292
- server.middlewares.use(initRewriteResponse((url) => {
1293
- return url.endsWith('index.html');
1294
- }, (response, req) => {
1295
- return Buffer.from(urlReplacer(baseUrlHost, req.headers.host ?? '', mi.buildPage(response, miHudLess)));
1296
- }));
1297
- };
1298
- }
1299
- },
1300
- };
1301
- }
1302
-
1303
- exports.MiAPI = MiAPI;
1304
- exports.colors = colors;
1305
- exports.createLogger = createLogger;
1306
- exports.cutUrlParams = cutUrlParams;
1307
- exports.initLoadPPData = initLoadPPData;
1308
- exports.initPPRedirect = initPPRedirect;
1309
- exports.initProxy = initProxy;
1310
- exports.initProxyCache = initProxyCache;
1311
- exports.initRewriteResponse = initRewriteResponse;
1312
- exports.normalizeVitePPDevConfig = normalizeVitePPDevConfig;
1313
- exports.urlReplacer = urlReplacer;
1314
- exports.vitePPDev = vitePPDev;
1315
- //# sourceMappingURL=plugin-DZS4Taov.js.map