underpost 2.85.7 → 2.89.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 (36) hide show
  1. package/.github/workflows/release.cd.yml +1 -1
  2. package/README.md +2 -2
  3. package/bin/build.js +8 -10
  4. package/cli.md +3 -2
  5. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  6. package/manifests/deployment/dd-test-development/deployment.yaml +50 -50
  7. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  8. package/package.json +1 -1
  9. package/src/api/file/file.service.js +29 -3
  10. package/src/cli/baremetal.js +1 -2
  11. package/src/cli/index.js +1 -0
  12. package/src/cli/repository.js +8 -1
  13. package/src/cli/run.js +97 -36
  14. package/src/client/components/core/AgGrid.js +42 -3
  15. package/src/client/components/core/CommonJs.js +4 -0
  16. package/src/client/components/core/Css.js +95 -48
  17. package/src/client/components/core/CssCore.js +0 -1
  18. package/src/client/components/core/LoadingAnimation.js +2 -2
  19. package/src/client/components/core/Logger.js +2 -9
  20. package/src/client/components/core/Modal.js +22 -14
  21. package/src/client/components/core/ObjectLayerEngine.js +300 -9
  22. package/src/client/components/core/ObjectLayerEngineModal.js +686 -148
  23. package/src/client/components/core/ObjectLayerEngineViewer.js +1061 -0
  24. package/src/client/components/core/Pagination.js +15 -5
  25. package/src/client/components/core/Router.js +5 -1
  26. package/src/client/components/core/Translate.js +4 -0
  27. package/src/client/components/core/Worker.js +8 -1
  28. package/src/client/services/default/default.management.js +86 -16
  29. package/src/db/mariadb/MariaDB.js +2 -2
  30. package/src/index.js +1 -1
  31. package/src/server/client-build.js +57 -2
  32. package/src/server/object-layer.js +44 -0
  33. package/src/server/start.js +12 -0
  34. package/src/ws/IoInterface.js +2 -3
  35. package/AUTHORS.md +0 -21
  36. package/src/server/network.js +0 -72
@@ -10,12 +10,13 @@ class AgPagination extends HTMLElement {
10
10
  this._limit = parseInt(queryParams.limit, 10) || 10;
11
11
  this._totalPages = 1;
12
12
  this._totalItems = 0;
13
+ this._limitOptions = [10, 20, 50, 100]; // Default options
13
14
  this.handlePageChange = this.handlePageChange.bind(this);
14
15
  this.handleLimitChange = this.handleLimitChange.bind(this);
15
16
  }
16
17
 
17
18
  static get observedAttributes() {
18
- return ['grid-id', 'current-page', 'total-pages', 'total-items', 'limit'];
19
+ return ['grid-id', 'current-page', 'total-pages', 'total-items', 'limit', 'limit-options'];
19
20
  }
20
21
 
21
22
  attributeChangedCallback(name, oldValue, newValue) {
@@ -35,6 +36,16 @@ class AgPagination extends HTMLElement {
35
36
  case 'limit':
36
37
  this._limit = parseInt(newValue, 10) || this._limit;
37
38
  break;
39
+ case 'limit-options':
40
+ try {
41
+ const parsed = JSON.parse(newValue);
42
+ if (Array.isArray(parsed) && parsed.length > 0) {
43
+ this._limitOptions = parsed.map((v) => parseInt(v, 10)).filter((v) => !isNaN(v) && v > 0);
44
+ }
45
+ } catch (e) {
46
+ console.warn('Invalid limit-options format, using defaults');
47
+ }
48
+ break;
38
49
  }
39
50
  this.update();
40
51
  }
@@ -133,6 +144,8 @@ class AgPagination extends HTMLElement {
133
144
  }
134
145
 
