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.
Files changed (226) hide show
  1. package/base/baseEnv.ts +19 -5
  2. package/client/csrTypes.ts +2 -0
  3. package/client/device.ts +28 -12
  4. package/client/index.ts +1 -0
  5. package/client/native/accessibility.ts +1 -0
  6. package/client/native/app-state.ts +1 -0
  7. package/client/native/app.ts +1 -0
  8. package/client/native/appearance.ts +1 -0
  9. package/client/native/auth-session.ts +1 -0
  10. package/client/native/autostart.ts +1 -0
  11. package/client/native/badge.ts +1 -0
  12. package/client/native/biometric.ts +1 -0
  13. package/client/native/browser.ts +1 -0
  14. package/client/native/camera.ts +1 -0
  15. package/client/native/clipboard.ts +1 -0
  16. package/client/native/contacts.ts +1 -0
  17. package/client/native/device.ts +1 -0
  18. package/client/native/dialog.ts +1 -0
  19. package/client/native/dock.ts +1 -0
  20. package/client/native/file-picker.ts +1 -0
  21. package/client/native/filesystem.ts +1 -0
  22. package/client/native/geolocation.ts +1 -0
  23. package/client/native/global-shortcut.ts +1 -0
  24. package/client/native/haptics.ts +1 -0
  25. package/client/native/http.ts +1 -0
  26. package/client/native/iap.ts +1 -0
  27. package/client/native/keep-awake.ts +1 -0
  28. package/client/native/keyboard.ts +1 -0
  29. package/client/native/local-notifications.ts +1 -0
  30. package/client/native/menu.ts +1 -0
  31. package/client/native/network.ts +1 -0
  32. package/client/native/opener.ts +1 -0
  33. package/client/native/preferences.ts +1 -0
  34. package/client/native/push.ts +1 -0
  35. package/client/native/screen-orientation.ts +1 -0
  36. package/client/native/screen.ts +1 -0
  37. package/client/native/secure-storage.ts +1 -0
  38. package/client/native/share.ts +1 -0
  39. package/client/native/single-instance.ts +1 -0
  40. package/client/native/splash-screen.ts +1 -0
  41. package/client/native/sqlite.ts +1 -0
  42. package/client/native/toast.ts +1 -0
  43. package/client/native/tray.ts +1 -0
  44. package/client/native/updates.ts +1 -0
  45. package/client/native/volume.ts +1 -0
  46. package/client/native/window-state.ts +1 -0
  47. package/client/native/window.ts +1 -0
  48. package/client/native.ts +31 -1
  49. package/client/resolveServerUrl.ts +11 -0
  50. package/client/router.ts +8 -0
  51. package/common/Logger.ts +26 -2
  52. package/common/RouteLayering.ts +52 -0
  53. package/common/index.ts +1 -0
  54. package/index.ts +115 -6
  55. package/native/desktop.ts +5 -0
  56. package/package.json +11 -1
  57. package/server/akanApp.ts +23 -3
  58. package/server/akanAppHeaders.ts +4 -1
  59. package/server/akanServer.ts +27 -7
  60. package/server/index.ts +1 -0
  61. package/server/lifecycle/orphanGroup.ts +21 -0
  62. package/server/nativeFile.ts +107 -0
  63. package/server/ops/opsRoute.ts +3 -2
  64. package/server/routeTreeBuilder.ts +14 -39
  65. package/server/routing/apiRouter.ts +26 -3
  66. package/server/routing/hostAllowlist.ts +24 -0
  67. package/server/selfExec.ts +25 -0
  68. package/server/types.tsx +3 -1
  69. package/server/webRouter.ts +7 -4
  70. package/service/ipcTypes.ts +4 -0
  71. package/signal/CrossSiteGuard.ts +7 -0
  72. package/test/signalTestRuntime.ts +8 -2
  73. package/types/base/baseEnv.d.ts +1 -0
  74. package/types/client/csrTypes.d.ts +2 -0
  75. package/types/client/index.d.ts +1 -0
  76. package/types/client/native/accessibility.d.ts +1 -0
  77. package/types/client/native/app-state.d.ts +1 -0
  78. package/types/client/native/app.d.ts +1 -0
  79. package/types/client/native/appearance.d.ts +1 -0
  80. package/types/client/native/auth-session.d.ts +1 -0
  81. package/types/client/native/autostart.d.ts +1 -0
  82. package/types/client/native/badge.d.ts +1 -0
  83. package/types/client/native/biometric.d.ts +1 -0
  84. package/types/client/native/browser.d.ts +1 -0
  85. package/types/client/native/camera.d.ts +1 -0
  86. package/types/client/native/clipboard.d.ts +1 -0
  87. package/types/client/native/contacts.d.ts +1 -0
  88. package/types/client/native/device.d.ts +1 -0
  89. package/types/client/native/dialog.d.ts +1 -0
  90. package/types/client/native/dock.d.ts +1 -0
  91. package/types/client/native/file-picker.d.ts +1 -0
  92. package/types/client/native/filesystem.d.ts +1 -0
  93. package/types/client/native/geolocation.d.ts +1 -0
  94. package/types/client/native/global-shortcut.d.ts +1 -0
  95. package/types/client/native/haptics.d.ts +1 -0
  96. package/types/client/native/http.d.ts +1 -0
  97. package/types/client/native/iap.d.ts +1 -0
  98. package/types/client/native/keep-awake.d.ts +1 -0
  99. package/types/client/native/keyboard.d.ts +1 -0
  100. package/types/client/native/local-notifications.d.ts +1 -0
  101. package/types/client/native/menu.d.ts +1 -0
  102. package/types/client/native/network.d.ts +1 -0
  103. package/types/client/native/opener.d.ts +1 -0
  104. package/types/client/native/preferences.d.ts +1 -0
  105. package/types/client/native/push.d.ts +1 -0
  106. package/types/client/native/screen-orientation.d.ts +1 -0
  107. package/types/client/native/screen.d.ts +1 -0
  108. package/types/client/native/secure-storage.d.ts +1 -0
  109. package/types/client/native/share.d.ts +1 -0
  110. package/types/client/native/single-instance.d.ts +1 -0
  111. package/types/client/native/splash-screen.d.ts +1 -0
  112. package/types/client/native/sqlite.d.ts +1 -0
  113. package/types/client/native/toast.d.ts +1 -0
  114. package/types/client/native/tray.d.ts +1 -0
  115. package/types/client/native/updates.d.ts +1 -0
  116. package/types/client/native/volume.d.ts +1 -0
  117. package/types/client/native/window-state.d.ts +1 -0
  118. package/types/client/native/window.d.ts +1 -0
  119. package/types/client/native.d.ts +14 -2
  120. package/types/client/resolveServerUrl.d.ts +1 -0
  121. package/types/client/router.d.ts +3 -0
  122. package/types/common/RouteLayering.d.ts +28 -0
  123. package/types/common/index.d.ts +1 -0
  124. package/types/index.d.ts +112 -6
  125. package/types/native/desktop.d.ts +3 -0
  126. package/types/server/akanAppHeaders.d.ts +2 -0
  127. package/types/server/index.d.ts +1 -0
  128. package/types/server/lifecycle/orphanGroup.d.ts +7 -0
  129. package/types/server/nativeFile.d.ts +10 -0
  130. package/types/server/routing/apiRouter.d.ts +3 -1
  131. package/types/server/routing/hostAllowlist.d.ts +8 -0
  132. package/types/server/selfExec.d.ts +8 -0
  133. package/types/server/types.d.ts +3 -1
  134. package/types/service/ipcTypes.d.ts +16 -0
  135. package/types/signal/CrossSiteGuard.d.ts +1 -0
  136. package/types/ui/recipe/buttonRecipe.d.ts +2 -2
  137. package/types/vendor/@akanjs/native/packages/cli/src/api.d.ts +57 -4
  138. package/types/vendor/@akanjs/native/packages/cli/src/config.d.ts +48 -0
  139. package/types/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.d.ts +8 -0
  140. package/types/vendor/@akanjs/native/packages/cli/src/lib/prepare.d.ts +8 -2
  141. package/types/vendor/@akanjs/native/packages/cli/src/lib/project.d.ts +10 -0
  142. package/types/vendor/@akanjs/native/packages/cli/src/lib/publish.d.ts +24 -0
  143. package/types/vendor/@akanjs/native/packages/cli/src/lib/updates.d.ts +24 -0
  144. package/types/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.d.ts +4 -1
  145. package/types/vendor/@akanjs/native/packages/cli/src/platforms/macos.d.ts +5 -0
  146. package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.d.ts +38 -0
  147. package/types/vendor/@akanjs/native/packages/desktop/src/dispatcher.d.ts +8 -1
  148. package/types/vendor/@akanjs/native/packages/desktop/src/grants.d.ts +11 -0
  149. package/types/vendor/@akanjs/native/packages/desktop/src/main.d.ts +11 -0
  150. package/types/vendor/@akanjs/native/packages/desktop/src/paths.d.ts +13 -2
  151. package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +27 -0
  152. package/types/vendor/@akanjs/native/packages/desktop/src/relaunch.d.ts +21 -0
  153. package/types/vendor/@akanjs/native/packages/desktop/src/server.d.ts +79 -0
  154. package/types/vendor/@akanjs/native/plugins/app/src/index.d.ts +5 -0
  155. package/types/vendor/@akanjs/native/plugins/file-picker/src/index.d.ts +20 -1
  156. package/types/vendor/@akanjs/native/plugins/push/src/index.d.ts +9 -0
  157. package/types/vendor/@akanjs/native/plugins/updates/src/desktop.d.ts +28 -0
  158. package/types/vendor/@akanjs/native/plugins/volume/src/common.d.ts +10 -0
  159. package/types/vendor/@akanjs/native/plugins/volume/src/desktop.d.ts +18 -0
  160. package/types/vendor/@akanjs/native/plugins/volume/src/index.d.ts +28 -0
  161. package/types/vendor/@akanjs/native/plugins/volume/src.d.ts +1 -0
  162. package/types/webkit/csrFrameDump.d.ts +42 -0
  163. package/types/webkit/nativeNavigation.d.ts +1 -0
  164. package/types/webkit/nativePurchase.d.ts +6 -2
  165. package/types/webkit/nativeUpdates.d.ts +8 -0
  166. package/ui/Agent/Attach.tsx +6 -2
  167. package/ui/CsrImage.tsx +3 -2
  168. package/ui/System/CSR.tsx +4 -0
  169. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeActivity.kt +5 -1
  170. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeBridge.kt +19 -0
  171. package/vendor/@akanjs/native/native/desktop/Cargo.toml +1 -1
  172. package/vendor/@akanjs/native/native/desktop/src/lib.rs +161 -25
  173. package/vendor/@akanjs/native/native/desktop/src/volume.rs +184 -0
  174. package/vendor/@akanjs/native/native/desktop/src/win/mod.rs +3 -1
  175. package/vendor/@akanjs/native/native/desktop/src/win/volume.rs +71 -0
  176. package/vendor/@akanjs/native/native/ios/Sources/AkanNativeShell.swift +12 -2
  177. package/vendor/@akanjs/native/packages/cli/src/api.ts +142 -12
  178. package/vendor/@akanjs/native/packages/cli/src/commands/build.ts +5 -3
  179. package/vendor/@akanjs/native/packages/cli/src/commands/update.ts +10 -71
  180. package/vendor/@akanjs/native/packages/cli/src/config.ts +41 -0
  181. package/vendor/@akanjs/native/packages/cli/src/lib/configkeys.ts +9 -2
  182. package/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.ts +58 -0
  183. package/vendor/@akanjs/native/packages/cli/src/lib/hmr.ts +2 -0
  184. package/vendor/@akanjs/native/packages/cli/src/lib/prepare.ts +10 -2
  185. package/vendor/@akanjs/native/packages/cli/src/lib/project.ts +38 -2
  186. package/vendor/@akanjs/native/packages/cli/src/lib/publish.ts +104 -0
  187. package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +85 -5
  188. package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +1 -0
  189. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.ts +6 -4
  190. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop.ts +16 -0
  191. package/vendor/@akanjs/native/packages/cli/src/platforms/macos.ts +44 -1
  192. package/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.ts +436 -0
  193. package/vendor/@akanjs/native/packages/cli/src/platforms/windows.ts +2 -0
  194. package/vendor/@akanjs/native/packages/core/src/runtime.ts +26 -5
  195. package/vendor/@akanjs/native/packages/desktop/src/dispatcher.ts +20 -0
  196. package/vendor/@akanjs/native/packages/desktop/src/grants.ts +47 -0
  197. package/vendor/@akanjs/native/packages/desktop/src/host.ts +102 -14
  198. package/vendor/@akanjs/native/packages/desktop/src/main.ts +59 -11
  199. package/vendor/@akanjs/native/packages/desktop/src/paths.ts +38 -4
  200. package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +28 -0
  201. package/vendor/@akanjs/native/packages/desktop/src/relaunch.ts +159 -0
  202. package/vendor/@akanjs/native/packages/desktop/src/server.ts +493 -0
  203. package/vendor/@akanjs/native/plugins/app/android/AppPlugin.kt +14 -0
  204. package/vendor/@akanjs/native/plugins/app/native-plugin.json +2 -2
  205. package/vendor/@akanjs/native/plugins/app/src/desktop.ts +5 -0
  206. package/vendor/@akanjs/native/plugins/app/src/index.ts +6 -1
  207. package/vendor/@akanjs/native/plugins/app/src/web.ts +3 -0
  208. package/vendor/@akanjs/native/plugins/file-picker/src/desktop.ts +39 -2
  209. package/vendor/@akanjs/native/plugins/file-picker/src/index.ts +36 -1
  210. package/vendor/@akanjs/native/plugins/push/android/PushPlugin.kt +9 -1
  211. package/vendor/@akanjs/native/plugins/push/ios/PushPlugin.swift +4 -0
  212. package/vendor/@akanjs/native/plugins/push/src/index.ts +10 -0
  213. package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +464 -452
  214. package/vendor/@akanjs/native/plugins/volume/android/VolumePlugin.kt +107 -0
  215. package/vendor/@akanjs/native/plugins/volume/native-plugin.json +14 -0
  216. package/vendor/@akanjs/native/plugins/volume/src/common.ts +28 -0
  217. package/vendor/@akanjs/native/plugins/volume/src/desktop.ts +185 -0
  218. package/vendor/@akanjs/native/plugins/volume/src/index.ts +32 -0
  219. package/webkit/CsrRouteTable.ts +15 -35
  220. package/webkit/RenderLayer.tsx +71 -6
  221. package/webkit/bootCsr.tsx +11 -8
  222. package/webkit/csrFrameDump.ts +67 -0
  223. package/webkit/nativeNavigation.ts +17 -0
  224. package/webkit/nativePurchase.ts +12 -2
  225. package/webkit/nativeUpdates.ts +55 -0
  226. package/webkit/useCsrValues.ts +27 -0
