@vctrl/hooks 0.25.0 → 1.0.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 (46) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +110 -67
  3. package/index.cjs +1 -0
  4. package/index.d.ts +2 -1
  5. package/index.es.js +4 -4
  6. package/package.json +18 -10
  7. package/{chunk-CMqjfN_6.cjs → rolldown-runtime-BocRIvOZ.cjs} +1 -1
  8. package/use-export-model/use-export-model.d.ts +1 -1
  9. package/use-export-model-CORoAKbf.cjs +1 -0
  10. package/{use-export-model-efFsSWe-.js → use-export-model-DXesLypI.js} +1 -1
  11. package/use-export-model.cjs +1 -0
  12. package/use-export-model.es.js +1 -1
  13. package/use-load-model/error-helpers.d.ts +5 -0
  14. package/use-load-model/file-loaders.d.ts +11 -12
  15. package/use-load-model/index.d.ts +1 -1
  16. package/use-load-model/load-context.d.ts +17 -0
  17. package/use-load-model/optimizer-ingest.d.ts +8 -0
  18. package/use-load-model/optimizer-integration.d.ts +3 -4
  19. package/use-load-model/scene-loaders.d.ts +15 -0
  20. package/use-load-model/state.d.ts +14 -14
  21. package/use-load-model/types.d.ts +154 -131
  22. package/use-load-model/use-load-model.d.ts +12 -8
  23. package/use-load-model/utils/index.d.ts +1 -1
  24. package/use-load-model/utils/reconstruct-files.d.ts +27 -5
  25. package/use-load-model/utils/resolve-scene-payload.d.ts +9 -0
  26. package/use-load-model-CRDVzrPC.js +635 -0
  27. package/use-load-model-CZCi6bPM.cjs +1 -0
  28. package/use-load-model.cjs +1 -0
  29. package/use-load-model.es.js +1 -1
  30. package/use-optimize-model/index.d.ts +1 -0
  31. package/use-optimize-model/types.d.ts +3 -1
  32. package/use-optimize-model/use-optimize-model.d.ts +11 -6
  33. package/use-optimize-model-Fwew6qD8.cjs +1 -0
  34. package/{use-optimize-model-D16-4Zwm.js → use-optimize-model-sNXkORNg.js} +94 -76
  35. package/use-optimize-model.cjs +1 -0
  36. package/use-optimize-model.es.js +2 -2
  37. package/utils/server-communication.d.ts +0 -5
  38. package/index.cjs.js +0 -1
  39. package/use-export-model-yQWV3O3H.cjs +0 -1
  40. package/use-export-model.cjs.js +0 -1
  41. package/use-load-model/event-system.d.ts +0 -7
  42. package/use-load-model-B8oqou4I.cjs +0 -1
  43. package/use-load-model-C88r8-HE.js +0 -585
  44. package/use-load-model.cjs.js +0 -1
  45. package/use-optimize-model-CD5zqTLK.cjs +0 -1
  46. package/use-optimize-model.cjs.js +0 -1
