@netless/window-manager 0.4.73-beta.0 → 0.4.73-beta.1

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 (75) hide show
  1. package/dist/index.d.ts +1087 -38
  2. package/dist/index.js +14 -14
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +130 -40
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +7 -7
  7. package/src/App/AppContext.ts +13 -5
  8. package/src/App/AppProxy.ts +2 -2
  9. package/src/App/MagixEvent/index.ts +38 -38
  10. package/src/App/Storage/StorageEvent.ts +13 -13
  11. package/src/App/Storage/index.ts +265 -242
  12. package/src/App/Storage/typings.ts +4 -2
  13. package/src/App/Storage/utils.ts +3 -3
  14. package/src/AppListener.ts +5 -5
  15. package/src/AttributesDelegate.ts +5 -7
  16. package/src/BoxEmitter.ts +12 -6
  17. package/src/BoxManager.ts +1 -1
  18. package/src/ContainerResizeObserver.ts +1 -1
  19. package/src/Helper.ts +67 -15
  20. package/src/InternalEmitter.ts +4 -3
  21. package/src/Page/index.ts +1 -1
  22. package/src/Register/index.ts +5 -7
  23. package/src/Register/loader.ts +1 -1
  24. package/src/Register/storage.ts +13 -13
  25. package/src/Utils/Common.ts +10 -5
  26. package/src/Utils/Reactive.ts +26 -25
  27. package/src/Utils/RoomHacker.ts +1 -1
  28. package/src/Utils/error.ts +0 -1
  29. package/src/View/IframeBridge.ts +627 -583
  30. package/src/View/MainView.ts +7 -2
  31. package/src/callback.ts +7 -1
  32. package/src/index.ts +8 -21
  33. package/src/typings.ts +11 -6
  34. package/dist/App/AppContext.d.ts +0 -79
  35. package/dist/App/AppPageStateImpl.d.ts +0 -17
  36. package/dist/App/AppProxy.d.ts +0 -67
  37. package/dist/App/MagixEvent/index.d.ts +0 -29
  38. package/dist/App/Storage/StorageEvent.d.ts +0 -8
  39. package/dist/App/Storage/index.d.ts +0 -39
  40. package/dist/App/Storage/typings.d.ts +0 -22
  41. package/dist/App/Storage/utils.d.ts +0 -5
  42. package/dist/App/index.d.ts +0 -2
  43. package/dist/AppListener.d.ts +0 -21
  44. package/dist/AppManager.d.ts +0 -110
  45. package/dist/AttributesDelegate.d.ts +0 -91
  46. package/dist/BoxEmitter.d.ts +0 -34
  47. package/dist/BoxManager.d.ts +0 -98
  48. package/dist/BuiltinApps.d.ts +0 -5
  49. package/dist/ContainerResizeObserver.d.ts +0 -11
  50. package/dist/Cursor/Cursor.d.ts +0 -43
  51. package/dist/Cursor/icons.d.ts +0 -3
  52. package/dist/Cursor/icons2.d.ts +0 -4
  53. package/dist/Cursor/index.d.ts +0 -55
  54. package/dist/Helper.d.ts +0 -11
  55. package/dist/InternalEmitter.d.ts +0 -34
  56. package/dist/Page/PageController.d.ts +0 -21
  57. package/dist/Page/index.d.ts +0 -3
  58. package/dist/PageState.d.ts +0 -9
  59. package/dist/ReconnectRefresher.d.ts +0 -24
  60. package/dist/RedoUndo.d.ts +0 -18
  61. package/dist/Register/index.d.ts +0 -28
  62. package/dist/Register/loader.d.ts +0 -4
  63. package/dist/Register/storage.d.ts +0 -8
  64. package/dist/Utils/AppCreateQueue.d.ts +0 -15
  65. package/dist/Utils/Common.d.ts +0 -22
  66. package/dist/Utils/Reactive.d.ts +0 -6
  67. package/dist/Utils/RoomHacker.d.ts +0 -3
  68. package/dist/Utils/error.d.ts +0 -27
  69. package/dist/Utils/log.d.ts +0 -1
  70. package/dist/View/IframeBridge.d.ts +0 -146
  71. package/dist/View/MainView.d.ts +0 -58
  72. package/dist/View/ViewManager.d.ts +0 -13
  73. package/dist/callback.d.ts +0 -38
  74. package/dist/constants.d.ts +0 -48
  75. package/dist/typings.d.ts +0 -84
package/src/BoxEmitter.ts CHANGED
@@ -1,19 +1,25 @@
1
1
  import type { TELE_BOX_STATE } from "@netless/telebox-insider";
2
2
  import Emittery from "emittery";
