Metadata-Version: 2.4
Name: caspian-native
Version: 0.0.3
Summary: Optional Tauri packaging for Caspian applications
Author: Caspian Native contributors
License-Expression: MIT
Keywords: caspian,pulsepoint,tauri,desktop,webview
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Environment :: Win32 (MS Windows)
Classifier: Framework :: FastAPI
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: build
Requires-Dist: pyinstaller>=6; extra == "build"
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: ruff>=0.8; extra == "test"
Requires-Dist: pyright>=1.1; extra == "test"
Dynamic: license-file

# caspian-native

Optional Tauri packaging for applications built with the Caspian framework and
PulsePoint. Version `0.0.1` packages the existing application in a system
WebView; it does not translate HTML into operating-system widgets.

## Support in 0.0.1

| Target | Backend | Status |
| --- | --- | --- |
| Windows | Embedded Python sidecar | Initial support |
| Windows | Remote Caspian server | Initial support |
| Android | Remote Caspian server | Initial support |
| Android | Embedded Python | Not supported yet |

Android embedded Python is deliberately refused. A Caspian application may
depend on native Python wheels such as `asyncpg`, `cryptography`, or Pillow;
shipping an APK without proving every wheel for every ABI would produce a
package that builds unreliably or fails on launch.

## Install for development

```text
python -m pip install -e ".[test,build]"
```

Tauri's CLI is installed separately so it can match the version selected by
the generated application's `native/Cargo.toml`:

```text
cargo install tauri-cli --version "^2" --locked
```

## Add native packaging to a Caspian project

From a directory containing `caspian.config.json`:

```text
caspian-native init --identifier com.example.myapp --windows
caspian-native doctor --target windows
caspian-native backend build
caspian-native dev --target windows
caspian-native build --target windows
```

For an Android thin client backed by a deployed Caspian server:

```text
caspian-native init \
  --identifier com.example.myapp \
  --windows --android \
  --remote-url https://app.example.com
caspian-native doctor --target android
caspian-native build --target android
```

When Android is enabled, `init` also runs Tauri's non-interactive Android
project initializer. `dev` and `build` repeat this check and automatically
initialize `native/gen/android` for projects created by an earlier version.
The generated `tauri.android.conf.json` removes the desktop-only Python
sidecar from Android builds; Android always loads the configured remote server.

The generated files live under `native/`. Re-running `init` never overwrites a
changed generated file unless `--force` is supplied.

## Configuration

`caspian.native.json` is the source of truth:

```json
{
  "$schema": "./caspian.native.schema.json",
  "schema": 1,
  "productName": "My App",
  "identifier": "com.example.myapp",
  "version": "0.0.1",
  "targets": ["windows"],
  "window": {
    "title": "My App",
    "width": 1200,
    "height": 800,
    "resizable": true
  },
  "backend": {
    "desktopMode": "embedded",
    "remoteUrl": null
  },
  "security": {
    "loopbackToken": true
  }
}
```

## Runtime model

Embedded desktop mode builds `main.py`, the Caspian runtime, project modules,
route index, and `public/` into a one-file sidecar. The sidecar:

1. restores a per-installation `AUTH_SECRET` from application data;
2. imports the project's `main.app` in production mode;
3. binds `127.0.0.1` on an operating-system-assigned port;
4. prints the protected launch URL to the Tauri host;
5. serves the normal Caspian ASGI application with Uvicorn.

The WebView receives a per-launch token once. The native middleware exchanges
it for an `HttpOnly; SameSite=Strict` cookie and refuses documents, assets,
RPCs, uploads, streams, and WebSocket handshakes without that cookie.

Caspian's production session cookie normally has the `Secure` flag. A packaged
loopback server intentionally uses `http://127.0.0.1`, so the adapter changes
only that middleware option before Starlette constructs the stack. The app
otherwise remains in production mode.

## Native bridge

Pages may capability-check `window.caspianNative`:

```javascript
const native = window.caspianNative;
if (native?.has("open-external")) {
  await native.invoke("open_external", { url: "https://example.com" });
}
```

The bridge allowlist is intentionally short: platform, application version,
application data directory, external HTTP/HTTPS/mail links, and a user-driven
file picker. An XSS can reach every bridge command, so commands must remain
safe even when the calling page is compromised.

## Current limitations

- The first embedded-backend implementation uses PyInstaller and has only been
  designed for Windows packaging.
- Dynamic route discovery requires project Python sources and
  `settings/files-list.json` to be bundled.
- Secrets from `.env` are never embedded. Remote database credentials and
  third-party credentials must be provisioned outside the package.
- Android remote mode requires connectivity and a deployed Caspian server.
- Installer signing and Android store signing are not automated in `0.0.1`.
