underpost 3.2.12 → 3.2.14

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.
package/bin/index.js CHANGED
@@ -6,8 +6,8 @@ import { loggerFactory } from '../src/server/logger.js';
6
6
  const logger = loggerFactory(import.meta);
7
7
 
8
8
  try {
9
- program.parse();
9
+ await program.parseAsync();
10
10
  } catch (error) {
11
11
  logger.error(error);
12
12
  process.exit(1);
13
- }
13
+ }
package/conf.js CHANGED
@@ -95,16 +95,8 @@ const DefaultConf = /**/ {
95
95
  { path: '/default-management', client: 'Default', ssr: 'Default' },
96
96
  { client: 'Default', ssr: 'Default', path: '/404', title: '404 Not Found' },
97
97
  { client: 'Default', ssr: 'Default', path: '/500', title: '500 Server Error' },
98
- {
99
- path: '/blog',
100
- client: 'Default',
101
- ssr: 'Default',
102
- },
103
- {
104
- path: '/chat',
105
- client: 'Default',
106
- ssr: 'Default',
107
- },
98
+ { path: '/blog', client: 'Default', ssr: 'Default' },
99
+ { path: '/chat', client: 'Default', ssr: 'Default' },
108
100
  ],
109
101
  dists: [
110
102
  {
@@ -121,10 +113,7 @@ const DefaultConf = /**/ {
121
113
  import_name_build: '/dist/sortablejs/sortable.complete.esm.js',
122
114
  },
123
115
  { folder: './node_modules/validator', public_folder: '/dist/validator' },
124
- {
125
- folder: './node_modules/easymde/dist',
126
- public_folder: '/dist/easymde',
127
- },
116
+ { folder: './node_modules/easymde/dist', public_folder: '/dist/easymde' },
128
117
  {
129
118
  folder: './node_modules/marked/lib',
130
119
  public_folder: '/dist/marked',
@@ -157,7 +146,6 @@ const DefaultConf = /**/ {
157
146
  import_name: 'dexie',
158
147
  import_name_build: '/dist/dexie/dexie.mjs',
159
148
  },
160
-
161
149
  { folder: './node_modules/peerjs/dist', public_folder: '/dist/peerjs' },
162
150
  ],
163
151
  services: ['default', 'core', 'user', 'test', 'file', 'document'],
@@ -201,40 +189,26 @@ const DefaultConf = /**/ {
201
189
  proxy: [80, 443],
202
190
  db: {
203
191
  provider: 'env:DB_PROVIDER:mongoose',
204
- host: 'env:DB_HOST:mongodb://mongodb-0.mongodb-service:27017',
192
+ host: 'env:DB_HOST:mongodb://127.0.0.1:27017',
205
193
  name: 'env:DB_NAME:default',
206
194
  replicaSet: 'env:DB_REPLICA_SET:rs0',
195
+ authSource: 'env:DB_AUTH_SOURCE:admin',
196
+ user: 'env:DB_USER:',
197
+ password: 'env:DB_PASSWORD:',
207
198
  },
208
199
  mailer: {
209
- sender: {
210
- email: 'env:MAILER_SENDER_EMAIL:noreply@default.net',
211
- name: 'env:MAILER_SENDER_NAME:Default',
212
- },
200
+ sender: { email: 'env:MAILER_SENDER_EMAIL:noreply@default.net', name: 'env:MAILER_SENDER_NAME:Default' },
213
201
  transport: {
214
202
  host: 'env:SMTP_HOST:smtp.default.com',
215
203
  port: 'env:SMTP_PORT:int:465',
216
204
  secure: 'env:SMTP_SECURE:bool:true',
217
- auth: {
218
- user: 'env:SMTP_AUTH_USER:',
219
- pass: 'env:SMTP_AUTH_PASS:',
220
- },
205
+ auth: { user: 'env:SMTP_AUTH_USER:', pass: 'env:SMTP_AUTH_PASS:' },
221
206
  },
222
207
  },
223
- valkey: {
224
- port: 'env:VALKEY_PORT:int:6379',
225
- host: 'env:VALKEY_HOST:127.0.0.1',
226
- },
227
- },
228
- },
229
- 'www.default.net': {
230
- '/': {
231
- client: null,
232
- runtime: 'nodejs',
233
- apis: [],
234
- origins: [],
235
- proxy: [80, 443],
208
+ valkey: { port: 'env:VALKEY_PORT:int:6379', host: 'env:VALKEY_HOST:127.0.0.1' },
236
209
  },
237
210
  },
211
+ 'www.default.net': { '/': { client: null, runtime: 'nodejs', apis: [], origins: [], proxy: [80, 443] } },
238
212
  },