3
3
 
4
- export type BoxMovePayload = { appId: string, x: number; y: number };
4
+ export type BoxMovePayload = { appId: string; x: number; y: number };
5
5
  export type BoxFocusPayload = { appId: string };
6
- export type BoxResizePayload = { appId: string, width: number; height: number, x?: number, y?: number };
7
- export type BoxClosePayload = { appId: string, error?: Error };
8
- export type BoxStateChangePayload = { appId: string, state: TELE_BOX_STATE };
6
+ export type BoxResizePayload = {
7
+ appId: string;
8
+ width: number;
9
+ height: number;
10
+ x?: number;
11
+ y?: number;
12
+ };
13
+ export type BoxClosePayload = { appId: string; error?: Error };
14
+ export type BoxStateChangePayload = { appId: string; state: TELE_BOX_STATE };
9
15
 
10
16
  export type BoxEvent = {
11
17
  move: BoxMovePayload;
12
18
  focus: BoxFocusPayload;
13
19
  resize: BoxResizePayload;
14
20
  close: BoxClosePayload;
15
- boxStateChange: BoxStateChangePayload
16
- }
21
+ boxStateChange: BoxStateChangePayload;
22
+ };
17
23
 
18
24
  export type BoxEmitterType = Emittery<BoxEvent>;
19
25
  export const boxEmitter: BoxEmitterType = new Emittery();
package/src/BoxManager.ts CHANGED
@@ -79,7 +79,7 @@ export const createBoxManager = (
79
79
  setAppFocus: (appId: string) => manager.appManager?.store.setAppFocus(appId, true),
80
80
  callbacks,
81
81
  emitter,
82
- boxEmitter
82
+ boxEmitter,
83
83
  },
84
84
  options
85
85
  );
@@ -70,6 +70,6 @@ export class ContainerResizeObserver {
70
70
  if (isFunction(this.disposer)) {
71
71
  this.disposer();
72
72
  this.disposer = undefined;
73
- }
73
+ }
74
74
  }
75
75
  }
package/src/Helper.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { getVersionNumber, wait } from "./Utils/Common";
2
- import { log } from "./Utils/log";
3
- import { REQUIRE_VERSION } from "./constants";
1
+ import pRetry from "p-retry";
4
2
  import type { Room, RoomMember } from "white-web-sdk";
5
3
  import { WhiteVersion } from "white-web-sdk";
6
- import { WhiteWebSDKInvalidError } from "./Utils/error";
4
+ import { REQUIRE_VERSION } from "./constants";
7
5
  import { WindowManager } from "./index";
6
+ import { getVersionNumber } from "./Utils/Common";
7
+ import { WhiteWebSDKInvalidError } from "./Utils/error";
8
+ import { log } from "./Utils/log";
8
9
 
9
10
  export const setupWrapper = (
10
11
  root: HTMLElement
@@ -53,19 +54,70 @@ export const findMemberByUid = (room: Room | undefined, uid: string) => {
53
54
  }
54
55
  }
55
56
  return result;
