underpost 3.1.3 → 3.2.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 (87) hide show
  1. package/.env.example +0 -2
  2. package/.github/workflows/ghpkg.ci.yml +4 -4
  3. package/.github/workflows/npmpkg.ci.yml +28 -11
  4. package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -4
  5. package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
  6. package/.github/workflows/release.cd.yml +4 -4
  7. package/CHANGELOG.md +324 -1
  8. package/CLI-HELP.md +49 -3
  9. package/README.md +3 -2
  10. package/bin/build.js +18 -12
  11. package/bin/deploy.js +177 -124
  12. package/bin/file.js +3 -0
  13. package/conf.js +3 -2
  14. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  15. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  16. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  17. package/manifests/deployment/dd-test-development/deployment.yaml +72 -50
  18. package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
  19. package/manifests/deployment/playwright/deployment.yaml +1 -1
  20. package/nodemon.json +1 -1
  21. package/package.json +22 -15
  22. package/scripts/rhel-grpc-setup.sh +56 -0
  23. package/src/api/file/file.ref.json +18 -0
  24. package/src/api/user/user.service.js +8 -7
  25. package/src/cli/cluster.js +7 -7
  26. package/src/cli/db.js +76 -242
  27. package/src/cli/deploy.js +104 -65
  28. package/src/cli/env.js +1 -0
  29. package/src/cli/fs.js +2 -1
  30. package/src/cli/index.js +42 -1
  31. package/src/cli/kubectl.js +211 -0
  32. package/src/cli/release.js +284 -0
  33. package/src/cli/repository.js +291 -75
  34. package/src/cli/run.js +188 -33
  35. package/src/cli/test.js +3 -3
  36. package/src/client/Default.index.js +3 -4
  37. package/src/client/components/core/AppStore.js +69 -0
  38. package/src/client/components/core/CalendarCore.js +2 -2
  39. package/src/client/components/core/DropDown.js +129 -17
  40. package/src/client/components/core/Keyboard.js +2 -2
  41. package/src/client/components/core/LogIn.js +2 -2
  42. package/src/client/components/core/LogOut.js +2 -2
  43. package/src/client/components/core/Modal.js +0 -1
  44. package/src/client/components/core/Panel.js +0 -1
  45. package/src/client/components/core/PanelForm.js +19 -19
  46. package/src/client/components/core/SocketIo.js +82 -29
  47. package/src/client/components/core/SocketIoHandler.js +75 -0
  48. package/src/client/components/core/Stream.js +143 -95
  49. package/src/client/components/core/Webhook.js +40 -7
  50. package/src/client/components/default/AppStoreDefault.js +5 -0
  51. package/src/client/components/default/LogInDefault.js +3 -3
  52. package/src/client/components/default/LogOutDefault.js +2 -2
  53. package/src/client/components/default/MenuDefault.js +5 -5
  54. package/src/client/components/default/SocketIoDefault.js +3 -51
  55. package/src/client/services/core/core.service.js +20 -8
  56. package/src/client/services/user/user.management.js +2 -2
  57. package/src/index.js +24 -1
  58. package/src/runtime/express/Express.js +18 -1
  59. package/src/runtime/lampp/Dockerfile +9 -2
  60. package/src/runtime/lampp/Lampp.js +4 -3
  61. package/src/runtime/wp/Dockerfile +64 -0
  62. package/src/runtime/wp/Wp.js +497 -0
  63. package/src/server/auth.js +24 -1
  64. package/src/server/backup.js +19 -1
  65. package/src/server/client-build-docs.js +9 -2
  66. package/src/server/client-build.js +31 -31
  67. package/src/server/client-formatted.js +109 -57
  68. package/src/server/ipfs-client.js +24 -1
  69. package/src/server/peer.js +8 -0
  70. package/src/server/runtime.js +25 -1
  71. package/src/server/start.js +6 -0
  72. package/src/ws/IoInterface.js +1 -10
  73. package/src/ws/IoServer.js +14 -33
  74. package/src/ws/core/channels/core.ws.chat.js +65 -20
  75. package/src/ws/core/channels/core.ws.mailer.js +113 -32
  76. package/src/ws/core/channels/core.ws.stream.js +90 -31
  77. package/src/ws/core/core.ws.connection.js +12 -33
  78. package/src/ws/core/core.ws.emit.js +10 -26
  79. package/src/ws/core/core.ws.server.js +25 -58
  80. package/src/ws/default/channels/default.ws.main.js +53 -12
  81. package/src/ws/default/default.ws.connection.js +26 -13
  82. package/src/ws/default/default.ws.server.js +30 -12
  83. package/src/client/components/default/ElementsDefault.js +0 -38
  84. package/src/ws/core/management/core.ws.chat.js +0 -8
  85. package/src/ws/core/management/core.ws.mailer.js +0 -16
  86. package/src/ws/core/management/core.ws.stream.js +0 -8
  87. package/src/ws/default/management/default.ws.main.js +0 -8
