mirror of
https://github.com/colanode/colanode.git
synced 2025-12-16 11:47:47 +01:00
Switch to npm workspaces and electron forge
This commit is contained in:
@@ -3,5 +3,6 @@ out
|
|||||||
tsconfig.base.json
|
tsconfig.base.json
|
||||||
tsconfig.json
|
tsconfig.json
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
package-lock.json
|
||||||
.env
|
.env
|
||||||
LICENSE.md
|
LICENSE.md
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
out
|
|
||||||
.gitignore
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:react/recommended',
|
|
||||||
'plugin:react/jsx-runtime',
|
|
||||||
'@electron-toolkit/eslint-config-ts/recommended',
|
|
||||||
'@electron-toolkit/eslint-config-prettier',
|
|
||||||
],
|
|
||||||
};
|
|
||||||
16
apps/desktop/.eslintrc.json
Normal file
16
apps/desktop/.eslintrc.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:import/recommended",
|
||||||
|
"plugin:import/electron",
|
||||||
|
"plugin:import/typescript"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser"
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
electron_mirror=https://npmmirror.com/mirrors/electron/
|
|
||||||
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
|
|
||||||
shamefully-hoist=true
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>com.apple.security.cs.allow-jit</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 121 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,3 +0,0 @@
|
|||||||
provider: generic
|
|
||||||
url: https://example.com/auto-updates
|
|
||||||
updaterCacheDirName: colanode-updater
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"appId": "com.colanode.desktop",
|
|
||||||
"productName": "Colanode",
|
|
||||||
"directories": {
|
|
||||||
"buildResources": "build"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"!**/.vscode/*",
|
|
||||||
"!src/*",
|
|
||||||
"!electron.vite.config.{js,ts,mjs,cjs}",
|
|
||||||
"!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}",
|
|
||||||
"!{.env,.env.*,.npmrc,pnpm-lock.yaml}",
|
|
||||||
"!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}"
|
|
||||||
],
|
|
||||||
"asarUnpack": ["resources/**"],
|
|
||||||
"win": {
|
|
||||||
"executableName": "Colanode",
|
|
||||||
"nsis": {
|
|
||||||
"artifactName": "${name}-${version}-setup.${ext}",
|
|
||||||
"shortcutName": "${productName}",
|
|
||||||
"uninstallDisplayName": "${productName}",
|
|
||||||
"createDesktopShortcut": "always"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mac": {
|
|
||||||
"entitlementsInherit": "build/entitlements.mac.plist",
|
|
||||||
"extendInfo": {
|
|
||||||
"NSCameraUsageDescription": "Application requests access to the device's camera.",
|
|
||||||
"NSMicrophoneUsageDescription": "Application requests access to the device's microphone.",
|
|
||||||
"NSDocumentsFolderUsageDescription": "Application requests access to the user's Documents folder.",
|
|
||||||
"NSDownloadsFolderUsageDescription": "Application requests access to the user's Downloads folder."
|
|
||||||
},
|
|
||||||
"notarize": false
|
|
||||||
},
|
|
||||||
"dmg": {
|
|
||||||
"artifactName": "${name}-${version}.${ext}"
|
|
||||||
},
|
|
||||||
"linux": {
|
|
||||||
"target": ["AppImage", "snap", "deb"],
|
|
||||||
"maintainer": "electronjs.org",
|
|
||||||
"category": "Utility"
|
|
||||||
},
|
|
||||||
"appImage": {
|
|
||||||
"artifactName": "${name}-${version}.${ext}"
|
|
||||||
},
|
|
||||||
"npmRebuild": false,
|
|
||||||
"publish": {
|
|
||||||
"provider": "generic",
|
|
||||||
"url": "https://example.com/auto-updates"
|
|
||||||
},
|
|
||||||
"electronDownload": {
|
|
||||||
"mirror": "https://npmmirror.com/mirrors/electron/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import { resolve } from 'path';
|
|
||||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite';
|
|
||||||
import react from '@vitejs/plugin-react';
|
|
||||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
main: {
|
|
||||||
plugins: [
|
|
||||||
externalizeDepsPlugin({
|
|
||||||
exclude: ['@colanode/core', '@colanode/crdt'],
|
|
||||||
}),
|
|
||||||
viteStaticCopy({
|
|
||||||
targets: [
|
|
||||||
{
|
|
||||||
src: 'assets/**/*',
|
|
||||||
dest: 'assets',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@/main': resolve('src/main'),
|
|
||||||
'@/shared': resolve('src/shared'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preload: {
|
|
||||||
plugins: [
|
|
||||||
externalizeDepsPlugin({
|
|
||||||
exclude: ['@colanode/core', '@colanode/crdt'],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@/shared': resolve('src/shared'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
renderer: {
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@/renderer': resolve('src/renderer'),
|
|
||||||
'@/shared': resolve('src/shared'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [react()],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
59
apps/desktop/forge.config.ts
Normal file
59
apps/desktop/forge.config.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import type { ForgeConfig } from '@electron-forge/shared-types';
|
||||||
|
import { MakerSquirrel } from '@electron-forge/maker-squirrel';
|
||||||
|
import { MakerZIP } from '@electron-forge/maker-zip';
|
||||||
|
import { MakerDeb } from '@electron-forge/maker-deb';
|
||||||
|
import { MakerRpm } from '@electron-forge/maker-rpm';
|
||||||
|
import { VitePlugin } from '@electron-forge/plugin-vite';
|
||||||
|
import { FusesPlugin } from '@electron-forge/plugin-fuses';
|
||||||
|
import { FuseV1Options, FuseVersion } from '@electron/fuses';
|
||||||
|
|
||||||
|
const config: ForgeConfig = {
|
||||||
|
packagerConfig: {
|
||||||
|
asar: true,
|
||||||
|
},
|
||||||
|
rebuildConfig: {},
|
||||||
|
makers: [
|
||||||
|
new MakerSquirrel({}),
|
||||||
|
new MakerZIP({}, ['darwin']),
|
||||||
|
new MakerRpm({}),
|
||||||
|
new MakerDeb({}),
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
new VitePlugin({
|
||||||
|
// `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
|
||||||
|
// If you are familiar with Vite configuration, it will look really familiar.
|
||||||
|
build: [
|
||||||
|
{
|
||||||
|
// `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
|
||||||
|
entry: 'src/main.ts',
|
||||||
|
config: 'vite.main.config.ts',
|
||||||
|
target: 'main',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entry: 'src/preload.ts',
|
||||||
|
config: 'vite.preload.config.ts',
|
||||||
|
target: 'preload',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
renderer: [
|
||||||
|
{
|
||||||
|
name: 'main_window',
|
||||||
|
config: 'vite.renderer.config.ts',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
// Fuses are used to enable/disable various Electron functionality
|
||||||
|
// at package time, before code signing the application
|
||||||
|
new FusesPlugin({
|
||||||
|
version: FuseVersion.V1,
|
||||||
|
[FuseV1Options.RunAsNode]: false,
|
||||||
|
[FuseV1Options.EnableCookieEncryption]: true,
|
||||||
|
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
|
||||||
|
[FuseV1Options.EnableNodeCliInspectArguments]: false,
|
||||||
|
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
|
||||||
|
[FuseV1Options.OnlyLoadAppFromAsar]: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
4
apps/desktop/forge.env.d.ts
vendored
Normal file
4
apps/desktop/forge.env.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/// <reference types="@electron-forge/plugin-vite/forge-vite-env" />
|
||||||
|
|
||||||
|
declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string;
|
||||||
|
declare const MAIN_WINDOW_VITE_NAME: string;
|
||||||
17
apps/desktop/index.html
Normal file
17
apps/desktop/index.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Colanode</title>
|
||||||
|
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||||
|
<meta
|
||||||
|
http-equiv="Content-Security-Policy"
|
||||||
|
content="default-src 'self' 'unsafe-inline' data: avatar: local-file: local-file-preview: asset:;"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/renderer.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -3,29 +3,49 @@
|
|||||||
"productName": "Colanode",
|
"productName": "Colanode",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Colanode desktop application",
|
"description": "Colanode desktop application",
|
||||||
"main": "./out/main/index.js",
|
"main": ".vite/build/main.js",
|
||||||
"author": "Hakan Shehu",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write .",
|
"dev": "electron-forge start",
|
||||||
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
|
"package": "electron-forge package",
|
||||||
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
|
"make": "electron-forge make",
|
||||||
"typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false",
|
"publish": "electron-forge publish",
|
||||||
"typecheck": "pnpm run typecheck:node && pnpm run typecheck:web",
|
"lint": "eslint --ext .ts,.tsx .",
|
||||||
"start": "electron-vite preview",
|
"postinstall": "electron-rebuild"
|
||||||
"dev": "electron-vite dev --watch",
|
|
||||||
"build": "pnpm run typecheck && electron-vite build",
|
|
||||||
"postinstall": "electron-builder install-app-deps",
|
|
||||||
"build:unpack": "pnpm run build && electron-builder --dir",
|
|
||||||
"build:win": "pnpm run build && electron-builder --win",
|
|
||||||
"build:mac": "electron-vite build && electron-builder --mac",
|
|
||||||
"build:linux": "electron-vite build && electron-builder --linux"
|
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@electron-forge/cli": "^7.5.0",
|
||||||
|
"@electron-forge/maker-deb": "^7.5.0",
|
||||||
|
"@electron-forge/maker-rpm": "^7.5.0",
|
||||||
|
"@electron-forge/maker-squirrel": "^7.5.0",
|
||||||
|
"@electron-forge/maker-zip": "^7.5.0",
|
||||||
|
"@electron-forge/plugin-auto-unpack-natives": "^7.5.0",
|
||||||
|
"@electron-forge/plugin-fuses": "^7.5.0",
|
||||||
|
"@electron-forge/plugin-vite": "^7.5.0",
|
||||||
|
"@electron/fuses": "^1.8.0",
|
||||||
|
"@types/better-sqlite3": "^7.6.11",
|
||||||
|
"@types/is-hotkey": "^0.1.10",
|
||||||
|
"@types/mime-types": "^2.1.4",
|
||||||
|
"@types/react": "^18.3.12",
|
||||||
|
"@types/react-dom": "^18.3.1",
|
||||||
|
"@types/react-window": "^1.8.8",
|
||||||
|
"@types/unzipper": "^0.10.10",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"electron": "33.2.0",
|
||||||
|
"postcss": "^8.4.49",
|
||||||
|
"tailwindcss": "^3.4.15",
|
||||||
|
"vite": "^5.4.11",
|
||||||
|
"vite-plugin-static-copy": "^2.1.0"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": {
|
||||||
|
"name": "Hakan Shehu",
|
||||||
|
"email": "***REMOVED***"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@colanode/core": "workspace:*",
|
"@colanode/core": "*",
|
||||||
"@colanode/crdt": "workspace:*",
|
"@colanode/crdt": "*",
|
||||||
"@electron-toolkit/preload": "^3.0.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
"@electron-toolkit/utils": "^3.0.0",
|
|
||||||
"@hookform/resolvers": "^3.9.0",
|
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.2",
|
"@radix-ui/react-alert-dialog": "^1.1.2",
|
||||||
"@radix-ui/react-checkbox": "^1.1.2",
|
"@radix-ui/react-checkbox": "^1.1.2",
|
||||||
"@radix-ui/react-collapsible": "^1.1.1",
|
"@radix-ui/react-collapsible": "^1.1.1",
|
||||||
@@ -33,18 +53,16 @@
|
|||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||||
"@radix-ui/react-hover-card": "^1.1.2",
|
"@radix-ui/react-hover-card": "^1.1.2",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-popover": "^1.1.2",
|
"@radix-ui/react-popover": "^1.1.2",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.0",
|
"@radix-ui/react-scroll-area": "^1.2.1",
|
||||||
"@radix-ui/react-separator": "^1.1.0",
|
"@radix-ui/react-separator": "^1.1.0",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
|
||||||
"@radix-ui/react-tabs": "^1.1.1",
|
"@radix-ui/react-tabs": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.2",
|
"@radix-ui/react-toast": "^1.2.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.3",
|
"@radix-ui/react-tooltip": "^1.1.4",
|
||||||
"@radix-ui/react-visually-hidden": "^1.1.0",
|
"@radix-ui/react-visually-hidden": "^1.1.0",
|
||||||
"@react-oauth/google": "^0.12.1",
|
"@tanstack/react-query": "^5.60.5",
|
||||||
"@tanstack/react-query": "^5.59.20",
|
|
||||||
"@tiptap/core": "^2.9.1",
|
"@tiptap/core": "^2.9.1",
|
||||||
"@tiptap/extension-blockquote": "^2.9.1",
|
"@tiptap/extension-blockquote": "^2.9.1",
|
||||||
"@tiptap/extension-bold": "^2.9.1",
|
"@tiptap/extension-bold": "^2.9.1",
|
||||||
@@ -53,9 +71,6 @@
|
|||||||
"@tiptap/extension-code-block-lowlight": "^2.9.1",
|
"@tiptap/extension-code-block-lowlight": "^2.9.1",
|
||||||
"@tiptap/extension-document": "^2.9.1",
|
"@tiptap/extension-document": "^2.9.1",
|
||||||
"@tiptap/extension-dropcursor": "^2.9.1",
|
"@tiptap/extension-dropcursor": "^2.9.1",
|
||||||
"@tiptap/extension-hard-break": "^2.9.1",
|
|
||||||
"@tiptap/extension-heading": "^2.9.1",
|
|
||||||
"@tiptap/extension-highlight": "^2.9.1",
|
|
||||||
"@tiptap/extension-horizontal-rule": "^2.9.1",
|
"@tiptap/extension-horizontal-rule": "^2.9.1",
|
||||||
"@tiptap/extension-italic": "^2.9.1",
|
"@tiptap/extension-italic": "^2.9.1",
|
||||||
"@tiptap/extension-link": "^2.9.1",
|
"@tiptap/extension-link": "^2.9.1",
|
||||||
@@ -65,84 +80,38 @@
|
|||||||
"@tiptap/extension-paragraph": "^2.9.1",
|
"@tiptap/extension-paragraph": "^2.9.1",
|
||||||
"@tiptap/extension-placeholder": "^2.9.1",
|
"@tiptap/extension-placeholder": "^2.9.1",
|
||||||
"@tiptap/extension-strike": "^2.9.1",
|
"@tiptap/extension-strike": "^2.9.1",
|
||||||
"@tiptap/extension-subscript": "^2.9.1",
|
|
||||||
"@tiptap/extension-superscript": "^2.9.1",
|
|
||||||
"@tiptap/extension-task-item": "^2.9.1",
|
"@tiptap/extension-task-item": "^2.9.1",
|
||||||
"@tiptap/extension-task-list": "^2.9.1",
|
"@tiptap/extension-task-list": "^2.9.1",
|
||||||
"@tiptap/extension-text": "^2.9.1",
|
"@tiptap/extension-text": "^2.9.1",
|
||||||
"@tiptap/extension-text-style": "^2.9.1",
|
|
||||||
"@tiptap/extension-underline": "^2.9.1",
|
"@tiptap/extension-underline": "^2.9.1",
|
||||||
"@tiptap/pm": "^2.9.1",
|
|
||||||
"@tiptap/react": "^2.9.1",
|
"@tiptap/react": "^2.9.1",
|
||||||
"@tiptap/suggestion": "^2.9.1",
|
"@tiptap/suggestion": "^2.9.1",
|
||||||
"axios": "^1.7.7",
|
|
||||||
"better-sqlite3": "^11.5.0",
|
"better-sqlite3": "^11.5.0",
|
||||||
|
"bufferutil": "^4.0.8",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.4",
|
||||||
"date-fns": "^3.6.0",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"electron-updater": "^6.1.7",
|
|
||||||
"form-data": "^4.0.1",
|
|
||||||
"fractional-indexing-jittered": "^0.9.1",
|
"fractional-indexing-jittered": "^0.9.1",
|
||||||
"is-hotkey": "^0.2.0",
|
"is-hotkey": "^0.2.0",
|
||||||
"js-sha256": "^0.11.0",
|
|
||||||
"kysely": "^0.27.4",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"lowlight": "^3.1.0",
|
"lowlight": "^3.1.0",
|
||||||
"lucide-react": "^0.453.0",
|
"lucide-react": "^0.460.0",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"public-ip": "^7.0.1",
|
"re-resizable": "^6.10.1",
|
||||||
"re-resizable": "^6.10.0",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^16.0.1",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.1",
|
"react-hook-form": "^7.53.2",
|
||||||
"react-intersection-observer": "^9.13.1",
|
"react-intersection-observer": "^9.13.1",
|
||||||
"react-router-dom": "^6.27.0",
|
"react-router-dom": "^6.28.0",
|
||||||
"react-virtualized-auto-sizer": "^1.0.24",
|
"react-virtualized-auto-sizer": "^1.0.24",
|
||||||
"react-window": "^1.8.10",
|
"react-window": "^1.8.10",
|
||||||
"tailwind-merge": "^2.5.4",
|
"tailwind-merge": "^2.5.4",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"ts-pattern": "^5.5.0",
|
"ts-pattern": "^5.5.0",
|
||||||
"unzipper": "^0.12.3",
|
"unzipper": "^0.12.3",
|
||||||
"ws": "^8.18.0"
|
"utf-8-validate": "^5.0.10"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@electron-toolkit/eslint-config-prettier": "^2.0.0",
|
|
||||||
"@electron-toolkit/eslint-config-ts": "^2.0.0",
|
|
||||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
|
||||||
"@electron/fuses": "^1.8.0",
|
|
||||||
"@types/better-sqlite3": "^7.6.11",
|
|
||||||
"@types/diff": "^5.2.3",
|
|
||||||
"@types/is-hotkey": "^0.1.10",
|
|
||||||
"@types/lodash": "^4.17.12",
|
|
||||||
"@types/mime-types": "^2.1.4",
|
|
||||||
"@types/node": "^20.14.8",
|
|
||||||
"@types/react": "^18.3.3",
|
|
||||||
"@types/react-dom": "^18.3.0",
|
|
||||||
"@types/react-window": "^1.8.8",
|
|
||||||
"@types/unzipper": "^0.10.10",
|
|
||||||
"@types/ws": "^8.5.12",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
||||||
"@typescript-eslint/parser": "^5.62.0",
|
|
||||||
"@vitejs/plugin-react": "^4.3.1",
|
|
||||||
"autoprefixer": "^10.4.20",
|
|
||||||
"electron": "^31.0.2",
|
|
||||||
"electron-builder": "^24.13.3",
|
|
||||||
"electron-vite": "^2.3.0",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-plugin-import": "^2.31.0",
|
|
||||||
"eslint-plugin-react": "^7.34.3",
|
|
||||||
"node-abi": "^3.71.0",
|
|
||||||
"postcss": "^8.4.47",
|
|
||||||
"prettier": "^3.3.2",
|
|
||||||
"prettier-plugin-tailwindcss": "^0.6.8",
|
|
||||||
"react": "^18.3.1",
|
|
||||||
"react-dom": "^18.3.1",
|
|
||||||
"tailwindcss": "^3.4.14",
|
|
||||||
"vite": "^5.3.1",
|
|
||||||
"vite-plugin-static-copy": "^2.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
import { app, shell, BrowserWindow, ipcMain, protocol } from 'electron';
|
import { app, BrowserWindow, ipcMain, protocol } from 'electron';
|
||||||
import { join } from 'path';
|
import path from 'path';
|
||||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils';
|
|
||||||
import { eventBus } from '@/shared/lib/event-bus';
|
import { eventBus } from '@/shared/lib/event-bus';
|
||||||
|
import { avatarService } from '@/main/services/avatar-service';
|
||||||
|
import { fileService } from '@/main/services/file-service';
|
||||||
|
import { assetService } from '@/main/services/asset-service';
|
||||||
|
import { MutationMap } from '@/shared/mutations';
|
||||||
|
import { MutationInput } from '@/shared/mutations';
|
||||||
|
import { QueryMap } from '@/shared/queries';
|
||||||
|
import { mutationService } from '@/main/services/mutation-service';
|
||||||
|
import { queryService } from '@/main/services/query-service';
|
||||||
|
import { QueryInput } from '@/shared/queries';
|
||||||
|
import { CommandMap } from '@/shared/commands';
|
||||||
|
import { CommandInput } from '@/shared/commands';
|
||||||
|
import { commandService } from '@/main/services/command-service';
|
||||||
import { databaseService } from '@/main/data/database-service';
|
import { databaseService } from '@/main/data/database-service';
|
||||||
import { socketService } from '@/main/services/socket-service';
|
import { socketService } from '@/main/services/socket-service';
|
||||||
import { syncService } from '@/main/services/sync-service';
|
import { syncService } from '@/main/services/sync-service';
|
||||||
import { avatarService } from '@/main/services/avatar-service';
|
|
||||||
import { fileService } from '@/main/services/file-service';
|
|
||||||
import { MutationInput, MutationMap } from '@/shared/mutations';
|
|
||||||
import { QueryInput, QueryMap } from '@/shared/queries';
|
|
||||||
import { assetService } from '@/main/services/asset-service';
|
|
||||||
import { radarService } from '@/main/services/radar-service';
|
import { radarService } from '@/main/services/radar-service';
|
||||||
import { mutationService } from '@/main/services/mutation-service';
|
|
||||||
import { queryService } from '@/main/services/query-service';
|
|
||||||
import { CommandInput } from '@/shared/commands';
|
|
||||||
import { commandService } from '@/main/services/command-service';
|
|
||||||
import { CommandMap } from '@/shared/commands';
|
|
||||||
|
|
||||||
let subscriptionId: string | null = null;
|
let subscriptionId: string | null = null;
|
||||||
const icon = join(__dirname, '../assets/icon.png');
|
|
||||||
|
|
||||||
app.setName('Colanode');
|
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||||
|
if (require('electron-squirrel-startup')) {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
|
||||||
const createWindow = async (): Promise<void> => {
|
const createWindow = async () => {
|
||||||
await databaseService.init();
|
await databaseService.init();
|
||||||
assetService.checkAssets();
|
assetService.checkAssets();
|
||||||
socketService.init();
|
socketService.init();
|
||||||
@@ -32,31 +35,20 @@ const createWindow = async (): Promise<void> => {
|
|||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const mainWindow = new BrowserWindow({
|
const mainWindow = new BrowserWindow({
|
||||||
fullscreen: true,
|
fullscreen: true,
|
||||||
show: false,
|
|
||||||
autoHideMenuBar: true,
|
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: join(__dirname, '../preload/index.js'),
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
sandbox: false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.on('ready-to-show', () => {
|
// and load the index.html of the app.
|
||||||
mainWindow.show();
|
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
|
||||||
});
|
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
|
||||||
|
// Open the DevTools.
|
||||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
mainWindow.webContents.openDevTools();
|
||||||
shell.openExternal(details.url);
|
|
||||||
return { action: 'deny' };
|
|
||||||
});
|
|
||||||
|
|
||||||
// HMR for renderer base on electron-vite cli.
|
|
||||||
// Load the remote URL for development or the local html file for production.
|
|
||||||
const electronRendererUrl = process.env['ELECTRON_RENDERER_URL'];
|
|
||||||
if (is.dev && electronRendererUrl) {
|
|
||||||
mainWindow.loadURL(electronRendererUrl);
|
|
||||||
} else {
|
} else {
|
||||||
mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
|
mainWindow.loadFile(
|
||||||
|
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subscriptionId === null) {
|
if (subscriptionId === null) {
|
||||||
@@ -95,45 +87,32 @@ const createWindow = async (): Promise<void> => {
|
|||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
app.whenReady().then(() => {
|
app.on('ready', createWindow);
|
||||||
// Set app user model id for windows
|
|
||||||
electronApp.setAppUserModelId('com.colanode.desktop');
|
|
||||||
|
|
||||||
// Default open or close DevTools by F12 in development
|
|
||||||
// and ignore CommandOrControl + R in production.
|
|
||||||
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
|
|
||||||
app.on('browser-window-created', (_, window) => {
|
|
||||||
optimizer.watchWindowShortcuts(window);
|
|
||||||
});
|
|
||||||
|
|
||||||
// IPC test
|
|
||||||
ipcMain.on('ping', () => console.log('pong'));
|
|
||||||
|
|
||||||
createWindow();
|
|
||||||
|
|
||||||
app.on('activate', function () {
|
|
||||||
// On macOS it's common to re-create a window in the app when the
|
|
||||||
// dock icon is clicked and there are no other windows open.
|
|
||||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Quit when all windows are closed, except on macOS. There, it's common
|
// Quit when all windows are closed, except on macOS. There, it's common
|
||||||
// for applications and their menu bar to stay active until the user quits
|
// for applications and their menu bar to stay active until the user quits
|
||||||
// explicitly with Cmd + Q.
|
// explicitly with Cmd + Q.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
if (subscriptionId) {
|
if (subscriptionId) {
|
||||||
eventBus.unsubscribe(subscriptionId);
|
eventBus.unsubscribe(subscriptionId);
|
||||||
subscriptionId = null;
|
subscriptionId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// In this file you can include the rest of your app"s specific main process
|
app.on('activate', () => {
|
||||||
// code. You can also put them in separate files and require them here.
|
// On OS X it's common to re-create a window in the app when the
|
||||||
|
// dock icon is clicked and there are no other windows open.
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// In this file you can include the rest of your app's specific main process
|
||||||
|
// code. You can also put them in separate files and import them here.
|
||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
'execute-mutation',
|
'execute-mutation',
|
||||||
async <T extends MutationInput>(
|
async <T extends MutationInput>(
|
||||||
@@ -6,6 +6,7 @@ import { appDatabaseMigrations } from '@/main/data/app/migrations';
|
|||||||
import { workspaceDatabaseMigrations } from '@/main/data/workspace/migrations';
|
import { workspaceDatabaseMigrations } from '@/main/data/workspace/migrations';
|
||||||
import { appDatabasePath, getWorkspaceDirectoryPath } from '@/main/utils';
|
import { appDatabasePath, getWorkspaceDirectoryPath } from '@/main/utils';
|
||||||
import SQLite from 'better-sqlite3';
|
import SQLite from 'better-sqlite3';
|
||||||
|
|
||||||
class DatabaseService {
|
class DatabaseService {
|
||||||
private initPromise: Promise<void> | null = null;
|
private initPromise: Promise<void> | null = null;
|
||||||
private readonly workspaceDatabases: Map<
|
private readonly workspaceDatabases: Map<
|
||||||
|
|||||||
@@ -45,17 +45,17 @@ class NodeService {
|
|||||||
await databaseService.getWorkspaceDatabase(userId);
|
await databaseService.getWorkspaceDatabase(userId);
|
||||||
|
|
||||||
await workspaceDatabase.transaction().execute(async (transaction) => {
|
await workspaceDatabase.transaction().execute(async (transaction) => {
|
||||||
for (const input of inputs) {
|
for (const inputItem of inputs) {
|
||||||
const model = registry.getModel(input.attributes.type);
|
const model = registry.getModel(inputItem.attributes.type);
|
||||||
if (!model.schema.safeParse(input.attributes).success) {
|
if (!model.schema.safeParse(inputItem.attributes).success) {
|
||||||
throw new Error('Invalid attributes');
|
throw new Error('Invalid attributes');
|
||||||
}
|
}
|
||||||
|
|
||||||
let ancestors: Node[] = [];
|
let ancestors: Node[] = [];
|
||||||
if (input.attributes.parentId) {
|
if (inputItem.attributes.parentId) {
|
||||||
const ancestorRows = await fetchNodeAncestors(
|
const ancestorRows = await fetchNodeAncestors(
|
||||||
transaction,
|
transaction,
|
||||||
input.attributes.parentId
|
inputItem.attributes.parentId
|
||||||
);
|
);
|
||||||
ancestors = ancestorRows.map(mapNode);
|
ancestors = ancestorRows.map(mapNode);
|
||||||
}
|
}
|
||||||
@@ -68,19 +68,19 @@ class NodeService {
|
|||||||
ancestors
|
ancestors
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!model.canCreate(context, input.attributes)) {
|
if (!model.canCreate(context, inputItem.attributes)) {
|
||||||
throw new Error('Insufficient permissions');
|
throw new Error('Insufficient permissions');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ydoc = new YDoc(input.id);
|
const ydoc = new YDoc(inputItem.id);
|
||||||
ydoc.updateAttributes(input.attributes);
|
ydoc.updateAttributes(inputItem.attributes);
|
||||||
|
|
||||||
const createdAt = new Date().toISOString();
|
const createdAt = new Date().toISOString();
|
||||||
const versionId = generateId(IdType.Version);
|
const versionId = generateId(IdType.Version);
|
||||||
|
|
||||||
const changeData: LocalCreateNodeChangeData = {
|
const changeData: LocalCreateNodeChangeData = {
|
||||||
type: 'node_create',
|
type: 'node_create',
|
||||||
id: input.id,
|
id: inputItem.id,
|
||||||
state: ydoc.getEncodedState(),
|
state: ydoc.getEncodedState(),
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
createdBy: context.userId,
|
createdBy: context.userId,
|
||||||
@@ -91,8 +91,8 @@ class NodeService {
|
|||||||
.insertInto('nodes')
|
.insertInto('nodes')
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.values({
|
.values({
|
||||||
id: input.id,
|
id: inputItem.id,
|
||||||
attributes: JSON.stringify(input.attributes),
|
attributes: JSON.stringify(inputItem.attributes),
|
||||||
state: ydoc.getState(),
|
state: ydoc.getState(),
|
||||||
created_at: createdAt,
|
created_at: createdAt,
|
||||||
created_by: context.userId,
|
created_by: context.userId,
|
||||||
@@ -119,11 +119,11 @@ class NodeService {
|
|||||||
createdChangeIds.push(createdChange.id);
|
createdChangeIds.push(createdChange.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.upload) {
|
if (inputItem.upload) {
|
||||||
const createdUploadRow = await transaction
|
const createdUploadRow = await transaction
|
||||||
.insertInto('uploads')
|
.insertInto('uploads')
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.values(input.upload)
|
.values(inputItem.upload)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
|
|
||||||
if (createdUploadRow) {
|
if (createdUploadRow) {
|
||||||
@@ -137,11 +137,11 @@ class NodeService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.download) {
|
if (inputItem.download) {
|
||||||
const createdDownloadRow = await transaction
|
const createdDownloadRow = await transaction
|
||||||
.insertInto('downloads')
|
.insertInto('downloads')
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.values(input.download)
|
.values(inputItem.download)
|
||||||
.executeTakeFirst();
|
.executeTakeFirst();
|
||||||
|
|
||||||
if (createdDownloadRow) {
|
if (createdDownloadRow) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class QueryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async checkForQueryChanges(event: Event): Promise<void> {
|
private async checkForQueryChanges(event: Event): Promise<void> {
|
||||||
if (event.type !== 'query_result_updated') {
|
if (event.type === 'query_result_updated') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { workspaceService } from '@/main/services/workspace-service';
|
|||||||
import { deviceService } from '@/main/services/device-service';
|
import { deviceService } from '@/main/services/device-service';
|
||||||
|
|
||||||
// one minute
|
// one minute
|
||||||
const EVENT_LOOP_INTERVAL = 1000 * 5;
|
const EVENT_LOOP_INTERVAL = 1000 * 60;
|
||||||
|
|
||||||
class SyncService {
|
class SyncService {
|
||||||
private initiated: boolean = false;
|
private initiated: boolean = false;
|
||||||
|
|||||||
54
apps/desktop/src/preload.ts
Normal file
54
apps/desktop/src/preload.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// See the Electron documentation for details on how to use preload scripts:
|
||||||
|
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
|
||||||
|
import { CommandMap } from '@/shared/commands';
|
||||||
|
import { CommandInput } from '@/shared/commands';
|
||||||
|
import { MutationMap } from '@/shared/mutations';
|
||||||
|
import { MutationInput } from '@/shared/mutations';
|
||||||
|
import { QueryInput, QueryMap } from '@/shared/queries';
|
||||||
|
import { contextBridge, ipcRenderer } from 'electron';
|
||||||
|
import { eventBus } from '@/shared/lib/event-bus';
|
||||||
|
import { Event } from '@/shared/types/events';
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('colanode', {
|
||||||
|
init: () => ipcRenderer.invoke('init'),
|
||||||
|
logout: (accountId: string) => ipcRenderer.invoke('logout', accountId),
|
||||||
|
|
||||||
|
executeMutation: <T extends MutationInput>(
|
||||||
|
input: T
|
||||||
|
): Promise<MutationMap[T['type']]['output']> => {
|
||||||
|
return ipcRenderer.invoke('execute-mutation', input);
|
||||||
|
},
|
||||||
|
|
||||||
|
executeQuery: <T extends QueryInput>(
|
||||||
|
input: T
|
||||||
|
): Promise<QueryMap[T['type']]['output']> => {
|
||||||
|
return ipcRenderer.invoke('execute-query', input);
|
||||||
|
},
|
||||||
|
|
||||||
|
executeQueryAndSubscribe: <T extends QueryInput>(
|
||||||
|
id: string,
|
||||||
|
input: T
|
||||||
|
): Promise<QueryMap[T['type']]['output']> => {
|
||||||
|
return ipcRenderer.invoke('execute-query-and-subscribe', id, input);
|
||||||
|
},
|
||||||
|
|
||||||
|
unsubscribeQuery: (id: string): Promise<void> => {
|
||||||
|
return ipcRenderer.invoke('unsubscribe-query', id);
|
||||||
|
},
|
||||||
|
|
||||||
|
executeCommand: <T extends CommandInput>(
|
||||||
|
input: T
|
||||||
|
): Promise<CommandMap[T['type']]['output']> => {
|
||||||
|
return ipcRenderer.invoke('execute-command', input);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('eventBus', {
|
||||||
|
subscribe: (callback: (event: Event) => void) => eventBus.subscribe(callback),
|
||||||
|
unsubscribe: (id: string) => eventBus.unsubscribe(id),
|
||||||
|
publish: (event: Event) => eventBus.publish(event),
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('event', (_, event) => {
|
||||||
|
eventBus.publish(event);
|
||||||
|
});
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import { contextBridge, ipcRenderer } from 'electron';
|
|
||||||
import { electronAPI } from '@electron-toolkit/preload';
|
|
||||||
import { eventBus } from '@/shared/lib/event-bus';
|
|
||||||
import { MutationInput, MutationMap } from '@/shared/mutations';
|
|
||||||
import { QueryInput, QueryMap } from '@/shared/queries';
|
|
||||||
import { Event } from '@/shared/types/events';
|
|
||||||
import { CommandMap } from '@/shared/commands';
|
|
||||||
import { CommandInput } from '@/shared/commands';
|
|
||||||
|
|
||||||
// Use `contextBridge` APIs to expose Electron APIs to
|
|
||||||
// renderer only if context isolation is enabled, otherwise
|
|
||||||
// just add to the DOM global.
|
|
||||||
if (process.contextIsolated) {
|
|
||||||
try {
|
|
||||||
contextBridge.exposeInMainWorld('electron', electronAPI);
|
|
||||||
contextBridge.exposeInMainWorld('colanode', {
|
|
||||||
init: () => ipcRenderer.invoke('init'),
|
|
||||||
logout: (accountId: string) => ipcRenderer.invoke('logout', accountId),
|
|
||||||
|
|
||||||
executeMutation: <T extends MutationInput>(
|
|
||||||
input: T
|
|
||||||
): Promise<MutationMap[T['type']]['output']> => {
|
|
||||||
return ipcRenderer.invoke('execute-mutation', input);
|
|
||||||
},
|
|
||||||
|
|
||||||
executeQuery: <T extends QueryInput>(
|
|
||||||
input: T
|
|
||||||
): Promise<QueryMap[T['type']]['output']> => {
|
|
||||||
return ipcRenderer.invoke('execute-query', input);
|
|
||||||
},
|
|
||||||
|
|
||||||
executeQueryAndSubscribe: <T extends QueryInput>(
|
|
||||||
id: string,
|
|
||||||
input: T
|
|
||||||
): Promise<QueryMap[T['type']]['output']> => {
|
|
||||||
return ipcRenderer.invoke('execute-query-and-subscribe', id, input);
|
|
||||||
},
|
|
||||||
|
|
||||||
unsubscribeQuery: (id: string): Promise<void> => {
|
|
||||||
return ipcRenderer.invoke('unsubscribe-query', id);
|
|
||||||
},
|
|
||||||
|
|
||||||
executeCommand: <T extends CommandInput>(
|
|
||||||
input: T
|
|
||||||
): Promise<CommandMap[T['type']]['output']> => {
|
|
||||||
return ipcRenderer.invoke('execute-command', input);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('eventBus', {
|
|
||||||
subscribe: (callback: (event: Event) => void) =>
|
|
||||||
eventBus.subscribe(callback),
|
|
||||||
unsubscribe: (id: string) => eventBus.unsubscribe(id),
|
|
||||||
publish: (event: Event) => eventBus.publish(event),
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRenderer.on('event', (_, event) => {
|
|
||||||
eventBus.publish(event);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// @ts-ignore (define in dts)
|
|
||||||
window.electron = electronAPI;
|
|
||||||
// @ts-ignore (define in dts)
|
|
||||||
window.api = api;
|
|
||||||
}
|
|
||||||
1
apps/desktop/src/renderer.ts
Normal file
1
apps/desktop/src/renderer.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import './renderer/root';
|
||||||
1
apps/desktop/src/renderer/env.d.ts
vendored
1
apps/desktop/src/renderer/env.d.ts
vendored
@@ -1 +0,0 @@
|
|||||||
/// <reference types="vite/client" />
|
|
||||||
@@ -1,28 +1,23 @@
|
|||||||
import { ElectronAPI } from '@electron-toolkit/preload';
|
import { CommandMap } from '@/shared/commands';
|
||||||
import { EventBus } from '@/lib/event-bus';
|
import { QueryInput } from '@/shared/queries';
|
||||||
import { MutationMap, MutationInput } from '@/shared/mutations';
|
import { MutationInput, MutationMap } from '@/shared/mutations';
|
||||||
import { QueryMap, QueryInput } from '@/shared/queries';
|
import { QueryMap } from '@/shared/queries';
|
||||||
import { CommandMap, CommandInput } from '@/shared/commands';
|
import { CommandInput } from '@/shared/commands';
|
||||||
|
import { EventBus } from '@/shared/lib/event-bus';
|
||||||
|
|
||||||
interface ColanodeAPI {
|
export interface ColanodeApi {
|
||||||
init: () => Promise<void>;
|
init: () => Promise<void>;
|
||||||
logout: (accountId: string) => Promise<void>;
|
|
||||||
|
|
||||||
executeMutation: <T extends MutationInput>(
|
executeMutation: <T extends MutationInput>(
|
||||||
input: T
|
input: T
|
||||||
) => Promise<MutationMap[T['type']]['output']>;
|
) => Promise<MutationMap[T['type']]['output']>;
|
||||||
|
|
||||||
executeQuery: <T extends QueryInput>(
|
executeQuery: <T extends QueryInput>(
|
||||||
input: T
|
input: T
|
||||||
) => Promise<QueryMap[T['type']]['output']>;
|
) => Promise<QueryMap[T['type']]['output']>;
|
||||||
|
|
||||||
executeQueryAndSubscribe: <T extends QueryInput>(
|
executeQueryAndSubscribe: <T extends QueryInput>(
|
||||||
id: string,
|
id: string,
|
||||||
input: T
|
input: T
|
||||||
) => Promise<QueryMap[T['type']]['output']>;
|
) => Promise<QueryMap[T['type']]['output']>;
|
||||||
|
|
||||||
unsubscribeQuery: (id: string) => Promise<void>;
|
unsubscribeQuery: (id: string) => Promise<void>;
|
||||||
|
|
||||||
executeCommand: <T extends CommandInput>(
|
executeCommand: <T extends CommandInput>(
|
||||||
input: T
|
input: T
|
||||||
) => Promise<CommandMap[T['type']]['output']>;
|
) => Promise<CommandMap[T['type']]['output']>;
|
||||||
@@ -30,8 +25,7 @@ interface ColanodeAPI {
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
electron: ElectronAPI;
|
colanode: ColanodeApi;
|
||||||
colanode: ColanodeAPI;
|
|
||||||
eventBus: EventBus;
|
eventBus: EventBus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,23 @@
|
|||||||
{
|
{
|
||||||
"files": [],
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "commonjs",
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"outDir": "dist",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../packages/core/tsconfig.json" },
|
{ "path": "../../packages/core/tsconfig.json" },
|
||||||
{ "path": "../../packages/crdt/tsconfig.json" },
|
{ "path": "../../packages/crdt/tsconfig.json" }
|
||||||
{ "path": "./tsconfig.node.json" },
|
|
||||||
{ "path": "./tsconfig.web.json" }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
|
|
||||||
"include": [
|
|
||||||
"electron.vite.config.*",
|
|
||||||
"src/main/**/*",
|
|
||||||
"src/preload/**/*",
|
|
||||||
"src/shared/**/*"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"types": ["electron-vite/node"],
|
|
||||||
"paths": {
|
|
||||||
"@/shared/*": ["./src/shared/*"],
|
|
||||||
"@/main/*": ["./src/main/*"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@electron-toolkit/tsconfig/tsconfig.web.json",
|
|
||||||
"include": [
|
|
||||||
"src/renderer/env.d.ts",
|
|
||||||
"src/renderer/**/*",
|
|
||||||
"src/preload/*.d.ts",
|
|
||||||
"src/shared/**/*"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"paths": {
|
|
||||||
"@/renderer/*": ["./src/renderer/*"],
|
|
||||||
"@/shared/*": ["./src/shared/*"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
35
apps/desktop/vite.main.config.ts
Normal file
35
apps/desktop/vite.main.config.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config
|
||||||
|
export default defineConfig(async () => {
|
||||||
|
const { viteStaticCopy } = await import('vite-plugin-static-copy');
|
||||||
|
return {
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': '/src',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
external: [
|
||||||
|
'better-sqlite3',
|
||||||
|
'kysely',
|
||||||
|
'unzipper',
|
||||||
|
'mime-types',
|
||||||
|
'node-gyp-build',
|
||||||
|
'asynckit',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
viteStaticCopy({
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
src: 'assets/**/*',
|
||||||
|
dest: 'assets',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
10
apps/desktop/vite.preload.config.ts
Normal file
10
apps/desktop/vite.preload.config.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config
|
||||||
|
export default defineConfig({
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': '/src',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
10
apps/desktop/vite.renderer.config.ts
Normal file
10
apps/desktop/vite.renderer.config.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
// https://vitejs.dev/config
|
||||||
|
export default defineConfig({
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': '/src',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "tsc --noEmit -p tsconfig.json",
|
"compile": "tsc --noEmit -p tsconfig.json",
|
||||||
"build": "pnpm run compile && tsup-node",
|
"build": "npm run compile && tsup-node",
|
||||||
"clean": "del-cli dist isolate tsconfig.tsbuildinfo",
|
"clean": "del-cli dist isolate tsconfig.tsbuildinfo",
|
||||||
"lint": "eslint . --max-warnings 0",
|
"lint": "eslint . --max-warnings 0",
|
||||||
"dev": "nodemon --env-file .env dist/index.js"
|
"dev": "nodemon --env-file .env dist/index.js"
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.675.0",
|
"@aws-sdk/client-s3": "^3.675.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.675.0",
|
"@aws-sdk/s3-request-presigner": "^3.675.0",
|
||||||
"@colanode/core": "workspace:*",
|
"@colanode/core": "^1.0.0",
|
||||||
"@colanode/crdt": "workspace:*",
|
"@colanode/crdt": "^1.0.0",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"bullmq": "^5.21.1",
|
"bullmq": "^5.21.1",
|
||||||
|
|||||||
17797
package-lock.json
generated
Normal file
17797
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,10 @@
|
|||||||
"description": "Colanode monorepo",
|
"description": "Colanode monorepo",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@9.0.4+sha256.caa915eaae9d9aefccf50ee8aeda25a2f8684d8f9d5c6e367eaf176d97c1f89e",
|
"workspaces": [
|
||||||
|
"packages/*",
|
||||||
|
"apps/*"
|
||||||
|
],
|
||||||
"author": "Hakan Shehu",
|
"author": "Hakan Shehu",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"vitest": "^1.6.0"
|
"vitest": "^1.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@colanode/core": "workspace:*",
|
"@colanode/core": "^1.0.0",
|
||||||
"diff": "^7.0.0",
|
"diff": "^7.0.0",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
"yjs": "^13.6.20",
|
"yjs": "^13.6.20",
|
||||||
|
|||||||
12609
pnpm-lock.yaml
generated
12609
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
|||||||
packages:
|
|
||||||
- "apps/*"
|
|
||||||
- "packages/*"
|
|
||||||
Reference in New Issue
Block a user