create-ekka-desktop-app 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -0
- package/bin/cli.js +72 -0
- package/package.json +23 -0
- package/template/branding/app.json +6 -0
- package/template/branding/icon.icns +0 -0
- package/template/eslint.config.js +98 -0
- package/template/index.html +29 -0
- package/template/package.json +40 -0
- package/template/src/app/App.tsx +24 -0
- package/template/src/demo/DemoApp.tsx +260 -0
- package/template/src/demo/components/Banner.tsx +82 -0
- package/template/src/demo/components/EmptyState.tsx +61 -0
- package/template/src/demo/components/InfoPopover.tsx +171 -0
- package/template/src/demo/components/InfoTooltip.tsx +76 -0
- package/template/src/demo/components/LearnMore.tsx +98 -0
- package/template/src/demo/components/NodeCredentialsOnboarding.tsx +219 -0
- package/template/src/demo/components/SetupWizard.tsx +48 -0
- package/template/src/demo/components/StatusBadge.tsx +83 -0
- package/template/src/demo/components/index.ts +10 -0
- package/template/src/demo/hooks/index.ts +6 -0
- package/template/src/demo/hooks/useAuditEvents.ts +30 -0
- package/template/src/demo/layout/Shell.tsx +110 -0
- package/template/src/demo/layout/Sidebar.tsx +192 -0
- package/template/src/demo/pages/AuditLogPage.tsx +235 -0
- package/template/src/demo/pages/DocGenPage.tsx +874 -0
- package/template/src/demo/pages/HomeSetupPage.tsx +182 -0
- package/template/src/demo/pages/LoginPage.tsx +192 -0
- package/template/src/demo/pages/PathPermissionsPage.tsx +873 -0
- package/template/src/demo/pages/RunnerPage.tsx +445 -0
- package/template/src/demo/pages/SystemPage.tsx +557 -0
- package/template/src/demo/pages/VaultPage.tsx +805 -0
- package/template/src/ekka/__tests__/demo-backend.test.ts +187 -0
- package/template/src/ekka/audit/index.ts +7 -0
- package/template/src/ekka/audit/store.ts +68 -0
- package/template/src/ekka/audit/types.ts +22 -0
- package/template/src/ekka/auth/client.ts +212 -0
- package/template/src/ekka/auth/index.ts +30 -0
- package/template/src/ekka/auth/storage.ts +114 -0
- package/template/src/ekka/auth/types.ts +67 -0
- package/template/src/ekka/backend/demo.ts +151 -0
- package/template/src/ekka/backend/interface.ts +36 -0
- package/template/src/ekka/config.ts +48 -0
- package/template/src/ekka/constants.ts +143 -0
- package/template/src/ekka/errors.ts +54 -0
- package/template/src/ekka/index.ts +516 -0
- package/template/src/ekka/internal/backend.ts +156 -0
- package/template/src/ekka/internal/index.ts +7 -0
- package/template/src/ekka/ops/auth.ts +29 -0
- package/template/src/ekka/ops/debug.ts +68 -0
- package/template/src/ekka/ops/home.ts +101 -0
- package/template/src/ekka/ops/index.ts +16 -0
- package/template/src/ekka/ops/nodeCredentials.ts +131 -0
- package/template/src/ekka/ops/nodeSession.ts +145 -0
- package/template/src/ekka/ops/paths.ts +183 -0
- package/template/src/ekka/ops/runner.ts +86 -0
- package/template/src/ekka/ops/runtime.ts +31 -0
- package/template/src/ekka/ops/setup.ts +47 -0
- package/template/src/ekka/ops/vault.ts +459 -0
- package/template/src/ekka/ops/workflowRuns.ts +116 -0
- package/template/src/ekka/types.ts +82 -0
- package/template/src/ekka/utils/idempotency.ts +14 -0
- package/template/src/ekka/utils/index.ts +7 -0
- package/template/src/ekka/utils/time.ts +77 -0
- package/template/src/main.tsx +12 -0
- package/template/src/vite-env.d.ts +12 -0
- package/template/src-tauri/Cargo.toml +41 -0
- package/template/src-tauri/build.rs +3 -0
- package/template/src-tauri/capabilities/default.json +11 -0
- package/template/src-tauri/icons/icon.icns +0 -0
- package/template/src-tauri/icons/icon.png +0 -0
- package/template/src-tauri/resources/ekka-engine-bootstrap +0 -0
- package/template/src-tauri/src/bootstrap.rs +37 -0
- package/template/src-tauri/src/commands.rs +1215 -0
- package/template/src-tauri/src/device_secret.rs +111 -0
- package/template/src-tauri/src/engine_process.rs +538 -0
- package/template/src-tauri/src/grants.rs +129 -0
- package/template/src-tauri/src/handlers/home.rs +65 -0
- package/template/src-tauri/src/handlers/mod.rs +7 -0
- package/template/src-tauri/src/handlers/paths.rs +128 -0
- package/template/src-tauri/src/handlers/vault.rs +680 -0
- package/template/src-tauri/src/main.rs +243 -0
- package/template/src-tauri/src/node_auth.rs +858 -0
- package/template/src-tauri/src/node_credentials.rs +541 -0
- package/template/src-tauri/src/node_runner.rs +882 -0
- package/template/src-tauri/src/node_vault_crypto.rs +113 -0
- package/template/src-tauri/src/node_vault_store.rs +267 -0
- package/template/src-tauri/src/ops/auth.rs +50 -0
- package/template/src-tauri/src/ops/home.rs +251 -0
- package/template/src-tauri/src/ops/mod.rs +7 -0
- package/template/src-tauri/src/ops/runtime.rs +21 -0
- package/template/src-tauri/src/state.rs +639 -0
- package/template/src-tauri/src/types.rs +84 -0
- package/template/src-tauri/tauri.conf.json +41 -0
- package/template/tsconfig.json +26 -0
- package/template/tsconfig.tsbuildinfo +1 -0
- package/template/vite.config.ts +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# create-ekka-desktop-app
|
|
2
|
+
|
|
3
|
+
Scaffold a new EKKA desktop app with one command. Zero config, batteries included.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx create-ekka-desktop-app my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
npm install
|
|
11
|
+
npm run tauri:dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
That's it. You now have a native desktop app running.
|
|
15
|
+
|
|
16
|
+
## What You Get
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
my-app/
|
|
20
|
+
├── src/
|
|
21
|
+
│ ├── app/App.tsx # Your app (start here)
|
|
22
|
+
│ ├── demo/ # Demo UI (delete when ready)
|
|
23
|
+
│ └── ekka/ # EKKA SDK (do not modify)
|
|
24
|
+
├── src-tauri/ # Tauri (Rust) shell
|
|
25
|
+
├── branding/ # App name, icon, bundle ID
|
|
26
|
+
├── package.json
|
|
27
|
+
└── vite.config.ts
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Development
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Web browser (fast reload)
|
|
34
|
+
npm start
|
|
35
|
+
|
|
36
|
+
# Desktop window (native)
|
|
37
|
+
npm run tauri:dev
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Build
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Create distributable .app
|
|
44
|
+
npm run tauri:build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Output: `src-tauri/target/release/bundle/macos/<AppName>.app`
|
|
48
|
+
|
|
49
|
+
## Customize Branding
|
|
50
|
+
|
|
51
|
+
Edit `branding/app.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"name": "My App",
|
|
56
|
+
"bundleId": "com.mycompany.myapp",
|
|
57
|
+
"version": "1.0.0"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Replace `branding/icon.icns` with your app icon.
|
|
62
|
+
|
|
63
|
+
## Project Structure
|
|
64
|
+
|
|
65
|
+
| Path | Purpose |
|
|
66
|
+
|------|---------|
|
|
67
|
+
| `src/app/App.tsx` | **Your app code starts here** |
|
|
68
|
+
| `src/demo/` | Demo UI - delete when you're ready to build your own |
|
|
69
|
+
| `src/ekka/` | EKKA SDK - provides secure APIs (do not modify) |
|
|
70
|
+
| `src-tauri/` | Tauri shell - handles native window, builds .app |
|
|
71
|
+
| `branding/` | App name, icon, bundle ID |
|
|
72
|
+
|
|
73
|
+
## EKKA SDK
|
|
74
|
+
|
|
75
|
+
The app includes the EKKA SDK at `src/ekka/`. It provides:
|
|
76
|
+
|
|
77
|
+
- **Secure key-value storage** - Data persists across sessions
|
|
78
|
+
- **Background work queues** - Run async tasks reliably
|
|
79
|
+
- **Policy enforcement** - All operations are auditable
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { ekka } from './ekka';
|
|
83
|
+
|
|
84
|
+
// Store data
|
|
85
|
+
await ekka.store.set('key', 'value');
|
|
86
|
+
|
|
87
|
+
// Retrieve data
|
|
88
|
+
const value = await ekka.store.get('key');
|
|
89
|
+
|
|
90
|
+
// Queue background work
|
|
91
|
+
await ekka.work.enqueue({ task: 'process', data: {...} });
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Demo Mode
|
|
95
|
+
|
|
96
|
+
The app runs in **demo mode** by default - all data is stored in memory. This lets you develop and test without any backend setup.
|
|
97
|
+
|
|
98
|
+
When you're ready for production:
|
|
99
|
+
1. Build with the EKKA engine sidecar (via `ekka-desktop-build`)
|
|
100
|
+
2. The SDK automatically connects to the real backend
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
|
|
104
|
+
- Node.js 18+
|
|
105
|
+
- Rust (for Tauri builds)
|
|
106
|
+
- Xcode Command Line Tools (macOS)
|
|
107
|
+
|
|
108
|
+
## Commands
|
|
109
|
+
|
|
110
|
+
| Command | Description |
|
|
111
|
+
|---------|-------------|
|
|
112
|
+
| `npm start` | Start dev server (web) |
|
|
113
|
+
| `npm run tauri:dev` | Start dev server (desktop) |
|
|
114
|
+
| `npm run tauri:build` | Build distributable app |
|
|
115
|
+
| `npm run lint` | Run ESLint |
|
|
116
|
+
| `npm run build` | Build frontend only |
|
|
117
|
+
|
|
118
|
+
## FAQ
|
|
119
|
+
|
|
120
|
+
**Q: How do I change the app name?**
|
|
121
|
+
Edit `branding/app.json` and set the `name` field.
|
|
122
|
+
|
|
123
|
+
**Q: How do I change the app icon?**
|
|
124
|
+
Replace `branding/icon.icns` with your icon file.
|
|
125
|
+
|
|
126
|
+
**Q: How do I remove the demo UI?**
|
|
127
|
+
Delete `src/demo/` and update `src/main.tsx` to render your own component.
|
|
128
|
+
|
|
129
|
+
**Q: Where is my data stored in demo mode?**
|
|
130
|
+
In memory. It resets when you restart the app.
|
|
131
|
+
|
|
132
|
+
**Q: How do I connect to a real backend?**
|
|
133
|
+
Build with `ekka-desktop-build` which injects the EKKA engine sidecar.
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { resolve, join, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const templateDir = resolve(__dirname, '..', 'template');
|
|
9
|
+
|
|
10
|
+
const projectName = process.argv[2];
|
|
11
|
+
|
|
12
|
+
if (!projectName) {
|
|
13
|
+
console.error('Usage: npx create-ekka-desktop-app <project-name>');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const targetDir = resolve(process.cwd(), projectName);
|
|
18
|
+
|
|
19
|
+
if (existsSync(targetDir)) {
|
|
20
|
+
console.error(`Error: Directory "${projectName}" already exists.`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log(`Creating EKKA desktop app in ${targetDir}...`);
|
|
25
|
+
|
|
26
|
+
// Copy template
|
|
27
|
+
mkdirSync(targetDir, { recursive: true });
|
|
28
|
+
cpSync(templateDir, targetDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
// Update package.json with project name
|
|
31
|
+
const pkgPath = join(targetDir, 'package.json');
|
|
32
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
33
|
+
pkg.name = projectName;
|
|
34
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
35
|
+
|
|
36
|
+
// Update branding/app.json with project name
|
|
37
|
+
const brandingPath = join(targetDir, 'branding', 'app.json');
|
|
38
|
+
const branding = JSON.parse(readFileSync(brandingPath, 'utf8'));
|
|
39
|
+
// Convert project-name to "Project Name" for display
|
|
40
|
+
const displayName = projectName
|
|
41
|
+
.split('-')
|
|
42
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
43
|
+
.join(' ');
|
|
44
|
+
// Convert project-name to ai.ekka.projectname for bundleId
|
|
45
|
+
const bundleId = `ai.ekka.${projectName.replace(/-/g, '')}`;
|
|
46
|
+
branding.name = displayName;
|
|
47
|
+
branding.bundleId = bundleId;
|
|
48
|
+
writeFileSync(brandingPath, JSON.stringify(branding, null, 2) + '\n');
|
|
49
|
+
|
|
50
|
+
// Update src-tauri/Cargo.toml crate name
|
|
51
|
+
const cargoPath = join(targetDir, 'src-tauri', 'Cargo.toml');
|
|
52
|
+
let cargoContent = readFileSync(cargoPath, 'utf8');
|
|
53
|
+
cargoContent = cargoContent.replace(/^name = ".*"$/m, `name = "${projectName}"`);
|
|
54
|
+
cargoContent = cargoContent.replace(/^description = ".*"$/m, `description = "${displayName}"`);
|
|
55
|
+
writeFileSync(cargoPath, cargoContent);
|
|
56
|
+
|
|
57
|
+
console.log(`
|
|
58
|
+
Done! To get started:
|
|
59
|
+
|
|
60
|
+
cd ${projectName}
|
|
61
|
+
npm install
|
|
62
|
+
|
|
63
|
+
Development:
|
|
64
|
+
npm start # Web (browser)
|
|
65
|
+
npm run tauri:dev # Desktop (native window)
|
|
66
|
+
|
|
67
|
+
Build:
|
|
68
|
+
npm run tauri:build # Create distributable app
|
|
69
|
+
|
|
70
|
+
Edit src/app/App.tsx to build your UI.
|
|
71
|
+
Delete src/demo/ when ready.
|
|
72
|
+
`);
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-ekka-desktop-app",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Create an EKKA desktop app with built-in demo backend. No setup required.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-ekka-desktop-app": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"template"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"ekka",
|
|
15
|
+
"desktop",
|
|
16
|
+
"scaffold",
|
|
17
|
+
"generator"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18.0.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EKKA Desktop App ESLint Configuration
|
|
3
|
+
*
|
|
4
|
+
* GUARDRAILS ENFORCED:
|
|
5
|
+
* - No fs, https, axios, child_process imports (TS is sandboxed)
|
|
6
|
+
* - No process.env access (TS MUST NOT decide config)
|
|
7
|
+
* - No direct fetch() calls outside src/ekka/client.ts
|
|
8
|
+
* - All network MUST go through the ekka client
|
|
9
|
+
*
|
|
10
|
+
* These rules enforce the EKKA security model:
|
|
11
|
+
* TS communicates ONLY through the ekka client to EKKA's servers.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import js from '@eslint/js'
|
|
15
|
+
import globals from 'globals'
|
|
16
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
17
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
18
|
+
import tseslint from 'typescript-eslint'
|
|
19
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
20
|
+
|
|
21
|
+
export default defineConfig([
|
|
22
|
+
globalIgnores(['dist', 'node_modules', 'src-tauri', 'vite.config.ts', 'eslint.config.js']),
|
|
23
|
+
|
|
24
|
+
// Base config for all TypeScript files
|
|
25
|
+
{
|
|
26
|
+
files: ['**/*.{ts,tsx}'],
|
|
27
|
+
extends: [
|
|
28
|
+
js.configs.recommended,
|
|
29
|
+
tseslint.configs.recommended,
|
|
30
|
+
reactRefresh.configs.vite,
|
|
31
|
+
],
|
|
32
|
+
plugins: {
|
|
33
|
+
'react-hooks': reactHooks,
|
|
34
|
+
},
|
|
35
|
+
languageOptions: {
|
|
36
|
+
ecmaVersion: 2020,
|
|
37
|
+
globals: globals.browser,
|
|
38
|
+
},
|
|
39
|
+
rules: {
|
|
40
|
+
// React hooks rules
|
|
41
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
42
|
+
'react-hooks/exhaustive-deps': 'warn',
|
|
43
|
+
|
|
44
|
+
// ========================================
|
|
45
|
+
// EKKA GUARDRAILS - FORBIDDEN IMPORTS
|
|
46
|
+
// ========================================
|
|
47
|
+
'no-restricted-imports': ['error', {
|
|
48
|
+
paths: [
|
|
49
|
+
// Node.js modules - TS MUST NOT access filesystem or spawn processes
|
|
50
|
+
{ name: 'fs', message: 'EKKA: TS is sandboxed. TS MUST NOT read files.' },
|
|
51
|
+
{ name: 'fs/promises', message: 'EKKA: TS is sandboxed. TS MUST NOT read files.' },
|
|
52
|
+
{ name: 'node:fs', message: 'EKKA: TS is sandboxed. TS MUST NOT read files.' },
|
|
53
|
+
{ name: 'node:fs/promises', message: 'EKKA: TS is sandboxed. TS MUST NOT read files.' },
|
|
54
|
+
{ name: 'path', message: 'EKKA: TS is sandboxed. Use ekka client for all operations.' },
|
|
55
|
+
{ name: 'node:path', message: 'EKKA: TS is sandboxed. Use ekka client for all operations.' },
|
|
56
|
+
{ name: 'child_process', message: 'EKKA: TS is sandboxed. TS MUST NOT spawn processes.' },
|
|
57
|
+
{ name: 'node:child_process', message: 'EKKA: TS is sandboxed. TS MUST NOT spawn processes.' },
|
|
58
|
+
|
|
59
|
+
// Network libraries - TS MUST NOT make direct network calls
|
|
60
|
+
{ name: 'https', message: 'EKKA: TS MUST NOT make direct network calls. Use ekka client only.' },
|
|
61
|
+
{ name: 'node:https', message: 'EKKA: TS MUST NOT make direct network calls. Use ekka client only.' },
|
|
62
|
+
{ name: 'http', message: 'EKKA: TS MUST NOT make direct network calls. Use ekka client only.' },
|
|
63
|
+
{ name: 'node:http', message: 'EKKA: TS MUST NOT make direct network calls. Use ekka client only.' },
|
|
64
|
+
{ name: 'axios', message: 'EKKA: TS MUST NOT use axios. Use ekka client only.' },
|
|
65
|
+
{ name: 'node-fetch', message: 'EKKA: TS MUST NOT use node-fetch. Use ekka client only.' },
|
|
66
|
+
|
|
67
|
+
// Crypto - TS MUST NOT do crypto
|
|
68
|
+
{ name: 'crypto', message: 'EKKA: TS MUST NOT do crypto. Server handles all crypto.' },
|
|
69
|
+
{ name: 'node:crypto', message: 'EKKA: TS MUST NOT do crypto. Server handles all crypto.' },
|
|
70
|
+
],
|
|
71
|
+
patterns: [
|
|
72
|
+
{ group: ['axios/*'], message: 'EKKA: TS MUST NOT use axios. Use ekka client only.' },
|
|
73
|
+
],
|
|
74
|
+
}],
|
|
75
|
+
|
|
76
|
+
// ========================================
|
|
77
|
+
// EKKA GUARDRAILS - NO PROCESS.ENV
|
|
78
|
+
// ========================================
|
|
79
|
+
'no-restricted-globals': ['error',
|
|
80
|
+
{ name: 'process', message: 'EKKA: TS MUST NOT access process.env. Config is managed by EKKA.' },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// ========================================
|
|
86
|
+
// EKKA GUARDRAILS - NO FETCH() ANYWHERE
|
|
87
|
+
// ALL HTTP must go through Tauri/Rust via engine_request
|
|
88
|
+
// ========================================
|
|
89
|
+
{
|
|
90
|
+
files: ['src/**/*.{ts,tsx}'],
|
|
91
|
+
rules: {
|
|
92
|
+
'no-restricted-globals': ['error',
|
|
93
|
+
{ name: 'process', message: 'EKKA: TS MUST NOT access process.env. Config is managed by EKKA.' },
|
|
94
|
+
{ name: 'fetch', message: 'EKKA: Direct fetch() is FORBIDDEN. All HTTP must go through Tauri via engine_request. See RULEBOOK_ARCHITECTURE_AI.md.' },
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
])
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>EKKA Desktop App</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
html, body, #root {
|
|
14
|
+
height: 100%;
|
|
15
|
+
width: 100%;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
body {
|
|
19
|
+
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
|
|
20
|
+
-webkit-font-smoothing: antialiased;
|
|
21
|
+
-moz-osx-font-smoothing: grayscale;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<div id="root"></div>
|
|
27
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ekka-desktop-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"start": "vite",
|
|
9
|
+
"build": "tsc -b && vite build",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"lint:fix": "eslint . --fix",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:watch": "vitest",
|
|
14
|
+
"preview": "vite preview",
|
|
15
|
+
"tauri": "tauri",
|
|
16
|
+
"tauri:dev": "tauri dev",
|
|
17
|
+
"tauri:build": "tauri build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@tauri-apps/api": "^2.0.0",
|
|
21
|
+
"@tauri-apps/plugin-dialog": "^2.6.0",
|
|
22
|
+
"react": "^19.0.0",
|
|
23
|
+
"react-dom": "^19.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@eslint/js": "^9.17.0",
|
|
27
|
+
"@tauri-apps/cli": "^2.0.0",
|
|
28
|
+
"@types/react": "^19.0.0",
|
|
29
|
+
"@types/react-dom": "^19.0.0",
|
|
30
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
31
|
+
"eslint": "^9.17.0",
|
|
32
|
+
"eslint-plugin-react-hooks": "^5.0.0",
|
|
33
|
+
"eslint-plugin-react-refresh": "^0.4.16",
|
|
34
|
+
"globals": "^15.14.0",
|
|
35
|
+
"typescript": "~5.6.2",
|
|
36
|
+
"typescript-eslint": "^8.18.2",
|
|
37
|
+
"vite": "^6.0.0",
|
|
38
|
+
"vitest": "^3.2.4"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Your App - Edit this file!
|
|
3
|
+
*
|
|
4
|
+
* This is where you build your UI.
|
|
5
|
+
* Use the ekka client for all data operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ekka } from '../ekka';
|
|
9
|
+
|
|
10
|
+
export function App() {
|
|
11
|
+
// Example: Initialize on button click
|
|
12
|
+
async function handleStart() {
|
|
13
|
+
await ekka.connect();
|
|
14
|
+
// Now you can use ekka.db and ekka.queue
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div style={{ padding: '2rem', fontFamily: 'system-ui, sans-serif' }}>
|
|
19
|
+
<h1>My EKKA App</h1>
|
|
20
|
+
<p>Edit <code>src/app/App.tsx</code> to get started.</p>
|
|
21
|
+
<button onClick={handleStart}>Start</button>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|