@netless/window-manager 1.0.0-canary.49 → 1.0.0-canary.51

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/dist/index.cjs.js CHANGED
@@ -171,18 +171,27 @@ const emitter = new Emittery__default["default"]();
171
171
  const DatabaseName = "__WindowManagerAppCache";
172
172
  let db;
173
173
  let store$1;
174
- const initDb = async () => {
174
+ const initDb = async (appRegister2) => {
175
175
  db = await createDb();
176
+ const items = await queryAll(db);
177
+ items.forEach((item) => {
178
+ appRegister2.downloaded.set(item.kind, item.url);
179
+ });
176
180
  };
177
- const setItem = (key, val) => {
181
+ const setItem = (kind, url, val) => {
178
182
  if (!db)
179
183
  return;
180
- return addRecord(db, { kind: key, sourceCode: val });
184
+ return addRecord(db, { kind, url, sourceCode: val });
181
185
  };
182
- const getItem = async (key) => {
186
+ const getItem = async (kind) => {
183
187
  if (!db)
184
188
  return null;
185
- return await query(db, key);
189
+ return await query(db, kind);
190
+ };
191
+ const removeItem = (key) => {
192
+ if (!db)
193
+ return;
194
+ return deleteRecord(db, key);
186
195
  };
187
196
  function createDb() {
188
197
  return new Promise((resolve, reject) => {
@@ -217,6 +226,14 @@ function query(db2, val) {
217
226
  };
218
227
  });
219
228
  }
229
+ function queryAll(db2) {
230
+ return new Promise((resolve, reject) => {
231
+ const index2 = db2.transaction(["apps"]).objectStore("apps").index("kind");
232
+ const request = index2.getAll();
233
+ request.onerror = (e) => reject(e);
234
+ request.onsuccess = () => resolve(request.result);
235
+ });
236
+ }
220
237
  function addRecord(db2, payload) {
221
238
  return new Promise((resolve, reject) => {
222
239
  const request = db2.transaction(["apps"], "readwrite").objectStore("apps").add(payload);
@@ -224,16 +241,23 @@ function addRecord(db2, payload) {
224
241
  request.onerror = () => reject();
225
242
  });
226
243
  }
244
+ function deleteRecord(db2, key) {
245
+ return new Promise((resolve, reject) => {
246
+ const request = db2.transaction(["apps"], "readwrite").objectStore("apps").delete(key);
247
+ request.onsuccess = () => resolve();
248
+ request.onerror = () => reject();
249
+ });
250
+ }
227
251
  const Prefix = "NetlessApp";
228
252
  const TIMEOUT = 1e4;
229
- const getScript = async (url) => {
230
- const item = await getItem(url);
253
+ const getScript = async (kind, url) => {
254
+ const item = await getItem(kind);
231
255
  if (item) {
232
256
  return item.sourceCode;
233
257
  } else {
234
258
  const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
235
259
  const text2 = await result.text();
236
- await setItem(url, text2);
260
+ await setItem(kind, url, text2);
237
261
  return text2;
238
262
  }
239
263
  };
@@ -245,18 +269,25 @@ const executeScript = (text2, appName) => {
245
269
  }
246
270
  return result;
247
271
  };
272
+ const emitSuccess = (kind, url) => {
273
+ callbacks.emit("loadApp", { kind, status: "success" });
274
+ appRegister.downloaded.set(kind, url);
275
+ };
276
+ const emitFailed = (kind, reason) => {
277
+ callbacks.emit("loadApp", { kind, status: "failed", reason });
278
+ };
248
279
  const loadApp = async (url, key, name) => {
249
280
  const appName = name || Prefix + key;
250
281
  callbacks.emit("loadApp", { kind: key, status: "start" });
251
282
  try {
252
- const text2 = await getScript(url);
283
+ const text2 = await getScript(key, url);
253
284
  if (!text2 || text2.length === 0) {
254
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: "script is empty." });
285
+ emitFailed(key, "script is empty");
255
286
  return;
256
287
  }
257
288
  try {
258
289
  const result = executeScript(text2, appName);
259
- callbacks.emit("loadApp", { kind: key, status: "success" });
290
+ emitSuccess(key, url);
260
291
  return result;
261
292
  } catch (error) {
262
293
  if (error.message.includes("Can only have one anonymous define call per script file")) {
@@ -265,13 +296,13 @@ const loadApp = async (url, key, name) => {
265
296
  delete define.amd;
266
297
  }
267
298
  const result = executeScript(text2, appName);
268
- callbacks.emit("loadApp", { kind: key, status: "success" });
299
+ emitSuccess(key, url);
269
300
  return result;
270
301
  }
271
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
302
+ emitFailed(key, error.message);
272
303
  }
273
304
  } catch (error) {
274
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
305
+ emitFailed(key, error.message);
275
306
  }
276
307
  };
277
308
  async function fetchWithTimeout(resource, options) {
@@ -293,6 +324,7 @@ class AppRegister {
293
324
  this.registered = /* @__PURE__ */ new Map();
294
325
  this.appClassesCache = /* @__PURE__ */ new Map();
295
326
  this.appClasses = /* @__PURE__ */ new Map();
327
+ this.downloaded = /* @__PURE__ */ new Map();
296
328
  this.syncRegisterApp = null;
297
329
  this.onSyncRegisterAppChange = (payload) => {
298
330
  this.register({ kind: payload.kind, src: payload.src });
@@ -304,27 +336,35 @@ class AppRegister {
304
336
  async register(params) {
305
337
  this.appClassesCache.delete(params.kind);
306
338
  this.registered.set(params.kind, params);
307
- const srcOrAppOrFunction = params.src;
339
+ const paramSrc = params.src;
308
340
  let downloadApp;
309
- if (typeof srcOrAppOrFunction === "string") {
341
+ if (typeof paramSrc === "string") {
342
+ downloadApp = async () => {
343
+ const result = await loadApp(paramSrc, params.kind, params.name);
344
+ if (result.__esModule) {
345
+ return result.default;
346
+ }
347
+ return result;
348
+ };
349
+ if (this.syncRegisterApp) {
350
+ this.syncRegisterApp({ kind: params.kind, src: paramSrc, name: params.name });
351
+ }
352
+ }
353
+ if (typeof paramSrc === "function") {
310
354
  downloadApp = async () => {
311
- let appClass = await loadApp(srcOrAppOrFunction, params.kind, params.name);
355
+ let appClass = await paramSrc();
312
356
  if (appClass) {
313
- if (appClass.__esModule) {
357
+ if (appClass.__esModule || appClass.default) {
314
358
  appClass = appClass.default;
315
359
  }
316
360
  return appClass;
317
361
  } else {
318
- throw new Error(`[WindowManager]: load remote script failed, ${srcOrAppOrFunction}`);
362
+ throw new Error(`[WindowManager]: load remote script failed, ${paramSrc}`);
319
363
  }
320
364
  };
321
- if (this.syncRegisterApp) {
322
- this.syncRegisterApp({ kind: params.kind, src: srcOrAppOrFunction, name: params.name });
323
- }
324
- } else if (typeof srcOrAppOrFunction === "function") {
325
- downloadApp = srcOrAppOrFunction;
326
- } else {
327
- downloadApp = async () => srcOrAppOrFunction;
365
+ }
366
+ if (typeof paramSrc === "object") {
367
+ downloadApp = async () => paramSrc;
328
368
  }
329
369
  this.appClasses.set(params.kind, async () => {
330
370
  let app = this.appClassesCache.get(params.kind);
@@ -341,10 +381,21 @@ class AppRegister {
341
381
  }
342
382
  }
343
383
  }
384
+ downloadApp(kind) {
385
+ const src = this.registered.get(kind);
386
+ if (src && typeof src.src === "string") {
387
+ return loadApp(src.src, src.kind, src.name);
388
+ }
389
+ }
390
+ async removeDownloaded(kind) {
391
+ await removeItem(kind);
392
+ this.downloaded.delete(kind);
393
+ }
344
394
  unregister(kind) {
345
395
  this.appClasses.delete(kind);
346
396
  this.appClassesCache.delete(kind);
347
397
  this.registered.delete(kind);
398
+ this.removeDownloaded(kind);
348
399
  const kindEmitter = this.kindEmitters.get(kind);
349
400
  if (kindEmitter) {
350
401
  kindEmitter.clearListeners();
@@ -2416,6 +2467,7 @@ class MainViewProxy {
2416
2467
  start() {
2417
2468
  if (this.started)
2418
2469
  return;
2470
+ this.removeCameraListener();
2419
2471
  this.addCameraListener();
2420
2472
  this.addCameraReaction();
2421
2473
  this.started = true;
@@ -2494,7 +2546,6 @@ class MainViewProxy {
2494
2546
  this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
2495
2547
  }
2496
2548
  stop() {
2497
- this.removeCameraListener();
2498
2549
  this.manager.refresher.remove(Fields.MainViewCamera);
2499
2550
  this.manager.refresher.remove(Fields.MainViewSize);
2500
2551
  this.started = false;
@@ -11637,7 +11688,7 @@ const reconnectRefresher = new ReconnectRefresher({ emitter });
11637
11688
  const _WindowManager = class extends whiteWebSdk.InvisiblePlugin {
11638
11689
  constructor(context) {
11639
11690
  super(context);
11640
- this.version = "1.0.0-canary.49";
11691
+ this.version = "1.0.0-canary.51";
11641
11692
  this.dependencies = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.1.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "2.16.26" } };
11642
11693
  this.emitter = callbacks;
11643
11694
  this.viewMode = whiteWebSdk.ViewMode.Broadcaster;
@@ -11710,8 +11761,8 @@ const _WindowManager = class extends whiteWebSdk.InvisiblePlugin {
11710
11761
  const cursor = params.cursor;
11711
11762
  _WindowManager.params = params;
11712
11763
  _WindowManager.displayer = params.room;
11713
- checkVersion();
11714
11764
  let manager = void 0;
11765
+ checkVersion();
11715
11766
  if (whiteWebSdk.isRoom(room)) {
11716
11767
  if (room.phase !== whiteWebSdk.RoomPhase.Connected) {
11717
11768
  throw new Error("[WindowManager]: Room only Connected can be mount");
@@ -11768,7 +11819,7 @@ const _WindowManager = class extends whiteWebSdk.InvisiblePlugin {
11768
11819
  emitter.emit("onCreated");
11769
11820
  _WindowManager.isCreated = true;
11770
11821
  try {
11771
- await initDb();
11822
+ await initDb(appRegister);
11772
11823
  } catch (error) {
11773
11824
  console.warn("[WindowManager]: indexedDB open failed");
11774
11825
  console.log(error);
@@ -12420,6 +12471,7 @@ WindowManager.kind = "WindowManager";
12420
12471
  WindowManager.debug = false;
12421
12472
  WindowManager.containerSizeRatio = DEFAULT_CONTAINER_RATIO;
12422
12473
  WindowManager.isCreated = false;
12474
+ WindowManager.registry = appRegister;
12423
12475
  setupBuiltin();
12424
12476
  exports.AppCreateError = AppCreateError;
12425
12477
  exports.AppManagerNotInitError = AppManagerNotInitError;
package/dist/index.es.js CHANGED
@@ -164,18 +164,27 @@ const emitter = new Emittery();
164
164
  const DatabaseName = "__WindowManagerAppCache";
165
165
  let db;
166
166
  let store$1;
167
- const initDb = async () => {
167
+ const initDb = async (appRegister2) => {
168
168
  db = await createDb();
169
+ const items = await queryAll(db);
170
+ items.forEach((item) => {
171
+ appRegister2.downloaded.set(item.kind, item.url);
172
+ });
169
173
  };
170
- const setItem = (key, val) => {
174
+ const setItem = (kind, url, val) => {
171
175
  if (!db)
172
176
  return;
173
- return addRecord(db, { kind: key, sourceCode: val });
177
+ return addRecord(db, { kind, url, sourceCode: val });
174
178
  };
175
- const getItem = async (key) => {
179
+ const getItem = async (kind) => {
176
180
  if (!db)
177
181
  return null;
178
- return await query(db, key);
182
+ return await query(db, kind);
183
+ };
184
+ const removeItem = (key) => {
185
+ if (!db)
186
+ return;
187
+ return deleteRecord(db, key);
179
188
  };
180
189
  function createDb() {
181
190
  return new Promise((resolve, reject) => {
@@ -210,6 +219,14 @@ function query(db2, val) {
210
219
  };
211
220
  });
212
221
  }
222
+ function queryAll(db2) {
223
+ return new Promise((resolve, reject) => {
224
+ const index2 = db2.transaction(["apps"]).objectStore("apps").index("kind");
225
+ const request = index2.getAll();
226
+ request.onerror = (e) => reject(e);
227
+ request.onsuccess = () => resolve(request.result);
228
+ });
229
+ }
213
230
  function addRecord(db2, payload) {
214
231
  return new Promise((resolve, reject) => {
215
232
  const request = db2.transaction(["apps"], "readwrite").objectStore("apps").add(payload);
@@ -217,16 +234,23 @@ function addRecord(db2, payload) {
217
234
  request.onerror = () => reject();
218
235
  });
219
236
  }
237
+ function deleteRecord(db2, key) {
238
+ return new Promise((resolve, reject) => {
239
+ const request = db2.transaction(["apps"], "readwrite").objectStore("apps").delete(key);
240
+ request.onsuccess = () => resolve();
241
+ request.onerror = () => reject();
242
+ });
243
+ }
220
244
  const Prefix = "NetlessApp";
221
245
  const TIMEOUT = 1e4;
222
- const getScript = async (url) => {
223
- const item = await getItem(url);
246
+ const getScript = async (kind, url) => {
247
+ const item = await getItem(kind);
224
248
  if (item) {
225
249
  return item.sourceCode;
226
250
  } else {
227
251
  const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
228
252
  const text2 = await result.text();
229
- await setItem(url, text2);
253
+ await setItem(kind, url, text2);
230
254
  return text2;
231
255
  }
232
256
  };
@@ -238,18 +262,25 @@ const executeScript = (text2, appName) => {
238
262
  }
239
263
  return result;
240
264
  };
265
+ const emitSuccess = (kind, url) => {
266
+ callbacks.emit("loadApp", { kind, status: "success" });
267
+ appRegister.downloaded.set(kind, url);
268
+ };
269
+ const emitFailed = (kind, reason) => {
270
+ callbacks.emit("loadApp", { kind, status: "failed", reason });
271
+ };
241
272
  const loadApp = async (url, key, name) => {
242
273
  const appName = name || Prefix + key;
243
274
  callbacks.emit("loadApp", { kind: key, status: "start" });
244
275
  try {
245
- const text2 = await getScript(url);
276
+ const text2 = await getScript(key, url);
246
277
  if (!text2 || text2.length === 0) {
247
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: "script is empty." });
278
+ emitFailed(key, "script is empty");
248
279
  return;
249
280
  }
250
281
  try {
251
282
  const result = executeScript(text2, appName);
252
- callbacks.emit("loadApp", { kind: key, status: "success" });
283
+ emitSuccess(key, url);
253
284
  return result;
254
285
  } catch (error) {
255
286
  if (error.message.includes("Can only have one anonymous define call per script file")) {
@@ -258,13 +289,13 @@ const loadApp = async (url, key, name) => {
258
289
  delete define.amd;
259
290
  }
260
291
  const result = executeScript(text2, appName);
261
- callbacks.emit("loadApp", { kind: key, status: "success" });
292
+ emitSuccess(key, url);
262
293
  return result;
263
294
  }
264
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
295
+ emitFailed(key, error.message);
265
296
  }
266
297
  } catch (error) {
267
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
298
+ emitFailed(key, error.message);
268
299
  }
269
300
  };
270
301
  async function fetchWithTimeout(resource, options) {
@@ -286,6 +317,7 @@ class AppRegister {
286
317
  this.registered = /* @__PURE__ */ new Map();
287
318
  this.appClassesCache = /* @__PURE__ */ new Map();
288
319
  this.appClasses = /* @__PURE__ */ new Map();
320
+ this.downloaded = /* @__PURE__ */ new Map();
289
321
  this.syncRegisterApp = null;
290
322
  this.onSyncRegisterAppChange = (payload) => {
291
323
  this.register({ kind: payload.kind, src: payload.src });
@@ -297,27 +329,35 @@ class AppRegister {
297
329
  async register(params) {
298
330
  this.appClassesCache.delete(params.kind);
299
331
  this.registered.set(params.kind, params);
300
- const srcOrAppOrFunction = params.src;
332
+ const paramSrc = params.src;
301
333
  let downloadApp;
302
- if (typeof srcOrAppOrFunction === "string") {
334
+ if (typeof paramSrc === "string") {
335
+ downloadApp = async () => {
336
+ const result = await loadApp(paramSrc, params.kind, params.name);
337
+ if (result.__esModule) {
338
+ return result.default;
339
+ }
340
+ return result;
341
+ };
342
+ if (this.syncRegisterApp) {
343
+ this.syncRegisterApp({ kind: params.kind, src: paramSrc, name: params.name });
344
+ }
345
+ }
346
+ if (typeof paramSrc === "function") {
303
347
  downloadApp = async () => {
304
- let appClass = await loadApp(srcOrAppOrFunction, params.kind, params.name);
348
+ let appClass = await paramSrc();
305
349
  if (appClass) {
306
- if (appClass.__esModule) {
350
+ if (appClass.__esModule || appClass.default) {
307
351
  appClass = appClass.default;
308
352
  }
309
353
  return appClass;
310
354
  } else {
311
- throw new Error(`[WindowManager]: load remote script failed, ${srcOrAppOrFunction}`);
355
+ throw new Error(`[WindowManager]: load remote script failed, ${paramSrc}`);
312
356
  }
313
357
  };
314
- if (this.syncRegisterApp) {
315
- this.syncRegisterApp({ kind: params.kind, src: srcOrAppOrFunction, name: params.name });
316
- }
317
- } else if (typeof srcOrAppOrFunction === "function") {
318
- downloadApp = srcOrAppOrFunction;
319
- } else {
320
- downloadApp = async () => srcOrAppOrFunction;
358
+ }
359
+ if (typeof paramSrc === "object") {
360
+ downloadApp = async () => paramSrc;
321
361
  }
322
362
  this.appClasses.set(params.kind, async () => {
323
363
  let app = this.appClassesCache.get(params.kind);
@@ -334,10 +374,21 @@ class AppRegister {
334
374
  }
335
375
  }
336
376
  }
377
+ downloadApp(kind) {
378
+ const src = this.registered.get(kind);
379
+ if (src && typeof src.src === "string") {
380
+ return loadApp(src.src, src.kind, src.name);
381
+ }
382
+ }
383
+ async removeDownloaded(kind) {
384
+ await removeItem(kind);
385
+ this.downloaded.delete(kind);
386
+ }
337
387
  unregister(kind) {
338
388
  this.appClasses.delete(kind);
339
389
  this.appClassesCache.delete(kind);
340
390
  this.registered.delete(kind);
391
+ this.removeDownloaded(kind);
341
392
  const kindEmitter = this.kindEmitters.get(kind);
342
393
  if (kindEmitter) {
343
394
  kindEmitter.clearListeners();
@@ -2409,6 +2460,7 @@ class MainViewProxy {
2409
2460
  start() {
2410
2461
  if (this.started)
2411
2462
  return;
2463
+ this.removeCameraListener();
2412
2464
  this.addCameraListener();
2413
2465
  this.addCameraReaction();
2414
2466
  this.started = true;
@@ -2487,7 +2539,6 @@ class MainViewProxy {
2487
2539
  this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
2488
2540
  }
2489
2541
  stop() {
2490
- this.removeCameraListener();
2491
2542
  this.manager.refresher.remove(Fields.MainViewCamera);
2492
2543
  this.manager.refresher.remove(Fields.MainViewSize);
2493
2544
  this.started = false;
@@ -11630,7 +11681,7 @@ const reconnectRefresher = new ReconnectRefresher({ emitter });
11630
11681
  const _WindowManager = class extends InvisiblePlugin {
11631
11682
  constructor(context) {
11632
11683
  super(context);
11633
- this.version = "1.0.0-canary.49";
11684
+ this.version = "1.0.0-canary.51";
11634
11685
  this.dependencies = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.1.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "2.16.26" } };
11635
11686
  this.emitter = callbacks;
11636
11687
  this.viewMode = ViewMode.Broadcaster;
@@ -11703,8 +11754,8 @@ const _WindowManager = class extends InvisiblePlugin {
11703
11754
  const cursor = params.cursor;
11704
11755
  _WindowManager.params = params;
11705
11756
  _WindowManager.displayer = params.room;
11706
- checkVersion();
11707
11757
  let manager = void 0;
11758
+ checkVersion();
11708
11759
  if (isRoom(room)) {
11709
11760
  if (room.phase !== RoomPhase.Connected) {
11710
11761
  throw new Error("[WindowManager]: Room only Connected can be mount");
@@ -11761,7 +11812,7 @@ const _WindowManager = class extends InvisiblePlugin {
11761
11812
  emitter.emit("onCreated");
11762
11813
  _WindowManager.isCreated = true;
11763
11814
  try {
11764
- await initDb();
11815
+ await initDb(appRegister);
11765
11816
  } catch (error) {
11766
11817
  console.warn("[WindowManager]: indexedDB open failed");
11767
11818
  console.log(error);
@@ -12413,5 +12464,6 @@ WindowManager.kind = "WindowManager";
12413
12464
  WindowManager.debug = false;
12414
12465
  WindowManager.containerSizeRatio = DEFAULT_CONTAINER_RATIO;
12415
12466
  WindowManager.isCreated = false;
12467
+ WindowManager.registry = appRegister;
12416
12468
  setupBuiltin();
12417
12469
  export { AppCreateError, AppManagerNotInitError, AppNotRegisterError, BindContainerRoomPhaseInvalidError, BoxManagerNotInitializeError, BoxNotCreatedError, BuiltinApps, BuiltinAppsMap, InvalidScenePath, ParamsInvalidError, WhiteWebSDKInvalidError, WindowManager, calculateNextIndex, reconnectRefresher };
package/dist/index.umd.js CHANGED
@@ -165,18 +165,27 @@ var __objRest = (source, exclude) => {
165
165
  const DatabaseName = "__WindowManagerAppCache";
166
166
  let db;
167
167
  let store$1;
168
- const initDb = async () => {
168
+ const initDb = async (appRegister2) => {
169
169
  db = await createDb();
170
+ const items = await queryAll(db);
171
+ items.forEach((item) => {
172
+ appRegister2.downloaded.set(item.kind, item.url);
173
+ });
170
174
  };
171
- const setItem = (key, val) => {
175
+ const setItem = (kind, url, val) => {
172
176
  if (!db)
173
177
  return;
174
- return addRecord(db, { kind: key, sourceCode: val });
178
+ return addRecord(db, { kind, url, sourceCode: val });
175
179
  };
176
- const getItem = async (key) => {
180
+ const getItem = async (kind) => {
177
181
  if (!db)
178
182
  return null;
179
- return await query(db, key);
183
+ return await query(db, kind);
184
+ };
185
+ const removeItem = (key) => {
186
+ if (!db)
187
+ return;
188
+ return deleteRecord(db, key);
180
189
  };
181
190
  function createDb() {
182
191
  return new Promise((resolve, reject) => {
@@ -211,6 +220,14 @@ var __objRest = (source, exclude) => {
211
220
  };
212
221
  });
213
222
  }
223
+ function queryAll(db2) {
224
+ return new Promise((resolve, reject) => {
225
+ const index2 = db2.transaction(["apps"]).objectStore("apps").index("kind");
226
+ const request = index2.getAll();
227
+ request.onerror = (e) => reject(e);
228
+ request.onsuccess = () => resolve(request.result);
229
+ });
230
+ }
214
231
  function addRecord(db2, payload) {
215
232
  return new Promise((resolve, reject) => {
216
233
  const request = db2.transaction(["apps"], "readwrite").objectStore("apps").add(payload);
@@ -218,16 +235,23 @@ var __objRest = (source, exclude) => {
218
235
  request.onerror = () => reject();
219
236
  });
220
237
  }
238
+ function deleteRecord(db2, key) {
239
+ return new Promise((resolve, reject) => {
240
+ const request = db2.transaction(["apps"], "readwrite").objectStore("apps").delete(key);
241
+ request.onsuccess = () => resolve();
242
+ request.onerror = () => reject();
243
+ });
244
+ }
221
245
  const Prefix = "NetlessApp";
222
246
  const TIMEOUT = 1e4;
223
- const getScript = async (url) => {
224
- const item = await getItem(url);
247
+ const getScript = async (kind, url) => {
248
+ const item = await getItem(kind);
225
249
  if (item) {
226
250
  return item.sourceCode;
227
251
  } else {
228
252
  const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
229
253
  const text2 = await result.text();
230
- await setItem(url, text2);
254
+ await setItem(kind, url, text2);
231
255
  return text2;
232
256
  }
233
257
  };
@@ -239,18 +263,25 @@ var __objRest = (source, exclude) => {
239
263
  }
240
264
  return result;
241
265
  };
266
+ const emitSuccess = (kind, url) => {
267
+ callbacks.emit("loadApp", { kind, status: "success" });
268
+ appRegister.downloaded.set(kind, url);
269
+ };
270
+ const emitFailed = (kind, reason) => {
271
+ callbacks.emit("loadApp", { kind, status: "failed", reason });
272
+ };
242
273
  const loadApp = async (url, key, name) => {
243
274
  const appName = name || Prefix + key;
244
275
  callbacks.emit("loadApp", { kind: key, status: "start" });
245
276
  try {
246
- const text2 = await getScript(url);
277
+ const text2 = await getScript(key, url);
247
278
  if (!text2 || text2.length === 0) {
248
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: "script is empty." });
279
+ emitFailed(key, "script is empty");
249
280
  return;
250
281
  }
251
282
  try {
252
283
  const result = executeScript(text2, appName);
253
- callbacks.emit("loadApp", { kind: key, status: "success" });
284
+ emitSuccess(key, url);
254
285
  return result;
255
286
  } catch (error) {
256
287
  if (error.message.includes("Can only have one anonymous define call per script file")) {
@@ -259,13 +290,13 @@ var __objRest = (source, exclude) => {
259
290
  delete define2.amd;
260
291
  }
261
292
  const result = executeScript(text2, appName);
262
- callbacks.emit("loadApp", { kind: key, status: "success" });
293
+ emitSuccess(key, url);
263
294
  return result;
264
295
  }
265
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
296
+ emitFailed(key, error.message);
266
297
  }
267
298
  } catch (error) {
268
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
299
+ emitFailed(key, error.message);
269
300
  }
270
301
  };
271
302
  async function fetchWithTimeout(resource, options) {
@@ -287,6 +318,7 @@ var __objRest = (source, exclude) => {
287
318
  this.registered = /* @__PURE__ */ new Map();
288
319
  this.appClassesCache = /* @__PURE__ */ new Map();
289
320
  this.appClasses = /* @__PURE__ */ new Map();
321
+ this.downloaded = /* @__PURE__ */ new Map();
290
322
  this.syncRegisterApp = null;
291
323
  this.onSyncRegisterAppChange = (payload) => {
292
324
  this.register({ kind: payload.kind, src: payload.src });
@@ -298,27 +330,35 @@ var __objRest = (source, exclude) => {
298
330
  async register(params) {
299
331
  this.appClassesCache.delete(params.kind);
300
332
  this.registered.set(params.kind, params);
301
- const srcOrAppOrFunction = params.src;
333
+ const paramSrc = params.src;
302
334
  let downloadApp;
303
- if (typeof srcOrAppOrFunction === "string") {
335
+ if (typeof paramSrc === "string") {
336
+ downloadApp = async () => {
337
+ const result = await loadApp(paramSrc, params.kind, params.name);
338
+ if (result.__esModule) {
339
+ return result.default;
340
+ }
341
+ return result;
342
+ };
343
+ if (this.syncRegisterApp) {
344
+ this.syncRegisterApp({ kind: params.kind, src: paramSrc, name: params.name });
345
+ }
346
+ }
347
+ if (typeof paramSrc === "function") {
304
348
  downloadApp = async () => {
305
- let appClass = await loadApp(srcOrAppOrFunction, params.kind, params.name);
349
+ let appClass = await paramSrc();
306
350
  if (appClass) {
307
- if (appClass.__esModule) {
351
+ if (appClass.__esModule || appClass.default) {
308
352
  appClass = appClass.default;
309
353
  }
310
354
  return appClass;
311
355
  } else {
312
- throw new Error(`[WindowManager]: load remote script failed, ${srcOrAppOrFunction}`);
356
+ throw new Error(`[WindowManager]: load remote script failed, ${paramSrc}`);
313
357
  }
314
358
  };
315
- if (this.syncRegisterApp) {
316
- this.syncRegisterApp({ kind: params.kind, src: srcOrAppOrFunction, name: params.name });
317
- }
318
- } else if (typeof srcOrAppOrFunction === "function") {
319
- downloadApp = srcOrAppOrFunction;
320
- } else {
321
- downloadApp = async () => srcOrAppOrFunction;
359
+ }
360
+ if (typeof paramSrc === "object") {
361
+ downloadApp = async () => paramSrc;
322
362
  }
323
363
  this.appClasses.set(params.kind, async () => {
324
364
  let app = this.appClassesCache.get(params.kind);
@@ -335,10 +375,21 @@ var __objRest = (source, exclude) => {
335
375
  }
336
376
  }
337
377
  }
378
+ downloadApp(kind) {
379
+ const src = this.registered.get(kind);
380
+ if (src && typeof src.src === "string") {
381
+ return loadApp(src.src, src.kind, src.name);
382
+ }
383
+ }
384
+ async removeDownloaded(kind) {
385
+ await removeItem(kind);
386
+ this.downloaded.delete(kind);
387
+ }
338
388
  unregister(kind) {
339
389
  this.appClasses.delete(kind);
340
390
  this.appClassesCache.delete(kind);
341
391
  this.registered.delete(kind);
392
+ this.removeDownloaded(kind);
342
393
  const kindEmitter = this.kindEmitters.get(kind);
343
394
  if (kindEmitter) {
344
395
  kindEmitter.clearListeners();
@@ -2410,6 +2461,7 @@ var __objRest = (source, exclude) => {
2410
2461
  start() {
2411
2462
  if (this.started)
2412
2463
  return;
2464
+ this.removeCameraListener();
2413
2465
  this.addCameraListener();
2414
2466
  this.addCameraReaction();
2415
2467
  this.started = true;
@@ -2488,7 +2540,6 @@ var __objRest = (source, exclude) => {
2488
2540
  this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
2489
2541
  }
2490
2542
  stop() {
2491
- this.removeCameraListener();
2492
2543
  this.manager.refresher.remove(Fields.MainViewCamera);
2493
2544
  this.manager.refresher.remove(Fields.MainViewSize);
2494
2545
  this.started = false;
@@ -11631,7 +11682,7 @@ var __objRest = (source, exclude) => {
11631
11682
  const _WindowManager = class extends whiteWebSdk.InvisiblePlugin {
11632
11683
  constructor(context) {
11633
11684
  super(context);
11634
- this.version = "1.0.0-canary.49";
11685
+ this.version = "1.0.0-canary.51";
11635
11686
  this.dependencies = { "dependencies": { "@juggle/resize-observer": "^3.3.1", "@netless/telebox-insider": "1.0.0-alpha.37", "emittery": "^0.11.0", "lodash": "^4.17.21", "p-retry": "^4.6.2", "side-effect-manager": "^1.1.1", "uuid": "^7.0.3", "value-enhancer": "^1.3.2" }, "peerDependencies": { "white-web-sdk": "^2.16.0" }, "devDependencies": { "@netless/app-docs-viewer": "^0.3.3", "@netless/app-plyr": "0.2.2", "@playwright/test": "^1.23.2", "@rollup/plugin-commonjs": "^20.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-url": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.49", "@tsconfig/svelte": "^2.0.1", "@types/debug": "^4.1.7", "@types/lodash": "^4.14.182", "@types/lodash-es": "^4.17.6", "@types/node": "^18.0.3", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^4.30.0", "@typescript-eslint/parser": "^4.30.0", "@vitest/ui": "^0.14.2", "cypress": "^8.7.0", "dotenv": "^10.0.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.0", "jsdom": "^19.0.0", "less": "^4.1.3", "prettier": "^2.3.2", "prettier-plugin-svelte": "^2.4.0", "rollup-plugin-analyzer": "^4.0.0", "rollup-plugin-styles": "^3.14.1", "svelte": "^3.42.4", "typescript": "^4.5.5", "vite": "^2.5.3", "vite-plugin-dts": "^1.2.1", "vitest": "^0.18.0", "white-web-sdk": "2.16.26" } };
11636
11687
  this.emitter = callbacks;
11637
11688
  this.viewMode = whiteWebSdk.ViewMode.Broadcaster;
@@ -11704,8 +11755,8 @@ var __objRest = (source, exclude) => {
11704
11755
  const cursor = params.cursor;
11705
11756
  _WindowManager.params = params;
11706
11757
  _WindowManager.displayer = params.room;
11707
- checkVersion();
11708
11758
  let manager = void 0;
11759
+ checkVersion();
11709
11760
  if (whiteWebSdk.isRoom(room)) {
11710
11761
  if (room.phase !== whiteWebSdk.RoomPhase.Connected) {
11711
11762
  throw new Error("[WindowManager]: Room only Connected can be mount");
@@ -11762,7 +11813,7 @@ var __objRest = (source, exclude) => {
11762
11813
  emitter.emit("onCreated");
11763
11814
  _WindowManager.isCreated = true;
11764
11815
  try {
11765
- await initDb();
11816
+ await initDb(appRegister);
11766
11817
  } catch (error) {
11767
11818
  console.warn("[WindowManager]: indexedDB open failed");
11768
11819
  console.log(error);
@@ -12414,6 +12465,7 @@ var __objRest = (source, exclude) => {
12414
12465
  WindowManager.debug = false;
12415
12466
  WindowManager.containerSizeRatio = DEFAULT_CONTAINER_RATIO;
12416
12467
  WindowManager.isCreated = false;
12468
+ WindowManager.registry = appRegister;
12417
12469
  setupBuiltin();
12418
12470
  exports2.AppCreateError = AppCreateError;
12419
12471
  exports2.AppManagerNotInitError = AppManagerNotInitError;
@@ -11,18 +11,20 @@ export declare type SyncRegisterAppPayload = {
11
11
  name: string | undefined;
12
12
  };
13
13
  export declare type SyncRegisterApp = (payload: SyncRegisterAppPayload) => void;
14
- declare class AppRegister {
14
+ export declare class AppRegister {
15
15
  kindEmitters: Map<string, Emittery<RegisterEvents>>;
16
16
  registered: Map<string, RegisterParams>;
17
17
  appClassesCache: Map<string, Promise<NetlessApp>>;
18
18
  appClasses: Map<string, () => Promise<NetlessApp>>;
19
+ downloaded: Map<string, string>;
19
20
  private syncRegisterApp;
20
21
  setSyncRegisterApp(fn: SyncRegisterApp): void;
21
22
  onSyncRegisterAppChange: (payload: SyncRegisterAppPayload) => void;
22
23
  register(params: RegisterParams): Promise<void>;
24
+ downloadApp(kind: string): Promise<NetlessApp<any, any, any, any> | undefined> | undefined;
25
+ removeDownloaded(kind: string): Promise<void>;
23
26
  unregister(kind: string): void;
24
27
  notifyApp<T extends keyof RegisterEvents>(kind: string, event: T, payload: RegisterEvents[T]): Promise<void>;
25
28
  private createKindEmitter;
26
29
  }
27
30
  export declare const appRegister: AppRegister;
28
- export {};
@@ -1,4 +1,4 @@
1
1
  import type { NetlessApp } from "../typings";
2
- export declare const getScript: (url: string) => Promise<string>;
2
+ export declare const getScript: (kind: string, url: string) => Promise<string>;
3
3
  export declare const executeScript: (text: string, appName: string) => NetlessApp;
4
4
  export declare const loadApp: (url: string, key: string, name?: string | undefined) => Promise<NetlessApp | undefined>;
@@ -1,8 +1,11 @@
1
+ import type { AppRegister } from "./index";
1
2
  export declare type Item = {
2
3
  kind: string;
4
+ url: string;
3
5
  sourceCode: string;
4
6
  };
5
- export declare const initDb: () => Promise<void>;
6
- export declare const setItem: (key: string, val: any) => Promise<void> | undefined;
7
- export declare const getItem: (key: string) => Promise<Item | null>;
7
+ export declare const initDb: (appRegister: AppRegister) => Promise<void>;
8
+ export declare const setItem: (kind: string, url: string, val: any) => Promise<void> | undefined;
9
+ export declare const getItem: (kind: string) => Promise<Item | null>;
8
10
  export declare const removeItem: (key: string) => Promise<void> | undefined;
11
+ export declare const getAll: () => Promise<Item[]> | undefined;
@@ -113,6 +113,7 @@ export declare class WindowManager extends InvisiblePlugin<WindowMangerAttribute
113
113
  static debug: boolean;
114
114
  static containerSizeRatio: number;
115
115
  private static isCreated;
116
+ static registry: import("./Register").AppRegister;
116
117
  version: string;
117
118
  dependencies: Record<string, string>;
118
119
  appListeners?: AppListeners;
@@ -66,7 +66,9 @@ export declare type RegisterEvents<SetupResult = any> = {
66
66
  };
67
67
  export declare type RegisterParams<AppOptions = any, SetupResult = any, Attributes = any> = {
68
68
  kind: string;
69
- src: NetlessApp<Attributes, SetupResult> | string | (() => Promise<NetlessApp<Attributes, SetupResult>>);
69
+ src: NetlessApp<Attributes, SetupResult> | string | (() => Promise<NetlessApp<Attributes, SetupResult>>) | (() => Promise<{
70
+ default: NetlessApp<Attributes, SetupResult>;
71
+ }>);
70
72
  appOptions?: AppOptions | (() => AppOptions);
71
73
  addHooks?: (emitter: Emittery<RegisterEvents<SetupResult>>) => void;
72
74
  /** dynamic load app package name */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "1.0.0-canary.49",
3
+ "version": "1.0.0-canary.51",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -1,6 +1,7 @@
1
1
  import Emittery from "emittery";
2
2
  import { loadApp } from "./loader";
3
3
  import type { NetlessApp, RegisterEvents, RegisterParams } from "../typings";
4
+ import { removeItem } from "./storage";
4
5
 
5
6
  export type LoadAppEvent = {
6
7
  kind: string;
@@ -11,11 +12,12 @@ export type LoadAppEvent = {
11
12
  export type SyncRegisterAppPayload = { kind: string, src: string, name: string | undefined };
12
13
  export type SyncRegisterApp = (payload: SyncRegisterAppPayload) => void;
13
14
 
14
- class AppRegister {
15
+ export class AppRegister {
15
16
  public kindEmitters: Map<string, Emittery<RegisterEvents>> = new Map();
16
17
  public registered: Map<string, RegisterParams> = new Map();
17
18
  public appClassesCache: Map<string, Promise<NetlessApp>> = new Map();
18
19
  public appClasses: Map<string, () => Promise<NetlessApp>> = new Map();
20
+ public downloaded: Map<string, string> = new Map();
19
21
 
20
22
  private syncRegisterApp: SyncRegisterApp | null = null;
21
23
 
@@ -31,32 +33,39 @@ class AppRegister {
31
33
  this.appClassesCache.delete(params.kind);
32
34
  this.registered.set(params.kind, params);
33
35
 
34
- const srcOrAppOrFunction = params.src;
36
+ const paramSrc = params.src;
35
37
  let downloadApp: () => Promise<NetlessApp>;
36
38
 
37
- if (typeof srcOrAppOrFunction === "string") {
39
+ if (typeof paramSrc === "string") {
38
40
  downloadApp = async () => {
39
- let appClass = (await loadApp(srcOrAppOrFunction, params.kind, params.name)) as any;
41
+ const result = await loadApp(paramSrc, params.kind, params.name) as any;
42
+ if (result.__esModule) {
43
+ return result.default;
44
+ }
45
+ return result;
46
+ };
47
+ if (this.syncRegisterApp) {
48
+ this.syncRegisterApp({ kind: params.kind, src: paramSrc, name: params.name });
49
+ }
50
+ }
51
+ if (typeof paramSrc === "function") {
52
+ downloadApp = async () => {
53
+ let appClass = await paramSrc() as any;
40
54
  if (appClass) {
41
- if (appClass.__esModule) {
55
+ if (appClass.__esModule || appClass.default) {
42
56
  appClass = appClass.default;
43
57
  }
44
58
  return appClass;
45
59
  } else {
46
60
  throw new Error(
47
- `[WindowManager]: load remote script failed, ${srcOrAppOrFunction}`
61
+ `[WindowManager]: load remote script failed, ${paramSrc}`
48
62
  );
49
63
  }
50
64
  };
51
- if (this.syncRegisterApp) {
52
- this.syncRegisterApp({ kind: params.kind, src: srcOrAppOrFunction, name: params.name });
53
- }
54
- } else if (typeof srcOrAppOrFunction === "function") {
55
- downloadApp = srcOrAppOrFunction;
56
- } else {
57
- downloadApp = async () => srcOrAppOrFunction;
58
65
  }
59
-
66
+ if (typeof paramSrc === "object") {
67
+ downloadApp = async () => paramSrc;
68
+ }
60
69
  this.appClasses.set(params.kind, async () => {
61
70
  let app = this.appClassesCache.get(params.kind);
62
71
  if (!app) {
@@ -74,10 +83,23 @@ class AppRegister {
74
83
  }
75
84
  }
76
85
 
86
+ public downloadApp(kind: string) {
87
+ const src = this.registered.get(kind);
88
+ if (src && typeof src.src === "string") {
89
+ return loadApp(src.src, src.kind, src.name)
90
+ }
91
+ }
92
+
93
+ public async removeDownloaded(kind: string) {
94
+ await removeItem(kind);
95
+ this.downloaded.delete(kind);
96
+ }
97
+
77
98
  public unregister(kind: string) {
78
99
  this.appClasses.delete(kind);
79
100
  this.appClassesCache.delete(kind);
80
101
  this.registered.delete(kind);
102
+ this.removeDownloaded(kind);
81
103
  const kindEmitter = this.kindEmitters.get(kind);
82
104
  if (kindEmitter) {
83
105
  kindEmitter.clearListeners();
@@ -1,19 +1,20 @@
1
1
  import { callbacks } from "../callback";
2
2
  import { getItem, setItem } from "./storage";
3
3
  import type { NetlessApp } from "../typings";
4
+ import { appRegister } from ".";
4
5
 
5
6
  const Prefix = "NetlessApp";
6
7
 
7
8
  const TIMEOUT = 10000; // 下载 script 10 秒超时
8
9
 
9
- export const getScript = async (url: string): Promise<string> => {
10
- const item = await getItem(url);
10
+ export const getScript = async (kind: string, url: string): Promise<string> => {
11
+ const item = await getItem(kind);
11
12
  if (item) {
12
13
  return item.sourceCode;
13
14
  } else {
14
15
  const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
15
16
  const text = await result.text();
16
- await setItem(url, text);
17
+ await setItem(kind, url, text);
17
18
  return text;
18
19
  }
19
20
  };
@@ -28,6 +29,15 @@ export const executeScript = (text: string, appName: string): NetlessApp => {
28
29
  return result;
29
30
  };
30
31
 
32
+ const emitSuccess = (kind: string, url: string) => {
33
+ callbacks.emit("loadApp", { kind, status: "success" });
34
+ appRegister.downloaded.set(kind, url);
35
+ };
36
+
37
+ const emitFailed = (kind: string, reason: string) => {
38
+ callbacks.emit("loadApp", { kind, status: "failed", reason, });
39
+ };
40
+
31
41
  export const loadApp = async (
32
42
  url: string,
33
43
  key: string,
@@ -36,14 +46,14 @@ export const loadApp = async (
36
46
  const appName = name || Prefix + key;
37
47
  callbacks.emit("loadApp", { kind: key, status: "start" });
38
48
  try {
39
- const text = await getScript(url);
49
+ const text = await getScript(key, url);
40
50
  if (!text || text.length === 0) {
41
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: "script is empty." });
51
+ emitFailed(key, "script is empty");
42
52
  return;
43
53
  }
44
54
  try {
45
55
  const result = executeScript(text, appName);
46
- callbacks.emit("loadApp", { kind: key, status: "success" });
56
+ emitSuccess(key, url);
47
57
  return result;
48
58
  } catch (error: any) {
49
59
  if (error.message.includes("Can only have one anonymous define call per script file")) {
@@ -54,16 +64,17 @@ export const loadApp = async (
54
64
  delete define.amd;
55
65
  }
56
66
  const result = executeScript(text, appName);
57
- callbacks.emit("loadApp", { kind: key, status: "success" });
67
+ emitSuccess(key, url);
58
68
  return result;
59
69
  }
60
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
70
+ emitFailed(key, error.message);
61
71
  }
62
72
  } catch (error: any) {
63
- callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
73
+ emitFailed(key, error.message);
64
74
  }
65
75
  };
66
76
 
77
+
67
78
  async function fetchWithTimeout(resource: string, options: RequestInit & { timeout: number }) {
68
79
  const { timeout = 10000 } = options;
69
80
 
@@ -1,3 +1,5 @@
1
+ import type { AppRegister } from "./index";
2
+
1
3
  const DatabaseName = "__WindowManagerAppCache";
2
4
 
3
5
  let db: IDBDatabase;
@@ -5,21 +7,26 @@ let store: IDBObjectStore;
5
7
 
6
8
  export type Item = {
7
9
  kind: string;
10
+ url: string;
8
11
  sourceCode: string;
9
12
  }
10
13
 
11
- export const initDb = async () => {
14
+ export const initDb = async (appRegister: AppRegister) => {
12
15
  db = await createDb();
16
+ const items = await queryAll(db);
17
+ items.forEach(item => {
18
+ appRegister.downloaded.set(item.kind, item.url);
19
+ });
13
20
  }
14
21
 
15
- export const setItem = (key: string, val: any) => {
22
+ export const setItem = (kind: string, url: string, val: any) => {
16
23
  if (!db) return;
17
- return addRecord(db, { kind: key, sourceCode: val })
24
+ return addRecord(db, { kind, url, sourceCode: val })
18
25
  };
19
26
 
20
- export const getItem = async (key: string): Promise<Item | null> => {
27
+ export const getItem = async (kind: string): Promise<Item | null> => {
21
28
  if (!db) return null;
22
- return await query(db, key);
29
+ return await query(db, kind);
23
30
  };
24
31
 
25
32
  export const removeItem = (key: string) => {
@@ -27,6 +34,11 @@ export const removeItem = (key: string) => {
27
34
  return deleteRecord(db, key);
28
35
  };
29
36
 
37
+ export const getAll = () => {
38
+ if (!db) return;
39
+ return queryAll(db);
40
+ }
41
+
30
42
  function createDb(): Promise<IDBDatabase> {
31
43
  return new Promise((resolve, reject) => {
32
44
  const request = indexedDB.open(DatabaseName, 2);
@@ -64,6 +76,15 @@ function query<T>(db: IDBDatabase, val: string): Promise<T | null> {
64
76
  })
65
77
  }
66
78
 
79
+ function queryAll(db: IDBDatabase): Promise<Item[]> {
80
+ return new Promise((resolve, reject) => {
81
+ const index = db.transaction(["apps"]).objectStore("apps").index("kind");
82
+ const request = index.getAll();
83
+ request.onerror = e => reject(e);
84
+ request.onsuccess = () => resolve(request.result);
85
+ });
86
+ }
87
+
67
88
  function addRecord(db: IDBDatabase, payload: any): Promise<void> {
68
89
  return new Promise((resolve, reject) => {
69
90
  const request = db.transaction(["apps"], "readwrite").objectStore("apps").add(payload);
@@ -118,6 +118,7 @@ export class MainViewProxy {
118
118
 
119
119
  public start() {
120
120
  if (this.started) return;
121
+ this.removeCameraListener();
121
122
  this.addCameraListener();
122
123
  this.addCameraReaction();
123
124
  this.started = true;
@@ -279,7 +280,6 @@ export class MainViewProxy {
279
280
  };
280
281
 
281
282
  public stop() {
282
- this.removeCameraListener();
283
283
  this.manager.refresher.remove(Fields.MainViewCamera);
284
284
  this.manager.refresher.remove(Fields.MainViewSize);
285
285
  this.started = false;
package/src/index.ts CHANGED
@@ -166,6 +166,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
166
166
  public static debug = false;
167
167
  public static containerSizeRatio = DEFAULT_CONTAINER_RATIO;
168
168
  private static isCreated = false;
169
+ public static registry = appRegister;
169
170
 
170
171
  public version = __APP_VERSION__;
171
172
  public dependencies = __APP_DEPENDENCIES__;
@@ -198,14 +199,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
198
199
  public static async mount(params: MountParams): Promise<WindowManager> {
199
200
  const room = params.room;
200
201
  WindowManager.container = params.container;
201
-
202
202
  const debug = params.debug;
203
-
204
203
  const cursor = params.cursor;
205
204
  WindowManager.params = params;
206
205
  WindowManager.displayer = params.room;
207
- checkVersion();
208
206
  let manager: WindowManager | undefined = undefined;
207
+
208
+ checkVersion();
209
209
  if (isRoom(room)) {
210
210
  if (room.phase !== RoomPhase.Connected) {
211
211
  throw new Error("[WindowManager]: Room only Connected can be mount");
@@ -273,7 +273,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
273
273
  emitter.emit("onCreated");
274
274
  WindowManager.isCreated = true;
275
275
  try {
276
- await initDb();
276
+ await initDb(appRegister);
277
277
  } catch (error) {
278
278
  console.warn("[WindowManager]: indexedDB open failed");
279
279
  console.log(error);
package/src/typings.ts CHANGED
@@ -72,7 +72,11 @@ export type RegisterEvents<SetupResult = any> = {
72
72
 
73
73
  export type RegisterParams<AppOptions = any, SetupResult = any, Attributes = any> = {
74
74
  kind: string;
75
- src: NetlessApp<Attributes, SetupResult> | string | (() => Promise<NetlessApp<Attributes, SetupResult>>);
75
+ src:
76
+ | NetlessApp<Attributes, SetupResult>
77
+ | string
78
+ | (() => Promise<NetlessApp<Attributes, SetupResult>>)
79
+ | (() => Promise<{ default: NetlessApp<Attributes, SetupResult> }>);
76
80
  appOptions?: AppOptions | (() => AppOptions);
77
81
  addHooks?: (emitter: Emittery<RegisterEvents<SetupResult>>) => void;
78
82
  /** dynamic load app package name */