|  | @@ -37,6 +37,7 @@ import {
 | 
	
		
			
				|  |  |    IAssetsProxy,
 | 
	
		
			
				|  |  |    AppInfo,
 | 
	
		
			
				|  |  |    IPluginSearchServiceHooks,
 | 
	
		
			
				|  |  | +  PageEntity,
 | 
	
		
			
				|  |  |  } from './LSPlugin'
 | 
	
		
			
				|  |  |  import Debug from 'debug'
 | 
	
		
			
				|  |  |  import * as CSS from 'csstype'
 | 
	
	
		
			
				|  | @@ -64,7 +65,7 @@ const logger = new PluginLogger('', { console: true })
 | 
	
		
			
				|  |  |   * @param opts
 | 
	
		
			
				|  |  |   * @param action
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -function registerSimpleCommand (
 | 
	
		
			
				|  |  | +function registerSimpleCommand(
 | 
	
		
			
				|  |  |    this: LSPluginUser,
 | 
	
		
			
				|  |  |    type: string,
 | 
	
		
			
				|  |  |    opts: {
 | 
	
	
		
			
				|  | @@ -109,7 +110,7 @@ function registerSimpleCommand (
 | 
	
		
			
				|  |  |    })
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -function shouldValidUUID (uuid: string) {
 | 
	
		
			
				|  |  | +function shouldValidUUID(uuid: string) {
 | 
	
		
			
				|  |  |    if (!isValidUUID(uuid)) {
 | 
	
		
			
				|  |  |      logger.error(`#${uuid} is not a valid UUID string.`)
 | 
	
		
			
				|  |  |      return false
 | 
	
	
		
			
				|  | @@ -118,7 +119,7 @@ function shouldValidUUID (uuid: string) {
 | 
	
		
			
				|  |  |    return true
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -function checkEffect (p: LSPluginUser) {
 | 
	
		
			
				|  |  | +function checkEffect(p: LSPluginUser) {
 | 
	
		
			
				|  |  |    return p && (p.baseInfo?.effect || !p.baseInfo?.iir)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -126,7 +127,7 @@ let _appBaseInfo: AppInfo = null
 | 
	
		
			
				|  |  |  let _searchServices: Map<string, LSPluginSearchService> = new Map()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  | -  async getInfo (this: LSPluginUser, key) {
 | 
	
		
			
				|  |  | +  async getInfo(this: LSPluginUser, key) {
 | 
	
		
			
				|  |  |      if (!_appBaseInfo) {
 | 
	
		
			
				|  |  |        _appBaseInfo = await this._execCallableAPIAsync('get-app-info')
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -135,7 +136,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    registerCommand: registerSimpleCommand,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerSearchService<T extends IPluginSearchServiceHooks> (
 | 
	
		
			
				|  |  | +  registerSearchService<T extends IPluginSearchServiceHooks>(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      s: T
 | 
	
		
			
				|  |  |    ) {
 | 
	
	
		
			
				|  | @@ -146,7 +147,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      _searchServices.set(s.name, new LSPluginSearchService(this, s))
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerCommandPalette (
 | 
	
		
			
				|  |  | +  registerCommandPalette(
 | 
	
		
			
				|  |  |      opts: { key: string; label: string; keybinding?: SimpleCommandKeybinding },
 | 
	
		
			
				|  |  |      action: SimpleCommandCallback
 | 
	
		
			
				|  |  |    ) {
 | 
	
	
		
			
				|  | @@ -161,7 +162,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerCommandShortcut (
 | 
	
		
			
				|  |  | +  registerCommandShortcut(
 | 
	
		
			
				|  |  |      keybinding: SimpleCommandKeybinding | string,
 | 
	
		
			
				|  |  |      action: SimpleCommandCallback,
 | 
	
		
			
				|  |  |      opts: Partial<{
 | 
	
	
		
			
				|  | @@ -190,7 +191,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerUIItem (
 | 
	
		
			
				|  |  | +  registerUIItem(
 | 
	
		
			
				|  |  |      type: 'toolbar' | 'pagebar',
 | 
	
		
			
				|  |  |      opts: { key: string; template: string }
 | 
	
		
			
				|  |  |    ) {
 | 
	
	
		
			
				|  | @@ -203,7 +204,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerPageMenuItem (
 | 
	
		
			
				|  |  | +  registerPageMenuItem(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      tag: string,
 | 
	
		
			
				|  |  |      action: (e: IHookEvent & { page: string }) => void
 | 
	
	
		
			
				|  | @@ -227,7 +228,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  onBlockRendererSlotted (uuid, callback: (payload: any) => void) {
 | 
	
		
			
				|  |  | +  onBlockRendererSlotted(uuid, callback: (payload: any) => void) {
 | 
	
		
			
				|  |  |      if (!shouldValidUUID(uuid)) return
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      const pid = this.baseInfo.id
 | 
	
	
		
			
				|  | @@ -242,7 +243,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  invokeExternalPlugin (this: LSPluginUser, type: string, ...args: Array<any>) {
 | 
	
		
			
				|  |  | +  invokeExternalPlugin(this: LSPluginUser, type: string, ...args: Array<any>) {
 | 
	
		
			
				|  |  |      type = type?.trim()
 | 
	
		
			
				|  |  |      if (!type) return
 | 
	
		
			
				|  |  |      let [pid, group] = type.split('.')
 | 
	
	
		
			
				|  | @@ -263,7 +264,7 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  setFullScreen (flag) {
 | 
	
		
			
				|  |  | +  setFullScreen(flag) {
 | 
	
		
			
				|  |  |      const sf = (...args) => this._callWin('setFullScreen', ...args)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (flag === 'toggle') {
 | 
	
	
		
			
				|  | @@ -279,11 +280,18 @@ const app: Partial<IAppProxy> = {
 | 
	
		
			
				|  |  |  let registeredCmdUid = 0
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const editor: Partial<IEditorProxy> = {
 | 
	
		
			
				|  |  | -  newBlockUUID (this: LSPluginUser): Promise<string> {
 | 
	
		
			
				|  |  | +  newBlockUUID(this: LSPluginUser): Promise<string> {
 | 
	
		
			
				|  |  |      return this._execCallableAPIAsync('new_block_uuid')
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerSlashCommand (
 | 
	
		
			
				|  |  | +  isPageBlock(
 | 
	
		
			
				|  |  | +    this: LSPluginUser,
 | 
	
		
			
				|  |  | +    block: BlockEntity | PageEntity
 | 
	
		
			
				|  |  | +  ): Boolean {
 | 
	
		
			
				|  |  | +    return block.uuid && block.hasOwnProperty('name')
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  registerSlashCommand(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      tag: string,
 | 
	
		
			
				|  |  |      actions: BlockCommandCallback | Array<SlashCommandAction>
 | 
	
	
		
			
				|  | @@ -331,7 +339,7 @@ const editor: Partial<IEditorProxy> = {
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerBlockContextMenuItem (
 | 
	
		
			
				|  |  | +  registerBlockContextMenuItem(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      label: string,
 | 
	
		
			
				|  |  |      action: BlockCommandCallback
 | 
	
	
		
			
				|  | @@ -354,7 +362,7 @@ const editor: Partial<IEditorProxy> = {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  registerHighlightContextMenuItem (
 | 
	
		
			
				|  |  | +  registerHighlightContextMenuItem(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      label: string,
 | 
	
		
			
				|  |  |      action: SimpleCommandCallback,
 | 
	
	
		
			
				|  | @@ -379,7 +387,7 @@ const editor: Partial<IEditorProxy> = {
 | 
	
		
			
				|  |  |      )
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  scrollToBlockInPage (
 | 
	
		
			
				|  |  | +  scrollToBlockInPage(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      pageName: BlockPageName,
 | 
	
		
			
				|  |  |      blockId: BlockIdentity,
 | 
	
	
		
			
				|  | @@ -395,7 +403,7 @@ const editor: Partial<IEditorProxy> = {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const db: Partial<IDBProxy> = {
 | 
	
		
			
				|  |  | -  onBlockChanged (
 | 
	
		
			
				|  |  | +  onBlockChanged(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      uuid: BlockUUID,
 | 
	
		
			
				|  |  |      callback: (
 | 
	
	
		
			
				|  | @@ -425,7 +433,7 @@ const db: Partial<IDBProxy> = {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  datascriptQuery<T = any> (
 | 
	
		
			
				|  |  | +  datascriptQuery<T = any>(
 | 
	
		
			
				|  |  |      this: LSPluginUser,
 | 
	
		
			
				|  |  |      query: string,
 | 
	
		
			
				|  |  |      ...inputs: Array<any>
 | 
	
	
		
			
				|  | @@ -447,7 +455,7 @@ const git: Partial<IGitProxy> = {}
 | 
	
		
			
				|  |  |  const ui: Partial<IUIProxy> = {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const assets: Partial<IAssetsProxy> = {
 | 
	
		
			
				|  |  | -  makeSandboxStorage (this: LSPluginUser): IAsyncStorage {
 | 
	
		
			
				|  |  | +  makeSandboxStorage(this: LSPluginUser): IAsyncStorage {
 | 
	
		
			
				|  |  |      return new LSPluginFileStorage(this, { assets: true })
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -496,7 +504,7 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |     * @param _baseInfo
 | 
	
		
			
				|  |  |     * @param _caller
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  | -  constructor (
 | 
	
		
			
				|  |  | +  constructor(
 | 
	
		
			
				|  |  |      private _baseInfo: LSPluginBaseInfo,
 | 
	
		
			
				|  |  |      private _caller: LSPluginCaller
 | 
	
		
			
				|  |  |    ) {
 | 
	
	
		
			
				|  | @@ -529,7 +537,7 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Life related
 | 
	
		
			
				|  |  | -  async ready (model?: any, callback?: any) {
 | 
	
		
			
				|  |  | +  async ready(model?: any, callback?: any) {
 | 
	
		
			
				|  |  |      if (this._connected) return
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      try {
 | 
	
	
		
			
				|  | @@ -576,39 +584,39 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  ensureConnected () {
 | 
	
		
			
				|  |  | +  ensureConnected() {
 | 
	
		
			
				|  |  |      if (!this._connected) {
 | 
	
		
			
				|  |  |        throw new Error('not connected')
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  beforeunload (callback: (e: any) => Promise<void>): void {
 | 
	
		
			
				|  |  | +  beforeunload(callback: (e: any) => Promise<void>): void {
 | 
	
		
			
				|  |  |      if (typeof callback !== 'function') return
 | 
	
		
			
				|  |  |      this._beforeunloadCallback = callback
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  provideModel (model: Record<string, any>) {
 | 
	
		
			
				|  |  | +  provideModel(model: Record<string, any>) {
 | 
	
		
			
				|  |  |      this.caller._extendUserModel(model)
 | 
	
		
			
				|  |  |      return this
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  provideTheme (theme: Theme) {
 | 
	
		
			
				|  |  | +  provideTheme(theme: Theme) {
 | 
	
		
			
				|  |  |      this.caller.call('provider:theme', theme)
 | 
	
		
			
				|  |  |      return this
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  provideStyle (style: StyleString) {
 | 
	
		
			
				|  |  | +  provideStyle(style: StyleString) {
 | 
	
		
			
				|  |  |      this.caller.call('provider:style', style)
 | 
	
		
			
				|  |  |      return this
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  provideUI (ui: UIOptions) {
 | 
	
		
			
				|  |  | +  provideUI(ui: UIOptions) {
 | 
	
		
			
				|  |  |      this.caller.call('provider:ui', ui)
 | 
	
		
			
				|  |  |      return this
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Settings related
 | 
	
		
			
				|  |  | -  useSettingsSchema (schema: Array<SettingSchemaDesc>) {
 | 
	
		
			
				|  |  | +  useSettingsSchema(schema: Array<SettingSchemaDesc>) {
 | 
	
		
			
				|  |  |      if (this.connected) {
 | 
	
		
			
				|  |  |        this.caller.call('settings:schema', {
 | 
	
		
			
				|  |  |          schema,
 | 
	
	
		
			
				|  | @@ -620,35 +628,35 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |      return this
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  updateSettings (attrs: Record<string, any>) {
 | 
	
		
			
				|  |  | +  updateSettings(attrs: Record<string, any>) {
 | 
	
		
			
				|  |  |      this.caller.call('settings:update', attrs)
 | 
	
		
			
				|  |  |      // TODO: update associated baseInfo settings
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  onSettingsChanged<T = any> (cb: (a: T, b: T) => void): IUserOffHook {
 | 
	
		
			
				|  |  | +  onSettingsChanged<T = any>(cb: (a: T, b: T) => void): IUserOffHook {
 | 
	
		
			
				|  |  |      const type = 'settings:changed'
 | 
	
		
			
				|  |  |      this.on(type, cb)
 | 
	
		
			
				|  |  |      return () => this.off(type, cb)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  showSettingsUI () {
 | 
	
		
			
				|  |  | +  showSettingsUI() {
 | 
	
		
			
				|  |  |      this.caller.call('settings:visible:changed', { visible: true })
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  hideSettingsUI () {
 | 
	
		
			
				|  |  | +  hideSettingsUI() {
 | 
	
		
			
				|  |  |      this.caller.call('settings:visible:changed', { visible: false })
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // UI related
 | 
	
		
			
				|  |  | -  setMainUIAttrs (attrs: Partial<UIContainerAttrs>): void {
 | 
	
		
			
				|  |  | +  setMainUIAttrs(attrs: Partial<UIContainerAttrs>): void {
 | 
	
		
			
				|  |  |      this.caller.call('main-ui:attrs', attrs)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  setMainUIInlineStyle (style: CSS.Properties): void {
 | 
	
		
			
				|  |  | +  setMainUIInlineStyle(style: CSS.Properties): void {
 | 
	
		
			
				|  |  |      this.caller.call('main-ui:style', style)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  hideMainUI (opts?: { restoreEditingCursor: boolean }): void {
 | 
	
		
			
				|  |  | +  hideMainUI(opts?: { restoreEditingCursor: boolean }): void {
 | 
	
		
			
				|  |  |      const payload = {
 | 
	
		
			
				|  |  |        key: KEY_MAIN_UI,
 | 
	
		
			
				|  |  |        visible: false,
 | 
	
	
		
			
				|  | @@ -659,7 +667,7 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |      this._ui.set(payload.key, payload)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  showMainUI (opts?: { autoFocus: boolean }): void {
 | 
	
		
			
				|  |  | +  showMainUI(opts?: { autoFocus: boolean }): void {
 | 
	
		
			
				|  |  |      const payload = {
 | 
	
		
			
				|  |  |        key: KEY_MAIN_UI,
 | 
	
		
			
				|  |  |        visible: true,
 | 
	
	
		
			
				|  | @@ -670,7 +678,7 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |      this._ui.set(payload.key, payload)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  toggleMainUI (): void {
 | 
	
		
			
				|  |  | +  toggleMainUI(): void {
 | 
	
		
			
				|  |  |      const payload = { key: KEY_MAIN_UI, toggle: true }
 | 
	
		
			
				|  |  |      const state = this._ui.get(payload.key)
 | 
	
		
			
				|  |  |      if (state && state.visible) {
 | 
	
	
		
			
				|  | @@ -681,40 +689,40 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Getters
 | 
	
		
			
				|  |  | -  get version (): string {
 | 
	
		
			
				|  |  | +  get version(): string {
 | 
	
		
			
				|  |  |      return this._version
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get isMainUIVisible (): boolean {
 | 
	
		
			
				|  |  | +  get isMainUIVisible(): boolean {
 | 
	
		
			
				|  |  |      const state = this._ui.get(KEY_MAIN_UI)
 | 
	
		
			
				|  |  |      return Boolean(state && state.visible)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get connected (): boolean {
 | 
	
		
			
				|  |  | +  get connected(): boolean {
 | 
	
		
			
				|  |  |      return this._connected
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get baseInfo (): LSPluginBaseInfo {
 | 
	
		
			
				|  |  | +  get baseInfo(): LSPluginBaseInfo {
 | 
	
		
			
				|  |  |      return this._baseInfo
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get effect (): Boolean {
 | 
	
		
			
				|  |  | +  get effect(): Boolean {
 | 
	
		
			
				|  |  |      return checkEffect(this)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get logger () {
 | 
	
		
			
				|  |  | +  get logger() {
 | 
	
		
			
				|  |  |      return logger
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get settings () {
 | 
	
		
			
				|  |  | +  get settings() {
 | 
	
		
			
				|  |  |      return this.baseInfo?.settings
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get caller (): LSPluginCaller {
 | 
	
		
			
				|  |  | +  get caller(): LSPluginCaller {
 | 
	
		
			
				|  |  |      return this._caller
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  resolveResourceFullUrl (filePath: string) {
 | 
	
		
			
				|  |  | +  resolveResourceFullUrl(filePath: string) {
 | 
	
		
			
				|  |  |      this.ensureConnected()
 | 
	
		
			
				|  |  |      if (!filePath) return
 | 
	
		
			
				|  |  |      filePath = filePath.replace(/^[.\\/]+/, '')
 | 
	
	
		
			
				|  | @@ -724,12 +732,12 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |    /**
 | 
	
		
			
				|  |  |     * @internal
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  | -  _makeUserProxy (target: any, tag?: UserProxyTags) {
 | 
	
		
			
				|  |  | +  _makeUserProxy(target: any, tag?: UserProxyTags) {
 | 
	
		
			
				|  |  |      const that = this
 | 
	
		
			
				|  |  |      const caller = this.caller
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return new Proxy(target, {
 | 
	
		
			
				|  |  | -      get (target: any, propKey, receiver) {
 | 
	
		
			
				|  |  | +      get(target: any, propKey, _receiver) {
 | 
	
		
			
				|  |  |          const origMethod = target[propKey]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          return function (this: any, ...args: any) {
 | 
	
	
		
			
				|  | @@ -800,68 +808,74 @@ export class LSPluginUser
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  _execCallableAPIAsync (method: callableMethods, ...args) {
 | 
	
		
			
				|  |  | +  _execCallableAPIAsync(method: callableMethods, ...args) {
 | 
	
		
			
				|  |  |      return this._caller.callAsync(`api:call`, {
 | 
	
		
			
				|  |  |        method,
 | 
	
		
			
				|  |  |        args,
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  _execCallableAPI (method: callableMethods, ...args) {
 | 
	
		
			
				|  |  | +  _execCallableAPI(method: callableMethods, ...args) {
 | 
	
		
			
				|  |  |      this._caller.call(`api:call`, {
 | 
	
		
			
				|  |  |        method,
 | 
	
		
			
				|  |  |        args,
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  _callWin (...args) {
 | 
	
		
			
				|  |  | +  _callWin(...args) {
 | 
	
		
			
				|  |  |      return this._execCallableAPIAsync(`_callMainWin`, ...args)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // User Proxies
 | 
	
		
			
				|  |  |    #appProxy: IAppProxy
 | 
	
		
			
				|  |  | +  #editorProxy: IEditorProxy
 | 
	
		
			
				|  |  | +  #dbProxy: IDBProxy
 | 
	
		
			
				|  |  | +  #uiProxy: IUIProxy
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /**
 | 
	
		
			
				|  |  |     * The interface methods of {@link IAppProxy}
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  | -  get App (): IAppProxy {
 | 
	
		
			
				|  |  | +  get App(): IAppProxy {
 | 
	
		
			
				|  |  |      if (this.#appProxy) return this.#appProxy
 | 
	
		
			
				|  |  |      return (this.#appProxy = this._makeUserProxy(app, 'app'))
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get Editor (): IEditorProxy {
 | 
	
		
			
				|  |  | -    return this._makeUserProxy(editor, 'editor')
 | 
	
		
			
				|  |  | +  get Editor(): IEditorProxy {
 | 
	
		
			
				|  |  | +    if (this.#editorProxy) return this.#editorProxy
 | 
	
		
			
				|  |  | +    return (this.#editorProxy = this._makeUserProxy(editor, 'editor'))
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get DB (): IDBProxy {
 | 
	
		
			
				|  |  | -    return this._makeUserProxy(db, 'db')
 | 
	
		
			
				|  |  | +  get DB(): IDBProxy {
 | 
	
		
			
				|  |  | +    if (this.#dbProxy) return this.#dbProxy
 | 
	
		
			
				|  |  | +    return (this.#dbProxy = this._makeUserProxy(db, 'db'))
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get Git (): IGitProxy {
 | 
	
		
			
				|  |  | -    return this._makeUserProxy(git, 'git')
 | 
	
		
			
				|  |  | +  get UI(): IUIProxy {
 | 
	
		
			
				|  |  | +    if (this.#uiProxy) return this.#uiProxy
 | 
	
		
			
				|  |  | +    return (this.#uiProxy = this._makeUserProxy(ui, 'ui'))
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get UI (): IUIProxy {
 | 
	
		
			
				|  |  | -    return this._makeUserProxy(ui, 'ui')
 | 
	
		
			
				|  |  | +  get Git(): IGitProxy {
 | 
	
		
			
				|  |  | +    return this._makeUserProxy(git, 'git')
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get Assets (): IAssetsProxy {
 | 
	
		
			
				|  |  | +  get Assets(): IAssetsProxy {
 | 
	
		
			
				|  |  |      return this._makeUserProxy(assets, 'assets')
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get FileStorage (): LSPluginFileStorage {
 | 
	
		
			
				|  |  | +  get FileStorage(): LSPluginFileStorage {
 | 
	
		
			
				|  |  |      let m = this._mFileStorage
 | 
	
		
			
				|  |  |      if (!m) m = this._mFileStorage = new LSPluginFileStorage(this)
 | 
	
		
			
				|  |  |      return m
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get Request (): LSPluginRequest {
 | 
	
		
			
				|  |  | +  get Request(): LSPluginRequest {
 | 
	
		
			
				|  |  |      let m = this._mRequest
 | 
	
		
			
				|  |  |      if (!m) m = this._mRequest = new LSPluginRequest(this)
 | 
	
		
			
				|  |  |      return m
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  get Experiments (): LSPluginExperiments {
 | 
	
		
			
				|  |  | +  get Experiments(): LSPluginExperiments {
 | 
	
		
			
				|  |  |      let m = this._mExperiments
 | 
	
		
			
				|  |  |      if (!m) m = this._mExperiments = new LSPluginExperiments(this)
 | 
	
		
			
				|  |  |      return m
 | 
	
	
		
			
				|  | @@ -873,7 +887,7 @@ export * from './LSPlugin'
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * @internal
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -export function setupPluginUserInstance (
 | 
	
		
			
				|  |  | +export function setupPluginUserInstance(
 | 
	
		
			
				|  |  |    pluginBaseInfo: LSPluginBaseInfo,
 | 
	
		
			
				|  |  |    pluginCaller: LSPluginCaller
 | 
	
		
			
				|  |  |  ) {
 |