cyberia 3.0.1 → 3.0.2
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/.github/workflows/engine-cyberia.cd.yml +1 -0
- package/CHANGELOG.md +56 -1
- package/CLI-HELP.md +2 -4
- package/README.md +139 -0
- package/bin/build.js +5 -0
- package/bin/cyberia.js +385 -71
- package/bin/deploy.js +18 -26
- package/bin/file.js +3 -0
- package/bin/index.js +385 -71
- package/conf.js +32 -3
- package/deployment.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/ipfs/configmap.yaml +7 -0
- package/package.json +8 -8
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +2 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +7 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +93 -2
- package/src/api/file/file.controller.js +3 -13
- package/src/api/file/file.ref.json +0 -21
- package/src/api/ipfs/ipfs.controller.js +104 -0
- package/src/api/ipfs/ipfs.model.js +71 -0
- package/src/api/ipfs/ipfs.router.js +31 -0
- package/src/api/ipfs/ipfs.service.js +193 -0
- package/src/api/object-layer/README.md +139 -0
- package/src/api/object-layer/object-layer.controller.js +3 -0
- package/src/api/object-layer/object-layer.model.js +15 -1
- package/src/api/object-layer/object-layer.router.js +6 -10
- package/src/api/object-layer/object-layer.service.js +311 -182
- package/src/cli/cluster.js +30 -38
- package/src/cli/index.js +0 -1
- package/src/cli/run.js +14 -0
- package/src/client/components/core/LoadingAnimation.js +2 -3
- package/src/client/components/core/Modal.js +1 -1
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +4 -5
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +280 -29
- package/src/client/services/ipfs/ipfs.service.js +144 -0
- package/src/client/services/object-layer/object-layer.management.js +161 -8
- package/src/index.js +1 -1
- package/src/runtime/express/Express.js +1 -1
- package/src/server/auth.js +18 -18
- package/src/server/ipfs-client.js +433 -0
- package/src/server/object-layer.js +649 -18
- package/src/server/semantic-layer-generator.js +1083 -0
- package/src/server/shape-generator.js +952 -0
- package/test/shape-generator.test.js +457 -0
- package/bin/ssl.js +0 -63
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { DefaultManagement } from '../default/default.management.js';
|
|
2
2
|
import { ObjectLayerService } from './object-layer.service.js';
|
|
3
|
-
import { commonUserGuard } from '../../components/core/CommonJs.js';
|
|
3
|
+
import { commonUserGuard, commonModeratorGuard } from '../../components/core/CommonJs.js';
|
|
4
4
|
import { getProxyPath, setPath, setQueryParams } from '../../components/core/Router.js';
|
|
5
5
|
import { ObjectLayerEngineModal } from '../../components/cyberia/ObjectLayerEngineModal.js';
|
|
6
6
|
import { ObjectLayerEngineViewer } from '../../components/cyberia/ObjectLayerEngineViewer.js';
|
|
7
7
|
import { s } from '../../components/core/VanillaJs.js';
|
|
8
8
|
import { Modal } from '../../components/core/Modal.js';
|
|
9
9
|
import { BtnIcon } from '../../components/core/BtnIcon.js';
|
|
10
|
+
import { NotificationManager } from '../../components/core/NotificationManager.js';
|
|
11
|
+
import { AgGrid } from '../../components/core/AgGrid.js';
|
|
10
12
|
|
|
11
13
|
const ObjectLayerManagement = {
|
|
12
|
-
RenderTable: async ({ Elements, idModal }) => {
|
|
14
|
+
RenderTable: async ({ Elements, idModal: rawIdModal }) => {
|
|
15
|
+
const idModal = rawIdModal || 'modal-object-layer-engine-management';
|
|
16
|
+
const serviceId = 'object-layer-engine-management';
|
|
17
|
+
const gridId = `${serviceId}-grid-${idModal}`;
|
|
13
18
|
const user = Elements.Data.user.main.model.user;
|
|
14
19
|
const { role } = user;
|
|
15
20
|
|
|
@@ -41,9 +46,9 @@ const ObjectLayerManagement = {
|
|
|
41
46
|
// Navigate to viewer route first
|
|
42
47
|
setPath(`${getProxyPath()}object-layer-engine-viewer`);
|
|
43
48
|
// Then add query param without replacing history
|
|
44
|
-
setQueryParams({
|
|
49
|
+
setQueryParams({ id: data._id }, { replace: true });
|
|
45
50
|
if (s(`.modal-object-layer-engine-viewer`)) {
|
|
46
|
-
await ObjectLayerEngineViewer.Reload({ Elements });
|
|
51
|
+
await ObjectLayerEngineViewer.Reload({ Elements, force: true });
|
|
47
52
|
}
|
|
48
53
|
s(`.main-btn-object-layer-engine-viewer`).click();
|
|
49
54
|
});
|
|
@@ -87,7 +92,7 @@ const ObjectLayerManagement = {
|
|
|
87
92
|
// Navigate to editor route first
|
|
88
93
|
setPath(`${getProxyPath()}object-layer-engine`);
|
|
89
94
|
// Then add query param without replacing history
|
|
90
|
-
setQueryParams({
|
|
95
|
+
setQueryParams({ id: data._id }, { replace: true });
|
|
91
96
|
if (s(`.modal-object-layer-engine`)) await ObjectLayerEngineModal.Reload();
|
|
92
97
|
else s(`.main-btn-object-layer-engine`).click();
|
|
93
98
|
});
|
|
@@ -148,6 +153,123 @@ const ObjectLayerManagement = {
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
156
|
+
// Custom renderer for delete button (moderator+ only)
|
|
157
|
+
const canDelete = commonModeratorGuard(role);
|
|
158
|
+
|
|
159
|
+
class DeleteButtonRenderer {
|
|
160
|
+
eGui;
|
|
161
|
+
|
|
162
|
+
async init(params) {
|
|
163
|
+
this.eGui = document.createElement('div');
|
|
164
|
+
const { data } = params;
|
|
165
|
+
|
|
166
|
+
if (!data || !data._id || !canDelete) {
|
|
167
|
+
this.eGui.innerHTML = '';
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.eGui.innerHTML = html` ${await BtnIcon.Render({
|
|
172
|
+
label: html`<div class="abs center">
|
|
173
|
+
<i class="fas fa-trash" style="color: #dc3545;"></i>
|
|
174
|
+
</div> `,
|
|
175
|
+
class: `in fll section-mp management-table-btn-mini btn-delete-object-layer-${data._id}`,
|
|
176
|
+
})}`;
|
|
177
|
+
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
const btn = this.eGui.querySelector(`.btn-delete-object-layer-${data._id}`);
|
|
180
|
+
if (btn)
|
|
181
|
+
btn.onclick = async () => {
|
|
182
|
+
const itemId = data?.data?.item?.id || data._id;
|
|
183
|
+
const confirmResult = await Modal.RenderConfirm({
|
|
184
|
+
id: `delete-object-layer-${data._id}`,
|
|
185
|
+
html: async () => html`
|
|
186
|
+
<div class="in section-mp" style="text-align: center">
|
|
187
|
+
<p>Are you sure you want to permanently delete object layer <strong>"${itemId}"</strong>?</p>
|
|
188
|
+
<p style="color: #dc3545; font-size: 13px; margin-top: 8px;">
|
|
189
|
+
This will remove all associated data including render frames, atlas sprite sheet, IPFS pins, and
|
|
190
|
+
static asset files.
|
|
191
|
+
</p>
|
|
192
|
+
</div>
|
|
193
|
+
`,
|
|
194
|
+
});
|
|
195
|
+
if (confirmResult.status !== 'confirm') return;
|
|
196
|
+
try {
|
|
197
|
+
const result = await ObjectLayerService.delete({ id: data._id });
|
|
198
|
+
if (result.status === 'success') {
|
|
199
|
+
NotificationManager.Push({
|
|
200
|
+
html: `Object layer "${itemId}" deleted successfully`,
|
|
201
|
+
status: 'success',
|
|
202
|
+
});
|
|
203
|
+
if (AgGrid.grids[gridId]) {
|
|
204
|
+
AgGrid.grids[gridId].applyTransaction({ remove: [data] });
|
|
205
|
+
}
|
|
206
|
+
const token = DefaultManagement.Tokens[idModal];
|
|
207
|
+
if (token) {
|
|
208
|
+
const newTotal = token.total - 1;
|
|
209
|
+
const newTotalPages = Math.ceil(newTotal / token.limit);
|
|
210
|
+
if (token.page > newTotalPages && newTotalPages > 0) {
|
|
211
|
+
token.page = newTotalPages;
|
|
212
|
+
}
|
|
213
|
+
await DefaultManagement.loadTable(idModal, { reload: false });
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
throw new Error(result.message || 'Failed to delete object layer');
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
NotificationManager.Push({
|
|
220
|
+
html: `Failed to delete: ${error.message}`,
|
|
221
|
+
status: 'error',
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
getGui() {
|
|
229
|
+
return this.eGui;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
refresh(params) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const createCidRenderer = (cidAccessor) => {
|
|
238
|
+
return class {
|
|
239
|
+
eGui;
|
|
240
|
+
|
|
241
|
+
async init(params) {
|
|
242
|
+
this.eGui = document.createElement('div');
|
|
243
|
+
const { data } = params;
|
|
244
|
+
const cid = cidAccessor(data) || '';
|
|
245
|
+
|
|
246
|
+
if (!cid) {
|
|
247
|
+
this.eGui.innerHTML = html`<span style="color: #666; font-style: italic;">—</span>`;
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
this.eGui.innerHTML = html`<span
|
|
252
|
+
title="${cid}"
|
|
253
|
+
style="font-family: monospace; font-size: 11px; cursor: default; user-select: all;"
|
|
254
|
+
>${cid}</span
|
|
255
|
+
>`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getGui() {
|
|
259
|
+
return this.eGui;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
refresh(params) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// IPFS CID of object layer data JSON (fast-json-stable-stringify)
|
|
269
|
+
const CidRenderer = createCidRenderer((d) => d?.cid);
|
|
270
|
+
// IPFS CID of the consolidated atlas sprite sheet PNG
|
|
271
|
+
const AtlasCidRenderer = createCidRenderer((d) => d?.data?.atlasSpriteSheetCid || d?.atlasSpriteSheetId?.cid);
|
|
272
|
+
|
|
151
273
|
let columnDefs = [
|
|
152
274
|
// {
|
|
153
275
|
// field: '_id',
|
|
@@ -163,6 +285,24 @@ const ObjectLayerManagement = {
|
|
|
163
285
|
},
|
|
164
286
|
{ field: 'data.item.type', headerName: 'Item Type', editable: role === 'user' },
|
|
165
287
|
{ field: 'data.item.description', headerName: 'Description', flex: 1, editable: role === 'user' },
|
|
288
|
+
{
|
|
289
|
+
field: 'cid',
|
|
290
|
+
headerName: 'IPFS CID',
|
|
291
|
+
width: 160,
|
|
292
|
+
cellRenderer: CidRenderer,
|
|
293
|
+
editable: false,
|
|
294
|
+
sortable: false,
|
|
295
|
+
filter: false,
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
field: 'data.atlasSpriteSheetCid',
|
|
299
|
+
headerName: 'Atlas CID',
|
|
300
|
+
width: 160,
|
|
301
|
+
cellRenderer: AtlasCidRenderer,
|
|
302
|
+
editable: false,
|
|
303
|
+
sortable: false,
|
|
304
|
+
filter: false,
|
|
305
|
+
},
|
|
166
306
|
{
|
|
167
307
|
field: 'frame08',
|
|
168
308
|
headerName: 'Frame 08 Preview',
|
|
@@ -190,15 +330,28 @@ const ObjectLayerManagement = {
|
|
|
190
330
|
sortable: false,
|
|
191
331
|
filter: false,
|
|
192
332
|
},
|
|
333
|
+
...(canDelete
|
|
334
|
+
? [
|
|
335
|
+
{
|
|
336
|
+
field: 'delete',
|
|
337
|
+
headerName: '',
|
|
338
|
+
width: 100,
|
|
339
|
+
cellRenderer: DeleteButtonRenderer,
|
|
340
|
+
editable: false,
|
|
341
|
+
sortable: false,
|
|
342
|
+
filter: false,
|
|
343
|
+
},
|
|
344
|
+
]
|
|
345
|
+
: []),
|
|
193
346
|
];
|
|
194
347
|
|
|
195
348
|
return await DefaultManagement.RenderTable({
|
|
196
|
-
idModal
|
|
197
|
-
serviceId
|
|
349
|
+
idModal,
|
|
350
|
+
serviceId,
|
|
198
351
|
entity: 'object-layer',
|
|
199
352
|
permissions: {
|
|
200
353
|
add: commonUserGuard(role),
|
|
201
|
-
remove:
|
|
354
|
+
remove: false,
|
|
202
355
|
reload: commonUserGuard(role),
|
|
203
356
|
},
|
|
204
357
|
customEvent: {
|
package/src/index.js
CHANGED
|
@@ -99,7 +99,7 @@ class ExpressService {
|
|
|
99
99
|
|
|
100
100
|
if (origins && isDevProxyContext())
|
|
101
101
|
origins.push(devProxyHostFactory({ host, includeHttp: true, tls: isTlsDevProxy() }));
|
|
102
|
-
app.set('trust proxy',
|
|
102
|
+
app.set('trust proxy', 1);
|
|
103
103
|
|
|
104
104
|
app.use((req, res, next) => {
|
|
105
105
|
res.on('finish', () => {
|
package/src/server/auth.js
CHANGED
|
@@ -647,24 +647,24 @@ function applySecurity(app, opts = {}) {
|
|
|
647
647
|
}),
|
|
648
648
|
);
|
|
649
649
|
logger.info('Cors origin', origin);
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
650
|
+
if (!process.env.DISABLE_API_RATE_LIMIT) {
|
|
651
|
+
// Rate limiting + slow down
|
|
652
|
+
const limiter = rateLimit({
|
|
653
|
+
windowMs: rate.windowMs,
|
|
654
|
+
max: rate.max,
|
|
655
|
+
standardHeaders: true,
|
|
656
|
+
legacyHeaders: false,
|
|
657
|
+
message: { error: 'Too many requests, please try again later.' },
|
|
658
|
+
});
|
|
659
|
+
app.use(limiter);
|
|
660
|
+
|
|
661
|
+
const speedLimiter = slowDown({
|
|
662
|
+
windowMs: slowdown.windowMs,
|
|
663
|
+
delayAfter: slowdown.delayAfter,
|
|
664
|
+
delayMs: () => slowdown.delayMs,
|
|
665
|
+
});
|
|
666
|
+
app.use(speedLimiter);
|
|
667
|
+
}
|
|
668
668
|
// Cookie parsing
|
|
669
669
|
app.use(cookieParser(process.env.JWT_SECRET));
|
|
670
670
|
}
|