135
146
  render() {
147
+ const limitOptionsHtml = this._limitOptions.map((value) => `<option value="${value}">${value}</option>`).join('');
148
+
136
149
  this.shadowRoot.innerHTML = html`
137
150
  <style>
138
151
  :host {
@@ -193,10 +206,7 @@ class AgPagination extends HTMLElement {
193
206
  <button id="next-page">Next</button>
194
207
  <button id="last-page">Last</button>
195
208
  <select id="limit-selector">
196
- <option value="10">10</option>
197
- <option value="20">20</option>
198
- <option value="50">50</option>
199
- <option value="100">100</option>
209
+ ${limitOptionsHtml}
200
210
  </select>
201
211
  `;
202
212
  }
@@ -300,7 +300,11 @@ const setQueryParams = (newParams, options = { replace: true }) => {
300
300
 
301
301
  const newPath = url.pathname + url.search + url.hash;
302
302
 
303
- history.pushState(history.state, '', newPath);
303
+ if (options.replace) {
304
+ history.replaceState(history.state, '', newPath);
305
+ } else {
306
+ history.pushState(history.state, '', newPath);
307
+ }
304
308
  };
305
309
 
306
310
  export {
@@ -516,6 +516,10 @@ const TranslateCore = {
516
516
  en: 'Cron Management',
517
517
  es: 'Gestion de cron jobs',
518
518
  };
519
+ Translate.Data['success-reload-data'] = {
520
+ en: 'Data reloaded successfully.',
521
+ es: 'Datos recargados con éxito.',
522
+ };
519
523
  },
520
524
  };
521
525
 
