From 10f879f29aeafd44ec64604e42d479d33b17a3c3 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Tue, 25 Jul 2023 14:32:34 -0700 Subject: [PATCH] refactor(electron): server side plugin (#3360) --- .../src/components/page-detail-editor.tsx | 23 +- apps/electron/scripts/build-layers.mjs | 1 - apps/electron/scripts/common.mjs | 20 +- apps/electron/scripts/dev.mjs | 29 --- .../scripts/macos-arm64-output-check.mts | 12 +- apps/electron/src/main/plugin.ts | 75 ++---- .../src/main/workers/plugin.worker.ts | 69 ------ package.json | 2 +- packages/cli/src/bin/dev-plugin.ts | 38 ++- packages/plugin-infra/src/manager.ts | 49 +--- packages/plugin-infra/src/server.ts | 4 + packages/plugin-infra/src/type.ts | 162 ------------- packages/plugin-infra/src/webpack-hmr.d.ts | 224 ------------------ plugins/bookmark-block/README.md | 7 - plugins/bookmark-block/assets/preview.png | Bin 63067 -> 0 bytes plugins/bookmark-block/package.json | 19 -- plugins/bookmark-block/project.json | 17 -- plugins/bookmark-block/scripts/build.mjs | 20 -- plugins/bookmark-block/scripts/dev.mjs | 22 -- plugins/bookmark-block/scripts/utils.mjs | 34 --- plugins/bookmark-block/src/index.ts | 30 --- plugins/bookmark-block/tsconfig.json | 16 -- plugins/bookmark/package.json | 6 +- .../src/server.ts | 10 +- plugins/copilot/src/UI/debug-content.tsx | 5 +- plugins/copilot/src/UI/index.ts | 12 - tsconfig.json | 3 - yarn.lock | 10 +- 28 files changed, 79 insertions(+), 840 deletions(-) delete mode 100644 apps/electron/src/main/workers/plugin.worker.ts create mode 100644 packages/plugin-infra/src/server.ts delete mode 100644 packages/plugin-infra/src/webpack-hmr.d.ts delete mode 100644 plugins/bookmark-block/README.md delete mode 100644 plugins/bookmark-block/assets/preview.png delete mode 100644 plugins/bookmark-block/package.json delete mode 100644 plugins/bookmark-block/project.json delete mode 100755 plugins/bookmark-block/scripts/build.mjs delete mode 100755 plugins/bookmark-block/scripts/dev.mjs delete mode 100644 plugins/bookmark-block/scripts/utils.mjs delete mode 100644 plugins/bookmark-block/src/index.ts delete mode 100644 plugins/bookmark-block/tsconfig.json rename plugins/{bookmark-block => bookmark}/src/server.ts (88%) delete mode 100644 plugins/copilot/src/UI/index.ts diff --git a/apps/core/src/components/page-detail-editor.tsx b/apps/core/src/components/page-detail-editor.tsx index bfe1605df7..2fb3d78b26 100644 --- a/apps/core/src/components/page-detail-editor.tsx +++ b/apps/core/src/components/page-detail-editor.tsx @@ -9,13 +9,12 @@ import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page- import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page'; import type { CallbackMap } from '@toeverything/plugin-infra/entry'; import { - affinePluginsAtom, contentLayoutAtom, editorItemsAtom, rootStore, windowItemsAtom, } from '@toeverything/plugin-infra/manager'; -import type { AffinePlugin, LayoutNode } from '@toeverything/plugin-infra/type'; +import type { LayoutNode } from '@toeverything/plugin-infra/type'; import clsx from 'clsx'; import { useAtomValue, useSetAtom } from 'jotai'; import type { CSSProperties, FC, ReactElement } from 'react'; @@ -164,7 +163,6 @@ const PluginContentAdapter = memo<{ type LayoutPanelProps = { node: LayoutNode; editorProps: PageDetailEditorProps; - plugins: AffinePlugin[]; }; const LayoutPanel = memo(function LayoutPanel( @@ -189,21 +187,13 @@ const LayoutPanel = memo(function LayoutPanel( > - + - + @@ -219,16 +209,11 @@ export const PageDetailEditor: FC = props => { } const layout = useAtomValue(contentLayoutAtom); - const affinePluginsMap = useAtomValue(affinePluginsAtom); - const plugins = useMemo( - () => Object.values(affinePluginsMap), - [affinePluginsMap] - ); return ( <> - + ); diff --git a/apps/electron/scripts/build-layers.mjs b/apps/electron/scripts/build-layers.mjs index f5584a8e3f..f4a37b1139 100644 --- a/apps/electron/scripts/build-layers.mjs +++ b/apps/electron/scripts/build-layers.mjs @@ -15,7 +15,6 @@ if (process.platform === 'win32') { async function buildLayers() { const common = config(); - await esbuild.build(common.workers); await esbuild.build({ ...common.layers, define: { diff --git a/apps/electron/scripts/common.mjs b/apps/electron/scripts/common.mjs index 3a0747c2b2..7e411b9a06 100644 --- a/apps/electron/scripts/common.mjs +++ b/apps/electron/scripts/common.mjs @@ -15,7 +15,7 @@ const DEV_SERVER_URL = process.env.DEV_SERVER_URL; /** @type 'production' | 'development'' */ const mode = (process.env.NODE_ENV = process.env.NODE_ENV || 'development'); -/** @return {{layers: import('esbuild').BuildOptions, workers: import('esbuild').BuildOptions}} */ +/** @return {{layers: import('esbuild').BuildOptions}} */ export const config = () => { const define = Object.fromEntries([ ['process.env.NODE_ENV', `"${mode}"`], @@ -52,23 +52,5 @@ export const config = () => { assetNames: '[name]', treeShaking: true, }, - workers: { - entryPoints: [ - resolve(electronDir, './src/main/workers/plugin.worker.ts'), - ], - entryNames: '[dir]/[name]', - outdir: resolve(electronDir, './dist/workers'), - bundle: true, - target: `node${NODE_MAJOR_VERSION}`, - platform: 'node', - external: ['@toeverything/plugin-infra', 'async-call-rpc'], - define: define, - format: 'cjs', - loader: { - '.node': 'copy', - }, - assetNames: '[name]', - treeShaking: true, - }, }; }; diff --git a/apps/electron/scripts/dev.mjs b/apps/electron/scripts/dev.mjs index 3c5c4c4bbb..99c552d61e 100644 --- a/apps/electron/scripts/dev.mjs +++ b/apps/electron/scripts/dev.mjs @@ -96,37 +96,8 @@ async function watchLayers() { }); } -async function watchWorkers() { - return new Promise(async resolve => { - let initialBuild = false; - - const buildContext = await esbuild.context({ - ...common.workers, - plugins: [ - ...(common.workers.plugins ?? []), - { - name: 'electron-dev:reload-app-on-workers-change', - setup(build) { - build.onEnd(() => { - if (initialBuild) { - console.log(`[workers] has changed, [re]launching electron...`); - spawnOrReloadElectron(); - } else { - resolve(); - initialBuild = true; - } - }); - }, - }, - ], - }); - await buildContext.watch(); - }); -} - async function main() { await watchLayers(); - await watchWorkers(); if (watchMode) { console.log(`Watching for changes...`); diff --git a/apps/electron/scripts/macos-arm64-output-check.mts b/apps/electron/scripts/macos-arm64-output-check.mts index 0b079e2886..9194ed6bb4 100644 --- a/apps/electron/scripts/macos-arm64-output-check.mts +++ b/apps/electron/scripts/macos-arm64-output-check.mts @@ -16,18 +16,10 @@ const outputList = [ 'preload.js', 'affine.darwin-arm64.node', 'plugins', - 'workers', ], ], - ['dist/plugins', ['bookmark-block']], - ['dist/plugins/bookmark-block', ['index.mjs']], - ['dist/workers', ['plugin.worker.js']], - [ - 'node_modules/@toeverything/plugin-infra/dist', - ['manager.js', 'manager.cjs'], - ], - ['node_modules/@blocksuite/global/dist', ['utils.js']], - ['node_modules/jotai', ['vanilla.js']], + ['dist/plugins', ['bookmark']], + ['dist/plugins/bookmark', ['index.js']], ] as [entry: string, expected: string[]][]; await Promise.all( diff --git a/apps/electron/src/main/plugin.ts b/apps/electron/src/main/plugin.ts index 337cda0619..4cc6cb1ce3 100644 --- a/apps/electron/src/main/plugin.ts +++ b/apps/electron/src/main/plugin.ts @@ -1,12 +1,8 @@ import { join, resolve } from 'node:path'; -import { Worker } from 'node:worker_threads'; import { logger } from '@affine/electron/main/logger'; -import { AsyncCall } from 'async-call-rpc'; import { ipcMain } from 'electron'; -import { MessageEventChannel } from './utils'; - declare global { // fixme(himself65): // remove this when bookmark block plugin is migrated to plugin-infra @@ -15,56 +11,25 @@ declare global { } export function registerPlugin() { - const pluginWorkerPath = join(__dirname, './workers/plugin.worker.js'); - const asyncCall = AsyncCall< - Record PromiseLike> - >( - { - log: (...args: any[]) => { - logger.log('Plugin Worker', ...args); - }, - }, - { - channel: new MessageEventChannel(new Worker(pluginWorkerPath)), - } - ); - globalThis.asyncCall = asyncCall; logger.info('import plugin manager'); - import('@toeverything/plugin-infra/manager') - .then(({ rootStore, affinePluginsAtom }) => { - logger.info('import plugin manager'); - const bookmarkPluginPath = join( - process.env.PLUGIN_DIR ?? resolve(__dirname, './plugins'), - './bookmark-block/index.mjs' - ); - logger.info('bookmark plugin path:', bookmarkPluginPath); - import('file://' + bookmarkPluginPath); - let dispose: () => void = () => { - // noop - }; - rootStore.sub(affinePluginsAtom, () => { - dispose(); - const plugins = rootStore.get(affinePluginsAtom); - Object.values(plugins).forEach(plugin => { - logger.info('register plugin', plugin.definition.id); - plugin.definition.commands.forEach(command => { - logger.info('register plugin command', command); - ipcMain.handle(command, (event, ...args) => - asyncCall[command](...args) - ); - }); - }); - dispose = () => { - Object.values(plugins).forEach(plugin => { - plugin.definition.commands.forEach(command => { - logger.info('unregister plugin command', command); - ipcMain.removeHandler(command); - }); - }); - }; - }); - }) - .catch(error => { - logger.error('import plugin manager error', error); - }); + globalThis.asyncCall = {}; + const bookmarkPluginPath = join( + process.env.PLUGIN_DIR ?? resolve(__dirname, './plugins'), + './bookmark/index.js' + ); + logger.info('bookmark plugin path:', bookmarkPluginPath); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { entry } = require(bookmarkPluginPath); + + entry({ + registerCommand: (command: string, handler: (...args: any[]) => any) => { + logger.info('register plugin command', command); + ipcMain.handle(command, (event, ...args) => handler(...args)); + globalThis.asyncCall[command] = handler; + }, + registerCommands: (command: string) => { + ipcMain.removeHandler(command); + delete globalThis.asyncCall[command]; + }, + }); } diff --git a/apps/electron/src/main/workers/plugin.worker.ts b/apps/electron/src/main/workers/plugin.worker.ts deleted file mode 100644 index a0af86929d..0000000000 --- a/apps/electron/src/main/workers/plugin.worker.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { join, resolve } from 'node:path'; -import { parentPort } from 'node:worker_threads'; - -import { AsyncCall } from 'async-call-rpc'; - -import { MessageEventChannel } from '../utils'; - -const commandProxy: Record Promise> = {}; - -if (!parentPort) { - throw new Error('parentPort is undefined'); -} - -const mainThread = AsyncCall<{ - log: (...args: any[]) => Promise; -}>(commandProxy, { - channel: new MessageEventChannel(parentPort), -}); - -globalThis.console.log = mainThread.log; -globalThis.console.error = mainThread.log; -globalThis.console.info = mainThread.log; -globalThis.console.debug = mainThread.log; -globalThis.console.warn = mainThread.log; - -console.log('import plugin infra'); - -import('@toeverything/plugin-infra/manager') - .then(({ rootStore, affinePluginsAtom }) => { - const bookmarkPluginPath = join( - process.env.PLUGIN_DIR ?? resolve(__dirname, '../plugins'), - './bookmark-block/index.mjs' - ); - - console.log('import bookmark plugin', bookmarkPluginPath); - - import('file://' + bookmarkPluginPath).catch(console.log); - rootStore.sub(affinePluginsAtom, () => { - const plugins = rootStore.get(affinePluginsAtom); - Object.values(plugins).forEach(plugin => { - console.log('handle plugin', plugin.definition.id); - if (plugin.serverAdapter) { - try { - plugin.serverAdapter({ - registerCommand: (command, fn) => { - console.log('register command', command); - commandProxy[command] = fn; - }, - unregisterCommand: command => { - console.log('unregister command', command); - delete commandProxy[command]; - }, - }); - } catch (e) { - console.log( - 'error when handle plugin', - plugin.definition.id, - `${e}` - ); - } - } else { - console.log('no server adapter, skipping.'); - } - }); - }); - }) - .catch(err => { - console.error(err); - }); diff --git a/package.json b/package.json index b524898855..3f8138deb1 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "build:electron": "yarn nx build @affine/electron", "build:storage": "yarn nx run-many -t build -p @affine/storage", "build:infra": "yarn nx run-many -t build -p plugin-infra infra", - "build:plugins": "yarn workspace @affine/bookmark-block build && node ./scripts/build-plugins.mjs", + "build:plugins": "node ./scripts/build-plugins.mjs", "build:storybook": "yarn nx build @affine/storybook", "start:web-static": "yarn workspace @affine/core static-server", "start:storybook": "yarn exec serve apps/storybook/storybook-static -l 6006", diff --git a/packages/cli/src/bin/dev-plugin.ts b/packages/cli/src/bin/dev-plugin.ts index 951868228e..8e650047fd 100644 --- a/packages/cli/src/bin/dev-plugin.ts +++ b/packages/cli/src/bin/dev-plugin.ts @@ -40,6 +40,7 @@ const packageJsonSchema = z.object({ release: z.boolean(), entry: z.object({ core: z.string(), + server: z.string().optional(), }), }), }); @@ -59,6 +60,9 @@ const external = [ // css /^@vanilla-extract/, + + // remove this when bookmark plugin is ready + 'link-preview-js', ]; const allPluginDir = path.resolve(projectRoot, 'plugins'); @@ -91,7 +95,7 @@ const metadata: Metadata = { assets: new Set(), }; -const outDir = path.resolve( +const coreOutDir = path.resolve( projectRoot, 'apps', 'core', @@ -100,15 +104,43 @@ const outDir = path.resolve( plugin ); -const pluginListJsonPath = path.resolve(outDir, '..', 'plugin-list.json'); +const serverOutDir = path.resolve( + projectRoot, + 'apps', + 'electron', + 'dist', + 'plugins', + plugin +); + +const pluginListJsonPath = path.resolve(coreOutDir, '..', 'plugin-list.json'); const coreEntry = path.resolve(pluginDir, json.affinePlugin.entry.core); +if (json.affinePlugin.entry.server) { + const serverEntry = path.resolve(pluginDir, json.affinePlugin.entry.server); + await build({ + build: { + watch: isWatch ? {} : undefined, + minify: false, + outDir: serverOutDir, + emptyOutDir: true, + lib: { + entry: serverEntry, + fileName: 'index', + formats: ['cjs'], + }, + rollupOptions: { + external, + }, + }, + }); +} await build({ build: { watch: isWatch ? {} : undefined, minify: false, - outDir, + outDir: coreOutDir, emptyOutDir: true, lib: { entry: coreEntry, diff --git a/packages/plugin-infra/src/manager.ts b/packages/plugin-infra/src/manager.ts index 6077b47d3e..d1bc3ab9c9 100644 --- a/packages/plugin-infra/src/manager.ts +++ b/packages/plugin-infra/src/manager.ts @@ -4,14 +4,7 @@ import { atom, createStore } from 'jotai/vanilla'; import { getWorkspace, waitForWorkspace } from './__internal__/workspace'; import type { CallbackMap } from './entry'; -import type { - AffinePlugin, - Definition, - ExpectedLayout, - ServerAdapter, -} from './type'; -import type { Loader, PluginUIAdapter } from './type'; -import type { PluginBlockSuiteAdapter } from './type'; +import type { ExpectedLayout } from './type'; // global store export const rootStore = createStore(); @@ -24,10 +17,6 @@ export const editorItemsAtom = atom>({}); export const registeredPluginAtom = atom([]); export const windowItemsAtom = atom>({}); -/** - * @deprecated - */ -export const affinePluginsAtom = atom>>({}); export const currentWorkspaceIdAtom = atom(null); export const currentPageIdAtom = atom(null); export const currentWorkspaceAtom = atom>(async get => { @@ -83,39 +72,3 @@ export const contentLayoutAtom = atom< }); } ); - -export function definePlugin( - definition: Definition, - uiAdapterLoader?: Loader>, - blockSuiteAdapter?: Loader>, - serverAdapter?: Loader -) { - const basePlugin = { - definition, - uiAdapter: undefined, - blockSuiteAdapter: undefined, - }; - - rootStore.set(affinePluginsAtom, plugins => ({ - ...plugins, - [definition.id]: basePlugin, - })); - - if (serverAdapter) { - console.log('register server adapter'); - serverAdapter - .load() - .then(({ default: adapter }) => { - rootStore.set(affinePluginsAtom, plugins => ({ - ...plugins, - [definition.id]: { - ...basePlugin, - serverAdapter: adapter, - }, - })); - }) - .catch(err => { - console.error(err); - }); - } -} diff --git a/packages/plugin-infra/src/server.ts b/packages/plugin-infra/src/server.ts new file mode 100644 index 0000000000..f7f88e3c48 --- /dev/null +++ b/packages/plugin-infra/src/server.ts @@ -0,0 +1,4 @@ +export interface ServerContext { + registerCommand: (command: string, fn: (...args: any[]) => any) => void; + unregisterCommand: (command: string) => void; +} diff --git a/packages/plugin-infra/src/type.ts b/packages/plugin-infra/src/type.ts index a18962622a..5f7b4dbd22 100644 --- a/packages/plugin-infra/src/type.ts +++ b/packages/plugin-infra/src/type.ts @@ -1,84 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/triple-slash-reference -/// - -/** - * AFFiNE Plugin System Types - */ - -import type { EditorContainer } from '@blocksuite/editor'; -import type { Workspace } from '@blocksuite/store'; -import type { Page } from '@playwright/test'; import type { WritableAtom } from 'jotai'; -import type { ReactElement } from 'react'; - -/** - * A code loader interface of the plugin API. - * - * Plugin should be lazy-loaded. If a plugin is not enabled, it will not be loaded into the Mask. - * - * @example - * ```ts - * const loader = { - * load: () => import("./code"), - * hotModuleReload: hot => import.meta.webpackHot && import.meta.webpackHot.accept('./code', () => hot(import("./code"))) - * } - * ``` - * - * The `./code` should use `export default` to export what loader expects. - */ -export interface Loader { - /** - * The `load()` function will be called on demand. - * - * It should not have side effects (e.g. start some daemon, start a new HTTP request or WebSocket client), - * those work should be in the `.init()` function. - * @returns the actual definition of this plugin - * @example load: () => import('./path') - */ - load(): Promise<{ - default: DeferredModule; - }>; - - /** - * This provides the functionality for hot module reload on the plugin. - * When the callback is called, the old instance of the plugin will be unloaded, then the new instance will be init. - * @example hotModuleReload: hot => import.meta.webpackHot && import.meta.webpackHot.accept('./path', () => hot(import('./path'))) - */ - hotModuleReload( - onHot: ( - hot: Promise<{ - default: DeferredModule; - }> - ) => void - ): void; -} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars -interface AFFiNEPlugin { - // todo: add more fields -} - -export interface I18NStringField { - /** The i18n key of the string content. */ - i18nKey?: string; - /** The fallback content to display if there is no i18n string found. */ - fallback: string; -} - -/** The publisher of the plugin */ -export interface Publisher { - /** The name of the publisher */ - name: I18NStringField; - /** URL of the publisher */ - link: string; -} - -/** For what stage the plugin */ -export enum ReleaseStage { - NIGHTLY = 'nightly', - PROD = 'prod', - DEV = 'dev', -} export type LayoutDirection = 'horizontal' | 'vertical'; export type LayoutNode = LayoutParentNode | string; @@ -107,85 +27,3 @@ export type ContentLayoutAtom = WritableAtom< [SetStateAction], void >; - -export type Definition = { - /** - * ID of the plugin. It should be unique. - * @example "com.affine.pro" - */ - id: ID; - /** - * The human-readable name of the plugin. - * @example { i18nKey: "name", fallback: "Never gonna give you up" } - */ - name: I18NStringField; - /** - * A brief description of this plugin. - * @example { i18nKey: "description", fallback: "This plugin is going to replace every link in the page to https://www.youtube.com/watch?v=dQw4w9WgXcQ" } - */ - description?: I18NStringField; - /** - * Publisher of this plugin. - * @example { link: "https://affine.pro", name: { fallback: "AFFiNE", i18nKey: "org_name" } } - */ - publisher?: Publisher; - - /** - * The version of this plugin. - * @example "1.0.0" - */ - version: string; - - /** - * The loader of this plugin. - * @example ReleaseStage.PROD - */ - stage: ReleaseStage; - - /** - * Registered commands - */ - commands: string[]; -}; - -// todo(himself65): support Vue.js -export type Adapter> = ( - props: Props -) => ReactElement; - -export type AffinePluginContext = { - toast: (text: string) => void; -}; - -export type BaseProps = { - contentLayoutAtom: ContentLayoutAtom; -}; - -export type PluginUIAdapter = { - sidebarItem: Adapter; - headerItem: Adapter; - detailContent: Adapter; - debugContent: Adapter>; -}; - -type Cleanup = () => void; - -export type PluginBlockSuiteAdapter = { - storeDecorator: (currentWorkspace: Workspace) => Promise; - pageDecorator: (currentPage: Page) => Cleanup; - uiDecorator: (root: EditorContainer) => Cleanup; -}; - -type AFFiNEServer = { - registerCommand: (command: string, fn: (...args: any[]) => any) => void; - unregisterCommand: (command: string) => void; -}; - -export type ServerAdapter = (affine: AFFiNEServer) => () => void; - -export type AffinePlugin = { - definition: Definition; - uiAdapter: undefined; - blockSuiteAdapter: undefined; - serverAdapter?: ServerAdapter; -}; diff --git a/packages/plugin-infra/src/webpack-hmr.d.ts b/packages/plugin-infra/src/webpack-hmr.d.ts deleted file mode 100644 index 03c144c22f..0000000000 --- a/packages/plugin-infra/src/webpack-hmr.d.ts +++ /dev/null @@ -1,224 +0,0 @@ -// Copied from @types/webpack-env -/** - * Webpack module API - variables and global functions available inside modules - */ - -declare namespace __WebpackModuleApi { - type ModuleId = any; - interface HotNotifierInfo { - type: - | 'self-declined' - | 'declined' - | 'unaccepted' - | 'accepted' - | 'disposed' - | 'accept-errored' - | 'self-accept-errored' - | 'self-accept-error-handler-errored'; - /** - * The module in question. - */ - moduleId: number; - /** - * For errors: the module id owning the accept handler. - */ - dependencyId?: number | undefined; - /** - * For declined/accepted/unaccepted: the chain from where the update was propagated. - */ - chain?: number[] | undefined; - /** - * For declined: the module id of the declining parent - */ - parentId?: number | undefined; - /** - * For accepted: the modules that are outdated and will be disposed - */ - outdatedModules?: number[] | undefined; - /** - * For accepted: The location of accept handlers that will handle the update - */ - outdatedDependencies?: - | { - [dependencyId: number]: number[]; - } - | undefined; - /** - * For errors: the thrown error - */ - error?: Error | undefined; - /** - * For self-accept-error-handler-errored: the error thrown by the module - * before the error handler tried to handle it. - */ - originalError?: Error | undefined; - } - - interface Hot { - /** - * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. - * @param dependencies - * @param callback - * @param errorHandler - */ - accept( - dependencies: string[], - callback?: (updatedDependencies: ModuleId[]) => void, - errorHandler?: (err: Error) => void - ): void; - /** - * Accept code updates for the specified dependencies. The callback is called when dependencies were replaced. - * @param dependency - * @param callback - * @param errorHandler - */ - accept( - dependency: string, - callback?: () => void, - errorHandler?: (err: Error) => void - ): void; - /** - * Accept code updates for this module without notification of parents. - * This should only be used if the module doesn’t export anything. - * The errHandler can be used to handle errors that occur while loading the updated module. - * @param errHandler - */ - accept(errHandler?: (err: Error) => void): void; - /** - * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". - */ - decline(dependencies: string[]): void; - /** - * Do not accept updates for the specified dependencies. If any dependencies is updated, the code update fails with code "decline". - */ - decline(dependency: string): void; - /** - * Flag the current module as not update-able. If updated the update code would fail with code "decline". - */ - decline(): void; - /** - * Add a one time handler, which is executed when the current module code is replaced. - * Here you should destroy/remove any persistent resource you have claimed/created. - * If you want to transfer state to the new module, add it to data object. - * The data will be available at module.hot.data on the new module. - * @param callback - */ - dispose(callback: (data: any) => void): void; - dispose(callback: (data: T) => void): void; - /** - * Add a one time handler, which is executed when the current module code is replaced. - * Here you should destroy/remove any persistent resource you have claimed/created. - * If you want to transfer state to the new module, add it to data object. - * The data will be available at module.hot.data on the new module. - * @param callback - */ - addDisposeHandler(callback: (data: any) => void): void; - addDisposeHandler(callback: (data: T) => void): void; - /** - * Remove a handler. - * This can useful to add a temporary dispose handler. You could i. e. replace code while in the middle of a multi-step async function. - * @param callback - */ - removeDisposeHandler(callback: (data: any) => void): void; - removeDisposeHandler(callback: (data: T) => void): void; - /** - * Throws an exceptions if status() is not idle. - * Check all currently loaded modules for updates and apply updates if found. - * If no update was found, the callback is called with null. - * If autoApply is truthy the callback will be called with all modules that were disposed. - * apply() is automatically called with autoApply as options parameter. - * If autoApply is not set the callback will be called with all modules that will be disposed on apply(). - * @param autoApply - * @param callback - */ - check( - autoApply: boolean, - callback: (err: Error, outdatedModules: ModuleId[]) => void - ): void; - /** - * Throws an exceptions if status() is not idle. - * Check all currently loaded modules for updates and apply updates if found. - * If no update was found, the callback is called with null. - * The callback will be called with all modules that will be disposed on apply(). - * @param callback - */ - check(callback: (err: Error, outdatedModules: ModuleId[]) => void): void; - /** - * If status() != "ready" it throws an error. - * Continue the update process. - * @param options - * @param callback - */ - apply( - options: AcceptOptions, - callback: (err: Error, outdatedModules: ModuleId[]) => void - ): void; - /** - * If status() != "ready" it throws an error. - * Continue the update process. - * @param callback - */ - apply(callback: (err: Error, outdatedModules: ModuleId[]) => void): void; - /** - * Return one of idle, check, watch, watch-delay, prepare, ready, dispose, apply, abort or fail. - */ - status(): string; - /** Register a callback on status change. */ - status(callback: (status: string) => void): void; - /** Register a callback on status change. */ - addStatusHandler(callback: (status: string) => void): void; - /** - * Remove a registered status change handler. - * @param callback - */ - removeStatusHandler(callback: (status: string) => void): void; - - active: boolean; - data: any; - } - - interface AcceptOptions { - /** - * If true the update process continues even if some modules are not accepted (and would bubble to the entry point). - */ - ignoreUnaccepted?: boolean | undefined; - /** - * Ignore changes made to declined modules. - */ - ignoreDeclined?: boolean | undefined; - /** - * Ignore errors throw in accept handlers, error handlers and while reevaluating module. - */ - ignoreErrored?: boolean | undefined; - /** - * Notifier for declined modules. - */ - onDeclined?: ((info: HotNotifierInfo) => void) | undefined; - /** - * Notifier for unaccepted modules. - */ - onUnaccepted?: ((info: HotNotifierInfo) => void) | undefined; - /** - * Notifier for accepted modules. - */ - onAccepted?: ((info: HotNotifierInfo) => void) | undefined; - /** - * Notifier for disposed modules. - */ - onDisposed?: ((info: HotNotifierInfo) => void) | undefined; - /** - * Notifier for errors. - */ - onErrored?: ((info: HotNotifierInfo) => void) | undefined; - /** - * Indicates that apply() is automatically called by check function - */ - autoApply?: boolean | undefined; - } -} -interface ImportMeta { - /** - * `import.meta.webpackHot` is an alias for` module.hot` which is also available in strict ESM - */ - webpackHot?: __WebpackModuleApi.Hot | undefined; -} diff --git a/plugins/bookmark-block/README.md b/plugins/bookmark-block/README.md deleted file mode 100644 index 09faa53788..0000000000 --- a/plugins/bookmark-block/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# `@affine/bookmark-block` - -> Moved to [@affine/bookmark-plugin](../bookmark) -> -> A block for bookmarking a website - -![preview](assets/preview.png) diff --git a/plugins/bookmark-block/assets/preview.png b/plugins/bookmark-block/assets/preview.png deleted file mode 100644 index 7b5ea5c0a9a525db3b49501f13dc2c5c0c9d4f68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63067 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 kL;my3rhDlBV import('./server'), - hotModuleReload: onHot => onHot(import('./server')), - } -); diff --git a/plugins/bookmark-block/tsconfig.json b/plugins/bookmark-block/tsconfig.json deleted file mode 100644 index 1c21e13084..0000000000 --- a/plugins/bookmark-block/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["./src"], - "compilerOptions": { - "noEmit": false, - "outDir": "lib" - }, - "references": [ - { - "path": "../../packages/component" - }, - { - "path": "../../packages/plugin-infra" - } - ] -} diff --git a/plugins/bookmark/package.json b/plugins/bookmark/package.json index 47ec49495d..f8f29c0da6 100644 --- a/plugins/bookmark/package.json +++ b/plugins/bookmark/package.json @@ -4,13 +4,15 @@ "affinePlugin": { "release": true, "entry": { - "core": "./src/index.ts" + "core": "./src/index.ts", + "server": "./src/server.ts" } }, "dependencies": { "@affine/component": "workspace:*", "@blocksuite/icons": "^2.1.27", "@toeverything/plugin-infra": "workspace:*", - "foxact": "^0.2.17" + "foxact": "^0.2.17", + "link-preview-js": "^3.0.4" } } diff --git a/plugins/bookmark-block/src/server.ts b/plugins/bookmark/src/server.ts similarity index 88% rename from plugins/bookmark-block/src/server.ts rename to plugins/bookmark/src/server.ts index 6e95ea381a..c6870fa0af 100644 --- a/plugins/bookmark-block/src/server.ts +++ b/plugins/bookmark/src/server.ts @@ -1,4 +1,4 @@ -import type { ServerAdapter } from '@toeverything/plugin-infra/type'; +import type { ServerContext } from '@toeverything/plugin-infra/server'; import { getLinkPreview } from 'link-preview-js'; type MetaData = { @@ -27,8 +27,8 @@ export interface PreviewType { favicons: string[]; } -const adapter: ServerAdapter = affine => { - affine.registerCommand( +export const entry = (context: ServerContext) => { + context.registerCommand( 'com.blocksuite.bookmark-block.get-bookmark-data-by-link', async (url: string): Promise => { const previewData = (await getLinkPreview(url, { @@ -58,10 +58,8 @@ const adapter: ServerAdapter = affine => { } ); return () => { - affine.unregisterCommand( + context.unregisterCommand( 'com.blocksuite.bookmark-block.get-bookmark-data-by-link' ); }; }; - -export default adapter; diff --git a/plugins/copilot/src/UI/debug-content.tsx b/plugins/copilot/src/UI/debug-content.tsx index 8bedb984de..2bc178ad9f 100644 --- a/plugins/copilot/src/UI/debug-content.tsx +++ b/plugins/copilot/src/UI/debug-content.tsx @@ -1,14 +1,13 @@ import { Button, FlexWrapper, Input } from '@affine/component'; import { SettingRow } from '@affine/component/setting-components'; import { SettingWrapper } from '@affine/component/setting-components'; -import type { PluginUIAdapter } from '@toeverything/plugin-infra/type'; import { useAtom } from 'jotai'; -import { useCallback } from 'react'; +import { type ReactElement, useCallback } from 'react'; import { openAIApiKeyAtom } from '../core/hooks'; import { conversationHistoryDBName } from '../core/langchain/message-history'; -export const DebugContent: PluginUIAdapter['debugContent'] = () => { +export const DebugContent = (): ReactElement => { const [key, setKey] = useAtom(openAIApiKeyAtom); const desc = ( <> diff --git a/plugins/copilot/src/UI/index.ts b/plugins/copilot/src/UI/index.ts deleted file mode 100644 index 4a1d49cecd..0000000000 --- a/plugins/copilot/src/UI/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { PluginUIAdapter } from '@toeverything/plugin-infra/type'; -import { createElement } from 'react'; - -import { DebugContent } from './debug-content'; -import { DetailContent } from './detail-content'; -import { HeaderItem } from './header-item'; - -export default { - headerItem: props => createElement(HeaderItem, props), - detailContent: props => createElement(DetailContent, props), - debugContent: props => createElement(DebugContent, props), -} satisfies Partial; diff --git a/tsconfig.json b/tsconfig.json index 5172333b43..7d795d0ddb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -114,9 +114,6 @@ { "path": "./packages/plugin-infra" }, - { - "path": "./plugins/bookmark-block" - }, { "path": "./plugins/bookmark" }, diff --git a/yarn.lock b/yarn.lock index 28b5d8c966..2f961e63ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -64,15 +64,6 @@ __metadata: languageName: unknown linkType: soft -"@affine/bookmark-block@workspace:plugins/bookmark-block": - version: 0.0.0-use.local - resolution: "@affine/bookmark-block@workspace:plugins/bookmark-block" - dependencies: - "@toeverything/plugin-infra": "workspace:*" - link-preview-js: ^3.0.4 - languageName: unknown - linkType: soft - "@affine/bookmark-plugin@workspace:plugins/bookmark": version: 0.0.0-use.local resolution: "@affine/bookmark-plugin@workspace:plugins/bookmark" @@ -81,6 +72,7 @@ __metadata: "@blocksuite/icons": ^2.1.27 "@toeverything/plugin-infra": "workspace:*" foxact: ^0.2.17 + link-preview-js: ^3.0.4 languageName: unknown linkType: soft