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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 { dbHandlers } from './db';
import { dialogHandlers } from './dialog';
import { exportHandlers } from './export';
import { getLogFilePath, logger, revealLogFile } from './logger';
import type { NamespaceHandlers } from './type';
import { uiHandlers } from './ui';
import { updaterHandlers } from './updater';
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
export const allHandlers = {
db: dbHandlers,
@ -27,7 +56,7 @@ export const allHandlers = {
export: exportHandlers,
updater: updaterHandlers,
workspace: workspaceHandlers,
} satisfies Record<string, NamespaceHandlers>;
} satisfies AllHandlers;
export const registerHandlers = () => {
// TODO: listen to namespace instead of individual event types

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,45 @@
/// <reference types="@blocksuite/global" />
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 { z } from 'zod';
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 {
interface Window {
appInfo: {
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;
}
}

View File

@ -5,5 +5,10 @@
"composite": true,
"noEmit": false,
"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
if (window.apis && environment.isDesktop) {
// @ts-expect-error
const desktopIds = (await window.apis.workspace.list()).map(([id]) => id);
// the ids maybe a subset of the local storage
const moreWorkspaces = desktopIds.filter(
// @ts-expect-error
id => !allWorkspaceIDs.includes(id)
);
allWorkspaceIDs = [...allWorkspaceIDs, ...moreWorkspaces];

View File

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

View File

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

View File

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