pakstr 0.29.1 → 0.31.0

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 CHANGED
@@ -19,7 +19,7 @@ The CLI API and configuration format may change before 1.0.0.
19
19
 
20
20
  ## Requirements
21
21
 
22
- * **Node.js** 22+
22
+ * **Node.js** 22.12+
23
23
  * **Docker Desktop**
24
24
 
25
25
  *Note: No Android SDK, Gradle, Java, or Android keystore setup is required locally.*
@@ -67,6 +67,16 @@ npx pakstr run
67
67
  * `npx pakstr delete --publisher` — Inventory every event authored by the configured publish nsec; add `--execute` for the publisher-wide NIP-09 deletion request.
68
68
  * `npx pakstr run` — Execute the full pipeline at once (**build** + **sign** + **publish**).
69
69
 
70
+ ### Desktop (macOS arm64, Windows x64, Linux x64, experimental)
71
+
72
+ `pakstr build --target macos-arm64` packages the same `pakstr.yaml` app as `<appName>.app` in `<appId>-macos-arm64.zip` next to `build.out`. It runs on macOS only and downloads the pinned Electron release on first use. The app is ad-hoc signed and **not notarized**: Gatekeeper rejects it once downloaded, so it is for local testing only. App data lives in `~/Library/Application Support/<appId>`.
73
+
74
+ `pakstr build --target windows-x64` writes `<appId>-windows-x64-setup.exe`, a per-user installer (no admin rights; installs to `%LOCALAPPDATA%\Programs\<appId>` with a Start menu shortcut and an uninstaller), and `<appId>-windows-x64.zip`, a portable `<appName>\<appName>.exe` folder. It builds on any host with [NSIS 3](https://nsis.sourceforge.io/) (`makensis`) on `PATH` (`brew install makensis`, `apt install nsis`, or the Windows NSIS installer). Both are **unsigned**, so SmartScreen warns before the first run. The numeric part of `versionName` becomes the Windows file version. App data lives in `%APPDATA%\<appId>` and survives uninstall.
75
+
76
+ `pakstr build --target linux-x64` writes `<appId>-linux-x64.AppImage` and `<appId>-linux-x64.zip`, a portable `<appName>/<appId>` folder that keeps its executable bits. It builds on macOS or Linux (not Windows) with squashfs-tools 4.5+ (`mksquashfs`, `unsquashfs`) on `PATH` (`brew install squashfs`, `apt install squashfs-tools`), and downloads the pinned Electron release and AppImage runtime on first use. The icon comes from the same `logo.png` / `app.icon` lookup as Android. Running the AppImage needs FUSE 3, and Chromium's sandbox needs unprivileged user namespaces; Pakstr never turns the sandbox off, so distributions that restrict them (Ubuntu 23.10+) need an AppArmor profile or an administrator-installed package. App data lives in `~/.config/<appId>`.
77
+
78
+ Desktop publishing and other platforms are not supported yet; `sign`, `publish`, and `run` remain Android-only.
79
+
70
80
  Delete commands are non-destructive by default. `--app` and `--publisher` are mutually exclusive, and Blossom HTTP deletion requires `--app --execute --delete-blobs`. NIP-09 is best-effort: relay acceptance does not prove physical erasure, and discovery is limited to events retained and returned by the configured relay.
71
81
 
72
82
  ---
@@ -1,6 +1,9 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
- <application>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ xmlns:tools="http://schemas.android.com/tools">
4
+ <application
5
+ android:memtagMode="sync"
6
+ tools:replace="android:memtagMode">
4
7
  <activity-alias
5
8
  android:name=".debug.DeveloperToolsDebugLauncher"
6
9
  android:enabled="true"
@@ -23,6 +23,7 @@
23
23
  android:fullBackupContent="@xml/backup_rules"
24
24
  android:icon="@mipmap/ic_launcher"
25
25
  android:label="@string/app_name"
26
+ android:memtagMode="async"
26
27
  android:networkSecurityConfig="@xml/network_security_config"
27
28
  android:roundIcon="@mipmap/ic_launcher_round"
28
29
  android:supportsRtl="true"
@@ -0,0 +1,108 @@
1
+ # Pakstr desktop runtime
2
+
3
+ Electron runtime that hosts a Pakstr web app on desktop, mirroring the Android
4
+ shell's contracts. `pakstr build --target macos-arm64|windows-x64|linux-x64`
5
+ stages this bundle with the app (`src/desktop/` in the CLI); the bundle ships
6
+ in the CLI's npm package. All targets package the same bundle; only the menu
7
+ differs (`src/appMenu.js`).
8
+
9
+ ## Build
10
+
11
+ ```sh
12
+ npm --prefix packages/cli ci
13
+ npm --prefix packages/cli run build # tsc, then bundles dist/main.js and dist/preload.js
14
+ ```
15
+
16
+ `npm --prefix packages/cli/desktop-runtime install` is only needed to run the
17
+ runtime unpackaged with the `electron` dev binary.
18
+
19
+ `dist/main.js` and `dist/preload.js` are self-contained: only `electron` and
20
+ Node built-ins are left external (the build fails otherwise), so a generated
21
+ app needs no `node_modules`. Third-party code and `src/shared` come from the
22
+ CLI package. The `debug` package is compiled out because applesauce logs
23
+ NIP-46 request params through it.
24
+
25
+ ## Generated app layout
26
+
27
+ ```
28
+ <appRoot>/package.json "main" -> the bundled main.js (preload.js beside it)
29
+ <appRoot>/pakstr-desktop.json { "appId": "com.example.app", "appName": "Example" }
30
+ <appRoot>/web/ staged web assets, incl. pakstr-runtime.json
31
+ ```
32
+
33
+ ## Behaviour
34
+
35
+ - The app is served from `pakstr://app` (standard, secure scheme) with the
36
+ Android SPA fallback. `/api/*` is proxied to the effective API base
37
+ (persisted override, then packaged `apiBase`, then disabled). API cookies
38
+ live in the session cookie jar and never reach the renderer, and neither
39
+ do `Set-Cookie` or `Location`. Redirects are not followed.
40
+ - NIP-98: `X-Forwarded-Host: app` / `X-Forwarded-Proto: pakstr` are added
41
+ only when the event's unique `u` tag is exactly the local request URL.
42
+ - `window.nostr` (plain and writable, like `nip07.js`) and the synchronous
43
+ `window.PakstrBridge.getApiBaseUrl()` / `setApiBaseUrl(url)` exist only in
44
+ the main window's `pakstr://app` top frame. The first `window.nostr` call
45
+ without a signer opens a `nostrconnect://` pairing prompt that uses the
46
+ strict `src/shared/nip46Pairing` module.
47
+ - All renderers are sandboxed with context isolation. Top-level navigation
48
+ stays on `pakstr://app`, `window.open` is denied, and web permissions are
49
+ denied except clipboard write and fullscreen. DevTools are available only
50
+ when unpackaged, and a packaged app exits if launched with a
51
+ remote-debugging or certificate-bypass switch. The runtime never disables
52
+ Chromium's sandbox.
53
+ - All data (cookies, storage, API base override) lives in
54
+ `<appData>/<appId>`. The Electron app name is also the appId, because it
55
+ names the keychain item holding the cookie-encryption key ("<name> Safe
56
+ Storage"): renaming `appName` keeps sessions. The macOS menu shows `appName`.
57
+
58
+ ## Windows: not yet verified on a Windows machine
59
+
60
+ Windows packages are cross-built and checked structurally (executable
61
+ metadata, fuses, asar integrity, portable ZIP contents, NSIS output), but
62
+ nothing here runs them. Before relying on `windows-x64`, check on real Windows
63
+ 10/11 x64:
64
+
65
+ - The installer runs without admin rights. The Start menu shortcut, the
66
+ Apps & features entry, and the finish-page launch work, and uninstalling
67
+ removes everything except `%APPDATA%\<appId>`.
68
+ - Reinstalling or upgrading over a running app prompts to close it, and an
69
+ upgrade that renames `appName` leaves no old `.exe` or shortcut behind.
70
+ - The portable ZIP runs after extraction, including from a path with spaces
71
+ or non-ASCII characters.
72
+ - The app starts with the asar-integrity and `OnlyLoadAppFromAsar` fuses on.
73
+ `pakstr://app` loads, `/api` proxying, cookies (DPAPI), `window.nostr`,
74
+ NIP-46 pairing, and signer auth links work, and a second launch focuses the
75
+ first window.
76
+ - Taskbar pinning: Electron's default AppUserModelID may not match the
77
+ installer's shortcut (it has no AUMID), so a pin from the Start menu can
78
+ show as a separate taskbar button.
79
+ - SmartScreen shows the unsigned-publisher warning; there is no Authenticode
80
+ signing yet.
81
+
82
+ ## Linux: not yet verified on a Linux machine
83
+
84
+ Linux packages are cross-built and checked structurally (pinned AppImage
85
+ runtime, root-owned squashfs with exact modes, desktop entry, icon, portable
86
+ ZIP modes, fuses, asar hashes), but nothing here runs them. Electron enforces
87
+ embedded asar integrity on macOS and Windows only, so on Linux the read-only
88
+ AppImage filesystem and the build-time checks are what protect `app.asar`.
89
+ Before relying on `linux-x64`, check on real x64 distributions (e.g. Ubuntu
90
+ 22.04 and 24.04, Fedora, Debian 12):
91
+
92
+ - The AppImage starts with FUSE 3 (`fusermount3`), and with
93
+ `--appimage-extract-and-run` without FUSE; the portable ZIP runs after
94
+ `unzip`, including from a path with spaces.
95
+ - Chromium's sandbox: with unprivileged user namespaces available the app
96
+ starts sandboxed. Where they are restricted (Ubuntu 23.10+ AppArmor) it
97
+ is expected to abort rather than run unsandboxed; record the message. The
98
+ runtime never passes `--no-sandbox`, and `chrome-sandbox` is not setuid.
99
+ - `pakstr://app` loads, `/api` proxying, `window.nostr`, NIP-46 pairing, and
100
+ signer auth links (`xdg-open`) work, and a second launch focuses the first
101
+ window.
102
+ - Cookies are encrypted with the desktop keyring (Secret Service / KWallet);
103
+ without one, Chromium falls back to a fixed key, so check which backend is
104
+ used.
105
+ - The window class / Wayland app id is the appId, so desktop integration
106
+ (AppImageLauncher, appimaged) groups the window with the desktop entry and
107
+ shows the icon. Required system libraries (GTK 3, NSS, libgbm, ALSA, ...)
108
+ are those of any Chromium build and are not bundled.