@shopware-ag/dive 1.18.5-beta.3 → 1.18.5
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/README.md +1 -1
- package/build/dive.cjs +3856 -1
- package/build/dive.cjs.map +1 -1
- package/build/dive.js +24728 -6
- package/build/dive.js.map +1 -1
- package/build/src/com/Communication.d.ts +1 -4
- package/build/src/module/Module.d.ts +8 -0
- package/package.json +2 -2
- package/src/com/Communication.ts +17 -84
- package/src/com/__test__/Communication.test.ts +43 -16
- package/src/module/Module.ts +45 -0
- package/src/module/__test__/Module.test.ts +54 -0
- package/build/AR-BzVanQ-t.js +0 -722
- package/build/AR-BzVanQ-t.js.map +0 -1
- package/build/AR-ySzrfSW3.cjs +0 -2
- package/build/AR-ySzrfSW3.cjs.map +0 -1
- package/build/IO-BTWL9Zfp.cjs +0 -19
- package/build/IO-BTWL9Zfp.cjs.map +0 -1
- package/build/IO-CYzpSt1J.js +0 -1289
- package/build/IO-CYzpSt1J.js.map +0 -1
- package/build/MediaCreator-BFa3Xfwk.js +0 -22
- package/build/MediaCreator-BFa3Xfwk.js.map +0 -1
- package/build/MediaCreator-BqLcaXbl.cjs +0 -2
- package/build/MediaCreator-BqLcaXbl.cjs.map +0 -1
- package/build/dive-BTQZqHRt.cjs +0 -3857
- package/build/dive-BTQZqHRt.cjs.map +0 -1
- package/build/dive-Dk0rFfvA.js +0 -24852
- package/build/dive-Dk0rFfvA.js.map +0 -1
|
@@ -34,16 +34,13 @@ export declare class DIVECommunication {
|
|
|
34
34
|
private controller;
|
|
35
35
|
private toolbox;
|
|
36
36
|
private _mediaGenerator;
|
|
37
|
-
private get mediaGenerator();
|
|
38
37
|
private _io;
|
|
39
|
-
private get io();
|
|
40
38
|
private _ar;
|
|
41
|
-
private get ar();
|
|
42
39
|
private registered;
|
|
43
40
|
private listeners;
|
|
44
41
|
constructor(renderer: DIVERenderer, scene: DIVEScene, controls: DIVEOrbitControls, toolbox: DIVEToolbox);
|
|
45
42
|
DestroyInstance(): boolean;
|
|
46
|
-
PerformAction<Action extends keyof Actions>(action: Action, payload
|
|
43
|
+
PerformAction<Action extends keyof Actions>(action: Action, payload?: Actions[Action]['PAYLOAD']): Actions[Action]['RETURN'];
|
|
47
44
|
Subscribe<Action extends keyof Actions>(type: Action, listener: EventListener<Action>): Unsubscribe;
|
|
48
45
|
private dispatch;
|
|
49
46
|
private getAllSceneData;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopware-ag/dive",
|
|
3
|
-
"version": "1.18.5
|
|
3
|
+
"version": "1.18.5",
|
|
4
4
|
"description": "Shopware Spatial Framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/dive.cjs",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"ts-jest": "^29.1.2",
|
|
52
52
|
"ts-node": "^10.9.2",
|
|
53
53
|
"tsc": "^2.0.4",
|
|
54
|
-
"typescript": "^5.
|
|
54
|
+
"typescript": "^5.8.2",
|
|
55
55
|
"typescript-eslint": "^7.7.1",
|
|
56
56
|
"vite": "^6.2.1",
|
|
57
57
|
"vite-plugin-dts": "^4.5.3"
|
package/src/com/Communication.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Actions } from './actions/index.ts';
|
|
|
2
2
|
import { generateUUID } from 'three/src/math/MathUtils';
|
|
3
3
|
import { isSelectTool } from '../toolbox/select/SelectTool.ts';
|
|
4
4
|
import { merge } from 'lodash';
|
|
5
|
+
import { DIVEModule } from '../module/Module.ts';
|
|
5
6
|
|
|
6
7
|
// type imports
|
|
7
8
|
import { type Color, type MeshStandardMaterial } from 'three';
|
|
@@ -74,80 +75,13 @@ export class DIVECommunication {
|
|
|
74
75
|
private controller: DIVEOrbitControls;
|
|
75
76
|
private toolbox: DIVEToolbox;
|
|
76
77
|
|
|
77
|
-
private _mediaGenerator: DIVEMediaCreator
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
.then((module) => {
|
|
83
|
-
const DIVEMediaCreator = module.DIVEMediaCreator;
|
|
84
|
-
this._mediaGenerator = new DIVEMediaCreator(
|
|
85
|
-
this.renderer,
|
|
86
|
-
this.scene,
|
|
87
|
-
this.controller,
|
|
88
|
-
);
|
|
89
|
-
resolve(this._mediaGenerator);
|
|
90
|
-
})
|
|
91
|
-
.catch((error) => {
|
|
92
|
-
console.error(
|
|
93
|
-
'DIVE: Error while lazy-loading IO module:',
|
|
94
|
-
error,
|
|
95
|
-
);
|
|
96
|
-
reject(error);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
return Promise.resolve(this._mediaGenerator);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private _io: DIVEIO | null;
|
|
104
|
-
private get io(): Promise<DIVEIO> {
|
|
105
|
-
if (!this._io) {
|
|
106
|
-
return new Promise((resolve, reject) => {
|
|
107
|
-
import('../io/IO.ts')
|
|
108
|
-
.then((module) => {
|
|
109
|
-
const DIVEIO = module.DIVEIO;
|
|
110
|
-
this._io = new DIVEIO(this.scene);
|
|
111
|
-
resolve(this._io);
|
|
112
|
-
})
|
|
113
|
-
.catch((error) => {
|
|
114
|
-
console.error(
|
|
115
|
-
'DIVE: Error while lazy-loading IO module:',
|
|
116
|
-
error,
|
|
117
|
-
);
|
|
118
|
-
reject(error);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return Promise.resolve(this._io);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private _ar: DIVEAR | null;
|
|
126
|
-
private get ar(): Promise<DIVEAR> {
|
|
127
|
-
if (!this._ar) {
|
|
128
|
-
return new Promise((resolve, reject) => {
|
|
129
|
-
import('../ar/AR.ts')
|
|
130
|
-
.then((module) => {
|
|
131
|
-
const DIVEAR = module.DIVEAR;
|
|
132
|
-
this._ar = new DIVEAR(
|
|
133
|
-
this.renderer,
|
|
134
|
-
this.scene,
|
|
135
|
-
this.controller,
|
|
136
|
-
);
|
|
137
|
-
resolve(this._ar);
|
|
138
|
-
})
|
|
139
|
-
.catch((error) => {
|
|
140
|
-
console.error(
|
|
141
|
-
'DIVE: Error while lazy-loading AR module:',
|
|
142
|
-
error,
|
|
143
|
-
);
|
|
144
|
-
reject(error);
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
}
|
|
78
|
+
private _mediaGenerator: DIVEModule<DIVEMediaCreator> = new DIVEModule(
|
|
79
|
+
'../mediacreator/MediaCreator.ts',
|
|
80
|
+
'DIVEMediaCreator',
|
|
81
|
+
);
|
|
82
|
+
private _io: DIVEModule<DIVEIO> = new DIVEModule('../io/IO.ts', 'DIVEIO');
|
|
148
83
|
|
|
149
|
-
|
|
150
|
-
}
|
|
84
|
+
private _ar: DIVEModule<DIVEAR> = new DIVEModule('../ar/AR.ts', 'DIVEAR');
|
|
151
85
|
|
|
152
86
|
private registered: Map<string, COMEntity> = new Map();
|
|
153
87
|
|
|
@@ -166,9 +100,6 @@ export class DIVECommunication {
|
|
|
166
100
|
this.scene = scene;
|
|
167
101
|
this.controller = controls;
|
|
168
102
|
this.toolbox = toolbox;
|
|
169
|
-
this._mediaGenerator = null;
|
|
170
|
-
this._io = null;
|
|
171
|
-
this._ar = null;
|
|
172
103
|
|
|
173
104
|
DIVECommunication.__instances.push(this);
|
|
174
105
|
}
|
|
@@ -184,7 +115,7 @@ export class DIVECommunication {
|
|
|
184
115
|
|
|
185
116
|
public PerformAction<Action extends keyof Actions>(
|
|
186
117
|
action: Action,
|
|
187
|
-
payload
|
|
118
|
+
payload?: Actions[Action]['PAYLOAD'],
|
|
188
119
|
): Actions[Action]['RETURN'] {
|
|
189
120
|
let returnValue: Actions[Action]['RETURN'] = false;
|
|
190
121
|
|
|
@@ -353,10 +284,11 @@ export class DIVECommunication {
|
|
|
353
284
|
}
|
|
354
285
|
case 'LAUNCH_AR': {
|
|
355
286
|
returnValue = new Promise<void>((resolve, reject) => {
|
|
356
|
-
this.
|
|
357
|
-
.
|
|
287
|
+
this._ar
|
|
288
|
+
.get()
|
|
289
|
+
.then((ar) => {
|
|
358
290
|
resolve(
|
|
359
|
-
|
|
291
|
+
ar.Launch(
|
|
360
292
|
payload as Actions['LAUNCH_AR']['PAYLOAD'],
|
|
361
293
|
),
|
|
362
294
|
);
|
|
@@ -784,7 +716,7 @@ export class DIVECommunication {
|
|
|
784
716
|
target = payload.target;
|
|
785
717
|
}
|
|
786
718
|
|
|
787
|
-
return this.
|
|
719
|
+
return this._mediaGenerator.get().then((module) => {
|
|
788
720
|
return module.GenerateMedia(
|
|
789
721
|
position,
|
|
790
722
|
target,
|
|
@@ -858,9 +790,10 @@ export class DIVECommunication {
|
|
|
858
790
|
payload: Actions['EXPORT_SCENE']['PAYLOAD'],
|
|
859
791
|
): Actions['EXPORT_SCENE']['RETURN'] {
|
|
860
792
|
return new Promise<string | null>((resolve, reject) => {
|
|
861
|
-
this.
|
|
862
|
-
.
|
|
863
|
-
|
|
793
|
+
this._io
|
|
794
|
+
.get()
|
|
795
|
+
.then((io) => {
|
|
796
|
+
resolve(io.Export(payload.type));
|
|
864
797
|
})
|
|
865
798
|
.catch(reject);
|
|
866
799
|
});
|
|
@@ -32,36 +32,47 @@ import {
|
|
|
32
32
|
type COMLight,
|
|
33
33
|
type COMModel,
|
|
34
34
|
type COMPov,
|
|
35
|
-
type COMPrimitive,
|
|
36
35
|
} from '../types';
|
|
37
36
|
import { type DIVESceneObject } from '../../types';
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
const mockModule: Record<string, any> = {
|
|
39
|
+
get: jest.fn().mockReturnValue(Promise.resolve({})),
|
|
40
|
+
};
|
|
41
|
+
jest.mock('../../module/Module', () => {
|
|
40
42
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
DIVEModule: jest.fn().mockImplementation(() => {
|
|
44
|
+
return mockModule;
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
});
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
jest.mock('../../mediacreator/MediaCreator', () => {
|
|
50
|
+
return {
|
|
51
|
+
DIVEMediaCreator: jest.fn().mockImplementation(() => {
|
|
52
|
+
return {
|
|
53
|
+
GenerateMedia: jest.fn(),
|
|
54
|
+
};
|
|
45
55
|
}),
|
|
46
56
|
};
|
|
47
57
|
});
|
|
48
58
|
|
|
49
59
|
jest.mock('../../io/IO', () => {
|
|
50
60
|
return {
|
|
51
|
-
DIVEIO: jest.fn(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
DIVEIO: jest.fn().mockImplementation(() => {
|
|
62
|
+
return {
|
|
63
|
+
Import: jest.fn(),
|
|
64
|
+
Export: jest.fn(),
|
|
65
|
+
};
|
|
55
66
|
}),
|
|
56
67
|
};
|
|
57
68
|
});
|
|
58
69
|
|
|
59
70
|
jest.mock('../../ar/AR', () => {
|
|
60
71
|
return {
|
|
61
|
-
DIVEAR: jest.fn(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
DIVEAR: jest.fn().mockImplementation(() => {
|
|
73
|
+
return {
|
|
74
|
+
Launch: jest.fn(),
|
|
75
|
+
};
|
|
65
76
|
}),
|
|
66
77
|
};
|
|
67
78
|
});
|
|
@@ -194,12 +205,14 @@ const mockToolBox = {
|
|
|
194
205
|
}),
|
|
195
206
|
SetGizmoMode: jest.fn(),
|
|
196
207
|
SetGizmoVisibility: jest.fn(),
|
|
208
|
+
SetGizmoScaleLinked: jest.fn(),
|
|
197
209
|
} as unknown as DIVEToolbox;
|
|
198
210
|
|
|
199
211
|
let testCom: DIVECommunication;
|
|
200
212
|
|
|
201
213
|
describe('dive/communication/DIVECommunication', () => {
|
|
202
214
|
beforeEach(() => {
|
|
215
|
+
jest.clearAllMocks();
|
|
203
216
|
testCom = new DIVECommunication(
|
|
204
217
|
mockRenderer,
|
|
205
218
|
mockScene,
|
|
@@ -797,6 +810,11 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
797
810
|
expect(visibility).toBe(false);
|
|
798
811
|
});
|
|
799
812
|
|
|
813
|
+
it('should perform action SET_GIZMO_SCALE_LINKED', () => {
|
|
814
|
+
const success = testCom.PerformAction('SET_GIZMO_SCALE_LINKED', true);
|
|
815
|
+
expect(success).toBe(true);
|
|
816
|
+
});
|
|
817
|
+
|
|
800
818
|
it('should perform action USE_TOOL', () => {
|
|
801
819
|
let success = testCom.PerformAction('USE_TOOL', { tool: 'select' });
|
|
802
820
|
expect(success).toBe(true);
|
|
@@ -844,7 +862,10 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
844
862
|
|
|
845
863
|
it('should perform action GENERATE_MEDIA', async () => {
|
|
846
864
|
const blobUri = 'blob:http://localhost:3000/1234';
|
|
847
|
-
|
|
865
|
+
jest.spyOn(mockModule, 'get').mockResolvedValue({
|
|
866
|
+
GenerateMedia: jest.fn(),
|
|
867
|
+
});
|
|
868
|
+
const mediaGeneratorModule = await testCom['_mediaGenerator'].get();
|
|
848
869
|
|
|
849
870
|
jest.spyOn(mediaGeneratorModule, 'GenerateMedia').mockReturnValue(
|
|
850
871
|
blobUri,
|
|
@@ -962,7 +983,10 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
962
983
|
|
|
963
984
|
it('should perform action EXPORT_SCENE', async () => {
|
|
964
985
|
const url = 'https://example.com';
|
|
965
|
-
|
|
986
|
+
jest.spyOn(mockModule, 'get').mockResolvedValue({
|
|
987
|
+
Export: jest.fn(),
|
|
988
|
+
});
|
|
989
|
+
const ioModule = await testCom['_io'].get();
|
|
966
990
|
|
|
967
991
|
jest.spyOn(ioModule, 'Export').mockResolvedValueOnce(url);
|
|
968
992
|
|
|
@@ -973,7 +997,10 @@ describe('dive/communication/DIVECommunication', () => {
|
|
|
973
997
|
});
|
|
974
998
|
|
|
975
999
|
it('should perform action LAUNCH_AR', async () => {
|
|
976
|
-
|
|
1000
|
+
jest.spyOn(mockModule, 'get').mockResolvedValue({
|
|
1001
|
+
Launch: jest.fn(),
|
|
1002
|
+
});
|
|
1003
|
+
const arModule = await testCom['_ar'].get();
|
|
977
1004
|
const arLaunchSpy = jest
|
|
978
1005
|
.spyOn(arModule, 'Launch')
|
|
979
1006
|
.mockResolvedValueOnce();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export class DIVEModule<T> {
|
|
2
|
+
constructor(
|
|
3
|
+
private _path: string,
|
|
4
|
+
private _ctor: string,
|
|
5
|
+
) {}
|
|
6
|
+
|
|
7
|
+
private _promise: Promise<T> | null = null;
|
|
8
|
+
private _instance: T | null = null;
|
|
9
|
+
|
|
10
|
+
public async get(): Promise<T> {
|
|
11
|
+
// if we already have an instance, return it
|
|
12
|
+
if (this._instance) {
|
|
13
|
+
return Promise.resolve(this._instance);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// if we already have a loading process ongoing, return the already created promise
|
|
17
|
+
if (this._promise) {
|
|
18
|
+
return this._promise;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// if we don't have a promise yet, it means that we are not already loading the module
|
|
22
|
+
this._promise = (async () => {
|
|
23
|
+
const module = await import(this._path);
|
|
24
|
+
|
|
25
|
+
const ModuleConstructor = module[this._ctor];
|
|
26
|
+
|
|
27
|
+
if (!ModuleConstructor) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`DIVE: Module class ${this._ctor} not found in ${this._path}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof ModuleConstructor !== 'function') {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`DIVE: Module at ${this._path} does not export a valid constructor (${this._ctor} wanted)`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this._instance = new ModuleConstructor() as T;
|
|
40
|
+
return this._instance;
|
|
41
|
+
})();
|
|
42
|
+
|
|
43
|
+
return this._promise;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DIVEModule } from '../Module';
|
|
2
|
+
|
|
3
|
+
jest.mock('/mock/path', () => mockModule, { virtual: true });
|
|
4
|
+
|
|
5
|
+
const mockModule: Record<string, any> = {};
|
|
6
|
+
|
|
7
|
+
describe('dive/module/DIVEModule', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
// Reset the mock module before each test
|
|
10
|
+
Object.keys(mockModule).forEach((key) => delete mockModule[key]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should return the same instance on multiple calls to get()', async () => {
|
|
14
|
+
mockModule.TestClass = class TestClass {};
|
|
15
|
+
const diveModule = new DIVEModule('/mock/path', 'TestClass');
|
|
16
|
+
|
|
17
|
+
const instance1 = await diveModule.get();
|
|
18
|
+
const instance2 = await diveModule.get();
|
|
19
|
+
|
|
20
|
+
expect(instance1).toBe(instance2);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should throw an error if the constructor is not found', async () => {
|
|
24
|
+
const diveModule = new DIVEModule('/mock/path', 'NonExistentClass');
|
|
25
|
+
|
|
26
|
+
await expect(diveModule.get()).rejects.toThrow(
|
|
27
|
+
'DIVE: Module class NonExistentClass not found in /mock/path',
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should throw an error if the constructor is not a function', async () => {
|
|
32
|
+
mockModule.InvalidClass = {};
|
|
33
|
+
const diveModule = new DIVEModule('/mock/path', 'InvalidClass');
|
|
34
|
+
|
|
35
|
+
await expect(diveModule.get()).rejects.toThrow(
|
|
36
|
+
'DIVE: Module at /mock/path does not export a valid constructor (InvalidClass wanted)',
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should only load the module once even with concurrent calls to get()', async () => {
|
|
41
|
+
mockModule.TestClass = class TestClass {};
|
|
42
|
+
const diveModule = new DIVEModule('/mock/path', 'TestClass');
|
|
43
|
+
|
|
44
|
+
const [
|
|
45
|
+
instance1,
|
|
46
|
+
instance2,
|
|
47
|
+
] = await Promise.all([
|
|
48
|
+
diveModule.get(),
|
|
49
|
+
diveModule.get(),
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
expect(instance1).toBe(instance2);
|
|
53
|
+
});
|
|
54
|
+
});
|