akanjs 3.0.0-beta.26 → 3.0.0-beta.28
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/base/baseEnv.ts +19 -5
- package/client/csrTypes.ts +2 -0
- package/client/device.ts +28 -12
- package/client/index.ts +1 -0
- package/client/native/accessibility.ts +1 -0
- package/client/native/app-state.ts +1 -0
- package/client/native/app.ts +1 -0
- package/client/native/appearance.ts +1 -0
- package/client/native/auth-session.ts +1 -0
- package/client/native/autostart.ts +1 -0
- package/client/native/badge.ts +1 -0
- package/client/native/biometric.ts +1 -0
- package/client/native/browser.ts +1 -0
- package/client/native/camera.ts +1 -0
- package/client/native/clipboard.ts +1 -0
- package/client/native/contacts.ts +1 -0
- package/client/native/device.ts +1 -0
- package/client/native/dialog.ts +1 -0
- package/client/native/dock.ts +1 -0
- package/client/native/file-picker.ts +1 -0
- package/client/native/filesystem.ts +1 -0
- package/client/native/geolocation.ts +1 -0
- package/client/native/global-shortcut.ts +1 -0
- package/client/native/haptics.ts +1 -0
- package/client/native/http.ts +1 -0
- package/client/native/iap.ts +1 -0
- package/client/native/keep-awake.ts +1 -0
- package/client/native/keyboard.ts +1 -0
- package/client/native/local-notifications.ts +1 -0
- package/client/native/menu.ts +1 -0
- package/client/native/network.ts +1 -0
- package/client/native/opener.ts +1 -0
- package/client/native/preferences.ts +1 -0
- package/client/native/push.ts +1 -0
- package/client/native/screen-orientation.ts +1 -0
- package/client/native/screen.ts +1 -0
- package/client/native/secure-storage.ts +1 -0
- package/client/native/share.ts +1 -0
- package/client/native/single-instance.ts +1 -0
- package/client/native/splash-screen.ts +1 -0
- package/client/native/sqlite.ts +1 -0
- package/client/native/toast.ts +1 -0
- package/client/native/tray.ts +1 -0
- package/client/native/updates.ts +1 -0
- package/client/native/volume.ts +1 -0
- package/client/native/window-state.ts +1 -0
- package/client/native/window.ts +1 -0
- package/client/native.ts +31 -1
- package/client/resolveServerUrl.ts +11 -0
- package/client/router.ts +8 -0
- package/common/Logger.ts +26 -2
- package/common/RouteLayering.ts +52 -0
- package/common/index.ts +1 -0
- package/index.ts +115 -6
- package/native/desktop.ts +5 -0
- package/package.json +11 -1
- package/server/akanApp.ts +23 -3
- package/server/akanAppHeaders.ts +4 -1
- package/server/akanServer.ts +27 -7
- package/server/index.ts +1 -0
- package/server/lifecycle/orphanGroup.ts +21 -0
- package/server/nativeFile.ts +107 -0
- package/server/ops/opsRoute.ts +3 -2
- package/server/routeTreeBuilder.ts +14 -39
- package/server/routing/apiRouter.ts +26 -3
- package/server/routing/hostAllowlist.ts +24 -0
- package/server/selfExec.ts +25 -0
- package/server/types.tsx +3 -1
- package/server/webRouter.ts +7 -4
- package/service/ipcTypes.ts +4 -0
- package/signal/CrossSiteGuard.ts +7 -0
- package/test/signalTestRuntime.ts +8 -2
- package/types/base/baseEnv.d.ts +1 -0
- package/types/client/csrTypes.d.ts +2 -0
- package/types/client/index.d.ts +1 -0
- package/types/client/native/accessibility.d.ts +1 -0
- package/types/client/native/app-state.d.ts +1 -0
- package/types/client/native/app.d.ts +1 -0
- package/types/client/native/appearance.d.ts +1 -0
- package/types/client/native/auth-session.d.ts +1 -0
- package/types/client/native/autostart.d.ts +1 -0
- package/types/client/native/badge.d.ts +1 -0
- package/types/client/native/biometric.d.ts +1 -0
- package/types/client/native/browser.d.ts +1 -0
- package/types/client/native/camera.d.ts +1 -0
- package/types/client/native/clipboard.d.ts +1 -0
- package/types/client/native/contacts.d.ts +1 -0
- package/types/client/native/device.d.ts +1 -0
- package/types/client/native/dialog.d.ts +1 -0
- package/types/client/native/dock.d.ts +1 -0
- package/types/client/native/file-picker.d.ts +1 -0
- package/types/client/native/filesystem.d.ts +1 -0
- package/types/client/native/geolocation.d.ts +1 -0
- package/types/client/native/global-shortcut.d.ts +1 -0
- package/types/client/native/haptics.d.ts +1 -0
- package/types/client/native/http.d.ts +1 -0
- package/types/client/native/iap.d.ts +1 -0
- package/types/client/native/keep-awake.d.ts +1 -0
- package/types/client/native/keyboard.d.ts +1 -0
- package/types/client/native/local-notifications.d.ts +1 -0
- package/types/client/native/menu.d.ts +1 -0
- package/types/client/native/network.d.ts +1 -0
- package/types/client/native/opener.d.ts +1 -0
- package/types/client/native/preferences.d.ts +1 -0
- package/types/client/native/push.d.ts +1 -0
- package/types/client/native/screen-orientation.d.ts +1 -0
- package/types/client/native/screen.d.ts +1 -0
- package/types/client/native/secure-storage.d.ts +1 -0
- package/types/client/native/share.d.ts +1 -0
- package/types/client/native/single-instance.d.ts +1 -0
- package/types/client/native/splash-screen.d.ts +1 -0
- package/types/client/native/sqlite.d.ts +1 -0
- package/types/client/native/toast.d.ts +1 -0
- package/types/client/native/tray.d.ts +1 -0
- package/types/client/native/updates.d.ts +1 -0
- package/types/client/native/volume.d.ts +1 -0
- package/types/client/native/window-state.d.ts +1 -0
- package/types/client/native/window.d.ts +1 -0
- package/types/client/native.d.ts +14 -2
- package/types/client/resolveServerUrl.d.ts +1 -0
- package/types/client/router.d.ts +3 -0
- package/types/common/RouteLayering.d.ts +28 -0
- package/types/common/index.d.ts +1 -0
- package/types/index.d.ts +112 -6
- package/types/native/desktop.d.ts +3 -0
- package/types/server/akanAppHeaders.d.ts +2 -0
- package/types/server/index.d.ts +1 -0
- package/types/server/lifecycle/orphanGroup.d.ts +7 -0
- package/types/server/nativeFile.d.ts +10 -0
- package/types/server/routing/apiRouter.d.ts +3 -1
- package/types/server/routing/hostAllowlist.d.ts +8 -0
- package/types/server/selfExec.d.ts +8 -0
- package/types/server/types.d.ts +3 -1
- package/types/service/ipcTypes.d.ts +16 -0
- package/types/signal/CrossSiteGuard.d.ts +1 -0
- package/types/ui/recipe/buttonRecipe.d.ts +2 -2
- package/types/vendor/@akanjs/native/packages/cli/src/api.d.ts +57 -4
- package/types/vendor/@akanjs/native/packages/cli/src/config.d.ts +48 -0
- package/types/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.d.ts +8 -0
- package/types/vendor/@akanjs/native/packages/cli/src/lib/prepare.d.ts +8 -2
- package/types/vendor/@akanjs/native/packages/cli/src/lib/project.d.ts +10 -0
- package/types/vendor/@akanjs/native/packages/cli/src/lib/publish.d.ts +24 -0
- package/types/vendor/@akanjs/native/packages/cli/src/lib/updates.d.ts +24 -0
- package/types/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.d.ts +4 -1
- package/types/vendor/@akanjs/native/packages/cli/src/platforms/macos.d.ts +5 -0
- package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.d.ts +38 -0
- package/types/vendor/@akanjs/native/packages/desktop/src/dispatcher.d.ts +8 -1
- package/types/vendor/@akanjs/native/packages/desktop/src/grants.d.ts +11 -0
- package/types/vendor/@akanjs/native/packages/desktop/src/main.d.ts +11 -0
- package/types/vendor/@akanjs/native/packages/desktop/src/paths.d.ts +13 -2
- package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +27 -0
- package/types/vendor/@akanjs/native/packages/desktop/src/relaunch.d.ts +21 -0
- package/types/vendor/@akanjs/native/packages/desktop/src/server.d.ts +79 -0
- package/types/vendor/@akanjs/native/plugins/app/src/index.d.ts +5 -0
- package/types/vendor/@akanjs/native/plugins/file-picker/src/index.d.ts +20 -1
- package/types/vendor/@akanjs/native/plugins/push/src/index.d.ts +9 -0
- package/types/vendor/@akanjs/native/plugins/updates/src/desktop.d.ts +28 -0
- package/types/vendor/@akanjs/native/plugins/volume/src/common.d.ts +10 -0
- package/types/vendor/@akanjs/native/plugins/volume/src/desktop.d.ts +18 -0
- package/types/vendor/@akanjs/native/plugins/volume/src/index.d.ts +28 -0
- package/types/vendor/@akanjs/native/plugins/volume/src.d.ts +1 -0
- package/types/webkit/csrFrameDump.d.ts +42 -0
- package/types/webkit/nativeNavigation.d.ts +1 -0
- package/types/webkit/nativePurchase.d.ts +6 -2
- package/types/webkit/nativeUpdates.d.ts +8 -0
- package/ui/Agent/Attach.tsx +6 -2
- package/ui/CsrImage.tsx +3 -2
- package/ui/System/CSR.tsx +4 -0
- package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeActivity.kt +5 -1
- package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeBridge.kt +19 -0
- package/vendor/@akanjs/native/native/desktop/Cargo.toml +1 -1
- package/vendor/@akanjs/native/native/desktop/src/lib.rs +161 -25
- package/vendor/@akanjs/native/native/desktop/src/volume.rs +184 -0
- package/vendor/@akanjs/native/native/desktop/src/win/mod.rs +3 -1
- package/vendor/@akanjs/native/native/desktop/src/win/volume.rs +71 -0
- package/vendor/@akanjs/native/native/ios/Sources/AkanNativeShell.swift +12 -2
- package/vendor/@akanjs/native/packages/cli/src/api.ts +142 -12
- package/vendor/@akanjs/native/packages/cli/src/commands/build.ts +5 -3
- package/vendor/@akanjs/native/packages/cli/src/commands/update.ts +10 -71
- package/vendor/@akanjs/native/packages/cli/src/config.ts +41 -0
- package/vendor/@akanjs/native/packages/cli/src/lib/configkeys.ts +9 -2
- package/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.ts +58 -0
- package/vendor/@akanjs/native/packages/cli/src/lib/hmr.ts +2 -0
- package/vendor/@akanjs/native/packages/cli/src/lib/prepare.ts +10 -2
- package/vendor/@akanjs/native/packages/cli/src/lib/project.ts +38 -2
- package/vendor/@akanjs/native/packages/cli/src/lib/publish.ts +104 -0
- package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +85 -5
- package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +1 -0
- package/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.ts +6 -4
- package/vendor/@akanjs/native/packages/cli/src/platforms/desktop.ts +16 -0
- package/vendor/@akanjs/native/packages/cli/src/platforms/macos.ts +44 -1
- package/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.ts +436 -0
- package/vendor/@akanjs/native/packages/cli/src/platforms/windows.ts +2 -0
- package/vendor/@akanjs/native/packages/core/src/runtime.ts +26 -5
- package/vendor/@akanjs/native/packages/desktop/src/dispatcher.ts +20 -0
- package/vendor/@akanjs/native/packages/desktop/src/grants.ts +47 -0
- package/vendor/@akanjs/native/packages/desktop/src/host.ts +102 -14
- package/vendor/@akanjs/native/packages/desktop/src/main.ts +59 -11
- package/vendor/@akanjs/native/packages/desktop/src/paths.ts +38 -4
- package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +28 -0
- package/vendor/@akanjs/native/packages/desktop/src/relaunch.ts +159 -0
- package/vendor/@akanjs/native/packages/desktop/src/server.ts +493 -0
- package/vendor/@akanjs/native/plugins/app/android/AppPlugin.kt +14 -0
- package/vendor/@akanjs/native/plugins/app/native-plugin.json +2 -2
- package/vendor/@akanjs/native/plugins/app/src/desktop.ts +5 -0
- package/vendor/@akanjs/native/plugins/app/src/index.ts +6 -1
- package/vendor/@akanjs/native/plugins/app/src/web.ts +3 -0
- package/vendor/@akanjs/native/plugins/file-picker/src/desktop.ts +39 -2
- package/vendor/@akanjs/native/plugins/file-picker/src/index.ts +36 -1
- package/vendor/@akanjs/native/plugins/push/android/PushPlugin.kt +9 -1
- package/vendor/@akanjs/native/plugins/push/ios/PushPlugin.swift +4 -0
- package/vendor/@akanjs/native/plugins/push/src/index.ts +10 -0
- package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +464 -452
- package/vendor/@akanjs/native/plugins/volume/android/VolumePlugin.kt +107 -0
- package/vendor/@akanjs/native/plugins/volume/native-plugin.json +14 -0
- package/vendor/@akanjs/native/plugins/volume/src/common.ts +28 -0
- package/vendor/@akanjs/native/plugins/volume/src/desktop.ts +185 -0
- package/vendor/@akanjs/native/plugins/volume/src/index.ts +32 -0
- package/webkit/CsrRouteTable.ts +15 -35
- package/webkit/RenderLayer.tsx +71 -6
- package/webkit/bootCsr.tsx +11 -8
- package/webkit/csrFrameDump.ts +67 -0
- package/webkit/nativeNavigation.ts +17 -0
- package/webkit/nativePurchase.ts +12 -2
- package/webkit/nativeUpdates.ts +55 -0
- package/webkit/useCsrValues.ts +27 -0
|
@@ -3,5 +3,10 @@ import type { Launched, LaunchOptions } from "../lib/launch.ts";
|
|
|
3
3
|
import type { BuildContext } from "../lib/prepare.ts";
|
|
4
4
|
export declare const MACOS_MIN = "26.0";
|
|
5
5
|
export declare function buildMacos(ctx: BuildContext): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Mach-O files the app carries in its server and its `bin`, whatever their names (native addons, executables, a
|
|
8
|
+
* package's own executable): nested code the bundle's signature does not sign.
|
|
9
|
+
*/
|
|
10
|
+
export declare function carriedNativeCode(resources: string): string[];
|
|
6
11
|
export declare function launchMacos(ctx: BuildContext, appPath: string, opts: LaunchOptions): Promise<Launched>;
|
|
7
12
|
export declare function runMacos(ctx: BuildContext, appPath: string, args: ParsedArgs): Promise<number>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BuildContext } from "../lib/prepare.ts";
|
|
2
|
+
/** Microsoft's permanent link to the Evergreen Bootstrapper (MicrosoftEdgeWebview2Setup.exe). */
|
|
3
|
+
export declare const WEBVIEW2_BOOTSTRAPPER_URL = "https://go.microsoft.com/fwlink/p/?LinkId=2124703";
|
|
4
|
+
/** MAX_PATH less its NUL: what a PC without long paths enabled (the Windows default) can open or unpack. */
|
|
5
|
+
export declare const WINDOWS_MAX_PATH = 259;
|
|
6
|
+
export interface InstallerInput {
|
|
7
|
+
name: string;
|
|
8
|
+
id: string;
|
|
9
|
+
exe: string;
|
|
10
|
+
version: string;
|
|
11
|
+
build: number;
|
|
12
|
+
/** The built app folder, copied whole. */
|
|
13
|
+
folder: string;
|
|
14
|
+
/** Its top-level files and folders: what an update or uninstall removes. */
|
|
15
|
+
entries: {
|
|
16
|
+
name: string;
|
|
17
|
+
dir: boolean;
|
|
18
|
+
}[];
|
|
19
|
+
icon?: string;
|
|
20
|
+
bootstrapper: string;
|
|
21
|
+
stopScript: string;
|
|
22
|
+
outFile: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function installerScript(input: InstallerInput): string;
|
|
25
|
+
/**
|
|
26
|
+
* Stops every process running from the install folder, and waits (up to 10 s) until they are gone. Through
|
|
27
|
+
* WMI: the installer is a 32-bit program, so its PowerShell is too, and a 32-bit process cannot read a
|
|
28
|
+
* 64-bit one's path (Get-Process's Path comes back empty).
|
|
29
|
+
*/
|
|
30
|
+
export declare const STOP_SCRIPT = "param([string]$Dir)\n$prefix = [IO.Path]::GetFullPath($Dir).TrimEnd('\\') + '\\'\n$running = { Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase) } }\n& $running | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }\nfor ($i = 0; $i -lt 50 -and (& $running); $i++) { Start-Sleep -Milliseconds 200 }\n";
|
|
31
|
+
/** The longest path under `folder`, relative and with Windows separators. Links are not followed. */
|
|
32
|
+
export declare function deepestPath(folder: string): string;
|
|
33
|
+
/** How long `relative` gets on a typical PC while an update unpacks, the longest it ever is: root, app, staging, app. */
|
|
34
|
+
export declare function installedPathLength(appName: string, relative: string): number;
|
|
35
|
+
/** makensis: AKAN_NATIVE_MAKENSIS, PATH, then where the NSIS installer puts it. */
|
|
36
|
+
export declare function findMakensis(env?: Record<string, string | undefined>): string | null;
|
|
37
|
+
/** Writes the setup program next to the app folder and answers its path. */
|
|
38
|
+
export declare function buildWindowsInstaller(ctx: BuildContext, folder: string): Promise<string>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AppInfo, FileRef, ResolvedAcl } from "../../core/src/index.ts";
|
|
2
2
|
import { type BridgeEvent, type BridgeRequest, type BridgeResponse } from "../../core/src/protocol.ts";
|
|
3
3
|
import type { Lifecycle } from "./lifecycle.ts";
|
|
4
|
-
import type { DesktopPlugin, Launch, NativeEvent } from "./plugin.ts";
|
|
4
|
+
import type { DesktopPlugin, DesktopServerStatus, Launch, NativeEvent } from "./plugin.ts";
|
|
5
5
|
/** How long the window waits for one plugin's setup. */
|
|
6
6
|
export declare const SETUP_TIMEOUT_MS = 3000;
|
|
7
7
|
/**
|
|
@@ -11,7 +11,14 @@ export declare const SETUP_TIMEOUT_MS = 3000;
|
|
|
11
11
|
export declare const SETUP_WAIT_MS = 5000;
|
|
12
12
|
export interface HostServices {
|
|
13
13
|
app: AppInfo;
|
|
14
|
+
dev?: boolean;
|
|
14
15
|
appDataDir: string;
|
|
16
|
+
/** paths.ts appLocalDataDir; appDataDir when not given. */
|
|
17
|
+
appLocalDataDir?: string;
|
|
18
|
+
/** desktop.bin in the app's resources, or null. */
|
|
19
|
+
binDir?: string | null;
|
|
20
|
+
/** The carried server (resources/server.json), or null. */
|
|
21
|
+
server?: DesktopServerStatus | null;
|
|
15
22
|
/** Sends an event (numbered for its document) to a window's page. */
|
|
16
23
|
emit(window: number, message: BridgeEvent): void;
|
|
17
24
|
/**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type GrantMode = "read" | "write" | "folder";
|
|
2
|
+
export interface FileGrant {
|
|
3
|
+
path: string;
|
|
4
|
+
mode: GrantMode;
|
|
5
|
+
}
|
|
6
|
+
export declare function devGrantKeyFile(home?: string): string;
|
|
7
|
+
export declare function grantFile(path: string, mode: GrantMode, { dev }?: {
|
|
8
|
+
dev?: boolean;
|
|
9
|
+
}): string;
|
|
10
|
+
export declare function resolveGrant(id: unknown): FileGrant | null;
|
|
11
|
+
export declare function devGrantKey(file?: string): Buffer;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { LaunchWindow } from "./plugin.ts";
|
|
2
|
+
/**
|
|
3
|
+
* env.runtime.json, overlaid with what the launch phase learned (the carried server's URL), then with
|
|
4
|
+
* AKAN_NATIVE_PUBLIC_* process variables (ENV-1, highest precedence).
|
|
5
|
+
*/
|
|
6
|
+
export declare function runtimeEnv(file: Record<string, string>, launched?: Record<string, string>, processEnv?: Record<string, string | undefined>): Record<string, string>;
|
|
2
7
|
/** The launch phase's window bounds that akan_native_run understands (x and y only together). */
|
|
3
8
|
export declare function launchBounds(window: LaunchWindow): LaunchWindow;
|
|
9
|
+
/**
|
|
10
|
+
* Windows renames no folder that is some process's working folder: an app started from its install folder (the
|
|
11
|
+
* installer, a shortcut, Explorer) would hand it to the webview's processes, and an update could never swap it
|
|
12
|
+
* (plugins/updates). Called after the launch phase, where single-instance forwards a second launch's folder.
|
|
13
|
+
*/
|
|
14
|
+
export declare function leaveInstallFolder(appId: string, platform?: NodeJS.Platform): void;
|
|
4
15
|
export declare function startMain(workerUrl: string): Promise<never>;
|
|
@@ -6,16 +6,27 @@ type Env = Record<string, string | undefined>;
|
|
|
6
6
|
* Linux $XDG_DATA_HOME/<id> (~/.local/share/<id>)
|
|
7
7
|
*/
|
|
8
8
|
export declare function appDataDir(id: string, platform?: NodeJS.Platform, env?: Env, home?: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* What is large and belongs to this PC: the webview's storage, the carried server's databases and logs.
|
|
11
|
+
* Windows %LOCALAPPDATA%\<id> (never Roaming, which follows the user and may be a network share)
|
|
12
|
+
* macOS, Linux appDataDir
|
|
13
|
+
*/
|
|
14
|
+
export declare function appLocalDataDir(id: string, platform?: NodeJS.Platform, env?: Env, home?: string): string;
|
|
9
15
|
/**
|
|
10
16
|
* The webview's own storage and caches (Windows, Linux; WKWebView chooses its own on macOS):
|
|
11
|
-
* Windows %LOCALAPPDATA%\<id>\WebView2
|
|
17
|
+
* Windows %LOCALAPPDATA%\<id>\WebView2
|
|
12
18
|
* Linux $XDG_DATA_HOME/<id>/webview
|
|
13
19
|
* WebView2's default would be next to the .exe, which is not writable once installed.
|
|
14
20
|
*/
|
|
15
21
|
export declare function webviewDataDir(id: string, platform?: NodeJS.Platform, env?: Env, home?: string): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The carried server's folder (server.ts): <app local data>/server. A debug build has the release app's id, so
|
|
24
|
+
* its server keeps its own folder and never opens the databases of the release app on the same PC.
|
|
25
|
+
*/
|
|
26
|
+
export declare function serverDataDir(id: string, dev: boolean, platform?: NodeJS.Platform, env?: Env, home?: string): string;
|
|
16
27
|
/**
|
|
17
28
|
* Folders whose files no FileRef may serve (L4): the shell's and the plugins' own storage
|
|
18
|
-
* (preferences, secure storage, databases, update bundles, window state, the webview's data). Only
|
|
29
|
+
* (preferences, secure storage, databases, update bundles, window state, the webview's data, the server's). Only
|
|
19
30
|
* the filesystem plugin's `data` base (<app data>/files) is servable inside the app data folder.
|
|
20
31
|
*/
|
|
21
32
|
export declare function reservedDirs(id: string, platform?: NodeJS.Platform, env?: Env, home?: string): {
|
|
@@ -12,6 +12,8 @@ export type EmitTarget = {
|
|
|
12
12
|
} | "focused";
|
|
13
13
|
export interface DesktopContext {
|
|
14
14
|
app: AppInfo;
|
|
15
|
+
/** A dev build (boot.json `dev`): its pages come from a dev server the shell did not start. */
|
|
16
|
+
readonly dev: boolean;
|
|
15
17
|
/**
|
|
16
18
|
* The window whose page made this call (SH-6; 1 = the window the app opened). Only in method
|
|
17
19
|
* calls; undefined in setup and event sources.
|
|
@@ -36,6 +38,22 @@ export interface DesktopContext {
|
|
|
36
38
|
readonly document?: DocumentScope;
|
|
37
39
|
/** Per-app data folder, e.g. ~/Library/Application Support/<app id>. Created on first access. */
|
|
38
40
|
readonly appDataDir: string;
|
|
41
|
+
/**
|
|
42
|
+
* For what is large and belongs to this PC (caches, downloads, databases): %LOCALAPPDATA%\<app id> on Windows,
|
|
43
|
+
* where appDataDir roams with the user; appDataDir on macOS and Linux. Created on first access.
|
|
44
|
+
*/
|
|
45
|
+
readonly appLocalDataDir: string;
|
|
46
|
+
/**
|
|
47
|
+
* The executables the app carries (desktop.bin, akanjs `bin`), or null. The host puts the folder first on
|
|
48
|
+
* process.env.PATH, which node:child_process and `Bun.spawn(cmd, { env: process.env })` use; a Bun.spawn or
|
|
49
|
+
* Bun.which without `env` reads the environment the app started with, so name a file here or pass the env.
|
|
50
|
+
*/
|
|
51
|
+
readonly binDir: string | null;
|
|
52
|
+
/**
|
|
53
|
+
* The server the app carries (desktop.server), or null. `ready` settles once per session: true when the server
|
|
54
|
+
* first answered ready, false when it could not start or gave up before that.
|
|
55
|
+
*/
|
|
56
|
+
readonly server: DesktopServerStatus | null;
|
|
39
57
|
/** Pushes an event of this plugin to the pages that listen. Returns the windows reached. */
|
|
40
58
|
emit(event: string, data?: unknown, target?: EmitTarget): number[];
|
|
41
59
|
/** Serves a local file at /__akan_native/file/<id> for the rest of the session (PL-7). */
|
|
@@ -100,6 +118,9 @@ export interface DesktopContext {
|
|
|
100
118
|
exit(code?: number): void;
|
|
101
119
|
};
|
|
102
120
|
}
|
|
121
|
+
export interface DesktopServerStatus {
|
|
122
|
+
readonly ready: Promise<boolean>;
|
|
123
|
+
}
|
|
103
124
|
/** Which page load ended. `id` is "" for a page that sends no document id (v1 callers, tests). */
|
|
104
125
|
export interface DocumentInfo {
|
|
105
126
|
window: number;
|
|
@@ -126,11 +147,17 @@ export interface LaunchWindow {
|
|
|
126
147
|
width?: number;
|
|
127
148
|
height?: number;
|
|
128
149
|
maximized?: boolean;
|
|
150
|
+
/** Borderless fullscreen from the first frame, on the display x and y are on (else the primary one). */
|
|
151
|
+
fullscreen?: boolean;
|
|
152
|
+
/** No taskbar button (Windows, Linux; macOS has none). */
|
|
153
|
+
skipTaskbar?: boolean;
|
|
129
154
|
}
|
|
130
155
|
/** What the launch phase decided; sent to the main thread with "ready". */
|
|
131
156
|
export interface Launch {
|
|
132
157
|
window: LaunchWindow;
|
|
133
158
|
exit?: number;
|
|
159
|
+
/** PUBLIC_* values for the page known only at launch (the carried server's URL), under AKAN_NATIVE_PUBLIC_*. */
|
|
160
|
+
env?: Record<string, string>;
|
|
134
161
|
}
|
|
135
162
|
export interface NativeEvent {
|
|
136
163
|
type: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface RelaunchOptions {
|
|
2
|
+
/** How long the helper waits after this process exited before it starts the app. */
|
|
3
|
+
delayMs?: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Once this process has exited: renames `moves` in order and starts `exe` with this environment. macOS and
|
|
7
|
+
* Linux rename a running app's folder right away, so only the start waits; Windows refuses that, so a helper
|
|
8
|
+
* does the renames too (and on a failed rename puts back what it moved, so there is always an app to start).
|
|
9
|
+
* Only the first call of a process starts a helper; later ones answer the same promise.
|
|
10
|
+
*/
|
|
11
|
+
export declare function relaunchAfterExit(exe: string, moves?: [string, string][], { delayMs }?: RelaunchOptions): Promise<void>;
|
|
12
|
+
/** Relaunches after the browser process ended, in a row: each one's app ran less than RELAUNCH_HEALTHY. */
|
|
13
|
+
export declare const RELAUNCH_LIMIT = 10;
|
|
14
|
+
export declare const RELAUNCH_HEALTHY = 60000;
|
|
15
|
+
/**
|
|
16
|
+
* desktop.recovery "reload" after the webview's browser process ended: how long the relaunched app waits, or null
|
|
17
|
+
* once RELAUNCH_LIMIT relaunches in a row did not help. The first relaunch is immediate, then 1 s doubling to a
|
|
18
|
+
* minute (lib.rs recovery_wait); an app that ran for RELAUNCH_HEALTHY starts the count again. `file` keeps the
|
|
19
|
+
* count across the processes.
|
|
20
|
+
*/
|
|
21
|
+
export declare function nextRelaunchDelay(file: string, now?: number): number | null;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export interface ServerManifest {
|
|
2
|
+
/** The file in resources/server that starts the server. */
|
|
3
|
+
entry: string;
|
|
4
|
+
env: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
/** Set by the launcher at every start, so desktop.server.env may not name them (cli lib/desktop-server.ts). */
|
|
7
|
+
export declare const LAUNCHER_ENV_KEYS: readonly ["BUN_BE_BUN", "BUN_RUNTIME_TRANSPILER_CACHE_PATH", "PORT", "JWT_SECRET", "AKAN_LISTEN_HOST", "AKAN_ALLOWED_HOSTS", "AKAN_SQLITE_DIR", "AKAN_WORKSPACE_ROOT", "AKAN_RUNTIME_DIR"];
|
|
8
|
+
/** How long the window waits for the server; after that it opens and the first calls may fail. */
|
|
9
|
+
export declare const READY_TIMEOUT = 8000;
|
|
10
|
+
/** Within the onQuit budget (lifecycle.ts QUIT_HOOK_TIMEOUT, 2 s). */
|
|
11
|
+
export declare const STOP_GRACE = 1500;
|
|
12
|
+
export declare const MAX_FAILURES = 5;
|
|
13
|
+
/** Between restarts of a server that has not been ready yet: MAX_FAILURES of them end well within READY_TIMEOUT. */
|
|
14
|
+
export declare const BOOT_RESTART_DELAY = 250;
|
|
15
|
+
/** A run that stayed up this long was healthy: its crash starts the count again. */
|
|
16
|
+
export declare const HEALTHY_RUN = 60000;
|
|
17
|
+
export interface ServerProcess {
|
|
18
|
+
readonly exited: Promise<number | null>;
|
|
19
|
+
send(message: unknown): void;
|
|
20
|
+
kill(signal?: NodeJS.Signals): void;
|
|
21
|
+
/** Signals what is left of the server's process group (macOS, Linux). */
|
|
22
|
+
killGroup?(signal: NodeJS.Signals): void;
|
|
23
|
+
}
|
|
24
|
+
export interface SpawnOptions {
|
|
25
|
+
cwd: string;
|
|
26
|
+
env: Record<string, string>;
|
|
27
|
+
onMessage(message: unknown): void;
|
|
28
|
+
onLine(line: string, stream: "stdout" | "stderr"): void;
|
|
29
|
+
}
|
|
30
|
+
export interface DesktopServerOptions {
|
|
31
|
+
resources: string;
|
|
32
|
+
/** Where the server keeps everything: its working folder, databases, logs, secret (paths.ts serverDataDir). */
|
|
33
|
+
dataDir: string;
|
|
34
|
+
manifest: ServerManifest;
|
|
35
|
+
/** The app's executables (resources/bin), first on the server's PATH. */
|
|
36
|
+
binDir?: string | null;
|
|
37
|
+
execPath?: string;
|
|
38
|
+
env?: Record<string, string | undefined>;
|
|
39
|
+
spawn?(argv: string[], options: SpawnOptions): ServerProcess;
|
|
40
|
+
/** A free loopback port: `preferred` when it is free. */
|
|
41
|
+
freePort?(preferred?: number): Promise<number>;
|
|
42
|
+
/** The server gave up: MAX_FAILURES crashes in a row, or it could not start at all. */
|
|
43
|
+
onGiveUp?(message: string): void;
|
|
44
|
+
readyTimeout?: number;
|
|
45
|
+
stopGrace?: number;
|
|
46
|
+
restartDelay?(failures: number, everReady: boolean): number;
|
|
47
|
+
now?(): number;
|
|
48
|
+
}
|
|
49
|
+
export interface DesktopServer {
|
|
50
|
+
/**
|
|
51
|
+
* The server's URL, once it is ready or readyTimeout passed (it keeps starting then), or at once when it gave up.
|
|
52
|
+
* Never throws: a server that cannot start still has a loopback URL, so the page's calls fail on this PC.
|
|
53
|
+
*/
|
|
54
|
+
start(): Promise<{
|
|
55
|
+
url: string;
|
|
56
|
+
ready: boolean;
|
|
57
|
+
}>;
|
|
58
|
+
/** Settles once: true at the first ready, false when the server gave up or stopped before that. */
|
|
59
|
+
readonly ready: Promise<boolean>;
|
|
60
|
+
stop(): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
export declare function readServerManifest(resources: string): ServerManifest | null;
|
|
63
|
+
export declare function serverArgv(execPath: string, resources: string, entry: string): string[];
|
|
64
|
+
/** `dir` first on a PATH, once: a relaunched app inherits the PATH its predecessor already extended. */
|
|
65
|
+
export declare function pathWithFirst(dir: string, path: string | undefined, platform?: NodeJS.Platform): string;
|
|
66
|
+
export declare function serverEnv(manifest: ServerManifest, { port, secret, dataDir, env, binDir, platform, }: {
|
|
67
|
+
port: number;
|
|
68
|
+
secret: string;
|
|
69
|
+
dataDir: string;
|
|
70
|
+
env: Record<string, string | undefined>;
|
|
71
|
+
binDir?: string | null;
|
|
72
|
+
platform?: NodeJS.Platform;
|
|
73
|
+
}): Record<string, string>;
|
|
74
|
+
/** One random secret per installation, readable by its owner only: outside operationMode local akanjs derives none. */
|
|
75
|
+
export declare function jwtSecret(dataDir: string): string;
|
|
76
|
+
export declare function restartDelay(failures: number, everReady?: boolean): number;
|
|
77
|
+
/** The port the last session's server was ready on (`<server data>/port`), if any. */
|
|
78
|
+
export declare function lastPort(dataDir: string): number | undefined;
|
|
79
|
+
export declare function createDesktopServer(options: DesktopServerOptions): DesktopServer;
|
|
@@ -18,6 +18,11 @@ export interface AppApi {
|
|
|
18
18
|
}>;
|
|
19
19
|
/** Ends the app without asking onBeforeQuit handlers. Android and desktop only (iOS apps must not quit themselves). */
|
|
20
20
|
exit(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Ends the app and starts it again in a new process, without asking onBeforeQuit handlers: after a setting
|
|
23
|
+
* that takes a restart, or to recover an app nobody attends. The web reloads the page; iOS answers UNSUPPORTED.
|
|
24
|
+
*/
|
|
25
|
+
relaunch(): Promise<void>;
|
|
21
26
|
/** Sends the app to the background (Android) or minimizes its window (desktop). */
|
|
22
27
|
minimize(): Promise<void>;
|
|
23
28
|
/** Internal: the page's answer to a beforeQuit event. Use onBeforeQuit(). */
|
|
@@ -3,6 +3,8 @@ import { AkanNativeError, type FileRef, type Plugin } from "../../../packages/co
|
|
|
3
3
|
export interface PickedFile extends FileRef {
|
|
4
4
|
/** The file's name as the user saw it, e.g. "Invoice.pdf". Never a path. */
|
|
5
5
|
name: string;
|
|
6
|
+
/** With forServer: what the app's server exchanges for the file's path (akanjs `NativeFile`). */
|
|
7
|
+
grant?: string;
|
|
6
8
|
}
|
|
7
9
|
export interface DirectoryFile extends PickedFile {
|
|
8
10
|
/** Relative to the picked folder, "/"-separated, e.g. "2026/March/receipt.pdf". */
|
|
@@ -17,6 +19,11 @@ export interface PickFilesOptions {
|
|
|
17
19
|
types?: string[];
|
|
18
20
|
/** Let the user pick more than one file. Default false. */
|
|
19
21
|
multiple?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Desktop only: hand the files to the app's server instead of copying them. The FileRefs serve the
|
|
24
|
+
* originals and each result carries a `grant`; nothing is copied, whatever the file's size.
|
|
25
|
+
*/
|
|
26
|
+
forServer?: boolean;
|
|
20
27
|
}
|
|
21
28
|
export interface SaveFileOptions {
|
|
22
29
|
/** Suggested file name; the user can change it (the result says what was chosen, where known). */
|
|
@@ -29,16 +36,25 @@ export interface SaveFileOptions {
|
|
|
29
36
|
url?: string;
|
|
30
37
|
/** MIME type of the content (Android files the document under it). Default: from the name's extension. */
|
|
31
38
|
mime?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Desktop only: ask where to save and write nothing. The result's `grant` lets the app's server write
|
|
41
|
+
* the file there; data and url are refused.
|
|
42
|
+
*/
|
|
43
|
+
forServer?: boolean;
|
|
32
44
|
}
|
|
33
45
|
export interface SaveFileResult {
|
|
34
46
|
/** False when the user closed the dialog. On the web without showSaveFilePicker this is true once the download started. */
|
|
35
47
|
saved: boolean;
|
|
36
48
|
/** The name the file was saved under, when the platform tells (it may differ from the suggestion). */
|
|
37
49
|
name?: string;
|
|
50
|
+
/** With forServer: what the app's server exchanges for the path to write. */
|
|
51
|
+
grant?: string;
|
|
38
52
|
}
|
|
39
53
|
export interface PickDirectoryOptions {
|
|
40
54
|
/** Most files to return (1–10000, default 1000); `truncated` tells whether there were more. */
|
|
41
55
|
limit?: number;
|
|
56
|
+
/** Desktop only: grant the folder to the app's server and copy nothing (FileRefs serve the originals). */
|
|
57
|
+
forServer?: boolean;
|
|
42
58
|
}
|
|
43
59
|
export interface PickDirectoryResult {
|
|
44
60
|
/** The folder's name; null when the user closed the dialog. */
|
|
@@ -46,6 +62,8 @@ export interface PickDirectoryResult {
|
|
|
46
62
|
/** Every file inside, recursively, as copies; hidden files and folders (".*") are left out. */
|
|
47
63
|
files: DirectoryFile[];
|
|
48
64
|
truncated: boolean;
|
|
65
|
+
/** With forServer: what the app's server exchanges for the folder's path. */
|
|
66
|
+
grant?: string;
|
|
49
67
|
}
|
|
50
68
|
/**
|
|
51
69
|
* System file dialogs.
|
|
@@ -54,7 +72,8 @@ export interface PickDirectoryResult {
|
|
|
54
72
|
* - saveFile: the export picker (iOS), ACTION_CREATE_DOCUMENT (Android), an NSSavePanel sheet
|
|
55
73
|
* (macOS), showSaveFilePicker or a download (web).
|
|
56
74
|
* - pickDirectory: a read-only snapshot of a folder the user picks: its files, copied like pickFiles.
|
|
57
|
-
* Results are copies registered as FileRefs; no absolute path reaches the page.
|
|
75
|
+
* Results are copies registered as FileRefs; no absolute path reaches the page. forServer (desktop)
|
|
76
|
+
* copies nothing and grants the originals to the app's server instead. Closing a dialog
|
|
58
77
|
* resolves (`files: []`, `saved: false`, `name: null`); a second dialog while one is open rejects
|
|
59
78
|
* CANCELLED. On the web call these from a click handler, before any await (user activation).
|
|
60
79
|
*/
|
|
@@ -26,6 +26,15 @@ export interface PushPresentation {
|
|
|
26
26
|
list?: boolean;
|
|
27
27
|
sound?: boolean;
|
|
28
28
|
badge?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Not shown when its `data[key]` is one of `values`, e.g. the chat room on screen: `{ key: "url", values: [path] }`.
|
|
31
|
+
* It still arrives as "received".
|
|
32
|
+
*/
|
|
33
|
+
except?: PushPresentationExcept;
|
|
34
|
+
}
|
|
35
|
+
export interface PushPresentationExcept {
|
|
36
|
+
key: string;
|
|
37
|
+
values: string[];
|
|
29
38
|
}
|
|
30
39
|
export interface PushApi {
|
|
31
40
|
checkPermission(): Promise<{
|
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
import { type DesktopPlugin } from "../../../packages/desktop/src/plugin.ts";
|
|
2
2
|
import type { UpdatesApi, UpdatesEvents } from "./index.ts";
|
|
3
|
+
export interface UpdatesConfig {
|
|
4
|
+
app: string;
|
|
5
|
+
platform: string;
|
|
6
|
+
nativeApi: string | null;
|
|
7
|
+
embeddedSequence: number;
|
|
8
|
+
url: string;
|
|
9
|
+
publicKey: string;
|
|
10
|
+
channel: string;
|
|
11
|
+
readyTimeout: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* How long a new release's carried server may take to answer ready before its trial clock starts anyway: a first
|
|
15
|
+
* run scans every file with a cold transpiler cache and migrates the databases, on a PC that may be slow. The
|
|
16
|
+
* launcher's own wait (READY_TIMEOUT, 8 s) only decides when the window opens.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SERVER_BOOT_ALLOWANCE = 120000;
|
|
19
|
+
export interface DesktopUpdatesOptions {
|
|
20
|
+
platform?: NodeJS.Platform;
|
|
21
|
+
/** The installed app; the running one by default. */
|
|
22
|
+
app?: string | null;
|
|
23
|
+
/** Its updates.json; read from `app` by default. */
|
|
24
|
+
config?: UpdatesConfig | null;
|
|
25
|
+
/** The executable's file name inside an app; the running one's by default. */
|
|
26
|
+
exeName?: string;
|
|
27
|
+
relaunch?(exe: string, moves: [string, string][]): Promise<void>;
|
|
28
|
+
serverBootAllowance?: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function createDesktopUpdates(options?: DesktopUpdatesOptions): DesktopPlugin<UpdatesApi, UpdatesEvents>;
|
|
3
31
|
declare const _default: DesktopPlugin<UpdatesApi, UpdatesEvents>;
|
|
4
32
|
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { VolumeState } from "./index.ts";
|
|
2
|
+
export declare function checkLevel(value: unknown): number;
|
|
3
|
+
export declare function checkMuted(value: unknown): boolean;
|
|
4
|
+
export declare const sameVolume: (a: VolumeState, b: VolumeState) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* `pactl get-sink-volume @DEFAULT_SINK@` ("Volume: front-left: 32768 / 50% / -18.06 dB, front-right: …"):
|
|
7
|
+
* the channels' mean. PulseAudio can boost past 100%, which reads as 1.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pactlLevel(output: string): number | null;
|
|
10
|
+
export declare const pactlMuted: (output: string) => boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { VolumeApi, VolumeEvents } from "./index.ts";
|
|
2
|
+
/** Runs pactl and answers its stdout. */
|
|
3
|
+
export type Pactl = (...args: string[]) => Promise<string>;
|
|
4
|
+
/** Answers stdout lines of `pactl subscribe` until the returned function stops it. */
|
|
5
|
+
export type PactlSubscribe = (onLine: (line: string) => void) => () => void;
|
|
6
|
+
export declare const resubscribeDelay: (ends: number) => number;
|
|
7
|
+
export declare const runPactl: Pactl;
|
|
8
|
+
/** One `pactl subscribe`: its lines until it ends; `stop` ends it. */
|
|
9
|
+
export type PactlSubscription = (onLine: (line: string) => void) => {
|
|
10
|
+
ended: Promise<void>;
|
|
11
|
+
stop(): void;
|
|
12
|
+
} | null;
|
|
13
|
+
/** `pactl subscribe`, started again (resubscribeDelay) whenever it ends until stopped: a restarted audio server ends it. */
|
|
14
|
+
export declare function resubscribing(subscription?: PactlSubscription, delay?: (ends: number) => number): PactlSubscribe;
|
|
15
|
+
export declare const subscribePactl: PactlSubscribe;
|
|
16
|
+
export declare function createDesktopVolume(platform?: NodeJS.Platform, pactl?: Pactl, subscribe?: PactlSubscribe): import("../../../packages/desktop/src/plugin.ts").DesktopPlugin<VolumeApi, VolumeEvents>;
|
|
17
|
+
declare const _default: import("../../../packages/desktop/src/plugin.ts").DesktopPlugin<VolumeApi, VolumeEvents>;
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** The default output's volume, as the system's own volume control shows it. */
|
|
2
|
+
export interface VolumeState {
|
|
3
|
+
/** 0 (silent) to 1 (full); null when the output takes no volume from the computer (HDMI audio on macOS). */
|
|
4
|
+
level: number | null;
|
|
5
|
+
muted: boolean;
|
|
6
|
+
/** False when setVolume is refused for this output. */
|
|
7
|
+
settable: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface VolumeApi {
|
|
10
|
+
getVolume(): Promise<VolumeState>;
|
|
11
|
+
/** `level` from 0 to 1. */
|
|
12
|
+
setVolume(args: {
|
|
13
|
+
level: number;
|
|
14
|
+
}): Promise<VolumeState>;
|
|
15
|
+
setMuted(args: {
|
|
16
|
+
muted: boolean;
|
|
17
|
+
}): Promise<VolumeState>;
|
|
18
|
+
}
|
|
19
|
+
export interface VolumeEvents {
|
|
20
|
+
/** The default output, its volume or its mute changed, whoever changed it. */
|
|
21
|
+
change: VolumeState;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The system's output volume: CoreAudio's default output device (macOS), the default render endpoint the taskbar
|
|
25
|
+
* slider moves (Windows), the default sink of PulseAudio or PipeWire through pactl (Linux), and on Android the
|
|
26
|
+
* media volume the volume keys move while the app plays. iOS and the web answer UNSUPPORTED.
|
|
27
|
+
*/
|
|
28
|
+
export declare const volume: import("../../../packages/core/src/plugin.ts").Plugin<VolumeApi, VolumeEvents>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/index.d.ts";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
interface LayerRecord {
|
|
2
|
+
layer: string;
|
|
3
|
+
status: "pending" | "settled" | "failed";
|
|
4
|
+
startedAt: number;
|
|
5
|
+
settledAt: number | null;
|
|
6
|
+
/** A mounted layer is waiting on this render's promise; false once it unmounts or its Activity hides. */
|
|
7
|
+
subscribed: boolean;
|
|
8
|
+
/** The layer has drawn this render's value. */
|
|
9
|
+
delivered: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface FrameState {
|
|
12
|
+
phase: string;
|
|
13
|
+
location: string;
|
|
14
|
+
prevLocation: string | null;
|
|
15
|
+
pendingLocation: string | null;
|
|
16
|
+
stack: {
|
|
17
|
+
key: string;
|
|
18
|
+
path: string;
|
|
19
|
+
pageType: string;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
export declare class CsrFrameDump {
|
|
23
|
+
#private;
|
|
24
|
+
static readonly limit = 300;
|
|
25
|
+
static track(layer: string, result: Promise<unknown>): LayerRecord;
|
|
26
|
+
static watchFrame(read: () => FrameState): void;
|
|
27
|
+
static dump(): {
|
|
28
|
+
now: number;
|
|
29
|
+
frame: FrameState | null;
|
|
30
|
+
layers: {
|
|
31
|
+
layer: string;
|
|
32
|
+
status: "pending" | "settled" | "failed";
|
|
33
|
+
startedAt: number;
|
|
34
|
+
settledAt: number | null;
|
|
35
|
+
/** A mounted layer is waiting on this render's promise; false once it unmounts or its Activity hides. */
|
|
36
|
+
subscribed: boolean;
|
|
37
|
+
/** The layer has drawn this render's value. */
|
|
38
|
+
delivered: boolean;
|
|
39
|
+
}[];
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export {};
|
|
@@ -24,6 +24,7 @@ export declare class NativeNavigation {
|
|
|
24
24
|
#private;
|
|
25
25
|
readonly options: NativeNavigationOptions;
|
|
26
26
|
constructor(options: NativeNavigationOptions);
|
|
27
|
+
showPushesExcept(pathname: string): void;
|
|
27
28
|
listen(): () => void;
|
|
28
29
|
/**
|
|
29
30
|
* Tells an Android shell whether back is the page's right now: the keyboard is up, there is history, or the
|
|
@@ -12,10 +12,14 @@ export interface BillingVerification {
|
|
|
12
12
|
transactionId: string;
|
|
13
13
|
}
|
|
14
14
|
export type PurchaseCallback = (transaction: IapTransaction, verified: unknown) => void | Promise<void>;
|
|
15
|
+
/** The app's own check; the store's raw proof is also on `transaction.verification`. */
|
|
16
|
+
export type BillingVerifier = (data: BillingVerification, transaction: IapTransaction) => Promise<unknown>;
|
|
15
17
|
export interface NativePurchaseOptions {
|
|
16
18
|
productInfo: PurchaseProductInfo[];
|
|
17
|
-
/** The verification server's origin; it answers `POST <url>/billing/verifyBilling`. */
|
|
18
|
-
url
|
|
19
|
+
/** The verification server's origin; it answers `POST <url>/billing/verifyBilling`. Unused with `verify`. */
|
|
20
|
+
url?: string;
|
|
21
|
+
/** Verifies instead of the POST: what it resolves reaches onPay/onSubscribe, and `null`, `undefined` or `false` refuses. */
|
|
22
|
+
verify?: BillingVerifier;
|
|
19
23
|
onPay?: PurchaseCallback;
|
|
20
24
|
onSubscribe?: PurchaseCallback;
|
|
21
25
|
}
|
package/ui/Agent/Attach.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn } from "akanjs/client";
|
|
2
|
+
import { cn, resolveServerUrl } from "akanjs/client";
|
|
3
3
|
import { useRef } from "react";
|
|
4
4
|
import { AiOutlineClose, AiOutlinePaperClip } from "react-icons/ai";
|
|
5
5
|
import type { MessageAttachment } from "../../vendor/use-agentic";
|
|
@@ -61,7 +61,11 @@ export const Chips = ({ className, attachments, onRemove, removeLabel, pending =
|
|
|
61
61
|
<img
|
|
62
62
|
alt={attachment.name}
|
|
63
63
|
className="size-6 rounded-field object-cover"
|
|
64
|
-
src={
|
|
64
|
+
src={
|
|
65
|
+
attachment.data
|
|
66
|
+
? `data:${attachment.mimeType};base64,${attachment.data}`
|
|
67
|
+
: resolveServerUrl(attachment.url ?? "")
|
|
68
|
+
}
|
|
65
69
|
/>
|
|
66
70
|
) : null}
|
|
67
71
|
<span className="max-w-32 truncate">{attachment.name}</span>
|
package/ui/CsrImage.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cn } from "akanjs/client";
|
|
2
|
+
import { cn, resolveServerUrl } from "akanjs/client";
|
|
3
3
|
import type { ProtoLightFile } from "akanjs/constant";
|
|
4
4
|
import type { ImgHTMLAttributes } from "react";
|
|
5
5
|
|
|
@@ -18,7 +18,8 @@ type CsrImageProps = Omit<ImgHTMLAttributes<HTMLImageElement>, "alt" | "src"> &
|
|
|
18
18
|
const EMPTY_IMAGE = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
19
19
|
|
|
20
20
|
export const CsrImage = ({ src, alt, file, className, abstractData, ...props }: CsrImageProps) => {
|
|
21
|
-
const
|
|
21
|
+
const stored = src || file?.url || null;
|
|
22
|
+
const url = stored ? resolveServerUrl(stored) : null;
|
|
22
23
|
const [width, height] = [props.width ?? file?.imageSize[0], props.height ?? file?.imageSize[1]];
|
|
23
24
|
const defaultAbstractData =
|
|
24
25
|
"data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFklEQVR42mN8//HLfwYiAOOoQvoqBABbWyZJf74GZgAAAABJRU5ErkJggg==";
|
package/ui/System/CSR.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import { st } from "akanjs/store";
|
|
|
17
17
|
import { animated } from "akanjs/ui";
|
|
18
18
|
import { Activity, type ComponentProps, type ReactNode, type RefObject, useEffect, useMemo } from "react";
|
|
19
19
|
import { createPortal } from "react-dom";
|
|
20
|
+
import { NativeUpdates } from "../../webkit/nativeUpdates";
|
|
20
21
|
import { RenderLayer } from "../../webkit/RenderLayer";
|
|
21
22
|
|
|
22
23
|
import { FontFace } from "../FontFace";
|
|
@@ -394,6 +395,9 @@ const CSRPageContainer = ({ entry, prefix, layoutStyle }: CSRPageContainerProps)
|
|
|
394
395
|
() => [...pathRoute.renderLayouts, pathRoute.renderPage],
|
|
395
396
|
[pathRoute.renderLayouts, pathRoute.renderPage],
|
|
396
397
|
);
|
|
398
|
+
useEffect(() => {
|
|
399
|
+
if (pageType === "current") NativeUpdates.confirm();
|
|
400
|
+
}, [pageType]);
|
|
397
401
|
const pageContainers = document.getElementById("pageContainers");
|
|
398
402
|
if (!pageContainers) return null;
|
|
399
403
|
const { page, pageContentRef, pageClassName, pageBind } =
|