feat: add infra code (#2718)

This commit is contained in:
Himself65
2023-06-08 09:41:20 +08:00
committed by GitHub
parent 4958d096b0
commit f3fd5ff76b
22 changed files with 283 additions and 16 deletions

View File

@@ -1,10 +1,19 @@
import type {
DBHandlerManager,
DebugHandlerManager,
DialogHandlerManager,
ExportHandlerManager,
UIHandlerManager,
UpdaterHandlerManager,
WorkspaceHandlerManager,
} from '@toeverything/infra';
import type { HandlerManager, PrimitiveHandlers } from '@toeverything/infra';
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import { dbHandlers } from './db'; import { dbHandlers } from './db';
import { dialogHandlers } from './dialog'; import { dialogHandlers } from './dialog';
import { exportHandlers } from './export'; import { exportHandlers } from './export';
import { getLogFilePath, logger, revealLogFile } from './logger'; import { getLogFilePath, logger, revealLogFile } from './logger';
import type { NamespaceHandlers } from './type';
import { uiHandlers } from './ui'; import { uiHandlers } from './ui';
import { updaterHandlers } from './updater'; import { updaterHandlers } from './updater';
import { workspaceHandlers } from './workspace'; import { workspaceHandlers } from './workspace';
@@ -18,6 +27,26 @@ export const debugHandlers = {
}, },
}; };
type UnwrapManagerHandler<
Manager extends HandlerManager<string, Record<string, PrimitiveHandlers>>
> = {
[K in keyof Manager['handlers']]: Manager['handlers'][K] extends (
...args: infer Args
) => Promise<infer R>
? (event: Electron.IpcMainInvokeEvent, ...args: Args) => Promise<R>
: never;
};
type AllHandlers = {
db: UnwrapManagerHandler<DBHandlerManager>;
debug: UnwrapManagerHandler<DebugHandlerManager>;
dialog: UnwrapManagerHandler<DialogHandlerManager>;
export: UnwrapManagerHandler<ExportHandlerManager>;
ui: UnwrapManagerHandler<UIHandlerManager>;
updater: UnwrapManagerHandler<UpdaterHandlerManager>;
workspace: UnwrapManagerHandler<WorkspaceHandlerManager>;
};
// Note: all of these handlers will be the single-source-of-truth for the apis exposed to the renderer process // Note: all of these handlers will be the single-source-of-truth for the apis exposed to the renderer process
export const allHandlers = { export const allHandlers = {
db: dbHandlers, db: dbHandlers,
@@ -27,7 +56,7 @@ export const allHandlers = {
export: exportHandlers, export: exportHandlers,
updater: updaterHandlers, updater: updaterHandlers,
workspace: workspaceHandlers, workspace: workspaceHandlers,
} satisfies Record<string, NamespaceHandlers>; } satisfies AllHandlers;
export const registerHandlers = () => { export const registerHandlers = () => {
// TODO: listen to namespace instead of individual event types // TODO: listen to namespace instead of individual event types

View File

@@ -35,6 +35,7 @@
"@electron-forge/maker-zip": "^6.1.1", "@electron-forge/maker-zip": "^6.1.1",
"@electron-forge/shared-types": "^6.1.1", "@electron-forge/shared-types": "^6.1.1",
"@electron/remote": "2.0.9", "@electron/remote": "2.0.9",
"@toeverything/infra": "workspace:*",
"@types/fs-extra": "^11.0.1", "@types/fs-extra": "^11.0.1",
"@types/uuid": "^9.0.1", "@types/uuid": "^9.0.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",

View File

@@ -46,7 +46,7 @@ export const config = () => {
bundle: true, bundle: true,
target: `node${NODE_MAJOR_VERSION}`, target: `node${NODE_MAJOR_VERSION}`,
platform: 'node', platform: 'node',
external: ['electron', 'yjs', 'electron-updater'], external: ['electron', 'yjs', 'electron-updater', '@toeverything/infra'],
define: define, define: define,
format: 'cjs', format: 'cjs',
loader: { loader: {

View File

@@ -26,6 +26,9 @@
{ {
"path": "../../packages/env" "path": "../../packages/env"
}, },
{
"path": "../../packages/infra"
},
{ "path": "../../tests/kit" } { "path": "../../tests/kit" }
], ],
"ts-node": { "ts-node": {

View File

@@ -112,6 +112,7 @@ const nextConfig = {
'@affine/copilot', '@affine/copilot',
'@toeverything/hooks', '@toeverything/hooks',
'@toeverything/y-indexeddb', '@toeverything/y-indexeddb',
'@toeverything/infra',
'@toeverything/plugin-infra', '@toeverything/plugin-infra',
], ],
publicRuntimeConfig: { publicRuntimeConfig: {

View File

@@ -35,6 +35,7 @@
"@react-hookz/web": "^23.0.1", "@react-hookz/web": "^23.0.1",
"@sentry/nextjs": "^7.54.0", "@sentry/nextjs": "^7.54.0",
"@toeverything/hooks": "workspace:*", "@toeverything/hooks": "workspace:*",
"@toeverything/infra": "workspace:*",
"@toeverything/plugin-infra": "workspace:*", "@toeverything/plugin-infra": "workspace:*",
"cmdk": "^0.2.0", "cmdk": "^0.2.0",
"css-spring": "^4.1.0", "css-spring": "^4.1.0",

View File

@@ -50,10 +50,8 @@ rootWorkspacesMetadataAtom.onMount = setAtom => {
}, 0); }, 0);
if (environment.isDesktop) { if (environment.isDesktop) {
// @ts-expect-error
window.apis?.workspace.list().then(workspaceIDs => { window.apis?.workspace.list().then(workspaceIDs => {
if (abortController.signal.aborted) return; if (abortController.signal.aborted) return;
// @ts-expect-error
const newMetadata = workspaceIDs.map(w => ({ const newMetadata = workspaceIDs.map(w => ({
id: w[0], id: w[0],
flavour: WorkspaceFlavour.LOCAL, flavour: WorkspaceFlavour.LOCAL,
@@ -61,7 +59,6 @@ rootWorkspacesMetadataAtom.onMount = setAtom => {
setAtom(metadata => { setAtom(metadata => {
return [ return [
...metadata, ...metadata,
// @ts-expect-error
...newMetadata.filter(m => !metadata.find(m2 => m2.id === m.id)), ...newMetadata.filter(m => !metadata.find(m2 => m2.id === m.id)),
]; ];
}); });

View File

@@ -122,7 +122,6 @@ const useDefaultDBLocation = () => {
const [defaultDBLocation, setDefaultDBLocation] = useState(''); const [defaultDBLocation, setDefaultDBLocation] = useState('');
useEffect(() => { useEffect(() => {
// @ts-expect-error
window.apis?.db.getDefaultStorageLocation().then(dir => { window.apis?.db.getDefaultStorageLocation().then(dir => {
setDefaultDBLocation(dir); setDefaultDBLocation(dir);
}); });

View File

@@ -27,7 +27,6 @@ const useShowOpenDBFile = (workspaceId: string) => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
useEffect(() => { useEffect(() => {
if (window.apis && window.events && environment.isDesktop) { if (window.apis && window.events && environment.isDesktop) {
// @ts-expect-error
window.apis.workspace.getMeta(workspaceId).then(meta => { window.apis.workspace.getMeta(workspaceId).then(meta => {
setShow(!!meta.secondaryDBPath); setShow(!!meta.secondaryDBPath);
}); });

View File

@@ -4,7 +4,6 @@
"main": "./src/index.ts", "main": "./src/index.ts",
"module": "./src/index.ts", "module": "./src/index.ts",
"devDependencies": { "devDependencies": {
"@affine/templates": "workspace:*",
"@blocksuite/global": "0.0.0-20230606130340-805f430b-nightly", "@blocksuite/global": "0.0.0-20230606130340-805f430b-nightly",
"next": "=13.4.2", "next": "=13.4.2",
"react": "18.3.0-canary-16d053d59-20230506", "react": "18.3.0-canary-16d053d59-20230506",
@@ -21,7 +20,9 @@
"./blocksuite": "./src/blocksuite/index.ts" "./blocksuite": "./src/blocksuite/index.ts"
}, },
"peerDependencies": { "peerDependencies": {
"@blocksuite/global": "0.0.0-20230409084303-221991d4-nightly" "@affine/templates": "workspace:*",
"@blocksuite/global": "0.0.0-20230409084303-221991d4-nightly",
"@toeverything/infra": "workspace:*"
}, },
"dependencies": { "dependencies": {
"lit": "^2.7.5" "lit": "^2.7.5"

View File

@@ -1,16 +1,45 @@
/// <reference types="@blocksuite/global" /> /// <reference types="@blocksuite/global" />
import { assertEquals } from '@blocksuite/global/utils'; import { assertEquals } from '@blocksuite/global/utils';
import type {
DBHandlerManager,
DebugHandlerManager,
DialogHandlerManager,
ExportHandlerManager,
HandlerManager,
PrimitiveHandlers,
UIHandlerManager,
UpdaterHandlerManager,
WorkspaceHandlerManager,
} from '@toeverything/infra';
import getConfig from 'next/config'; import getConfig from 'next/config';
import { z } from 'zod'; import { z } from 'zod';
import { UaHelper } from './ua-helper'; import { UaHelper } from './ua-helper';
type UnwrapManagerHandler<
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;
};
declare global { declare global {
interface Window { interface Window {
appInfo: { appInfo: {
electron: boolean; electron: boolean;
}; };
apis: any; apis: {
db: UnwrapManagerHandler<DBHandlerManager>;
debug: UnwrapManagerHandler<DebugHandlerManager>;
dialog: UnwrapManagerHandler<DialogHandlerManager>;
export: UnwrapManagerHandler<ExportHandlerManager>;
ui: UnwrapManagerHandler<UIHandlerManager>;
updater: UnwrapManagerHandler<UpdaterHandlerManager>;
workspace: UnwrapManagerHandler<WorkspaceHandlerManager>;
};
events: any; events: any;
} }
} }

View File

@@ -5,5 +5,10 @@
"composite": true, "composite": true,
"noEmit": false, "noEmit": false,
"outDir": "lib" "outDir": "lib"
} },
"references": [
{
"path": "../infra"
}
]
} }

View File

@@ -0,0 +1,31 @@
{
"name": "@toeverything/infra",
"main": "./src/index.ts",
"module": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"publishConfig": {
"module": "./dist/index.mjs",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"files": [
"dist"
]
},
"scripts": {
"build": "vite build",
"dev": "vite build --watch"
},
"devDependencies": {
"vite": "^4.3.9",
"vite-plugin-dts": "^2.3.0"
}
}

View File

@@ -0,0 +1,105 @@
export interface WorkspaceMeta {
id: string;
mainDBPath: string;
secondaryDBPath?: string; // assume there will be only one
}
export type PrimitiveHandlers = (...args: any[]) => Promise<any>;
type TODO = any;
export abstract class HandlerManager<
Namespace extends string,
Handlers extends Record<string, PrimitiveHandlers>
> {
abstract readonly app: TODO;
abstract readonly namespace: Namespace;
abstract readonly handlers: Handlers;
}
type DBHandlers = {
getDocAsUpdates: (id: string) => Promise<Uint8Array>;
applyDocUpdate: (id: string, update: Uint8Array) => 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<
'db',
DBHandlers
> {}
type DebugHandlers = {
revealLogFile: () => Promise<string>;
logFilePath: () => Promise<string>;
};
export abstract class DebugHandlerManager extends HandlerManager<
'debug',
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<
'dialog',
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<
'ui',
UIHandlers
> {}
type ExportHandlers = {
savePDFFileAs: (title: string) => Promise<any>;
};
export abstract class ExportHandlerManager extends HandlerManager<
'export',
ExportHandlers
> {}
type UpdaterHandlers = {
currentVersion: () => Promise<any>;
quitAndInstall: () => Promise<any>;
checkForUpdatesAndNotify: () => Promise<any>;
};
export abstract class UpdaterHandlerManager extends HandlerManager<
'updater',
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<
'workspace',
WorkspaceHandlers
> {}

View File

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

View File

@@ -0,0 +1,14 @@
{
"extends": "../../tsconfig.json",
"include": ["./src"],
"compilerOptions": {
"composite": true,
"noEmit": false,
"outDir": "lib"
},
"references": [
{
"path": "./tsconfig.node.json"
}
]
}

View File

@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"outDir": "lib",
"noEmit": false
},
"include": ["vite.config.ts"]
}

View File

@@ -0,0 +1,24 @@
import { resolve } from 'node:path';
import { fileURLToPath } from 'url';
import dts from 'vite-plugin-dts';
import { defineConfig } from 'vitest/config';
const root = fileURLToPath(new URL('.', import.meta.url));
export default defineConfig({
build: {
lib: {
entry: {
index: resolve(root, 'src/index.ts'),
},
formats: ['es', 'cjs'],
name: 'AffineInfra',
},
},
plugins: [
dts({
insertTypesEntry: true,
}),
],
});

View File

@@ -102,11 +102,9 @@ export const CRUD: WorkspaceCRUD<WorkspaceFlavour.LOCAL> = {
// workspaces in desktop // workspaces in desktop
if (window.apis && environment.isDesktop) { if (window.apis && environment.isDesktop) {
// @ts-expect-error
const desktopIds = (await window.apis.workspace.list()).map(([id]) => id); const desktopIds = (await window.apis.workspace.list()).map(([id]) => id);
// the ids maybe a subset of the local storage // the ids maybe a subset of the local storage
const moreWorkspaces = desktopIds.filter( const moreWorkspaces = desktopIds.filter(
// @ts-expect-error
id => !allWorkspaceIDs.includes(id) id => !allWorkspaceIDs.includes(id)
); );
allWorkspaceIDs = [...allWorkspaceIDs, ...moreWorkspaces]; allWorkspaceIDs = [...allWorkspaceIDs, ...moreWorkspaces];

View File

@@ -2,6 +2,7 @@
packages=( packages=(
"y-indexeddb" "y-indexeddb"
"infra"
) )
for package in "${packages[@]}"; do for package in "${packages[@]}"; do

View File

@@ -28,7 +28,7 @@
"@affine/i18n/hooks": ["./packages/i18n/src/i18n-generated"], "@affine/i18n/hooks": ["./packages/i18n/src/i18n-generated"],
"@affine/debug": ["./packages/debug"], "@affine/debug": ["./packages/debug"],
"@affine/jotai": ["./packages/jotai"], "@affine/jotai": ["./packages/jotai"],
"@affine/env": ["./packages/env"], "@affine/env": ["./packages/env/src"],
"@affine/env/*": ["./packages/env/src/*"], "@affine/env/*": ["./packages/env/src/*"],
"@affine/utils": ["./packages/utils"], "@affine/utils": ["./packages/utils"],
"@affine/workspace/*": ["./packages/workspace/src/*"], "@affine/workspace/*": ["./packages/workspace/src/*"],
@@ -41,6 +41,7 @@
], ],
"@affine-test/kit/*": ["./tests/kit/*"], "@affine-test/kit/*": ["./tests/kit/*"],
"@affine-test/fixtures/*": ["./tests/fixtures/*"], "@affine-test/fixtures/*": ["./tests/fixtures/*"],
"@toeverything/infra": ["./packages/infra/src"],
"@toeverything/y-indexeddb": ["./packages/y-indexeddb/src"], "@toeverything/y-indexeddb": ["./packages/y-indexeddb/src"],
"@toeverything/hooks/*": ["./packages/hooks/src/*"], "@toeverything/hooks/*": ["./packages/hooks/src/*"],
"@toeverything/plugin-infra": ["./packages/plugin-infra/src"], "@toeverything/plugin-infra": ["./packages/plugin-infra/src"],
@@ -63,6 +64,9 @@
{ {
"path": "./apps/server" "path": "./apps/server"
}, },
{
"path": "./packages/infra"
},
{ {
"path": "./packages/component" "path": "./packages/component"
}, },

View File

@@ -158,6 +158,7 @@ __metadata:
"@electron-forge/maker-zip": ^6.1.1 "@electron-forge/maker-zip": ^6.1.1
"@electron-forge/shared-types": ^6.1.1 "@electron-forge/shared-types": ^6.1.1
"@electron/remote": 2.0.9 "@electron/remote": 2.0.9
"@toeverything/infra": "workspace:*"
"@types/fs-extra": ^11.0.1 "@types/fs-extra": ^11.0.1
"@types/uuid": ^9.0.1 "@types/uuid": ^9.0.1
cheerio: ^1.0.0-rc.12 cheerio: ^1.0.0-rc.12
@@ -188,7 +189,6 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@affine/env@workspace:packages/env" resolution: "@affine/env@workspace:packages/env"
dependencies: dependencies:
"@affine/templates": "workspace:*"
"@blocksuite/global": 0.0.0-20230606130340-805f430b-nightly "@blocksuite/global": 0.0.0-20230606130340-805f430b-nightly
lit: ^2.7.5 lit: ^2.7.5
next: =13.4.2 next: =13.4.2
@@ -196,7 +196,9 @@ __metadata:
react-dom: 18.3.0-canary-16d053d59-20230506 react-dom: 18.3.0-canary-16d053d59-20230506
zod: ^3.21.4 zod: ^3.21.4
peerDependencies: peerDependencies:
"@affine/templates": "workspace:*"
"@blocksuite/global": 0.0.0-20230409084303-221991d4-nightly "@blocksuite/global": 0.0.0-20230409084303-221991d4-nightly
"@toeverything/infra": "workspace:*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -389,6 +391,7 @@ __metadata:
"@swc-jotai/debug-label": ^0.0.10 "@swc-jotai/debug-label": ^0.0.10
"@swc-jotai/react-refresh": ^0.0.8 "@swc-jotai/react-refresh": ^0.0.8
"@toeverything/hooks": "workspace:*" "@toeverything/hooks": "workspace:*"
"@toeverything/infra": "workspace:*"
"@toeverything/plugin-infra": "workspace:*" "@toeverything/plugin-infra": "workspace:*"
"@types/react": ^18.2.6 "@types/react": ^18.2.6
"@types/react-dom": ^18.2.4 "@types/react-dom": ^18.2.4
@@ -9204,6 +9207,15 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"@toeverything/infra@workspace:*, @toeverything/infra@workspace:packages/infra":
version: 0.0.0-use.local
resolution: "@toeverything/infra@workspace:packages/infra"
dependencies:
vite: ^4.3.9
vite-plugin-dts: ^2.3.0
languageName: unknown
linkType: soft
"@toeverything/plugin-infra@workspace:*, @toeverything/plugin-infra@workspace:packages/plugin-infra": "@toeverything/plugin-infra@workspace:*, @toeverything/plugin-infra@workspace:packages/plugin-infra":
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@toeverything/plugin-infra@workspace:packages/plugin-infra" resolution: "@toeverything/plugin-infra@workspace:packages/plugin-infra"