Skip to content

Commit fd2d555

Browse files
committed
Update files
1 parent 0a81a44 commit fd2d555

19 files changed

Lines changed: 5808 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ coverage/
1616
*.db-journal
1717
docker/artifacts/*
1818
!docker/artifacts/.gitkeep
19+
.cache/
20+
apps/objectos-desktop/runtime/
21+
apps/objectos-desktop/src-tauri/target/
22+
apps/objectos-desktop/src-tauri/gen/

apps/objectos-desktop/README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# `apps/objectos-desktop`
2+
3+
**ObjectOS Desktop** — a [Tauri](https://tauri.app) v2 shell that wraps
4+
the `@objectos/app` Node runtime as a sidecar and exposes it through a
5+
native WebView. The goal is a "download → double‑click → ready to use"
6+
experience for end users on macOS, Windows and Linux.
7+
8+
## Architecture
9+
10+
```
11+
┌──────────────────────────────────────────┐
12+
│ Tauri shell (Rust) │
13+
│ ├── splash WebView (src/index.html) │
14+
│ ├── waits for sidecar port │
15+
│ └── navigates to http://localhost:N │
16+
│ │
17+
│ Sidecar: bundled Node runs │
18+
│ apps/objectos/desktop.mjs │
19+
│ → objectstack serve --port N │
20+
└──────────────────────────────────────────┘
21+
```
22+
23+
The Node tree is staged under `runtime/` by
24+
`scripts/stage-runtime.mjs` (called automatically by `dev` / `build`)
25+
and bundled by Tauri as resources.
26+
27+
## Prerequisites
28+
29+
- Node ≥ 20 + pnpm 10
30+
- Rust (stable) — `curl https://sh.rustup.rs -sSf | sh`
31+
- macOS: Xcode Command Line Tools
32+
- Windows: WebView2 (preinstalled on Win10+) + MSVC build tools
33+
- Linux: `libwebkit2gtk-4.1-dev`, `build-essential`, `libssl-dev`
34+
35+
## Develop
36+
37+
```bash
38+
pnpm install # repo root
39+
pnpm --filter @objectos/desktop dev # stages runtime + tauri dev
40+
```
41+
42+
The first run builds Rust dependencies (~2–4 min). Subsequent runs are
43+
fast.
44+
45+
## Build distributables
46+
47+
```bash
48+
pnpm --filter @objectos/desktop build
49+
```
50+
51+
Output lands in `src-tauri/target/release/bundle/`:
52+
53+
| Platform | Artifact |
54+
|----------|-----------------------------------------|
55+
| macOS | `dmg/ObjectOS_<v>_<arch>.dmg` + `.app` |
56+
| Windows | `nsis/ObjectOS_<v>_x64-setup.exe` |
57+
| Linux | `deb/objectos_<v>_amd64.deb`, AppImage |
58+
59+
Code signing / notarization is configured per platform in
60+
`src-tauri/tauri.conf.json` (see Tauri docs).
61+
62+
## Comparison with the portable zip
63+
64+
| | Portable zip | Tauri |
65+
|---|---|---|
66+
| Brand | none (terminal) | dock icon, menu, tray |
67+
| Size | ~110 MB | ~120 MB (Node sidecar dominates; shell adds ~10 MB) |
68+
| Auto‑update | no | yes (Tauri updater) |
69+
| Code signing | manual | first‑class |
70+
| Dev effort | tiny | moderate (Rust toolchain) |
71+
72+
Both share `desktop.mjs`, so the runtime behaviour is identical.

apps/objectos-desktop/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "@objectos/desktop",
3+
"version": "0.0.0",
4+
"private": true,
5+
"license": "AGPL-3.0",
6+
"description": "ObjectOS Desktop — Tauri shell wrapping the @objectos/app Node runtime.",
7+
"type": "module",
8+
"scripts": {
9+
"stage": "node scripts/stage-runtime.mjs",
10+
"tauri": "tauri",
11+
"dev": "pnpm run stage && tauri dev",
12+
"build": "pnpm run stage && tauri build"
13+
},
14+
"devDependencies": {
15+
"@tauri-apps/cli": "^2.1.0"
16+
}
17+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Stage the Node runtime + @objectos/app tree under
4+
* `apps/objectos-desktop/runtime/`, so Tauri's resource bundler can ship it.
5+
*
6+
* Reuses the same bits scripts/build-desktop.sh produces, but in-tree
7+
* (no zipping). Idempotent; re-run after changing @objectos/app.
8+
*
9+
* runtime/
10+
* node | node.exe
11+
* app/
12+
* desktop.mjs
13+
* package.json
14+
* dist/objectstack.json
15+
* node_modules/
16+
*/
17+
import { execSync } from 'node:child_process';
18+
import { existsSync, mkdirSync, copyFileSync, rmSync, chmodSync } from 'node:fs';
19+
import { dirname, join, resolve } from 'node:path';
20+
import { fileURLToPath } from 'node:url';
21+
import { platform, arch } from 'node:os';
22+
23+
const HERE = dirname(fileURLToPath(import.meta.url));
24+
const PKG = resolve(HERE, '..');
25+
const REPO = resolve(PKG, '../..');
26+
const APP = resolve(REPO, 'apps/objectos');
27+
const RUNTIME = resolve(PKG, 'runtime');
28+
const NODE_VERSION = process.env.NODE_VERSION ?? '20.18.1';
29+
30+
const osName = ({ darwin: 'darwin', linux: 'linux', win32: 'win' })[platform()];
31+
const archName = ({ x64: 'x64', arm64: 'arm64' })[arch()];
32+
if (!osName || !archName) {
33+
console.error(`unsupported platform: ${platform()}/${arch()}`);
34+
process.exit(1);
35+
}
36+
37+
const sh = (cmd, opts = {}) => {
38+
console.log(`$ ${cmd}`);
39+
execSync(cmd, { stdio: 'inherit', ...opts });
40+
};
41+
42+
if (!existsSync(join(APP, 'dist/objectstack.json'))) {
43+
sh('pnpm --filter @objectos/app build', { cwd: REPO });
44+
}
45+
46+
rmSync(RUNTIME, { recursive: true, force: true });
47+
mkdirSync(join(RUNTIME, 'app/dist'), { recursive: true });
48+
copyFileSync(join(APP, 'package.json'), join(RUNTIME, 'app/package.json'));
49+
copyFileSync(join(APP, 'desktop.mjs'), join(RUNTIME, 'app/desktop.mjs'));
50+
copyFileSync(join(APP, 'dist/objectstack.json'), join(RUNTIME, 'app/dist/objectstack.json'));
51+
52+
sh(
53+
'npm install --omit=dev --no-audit --no-fund --loglevel=error --legacy-peer-deps better-sqlite3@^12.9.0',
54+
{ cwd: join(RUNTIME, 'app') }
55+
);
56+
57+
const cache = resolve(REPO, '.cache/node');
58+
mkdirSync(cache, { recursive: true });
59+
const ext = osName === 'win' ? 'zip' : osName === 'linux' ? 'tar.xz' : 'tar.gz';
60+
const pkgName = `node-v${NODE_VERSION}-${osName === 'win' ? 'win' : osName}-${archName}.${ext}`;
61+
const tarball = join(cache, pkgName);
62+
if (!existsSync(tarball)) {
63+
sh(`curl -fSL --retry 3 -o "${tarball}" https://nodejs.org/dist/v${NODE_VERSION}/${pkgName}`);
64+
}
65+
const extractDir = join(cache, pkgName.replace(/\.(tar\.(gz|xz)|zip)$/, ''));
66+
if (!existsSync(extractDir)) {
67+
if (ext === 'tar.gz') sh(`tar -xzf "${tarball}" -C "${cache}"`);
68+
else if (ext === 'tar.xz') sh(`tar -xJf "${tarball}" -C "${cache}"`);
69+
else sh(`cd "${cache}" && unzip -q "${tarball}"`);
70+
}
71+
if (osName === 'win') {
72+
copyFileSync(join(extractDir, 'node.exe'), join(RUNTIME, 'node.exe'));
73+
} else {
74+
const dst = join(RUNTIME, 'node');
75+
copyFileSync(join(extractDir, 'bin/node'), dst);
76+
chmodSync(dst, 0o755);
77+
}
78+
79+
console.log(`✓ staged runtime → ${RUNTIME}`);

0 commit comments

Comments
 (0)