56
- }
57
+ };
58
+
59
+ export const createInvisiblePlugin = async (room: Room): Promise<WindowManager> => {
60
+ let manager = room.getInvisiblePlugin(WindowManager.kind) as WindowManager;
61
+ if (manager) return manager;
57
62
 
58
- export const createInvisiblePlugin = async (room: Room) => {
63
+ let resolve!: (manager: WindowManager) => void;
64
+ const promise = new Promise<WindowManager>(r => {
65
+ // @ts-expect-error Set private property.
66
+ WindowManager._resolve = resolve = r;
67
+ });
68
+
69
+ let wasReadonly = false;
70
+ const canOperate = isRoomTokenWritable(room);
71
+ if (!room.isWritable && canOperate) {
72
+ wasReadonly = true;
73
+ await pRetry(
74
+ async count => {
75
+ log(`switching to writable (x${count})`);
76
+ await room.setWritable(true);
77
+ },
78
+ { retries: 10, maxTimeout: 5000 }
79
+ );
80
+ }
81
+ if (room.isWritable) {
82
+ log("creating InvisiblePlugin...");
83
+ room.createInvisiblePlugin(WindowManager, {}).catch(console.warn);
84
+ } else {
85
+ if (canOperate) console.warn("[WindowManager]: failed to switch to writable");
86
+ console.warn("[WindowManager]: waiting for others to create the plugin...");
87
+ }
88
+
89
+ const timeout = setTimeout(() => {
90
+ console.warn("[WindowManager]: no one called createInvisiblePlugin() after 20 seconds");
91
+ }, 20_000);
92
+
93
+ const abort = setTimeout(() => {
94
+ throw new Error("[WindowManager]: no one called createInvisiblePlugin() after 60 seconds");
95
+ }, 60_000);
96
+
97
+ const interval = setInterval(() => {
98
+ manager = room.getInvisiblePlugin(WindowManager.kind) as WindowManager;
99
+ if (manager) {
100
+ clearTimeout(abort);
101
+ clearTimeout(timeout);
102
+ clearInterval(interval);
103
+ resolve(manager);
104
+ if (wasReadonly && room.isWritable) {
105
+ setTimeout(() => room.setWritable(false).catch(console.warn), 500);
106
+ }
107
+ }
108
+ }, 200);
109
+
110
+ return promise;
111
+ };
112
+
113
+ const isRoomTokenWritable = (room: Room) => {
59
114
  try {
60
- const manager = (await room.createInvisiblePlugin(WindowManager, {})) as WindowManager;
61
- return manager;
115
+ const str = atob(room.roomToken.slice("NETLESSROOM_".length));
116
+ const index = str.indexOf("&role=");
117
+ const role = +str[index + "&role=".length];
118
+ return role < 2;
62
119
  } catch (error) {
63
- // 如果有两个用户同时调用 WindowManager.mount 有概率出现这个错误
64
- if (error.message === `invisible plugin "WindowManager" exits`) {
65
- await wait(200);
66
- return room.getInvisiblePlugin(WindowManager.kind) as WindowManager;
67
- } else {
68
- log("createInvisiblePlugin failed", error);
69
- }
120
+ console.error(error);
121
+ return false;
70
122
  }
71
123
  };
@@ -2,8 +2,9 @@ import Emittery from "emittery";
2
2
  import type { AppInitState, CursorMovePayload } from "./index";
3
3
 
4
4
  export type RemoveSceneParams = {
5
- scenePath: string, index?: number
6
- }
5
+ scenePath: string;
6
+ index?: number;
7
+ };
7
8
 
8
9
  export type EmitterEvent = {
9
10
  onCreated: undefined;
@@ -21,7 +22,7 @@ export type EmitterEvent = {
21
22
  cursorMove: CursorMovePayload;
22
23
  updateManagerRect: undefined;
23
24
  focusedChange: { focused: string | undefined; prev: string | undefined };
24
- rootDirRemoved: undefined; // 根目录整个被删除
25
+ rootDirRemoved: undefined; // 根目录整个被删除
25
26
  rootDirSceneRemoved: string; // 根目录下的场景被删除
26
27
  setReadonly: boolean;
27
28
  changePageState: undefined;
package/src/Page/index.ts CHANGED
@@ -15,4 +15,4 @@ export const calculateNextIndex = (index: number, pageState: PageState) => {
15
15
  nextIndex = pageState.index;
16
16
  }
17
17
  return nextIndex;
18
- }
18
+ };
@@ -8,7 +8,7 @@ export type LoadAppEvent = {
8
8
  reason?: string;
9
9
  };
10
10
 
11
- export type SyncRegisterAppPayload = { kind: string, src: string, name: string | undefined };
11
+ export type SyncRegisterAppPayload = { kind: string; src: string; name: string | undefined };
12
12
  export type SyncRegisterApp = (payload: SyncRegisterAppPayload) => void;
13
13
 