@@ -394,6 +394,7 @@ const buildCoverage = async ({ host, path, docs }) => {
394
394
  const jsDocSourcePath = docs.jsJsonPath;
395
395
  const jsDocsConfig = JSON.parse(fs.readFileSync(jsDocSourcePath, 'utf8'));
396
396
  const coveragePath = docs.coveragePath;
397
+ const coverageOutputDir = docs.coverageOutputDir || 'coverage';
397
398
 
398
399
  const coverageOutputPath = `${coveragePath}/coverage`;
399
400
  if (!fs.existsSync(coverageOutputPath)) {
@@ -411,9 +412,15 @@ const buildCoverage = async ({ host, path, docs }) => {
411
412
  }
412
413
 
413
414
  if (fs.existsSync(coverageOutputPath) && fs.readdirSync(coverageOutputPath).length > 0) {
414
- const coverageBuildPath = `${jsDocsConfig.opts.destination}coverage`;
415
+ const coverageBuildPath = `${jsDocsConfig.opts.destination}${coverageOutputDir}`;
415
416
  fs.mkdirSync(coverageBuildPath, { recursive: true });
416
- fs.copySync(coverageOutputPath, coverageBuildPath);
417
+ // Hardhat 3 outputs HTML to coverage/html/; Hardhat 2 / c8 output directly to coverage/
418
+ const coverageHtmlSubdir = `${coverageOutputPath}/html`;
419
+ if (fs.existsSync(coverageHtmlSubdir) && fs.existsSync(`${coverageHtmlSubdir}/index.html`)) {
420
+ fs.copySync(coverageHtmlSubdir, coverageBuildPath);
421
+ } else {
422
+ fs.copySync(coverageOutputPath, coverageBuildPath);
423
+ }
417
424
  logger.warn('build coverage', coverageBuildPath);
418
425
  } else {
419
426
  logger.warn('no coverage output found, skipping', coverageOutputPath);
@@ -7,7 +7,7 @@
7
7
  'use strict';
8
8
 
9
9
  import fs from 'fs-extra';
10
- import { srcFormatted, componentFormatted, viewFormatted, JSONweb } from './client-formatted.js';
10
+ import { transformClientJs, JSONweb } from './client-formatted.js';
11
11
  import { loggerFactory } from './logger.js';
12
12
  import {
13
13
  getCapVariableName,
@@ -16,7 +16,6 @@ import {
16
16
  uniqueArray,
17
17
  } from '../client/components/core/CommonJs.js';
18
18
  import { readConfJson } from './conf.js';
19
- import UglifyJS from 'uglify-js';
20
19
  import { minify } from 'html-minifier-terser';
21
20
  import AdmZip from 'adm-zip';
22
21
  import * as dir from 'path';
@@ -317,7 +316,8 @@ const buildClient = async (
317
316
  shellExec(`cd /home/dd && git clone https://github.com/designmodo/html-website-templates.git`);
318
317
  if (!fs.existsSync(`${rootClientPath}/index.php`)) {
319
318
  fs.copySync(`/home/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
320
- shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
319
+ Underpost.repo.initLocalRepo({ path: rootClientPath });
320
+ shellExec(`cd ${rootClientPath} && git add . && git commit -m "Base template implementation"`);
321
321
  // git remote add origin git@github.com:<username>/<repo>.git
322
322
  fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
323
323
  }
@@ -447,15 +447,15 @@ const buildClient = async (
447
447
 
448
448
  if (enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath)) continue;
449
449
 
450
- const jsSrc = componentFormatted(
451
- await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')),
452
- module,
450
+ const jsSrc = await transformClientJs(jsSrcPath, {
453
451
  dists,
454
- path,
455
- 'components',
452
+ proxyPath: path,
453
+ basePath: 'components',
454
+ module,
456
455
  baseHost,
457
- );
458
- fs.writeFileSync(jsPublicPath, minifyBuild ? UglifyJS.minify(jsSrc).code : jsSrc, 'utf8');
456
+ minify: minifyBuild,
457
+ });
458
+ fs.writeFileSync(jsPublicPath, jsSrc, 'utf8');
459
459
  }
460
460
  }
461
461
 
@@ -469,15 +469,15 @@ const buildClient = async (
469
469
  const jsPublicPath = `${rootClientPath}/services/${module}/${module}.service.js`;
470
470
  if (enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath)) continue;
471
471
 
472
- let jsSrc = componentFormatted(
473
- await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')),
474
- module,
472
+ const jsSrc = await transformClientJs(jsSrcPath, {
475
473
  dists,
476
- path,
477
- 'services',
474
+ proxyPath: path,
475
+ basePath: 'services',
476
+ module,
478
477
  baseHost,
479
- );
480
- fs.writeFileSync(jsPublicPath, minifyBuild ? UglifyJS.minify(jsSrc).code : jsSrc, 'utf8');
478
+ minify: minifyBuild,
479
+ });
480
+ fs.writeFileSync(jsPublicPath, jsSrc, 'utf8');
481
481
  }
482
482
  }
483
483
 
@@ -487,15 +487,15 @@ const buildClient = async (
487
487
  const jsPublicPath = `${rootClientPath}/services/${module}/${module}.management.js`;
488
488
  if (enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath)) continue;
489
489
 
490
- const jsSrc = componentFormatted(
491
- await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')),
492
- module,
490
+ const jsSrc = await transformClientJs(jsSrcPath, {
493
491
  dists,
494
- path,
495
- 'services',
492
+ proxyPath: path,
493
+ basePath: 'services',
494
+ module,
496
495
  baseHost,
497
- );
498
- fs.writeFileSync(jsPublicPath, minifyBuild ? UglifyJS.minify(jsSrc).code : jsSrc, 'utf8');
496
+ minify: minifyBuild,
497
+ });
498
+ fs.writeFileSync(jsPublicPath, jsSrc, 'utf8');
499
499
  }
500
500
  }
501
501
  }
@@ -513,9 +513,9 @@ const buildClient = async (
513
513
  const jsPublicPath = `${rootClientPath}/sw.js`;
514
514
 
515
515
  if (!(enableLiveRebuild && !options.liveClientBuildPaths.find((p) => p.srcBuildPath === jsSrcPath))) {
516
- const jsSrc = viewFormatted(await srcFormatted(fs.readFileSync(jsSrcPath, 'utf8')), dists, path, baseHost);
516
+ const jsSrc = await transformClientJs(jsSrcPath, { dists, proxyPath: path, baseHost, minify: minifyBuild });
517
517
 
518
- fs.writeFileSync(jsPublicPath, minifyBuild ? UglifyJS.minify(jsSrc).code : jsSrc, 'utf8');
518
+ fs.writeFileSync(jsPublicPath, jsSrc, 'utf8');
519
519
  }
520
520
 
521
521
  if (
@@ -535,14 +535,14 @@ const buildClient = async (
535
535
 
536
536
  logger.info('View build', buildPath);
537
537
 
538
- const jsSrc = viewFormatted(
539
- await srcFormatted(fs.readFileSync(`./src/client/${view.client}.index.js`, 'utf8')),
538
+ const jsSrc = await transformClientJs(`./src/client/${view.client}.index.js`, {
540
539
  dists,
541
- path,
540
+ proxyPath: path,
542
541
  baseHost,
543
- );
542
+ minify: minifyBuild,
543
+ });
544
544
 
545
- fs.writeFileSync(`${buildPath}${buildId}.js`, minifyBuild ? UglifyJS.minify(jsSrc).code : jsSrc, 'utf8');
545
+ fs.writeFileSync(`${buildPath}${buildId}.js`, jsSrc, 'utf8');
546
546
  const title = metadata.title ? metadata.title : title;
547
547
 
548
548
  const canonicalURL = `https://${host}${path}${
@@ -1,87 +1,139 @@
1
1
  /**
2
- * Module for formatting client-side code
2
+ * Module for formatting client-side code using esbuild for import rewriting and minification.
3
3
  * @module src/server/client-formatted.js
4
4
  * @namespace clientFormatted
5
5
  */
6
6
 
7
7
  'use strict';
8
8
 
9
+ import * as esbuild from 'esbuild';
10
+ import fs from 'fs-extra';
11
+ import * as path from 'path';
12
+
13
+ /**
14
+ * Escapes a string for safe use inside a RegExp.
15
+ * @param {string} s - The string to escape.
16
+ * @returns {string} The escaped string.
17
+ * @memberof clientFormatted
18
+ */
19
+ const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
20
+
9
21
  /**
10
- * Formats a source code string by removing 'html`' and 'css`' tags from template literals.
22
+ * Formats a source code string by removing 'html`' and 'css`' tagged template prefixes.
23
+ * Used for SSR VM execution where the full esbuild pipeline is not needed.
11
24
  * @param {string} src - The source code string.
12
25
  * @returns {string} The formatted source code.
13
26
  * @memberof clientFormatted
14
27
  */
15
- const srcFormatted = (src) =>
16
- src
17
- .replaceAll(' html`', '`')
18
- .replaceAll(' css`', '`')
19
- .replaceAll('{html`', '{`')
20
- .replaceAll('{css`', '{`')
21
- .replaceAll('(html`', '(`')
22
- .replaceAll('(css`', '(`')
23
- .replaceAll('[html`', '[`')
24
- .replaceAll('[css`', '[`');
28
+ const srcFormatted = (src) => src.replace(/(?<=[\s({[,;=+!?:^])(html|css)`/g, '`');
25
29
 
26
30
  /**
27
31
  * Converts a JavaScript object into a string that can be embedded in client-side code
28
32
  * and parsed back into an object (e.g., 'JSON.parse(`{...}`)').
33
+ * Escapes backticks and template expression markers for safe template literal embedding.
29
34
  * @param {*} data - The data to be stringified.
30
35
  * @returns {string} A string representing the code to parse the JSON data.
31
36
  * @memberof clientFormatted
32
37
  */
33
- const JSONweb = (data) => 'JSON.parse(`' + JSON.stringify(data) + '`)';
38
+ const JSONweb = (data) => {
39
+ const json = JSON.stringify(data).replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
40
+ return 'JSON.parse(`' + json + '`)';
41
+ };
34
42
 
35
43
  /**
36
- * Formats a component's source code by rewriting its import paths to be absolute for browser consumption.
37
- * @param {string} src - The source code of the component.
38
- * @param {string} module - The name of the module/component.
39
- * @param {Array<object>} dists - An array of distribution objects with import names.
40
- * @param {string} proxyPath - The proxy path for the application.
41
- * @param {string} [componentBasePath=''] - The base path for components.
42
- * @param {string} [baseHost=''] - The base host URL.
43
- * @returns {string} The formatted source code with updated import paths.
44
+ * Creates an esbuild plugin that rewrites import paths for browser consumption.
45
+ * Handles dist library imports, relative imports, and marks all remaining imports as external.
46
+ * @param {object} options
47
+ * @param {Array<object>} [options.dists=[]] - Distribution objects with import_name and import_name_build.
48
+ * @param {string} options.proxyPath - The proxy path for the application.
49
+ * @param {string} [options.basePath=''] - The base path for the module type (e.g., 'components', 'services').
50
+ * @param {string} [options.module=''] - The module/component name for relative import resolution.
51
+ * @param {string} [options.baseHost=''] - The base host URL.
52
+ * @returns {import('esbuild').Plugin}
44
53
  * @memberof clientFormatted
45
54
  */
46
- const componentFormatted = (src, module, dists, proxyPath, componentBasePath = '', baseHost = '') => {
47
- dists.map(
48
- (dist) =>
49
- (src = src.replaceAll(
50
- `from '${dist.import_name}'`,
51
- `from '${baseHost}${proxyPath !== '/' ? `${proxyPath}` : ''}${dist.import_name_build}'`,
52
- )),
53
- );
54
- return src
55
- .replaceAll(
56
- `from '../`,
57
- `from '${baseHost}${proxyPath !== '/' ? `${proxyPath}/` : '/'}${
58
- componentBasePath === '' ? `` : `${componentBasePath}/`
59
- }`,
60
- )
61
- .replaceAll(
62
- `from './`,
63
- `from '${baseHost}${proxyPath !== '/' ? `${proxyPath}/` : '/'}${
64
- componentBasePath === '' ? `` : `${componentBasePath}/`
65
- }${module}/`,
66
- );
67
- };
55
+ const importRewritePlugin = ({ dists = [], proxyPath, basePath = '', module = '', baseHost = '' }) => ({
56
+ name: 'import-rewrite',
57
+ setup(build) {
58
+ const prefix = `${baseHost}${proxyPath !== '/' ? `${proxyPath}/` : '/'}`;
59
+
60
+ // Rewrite dist library imports (e.g., '@neodrag/vanilla' '/proxyPath/dist/@neodrag-vanilla/index.js')
61
+ if (dists) {
62
+ for (const dist of dists) {
63
+ if (!dist.import_name) continue;
64
+ const filter = new RegExp(`^${escapeRegExp(dist.import_name)}$`);
65
+ build.onResolve({ filter }, () => ({
66
+ path: `${baseHost}${proxyPath !== '/' ? proxyPath : ''}${dist.import_name_build}`,
67
+ external: true,
68
+ }));
69
+ }
70
+ }
71
+
72
+ // Rewrite relative imports to absolute paths based on proxy path and module
73
+ build.onResolve({ filter: /^\.\.?\// }, (args) => {
74
+ const basePrefix = `${prefix}${basePath ? `${basePath}/` : ''}`;
75
+ if (args.path.startsWith('./')) {
76
+ return {
77
+ path: `${basePrefix}${module ? `${module}/` : ''}${args.path.slice(2)}`,
78
+ external: true,
79
+ };
80
+ }
81
+ if (args.path.startsWith('../')) {
82
+ return {
83
+ path: `${basePrefix}${args.path.slice(3)}`,
84
+ external: true,
85
+ };
86
+ }
87
+ });
88
+
89
+ // Mark any remaining imports as external
90
+ build.onResolve({ filter: /.*/ }, (args) => {
91
+ if (args.kind === 'entry-point') return;
92
+ return { path: args.path, external: true };
93
+ });
94
+ },
95
+ });
68
96
 
69
97
  /**
70
- * Formats a view's source code by rewriting its import paths.
71
- * @param {string} src - The source code of the view.
72
- * @param {Array<object>} dists - An array of distribution objects with import names.
73
- * @param {string} proxyPath - The proxy path for the application.
74
- * @param {string} [baseHost=''] - The base host URL.
75
- * @returns {string} The formatted source code with updated import paths.
98
+ * Transforms a JavaScript source file using esbuild with import path rewriting,
99
+ * tagged template stripping, and optional minification.
100
+ * Replaces the previous srcFormatted + componentFormatted/viewFormatted + UglifyJS pipeline.
101
+ * @param {string} srcPath - Path to the source file.
102
+ * @param {object} options
103
+ * @param {Array<object>} [options.dists=[]] - Distribution objects with import names.
104
+ * @param {string} options.proxyPath - The proxy path for the application.
105
+ * @param {string} [options.basePath=''] - Base path for the module type (e.g., 'components', 'services').
106
+ * @param {string} [options.module=''] - Module name for relative import resolution.
107
+ * @param {string} [options.baseHost=''] - Base host URL.
108
+ * @param {boolean} [options.minify=false] - Whether to minify the output.
109
+ * @returns {Promise<string>} The transformed source code.
76
110
  * @memberof clientFormatted
77
111
  */
78
- const viewFormatted = (src, dists, proxyPath, baseHost = '') => {
79
- dists.map(
80
- (dist) =>
81
- (src = src.replaceAll(dist.import_name, `${proxyPath !== '/' ? `${proxyPath}` : ''}${dist.import_name_build}`)),
82
- );
83
- const componentFromFormatted = `from '${baseHost}${proxyPath !== '/' ? `${proxyPath}/` : '/'}`;
84
- return src.replaceAll(`from './`, componentFromFormatted).replaceAll(`from '../`, componentFromFormatted);
112
+ const transformClientJs = async (
113
+ srcPath,
114
+ { dists = [], proxyPath, basePath = '', module = '', baseHost = '', minify: shouldMinify = false } = {},
115
+ ) => {
116
+ const src = fs.readFileSync(srcPath, 'utf8');
117
+ const stripped = srcFormatted(src);
118
+
119
+ const result = await esbuild.build({
120
+ stdin: {
121
+ contents: stripped,
122
+ loader: 'js',
123
+ resolveDir: path.dirname(path.resolve(srcPath)),
124
+ sourcefile: srcPath,
125
+ },
126
+ bundle: true,
127
+ write: false,
128
+ format: 'esm',
129
+ platform: 'browser',
130
+ target: 'esnext',
131
+ minify: shouldMinify,
132
+ logLevel: 'warning',
133
+ plugins: [importRewritePlugin({ dists, proxyPath, basePath, module, baseHost })],
134
+ });
135
+
136
+ return result.outputFiles[0].text;
85
137
  };
86
138
 
87
- export { srcFormatted, JSONweb, componentFormatted, viewFormatted };
139
+ export { srcFormatted, JSONweb, transformClientJs };
@@ -244,7 +244,11 @@ const unpinCid = async (cid) => {
244
244
  });
245
245
  if (!clusterRes.ok) {
246
246
  const text = await clusterRes.text();
247
- logger.warn(`IPFS Cluster unpin failed (${clusterRes.status}): ${text}`);
247
+ if (clusterRes.status === 404) {
248
+ logger.info(`IPFS Cluster unpin – CID already not pinned: ${cid}`);
249
+ } else {
250
+ logger.warn(`IPFS Cluster unpin failed (${clusterRes.status}): ${text}`);
251
+ }
248
252
  } else {
249
253
  logger.info(`IPFS Cluster unpin OK – CID: ${cid}`);
250
254
  }
@@ -428,6 +432,25 @@ const IpfsClient = {
428
432
  listClusterPins,
429
433
  listKuboPins,
430
434
  removeMfsPath,
435
+ /**
436
+ * Check whether a single CID is currently pinned on the local Kubo node.
437
+ * Uses the pin/ls?arg=<cid> endpoint which returns only that one pin
438
+ * (much cheaper than fetching the full list).
439
+ *
440
+ * @param {string} cid - IPFS Content Identifier to check.
441
+ * @returns {Promise<boolean>} true when the CID is pinned.
442
+ */
443
+ isCidPinned: async (cid) => {
444
+ const kuboUrl = getIpfsApiUrl();
445
+ try {
446
+ const res = await fetch(`${kuboUrl}/api/v0/pin/ls?arg=${encodeURIComponent(cid)}&type=all`, { method: 'POST' });
447
+ if (!res.ok) return false;
448
+ const json = await res.json();
449
+ return !!(json.Keys && json.Keys[cid]);
450
+ } catch {
451
+ return false;
452
+ }
453
+ },
431
454
  };
432
455
 
433
456
  export { IpfsClient };
@@ -44,6 +44,14 @@ const logger = loggerFactory(import.meta);
44
44
  */
45
45
  const createPeerServer = async ({ port, origins, path }) => {
46
46
  logger.info('origins', origins);
47
+
48
+ // In development, allow the local client origin (peer runs on port+1 relative to the client)
49
+ if (process.env.NODE_ENV === 'development') {
50
+ const clientPort = port - 1;
51
+ const devOrigin = `http://localhost:${clientPort}`;
52
+ if (!origins.includes(devOrigin)) origins.push(devOrigin);
53
+ }
54
+
47
55
  /** @type {import('peer').IConfig} */
48
56
  const options = {
49
57
  port,
@@ -11,6 +11,7 @@ import * as promClient from 'prom-client';
11
11
  import { loggerFactory } from './logger.js';
12
12
  import { newInstance } from '../client/components/core/CommonJs.js';
13
13
  import { Lampp } from '../runtime/lampp/Lampp.js';
14
+ import { WpService } from '../runtime/wp/Wp.js';
14
15
  import { getInstanceContext, readConfJson } from './conf.js';
15
16
 
16
17
  import ExpressService from '../runtime/express/Express.js';
@@ -71,6 +72,9 @@ const buildRuntime = async () => {
71
72
  valkey,
72
73
  apiBaseHost,
73
74
  useLocalSsl,
75
+ grpc,
76
+ repository,
77
+ wp,
74
78
  } = confServer[host][path];
75
79
 
76
80
  // Calculate context data
@@ -116,6 +120,7 @@ const buildRuntime = async () => {
116
120
  peer,
117
121
  valkey,
118
122
  apiBaseHost,
123
+ grpc,
119
124
  redirectTarget,
120
125
  rootHostPath,
121
126
  confSSR,
@@ -129,7 +134,7 @@ const buildRuntime = async () => {
129
134
 
130
135
  case 'lampp':
131
136
  {
132
- const { disabled } = await Lampp.createApp({
137
+ const { disabled } = Lampp.createApp({
133
138
  port,
134
139
  host,
135
140
  path,
@@ -143,6 +148,25 @@ const buildRuntime = async () => {
143
148
  await Underpost.start.listenPortController(Underpost.start.listenServerFactory(), port, runningData);
144
149
  }
145
150
  break;
151
+
152
+ case 'wp':
153
+ {
154
+ const { disabled } = WpService.createApp({
155
+ port,
156
+ host,
157
+ pathRoute: path,
158
+ repository,
159
+ db,
160
+ wp,
161
+ redirect,
162
+ redirectTarget,
163
+ resetRouter: currentPort === initPort,
164
+ });
165
+ if (disabled) continue;
166
+ await Underpost.start.listenPortController(Underpost.start.listenServerFactory(), port, runningData);
167
+ }
168
+ break;
169
+
146
170
  default:
147
171
  break;
148
172
  }
@@ -9,6 +9,7 @@ import { awaitDeployMonitor } from './conf.js';
9
9
  import { actionInitLog, loggerFactory } from './logger.js';
10
10
  import { shellCd, shellExec } from './process.js';
11
11
  import Underpost from '../index.js';
12
+ import isInsideContainer from 'is-inside-container';
12
13
  const logger = loggerFactory(import.meta);
13
14
 
14
15
  /**
@@ -198,6 +199,11 @@ class UnderpostStartUp {
198
199
  shellExec(`npm ${runCmd} ${deployId}`, { async: true });
199
200
  await awaitDeployMonitor(true);
200
201
  Underpost.env.set('container-status', `${deployId}-${env}-running-deployment`);
202
+ if (env === 'production' && isInsideContainer()) {
203
+ Underpost.env.clean();
204
+ shellExec(`sudo rm -rf /home/dd/engine/engine-private`);
205
+ if (fs.existsSync('/etc/config/.env.production')) fs.removeSync('/etc/config/.env.production');
206
+ }
201
207
  },
202
208
  };
203
209
  }
@@ -126,13 +126,4 @@ class IoChannel {
126
126
  }
127
127
  }
128
128
 
129
- /**
130
- * Backward compatibility function to create a new channel instance.
131
- * @memberof SocketIoInterface
132
- * @function IoCreateChannel
133
- * @param {ChannelInterface} IoInterface - The interface object defining the channel's behavior.
134
- * @returns {IoChannel} An instance of the IoChannel class.
135
- */
136
- const IoCreateChannel = (IoInterface) => new IoChannel(IoInterface);
137
-
138
- export { IoChannel, IoCreateChannel };
129
+ export { IoChannel };
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Module for creating and managing WebSocket servers.
3
- * @module src/ws/IoServer
4
- * @namespace SocketIoServer
3
+ * @module ws/IoServer
5
4
  */
6
5
 
7
6
  'use strict';
@@ -9,33 +8,27 @@
9
8
  import { Server } from 'socket.io';
10
9
  import { loggerFactory } from '../server/logger.js';
11
10
  import Underpost from '../index.js';
12
- import http from 'http';
13
11
 
14
12
  const logger = loggerFactory(import.meta);
15
13
 
16
14
  /**
17
- * @class IoServerClass
18
- * @alias IoServerClass
19
- * @memberof SocketIoServer
20
- * @classdesc Provides a static factory method to create and configure a Socket.IO server,
21
- * encapsulating WebSocket server initialization logic and CORS configuration.
15
+ * @class IoServer
16
+ * @classdesc Factory for creating and configuring Socket.IO server instances
17
+ * with CORS configuration and HTTP server attachment.
22
18
  */
23
- class IoServerClass {
19
+ class IoServer {
24
20
  /**
25
21
  * Creates a new WebSocket server instance attached to an HTTP server.
26
22
  *
27
23
  * @static
28
- * @param {http.Server} httpServer - The HTTP server instance to attach the WebSocket server to.
29
- * @param {Object} options - Configuration options for the WebSocket server.
30
- * @param {string[]} options.origins - List of allowed origins for Cross-Origin Resource Sharing (CORS).
31
- * @param {string} options.path - The base path for the API. The WebSocket path ('/socket.io') will be appended to this.
32
- * @param {function(import('socket.io').Socket): void} ConnectionHandler - The connection handler function to be executed on a new connection.
33
- * @returns {Object} An object containing the final options and the server instance.
34
- * @returns {import('socket.io').ServerOptions} return.options - The final options object used to create the WebSocket server.
35
- * @returns {import('socket.io').Server} return.ioServer - The created and listening WebSocket server instance.
36
- * @returns {object} return.meta - The module's import meta object (`import.meta`).
24
+ * @param {import('http').Server} httpServer - The HTTP server instance to attach to.
25
+ * @param {Object} options - Configuration options.
26
+ * @param {string[]} options.origins - Allowed CORS origins.
27
+ * @param {string} options.path - Base API path. Socket.IO path is appended automatically.
28
+ * @param {function(import('socket.io').Socket): void} connectionHandler - Handler for new connections.
29
+ * @returns {{ options: import('socket.io').ServerOptions, ioServer: import('socket.io').Server, meta: ImportMeta }}
37
30
  */
38
- static create(httpServer, options = {}, ConnectionHandler = () => {}) {
31
+ static create(httpServer, options = {}, connectionHandler = () => {}) {
39
32
  logger.info('origins', options.origins);
40
33
  const wsOptions = {
41
34
  cors: {
@@ -55,12 +48,11 @@ class IoServerClass {
55
48
  ],
56
49
  credentials: true,
57
50
  },
58
- // Ensure the path ends correctly, appending '/socket.io/'
59
51
  path: options.path !== '/' ? `${options.path}/socket.io/` : '/socket.io/',
60
52
  };
61
53
 
62
54
  const ioServerInstance = Underpost.start.listenServerFactory(() =>
63
- new Server(httpServer, wsOptions).on('connection', ConnectionHandler),
55
+ new Server(httpServer, wsOptions).on('connection', connectionHandler),
64
56
  );
65
57
 
66
58
  logger.info('Socket.IO Server created and listening', { path: wsOptions.path });
@@ -73,15 +65,4 @@ class IoServerClass {
73
65
  }
74
66
  }
75
67
 
76
- /**
77
- * Backward compatibility export for the server creation function.
78
- * @memberof SocketIoServer
79
- * @function IoServer
80
- * @param {http.Server} httpServer - The HTTP server instance.
81
- * @param {Object} options - Configuration options.
82
- * @param {function(import('socket.io').Socket): void} ConnectionHandler - The connection handler function.
83
- * @returns {Object} The server configuration object.
84
- */
85
- const IoServer = IoServerClass.create;
86
-
87
- export { IoServerClass, IoServer };
68
+ export { IoServer };