feat(electron): move preload to infra (#3011)

This commit is contained in:
Alex Yang
2023-07-05 00:43:30 +08:00
parent 1a93429ffa
commit 466b1bb173
20 changed files with 372 additions and 188 deletions

View File

@@ -121,3 +121,7 @@ runs:
run: node apps/electron/node_modules/electron/install.js run: node apps/electron/node_modules/electron/install.js
env: env:
ELECTRON_OVERRIDE_DIST_PATH: ./node_modules/.cache/electron ELECTRON_OVERRIDE_DIST_PATH: ./node_modules/.cache/electron
- name: Build Infra
shell: bash
run: yarn run build:infra

View File

@@ -352,9 +352,6 @@ jobs:
env: env:
NATIVE_TEST: 'true' NATIVE_TEST: 'true'
- name: Build Infra
run: yarn run build:infra
- name: Build Plugins - name: Build Plugins
run: yarn run build:plugins run: yarn run build:plugins
@@ -412,9 +409,6 @@ jobs:
with: with:
electron-install: false electron-install: false
- name: Build Infra
run: yarn run build:infra
- name: Unit Test - name: Unit Test
run: yarn nx test:coverage @affine/monorepo run: yarn nx test:coverage @affine/monorepo

View File

@@ -123,9 +123,6 @@ jobs:
name: before-make-web-static name: before-make-web-static
path: apps/electron/resources/web-static path: apps/electron/resources/web-static
- name: Build Infra
run: yarn run build:infra
- name: Build Plugins - name: Build Plugins
run: yarn run build:plugins run: yarn run build:plugins

View File

@@ -123,9 +123,6 @@ jobs:
name: before-make-web-static name: before-make-web-static
path: apps/electron/resources/web-static path: apps/electron/resources/web-static
- name: Build Infra
run: yarn run build:infra
- name: Build Plugins - name: Build Plugins
run: yarn run build:plugins run: yarn run build:plugins

View File

@@ -4,6 +4,9 @@
# check lockfile is up to date # check lockfile is up to date
yarn install --mode=update-lockfile yarn install --mode=update-lockfile
# build infra code
yarn -T run build:infra
# lint staged files # lint staged files
yarn exec lint-staged yarn exec lint-staged

View File

@@ -1,3 +1,4 @@
import type { RendererToHelper } from '@toeverything/infra/preload/electron';
import { AsyncCall } from 'async-call-rpc'; import { AsyncCall } from 'async-call-rpc';
import { events, handlers } from './exposed'; import { events, handlers } from './exposed';
@@ -30,7 +31,7 @@ function setupRendererConnection(rendererPort: Electron.MessagePortMain) {
}); });
} }
); );
const rpc = AsyncCall<PeersAPIs.RendererToHelper>( const rpc = AsyncCall<RendererToHelper>(
Object.fromEntries(flattenedHandlers), Object.fromEntries(flattenedHandlers),
{ {
channel: { channel: {

View File

@@ -1,12 +1,16 @@
import type {
HelperToMain,
MainToHelper,
} from '@toeverything/infra/preload/electron';
import { AsyncCall } from 'async-call-rpc'; import { AsyncCall } from 'async-call-rpc';
import { getExposedMeta } from './exposed'; import { getExposedMeta } from './exposed';
const helperToMainServer: PeersAPIs.HelperToMain = { const helperToMainServer: HelperToMain = {
getMeta: () => getExposedMeta(), getMeta: () => getExposedMeta(),
}; };
export const mainRPC = AsyncCall<PeersAPIs.MainToHelper>(helperToMainServer, { export const mainRPC = AsyncCall<MainToHelper>(helperToMainServer, {
strict: { strict: {
unknownMessage: false, unknownMessage: false,
}, },

View File

@@ -1,5 +1,9 @@
import path from 'node:path'; import path from 'node:path';
import type {
HelperToMain,
MainToHelper,
} from '@toeverything/infra/preload/electron';
import { type _AsyncVersionOf, AsyncCall } from 'async-call-rpc'; import { type _AsyncVersionOf, AsyncCall } from 'async-call-rpc';
import { import {
app, app,
@@ -36,7 +40,7 @@ class HelperProcessManager {
#process: UtilityProcess; #process: UtilityProcess;
// a rpc server for the main process -> helper process // a rpc server for the main process -> helper process
rpc?: _AsyncVersionOf<PeersAPIs.HelperToMain>; rpc?: _AsyncVersionOf<HelperToMain>;
static instance = new HelperProcessManager(); static instance = new HelperProcessManager();
@@ -86,13 +90,13 @@ class HelperProcessManager {
]); ]);
const appMethods = pickAndBind(app, ['getPath']); const appMethods = pickAndBind(app, ['getPath']);
const mainToHelperServer: PeersAPIs.MainToHelper = { const mainToHelperServer: MainToHelper = {
...dialogMethods, ...dialogMethods,
...shellMethods, ...shellMethods,
...appMethods, ...appMethods,
}; };
this.rpc = AsyncCall<PeersAPIs.HelperToMain>(mainToHelperServer, { this.rpc = AsyncCall<HelperToMain>(mainToHelperServer, {
strict: { strict: {
// the channel is shared for other purposes as well so that we do not want to // the channel is shared for other purposes as well so that we do not want to
// restrict to only JSONRPC messages // restrict to only JSONRPC messages

View File

@@ -1,8 +1,10 @@
import { contextBridge, ipcRenderer } from 'electron'; import { contextBridge, ipcRenderer } from 'electron';
(async () => { (async () => {
const { appInfo, getAffineAPIs } = await import('./affine-apis'); const { appInfo, getElectronAPIs } = await import(
const { apis, events } = getAffineAPIs(); '@toeverything/infra/preload/electron'
);
const { apis, events } = getElectronAPIs();
contextBridge.exposeInMainWorld('appInfo', appInfo); contextBridge.exposeInMainWorld('appInfo', appInfo);
contextBridge.exposeInMainWorld('apis', apis); contextBridge.exposeInMainWorld('apis', apis);

View File

@@ -1,35 +0,0 @@
declare namespace PeersAPIs {
import type { app, dialog, shell } from 'electron';
interface ExposedMeta {
handlers: [string, string[]][];
events: [string, string[]][];
}
// render <-> helper
interface RendererToHelper {
postEvent: (channel: string, ...args: any[]) => void;
}
interface HelperToRenderer {
[key: string]: (...args: any[]) => Promise<any>;
}
// helper <-> main
interface HelperToMain {
getMeta: () => ExposedMeta;
}
type MainToHelper = Pick<
typeof dialog & typeof shell & typeof app,
| 'showOpenDialog'
| 'showSaveDialog'
| 'openExternal'
| 'showItemInFolder'
| 'getPath'
>;
// render <-> main
// these are handled via IPC
// TODO: fix type
}

View File

@@ -1,32 +1,50 @@
{ {
"name": "@toeverything/infra", "name": "@toeverything/infra",
"main": "./src/index.ts", "type": "module",
"module": "./src/index.ts", "module": "./dist/index.mjs",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": { "exports": {
".": "./src/index.ts" ".": {
}, "types": "./dist/index.d.ts",
"publishConfig": { "import": "./dist/index.js",
"module": "./dist/index.mjs", "require": "./dist/index.cjs"
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
}, },
"files": [ "./core/*": {
"dist" "types": "./dist/core/*.d.ts",
] "import": "./dist/core/*.js",
"require": "./dist/core/*.cjs"
},
"./preload/*": {
"types": "./dist/preload/*.d.ts",
"import": "./dist/preload/*.js",
"require": "./dist/preload/*.cjs"
}
}, },
"files": [
"dist"
],
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
"dev": "vite build --watch" "dev": "vite build --watch"
}, },
"devDependencies": { "devDependencies": {
"async-call-rpc": "^6.3.1",
"electron": "link:../../apps/electron/node_modules/electron",
"vite": "^4.3.9", "vite": "^4.3.9",
"vite-plugin-dts": "3.0.2" "vite-plugin-dts": "3.0.2"
}, },
"peerDependencies": {
"async-call-rpc": "*",
"electron": "*"
},
"peerDependenciesMeta": {
"async-call-rpc": {
"optional": true
},
"electron": {
"optional": true
}
},
"version": "0.7.0-beta.0" "version": "0.7.0-beta.0"
} }

3
packages/infra/preload/electron.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
/* eslint-disable */
// @ts-ignore
export * from '../dist/preload/electron';

View File

@@ -0,0 +1,3 @@
/* eslint-disable */
/// <reference types="../dist/preload/electron.d.ts" />
export * from '../dist/preload/electron.js';

View File

@@ -0,0 +1,74 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2018 Andy Wermke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
export type EventMap = {
[key: string]: (...args: any[]) => void;
};
/**
* Type-safe event emitter.
*
* Use it like this:
*
* ```typescript
* type MyEvents = {
* error: (error: Error) => void;
* message: (from: string, content: string) => void;
* }
*
* const myEmitter = new EventEmitter() as TypedEmitter<MyEvents>;
*
* myEmitter.emit("error", "x") // <- Will catch this type error;
* ```
*
* Lifecycle:
* invoke -> handle -> emit -> on/once
*/
export interface TypedEventEmitter<Events extends EventMap> {
addListener<E extends keyof Events>(event: E, listener: Events[E]): this;
on<E extends keyof Events>(event: E, listener: Events[E]): this;
once<E extends keyof Events>(event: E, listener: Events[E]): this;
off<E extends keyof Events>(event: E, listener: Events[E]): this;
removeAllListeners<E extends keyof Events>(event?: E): this;
removeListener<E extends keyof Events>(event: E, listener: Events[E]): this;
emit<E extends keyof Events>(
event: E,
...args: Parameters<Events[E]>
): boolean;
// The sloppy `eventNames()` return type is to mitigate type incompatibilities - see #5
eventNames(): (keyof Events | string | symbol)[];
rawListeners<E extends keyof Events>(event: E): Events[E][];
listeners<E extends keyof Events>(event: E): Events[E][];
listenerCount<E extends keyof Events>(event: E): number;
handle<E extends keyof Events>(event: E, handler: Events[E]): this;
invoke<E extends keyof Events>(
event: E,
...args: Parameters<Events[E]>
): Promise<ReturnType<Events[E]>>;
getMaxListeners(): number;
setMaxListeners(maxListeners: number): this;
}

View File

@@ -1,145 +1,51 @@
export interface WorkspaceMeta { import type {
id: string; ClipboardHandlers,
mainDBPath: string; DBHandlers,
secondaryDBPath?: string; // assume there will be only one DebugHandlers,
} DialogHandlers,
ExportHandlers,
export type PrimitiveHandlers = (...args: any[]) => Promise<any>; UIHandlers,
type TODO = any; UpdaterHandlers,
WorkspaceHandlers,
export abstract class HandlerManager< } from './type';
Namespace extends string, import { HandlerManager } from './type';
Handlers extends Record<string, PrimitiveHandlers>
> {
abstract readonly app: TODO;
abstract readonly namespace: Namespace;
abstract readonly handlers: Handlers;
}
type DBHandlers = {
getDocAsUpdates: (
workspaceId: string,
subdocId?: string
) => Promise<Uint8Array>;
applyDocUpdate: (
id: string,
update: Uint8Array,
subdocId?: string
) => Promise<void>;
addBlob: (
workspaceId: string,
key: string,
data: Uint8Array
) => Promise<void>;
getBlob: (workspaceId: string, key: string) => Promise<any>;
deleteBlob: (workspaceId: string, key: string) => Promise<void>;
getBlobKeys: (workspaceId: string) => Promise<any>;
getDefaultStorageLocation: () => Promise<string>;
};
export abstract class DBHandlerManager extends HandlerManager< export abstract class DBHandlerManager extends HandlerManager<
'db', 'db',
DBHandlers DBHandlers
> {} > {}
type DebugHandlers = {
revealLogFile: () => Promise<string>;
logFilePath: () => Promise<string>;
};
export abstract class DebugHandlerManager extends HandlerManager< export abstract class DebugHandlerManager extends HandlerManager<
'debug', 'debug',
DebugHandlers DebugHandlers
> {} > {}
type DialogHandlers = {
revealDBFile: (workspaceId: string) => Promise<any>;
loadDBFile: () => Promise<any>;
saveDBFileAs: (workspaceId: string) => Promise<any>;
moveDBFile: (workspaceId: string, dbFileLocation?: string) => Promise<any>;
selectDBFileLocation: () => Promise<any>;
setFakeDialogResult: (result: any) => Promise<any>;
};
export abstract class DialogHandlerManager extends HandlerManager< export abstract class DialogHandlerManager extends HandlerManager<
'dialog', 'dialog',
DialogHandlers DialogHandlers
> {} > {}
type UIHandlers = {
handleThemeChange: (theme: 'system' | 'light' | 'dark') => Promise<any>;
handleSidebarVisibilityChange: (visible: boolean) => Promise<any>;
handleMinimizeApp: () => Promise<any>;
handleMaximizeApp: () => Promise<any>;
handleCloseApp: () => Promise<any>;
getGoogleOauthCode: () => Promise<any>;
};
export abstract class UIHandlerManager extends HandlerManager< export abstract class UIHandlerManager extends HandlerManager<
'ui', 'ui',
UIHandlers UIHandlers
> {} > {}
type ClipboardHandlers = {
copyAsImageFromString: (dataURL: string) => Promise<void>;
};
export abstract class ClipboardHandlerManager extends HandlerManager< export abstract class ClipboardHandlerManager extends HandlerManager<
'clipboard', 'clipboard',
ClipboardHandlers ClipboardHandlers
> {} > {}
type ExportHandlers = {
savePDFFileAs: (title: string) => Promise<any>;
};
export abstract class ExportHandlerManager extends HandlerManager< export abstract class ExportHandlerManager extends HandlerManager<
'export', 'export',
ExportHandlers ExportHandlers
> {} > {}
type UpdaterHandlers = {
currentVersion: () => Promise<any>;
quitAndInstall: () => Promise<any>;
checkForUpdatesAndNotify: () => Promise<any>;
};
export abstract class UpdaterHandlerManager extends HandlerManager< export abstract class UpdaterHandlerManager extends HandlerManager<
'updater', 'updater',
UpdaterHandlers UpdaterHandlers
> {} > {}
type WorkspaceHandlers = {
list: () => Promise<[workspaceId: string, meta: WorkspaceMeta][]>;
delete: (id: string) => Promise<void>;
getMeta: (id: string) => Promise<WorkspaceMeta>;
};
export abstract class WorkspaceHandlerManager extends HandlerManager< export abstract class WorkspaceHandlerManager extends HandlerManager<
'workspace', 'workspace',
WorkspaceHandlers WorkspaceHandlers
> {} > {}
export type UnwrapManagerHandlerToServerSide<
ElectronEvent extends {
frameId: number;
processId: number;
},
Manager extends HandlerManager<string, Record<string, PrimitiveHandlers>>
> = {
[K in keyof Manager['handlers']]: Manager['handlers'][K] extends (
...args: infer Args
) => Promise<infer R>
? (event: ElectronEvent, ...args: Args) => Promise<R>
: never;
};
export type UnwrapManagerHandlerToClientSide<
Manager extends HandlerManager<string, Record<string, PrimitiveHandlers>>
> = {
[K in keyof Manager['handlers']]: Manager['handlers'][K] extends (
...args: infer Args
) => Promise<infer R>
? (...args: Args) => Promise<R>
: never;
};

View File

@@ -1 +1,2 @@
export * from './handler'; export * from './handler';
export * from './type';

View File

@@ -1,14 +1,38 @@
// NOTE: we will generate preload types from this file // Please add modules to `external` in `rollupOptions` to avoid wrong bundling.
import { AsyncCall, type EventBasedChannel } from 'async-call-rpc'; import { AsyncCall, type EventBasedChannel } from 'async-call-rpc';
import type { app, dialog, shell } from 'electron';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
type ExposedMeta = { export interface ExposedMeta {
handlers: [namespace: string, handlerNames: string[]][]; handlers: [string, string[]][];
events: [namespace: string, eventNames: string[]][]; events: [string, string[]][];
}; }
export function getAffineAPIs() { // render <-> helper
export interface RendererToHelper {
postEvent: (channel: string, ...args: any[]) => void;
}
export interface HelperToRenderer {
[key: string]: (...args: any[]) => Promise<any>;
}
// helper <-> main
export interface HelperToMain {
getMeta: () => ExposedMeta;
}
export type MainToHelper = Pick<
typeof dialog & typeof shell & typeof app,
| 'showOpenDialog'
| 'showSaveDialog'
| 'openExternal'
| 'showItemInFolder'
| 'getPath'
>;
export function getElectronAPIs() {
const mainAPIs = getMainAPIs(); const mainAPIs = getMainAPIs();
const helperAPIs = getHelperAPIs(); const helperAPIs = getHelperAPIs();
@@ -126,13 +150,13 @@ function getHelperAPIs() {
return val ? JSON.parse(val) : null; return val ? JSON.parse(val) : null;
})(); })();
const rendererToHelperServer: PeersAPIs.RendererToHelper = { const rendererToHelperServer: RendererToHelper = {
postEvent: (channel, ...args) => { postEvent: (channel, ...args) => {
events$.next({ channel, args }); events$.next({ channel, args });
}, },
}; };
const rpc = AsyncCall<PeersAPIs.HelperToRenderer>(rendererToHelperServer, { const rpc = AsyncCall<HelperToRenderer>(rendererToHelperServer, {
channel: helperPort$.then(helperPort => channel: helperPort$.then(helperPort =>
createMessagePortChannel(helperPort) createMessagePortChannel(helperPort)
), ),
@@ -157,10 +181,10 @@ function getHelperAPIs() {
}; };
const setup = (meta: ExposedMeta) => { const setup = (meta: ExposedMeta) => {
const { handlers: handlersMeta, events: eventsMeta } = meta; const { handlers, events } = meta;
const helperHandlers = Object.fromEntries( const helperHandlers = Object.fromEntries(
handlersMeta.map(([namespace, functionNames]) => { handlers.map(([namespace, functionNames]) => {
return [ return [
namespace, namespace,
Object.fromEntries( Object.fromEntries(
@@ -173,7 +197,7 @@ function getHelperAPIs() {
); );
const helperEvents = Object.fromEntries( const helperEvents = Object.fromEntries(
eventsMeta.map(([namespace, eventNames]) => { events.map(([namespace, eventNames]) => {
return [ return [
namespace, namespace,
Object.fromEntries( Object.fromEntries(

162
packages/infra/src/type.ts Normal file
View File

@@ -0,0 +1,162 @@
import type { TypedEventEmitter } from './core/event-emitter';
export abstract class HandlerManager<
Namespace extends string,
Handlers extends Record<string, PrimitiveHandlers>
> {
static instance: HandlerManager<string, Record<string, PrimitiveHandlers>>;
private _app: App<Namespace, Handlers>;
private _namespace: Namespace;
private _handlers: Handlers;
constructor() {
throw new Error('Method not implemented.');
}
private _initialized = false;
registerHandlers(handlers: Handlers) {
if (this._initialized) {
throw new Error('Already initialized');
}
this._handlers = handlers;
for (const [name, handler] of Object.entries(this._handlers)) {
this._app.handle(`${this._namespace}:${name}`, (async (...args: any[]) =>
handler(...args)) as any);
}
this._initialized = true;
}
invokeHandler<K extends keyof Handlers>(
name: K,
...args: Parameters<Handlers[K]>
): Promise<ReturnType<Handlers[K]>> {
return this._handlers[name](...args);
}
static getInstance(): HandlerManager<
string,
Record<string, PrimitiveHandlers>
> {
throw new Error('Method not implemented.');
}
}
export interface WorkspaceMeta {
id: string;
mainDBPath: string;
secondaryDBPath?: string; // assume there will be only one
}
export type PrimitiveHandlers = (...args: any[]) => Promise<any>;
export type DBHandlers = {
getDocAsUpdates: (
workspaceId: string,
subdocId?: string
) => Promise<Uint8Array>;
applyDocUpdate: (
id: string,
update: Uint8Array,
subdocId?: string
) => Promise<void>;
addBlob: (
workspaceId: string,
key: string,
data: Uint8Array
) => Promise<void>;
getBlob: (workspaceId: string, key: string) => Promise<any>;
deleteBlob: (workspaceId: string, key: string) => Promise<void>;
getBlobKeys: (workspaceId: string) => Promise<any>;
getDefaultStorageLocation: () => Promise<string>;
};
export type DebugHandlers = {
revealLogFile: () => Promise<string>;
logFilePath: () => Promise<string>;
};
export type DialogHandlers = {
revealDBFile: (workspaceId: string) => Promise<any>;
loadDBFile: () => Promise<any>;
saveDBFileAs: (workspaceId: string) => Promise<any>;
moveDBFile: (workspaceId: string, dbFileLocation?: string) => Promise<any>;
selectDBFileLocation: () => Promise<any>;
setFakeDialogResult: (result: any) => Promise<any>;
};
export type UIHandlers = {
handleThemeChange: (theme: 'system' | 'light' | 'dark') => Promise<any>;
handleSidebarVisibilityChange: (visible: boolean) => Promise<any>;
handleMinimizeApp: () => Promise<any>;
handleMaximizeApp: () => Promise<any>;
handleCloseApp: () => Promise<any>;
getGoogleOauthCode: () => Promise<any>;
};
export type ClipboardHandlers = {
copyAsImageFromString: (dataURL: string) => Promise<void>;
};
export type ExportHandlers = {
savePDFFileAs: (title: string) => Promise<any>;
};
export type UpdaterHandlers = {
currentVersion: () => Promise<any>;
quitAndInstall: () => Promise<any>;
checkForUpdatesAndNotify: () => Promise<any>;
};
export type WorkspaceHandlers = {
list: () => Promise<[workspaceId: string, meta: WorkspaceMeta][]>;
delete: (id: string) => Promise<void>;
getMeta: (id: string) => Promise<WorkspaceMeta>;
};
export type EventMap = DBHandlers &
DebugHandlers &
DialogHandlers &
UIHandlers &
ClipboardHandlers &
ExportHandlers &
UpdaterHandlers &
WorkspaceHandlers;
export type UnwrapManagerHandlerToServerSide<
ElectronEvent extends {
frameId: number;
processId: number;
},
Manager extends HandlerManager<string, Record<string, PrimitiveHandlers>>
> = Manager extends HandlerManager<infer _, infer Handlers>
? {
[K in keyof Handlers]: Handlers[K] extends (
...args: infer Args
) => Promise<infer R>
? (event: ElectronEvent, ...args: Args) => Promise<R>
: never;
}
: never;
export type UnwrapManagerHandlerToClientSide<
Manager extends HandlerManager<string, Record<string, PrimitiveHandlers>>
> = Manager extends HandlerManager<infer _, infer Handlers>
? {
[K in keyof Handlers]: Handlers[K] extends (
...args: infer Args
) => Promise<infer R>
? (...args: Args) => Promise<R>
: never;
}
: never;
/**
* @internal
*/
export type App<
Namespace extends string,
Handlers extends Record<string, PrimitiveHandlers>
> = TypedEventEmitter<{
[K in keyof Handlers as `${Namespace}:${K & string}`]: Handlers[K];
}>;

View File

@@ -8,13 +8,19 @@ const root = fileURLToPath(new URL('.', import.meta.url));
export default defineConfig({ export default defineConfig({
build: { build: {
minify: false,
lib: { lib: {
entry: { entry: {
index: resolve(root, 'src/index.ts'), index: resolve(root, 'src/index.ts'),
'core/event-emitter': resolve(root, 'src/core/event-emitter.ts'),
'preload/electron': resolve(root, 'src/preload/electron.ts'),
}, },
formats: ['es', 'cjs'], formats: ['es', 'cjs'],
name: 'AffineInfra', name: 'AffineInfra',
}, },
rollupOptions: {
external: ['electron', 'async-call-rpc', 'rxjs'],
},
}, },
plugins: [ plugins: [
dts({ dts({

View File

@@ -11436,8 +11436,18 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@toeverything/infra@workspace:packages/infra" resolution: "@toeverything/infra@workspace:packages/infra"
dependencies: dependencies:
async-call-rpc: ^6.3.1
electron: "link:../../apps/electron/node_modules/electron"
vite: ^4.3.9 vite: ^4.3.9
vite-plugin-dts: 3.0.2 vite-plugin-dts: 3.0.2
peerDependencies:
async-call-rpc: "*"
electron: "*"
peerDependenciesMeta:
async-call-rpc:
optional: true
electron:
optional: true
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -17052,6 +17062,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"electron@link:../../apps/electron/node_modules/electron::locator=%40toeverything%2Finfra%40workspace%3Apackages%2Finfra":
version: 0.0.0-use.local
resolution: "electron@link:../../apps/electron/node_modules/electron::locator=%40toeverything%2Finfra%40workspace%3Apackages%2Finfra"
languageName: node
linkType: soft
"electron@npm:^25.2.0": "electron@npm:^25.2.0":
version: 25.2.0 version: 25.2.0
resolution: "electron@npm:25.2.0" resolution: "electron@npm:25.2.0"