14
14
  class AppRegister {
@@ -25,7 +25,7 @@ class AppRegister {
25
25
 
26
26
  public onSyncRegisterAppChange = (payload: SyncRegisterAppPayload) => {
27
27
  this.register({ kind: payload.kind, src: payload.src });
28
- }
28
+ };
29
29
 
30
30
  public async register(params: RegisterParams): Promise<void> {
31
31
  this.appClassesCache.delete(params.kind);
@@ -36,7 +36,7 @@ class AppRegister {
36
36
 
37
37
  if (typeof paramSrc === "string") {
38
38
  downloadApp = async () => {
39
- const result = await loadApp(paramSrc, params.kind, params.name) as any;
39
+ const result = (await loadApp(paramSrc, params.kind, params.name)) as any;
40
40
  if (result.__esModule) {
41
41
  return result.default;
42
42
  }
@@ -48,16 +48,14 @@ class AppRegister {
48
48
  }
49
49
  if (typeof paramSrc === "function") {
50
50
  downloadApp = async () => {
51
- let appClass = await paramSrc() as any;
51
+ let appClass = (await paramSrc()) as any;
52
52
  if (appClass) {
53
53
  if (appClass.__esModule || appClass.default) {
54
54
  appClass = appClass.default;
55
55
  }
56
56
  return appClass;
57
57
  } else {
58
- throw new Error(
59
- `[WindowManager]: load remote script failed, ${paramSrc}`
60
- );
58
+ throw new Error(`[WindowManager]: load remote script failed, ${paramSrc}`);
61
59
  }
62
60
  };
63
61
  }
@@ -66,7 +66,7 @@ const getResult = (text: string, appName: string, key: string): NetlessApp => {
66
66
  callbacks.emit("loadApp", { kind: key, status: "failed", reason: error.message });
67
67
  throw error;
68
68
  }
69
- }
69
+ };
70
70
 
71
71
  async function fetchWithTimeout(resource: string, options: RequestInit & { timeout: number }) {
72
72
  const { timeout = 10000 } = options;
@@ -6,15 +6,15 @@ let store: IDBObjectStore;
6
6
  export type Item = {
7
7
  kind: string;
8
8
  sourceCode: string;
9
- }
9
+ };
10
10
 
11
11
  export const initDb = async () => {
12
12
  db = await createDb();
13
- }
13
+ };
14
14
 
15
15
  export const setItem = (key: string, val: any) => {
16
16
  if (!db) return;
17
- return addRecord(db, { kind: key, sourceCode: val })
17
+ return addRecord(db, { kind: key, sourceCode: val });
18
18
  };
19
19
 
20
20
  export const getItem = async (key: string): Promise<Item | null> => {
@@ -30,9 +30,9 @@ export const removeItem = (key: string) => {
30
30
  function createDb(): Promise<IDBDatabase> {
31
31
  return new Promise((resolve, reject) => {
32
32
  const request = indexedDB.open(DatabaseName, 2);
33
- request.onerror = (e) => {
33
+ request.onerror = e => {
34
34
  reject(e);
35
- }
35
+ };
36
36
 
37
37
  request.onupgradeneeded = (event: any) => {
38
38
  const db = event.target.result as IDBDatabase;
@@ -40,28 +40,28 @@ function createDb(): Promise<IDBDatabase> {
40
40
  store = db.createObjectStore("apps", { keyPath: "kind" });
41
41
  store.createIndex("kind", "kind", { unique: true });
42
42
  }
43
- }
43
+ };
44
44
 
45
45
  request.onsuccess = () => {
46
46
  const db = request.result;
47
47
  resolve(db);
48
- }
49
- })
48
+ };
49
+ });
50
50
  }
51
51
 
52
52
  function query<T>(db: IDBDatabase, val: string): Promise<T | null> {
53
53
  return new Promise((resolve, reject) => {
54
54
  const index = db.transaction(["apps"]).objectStore("apps").index("kind");
55
55
  const request = index.get(val);
56
- request.onerror = (e) => reject(e);
56
+ request.onerror = e => reject(e);
57
57
  request.onsuccess = () => {
58
58
  if (request.result) {
59
59
  resolve(request.result);
60
60
  } else {
61
61
  resolve(null);
62
62
  }
63
- }
64
- })
63
+ };
64
+ });
65
65
  }
66
66
 
67
67
  function addRecord(db: IDBDatabase, payload: any): Promise<void> {
@@ -69,7 +69,7 @@ function addRecord(db: IDBDatabase, payload: any): Promise<void> {
69
69
  const request = db.transaction(["apps"], "readwrite").objectStore("apps").add(payload);
70
70
  request.onsuccess = () => resolve();
71
71
  request.onerror = () => reject();
72
- })
72
+ });
73
73
  }
74
74
 
75
75
  function deleteRecord(db: IDBDatabase, key: string): Promise<void> {
@@ -77,5 +77,5 @@ function deleteRecord(db: IDBDatabase, key: string): Promise<void> {
77
77
  const request = db.transaction(["apps"], "readwrite").objectStore("apps").delete(key);
78
78
  request.onsuccess = () => resolve();
79
79
  request.onerror = () => reject();
80
- })
80
+ });
81
81
  }
@@ -5,7 +5,7 @@ import { ROOT_DIR } from "../constants";
5
5
  import { ScenePathType } from "white-web-sdk";
6
6
  import { v4 } from "uuid";
7
7
  import type { PublicEvent } from "../callback";
8
- import type { Displayer, ViewVisionMode, Room, View , SceneDefinition} from "white-web-sdk";
8
+ import type { Displayer, ViewVisionMode, Room, View, SceneDefinition } from "white-web-sdk";
9
9
  import type Emittery from "emittery";
10
10
 