@@ -29,6 +29,7 @@ export { isMcpDescribableArg, type McpExposureEndpoint, type McpExposureOption,
29
29
  export { deepObjectify, objectify, plainFieldsOf } from "./objectify.d.ts";
30
30
  export { pathGet, pathGetLoose, pathSet, toPathSegments } from "./objectPath.d.ts";
31
31
  export { formatPhone, isPhoneNumber } from "./phone.d.ts";
32
+ export { type RouteLayer, RouteLayering } from "./RouteLayering.d.ts";
32
33
  export { randomPick, randomPicks } from "./randomPick.d.ts";
33
34
  export { hostFromRequest, isJsonContentType, originFromRequest } from "./requestOrigin.d.ts";
34
35
  export { RestClient, type RestClientOptions, type RestRequestOptions } from "./restClient.d.ts";
package/types/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { AkanNativeConfig } from "./vendor/@akanjs/native/packages/cli/src/config.d.ts";
1
2
  import type { AkanI18nConfig } from "akanjs/common";
2
3
  import type { AkanImageConfig } from "akanjs/server";
3
4
  export declare const archs: readonly ["amd64", "arm64"];
@@ -24,6 +25,31 @@ export interface LibDockerConfig {
24
25
  preRuns: DockerRun[];
25
26
  postRuns: DockerRun[];
26
27
  }
28
+ /** `${process.platform}-${process.arch}` of the computer a desktop app is built on, which is the one it runs on. */
29
+ export declare const binPlatforms: readonly ["darwin-arm64", "darwin-x64", "linux-arm64", "linux-x64", "win32-arm64", "win32-x64"];
30
+ export type BinPlatform = (typeof binPlatforms)[number];
31
+ /** Downloaded when the desktop app is built; the file must hash to `sha256`, so plain http is as safe as https. */
32
+ export interface AkanBinUrlSource {
33
+ url: string;
34
+ sha256: string;
35
+ /** The executable inside the archive `url` names (.zip, .tar.gz, .tgz, .tar.xz, .tar.bz2, .tar). */
36
+ file?: string;
37
+ }
38
+ /** A file on the building computer, relative to the `akan.config.ts` that declares it. */
39
+ export interface AkanBinPathSource {
40
+ path: string;
41
+ /** The executable inside the archive `path` names. */
42
+ file?: string;
43
+ }
44
+ export type AkanBinSource = AkanBinUrlSource | AkanBinPathSource;
45
+ /**
46
+ * Executables a desktop app carries, by the name its code spawns and then by platform. Their folder comes first on
47
+ * the app's PATH, so the carried server's `spawn("ffmpeg")` runs the carried file; a native plugin finds it in
48
+ * `ctx.binDir`.
49
+ */
50
+ export type AkanBinConfig = Record<string, {
51
+ [platform in BinPlatform]?: AkanBinSource;
52
+ }>;
27
53
  export interface AkanRouteDomains {
28
54
  main?: string[];
29
55
  develop?: string[];
@@ -59,8 +85,13 @@ export type DatabaseMode = "single" | "multiple" | "cluster";
59
85
  export type MobileEnv = "local" | "debug" | "develop" | "main";
60
86
  export type MobilePermission = "camera" | "contacts" | "location" | "push" | "speech";
61
87
  export interface AkanMobileTargetAssets {
62
- icon?: string;
63
- splash?: string;
88
+ /** A square PNG, relative to the app folder, or it with the color behind its transparent areas. */
89
+ icon?: string | {
90
+ image: string;
91
+ backgroundColor?: string;
92
+ };
93
+ /** A PNG shown centered at launch, or the launch screen's color, image and when it hides. */
94
+ splash?: string | NonNullable<AkanNativeConfig["splash"]>;
64
95
  }
65
96
  export interface AkanMobileTargetDeepLinks {
66
97
  schemes?: string[];
@@ -96,14 +127,77 @@ export interface AkanMobileNativeConfig {
96
127
  activity?: string[];
97
128
  /** The Firebase project's google-services.json, relative to the app folder, for FCM push on Android. */
98
129
  googleServices?: string;
130
+ /** Media plays with sound without a tap first, as it does on iOS and the desktop: a signage screen. */
131
+ autoplay?: boolean;
132
+ };
133
+ /** Android's notification channel, status bar icon (relative to the app folder) and accent color. */
134
+ push?: AkanNativeConfig["push"];
135
+ /** The app's part of the iOS privacy manifest (PrivacyInfo.xcprivacy), which an App Store upload requires. */
136
+ privacy?: AkanNativeConfig["privacy"];
137
+ desktop?: {
138
+ /**
139
+ * The desktop app carries the app's server (API only, database mode single, on loopback) and its pages call
140
+ * nothing else. `build-desktop`, `start-desktop` and `publish-update` all read it, and an installed app refuses
141
+ * a release that carries a server when it has none, or none when it has one.
142
+ */
143
+ server?: boolean;
144
+ /**
145
+ * `"reload"`: a window whose page's process ends (a crash, a hang) loads it again every time, waiting
146
+ * longer after each end in a row, and the app relaunches when the webview's browser process ends — for an
147
+ * app nobody attends. `"errorPage"` (default): one reload, then an error page, and a quit for the browser.
148
+ */
149
+ recovery?: "errorPage" | "reload";
150
+ /** The main window from its first frame: borderless fullscreen, and no taskbar button (Windows, Linux). */
151
+ window?: {
152
+ fullscreen?: boolean;
153
+ skipTaskbar?: boolean;
154
+ };
155
+ /**
156
+ * Windows: `"auto"` answers getDisplayMedia() with the first screen at once, no picker or gesture — remote
157
+ * support on an unattended screen; it covers every media request, so not for an app that asks for a camera.
158
+ */
159
+ screenCapture?: "picker" | "auto";
99
160
  };
100
161
  }
162
+ /**
163
+ * Where an installed app looks for newer releases of itself (the native runtime's updates plugin): the whole app on a
164
+ * desktop, the web bundle on a phone. `akan publish-update` writes and signs a release with a key on this machine;
165
+ * `akan pack-update` writes an unsigned phone bundle for whoever holds the key to sign.
166
+ */
167
+ export interface AkanMobileUpdatesConfig {
168
+ /**
169
+ * A static base URL, https in a release build: `<url>/<os>-<arch>/<channel>.json` (desktop) or `<url>/<platform>/…`
170
+ * (a phone's web bundle).
171
+ */
172
+ url: string;
173
+ /** The update key's public half, the raw 32-byte Ed25519 key in base64 (`akan update-keygen` prints it). */
174
+ publicKey: string;
175
+ /**
176
+ * The manifest the app follows, e.g. a "pilot" target's "pilot". Default: the backend env the app is built for
177
+ * (`main`, `develop`, `debug`, `local`).
178
+ */
179
+ channel?: string;
180
+ /** How long a newly applied release has to call notifyReady() before it is rolled back, ms. Default 10000. */
181
+ readyTimeout?: number;
182
+ }
183
+ /**
184
+ * One bundle id, or one per platform, for an app whose store listings already carry different ids. A platform without
185
+ * its own takes `default`.
186
+ */
187
+ export type AkanMobileAppId = string | {
188
+ default?: string;
189
+ ios?: string;
190
+ android?: string;
191
+ macos?: string;
192
+ windows?: string;
193
+ linux?: string;
194
+ };
101
195
  export interface AkanMobileTargetConfig {
102
196
  name: string;
103
197
  basePath?: string;
104
198
  indexPath?: string;
105
199
  appName: string;
106
- appId: string;
200
+ appId: AkanMobileAppId;
107
201
  /** Executables, archives and the Swift module; letters, digits, `.`, `_` and `-`. Default: the app's folder name. */
108
202
  fileName?: string;
109
203
  version: string;
@@ -113,15 +207,18 @@ export interface AkanMobileTargetConfig {
113
207
  deepLinks?: AkanMobileTargetDeepLinks;
114
208
  files?: AkanMobileTargetFiles;
115
209
  native?: AkanMobileNativeConfig;
210
+ /** Over mobile.updates, field by field: a pilot target names its own channel. */
211
+ updates?: Partial<AkanMobileUpdatesConfig>;
116
212
  }
117
213
  export interface AkanMobileConfig {
118
214
  appName: string;
119
- appId: string;
215
+ appId: AkanMobileAppId;
120
216
  fileName?: string;
121
217
  version: string;
122
218
  buildNum: number;
123
219
  files?: AkanMobileTargetFiles;
124
220
  native?: AkanMobileNativeConfig;
221
+ updates?: AkanMobileUpdatesConfig;
125
222
  targets: Record<string, AkanMobileTargetConfig>;
126
223
  }
127
224
  export interface AkanScanInfo {
@@ -219,6 +316,10 @@ export interface AppConfigResult {
219
316
  */
220
317
  syncPageLibs?: string[] | boolean;
221
318
  externalLibs: string[];
319
+ /** Dependencies whose install scripts `bun install --production` runs, in the image and in a desktop app's server. */
320
+ trustedDependencies: string[];
321
+ /** Every desktop build, run and dev session carries these, server or not; the image installs through `docker`. */
322
+ bin: AkanBinConfig;
222
323
  barrelImports: string[];
223
324
  optimizeImports: string[];
224
325
  images: AkanImageConfig;
@@ -230,6 +331,9 @@ export interface AppConfigResult {
230
331
  }
231
332
  export interface LibConfigResult {
232
333
  externalLibs: string[];
334
+ trustedDependencies: string[];
335
+ /** Carried by the desktop app of every app that depends on this lib; an app's own entry of the same name wins. */
336
+ bin: AkanBinConfig;
233
337
  /** Image steps every app that mounts this lib inherits, unless that app declares a whole Dockerfile. */
234
338
  docker: LibDockerConfig;
235
339
  /** Which of this lib's own public fonts every app that mounts it must keep. */
@@ -246,12 +350,14 @@ export interface LibConfigContext {
246
350
  readonly name: string;
247
351
  readonly type: "lib";
248
352
  }
249
- export type AppConfigInput = Omit<DeepPartial<AppConfigResult>, "docker" | "web"> & {
353
+ export type AppConfigInput = Omit<DeepPartial<AppConfigResult>, "docker" | "web" | "bin"> & {
250
354
  docker?: DockerOption;
251
355
  web?: AkanWebOption;
356
+ bin?: AkanBinConfig;
252
357
  plugins?: AkanPlugin[];
253
358
  };
254
- export type LibConfigInput = DeepPartial<LibConfigResult> & {
359
+ export type LibConfigInput = Omit<DeepPartial<LibConfigResult>, "bin"> & {
360
+ bin?: AkanBinConfig;
255
361
  plugins?: AkanPlugin[];
256
362
  };
257
363
  export interface SubspaceDeclaration {
@@ -0,0 +1,3 @@
1
+ export { AkanNativeError, mimeFor } from "../vendor/@akanjs/native/packages/core/src/index.d.ts";
2
+ export type { DesktopContext, DesktopPlugin, NativeEvent } from "../vendor/@akanjs/native/packages/desktop/src/plugin.d.ts";
3
+ export { createPageVeto, defineDesktopPlugin, externalOpenAllowed } from "../vendor/@akanjs/native/packages/desktop/src/plugin.d.ts";
@@ -1,3 +1,5 @@
1
+ /** The Host every request the gateway hands a replica carries; a browser never sends it to a replica's port. */
2
+ export declare const AKAN_CHILD_HOST = "akan-child";
1
3
  export interface ProxyClientPeer {
2
4
  address: string;
3
5
  port: number;
@@ -7,6 +7,7 @@ export * from "./console.d.ts";
7
7
  export * from "./decorators.d.ts";
8
8
  export * from "./devtools.d.ts";
9
9
  export type { ChangeBatch, ChangeKind } from "./hmr/wsHub.d.ts";
10
+ export * from "./nativeFile.d.ts";
10
11
  export * from "./oauth.d.ts";
11
12
  export * from "./processMetricsCollector.d.ts";
12
13
  export * from "./proxy.d.ts";
@@ -0,0 +1,7 @@
1
+ export declare class OrphanGroup {
2
+ #private;
3
+ static exit(code: number, { leads, graceMs }?: {
4
+ leads?: boolean | undefined;
5
+ graceMs?: number | undefined;
6
+ }): void;
7
+ }
@@ -0,0 +1,10 @@
1
+ export type NativeFileMode = "read" | "write" | "folder";
2
+ export declare class NativeFile {
3
+ #private;
4
+ static timeoutMs: number;
5
+ static operationMode: () => string;
6
+ /** The path behind `grant`, which the user must have given for `mode`. */
7
+ static resolve(grant: string, mode: NativeFileMode): Promise<string>;
8
+ /** A path inside a folder grant; one that climbs out of the folder is refused. */
9
+ static resolveIn(grant: string, relative: string): Promise<string>;
10
+ }
@@ -4,6 +4,7 @@ import type { HmrWsHub } from "../hmr/wsHub.d.ts";
4
4
  import { type WebProxyRunner } from "../proxy.d.ts";
5
5
  import type { HttpRoutes, SignalRouteOptions, WebsocketRoutes } from "../types.d.ts";
6
6
  import { AppWsData } from "./appWsData.d.ts";
7
+ import type { HostAllowlist } from "./hostAllowlist.d.ts";
7
8
  export interface HmrStateSource {
8
9
  readonly state: {
9
10
  buildId: number;
@@ -32,6 +33,7 @@ export interface ApiRouteInputs {
32
33
  renderEnvRoutes: HttpRoutes;
33
34
  upgradeAppWs: (req: Request, data: AppWsData) => boolean;
34
35
  webProxyRunner?: WebProxyRunner | null;
36
+ hostAllowlist?: HostAllowlist | null;
35
37
  }
36
38
  export interface WebsocketHandlersInputs {
37
39
  wsRoutes: WebsocketRoutes;
@@ -47,7 +49,7 @@ type WsTaggedData = {
47
49
  };
48
50
  export declare class ApiRouter {
49
51
  #private;
50
- static buildRoutes({ prefix, websocketPrefix, routes, builtinRoutes, routeOptions, renderEnvRoutes, upgradeAppWs, webProxyRunner, }: ApiRouteInputs): NonNullHttpRoutes;
52
+ static buildRoutes({ prefix, websocketPrefix, routes, builtinRoutes, routeOptions, renderEnvRoutes, upgradeAppWs, webProxyRunner, hostAllowlist, }: ApiRouteInputs): NonNullHttpRoutes;
51
53
  static buildWebsocketHandlers({ wsRoutes, registry, live, hmrHub, hmrState, logger, onDrain, }: WebsocketHandlersInputs): Bun.WebSocketHandler<WsTaggedData>;
52
54
  static applyGlobalPrefix(prefix: string, path: string, options?: SignalRouteOptions): string;
53
55
  static joinRoutePath(prefix: string, path: string): string;
@@ -0,0 +1,8 @@
1
+ export declare class HostAllowlist {
2
+ #private;
3
+ constructor(hosts: Iterable<string>);
4
+ /** `AKAN_ALLOWED_HOSTS`: comma-separated `host:port` entries; unset or blank serves every Host. */
5
+ static fromEnv(env?: Record<string, string | undefined>): HostAllowlist | null;
6
+ allows(req: Request): boolean;
7
+ refuse(): Response;
8
+ }
@@ -0,0 +1,8 @@
1
+ export declare class SelfExec {
2
+ #private;
3
+ static adopt(): void;
4
+ /** A desktop app's carried server: only its shell starts the app executable as Bun. */
5
+ static get carried(): boolean;
6
+ static env(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
7
+ static command(script: string, ...args: string[]): string[];
8
+ }
@@ -72,7 +72,9 @@ export declare const resolveWebConfig: (web: Partial<AkanWebConfig> | undefined)
72
72
  export declare const getWebConfigFromEnv: () => AkanWebConfig;
73
73
  export interface MobileDeepLinkAssociation {
74
74
  targetName: string;
75
- appId: string;
75
+ /** Null when the target names no id for the platform; that platform then gets no association. */
76
+ iosAppId: string | null;
77
+ androidAppId: string | null;
76
78
  domains: string[];
77
79
  iosTeamId?: string;
78
80
  androidSha256CertFingerprints?: string[];
@@ -155,6 +155,10 @@ export type AkanIpcMessage = {
155
155
  type: "tcp";
156
156
  }>;
157
157
  healthPath?: string;
158
+ crossSite?: {
159
+ allowedOrigins: string[];
160
+ enabled: boolean;
161
+ };
158
162
  } | {
159
163
  type: "backend-ready";
160
164
  pid: number;
@@ -233,6 +237,18 @@ export type AkanIpcMessage = {
233
237
  } | {
234
238
  type: "shutdown";
235
239
  signal?: string;
240
+ }
241
+ /** Desktop server → the shell that started it: the path behind a file picker grant (forServer). */
242
+ | {
243
+ type: "file.resolve";
244
+ id: string;
245
+ grant: string;
246
+ } | {
247
+ type: "file.resolved";
248
+ id: string;
249
+ path?: string;
250
+ mode?: "read" | "write" | "folder";
251
+ error?: string;
236
252
  } | {
237
253
  type: "error";
238
254
  message: string;
@@ -13,6 +13,7 @@ export declare class CrossSiteGuard {
13
13
  static readonly nativeOrigins: readonly ["app://localhost", "https://app.localhost"];
14
14
  /** Applied at boot from the mounting app's `option.ts`; the native shells stay allowed unless disabled. */
15
15
  static configure({ allowedOrigins, enabled }: CrossSiteOption): void;
16
+ static option(): Required<CrossSiteOption>;
16
17
  static reset(): void;
17
18
  /** Call only where a JSON body is read: a multipart upload relies on `assertOrigin` alone. */
18
19
  static assertJsonBody(contentType: string | null): void;
@@ -2,7 +2,7 @@
2
2
  export declare const buttonRecipe: (variants?: Omit<({
3
3
  size?: "lg" | "md" | "sm" | "xs" | "icon" | undefined;
4
4
  outline?: boolean | undefined;
5
- variant?: "link" | "default" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "destructive" | "neutral" | "outline" | "ghost" | undefined;
5
+ variant?: "default" | "link" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "destructive" | "neutral" | "outline" | "ghost" | undefined;
6
6
  shape?: "default" | "circle" | "square" | undefined;
7
7
  } & {
8
8
  class?: import("tailwind-variants").ClassValue;
@@ -10,7 +10,7 @@ export declare const buttonRecipe: (variants?: Omit<({
10
10
  }) | ({
11
11
  size?: "lg" | "md" | "sm" | "xs" | "icon" | undefined;
12
12
  outline?: boolean | undefined;
13
- variant?: "link" | "default" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "destructive" | "neutral" | "outline" | "ghost" | undefined;
13
+ variant?: "default" | "link" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "destructive" | "neutral" | "outline" | "ghost" | undefined;
14
14
  shape?: "default" | "circle" | "square" | undefined;
15
15
  } & {
16
16
  class?: never;
@@ -2,11 +2,12 @@ import { type DoctorCheck } from "./commands/doctor.ts";
2
2
  import type { AkanNativeConfig } from "./config.ts";
3
3
  import type { Device, DeviceSelector } from "./lib/launch.ts";
4
4
  import { type LogEvent, type LogSink } from "./lib/log.ts";
5
- import { type AndroidSigning, type BuildProfile, type IosBuild, type IosSigning, type IosSigningResult } from "./lib/prepare.ts";
5
+ import { type AndroidSigning, type BuildProfile, type IosBuild, type IosSigning, type IosSigningResult, type WindowsBuild } from "./lib/prepare.ts";
6
+ import { type UpdateManifest } from "./lib/updates.ts";
6
7
  import { type TargetPlatform } from "./platforms/index.ts";
7
- export type { AkanNativeConfig, AndroidSigning, Device, DeviceSelector, DoctorCheck, IosBuild, IosSigning, IosSigningResult, LogEvent, TargetPlatform, };
8
+ export type { AkanNativeConfig, AndroidSigning, Device, DeviceSelector, DoctorCheck, IosBuild, IosSigning, IosSigningResult, LogEvent, TargetPlatform, WindowsBuild, };
8
9
  /** semver of this API. A caller checks the major before it relies on anything here. */
9
- export declare const API_VERSION = "0.1.0";
10
+ export declare const API_VERSION = "0.8.0";
10
11
  export type AkanNativeErrorCode = "CONFIG_INVALID" | "TOOLCHAIN_MISSING" | "WEB_INPUT_INVALID" | "WEB_BUILD_FAILED" | "NATIVE_BUILD_FAILED" | "SIGNING_FAILED" | "DEVICE_FAILED" | "CANCELLED" | "INTERNAL";
11
12
  export declare class AkanNativeError extends Error {
12
13
  readonly code: AkanNativeErrorCode;
@@ -50,7 +51,7 @@ export interface TaskOptions {
50
51
  signal?: AbortSignal;
51
52
  }
52
53
  export interface Artifact {
53
- kind: "app" | "apk" | "aab" | "ipa" | "folder" | "web";
54
+ kind: "app" | "apk" | "aab" | "ipa" | "folder" | "web" | "installer";
54
55
  path: string;
55
56
  signing: "none" | "adhoc" | "debug" | "development" | "distribution";
56
57
  device?: "simulator" | "device";
@@ -87,6 +88,7 @@ export declare function validateConfig(config: AkanNativeConfig, options: {
87
88
  export declare function build(options: TaskOptions & {
88
89
  profile?: BuildProfile;
89
90
  ios?: IosBuild;
91
+ windows?: WindowsBuild;
90
92
  }): Promise<BuildResult>;
91
93
  /**
92
94
  * Store files: a release build signed for distribution. Android: the .aab (and, with formats, the
@@ -101,6 +103,57 @@ export declare function release(options: TaskOptions & ({
101
103
  platform: "ios";
102
104
  signing?: IosSigning;
103
105
  })): Promise<BuildResult>;
106
+ /**
107
+ * An unsigned web bundle update (UP-2), for a signer that keeps the key off the build machine. Writes
108
+ * `<out>/files/<sha256>`, `<out>/manifest.template.json` (the manifest with `channel`, `sequence` and `bundle` left
109
+ * empty for the signer) and `<out>/bundle.json` (the native API the bundle needs, UP-3). Prepares the web bundle as a
110
+ * release build does, without building the native app.
111
+ */
112
+ export declare function packUpdate(options: TaskOptions & {
113
+ platform: "ios" | "android";
114
+ out: string;
115
+ }): Promise<{
116
+ manifest: UpdateManifest;
117
+ out: string;
118
+ }>;
119
+ export interface PublishResult {
120
+ build: BuildResult;
121
+ /** `<out>/<os>-<arch>` (desktop) or `<out>/<platform>` (a phone's web bundle): what to upload under updates.url. */
122
+ dir: string;
123
+ bundle: string;
124
+ channel: string;
125
+ files: number;
126
+ /** Bytes of the files the manifest names. */
127
+ size: number;
128
+ }
129
+ /**
130
+ * A signed release for the updates plugin (UP-1, UP-2): a release build, then `<channel>.json`, its signature and
131
+ * its files under `out` (default <appDir>/.akan/native/updates), signed with the key updateKeygen() made.
132
+ */
133
+ export declare function publishUpdate(options: TaskOptions & {
134
+ platform: Exclude<TargetPlatform, "web">;
135
+ channel?: string;
136
+ out?: string;
137
+ }): Promise<PublishResult>;
138
+ /**
139
+ * Whether a web bundle can run in the binary a store release shipped (UP-3): `shipped` is that build's bundle.json,
140
+ * `bundle` the one `packUpdate` wrote. Anything in `problems` means a new binary.
141
+ */
142
+ export declare function compareBundles(shipped: string, bundle: string): {
143
+ compatible: boolean;
144
+ problems: string[];
145
+ };
146
+ /**
147
+ * The app's update signing key: made once (AKAN_NATIVE_UPDATE_KEY, else ~/.akan/native/keys/<app id>.update.key),
148
+ * then read. `publicKey` goes into the config's `updates.publicKey`; the key file never leaves the machine.
149
+ */
150
+ export declare function updateKeygen(options: {
151
+ config: AkanNativeConfig;
152
+ }): {
153
+ publicKey: string;
154
+ keyPath: string;
155
+ created: boolean;
156
+ };
104
157
  /** Builds (default profile debug) and launches the app on a simulator, emulator, desktop or browser. */
105
158
  export declare function run(options: TaskOptions & {
106
159
  profile?: BuildProfile;
@@ -192,6 +192,11 @@ export interface AkanNativeConfig {
192
192
  * or APIs the bundle uses. Android 10+ devices with Google Play update WebView themselves.
193
193
  */
194
194
  minWebViewVersion?: number;
195
+ /**
196
+ * Media plays with sound without a tap first, as it does on iOS and the desktop (WebView's
197
+ * mediaPlaybackRequiresUserGesture off): an app nobody taps, such as a signage screen. Default false.
198
+ */
199
+ autoplay?: boolean;
195
200
  /**
196
201
  * Appended to app.id in debug builds (e.g. ".debug"), so a debug build installs next to the
197
202
  * release app. Deep links and app links must list the suffixed id for debug builds.
@@ -245,6 +250,49 @@ export interface AkanNativeConfig {
245
250
  * hides the window: the app keeps running, a Dock click shows it again, Cmd+Q quits. Default true.
246
251
  */
247
252
  quitOnLastWindowClosed?: boolean;
253
+ /**
254
+ * What a window does when its page's web process ends: a crash, a hang, out of memory. "errorPage"
255
+ * (default) loads the page again once and shows an error page when it ends again within a minute, so a
256
+ * page that crashes on load does not loop; the app quits when the webview's browser process ends
257
+ * (Windows). "reload" loads it again every time, waiting longer after each end in a row (1 s, doubling
258
+ * to a minute), and relaunches the app when the browser process ends: an app nobody attends, such as a
259
+ * kiosk or a signage screen. iOS and Android always start the page over.
260
+ */
261
+ recovery?: "errorPage" | "reload";
262
+ /**
263
+ * The main window from its first frame: `fullscreen` (borderless, on the display the window opens on)
264
+ * and `skipTaskbar` (no taskbar button; Windows and Linux). A plugin's launch phase may still decide
265
+ * otherwise (DesktopContext.launch.setWindow). Default false for both.
266
+ */
267
+ window?: {
268
+ fullscreen?: boolean;
269
+ skipTaskbar?: boolean;
270
+ };
271
+ /**
272
+ * Windows: "auto" answers the page's getDisplayMedia() with the first screen at once, without the picker or a
273
+ * user gesture: a remote-support session on an unattended screen. It is Chromium's switch for automated media
274
+ * tests (--use-fake-ui-for-media-stream), made for every media request, so keep it to an app whose pages ask
275
+ * for no camera or microphone. Default "picker". WebView2's choice by title follows the UI language, so none is
276
+ * offered. macOS and Linux ignore it.
277
+ */
278
+ screenCapture?: "picker" | "auto";
279
+ /**
280
+ * A server the app starts beside its window (akanjs `native.desktop.server`). `dir` is copied to
281
+ * the app's resources (`server/`), and `entry` there runs on the app's own Bun with `env`, bound to
282
+ * a loopback port picked at launch; the page reads its URL as PUBLIC_AKAN_SERVER_URL. The launcher
283
+ * sets PORT, JWT_SECRET, the data folders (`<app local data>/server`) and the listen host itself.
284
+ */
285
+ server?: {
286
+ dir: string;
287
+ entry: string;
288
+ env?: Record<string, string>;
289
+ };
290
+ /**
291
+ * A folder of executables the app carries (akanjs `bin`): copied to the app's resources (`bin/`) and put
292
+ * first on the app's PATH at launch, so its plugins and its server find them by name before the computer's.
293
+ * macOS builds sign every Mach-O file in it.
294
+ */
295
+ bin?: string;
248
296
  };
249
297
  /**
250
298
  * App icon for every platform, generated from one square PNG, ideally 1024×1024 (CLI-8).
@@ -0,0 +1,8 @@
1
+ import type { AkanNativeConfig } from "../config.ts";
2
+ export interface DesktopServerConfig {
3
+ /** Absolute. */
4
+ dir: string;
5
+ entry: string;
6
+ env: Record<string, string>;
7
+ }
8
+ export declare function validateDesktopServer(desktop: AkanNativeConfig["desktop"], appDir: string, problems: string[]): DesktopServerConfig | null;
@@ -7,6 +7,9 @@ import { type Project } from "./project.ts";
7
7
  * picks the .env files, so a staging build is still a release build.
8
8
  */
9
9
  export type BuildProfile = "debug" | "release";
10
+ export interface WindowsBuild {
11
+ installer?: boolean;
12
+ }
10
13
  export interface BuildOptions {
11
14
  mode: string;
12
15
  profile: BuildProfile;
@@ -38,6 +41,8 @@ export interface BuildOptions {
38
41
  android?: AndroidRelease;
39
42
  /** iOS devices (akanjs readiness O1-2, O1-3). */
40
43
  ios?: IosBuild;
44
+ /** Windows: an NSIS setup program next to the app folder (platforms/windows-installer.ts). */
45
+ windows?: WindowsBuild;
41
46
  }
42
47
  /** Which identity and profile an iOS device build signs with; unset: found in the keychain and Xcode's profiles. */
43
48
  export interface IosSigning {
@@ -111,9 +116,10 @@ export interface BuildContext {
111
116
  startPath?: string;
112
117
  android?: AndroidRelease;
113
118
  ios?: IosBuild;
114
- /** Artifacts besides the one the builder returns (an .aab next to the .apk). */
119
+ windows?: WindowsBuild;
120
+ /** Artifacts besides the one the builder returns (an .aab next to the .apk, a Windows setup program). */
115
121
  artifacts: {
116
- kind: "aab" | "ipa";
122
+ kind: "aab" | "ipa" | "installer";
117
123
  path: string;
118
124
  }[];
119
125
  /** What the builder signed with, when it signs (Android: the app's release key or the debug key). */
@@ -1,5 +1,6 @@
1
1
  import type { AkanNativeConfig } from "../config.ts";
2
2
  import { type PermissionSet } from "./acl.ts";
3
+ import { type DesktopServerConfig } from "./desktop-server.ts";
3
4
  import { type EnvConfig } from "./env.ts";
4
5
  import { CliError } from "./log.ts";
5
6
  import { type PermissionsConfig } from "./permissions.ts";
@@ -28,6 +29,15 @@ export interface ResolvedConfig extends Omit<AkanNativeConfig, "icon" | "splash"
28
29
  };
29
30
  desktop: {
30
31
  quitOnLastWindowClosed: boolean;
32
+ recovery: "errorPage" | "reload";
33
+ window: {
34
+ fullscreen: boolean;
35
+ skipTaskbar: boolean;
36
+ };
37
+ screenCapture: "picker" | "auto";
38
+ server?: DesktopServerConfig;
39
+ /** Absolute. */
40
+ bin?: string;
31
41
  };
32
42
  updates: UpdatesConfig | null;
33
43
  /** Absolute image path. */
@@ -0,0 +1,24 @@
1
+ import type { BuildContext } from "./prepare.ts";
2
+ import { type UpdateManifest } from "./updates.ts";
3
+ export type ReleasePlatform = "macos" | "windows" | "linux" | "ios" | "android";
4
+ export interface PublishedRelease {
5
+ /** `<out>/<os>-<arch>` for a desktop app, `<out>/<platform>` for a phone's web bundle. */
6
+ dir: string;
7
+ manifest: UpdateManifest;
8
+ }
9
+ /**
10
+ * The publish time in seconds, and past the release `<channel>.json` in `dir` already names: apps take only a larger
11
+ * sequence, so a clock behind the last publisher's would make this release look older to every one of them.
12
+ */
13
+ export declare function nextSequence(dir: string, channel: string, now?: number): number;
14
+ /** Refuses before the build a release that could not be signed: no key on this machine, or another app's. */
15
+ export declare function assertSigningKey(config: {
16
+ app: {
17
+ id: string;
18
+ };
19
+ updates?: {
20
+ publicKey: string;
21
+ } | null;
22
+ }): void;
23
+ /** Writes the release of `artifact` (the app a release build made) and its signed `<channel>.json` under `out`. */
24
+ export declare function publishRelease(ctx: BuildContext, platform: ReleasePlatform, artifact: string, out: string, channel: string): Promise<PublishedRelease>;
@@ -53,6 +53,28 @@ export interface UpdateManifest {
53
53
  size: number;
54
54
  }[];
55
55
  }
56
+ /** Every file of a web bundle as the app serves it: index.html with the init script and CSP, public/, env.runtime.json. */
57
+ export declare function webFiles(webDir: string, html: string, env: Record<string, string>): {
58
+ path: string;
59
+ data: Uint8Array;
60
+ }[];
61
+ /** Writes a web bundle's files under `<out>/files/<sha256>` (content-addressed, so releases share them) and lists them. */
62
+ export declare function writeWebBundle(out: string, webDir: string, html: string, env: Record<string, string>): UpdateFile[];
63
+ /** A web bundle's manifest (UP-2), keys in the order `update publish` has always written them. */
64
+ export declare function webManifest(release: {
65
+ app: {
66
+ id: string;
67
+ version: string;
68
+ };
69
+ platform: Platform;
70
+ channel: string;
71
+ nativeApi: string;
72
+ sequence: number;
73
+ bundle: string;
74
+ files: UpdateFile[];
75
+ }): UpdateManifest;
76
+ /** Refuses a channel no app could be configured for: it would be written but never taken. */
77
+ export declare function assertChannel(channel: string): void;
56
78
  export declare function validateUpdates(raw: unknown, problems: string[]): UpdatesConfig | null;
57
79
  /** Where the signing key of an app lives: AKAN_NATIVE_UPDATE_KEY (a file path), else ~/.akan/native/keys/<app id>.update.key. */
58
80
  export declare function updateKeyPath(appId: string, env?: Record<string, string | undefined>): string;
@@ -61,6 +83,8 @@ export declare function generateUpdateKey(path: string): {
61
83
  publicKey: string;
62
84
  created: boolean;
63
85
  };
86
+ /** The key at `keyPath`, refused unless it is the one whose public half the apps were built with. */
87
+ export declare function signingKey(keyPath: string, expectedPublicKey: string): import("node:crypto").KeyObject;
64
88
  export declare function signManifest(bytes: Uint8Array, keyPath: string, expectedPublicKey: string): string;
65
89
  /** Verifies like the apps do: raw public key, base64 signature over the exact manifest bytes. */
66
90
  export declare function verifyManifest(bytes: Uint8Array, signature: string, publicKey: string): boolean;
@@ -1,4 +1,7 @@
1
1
  import type { BuildContext } from "../lib/prepare.ts";
2
2
  import { type UpdateManifest } from "../lib/updates.ts";
3
3
  import { type DesktopOs } from "./desktop.ts";
4
- export declare function publishAppUpdate(ctx: BuildContext, os: DesktopOs, app: string, out: string, channel: string, sequence: number): Promise<UpdateManifest>;
4
+ export declare function publishAppUpdate(ctx: BuildContext, os: DesktopOs, app: string, out: string, channel: string, sequence: number): Promise<{
5
+ manifest: UpdateManifest;
6
+ superseded: string | null;
7
+ }>;