239
213
  cron: {
240
214
  records: {
@@ -23,14 +23,14 @@ spec:
23
23
  spec:
24
24
  containers:
25
25
  - name: dd-cron-backup
26
- image: underpost/underpost-engine:v3.2.12
26
+ image: underpost/underpost-engine:v3.2.14
27
27
  command:
28
28
  - /bin/sh
29
29
  - -c
30
30
  - >
31
31
  cd /home/dd/engine &&
32
32
  node bin env dd-cron production &&
33
- node bin cron dd-lampp,dd-cyberia,dd-core,dd-test backup --git --kubeadm
33
+ node bin cron dd-lampp,dd-cyberia,dd-core,dd-prototype,dd-test backup --git --kubeadm
34
34
  volumeMounts:
35
35
  - mountPath: /home/dd/engine
36
36
  name: underpost-cron-container-volume
@@ -23,7 +23,7 @@ spec:
23
23
  spec:
24
24
  containers:
25
25
  - name: dd-cron-dns
26
- image: underpost/underpost-engine:v3.2.12
26
+ image: underpost/underpost-engine:v3.2.14
27
27
  command:
28
28
  - /bin/sh
29
29
  - -c
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-default-development-blue
20
- image: underpost/underpost-engine:v3.2.12
20
+ image: underpost/underpost-engine:v3.2.14
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "124Ki"
@@ -98,7 +98,7 @@ spec:
98
98
  spec:
99
99
  containers:
100
100
  - name: dd-default-development-green
101
- image: underpost/underpost-engine:v3.2.12
101
+ image: underpost/underpost-engine:v3.2.14
102
102
  # resources:
103
103
  # requests:
104
104
  # memory: "124Ki"
package/package.json CHANGED
@@ -2,12 +2,13 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "underpost",
5
- "version": "3.2.12",
5
+ "version": "3.2.14",
6
6
  "description": "Underpost Platform — end-to-end CI/CD and application-delivery toolchain CLI. Covers bare metal, Kubernetes, K3s, kubeadm, LXD, container/image orchestration, secrets, databases, cron jobs, monitoring, SSH, runners, PWA + Workbox delivery, and release orchestration. Extensible via downstream CLIs.",
7
7
  "scripts": {
8
8
  "start": "node --max-old-space-size=8192 src/server",
9
9
  "build": "node bin client",
10
10
  "test": "NODE_ENV=test c8 mocha",
11
+ "test:monitor": "NODE_ENV=test c8 mocha test/deploy-monitor.test.js",
11
12
  "dev": "NODE_ENV=development nodemon src/server",
12
13
  "dev:container": "NODE_ENV=development node src/server",
13
14
  "prod:container": "NODE_ENV=production node src/server",
@@ -45,18 +46,12 @@
45
46
  "k3s",
46
47
  "kubeadm",
47
48
  "lxd",
48
- "bare-metal",
49
+ "baremetal",
49
50
  "container-orchestration",
50
51
  "image-management",
51
52
  "pwa",
52
53
  "workbox",
53
- "microservices",
54
- "template",
55
- "builder",
56
- "engine",
57
- "server",
58
- "proxy",
59
- "client"
54
+ "microservices"
60
55
  ],
61
56
  "author": "https://github.com/underpostnet",
62
57
  "license": "MIT",
@@ -78,12 +73,12 @@
78
73
  "clipboardy": "^5.3.1",
79
74
  "cloudinary": "^2.10.0",
80
75
  "colors": "^1.4.0",
81
- "commander": "^14.0.3",
76
+ "commander": "^15.0.0",
82
77
  "compression": "^1.7.4",
83
78
  "cookie-parser": "^1.4.7",
84
79
  "cors": "^2.8.6",
85
80
  "d3": "^7.9.0",
86
- "dexie": "^4.2.1",
81
+ "dexie": "^4.4.3",
87
82
  "dotenv": "^17.4.2",
88
83
  "easymde": "^2.21.0",
89
84
  "esbuild": "^0.28.0",
@@ -93,7 +88,7 @@
93
88
  "express-rate-limit": "^8.5.2",
94
89
  "express-slow-down": "^3.1.0",
95
90
  "fast-json-stable-stringify": "^2.1.0",
96
- "favicons": "^7.2.0",
91
+ "favicons": "^7.3.0",
97
92
  "fs-extra": "^11.3.5",
98
93
  "fullcalendar": "^6.1.15",
99
94
  "helmet": "^8.2.0",
@@ -106,9 +101,9 @@
106
101
  "mariadb": "^3.2.2",
107
102
  "mocha": "^11.7.6",
108
103
  "marked": "^18.0.4",
109
- "mongoose": "^9.6.2",
104
+ "mongoose": "^9.6.3",
110
105
  "morgan": "^1.10.0",
111
- "nodemailer": "^8.0.9",
106
+ "nodemailer": "^8.0.10",
112
107
  "nodemon": "^3.0.1",
113
108
  "peer": "^1.0.2",
114
109
  "peerjs": "^1.5.5",
package/src/cli/deploy.js CHANGED
@@ -20,7 +20,6 @@ import { loggerFactory } from '../server/logger.js';
20
20
  import { shellExec } from '../server/process.js';
21
21
  import fs from 'fs-extra';
22
22
  import dotenv from 'dotenv';
23
- import { timer } from '../client/components/core/CommonJs.js';
24
23
  import os from 'node:os';
25
24
  import Underpost from '../index.js';
26
25
 
@@ -827,59 +826,6 @@ EOF`);
827
826
  }
828
827
  }
829
828
  },
830
- /**
831
- * Checks the status of a deployment.
832
- * @param {string} deployId - Deployment ID for which the status is being checked.
833
- * @param {string} env - Environment for which the status is being checked.
834
- * @param {string} traffic - Current traffic status for the deployment.
835
- * @param {Array<string>} ignoresNames - List of pod names to ignore.
836
- * @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
837
- * @returns {object} - Object containing the status of the deployment.
838
- * @memberof UnderpostDeploy
839
- */
840
- async checkDeploymentReadyStatus(deployId, env, traffic, ignoresNames = [], namespace = 'default') {
841
- const pods = Underpost.kubectl.get(`${deployId}-${env}-${traffic}`, 'pods', namespace);
842
- const readyPods = [];
843
- const notReadyPods = [];
844
-
845
- // Readiness signal: the pod's Kubernetes `Ready` condition driven by the
846
- // container's readinessProbe (TCP socket, HTTP get, or exec). Set by kubelet
847
- // when the probe passes. A failed or crashing runtime never becomes Ready —
848
- // kubelet surfaces CrashLoopBackOff and this gate stays closed.
849
- for (const pod of pods) {
850
- const { NAME } = pod;
851
- if (ignoresNames && ignoresNames.find((t) => NAME.trim().toLowerCase().match(t.trim().toLowerCase()))) continue;
852
-
853
- let podJson = null;
854
- try {
855
- // Pod may not exist yet (between deployment apply and pod
856
- // scheduling). silentOnError lets the monitor loop continue
857
- // instead of aborting on the transient NotFound exit.
858
- const raw = shellExec(`sudo kubectl get pod ${NAME} -n ${namespace} -o json`, {
859
- silent: true,
860
- disableLog: true,
861
- stdout: true,
862
- silentOnError: true,
863
- });
864
- podJson = raw ? JSON.parse(raw) : null;
865
- } catch (_) {
866
- podJson = null;
867
- }
868
- const conditions = podJson?.status?.conditions || [];
869
- const readyCondition = conditions.find((c) => c.type === 'Ready');
870
- const k8sReady = readyCondition?.status === 'True';
871
-
872
- pod.out = JSON.stringify({ k8sReady, condition: readyCondition ?? null });
873
-
874
- if (k8sReady) readyPods.push(pod);
875
- else notReadyPods.push(pod);
876
- }
877
- return {
878
- ready: pods.length > 0 && notReadyPods.length === 0,
879
- notReadyPods,
880
- readyPods,
881
- };
882
- },
883
829
  /**
884
830
  * Creates a Kubernetes Secret for a deployment (replaces configMap for secret data).
885
831
  * Secrets are mounted as tmpfs (never written to node disk) and support RBAC restrictions.
@@ -1139,180 +1085,6 @@ spec:
1139
1085
  env === 'production' &&
1140
1086
  options.cert === true &&
1141
1087
  (!options.certHosts || options.certHosts.split(',').includes(host)),
1142
- /**
1143
- * Monitors the ready status of a deployment.
1144
- *
1145
- * Ready signal:
1146
- * The orchestrator gate is the Kubernetes pod Ready condition. When the
1147
- * container's `readinessProbe` succeeds, kubelet flips
1148
- * `status.conditions[Ready]` to True and `checkDeploymentReadyStatus`
1149
- * returns the pod in `readyPods`. This is the only required signal — see
1150
- * `src/client/public/nexodev/docs/references/Deploy custom instance to K8S.md`.
1151
- *
1152
- * Container-status:
1153
- * `underpost config get container-status` is read from each pod for both
1154
- * the display column and as a second ready gate alongside the K8S Ready
1155
- * condition. Both must be satisfied before the monitor exits:
1156
- * 1. K8S readinessProbe (TCP socket) — ensures the port is bound.
1157
- * 2. container-status == `<deploy>-<env>-running-deployment` — ensures
1158
- * the application has completed its own startup sequence.
1159
- * Early-abort on `error` container-status remains in effect.
1160
- *
1161
- * @param {string} deployId - Deployment ID for which the ready status is being monitored.
1162
- * @param {string} env - Environment for which the ready status is being monitored.
1163
- * @param {string} targetTraffic - Target traffic status for the deployment.
1164
- * @param {Array<string>} ignorePods - List of pod names to ignore.
1165
- * @param {string} [namespace='default'] - Kubernetes namespace for the deployment.
1166
- * @returns {object} - Object containing the ready status of the deployment.
1167
- * @memberof UnderpostDeploy
1168
- */
1169
- async monitorReadyRunner(deployId, env, targetTraffic, ignorePods = [], namespace = 'default') {
1170
- const delayMs = 1000;
1171
- const maxIterations = 3000;
1172
- const deploymentId = `${deployId}-${env}-${targetTraffic}`;
1173
- const expectedContainerStatus = `${deployId}-${env}-running-deployment`;
1174
- const tag = `[${deploymentId}]`;
1175
- const containerStatusDefault = 'waiting for status';
1176
-
1177
- logger.info('Deployment init', { deployId, env, targetTraffic, namespace });
1178
-
1179
- // Per-pod cache of last-known container-status (persists across retries)
1180
- const podStatusCache = new Map();
1181
-
1182
- const readContainerStatus = (podName) => {
1183
- try {
1184
- const raw = shellExec(
1185
- `sudo kubectl exec ${podName} -n ${namespace} -- sh -c 'underpost config get container-status --plain'`,
1186
- { silent: true, disableLog: true, stdout: true, silentOnError: true },
1187
- );
1188
- const val = raw ? raw.toString().trim() : '';
1189
- return val && val !== 'undefined' ? val : containerStatusDefault;
1190
- } catch (_) {
1191
- // exec failed (e.g. pod not yet running) — preserve last known value
1192
- return podStatusCache.get(podName) || containerStatusDefault;
1193
- }
1194
- };
1195
-
1196
- for (let i = 0; i < maxIterations; i++) {
1197
- const result = await Underpost.deploy.checkDeploymentReadyStatus(
1198
- deployId,
1199
- env,
1200
- targetTraffic,
1201
- ignorePods,
1202
- namespace,
1203
- );
1204
-
1205
- const allPods = [...result.readyPods, ...result.notReadyPods];
1206
-
1207
- // Update cache with latest status for each pod (informational + error gate)
1208
- for (const pod of allPods) {
1209
- if (!pod?.NAME) continue;
1210
- const status = readContainerStatus(pod.NAME);
1211
- if (status === 'error') throw new Error(`Pod ${pod.NAME} has error status`);
1212
- podStatusCache.set(pod.NAME, status);
1213
- }
1214
-
1215
- const allPodsK8sReady = allPods.length > 0 && result.notReadyPods.length === 0;
1216
-
1217
- const allPodsStatusReady =
1218
- allPods.length > 0 && allPods.every((pod) => podStatusCache.get(pod.NAME) === expectedContainerStatus);
1219
-
1220
- // Print snapshot for every pod — annotate when container-status hasn't caught
1221
- // up to the K8S Ready condition yet.
1222
- for (const pod of allPods) {
1223
- const status = podStatusCache.get(pod.NAME) || containerStatusDefault;
1224
- const podStatus = pod.STATUS || 'Unknown';
1225
- const statusMatchesExpected = status === expectedContainerStatus;
1226
- const statusDisplay = statusMatchesExpected ? status : `${status} (pending)`;
1227
-
1228
- console.log(
1229
- 'Target pod:',
1230
- pod.NAME[pod.NAME.includes('green') ? 'bgGreen' : 'bgBlue'].bold.black,
1231
- '| Pod status:',
1232
- podStatus.bold.yellow,
1233
- '| Runtime status:',
1234
- statusDisplay.bold.cyan,
1235
- );
1236
- }
1237
-
1238
- // Both K8S readinessProbe AND container-status must be satisfied before
1239
- // declaring the deployment ready. The TCP probe ensures the port is bound;
1240
- // container-status == running-deployment ensures the application has
1241
- // completed its own startup sequence so traffic is not switched prematurely.
1242
- if (allPodsK8sReady && allPodsStatusReady) {
1243
- logger.info(`${tag} | All pods Ready (K8S readinessProbe satisfied)`);
1244
- return result;
1245
- }
1246
-
1247
- await timer(delayMs);
1248
-
1249
- if ((i + 1) % 10 === 0) {
1250
- logger.info(`${tag} | In progress... iteration ${i + 1}`);
1251
- }
1252
- }
1253
-
1254
- logger.error(`${tag} | Deployment timeout after ${maxIterations} iterations`);
1255
- throw new Error(
1256
- `monitorReadyRunner timeout: ${deploymentId} did not become Ready within ${maxIterations}*${delayMs}ms`,
1257
- );
1258
- },
1259
-
1260
- /**
1261
- * Retrieves the currently loaded images in the Kubernetes cluster.
1262
- * @param {string} [node='kind-worker'] - Node name to check for loaded images.
1263
- * @param {object} options - Options for the image retrieval.
1264
- * @param {boolean} options.spec - Whether to retrieve images from the pod specifications.
1265
- * @param {string} options.namespace - Kubernetes namespace to filter pods.
1266
- * @returns {Array<object>} - Array of objects containing pod names and their corresponding images.
1267
- * @memberof UnderpostDeploy
1268
- */
1269
- getCurrentLoadedImages(node = 'kind-worker', options = { spec: false, namespace: '' }) {
1270
- if (options.spec) {
1271
- const raw = shellExec(
1272
- `kubectl get pods ${options.namespace ? `--namespace ${options.namespace}` : `--all-namespaces`} -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.namespace}{"/"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
1273
- {
1274
- stdout: true,
1275
- silent: true,
1276
- },
1277
- );
1278
- return raw
1279
- .split(`\n`)
1280
- .map((lines) => ({
1281
- pod: lines.split('\t')[0].replaceAll(':', '').trim(),
1282
- image: lines.split('\t')[1] ? lines.split('\t')[1].replaceAll(',', '').trim() : null,
1283
- }))
1284
- .filter((o) => o.image);
1285
- }
1286
- const raw = shellExec(node === 'kind-worker' ? `docker exec -i ${node} crictl images` : `crictl images`, {
1287
- stdout: true,
1288
- silent: true,
1289
- });
1290
-
1291
- const heads = raw
1292
- .split(`\n`)[0]
1293
- .split(' ')
1294
- .filter((_r) => _r.trim());
1295
-
1296
- const pods = raw
1297
- .split(`\n`)
1298
- .filter((r) => !r.match('IMAGE'))
1299
- .map((r) => r.split(' ').filter((_r) => _r.trim()));
1300
-
1301
- const result = [];
1302
-
1303
- for (const row of pods) {
1304
- if (row.length === 0) continue;
1305
- const pod = {};
1306
- let index = -1;
1307
- for (const head of heads) {
1308
- if (head in pod) continue;
1309
- index++;
1310
- pod[head] = row[index];
1311
- }
1312
- result.push(pod);
1313
- }
1314
- return result;
1315
- },
1316
1088
 