11
11
  export const genAppId = async (kind: string) => {
@@ -104,14 +104,19 @@ export const entireScenes = (displayer: Displayer) => {
104
104
  return displayer.entireScenes();
105
105
  };
106
106
 
107
- export const putScenes = (room: Room | undefined, path: string, scenes: SceneDefinition[], index?: number) => {
107
+ export const putScenes = (
108
+ room: Room | undefined,
109
+ path: string,
110
+ scenes: SceneDefinition[],
111
+ index?: number
112
+ ) => {
108
113
  for (let i = 0; i < scenes.length; ++i) {
109
- if (scenes[i].name?.includes('/')) {
114
+ if (scenes[i].name?.includes("/")) {
110
115
  throw new Error("scenes name can not have '/'");
111
116
  }
112
117
  }
113
118
  return room?.putScenes(path, scenes, index);
114
- }
119
+ };
115
120
 
116
121
  export const isValidScenePath = (scenePath: string) => {
117
122
  return scenePath.startsWith("/");
@@ -156,4 +161,4 @@ export const isRootDirPage = (scenePath: string) => {
156
161
  return prev;
157
162
  }, 0);
158
163
  return delimiterCount === 1;
159
- }
164
+ };
@@ -1,5 +1,5 @@
1
1
  import { listenUpdated, unlistenUpdated, reaction, UpdateEventKind } from "white-web-sdk";
2
- import type { AkkoObjectUpdatedProperty , AkkoObjectUpdatedListener } from "white-web-sdk";
2
+ import type { AkkoObjectUpdatedProperty, AkkoObjectUpdatedListener } from "white-web-sdk";
3
3
  import { isObject } from "lodash";
4
4
 
5
5
  // 兼容 13 和 14 版本 SDK
@@ -12,7 +12,7 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
12
12
  if (kinds.includes(event)) {
13
13
  func();
14
14
  }
15
- }
15
+ };
16
16
  listenUpdated(object, listener);
17
17
  func();
18
18
  return () => unlistenUpdated(object, listener);
@@ -21,43 +21,44 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
21
21
  () => object,
22
22
  () => {
23
23
  func();
24
- }, {
24
+ },
25
+ {
25
26
  fireImmediately: true,
26
27
  }
27
- )
28
+ );
28
29
  }
29
- }
30
- }
30
+ };
31
+ };
31
32
 
32
33
  export const safeListenPropsUpdated = <T>(
33
34
  getProps: () => T,
34
35
  callback: AkkoObjectUpdatedListener<T>,
35
36
  onDestroyed?: (props: unknown) => void
36
- ) => {
37
+ ) => {
37
38
  let disposeListenUpdated: (() => void) | null = null;
38
39
  const disposeReaction = reaction(
39
- getProps,
40
- () => {
41
- if (disposeListenUpdated) {
42
- disposeListenUpdated();
43
- disposeListenUpdated = null;
44
- }
45
- const props = getProps();
46
- if (isObject(props)) {
47
- disposeListenUpdated = () => unlistenUpdated(props, callback);
48
- listenUpdated(props, callback);
49
- } else {
50
- onDestroyed?.(props);
51
- }
52
- },
53
- { fireImmediately: true }
40
+ getProps,
41
+ () => {
42
+ if (disposeListenUpdated) {
43
+ disposeListenUpdated();
44
+ disposeListenUpdated = null;
45
+ }
46
+ const props = getProps();
47
+ if (isObject(props)) {
48
+ disposeListenUpdated = () => unlistenUpdated(props, callback);
49
+ listenUpdated(props, callback);
50
+ } else {
51
+ onDestroyed?.(props);
52
+ }
53
+ },
54
+ { fireImmediately: true }
54
55
  );
55
56
 
56
57
  return () => {
57
- disposeListenUpdated?.();
58
- disposeReaction();
58
+ disposeListenUpdated?.();
59
+ disposeReaction();
59
60
  };
60
- }
61
+ };
61
62
 
62
63
  export const onObjectRemoved = onObjectByEvent(UpdateEventKind.Removed);
63
64
  export const onObjectInserted = onObjectByEvent(UpdateEventKind.Inserted);
@@ -78,7 +78,7 @@ const delegateSeekToProgressTime = (player: Player) => {
78
78
  // seek 时需要先关闭所有的 app 防止内部使用的 mobx 出现错误
79
79
  await internalEmitter.emit("seekStart");
80
80
  const seekResult = await originSeek.call(player, time);
81
- internalEmitter.emit("seek", time);
81
+ internalEmitter.emit("seek", time);
82
82
  return seekResult;
83
83
  }
84
84
  player.seekToProgressTime = newSeek;
@@ -1,4 +1,3 @@
1
-
2
1
  export class AppCreateError extends Error {
3
2
  override message = "[WindowManager]: app duplicate exists and cannot be created again";
4
3
  }