@@ -53,15 +53,22 @@ class PwaWorker {
53
53
  */
54
54
  constructor() {
55
55
  this.title = `${s('title').textContent}`;
56
+ if (!window.renderPayload.dev) {
57
+ console.log = () => null;
58
+ console.error = () => null;
59
+ console.info = () => null;
60
+ console.warn = () => null;
61
+ }
56
62
  }
57
63
 
58
64
  /**
59
65
  * Checks if the application is running in development mode (localhost or 127.0.0.1).
66
+ * @method devMode
60
67
  * @memberof PwaWorker
61
68
  * @returns {boolean} True if in development mode.
62
69
  */
63
70
  devMode() {
64
- return location.origin.match('localhost') || location.origin.match('127.0.0.1');
71
+ return window.renderPayload.dev || location.origin.match('localhost') || location.origin.match('127.0.0.1');
65
72
  }
66
73
 
67
74
  /**
@@ -18,7 +18,7 @@ const DefaultOptions = {
18
18
  serviceId: 'default-management',
19
19
  entity: 'default',
20
20
  columnDefs: [
21
- { field: '0', headerName: '0' },
21
+ { field: '0', headerName: '0', cellClassRules: { 'row-new-highlight': (params) => true } },
22
22
  { field: '1', headerName: '1' },
23
23
  { field: '2', headerName: '2' },
24
24
  { field: 'createdAt', headerName: 'createdAt', cellDataType: 'date', editable: false },
@@ -29,6 +29,10 @@ const DefaultOptions = {
29
29
  permissions: {
30
30
  add: true,
31
31
  remove: true,
32
+ reload: true,
33
+ },
34
+ paginationOptions: {
35
+ limitOptions: [10, 20, 50, 100],
32
36
  },
33
37
  };
34
38
 
@@ -66,25 +70,36 @@ const DefaultManagement = {
66
70
  paginationComp.setAttribute('current-page', this.Tokens[id].page);
67
71
  paginationComp.setAttribute('total-pages', this.Tokens[id].totalPages);
68
72
  paginationComp.setAttribute('total-items', this.Tokens[id].total);
73
+ setTimeout(async () => {
74
+ if (DefaultManagement.Tokens[id].readyRowDataEvent)
75
+ for (const event of Object.keys(DefaultManagement.Tokens[id].readyRowDataEvent))
76
+ await DefaultManagement.Tokens[id].readyRowDataEvent[event](rowDataScope);
77
+ }, 1);
78
+ }
79
+ },
80
+ refreshTable: async function (id) {
81
+ const gridApi = AgGrid.grids[this.Tokens[id].gridId];
82
+ if (gridApi) {
83
+ // Use refreshCells with change detection for optimal performance
84
+ // This is preferred over redrawRows() as it only updates changed cells
85
+ gridApi.refreshCells({
86
+ force: false, // Use change detection - only refresh cells whose values have changed
87
+ suppressFlash: false, // Show flash animation for changed cells (requires enableCellChangeFlash)
88
+ });
69
89
  }
70
90
  },
71
91
  RenderTable: async function (options = DefaultOptions) {
72
92
  if (!options) options = DefaultOptions;
73
- const { serviceId, columnDefs, entity, defaultColKeyFocus, ServiceProvider, permissions } = options;
93
+ const { serviceId, columnDefs, entity, defaultColKeyFocus, ServiceProvider, permissions, paginationOptions } =
94
+ options;
74
95
  logger.info('DefaultManagement RenderTable', options);
75
96
  const id = options?.idModal ? options.idModal : getId(this.Tokens, `${serviceId}-`);
76
97
  const gridId = `${serviceId}-grid-${id}`;
77
98
  const queryParams = getQueryParams();
78
99
  const page = parseInt(queryParams.page) || 1;
79
- const limit = parseInt(queryParams.limit) || 10;
80
- this.Tokens[id] = {
81
- ...options,
82
- gridId,
83
- page,
84
- limit,
85
- total: 0,
86
- totalPages: 1,
87
- };
100
+ const defaultLimit = paginationOptions?.limitOptions?.[0] || 10;
101
+ const limit = parseInt(queryParams.limit) || defaultLimit;
102
+ this.Tokens[id] = { ...this.Tokens[id], ...options, gridId, page, limit, total: 0, totalPages: 1 };
88
103
 
89
104
  setQueryParams({ page, limit });
90
105
  setTimeout(async () => {
@@ -107,7 +122,7 @@ const DefaultManagement = {
107
122
  label: html`<div class="abs center">
108
123
  <i class="fas fa-times"></i>
109
124
  </div> `,
110
- class: `in fll section-mp management-table-btn-mini management-table-btn-remove-${id}-${cellRenderId}`,
125
+ class: `in fll section-mp management-table-btn-mini management-table-btn-remove-${id}-${cellRenderId} ${!params.data._id ? 'hide' : ''}`,
111
126
  })}`;
112
127
  setTimeout(() => {
113
128
  EventsUI.onClick(
@@ -191,9 +206,16 @@ const DefaultManagement = {
191
206
  // }
192
207
  // }
193
208
  s(`.management-table-btn-save-${id}`).onclick = () => {
209
+ s(`.management-table-btn-save-${id}`).classList.add('hide');
210
+ // s(`.management-table-btn-stop-${id}`).classList.add('hide');
211
+ if (permissions.add) s(`.management-table-btn-add-${id}`).classList.remove('hide');
212
+ if (permissions.remove) s(`.management-table-btn-clean-${id}`).classList.remove('hide');
213
+ if (permissions.reload) s(`.management-table-btn-reload-${id}`).classList.remove('hide');
194
214
  AgGrid.grids[gridId].stopEditing();
195
215
  };
196
216
  EventsUI.onClick(`.management-table-btn-add-${id}`, async () => {
217
+ if (options.customEvent && options.customEvent.add) return await options.customEvent.add();
218
+
197
219
  const rowObj = {};
198
220
  for (const def of columnDefs) {
199
221
  rowObj[def.field] = '';
@@ -260,6 +282,11 @@ const DefaultManagement = {
260
282
  // }
261
283
 
262
284
  setTimeout(() => {
285
+ s(`.management-table-btn-save-${id}`).classList.remove('hide');
286
+ // s(`.management-table-btn-stop-${id}`).classList.remove('hide');
287
+ if (permissions.add) s(`.management-table-btn-add-${id}`).classList.add('hide');
288
+ if (permissions.remove) s(`.management-table-btn-clean-${id}`).classList.add('hide');
289
+ if (permissions.reload) s(`.management-table-btn-reload-${id}`).classList.add('hide');
263
290
  AgGrid.grids[gridId].startEditingCell({
264
291
  rowIndex: 0,
265
292
  colKey: defaultColKeyFocus,
@@ -268,6 +295,15 @@ const DefaultManagement = {
268
295
  });
269
296
  });
270
297
  });
298
+
299
+ EventsUI.onClick(`.management-table-btn-stop-${id}`, async () => {
300
+ s(`.management-table-btn-save-${id}`).classList.add('hide');
301
+ // s(`.management-table-btn-stop-${id}`).classList.add('hide');
302
+ if (permissions.add) s(`.management-table-btn-add-${id}`).classList.remove('hide');
303
+ if (permissions.remove) s(`.management-table-btn-clean-${id}`).classList.remove('hide');
304
+ if (permissions.reload) s(`.management-table-btn-reload-${id}`).classList.remove('hide');
305
+ AgGrid.grids[gridId].stopEditing();
306
+ });
271
307
  EventsUI.onClick(`.management-table-btn-clean-${id}`, async () => {
272
308
  const confirmResult = await Modal.RenderConfirm(
273
309
  {
@@ -292,6 +328,26 @@ const DefaultManagement = {
292
328
  DefaultManagement.loadTable(id);
293
329
  }
294
330
  });
331
+ EventsUI.onClick(`.management-table-btn-reload-${id}`, async () => {
332
+ try {
333
+ // Reload data from server
334
+ await DefaultManagement.loadTable(id);
335
+
336
+ // Other option: Refresh cells to update UI
337
+ // DefaultManagement.refreshTable(id);
338
+
339
+ NotificationManager.Push({
340
+ html: Translate.Render('success-reload-data') || 'Data reloaded successfully',
341
+ status: 'success',
342
+ });
343
+ } catch (error) {
344
+ NotificationManager.Push({
345
+ html: error.message || 'Error reloading data',
346
+ status: 'error',
347
+ });
348
+ } finally {
349
+ }
350
+ });
295
351
  s(`#ag-pagination-${gridId}`).addEventListener('page-change', async (event) => {
296
352
  const token = DefaultManagement.Tokens[id];
297
353
  token.page = event.detail.page;
@@ -318,7 +374,7 @@ const DefaultManagement = {
318
374
  }
319
375
  };
320
376
  }, 1);
321
- return html`<div class="fl">
377
+ return html`<div class="fl management-table-toolbar">
322
378
  ${await BtnIcon.Render({
323
379
  class: `in fll section-mp management-table-btn-mini management-table-btn-add-${id} ${
324
380
  permissions.add ? '' : 'hide'
@@ -327,12 +383,15 @@ const DefaultManagement = {
327
383
  type: 'button',
328
384
  })}
329
385
  ${await BtnIcon.Render({
330
- class: `in fll section-mp management-table-btn-mini management-table-btn-save-${id} ${
331
- permissions.add ? '' : 'hide'
332
- }`,
386
+ class: `in fll section-mp management-table-btn-mini management-table-btn-save-${id} hide`,
333
387
  label: html`<div class="abs center btn-save-${id}-label"><i class="fas fa-save"></i></div> `,
334
388
  type: 'button',
335
389
  })}
390
+ ${await BtnIcon.Render({
391
+ class: `in fll section-mp management-table-btn-mini management-table-btn-stop-${id} hide`,
392
+ label: html`<div class="abs center btn-save-${id}-label"><i class="fa-solid fa-rectangle-xmark"></i></div> `,
393
+ type: 'button',
394
+ })}
336
395
  ${await BtnIcon.Render({
337
396
  class: `in fll section-mp management-table-btn-mini management-table-btn-clean-${id} ${
338
397
  permissions.remove ? '' : 'hide'
@@ -340,12 +399,21 @@ const DefaultManagement = {
340
399
  label: html`<div class="abs center btn-clean-${id}-label"><i class="fas fa-broom"></i></div> `,
341
400
  type: 'button',
342
401
  })}
402
+ ${await BtnIcon.Render({
403
+ class: `in fll section-mp management-table-btn-mini management-table-btn-reload-${id} ${
404
+ permissions.reload ? '' : 'hide'
405
+ }`,
406
+ label: html`<div class="abs center btn-reload-${id}-label"><i class="fas fa-sync-alt"></i></div> `,
407
+ type: 'button',
408
+ })}
343
409
  </div>
344
410
  <div class="in section-mp">
345
411
  ${await AgGrid.Render({
346
412
  id: gridId,
347
413
  parentModal: options.idModal,
348
414
  usePagination: true,
415
+ paginationOptions,
416
+ customHeightOffset: !permissions.add && !permissions.remove && !permissions.reload ? 50 : 0,
349
417
  darkTheme,
350
418
  gridOptions: {
351
419
  defaultColDef: {
@@ -425,6 +493,7 @@ const DefaultManagement = {
425
493
  // rowNode.setData(newRow);
426
494
  // }, 2000);
427
495
  }
496
+ s(`.management-table-btn-save-${id}`).click();
428
497
  }
429
498
  } else {
430
499
  const body = event.data ? event.data : {};
@@ -441,6 +510,7 @@ const DefaultManagement = {
441
510
  }
442
511
  }
443
512
  },
513
+ ...(options.gridOptions ? options.gridOptions : undefined),
444
514
  },
445
515
  })}
446
516
  </div>`;
@@ -42,9 +42,9 @@ class MariaDBService {
42
42
  try {
43
43
  conn = await pool.getConnection();
44
44
  result = await conn.query(query, { supportBigNumbers: true, bigNumberStrings: true });
45
- logger.info(query, result);
45
+ logger.info('query');
46
+ console.log(result);
46
47
  } catch (error) {
47
- if (error.stack.startsWith('TypeError: Do not know how to serialize a BigInt')) return;
48
48
  logger.error(error, error.stack);
49
49
  } finally {
50
50
  if (conn) conn.release(); // release to pool
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ class Underpost {
35
35
  * @type {String}
36
36
  * @memberof Underpost
37
37
  */
38
- static version = 'v2.85.7';
38
+ static version = 'v2.89.0';
39
39
  /**
40
40
  * Repository cli API
41
41
  * @static
@@ -32,6 +32,51 @@ dotenv.config();
32
32
 
33
33
  // Static Site Generation (SSG)
34
34
 
35
+ /**
36
+ * Recursively copies files from source to destination, but only files that don't exist in destination.
37
+ * @function copyNonExistingFiles
38
+ * @param {string} src - Source directory path
39
+ * @param {string} dest - Destination directory path
40
+ * @returns {void}
41
+ * @memberof clientBuild
42
+ */
43
+ const copyNonExistingFiles = (src, dest) => {
44
+ // Ensure source exists
45
+ if (!fs.existsSync(src)) {
46
+ throw new Error(`Source directory does not exist: ${src}`);
47
+ }
48
+
49
+ // Get stats for source
50
+ const srcStats = fs.statSync(src);
51
+
52
+ // If source is a file, copy only if it doesn't exist in destination
53
+ if (srcStats.isFile()) {
54
+ if (!fs.existsSync(dest)) {
55
+ const destDir = dir.dirname(dest);
56
+ fs.mkdirSync(destDir, { recursive: true });
57
+ fs.copyFileSync(src, dest);
58
+ }
59
+ return;
60
+ }
61
+
62
+ // If source is a directory, create destination if it doesn't exist
63
+ if (srcStats.isDirectory()) {
64
+ if (!fs.existsSync(dest)) {
65
+ fs.mkdirSync(dest, { recursive: true });
66
+ }
67
+
68
+ // Read all items in source directory
69
+ const items = fs.readdirSync(src);
70
+
71
+ // Recursively process each item
72
+ for (const item of items) {
73
+ const srcPath = dir.join(src, item);
74
+ const destPath = dir.join(dest, item);
75
+ copyNonExistingFiles(srcPath, destPath);
76
+ }
77
+ }
78
+ };
79
+
35
80
  /**
36
81
  * @async
37
82
  * @function buildClient
@@ -83,6 +128,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
83
128
  * @param {string} options.publicClientId - Public client ID.
84
129
  * @param {boolean} options.iconsBuild - Whether to build icons.
85
130
  * @param {Object} options.metadata - Metadata for the client.
131
+ * @param {boolean} options.publicCopyNonExistingFiles - Whether to copy non-existing files from public directory.
86
132
  * @returns {Promise<void>} - Promise that resolves when the full build is complete.
87
133
  * @throws {Error} - If the full build fails.
88
134
  * @memberof clientBuild
@@ -98,6 +144,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
98
144
  publicClientId,
99
145
  iconsBuild,
100
146
  metadata,
147
+ publicCopyNonExistingFiles,
101
148
  }) => {
102
149
  logger.warn('Full build', rootClientPath);
103
150
 
@@ -169,11 +216,15 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
169
216
  fs.copySync(dist.styles, `${rootClientPath}${dist.public_styles_folder}`);
170
217
  }
171
218
  }
219
+
220
+ if (publicCopyNonExistingFiles)
221
+ copyNonExistingFiles(`./src/client/public/${publicCopyNonExistingFiles}`, rootClientPath);
172
222
  };
173
223
 
174
224
  // { srcBuildPath, publicBuildPath }
175
225
  const enableLiveRebuild =
176
226
  options && options.liveClientBuildPaths && options.liveClientBuildPaths.length > 0 ? true : false;
227
+ const isDevelopment = process.env.NODE_ENV === 'development';
177
228
 
178
229
  let currentPort = parseInt(process.env.PORT) + 1;
179
230
  for (const host of Object.keys(confServer)) {
@@ -205,7 +256,8 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
205
256
  } = confServer[host][path];
206
257
  if (singleReplica) continue;
207
258
  if (!confClient[client]) confClient[client] = {};
208
- const { components, dists, views, services, metadata, publicRef } = confClient[client];
259
+ const { components, dists, views, services, metadata, publicRef, publicCopyNonExistingFiles } =
260
+ confClient[client];
209
261
  let backgroundImage;
210
262
  if (metadata) {
211
263
  backgroundImage = metadata.backgroundImage;
@@ -240,6 +292,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
240
292
  publicClientId,
241
293
  iconsBuild,
242
294
  metadata,
295
+ publicCopyNonExistingFiles,
243
296
  });
244
297
 
245
298
  if (components)
@@ -520,6 +573,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
520
573
  apiBaseHost,
521
574
  apiBasePath: process.env.BASE_API,
522
575
  version: Underpost.version,
576
+ dev: isDevelopment,
523
577
  },
524
578
  renderApi: {
525
579
  JSONweb,
@@ -613,6 +667,7 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
613
667
  apiBaseHost,
614
668
  apiBasePath: process.env.BASE_API,
615
669
  version: Underpost.version,
670
+ dev: isDevelopment,
616
671
  },
617
672
  renderApi: {
618
673
  JSONweb,
@@ -687,4 +742,4 @@ ${fs.readFileSync(`${rootClientPath}/sw.js`, 'utf8')}`,
687
742
  }
688
743
  };
689
744
 
690
- export { buildClient };
745
+ export { buildClient, copyNonExistingFiles };
@@ -192,6 +192,49 @@ export class ObjectLayerEngine {
192
192
  return objectLayerFrameDirections;
193
193
  }
194
194
 
195
+ /**
196
+ * @memberof CyberiaObjectLayer
197
+ * @static
198
+ * @description Processes an image file through frameFactory and adds the resulting frame to the render data structure.
199
+ * Updates the color palette and pushes the frame to all keyframe directions corresponding to the given direction code.
200
+ * Initializes colors array, frames object, and direction arrays if they don't exist.
201
+ * @param {Object} renderData - The render data object containing frames and colors.
202
+ * @param {string} imagePath - The path to the image file to process.
203
+ * @param {string} directionCode - The numerical direction code (e.g., '08', '14').
204
+ * @returns {Promise<Object>} - The updated render data object.
205
+ * @memberof CyberiaObjectLayer
206
+ */
207
+ static async processAndPushFrame(renderData, imagePath, directionCode) {
208
+ // Initialize colors array if it doesn't exist
209
+ if (!renderData.colors) {
210
+ renderData.colors = [];
211
+ }
212
+
213
+ // Initialize frames object if it doesn't exist
214
+ if (!renderData.frames) {
215
+ renderData.frames = {};
216
+ }
217
+
218
+ // Process the image and extract frame matrix and updated colors
219
+ const frameFactoryResult = await ObjectLayerEngine.frameFactory(imagePath, renderData.colors);
220
+
221
+ // Update the colors palette
222
+ renderData.colors = frameFactoryResult.colors;
223
+
224
+ // Get all keyframe directions for this direction code
225
+ const keyframeDirections = ObjectLayerEngine.getKeyFramesDirectionsFromNumberFolderDirection(directionCode);
226
+
227
+ // Push the frame to all corresponding directions
228
+ for (const keyframeDirection of keyframeDirections) {
229
+ if (!renderData.frames[keyframeDirection]) {
230
+ renderData.frames[keyframeDirection] = [];
231
+ }
232
+ renderData.frames[keyframeDirection].push(frameFactoryResult.frame);
233
+ }
234
+
235
+ return renderData;
236
+ }
237
+
195
238
  /**
196
239
  * @memberof CyberiaObjectLayer
197
240
  * @static
@@ -290,5 +333,6 @@ export const readPngAsync = ObjectLayerEngine.readPngAsync;
290
333
  export const frameFactory = ObjectLayerEngine.frameFactory;
291
334
  export const getKeyFramesDirectionsFromNumberFolderDirection =
292
335
  ObjectLayerEngine.getKeyFramesDirectionsFromNumberFolderDirection;
336
+ export const processAndPushFrame = ObjectLayerEngine.processAndPushFrame;
293
337
  export const buildImgFromTile = ObjectLayerEngine.buildImgFromTile;
294
338
  export const generateRandomStats = ObjectLayerEngine.generateRandomStats;
@@ -122,6 +122,12 @@ class UnderpostStartUp {
122
122
  if (options.build === true) await UnderpostStartUp.API.build(deployId, env);
123
123
  if (options.run === true) await UnderpostStartUp.API.run(deployId, env);
124
124
  },
125
+ /**
126
+ * Run itc-scripts and builds client bundle.
127
+ * @param {string} deployId - The ID of the deployment.
128
+ * @param {string} env - The environment of the deployment.
129
+ * @memberof UnderpostStartUp
130
+ */
125
131
  async build(deployId = 'dd-default', env = 'development') {
126
132
  const buildBasePath = `/home/dd`;
127
133
  const repoName = `engine-${deployId.split('-')[1]}`;
@@ -139,6 +145,12 @@ class UnderpostStartUp {
139
145
  }
140
146
  shellExec(`node bin/deploy build-full-client ${deployId}`);
141
147
  },
148
+ /**
149
+ * Runs a deployment.
150
+ * @param {string} deployId - The ID of the deployment.
151
+ * @param {string} env - The environment of the deployment.
152
+ * @memberof UnderpostStartUp
153
+ */
142
154
  async run(deployId = 'dd-default', env = 'development') {
143
155
  const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
144
156
  if (fs.existsSync(`./engine-private/replica`)) {
@@ -21,11 +21,10 @@ const logger = loggerFactory(import.meta);
21
21
  */
22
22
 
23
23
  /**
24
+ * Manages the logic, client map, and event listeners for a specific WebSocket channel,
25
+ * ensuring robust message handling and lifecycle management.
24
26
  * @class IoChannel
25
- * @alias IoChannel
26
27
  * @memberof SocketIoInterface
27
- * @classdesc Manages the logic, client map, and event listeners for a specific WebSocket channel,
28
- * ensuring robust message handling and lifecycle management.
29
28
  */
30
29
  class IoChannel {
31
30
  /**
package/AUTHORS.md DELETED
@@ -1,21 +0,0 @@
1
- # Authors
2
-
3
-
4
- Author: fcoverdugoa <52893447+underpostnet@users.noreply.github.com>
5
-
6
-
7
- Author: fcoverdugoa <fcoverdugoa@underpost.net>
8
-
9
-
10
- Author: fcoverdugo <fcoverdugoa@underpost.net>
11
-
12
-
13
- Author: underpost.net <52893447+underpostnet@users.noreply.github.com>
14
-
15
-
16
- Author: underpostnet <fcoverdugoa@underpost.net>
17
-
18
-
19
-
20
-
21
- #### Generated by [underpost.net](https://underpost.net)
@@ -1,72 +0,0 @@
1
- import Underpost from '../index.js';
2
- import { actionInitLog, loggerFactory } from './logger.js';
3
-
4
- const logger = loggerFactory(import.meta);
5
-
6
- const logRuntimeRouter = () => {
7
- const displayLog = {};
8
-
9
- for (const host of Object.keys(Underpost.deployNetwork))
10
- for (const path of Object.keys(Underpost.deployNetwork[host]))
11
- displayLog[Underpost.deployNetwork[host][path].publicHost] = Underpost.deployNetwork[host][path].local;
12
-
13
- logger.info('Runtime network', displayLog);
14
- };
15
-
16
- const listenServerFactory = (logic = async () => {}) => {
17
- return {
18
- listen: async (...args) => (
19
- setTimeout(() => {
20
- const message = 'Listen server factory timeout';
21
- logger.error(message);
22
- throw new Error(message);
23
- }, 80000000), // ~ 55 days
24
- (logic ? await logic(...args) : undefined, args[1]())
25
- ),
26
- };
27
- };
28
-
29
- const listenPortController = async (server, port, metadata) =>
30
- new Promise((resolve) => {
31
- try {
32
- if (port === ':') {
33
- server.listen(port, actionInitLog);
34
- return resolve(true);
35
- }
36
-
37
- const { host, path, client, runtime, meta } = metadata;
38
- const error = [];
39
- if (port === undefined) error.push(`port`);
40
- if (host === undefined) error.push(`host`);
41
- if (path === undefined) error.push(`path`);
42
- if (client === undefined) error.push(`client`);
43
- if (runtime === undefined) error.push(`runtime`);
44
- if (meta === undefined) error.push(`meta`);
45
- if (error.length > 0) throw new Error('Listen port controller requires values: ' + error.join(', '));
46
-
47
- server.listen(port, () => {
48
- if (!Underpost.deployNetwork[host]) Underpost.deployNetwork[host] = {};
49
- Underpost.deployNetwork[host][path] = {
50
- meta,
51
- client,
52
- runtime,
53
- port,
54
- publicHost:
55
- port === 80
56
- ? `http://${host}${path}`
57
- : port === 443
58
- ? `https://${host}${path}`
59
- : `http://${host}:${port}${path}`,
60
- local: `http://localhost:${port}${path}`,
61
- apis: metadata.apis,
62
- };
63
-
64
- return resolve(true);
65
- });
66
- } catch (error) {
67
- logger.error(error, { metadata, port, stack: error.stack });
68
- resolve(false);
69
- }
70
- });
71
-
72
- export { listenPortController, logRuntimeRouter, listenServerFactory };