@@ -22,18 +22,21 @@ export interface WorkerResultMeta {
22
22
  * - Progress tracking and error handling
23
23
  * - Optimization reports with before/after metrics
24
24
  *
25
+ * Every method runs on the calling thread. To move the geometry passes off the main
26
+ * thread, run this hook inside a worker you own and hand the result back through
27
+ * `loadFromGlbBuffer(bytes, meta)`, as the Vectreal Platform does.
28
+ *
25
29
  * @example
26
30
  * const optimizer = useOptimizeModel()
27
31
  *
28
32
  * // Load a GLB into the optimizer
29
33
  * await optimizer.loadFromGlbBuffer(glbBytes)
30
34
  *
31
- * // Geometry optimizations run via Web Worker (use-optimization-process.ts)
32
- * // Texture compression runs browser-native via texturesOptimization()
33
- * await optimizer.texturesOptimization({ targetFormat: 'webp', quality: 0.8 })
35
+ * // quality is a 0-100 scale
36
+ * await optimizer.texturesOptimization({ targetFormat: 'webp', quality: 80 })
34
37
  *
35
- * // Sync result back to the Three.js viewer
36
- * await optimizer.applyOptimization()
38
+ * // Syncing the result back into the viewer is `applyOptimization`, which lives on
39
+ * // the object useLoadModel(optimizer) returns, not on this hook.
37
40
  *
38
41
  * @returns Object containing optimization methods, state, and report data
39
42
  */
@@ -47,7 +50,9 @@ declare const useOptimizeModel: () => {
47
50
  */
48
51
  load: (model: Object3D) => Promise<void>;
49
52
  loadFromServerSceneData: (sceneData: ServerSceneData) => Promise<void>;
50
- loadFromGlbBuffer: (buffer: Uint8Array, meta?: WorkerResultMeta) => Promise<void>;
53
+ loadFromGlbBuffer: (buffer: Uint8Array, meta?: WorkerResultMeta, options?: {
54
+ preserveBaseline?: boolean;
55
+ }) => Promise<void>;
51
56
  loadFromGLTFWithAssets: (gltfBytes: Uint8Array, assets: Map<string, Uint8Array>) => Promise<void>;
52
57
  /**
53
58
  * Retrieves the current model as a binary Uint8Array in glTF (.glb) format.
@@ -0,0 +1 @@
1
+ let e=require("react"),t=require("@vctrl/core"),n=require("@vctrl/core/model-optimizer");var r={error:null,loading:!1,report:null},i=(e,t)=>{switch(t.type){case`LOAD_START`:return{...e,loading:!0,error:null};case`LOAD_SUCCESS`:return{...e,loading:!1,report:t.payload.report};case`LOAD_ERROR`:return{...e,loading:!1,error:t.payload};case`RESET`:return{...r};default:return e}};function a(e){return e?{verticesCount:e.stats.verticesCount.after??0,primitivesCount:e.stats.primitivesCount.after??0,meshesCount:e.stats.meshesCount.after??0,textureAssetCount:e.stats.texturesCount.after??0,materialsCount:e.stats.materialsCount.after??0,sceneBytes:e.optimizedSize??0}:{verticesCount:0,primitivesCount:0,meshesCount:0,textureAssetCount:0,materialsCount:0,sceneBytes:0}}var o=t=>{let[n,r]=(0,e.useState)(null),i=t.report;return(0,e.useEffect)(()=>{!n&&i&&r(i)},[n,i]),{info:(0,e.useMemo)(()=>{let e=a(n),t=a(i);return{initial:{verticesCount:e.verticesCount,primitivesCount:e.primitivesCount,meshesCount:e.meshesCount,texturesCount:e.textureAssetCount,sceneBytes:e.sceneBytes},optimized:{verticesCount:t.verticesCount,primitivesCount:t.primitivesCount,meshesCount:t.meshesCount,texturesCount:t.textureAssetCount,sceneBytes:t.sceneBytes},improvement:{verticesCount:e.verticesCount-t.verticesCount,primitivesCount:e.primitivesCount-t.primitivesCount,meshesCount:e.meshesCount-t.meshesCount,texturesCount:e.textureAssetCount-t.textureAssetCount,sceneBytes:e.sceneBytes-t.sceneBytes}}},[i,n]),reset:(0,e.useCallback)(()=>{r(null)},[])}};async function s(e,t){let n=new Blob([e]),r=await createImageBitmap(n),{width:i,height:a}=r;if(t.maxWidth||t.maxHeight){let e=t.maxWidth?t.maxWidth/i:1/0,n=t.maxHeight?t.maxHeight/a:1/0,r=Math.min(e,n,1);r<1&&(i=Math.round(i*r),a=Math.round(a*r))}let o=new OffscreenCanvas(i,a),s=o.getContext(`2d`);if(!s)throw r.close(),Error(`OffscreenCanvas 2D context unavailable`);s.drawImage(r,0,0,i,a),r.close();let c=t.format===`webp`?`image/webp`:t.format===`jpeg`?`image/jpeg`:`image/png`,l=await o.convertToBlob({type:c,quality:t.quality/100});return new Uint8Array(await l.arrayBuffer())}function c(){return function(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),n=`webp`,r=80,i,a,o={resize(e,t,n){return i=e,a=t,o},webp(e){return n=`webp`,typeof e?.quality==`number`&&(r=e.quality),o},jpeg(e){return n=`jpeg`,typeof e?.quality==`number`&&(r=e.quality),o},png(e){return n=`png`,o},toFormat(e,t){return(e===`webp`||e===`jpeg`||e===`png`)&&(n=e),typeof t?.quality==`number`&&(r=t.quality),o},async toBuffer(){return s(t,{format:n,quality:r,maxWidth:i,maxHeight:a})},async metadata(){let e=new Blob([t]),n=await createImageBitmap(e),r={width:n.width,height:n.height,format:`unknown`};return n.close(),r}};return o}}var l=async(e,t)=>{e.hasModel()&&await e.compressTextures({...t,encoder:c()})},u=()=>{let[a,s]=(0,e.useReducer)(i,r),{report:c,error:u,loading:d}=a,{info:f,reset:p}=o(a),m=(0,e.useRef)(new n.ModelOptimizer);(0,e.useEffect)(()=>{let e=m.current;return()=>{e.reset()}},[]);let h=(0,e.useCallback)(async e=>{s({type:`LOAD_START`});try{let t=m.current;await t.loadFromThreeJS(e);let n=await t.getReport();s({type:`LOAD_SUCCESS`,payload:{report:n}})}catch(e){s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading model:`,e)}},[]),g=(0,e.useCallback)(async e=>{if(s({type:`LOAD_START`}),!e.gltfJson)throw Error(`Cannot optimize a scene loaded from a published GLB: it has no glTF document.`);try{let n=m.current,r=new Map;for(let n of Object.values(e.assetData??{}))for(let e of(0,t.buildAssetLookupKeys)(n.fileName))r.set(e,n);let i={},a=e.gltfJson,o=[...(a.images??[]).map(e=>e.uri).filter(e=>!!e&&!e.startsWith(`data:`)),...(a.buffers??[]).map(e=>e.uri).filter(e=>!!e&&!e.startsWith(`data:`))];for(let e of o){let n=(0,t.normalizeAssetUri)(e),a=n.split(`/`).pop()||n,o=r.get(e)??r.get(n)??r.get(a);o&&(i[e]=(0,t.toSerializedAssetBytes)(o))}let c={json:e.gltfJson,resources:i};await n.loadFromJSON(c);let l=await n.getReport();s({type:`LOAD_SUCCESS`,payload:{report:l}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading server scene into optimizer:`,e),e}},[]),_=(0,e.useCallback)(async(e,t,n)=>{s({type:`LOAD_START`});try{let r=n?.preserveBaseline?m.current.getBaseline():null;await m.current.loadFromBuffer(e),r&&m.current.setBaseline(r),m.current.setAppliedOptimizations(t?.appliedOptimizations??[]),m.current.setDracoReport(t?.dracoReport??null);let i=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:i}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading GLB buffer into optimizer:`,e),e}},[]),v=(0,e.useCallback)(async(e,t)=>{s({type:`LOAD_START`});try{await m.current.loadFromGLTFWithAssets(e,t);let n=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:n}})}catch(e){throw s({type:`LOAD_ERROR`,payload:e}),console.error(`Error loading GLTF with assets into optimizer:`,e),e}},[]),y=(0,e.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.simplify(e);let t=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:t}})}catch(e){console.error(`Simplification failed:`,e)}},[]),b=(0,e.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.deduplicate(e);let t=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:t}})}catch(e){console.error(`Deduplication failed:`,e)}},[]),x=(0,e.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.quantize(e);let t=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:t}})}catch(e){console.error(`Quantization failed:`,e)}},[]),S=(0,e.useCallback)(async e=>{if(m.current.hasModel())try{await m.current.optimizeNormals(e);let t=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:t}})}catch(e){console.error(`Normals optimization failed:`,e)}},[]),C=(0,e.useCallback)(async e=>{try{await l(m.current,e);let t=await m.current.getReport();s({type:`LOAD_SUCCESS`,payload:{report:t}})}catch(e){throw console.error(`Texture optimization failed:`,e),e}},[]),w=(0,e.useCallback)(async()=>{if(!m.current.hasModel())return null;try{return await m.current.export()}catch(e){return console.error(`Error getting model binary:`,e),null}},[]),T=(0,e.useCallback)(()=>m.current.hasModel()?m.current.document:null,[]);return{load:h,loadFromServerSceneData:g,loadFromGlbBuffer:_,loadFromGLTFWithAssets:v,getModel:w,isReady:!!T()&&!d,_getDocument:T,reset:(0,e.useCallback)(()=>{m.current.reset(),s({type:`RESET`}),p()},[p]),error:u,loading:d,report:c,info:f,simplifyOptimization:y,dedupOptimization:b,quantizeOptimization:x,normalsOptimization:S,texturesOptimization:C}};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return u}});
@@ -1,9 +1,8 @@
1
- import { buildAssetLookupKeys as e, normalizeAssetUri as t, toSerializedAssetBytes as n } from "@vctrl/core";
2
- import { useCallback as r, useEffect as i, useMemo as a, useReducer as o, useRef as s, useState as c } from "react";
1
+ import { useCallback as e, useEffect as t, useMemo as n, useReducer as r, useRef as i, useState as a } from "react";
2
+ import { buildAssetLookupKeys as o, normalizeAssetUri as s, toSerializedAssetBytes as c } from "@vctrl/core";
3
3
  import { ModelOptimizer as l } from "@vctrl/core/model-optimizer";
4
4
  //#region packages/hooks/src/use-optimize-model/state.ts
5
5
  var u = {
6
- info: null,
7
6
  error: null,
8
7
  loading: !1,
9
8
  report: null
@@ -32,11 +31,11 @@ var u = {
32
31
  //#region packages/hooks/src/use-optimize-model/use-calc-optimization-info.ts
33
32
  function f(e) {
34
33
  return e ? {
35
- verticesCount: e.stats.vertices.after ?? 0,
36
- primitivesCount: e.stats.triangles.after ?? 0,
37
- meshesCount: e.stats.meshes.after ?? 0,
34
+ verticesCount: e.stats.verticesCount.after ?? 0,
35
+ primitivesCount: e.stats.primitivesCount.after ?? 0,
36
+ meshesCount: e.stats.meshesCount.after ?? 0,
38
37
  textureAssetCount: e.stats.texturesCount.after ?? 0,
39
- materialsCount: e.stats.materials.after ?? 0,
38
+ materialsCount: e.stats.materialsCount.after ?? 0,
40
39
  sceneBytes: e.optimizedSize ?? 0
41
40
  } : {
42
41
  verticesCount: 0,
@@ -47,13 +46,13 @@ function f(e) {
47
46
  sceneBytes: 0
48
47
  };
49
48
  }
50
- var p = (e) => {
51
- let [t, n] = c(null), o = e.report;
52
- return i(() => {
53
- !t && o && n(o);
54
- }, [t, o]), {
55
- info: a(() => {
56
- let e = f(t), n = f(o);
49
+ var p = (r) => {
50
+ let [i, o] = a(null), s = r.report;
51
+ return t(() => {
52
+ !i && s && o(s);
53
+ }, [i, s]), {
54
+ info: n(() => {
55
+ let e = f(i), t = f(s);
57
56
  return {
58
57
  initial: {
59
58
  verticesCount: e.verticesCount,
@@ -63,23 +62,23 @@ var p = (e) => {
63
62
  sceneBytes: e.sceneBytes
64
63
  },
65
64
  optimized: {
66
- verticesCount: n.verticesCount,
67
- primitivesCount: n.primitivesCount,
68
- meshesCount: n.meshesCount,
69
- texturesCount: n.textureAssetCount,
70
- sceneBytes: n.sceneBytes
65
+ verticesCount: t.verticesCount,
66
+ primitivesCount: t.primitivesCount,
67
+ meshesCount: t.meshesCount,
68
+ texturesCount: t.textureAssetCount,
69
+ sceneBytes: t.sceneBytes
71
70
  },
72
71
  improvement: {
73
- verticesCount: e.verticesCount - n.verticesCount,
74
- primitivesCount: e.primitivesCount - n.primitivesCount,
75
- meshesCount: e.meshesCount - n.meshesCount,
76
- texturesCount: e.textureAssetCount - n.textureAssetCount,
77
- sceneBytes: e.sceneBytes - n.sceneBytes
72
+ verticesCount: e.verticesCount - t.verticesCount,
73
+ primitivesCount: e.primitivesCount - t.primitivesCount,
74
+ meshesCount: e.meshesCount - t.meshesCount,
75
+ texturesCount: e.textureAssetCount - t.textureAssetCount,
76
+ sceneBytes: e.sceneBytes - t.sceneBytes
78
77
  }
79
78
  };
80
- }, [o, t]),
81
- reset: r(() => {
82
- n(null);
79
+ }, [s, i]),
80
+ reset: e(() => {
81
+ o(null);
83
82
  }, [])
84
83
  };
85
84
  };
@@ -146,130 +145,149 @@ var g = async (e, t) => {
146
145
  encoder: h()
147
146
  });
148
147
  }, _ = () => {
149
- let [a, c] = o(d, u), { report: f, error: m, loading: h } = a, { info: _, reset: v } = p(a), y = s(new l());
150
- i(() => {
148
+ let [n, a] = r(d, u), { report: f, error: m, loading: h } = n, { info: _, reset: v } = p(n), y = i(new l());
149
+ t(() => {
151
150
  let e = y.current;
152
151
  return () => {
153
152
  e.reset();
154
153
  };
155
154
  }, []);
156
- let b = r(async (e) => {
157
- c({ type: "LOAD_START" });
155
+ let b = e(async (e) => {
156
+ a({ type: "LOAD_START" });
158
157
  try {
159
158
  let t = y.current;
160
- await t.loadFromThreeJS(e), c({
159
+ await t.loadFromThreeJS(e);
160
+ let n = await t.getReport();
161
+ a({
161
162
  type: "LOAD_SUCCESS",
162
- payload: { report: await t.getReport() }
163
+ payload: { report: n }
163
164
  });
164
165
  } catch (e) {
165
- c({
166
+ a({
166
167
  type: "LOAD_ERROR",
167
168
  payload: e
168
169
  }), console.error("Error loading model:", e);
169
170
  }
170
- }, []), x = r(async (r) => {
171
- c({ type: "LOAD_START" });
171
+ }, []), x = e(async (e) => {
172
+ if (a({ type: "LOAD_START" }), !e.gltfJson) throw Error("Cannot optimize a scene loaded from a published GLB: it has no glTF document.");
172
173
  try {
173
- let i = y.current, a = /* @__PURE__ */ new Map();
174
- for (let t of Object.values(r.assetData ?? {})) for (let n of e(t.fileName)) a.set(n, t);
175
- let o = {}, s = r.gltfJson, l = [...(s.images ?? []).map((e) => e.uri).filter((e) => !!e && !e.startsWith("data:")), ...(s.buffers ?? []).map((e) => e.uri).filter((e) => !!e && !e.startsWith("data:"))];
174
+ let t = y.current, n = /* @__PURE__ */ new Map();
175
+ for (let t of Object.values(e.assetData ?? {})) for (let e of o(t.fileName)) n.set(e, t);
176
+ let r = {}, i = e.gltfJson, l = [...(i.images ?? []).map((e) => e.uri).filter((e) => !!e && !e.startsWith("data:")), ...(i.buffers ?? []).map((e) => e.uri).filter((e) => !!e && !e.startsWith("data:"))];
176
177
  for (let e of l) {
177
- let r = t(e), i = r.split("/").pop() || r, s = a.get(e) ?? a.get(r) ?? a.get(i);
178
- s && (o[e] = n(s));
178
+ let t = s(e), i = t.split("/").pop() || t, a = n.get(e) ?? n.get(t) ?? n.get(i);
179
+ a && (r[e] = c(a));
179
180
  }
180
181
  let u = {
181
- json: r.gltfJson,
182
- resources: o
182
+ json: e.gltfJson,
183
+ resources: r
183
184
  };
184
- await i.loadFromJSON(u), c({
185
+ await t.loadFromJSON(u);
186
+ let d = await t.getReport();
187
+ a({
185
188
  type: "LOAD_SUCCESS",
186
- payload: { report: await i.getReport() }
189
+ payload: { report: d }
187
190
  });
188
191
  } catch (e) {
189
- throw c({
192
+ throw a({
190
193
  type: "LOAD_ERROR",
191
194
  payload: e
192
195
  }), console.error("Error loading server scene into optimizer:", e), e;
193
196
  }
194
- }, []), S = r(async (e, t) => {
195
- c({ type: "LOAD_START" });
197
+ }, []), S = e(async (e, t, n) => {
198
+ a({ type: "LOAD_START" });
196
199
  try {
197
- await y.current.loadFromBuffer(e), y.current.setAppliedOptimizations(t?.appliedOptimizations ?? []), y.current.setDracoReport(t?.dracoReport ?? null), c({
200
+ let r = n?.preserveBaseline ? y.current.getBaseline() : null;
201
+ await y.current.loadFromBuffer(e), r && y.current.setBaseline(r), y.current.setAppliedOptimizations(t?.appliedOptimizations ?? []), y.current.setDracoReport(t?.dracoReport ?? null);
202
+ let i = await y.current.getReport();
203
+ a({
198
204
  type: "LOAD_SUCCESS",
199
- payload: { report: await y.current.getReport() }
205
+ payload: { report: i }
200
206
  });
201
207
  } catch (e) {
202
- throw c({
208
+ throw a({
203
209
  type: "LOAD_ERROR",
204
210
  payload: e
205
211
  }), console.error("Error loading GLB buffer into optimizer:", e), e;
206
212
  }
207
- }, []), C = r(async (e, t) => {
208
- c({ type: "LOAD_START" });
213
+ }, []), C = e(async (e, t) => {
214
+ a({ type: "LOAD_START" });
209
215
  try {
210
- await y.current.loadFromGLTFWithAssets(e, t), c({
216
+ await y.current.loadFromGLTFWithAssets(e, t);
217
+ let n = await y.current.getReport();
218
+ a({
211
219
  type: "LOAD_SUCCESS",
212
- payload: { report: await y.current.getReport() }
220
+ payload: { report: n }
213
221
  });
214
222
  } catch (e) {
215
- throw c({
223
+ throw a({
216
224
  type: "LOAD_ERROR",
217
225
  payload: e
218
226
  }), console.error("Error loading GLTF with assets into optimizer:", e), e;
219
227
  }
220
- }, []), w = r(async (e) => {
228
+ }, []), w = e(async (e) => {
221
229
  if (y.current.hasModel()) try {
222
- await y.current.simplify(e), c({
230
+ await y.current.simplify(e);
231
+ let t = await y.current.getReport();
232
+ a({
223
233
  type: "LOAD_SUCCESS",
224
- payload: { report: await y.current.getReport() }
234
+ payload: { report: t }
225
235
  });
226
236
  } catch (e) {
227
237
  console.error("Simplification failed:", e);
228
238
  }
229
- }, []), T = r(async (e) => {
239
+ }, []), T = e(async (e) => {
230
240
  if (y.current.hasModel()) try {
231
- await y.current.deduplicate(e), c({
241
+ await y.current.deduplicate(e);
242
+ let t = await y.current.getReport();
243
+ a({
232
244
  type: "LOAD_SUCCESS",
233
- payload: { report: await y.current.getReport() }
245
+ payload: { report: t }
234
246
  });
235
247
  } catch (e) {
236
248
  console.error("Deduplication failed:", e);
237
249
  }
238
- }, []), E = r(async (e) => {
250
+ }, []), E = e(async (e) => {
239
251
  if (y.current.hasModel()) try {
240
- await y.current.quantize(e), c({
252
+ await y.current.quantize(e);
253
+ let t = await y.current.getReport();
254
+ a({
241
255
  type: "LOAD_SUCCESS",
242
- payload: { report: await y.current.getReport() }
256
+ payload: { report: t }
243
257
  });
244
258
  } catch (e) {
245
259
  console.error("Quantization failed:", e);
246
260
  }
247
- }, []), D = r(async (e) => {
261
+ }, []), D = e(async (e) => {
248
262
  if (y.current.hasModel()) try {
249
- await y.current.optimizeNormals(e), c({
263
+ await y.current.optimizeNormals(e);
264
+ let t = await y.current.getReport();
265
+ a({
250
266
  type: "LOAD_SUCCESS",
251
- payload: { report: await y.current.getReport() }
267
+ payload: { report: t }
252
268
  });
253
269
  } catch (e) {
254
270
  console.error("Normals optimization failed:", e);
255
271
  }
256
- }, []), O = r(async (e) => {
272
+ }, []), O = e(async (e) => {
257
273
  try {
258
- await g(y.current, e), c({
274
+ await g(y.current, e);
275
+ let t = await y.current.getReport();
276
+ a({
259
277
  type: "LOAD_SUCCESS",
260
- payload: { report: await y.current.getReport() }
278
+ payload: { report: t }
261
279
  });
262
280
  } catch (e) {
263
281
  throw console.error("Texture optimization failed:", e), e;
264
282
  }
265
- }, []), k = r(async () => {
283
+ }, []), k = e(async () => {
266
284
  if (!y.current.hasModel()) return null;
267
285
  try {
268
286
  return await y.current.export();
269
287
  } catch (e) {
270
288
  return console.error("Error getting model binary:", e), null;
271
289
  }
272
- }, []), A = r(() => y.current.hasModel() ? y.current.document : null, []);
290
+ }, []), A = e(() => y.current.hasModel() ? y.current.document : null, []);
273
291
  return {
274
292
  load: b,
275
293
  loadFromServerSceneData: x,
@@ -278,8 +296,8 @@ var g = async (e, t) => {
278
296
  getModel: k,
279
297
  isReady: !!A() && !h,
280
298
  _getDocument: A,
281
- reset: r(() => {
282
- y.current.reset(), c({ type: "RESET" }), v();
299
+ reset: e(() => {
300
+ y.current.reset(), a({ type: "RESET" }), v();
283
301
  }, [v]),
284
302
  error: m,
285
303
  loading: h,
@@ -293,4 +311,4 @@ var g = async (e, t) => {
293
311
  };
294
312
  };
295
313
  //#endregion
296
- export { _ as t };
314
+ export { h as n, _ as t };
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-optimize-model-Fwew6qD8.cjs");exports.createBrowserTextureEncoder=e.n,exports.useOptimizeModel=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "./use-optimize-model-D16-4Zwm.js";
2
- export { e as useOptimizeModel };
1
+ import { n as e, t } from "./use-optimize-model-sNXkORNg.js";
2
+ export { e as createBrowserTextureEncoder, t as useOptimizeModel };
@@ -48,11 +48,6 @@ export interface ServerRequestConfig {
48
48
  */
49
49
  export declare class ServerCommunicationService {
50
50
  private static extractApiData;
51
- /**
52
- * Creates default server options with required endpoint.
53
- * Merges provided options with defaults.
54
- */
55
- static createDefaultServerOptions(serverOptions?: ServerOptions): ServerOptions & Required<Pick<ServerOptions, 'endpoint'>>;
56
51
  /**
57
52
  * Creates request headers for server communication.
58
53
  * Includes authentication token if apiKey is provided.
package/index.cjs.js DELETED
@@ -1 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-load-model-B8oqou4I.cjs"),t=require("./use-export-model-yQWV3O3H.cjs"),n=require("./use-optimize-model-CD5zqTLK.cjs");exports.reconstructGltfFiles=e.r,exports.useExportModel=t.t,exports.useLoadModel=e.t,exports.useOptimizeModel=n.t;
@@ -1 +0,0 @@
1
- const e=require("./chunk-CMqjfN_6.cjs");let t=require("react"),n=require("@vctrl/core/model-exporter"),r=require("file-saver");r=e.t(r,1);var i=(e,i)=>{let a=(0,t.useRef)(new n.ModelExporter),o=(0,t.useCallback)(async(t,n)=>{let o=t?.model;if(!o){console.error(`Scene not initialized`);return}try{let i=a.current,s=t.name.replace(/\.[^/.]+$/,``);if(n){let e=await i.exportThreeJSGLB(o,{});if(!(e.data instanceof Uint8Array))throw Error(`Expected GLB export to return Uint8Array`);r.default.saveAs(new Blob([new Uint8Array(e.data)]),`${s}.glb`)}else{let e=await i.exportThreeJSGLTF(o),t=await i.createZIPArchive(e,s);r.default.saveAs(new Blob([new Uint8Array(t)]),`${s}.zip`)}e&&e()}catch(e){console.error(`Export failed:`,e),i&&i(e)}},[e,i]),s=(0,t.useCallback)(async t=>{let n=t?.model;if(!n){console.error(`Scene not initialized`);return}try{let i=a.current,o=t.name.replace(/\.[^/.]+$/,``),s=await i.exportThreeJSUSDZ(n);r.default.saveAs(new Blob([new Uint8Array(s.data)]),`${o}.usdz`),e&&e()}catch(e){console.error(`USDZ export failed:`,e),i&&i(e)}},[e,i]),c=(0,t.useCallback)(async(t,n)=>{try{let i=a.current,o=n?.name.replace(/\.[^/.]+$/,``)||`model`,s=await i.exportDocumentGLBDraco(t);r.default.saveAs(new Blob([new Uint8Array(s.data)]),`${o}.glb`),e&&e()}catch(e){console.error(`Draco GLB export failed:`,e),i&&i(e)}},[e,i]);return{handleThreeGltfExport:o,handleDocumentGltfExport:(0,t.useCallback)(async function(t,n,o=!1,s=!0){try{let i=a.current,c=n?.name.replace(/\.[^/.]+$/,``)||`model`;if(o){let e=await i.exportDocumentGLB(t);r.default.saveAs(new Blob([new Uint8Array(e.data)]),`${c}.glb`)}else{let e=await i.exportDocumentGLTF(t);if(!s)return e;let n=await i.createZIPArchive(e,c);r.default.saveAs(new Blob([new Uint8Array(n)]),`${c}.zip`)}e&&e()}catch(e){console.error(`Export failed:`,e),i&&i(e)}},[i,e]),handleThreeUsdzExport:s,handleDocumentGlbDracoExport:c}};Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
@@ -1 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./use-export-model-yQWV3O3H.cjs");exports.useExportModel=e.t;
@@ -1,7 +0,0 @@
1
- import { EventData, EventHandler, EventTypes } from './types';
2
- declare const eventSystem: {
3
- emit<T extends EventTypes>(event: T, data?: EventData[T]): void;
4
- on<T extends EventTypes>(event: T, handler?: EventHandler<T>): void;
5
- off<T extends EventTypes>(event: T, handler?: EventHandler<T>): void;
6
- };
7
- export default eventSystem;
@@ -1 +0,0 @@
1
- let e=require("@vctrl/core"),t=require("@vctrl/core/model-loader"),n=require("react");var r=({code:e,message:t,recoverable:n,source:r,cause:i,context:a})=>({code:e,message:t,recoverable:n,source:r,cause:i,context:a}),i=e=>e instanceof Error&&e.message?e.message:typeof e==`string`&&e.trim().length>0?e:`Unknown error`,a=(e,t,n)=>{let a=i(e);return r({code:a.includes(`missing required referenced assets`)?`missing_assets`:t,message:a,recoverable:!0,source:`local-upload`,cause:e,context:n})},o=(e,t)=>{let n=i(e),a=`server_load_failed`;return n.includes(`Server responded with 404`)?a=`not_found`:(n.includes(`Server responded with 402`)||n.includes(`Server responded with 403`))&&(a=`quota_exceeded`),r({code:a,message:n,recoverable:a!==`not_found`,source:`server-load`,cause:e,context:{sceneId:t}})},s={},c={emit(e,t){let n=s[e];console.debug(`Event emitted: ${e}`,t),n&&n.forEach(e=>e(t))},on(e,t){s[e]||(s[e]=[]),s[e].push(t)},off(e,t){let n=s[e];n&&(s[e]=n.filter(e=>e!==t))}},l=t=>{try{return(0,e.normalizeAssetUri)(t)}catch{return t}},u=e=>{let t=new Set,n=e,r=Array.isArray(n.images)?n.images:[];for(let e of r)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);let i=Array.isArray(n.buffers)?n.buffers:[];for(let e of i)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);return t},d=async(t,n)=>{let r=JSON.parse(await t.text()),i=u(r),a={},o=new Map,s=new Map,c=new Set,d=async e=>{let t=s.get(e);if(t)return t;let n=new Uint8Array(await e.arrayBuffer());return s.set(e,n),n};for(let t of n){for(let n of(0,e.buildAssetLookupKeys)(t.name))o.set(n,t);if(t.webkitRelativePath)for(let n of(0,e.buildAssetLookupKeys)(t.webkitRelativePath))o.set(n,t)}let f=[];for(let e of i){let t=l(e),n=t.split(`/`).pop()||t,r=o.get(e)||o.get(t)||o.get(n);if(!r){f.push(e);continue}c.add(r);let i=await d(r);a[t]={data:Array.from(i),fileName:t,mimeType:r.type||`application/octet-stream`}}if(f.length>0)throw Error(`Scene payload is missing required referenced assets: ${f.slice(0,5).join(`, `)}`);for(let[e,t]of n.entries()){if(c.has(t))continue;let n=l(t.name),r=n.split(`/`).pop()||n,i=await d(t);a[`extra-${e}-${r}`]={data:Array.from(i),fileName:r,mimeType:t.type||`application/octet-stream`}}return{gltfJson:r,assetData:a}},f=async(e,n,r,i,o)=>{try{let a={model:(await r.loadToThreeJS(e)).scene,type:n,name:e.name};if(o({type:`set-file`,payload:a}),o({type:`set-file-loading`,payload:!1}),i&&n!==t.ModelFileTypes.usdz){let t=new Uint8Array(await e.arrayBuffer());await i.loadFromGlbBuffer(t)}return a}catch(t){return console.error(`Error loading binary model:`,t),o({type:`set-file-loading`,payload:!1}),c.emit(`load-error`,a(t,`binary_load_failed`,{fileName:e.name,fileType:n,fileSize:e.size})),null}},p=async(e,n,r,i,o,s)=>{try{let{sourcePackageBytes:a,textureBytes:c}=await s(e,n),l=await r.loadGLTFWithAssetsToThreeJS(e,n),u={model:l.scene,type:t.ModelFileTypes.gltf,name:e.name,sourcePackageBytes:a,sourceTextureBytes:c};if(o({type:`set-file`,payload:u}),o({type:`set-file-loading`,payload:!1}),i)try{let t=await d(e,n);await i.loadFromServerSceneData(t)}catch(t){console.warn(`Failed to initialize optimizer from source GLTF payload; trying direct asset load.`,t);try{if(`loadFromGLTFWithAssets`in i){let t=new Uint8Array(await e.arrayBuffer()),r=new Map;for(let e of n){let t=new Uint8Array(await e.arrayBuffer());r.set(e.name,t),e.webkitRelativePath&&r.set(e.webkitRelativePath,t)}await i.loadFromGLTFWithAssets(t,r)}else throw Error(`loadFromGLTFWithAssets not available`)}catch(e){console.warn(`Direct asset load also failed; falling back to Three.js scene import. Texture names may be generic.`,e),await i.load(l.scene)}}return u}catch(t){return console.error(`Error loading GLTF model:`,t),console.error(`GLTF file:`,e.name),console.error(`Asset files:`,n.map(e=>e.name)),o({type:`set-file-loading`,payload:!1}),c.emit(`load-error`,a(t,`gltf_load_failed`,{fileName:e.name,fileSize:e.size,assetCount:n.length})),null}};function m(e,r,i,a){let o=(0,n.useCallback)(async(n,o)=>{if(!e){console.warn(`Optimizer is not available`);return}try{n&&await n(o);let s=await e.getModel();if(!s){console.warn(`No optimized model available after optimization`);return}let c=s instanceof Uint8Array?s.slice():new Uint8Array(s).slice(),l=new File([c],i?.name||`optimized_model.glb`,{type:`model/gltf-binary`});r({type:`set-file`,payload:{model:(await a.loadToThreeJS(l)).scene,type:t.ModelFileTypes.glb,name:l.name}})}catch(e){console.error(`Optimization failed:`,e)}},[e,a,i,r]);if(!e)return null;let s=e.isReady,c=!!i?.model&&!s;return{...e,isReady:s,isPreparing:c,applyOptimization:o,reset:e?.reset,error:e?.error,loading:e?.loading}}var h={file:null,isFileLoading:!1,progress:0,supportedFileTypes:[t.ModelFileTypes.gltf,t.ModelFileTypes.glb,t.ModelFileTypes.usdz]};function g(e,t){switch(t.type){case`set-file`:return{...e,file:t.payload};case`set-file-loading`:return{...e,isFileLoading:t.payload};case`set-progress`:return{...e,progress:t.payload};case`reset-state`:return{...h};default:return e}}async function _(e){let t=[];async function*n(e){let t=e;for await(let[,e]of t)e.kind===`file`?yield await e.getFile():e.kind===`directory`&&(yield*n(e))}for await(let r of n(e))t.push(r);return t}function v(t){let n=[];if(t.assetData&&typeof t.assetData==`object`)for(let[,r]of Object.entries(t.assetData)){let{fileName:t,mimeType:i}=r;if(t===e.PERSISTED_BAKE_FILENAME)continue;let a=(0,e.toSerializedAssetBytes)(r),o=new Uint8Array(a.byteLength);o.set(a);let s=new Blob([o],{type:i}),c=new File([s],t,{type:i});n.push(c)}let r=JSON.stringify(t.gltfJson),i=new Blob([r],{type:`model/gltf+json`}),a=t.meta?.name,o=a?`${a}.gltf`:`scene.gltf`;return[new File([i],o,{type:`model/gltf+json`}),...n]}var y=(t,n)=>{let r=(0,e.normalizeAssetUri)(t),i=r.split(`/`).pop()||r;for(let t of n){let n=(0,e.buildAssetLookupKeys)(t.fileName);if(n.has(r)||n.has(i))return t.size}return 0},b=e=>{let t=new Set,n=new Set,r=e,i=Array.isArray(r.images)?r.images:[];for(let e of i)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&n.add(e.uri);let a=Array.isArray(r.buffers)?r.buffers:[];for(let e of a)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);return{bufferUris:t,imageUris:n}};async function x(e,t){let n=await e.text(),r;try{r=JSON.parse(n)}catch{return{sourcePackageBytes:e.size,textureBytes:0}}let i=t.map(e=>({fileName:e.name,size:e.size})),{bufferUris:a,imageUris:o}=b(r),s=Array.from(a).reduce((e,t)=>e+y(t,i),0),c=Array.from(o).reduce((e,t)=>e+y(t,i),0);return{sourcePackageBytes:e.size+s+c,textureBytes:c}}function S(t){let n=t.gltfJson,r=Object.values(t.assetData||{}).map(t=>({fileName:t.fileName,size:(0,e.getSerializedAssetByteSize)(t.data)})),i=new TextEncoder().encode(JSON.stringify(n)).byteLength,{bufferUris:a,imageUris:o}=b(n),s=Array.from(a).reduce((e,t)=>e+y(t,r),0),c=Array.from(o).reduce((e,t)=>e+y(t,r),0);return{sourcePackageBytes:i+s+c,textureBytes:c}}function C(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function w(t){let n=C(t.settings)?t.settings:{},r=(0,e.normalizeCameraSettings)(t.camera??n.camera);return{...n,bounds:t.bounds??n.bounds,camera:r,interactions:(0,e.normalizeSceneInteractions)(n.interactions,{camera:r}),controls:t.controls??n.controls,environment:t.environment??n.environment,shadows:t.shadows??n.shadows}}function T(e){let t=new Set,n=e,r=Array.isArray(n.images)?n.images:[];for(let e of r)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);let i=Array.isArray(n.buffers)?n.buffers:[];for(let e of i)typeof e.uri==`string`&&!e.uri.startsWith(`data:`)&&t.add(e.uri);return t}function E(t){for(let[n,r]of Object.entries(t)){if(!r||typeof r!=`object`)throw Error(`Scene payload contains invalid asset entry for ${n}`);if(typeof r.fileName!=`string`||r.fileName.trim().length===0)throw Error(`Scene payload asset ${n} is missing a valid fileName`);if(typeof r.mimeType!=`string`||r.mimeType.trim().length===0)throw Error(`Scene payload asset ${n} is missing a valid mimeType`);if(typeof r.data==`string`&&r.encoding===`base64`&&!(0,e.isValidBase64)(r.data))throw Error(`Scene payload asset ${r.fileName} has invalid base64 data`)}}function D(t,n){let r=T(t);if(r.size===0)return;let i=new Set;for(let t of Object.values(n))for(let n of(0,e.buildAssetLookupKeys)(t.fileName))i.add(n);let a=[];for(let t of r){let n=(0,e.normalizeAssetUri)(t),r=n.split(`/`).pop()||n;!i.has(t)&&!i.has(n)&&!i.has(r)&&a.push(t)}if(a.length>0)throw Error(`Scene payload is missing required referenced assets: ${a.slice(0,5).join(`, `)}`)}function O(e){if(!C(e.gltfJson))throw Error(`Scene payload is missing a valid glTF document`);let t=e.assetData??{};return E(t),D(e.gltfJson,t),{meta:e.meta,gltfJson:e.gltfJson,assetData:t,...w(e)}}async function k(e,t={}){let n=Object.entries(e);if(n.length===0)return t.onProgress?.(1),{};let r=n.every(([,e])=>e.byteSize!=null),i=r?n.reduce((e,[,t])=>e+(t.byteSize??0),0):0,a=0,o=0,s={},c=new AbortController;return await Promise.all(n.map(async([e,l])=>{try{let u=await fetch(l.url,{headers:t.headers,credentials:`same-origin`,signal:c.signal});if(!u.ok)throw c.abort(),Error(`Failed to fetch scene asset ${l.fileName}: ${u.status}`);s[e]={data:new Uint8Array(await u.arrayBuffer()),fileName:l.fileName,mimeType:l.mimeType},o+=1,a+=l.byteSize??0,t.onProgress?.(r&&i>0?a/i:o/n.length)}catch(e){throw c.abort(),e}})),s}async function A(e,t){try{let n=await fetch(e,{method:`GET`,headers:{Accept:`application/json`,...t}});if(!n.ok)return null;let r=await n.json(),i=r.data??r;return!i||typeof i!=`object`||!i.gltfJson||!i.assetRefs&&!i.assetData?null:i}catch{return null}}async function j(e,t,n){let r=new FormData;r.append(`action`,`get-scene-settings`),r.append(`sceneId`,n);let i=await fetch(e,{method:`POST`,headers:t,body:r});if(!i.ok)throw Error(`Server responded with ${i.status} ${i.statusText}`);let a=await i.json();return a.data??a}function M(r){let i=(0,n.useRef)(!1),a=(0,n.useRef)(null),[s,l]=(0,n.useReducer)(g,h),u=(0,n.useMemo)(()=>{let e=new t.ModelLoader;return e.onProgress(e=>{l({type:`set-progress`,payload:e.progress}),e.progress!==100&&c.emit(`load-progress`,e.progress)}),e},[]),d=(0,n.useCallback)(e=>{l({type:`set-progress`,payload:e}),c.emit(`load-progress`,e)},[]),y=(0,n.useCallback)(()=>{l({type:`reset-state`}),c.emit(`load-reset`)},[]),b=(0,n.useCallback)((e,t)=>e.find(e=>e.name.endsWith(`.`+t)),[]),C=(0,n.useCallback)(async e=>{if(e.length===0)return;let n=b(e,t.ModelFileTypes.gltf),o=b(e,t.ModelFileTypes.glb),s=b(e,t.ModelFileTypes.usdz),d=[n,o,s].filter(Boolean);if(d.length>1){c.emit(`multiple-models`,d);return}let m=e.filter(e=>e!==n&&e!==o&&e!==s),h=()=>{i.current=!0,a.current&&(c.emit(`load-complete`,a.current),i.current=!1)};if(n){let e=await p(n,m,u,r,l,x);e&&(a.current=e),h()}else if(o){let e=await f(o,t.ModelFileTypes.glb,u,r,l);e&&(a.current=e),h()}else if(s){let e=await f(s,t.ModelFileTypes.usdz,u,r,l);e&&(a.current=e),h()}else c.emit(`not-loaded-files`,e),l({type:`set-file-loading`,payload:!1})},[b,u,r]),w=(0,n.useCallback)(async e=>{let t=[];c.emit(`load-start`),l({type:`reset-state`}),l({type:`set-file-loading`,payload:!0}),d(0),i.current=!1;for(let n of e)if(n instanceof File)t.push(n);else if(`kind`in n&&n.kind===`directory`){let e=await _(n);t.push(...e)}await C(t)},[C,d]),T=(0,n.useCallback)(async n=>{let{sceneData:i,sceneId:o}=n;if(d(40),n.parseMode===`direct`&&i.gltfJson){let n=new Map;for(let t of Object.values(i.assetData??{}))t.fileName!==e.PERSISTED_BAKE_FILENAME&&n.set(t.fileName,(0,e.toSerializedAssetBytes)(t));let{sourcePackageBytes:r,textureBytes:s}=S(i);d(60);let c={model:(await u.parseGLTFJsonToThreeJS(i.gltfJson,n)).scene,type:t.ModelFileTypes.gltf,name:i.meta?.name||`scene`,sourcePackageBytes:r,sourceTextureBytes:s};return l({type:`set-file`,payload:c}),l({type:`set-file-loading`,payload:!1}),a.current=c,d(100),{file:c,sceneId:o,...i}}let s=v(i),{sourcePackageBytes:c,textureBytes:f}=S(i);d(60);let p=s[0],m=s.slice(1),h={model:(await u.loadGLTFWithAssetsToThreeJS(p,m)).scene,type:t.ModelFileTypes.gltf,name:p.name,sourcePackageBytes:c,sourceTextureBytes:f};return l({type:`set-file`,payload:h}),l({type:`set-file-loading`,payload:!1}),a.current=h,r&&await r.loadFromServerSceneData(i),d(100),{file:h,sceneId:o,...i}},[u,r,d]),E=(0,n.useCallback)(async e=>{let{sceneId:t,serverOptions:n,parseMode:r}=e;try{c.emit(`server-load-start`,t),l({type:`reset-state`}),l({type:`set-file-loading`,payload:!0}),d(0);let e=n?.endpoint??`/api/scenes/${t}`,i=n?.apiKey?{Authorization:`Bearer ${n.apiKey}`,...n.headers}:{...n?.headers},a=await A(e,i);if(a?.assetRefs&&!a.assetData){d(10);let e=await k(a.assetRefs,{headers:i,onProgress:e=>d(10+Math.round(e*30))});a={...a,assetData:e}}a||=await j(e,i,t);let o=await T({sceneId:t,sceneData:O(a),parseMode:r});return c.emit(`server-load-complete`,o),o}catch(e){console.error(`Server scene loading failed:`,e),l({type:`set-file-loading`,payload:!1});let n=o(e,t);throw c.emit(`server-load-error`,n),n}},[T,d]),D=m(r,l,s.file,u);return{...s,on:c.on,off:c.off,load:w,loadFromData:T,loadFromServer:E,reset:y,optimizer:D}}Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return M}});