1317
1089
  /**
1318
1090
  * Predefined resource templates for Kubernetes deployments.
package/src/cli/image.js CHANGED
@@ -122,6 +122,63 @@ class UnderpostImage {
122
122
  else if (kubeadm === true) shellExec(`sudo ctr -n k8s.io images import ${tarFile}`);
123
123
  else if (k3s === true) shellExec(`sudo k3s ctr images import ${tarFile}`);
124
124
  },
125
+ /**
126
+ * @method getCurrentLoaded
127
+ * @description Retrieves the currently loaded images in the Kubernetes cluster.
128
+ * @param {string} [node='kind-worker'] - Node name to check for loaded images.
129
+ * @param {object} options - Options for the image retrieval.
130
+ * @param {boolean} options.spec - Whether to retrieve images from the pod specifications.
131
+ * @param {string} options.namespace - Kubernetes namespace to filter pods.
132
+ * @returns {Array<object>} - Array of objects containing pod names and their corresponding images.
133
+ * @memberof UnderpostImage
134
+ */
135
+ getCurrentLoaded(node = 'kind-worker', options = { spec: false, namespace: '' }) {
136
+ if (options.spec) {
137
+ const raw = shellExec(
138
+ `kubectl get pods ${options.namespace ? `--namespace ${options.namespace}` : `--all-namespaces`} -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.namespace}{"/"}{.metadata.name}{":\\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}'`,
139
+ {
140
+ stdout: true,
141
+ silent: true,
142
+ },
143
+ );
144
+ return raw
145
+ .split(`\n`)
146
+ .map((lines) => ({
147
+ pod: lines.split('\t')[0].replaceAll(':', '').trim(),
148
+ image: lines.split('\t')[1] ? lines.split('\t')[1].replaceAll(',', '').trim() : null,
149
+ }))
150
+ .filter((o) => o.image);
151
+ }
152
+ const raw = shellExec(node === 'kind-worker' ? `docker exec -i ${node} crictl images` : `crictl images`, {
153
+ stdout: true,
154
+ silent: true,
155
+ });
156
+
157
+ const heads = raw
158
+ .split(`\n`)[0]
159
+ .split(' ')
160
+ .filter((_r) => _r.trim());
161
+
162
+ const pods = raw
163
+ .split(`\n`)
164
+ .filter((r) => !r.match('IMAGE'))
165
+ .map((r) => r.split(' ').filter((_r) => _r.trim()));
166
+
167
+ const result = [];
168
+
169
+ for (const row of pods) {
170
+ if (row.length === 0) continue;
171
+ const pod = {};
172
+ let index = -1;
173
+ for (const head of heads) {
174
+ if (head in pod) continue;
175
+ index++;
176
+ pod[head] = row[index];
177
+ }
178
+ result.push(pod);
179
+ }
180
+ return result;
181
+ },
125
182
  /**
126
183
  * @method list
127
184
  * @description Lists currently loaded Docker images in the specified Kubernetes cluster node.
@@ -139,10 +196,7 @@ class UnderpostImage {
139
196
  list(options = { nodeName: '', namespace: '', spec: false, log: false, k3s: false, kubeadm: false, kind: false }) {
140
197
  if ((options.kubeadm === true || options.k3s === true) && !options.nodeName)
141
198
  options.nodeName = shellExec('echo $HOSTNAME', { stdout: true, silent: true }).trim();
142
- const list = Underpost.deploy.getCurrentLoadedImages(
143
- options.nodeName ? options.nodeName : 'kind-worker',
144
- options,
145
- );
199
+ const list = Underpost.image.getCurrentLoaded(options.nodeName ? options.nodeName : 'kind-worker', options);
146
200
  if (options.log) console.table(list);
147
201
  return list;
148
202
  },