akanjs 3.0.0-beta.27 → 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 (213) hide show
  1. package/base/baseEnv.ts +19 -5
  2. package/client/device.ts +22 -6
  3. package/client/index.ts +1 -0
  4. package/client/native/accessibility.ts +1 -0
  5. package/client/native/app-state.ts +1 -0
  6. package/client/native/app.ts +1 -0
  7. package/client/native/appearance.ts +1 -0
  8. package/client/native/auth-session.ts +1 -0
  9. package/client/native/autostart.ts +1 -0
  10. package/client/native/badge.ts +1 -0
  11. package/client/native/biometric.ts +1 -0
  12. package/client/native/browser.ts +1 -0
  13. package/client/native/camera.ts +1 -0
  14. package/client/native/clipboard.ts +1 -0
  15. package/client/native/contacts.ts +1 -0
  16. package/client/native/device.ts +1 -0
  17. package/client/native/dialog.ts +1 -0
  18. package/client/native/dock.ts +1 -0
  19. package/client/native/file-picker.ts +1 -0
  20. package/client/native/filesystem.ts +1 -0
  21. package/client/native/geolocation.ts +1 -0
  22. package/client/native/global-shortcut.ts +1 -0
  23. package/client/native/haptics.ts +1 -0
  24. package/client/native/http.ts +1 -0
  25. package/client/native/iap.ts +1 -0
  26. package/client/native/keep-awake.ts +1 -0
  27. package/client/native/keyboard.ts +1 -0
  28. package/client/native/local-notifications.ts +1 -0
  29. package/client/native/menu.ts +1 -0
  30. package/client/native/network.ts +1 -0
  31. package/client/native/opener.ts +1 -0
  32. package/client/native/preferences.ts +1 -0
  33. package/client/native/push.ts +1 -0
  34. package/client/native/screen-orientation.ts +1 -0
  35. package/client/native/screen.ts +1 -0
  36. package/client/native/secure-storage.ts +1 -0
  37. package/client/native/share.ts +1 -0
  38. package/client/native/single-instance.ts +1 -0
  39. package/client/native/splash-screen.ts +1 -0
  40. package/client/native/sqlite.ts +1 -0
  41. package/client/native/toast.ts +1 -0
  42. package/client/native/tray.ts +1 -0
  43. package/client/native/updates.ts +1 -0
  44. package/client/native/volume.ts +1 -0
  45. package/client/native/window-state.ts +1 -0
  46. package/client/native/window.ts +1 -0
  47. package/client/native.ts +31 -1
  48. package/client/resolveServerUrl.ts +11 -0
  49. package/client/router.ts +8 -0
  50. package/index.ts +115 -6
  51. package/native/desktop.ts +5 -0
  52. package/package.json +11 -1
  53. package/server/akanApp.ts +23 -3
  54. package/server/akanAppHeaders.ts +4 -1
  55. package/server/akanServer.ts +27 -7
  56. package/server/index.ts +1 -0
  57. package/server/lifecycle/orphanGroup.ts +21 -0
  58. package/server/nativeFile.ts +107 -0
  59. package/server/ops/opsRoute.ts +3 -2
  60. package/server/routing/apiRouter.ts +26 -3
  61. package/server/routing/hostAllowlist.ts +24 -0
  62. package/server/selfExec.ts +25 -0
  63. package/server/types.tsx +3 -1
  64. package/server/webRouter.ts +7 -4
  65. package/service/ipcTypes.ts +4 -0
  66. package/signal/CrossSiteGuard.ts +7 -0
  67. package/test/signalTestRuntime.ts +8 -2
  68. package/types/base/baseEnv.d.ts +1 -0
  69. package/types/client/index.d.ts +1 -0
  70. package/types/client/native/accessibility.d.ts +1 -0
  71. package/types/client/native/app-state.d.ts +1 -0
  72. package/types/client/native/app.d.ts +1 -0
  73. package/types/client/native/appearance.d.ts +1 -0
  74. package/types/client/native/auth-session.d.ts +1 -0
  75. package/types/client/native/autostart.d.ts +1 -0
  76. package/types/client/native/badge.d.ts +1 -0
  77. package/types/client/native/biometric.d.ts +1 -0
  78. package/types/client/native/browser.d.ts +1 -0
  79. package/types/client/native/camera.d.ts +1 -0
  80. package/types/client/native/clipboard.d.ts +1 -0
  81. package/types/client/native/contacts.d.ts +1 -0
  82. package/types/client/native/device.d.ts +1 -0
  83. package/types/client/native/dialog.d.ts +1 -0
  84. package/types/client/native/dock.d.ts +1 -0
  85. package/types/client/native/file-picker.d.ts +1 -0
  86. package/types/client/native/filesystem.d.ts +1 -0
  87. package/types/client/native/geolocation.d.ts +1 -0
  88. package/types/client/native/global-shortcut.d.ts +1 -0
  89. package/types/client/native/haptics.d.ts +1 -0
  90. package/types/client/native/http.d.ts +1 -0
  91. package/types/client/native/iap.d.ts +1 -0
  92. package/types/client/native/keep-awake.d.ts +1 -0
  93. package/types/client/native/keyboard.d.ts +1 -0
  94. package/types/client/native/local-notifications.d.ts +1 -0
  95. package/types/client/native/menu.d.ts +1 -0
  96. package/types/client/native/network.d.ts +1 -0
  97. package/types/client/native/opener.d.ts +1 -0
  98. package/types/client/native/preferences.d.ts +1 -0
  99. package/types/client/native/push.d.ts +1 -0
  100. package/types/client/native/screen-orientation.d.ts +1 -0
  101. package/types/client/native/screen.d.ts +1 -0
  102. package/types/client/native/secure-storage.d.ts +1 -0
  103. package/types/client/native/share.d.ts +1 -0
  104. package/types/client/native/single-instance.d.ts +1 -0
  105. package/types/client/native/splash-screen.d.ts +1 -0
  106. package/types/client/native/sqlite.d.ts +1 -0
  107. package/types/client/native/toast.d.ts +1 -0
  108. package/types/client/native/tray.d.ts +1 -0
  109. package/types/client/native/updates.d.ts +1 -0
  110. package/types/client/native/volume.d.ts +1 -0
  111. package/types/client/native/window-state.d.ts +1 -0
  112. package/types/client/native/window.d.ts +1 -0
  113. package/types/client/native.d.ts +14 -2
  114. package/types/client/resolveServerUrl.d.ts +1 -0
  115. package/types/client/router.d.ts +3 -0
  116. package/types/index.d.ts +112 -6
  117. package/types/native/desktop.d.ts +3 -0
  118. package/types/server/akanAppHeaders.d.ts +2 -0
  119. package/types/server/index.d.ts +1 -0
  120. package/types/server/lifecycle/orphanGroup.d.ts +7 -0
  121. package/types/server/nativeFile.d.ts +10 -0
  122. package/types/server/routing/apiRouter.d.ts +3 -1
  123. package/types/server/routing/hostAllowlist.d.ts +8 -0
  124. package/types/server/selfExec.d.ts +8 -0
  125. package/types/server/types.d.ts +3 -1
  126. package/types/service/ipcTypes.d.ts +16 -0
  127. package/types/signal/CrossSiteGuard.d.ts +1 -0
  128. package/types/ui/recipe/buttonRecipe.d.ts +2 -2
  129. package/types/vendor/@akanjs/native/packages/cli/src/api.d.ts +57 -4
  130. package/types/vendor/@akanjs/native/packages/cli/src/config.d.ts +48 -0
  131. package/types/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.d.ts +8 -0
  132. package/types/vendor/@akanjs/native/packages/cli/src/lib/prepare.d.ts +8 -2
  133. package/types/vendor/@akanjs/native/packages/cli/src/lib/project.d.ts +10 -0
  134. package/types/vendor/@akanjs/native/packages/cli/src/lib/publish.d.ts +24 -0
  135. package/types/vendor/@akanjs/native/packages/cli/src/lib/updates.d.ts +24 -0
  136. package/types/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.d.ts +4 -1
  137. package/types/vendor/@akanjs/native/packages/cli/src/platforms/macos.d.ts +5 -0
  138. package/types/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.d.ts +38 -0
  139. package/types/vendor/@akanjs/native/packages/desktop/src/dispatcher.d.ts +8 -1
  140. package/types/vendor/@akanjs/native/packages/desktop/src/grants.d.ts +11 -0
  141. package/types/vendor/@akanjs/native/packages/desktop/src/main.d.ts +11 -0
  142. package/types/vendor/@akanjs/native/packages/desktop/src/paths.d.ts +13 -2
  143. package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +27 -0
  144. package/types/vendor/@akanjs/native/packages/desktop/src/relaunch.d.ts +21 -0
  145. package/types/vendor/@akanjs/native/packages/desktop/src/server.d.ts +79 -0
  146. package/types/vendor/@akanjs/native/plugins/app/src/index.d.ts +5 -0
  147. package/types/vendor/@akanjs/native/plugins/file-picker/src/index.d.ts +20 -1
  148. package/types/vendor/@akanjs/native/plugins/push/src/index.d.ts +9 -0
  149. package/types/vendor/@akanjs/native/plugins/updates/src/desktop.d.ts +28 -0
  150. package/types/vendor/@akanjs/native/plugins/volume/src/common.d.ts +10 -0
  151. package/types/vendor/@akanjs/native/plugins/volume/src/desktop.d.ts +18 -0
  152. package/types/vendor/@akanjs/native/plugins/volume/src/index.d.ts +28 -0
  153. package/types/vendor/@akanjs/native/plugins/volume/src.d.ts +1 -0
  154. package/types/webkit/csrFrameDump.d.ts +42 -0
  155. package/types/webkit/nativeNavigation.d.ts +1 -0
  156. package/types/webkit/nativePurchase.d.ts +6 -2
  157. package/types/webkit/nativeUpdates.d.ts +8 -0
  158. package/ui/Agent/Attach.tsx +6 -2
  159. package/ui/CsrImage.tsx +3 -2
  160. package/ui/System/CSR.tsx +4 -0
  161. package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeActivity.kt +2 -0
  162. package/vendor/@akanjs/native/native/desktop/Cargo.toml +1 -1
  163. package/vendor/@akanjs/native/native/desktop/src/lib.rs +161 -25
  164. package/vendor/@akanjs/native/native/desktop/src/volume.rs +184 -0
  165. package/vendor/@akanjs/native/native/desktop/src/win/mod.rs +3 -1
  166. package/vendor/@akanjs/native/native/desktop/src/win/volume.rs +71 -0
  167. package/vendor/@akanjs/native/packages/cli/src/api.ts +142 -12
  168. package/vendor/@akanjs/native/packages/cli/src/commands/build.ts +5 -3
  169. package/vendor/@akanjs/native/packages/cli/src/commands/update.ts +10 -71
  170. package/vendor/@akanjs/native/packages/cli/src/config.ts +41 -0
  171. package/vendor/@akanjs/native/packages/cli/src/lib/configkeys.ts +9 -2
  172. package/vendor/@akanjs/native/packages/cli/src/lib/desktop-server.ts +58 -0
  173. package/vendor/@akanjs/native/packages/cli/src/lib/hmr.ts +2 -0
  174. package/vendor/@akanjs/native/packages/cli/src/lib/prepare.ts +10 -2
  175. package/vendor/@akanjs/native/packages/cli/src/lib/project.ts +38 -2
  176. package/vendor/@akanjs/native/packages/cli/src/lib/publish.ts +104 -0
  177. package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +85 -5
  178. package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +1 -0
  179. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop-update.ts +6 -4
  180. package/vendor/@akanjs/native/packages/cli/src/platforms/desktop.ts +16 -0
  181. package/vendor/@akanjs/native/packages/cli/src/platforms/macos.ts +44 -1
  182. package/vendor/@akanjs/native/packages/cli/src/platforms/windows-installer.ts +436 -0
  183. package/vendor/@akanjs/native/packages/cli/src/platforms/windows.ts +2 -0
  184. package/vendor/@akanjs/native/packages/desktop/src/dispatcher.ts +20 -0
  185. package/vendor/@akanjs/native/packages/desktop/src/grants.ts +47 -0
  186. package/vendor/@akanjs/native/packages/desktop/src/host.ts +97 -11
  187. package/vendor/@akanjs/native/packages/desktop/src/main.ts +59 -11
  188. package/vendor/@akanjs/native/packages/desktop/src/paths.ts +38 -4
  189. package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +28 -0
  190. package/vendor/@akanjs/native/packages/desktop/src/relaunch.ts +159 -0
  191. package/vendor/@akanjs/native/packages/desktop/src/server.ts +493 -0
  192. package/vendor/@akanjs/native/plugins/app/android/AppPlugin.kt +14 -0
  193. package/vendor/@akanjs/native/plugins/app/native-plugin.json +2 -2
  194. package/vendor/@akanjs/native/plugins/app/src/desktop.ts +5 -0
  195. package/vendor/@akanjs/native/plugins/app/src/index.ts +6 -1
  196. package/vendor/@akanjs/native/plugins/app/src/web.ts +3 -0
  197. package/vendor/@akanjs/native/plugins/file-picker/src/desktop.ts +39 -2
  198. package/vendor/@akanjs/native/plugins/file-picker/src/index.ts +36 -1
  199. package/vendor/@akanjs/native/plugins/push/android/PushPlugin.kt +9 -1
  200. package/vendor/@akanjs/native/plugins/push/ios/PushPlugin.swift +4 -0
  201. package/vendor/@akanjs/native/plugins/push/src/index.ts +10 -0
  202. package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +464 -452
  203. package/vendor/@akanjs/native/plugins/volume/android/VolumePlugin.kt +107 -0
  204. package/vendor/@akanjs/native/plugins/volume/native-plugin.json +14 -0
  205. package/vendor/@akanjs/native/plugins/volume/src/common.ts +28 -0
  206. package/vendor/@akanjs/native/plugins/volume/src/desktop.ts +185 -0
  207. package/vendor/@akanjs/native/plugins/volume/src/index.ts +32 -0
  208. package/webkit/RenderLayer.tsx +71 -6
  209. package/webkit/csrFrameDump.ts +67 -0
  210. package/webkit/nativeNavigation.ts +17 -0
  211. package/webkit/nativePurchase.ts +12 -2
  212. package/webkit/nativeUpdates.ts +55 -0
  213. package/webkit/useCsrValues.ts +27 -0
package/base/baseEnv.ts CHANGED
@@ -112,11 +112,15 @@ export const resetEnvCache = () => {
112
112
  };
113
113
 
114
114
  const csrServerUrl = (): URL | null => {
115
- const value = process.env.AKAN_PUBLIC_SERVER_URL;
115
+ const runtime = (globalThis as { __AKAN_NATIVE__?: { env?: Record<string, string | undefined> } }).__AKAN_NATIVE__
116
+ ?.env?.PUBLIC_AKAN_SERVER_URL;
117
+ const [key, value] = runtime
118
+ ? ["PUBLIC_AKAN_SERVER_URL", runtime]
119
+ : ["AKAN_PUBLIC_SERVER_URL", process.env.AKAN_PUBLIC_SERVER_URL];
116
120
  if (!value) return null;
117
121
  const url = new URL(value);
118
122
  if (url.protocol !== "http:" && url.protocol !== "https:")
119
- throw new Error(`AKAN_PUBLIC_SERVER_URL must be an http(s) URL, got "${value}".`);
123
+ throw new Error(`${key} must be an http(s) URL, got "${value}".`);
120
124
  return url;
121
125
  };
122
126
 
@@ -125,10 +129,12 @@ const nativeDevGatewayOrigin = (): string | null =>
125
129
  ? `${window.location.protocol}//${window.location.host}`
126
130
  : null;
127
131
 
132
+ const devServerOrigin = () => `http://localhost:${process.env.AKAN_PUBLIC_SERVER_PORT ?? "8282"}`;
133
+
128
134
  const nativeDevServerUrl = (operationMode: BaseEnv["operationMode"]): URL | null => {
129
135
  const platform = (globalThis as { __AKAN_NATIVE__?: { platform?: string } }).__AKAN_NATIVE__?.platform;
130
136
  if (operationMode !== "local" || !platform || platform === "web") return null;
131
- return new URL(`http://localhost:${process.env.AKAN_PUBLIC_SERVER_PORT ?? "8282"}`);
137
+ return new URL(devServerOrigin());
132
138
  };
133
139
 
134
140
  const missingPublicEnv = (key: string) =>
@@ -179,8 +185,9 @@ export const getEnv = (): ClientEnv => {
179
185
  : "https:";
180
186
  const clientHttpUri = `${clientHttpProtocol}//${clientHost}${clientPort === 443 ? "" : `:${clientPort}`}`;
181
187
  const csrClient = side === "client" && renderMode === "csr";
182
- const pageOrigin = csrClient && !process.env.AKAN_PUBLIC_SERVER_URL ? nativeDevGatewayOrigin() : null;
183
- const serverUrl = csrClient && !pageOrigin ? (csrServerUrl() ?? nativeDevServerUrl(operationMode)) : null;
188
+ const pinnedServerUrl = csrClient ? csrServerUrl() : null;
189
+ const pageOrigin = csrClient && !pinnedServerUrl ? nativeDevGatewayOrigin() : null;
190
+ const serverUrl = csrClient && !pageOrigin ? (pinnedServerUrl ?? nativeDevServerUrl(operationMode)) : null;
184
191
 
185
192
  const hostFromPage =
186
193
  side === "client" && !serverUrl && (!!pageOrigin || operationMode === "local" || renderMode !== "csr");
@@ -251,3 +258,10 @@ export const getEnv = (): ClientEnv => {
251
258
  cachedEnv = env;
252
259
  return env;
253
260
  };
261
+
262
+ export const getServerOrigin = (): string => {
263
+ const env = getEnv();
264
+ const behindGateway =
265
+ env.side === "client" && env.renderMode === "csr" && !csrServerUrl() && !!nativeDevGatewayOrigin();
266
+ return behindGateway ? devServerOrigin() : new URL(env.serverHttpUri).origin;
267
+ };
package/client/device.ts CHANGED
@@ -13,25 +13,41 @@ const globalWithProcess = globalThis as typeof globalThis & { process?: ProcessE
13
13
  const debugSessionId = Math.random().toString(36).slice(2, 8);
14
14
  let debugSeq = 0;
15
15
 
16
- const isFrameDebugEnabled = () => {
17
- if (typeof window === "undefined") return false;
18
- if (new URLSearchParams(window.location.search).get("akanFrameDebug") === "1") return true;
16
+ const FRAME_TRACE_LIMIT = 2000;
17
+ const frameTrace: { seq: number; event: string; details: DebugPayload }[] = [];
18
+
19
+ const readFrameDebugFlag = () => {
20
+ const fromSearch = new URLSearchParams(window.location.search).get("akanFrameDebug");
21
+ if (fromSearch) return fromSearch;
19
22
  try {
20
- return window.localStorage.getItem("akan:debug:frame") === "1";
23
+ return window.localStorage.getItem("akan:debug:frame");
21
24
  } catch {
22
25
 
23
- return false;
26
+ return null;
24
27
  }
25
28
  };
26
29
 
30
+ const frameDebugMode = (): "console" | "memory" | null => {
31
+ if (typeof window === "undefined") return null;
32
+ const flag = readFrameDebugFlag();
33
+ return flag === "1" ? "console" : flag === "memory" ? "memory" : null;
34
+ };
35
+
27
36
  export function debugFrame(event: string, payload: DebugPayload = {}) {
28
- if (!isFrameDebugEnabled()) return;
37
+ const mode = frameDebugMode();
38
+ if (!mode) return;
29
39
  debugSeq += 1;
30
40
  const details = {
31
41
  href: window.location.href,
32
42
  now: Math.round(performance.now()),
33
43
  ...payload,
34
44
  };
45
+ if (mode === "memory") {
46
+ frameTrace.push({ seq: debugSeq, event, details });
47
+ if (frameTrace.length > FRAME_TRACE_LIMIT) frameTrace.splice(0, frameTrace.length - FRAME_TRACE_LIMIT);
48
+ (window as { __AKAN_FRAME_TRACE__?: typeof frameTrace }).__AKAN_FRAME_TRACE__ = frameTrace;
49
+ return;
50
+ }
35
51
 
36
52
  console.debug(`[akan:frame:${debugSessionId}:${debugSeq}] ${event}`, details);
37
53
  }
package/client/index.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./device";
8
8
  export * from "./frameConfig";
9
9
  export * from "./locale";
10
10
  export * from "./makePageProto";
11
+ export * from "./resolveServerUrl";
11
12
  export * from "./route";
12
13
  export * from "./router";
13
14
  export * from "./rscNavigation";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/accessibility/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/app-state/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/app/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/appearance/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/auth-session/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/autostart/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/badge/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/biometric/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/browser/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/camera/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/clipboard/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/contacts/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/device/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/dialog/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/dock/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/file-picker/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/filesystem/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/geolocation/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/global-shortcut/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/haptics/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/http/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/iap/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/keep-awake/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/keyboard/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/local-notifications/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/menu/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/network/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/opener/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/preferences/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/push/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/screen-orientation/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/screen/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/secure-storage/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/share/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/single-instance/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/splash-screen/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/sqlite/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/toast/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/tray/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/updates/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/volume/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/window-state/src/index.ts";
@@ -0,0 +1 @@
1
+ export * from "../../vendor/@akanjs/native/plugins/window/src/index.ts";
package/client/native.ts CHANGED
@@ -2,14 +2,36 @@ import { isNative, platform } from "../vendor/@akanjs/native/packages/core/src/i
2
2
  import { browser } from "../vendor/@akanjs/native/plugins/browser/src/index.ts";
3
3
  import { opener } from "../vendor/@akanjs/native/plugins/opener/src/index.ts";
4
4
 
5
- export { AkanNativeError, fileBlob, releaseFile } from "../vendor/@akanjs/native/packages/core/src/index.ts";
5
+ export type { LiveValue, Plugin } from "../vendor/@akanjs/native/packages/core/src/index.ts";
6
+ export {
7
+ AkanNativeError,
8
+ createLiveValue,
9
+ definePlugin,
10
+ defineWebPlugin,
11
+ fileBlob,
12
+ isAkanNativeError,
13
+ releaseFile,
14
+ shallowEqual,
15
+ } from "../vendor/@akanjs/native/packages/core/src/index.ts";
6
16
  export { app } from "../vendor/@akanjs/native/plugins/app/src/index.ts";
7
17
  export { appState } from "../vendor/@akanjs/native/plugins/app-state/src/index.ts";
18
+ export type { AuthSessionApi } from "../vendor/@akanjs/native/plugins/auth-session/src/index.ts";
19
+ export { authSession } from "../vendor/@akanjs/native/plugins/auth-session/src/index.ts";
8
20
  export type { Photo } from "../vendor/@akanjs/native/plugins/camera/src/index.ts";
9
21
  export type { Contact } from "../vendor/@akanjs/native/plugins/contacts/src/index.ts";
10
22
  export type { DeviceInfo } from "../vendor/@akanjs/native/plugins/device/src/index.ts";
11
23
  export { device } from "../vendor/@akanjs/native/plugins/device/src/index.ts";
12
24
  export { dialog } from "../vendor/@akanjs/native/plugins/dialog/src/index.ts";
25
+ export type {
26
+ DirectoryFile,
27
+ PickDirectoryOptions,
28
+ PickDirectoryResult,
29
+ PickedFile,
30
+ PickFilesOptions,
31
+ SaveFileOptions,
32
+ SaveFileResult,
33
+ } from "../vendor/@akanjs/native/plugins/file-picker/src/index.ts";
34
+ export { filePicker } from "../vendor/@akanjs/native/plugins/file-picker/src/index.ts";
13
35
  export type { Position } from "../vendor/@akanjs/native/plugins/geolocation/src/index.ts";
14
36
  export { haptics } from "../vendor/@akanjs/native/plugins/haptics/src/index.ts";
15
37
  export type { IapProduct, IapTransaction } from "../vendor/@akanjs/native/plugins/iap/src/index.ts";
@@ -23,6 +45,11 @@ export type {
23
45
  } from "../vendor/@akanjs/native/plugins/push/src/index.ts";
24
46
  export { push } from "../vendor/@akanjs/native/plugins/push/src/index.ts";
25
47
  export { secureStorage } from "../vendor/@akanjs/native/plugins/secure-storage/src/index.ts";
48
+ export type { UpdateCheck, UpdateProgress, UpdateState } from "../vendor/@akanjs/native/plugins/updates/src/index.ts";
49
+ export { markReady, updates, useUpdateState } from "../vendor/@akanjs/native/plugins/updates/src/index.ts";
50
+ export type { VolumeState } from "../vendor/@akanjs/native/plugins/volume/src/index.ts";
51
+ export { volume } from "../vendor/@akanjs/native/plugins/volume/src/index.ts";
52
+ export { useLiveValue, usePluginEvent } from "../vendor/@akanjs/native/packages/react/src/index.ts";
26
53
  export { browser, opener };
27
54
 
28
55
  export const loadCamera = () => import("../vendor/@akanjs/native/plugins/camera/src/index.ts");
@@ -33,6 +60,9 @@ export const loadIap = () => import("../vendor/@akanjs/native/plugins/iap/src/in
33
60
  /** Inside an iOS or Android shell of the native runtime; a mobile target opened in a browser is not. */
34
61
  export const isNativeApp = () => isNative && (platform === "ios" || platform === "android");
35
62
 
63
+ /** Inside any shell of the native runtime, desktop included. */
64
+ export const isNativeShell = () => isNative;
65
+
36
66
  export const nativePlatform = () => (isNativeApp() ? (platform as "ios" | "android") : null);
37
67
 
38
68
  export const desktopPlatform = () =>
@@ -0,0 +1,11 @@
1
+ import { getEnv } from "akanjs/base";
2
+
3
+ export const resolveServerUrl = (url: string): string => {
4
+ if (!url.startsWith("/") || url.startsWith("//")) return url;
5
+ const env = getEnv();
6
+ if (env.side !== "client" || env.renderMode !== "csr") return url;
7
+ if (url !== env.apiPrefix && !url.startsWith(`${env.apiPrefix}/`)) return url;
8
+ const server = new URL(env.serverHttpUri);
9
+ const serverOrigin = `${server.protocol}//${server.host}`;
10
+ return serverOrigin === `${window.location.protocol}//${window.location.host}` ? url : `${serverOrigin}${url}`;
11
+ };
package/client/router.ts CHANGED
@@ -160,6 +160,7 @@ class Router {
160
160
  #indexPath = "/";
161
161
  #navigation: Promise<void> = Promise.resolve();
162
162
  #historyIdx = 0;
163
+ #redirects = 0;
163
164
  #instance: RouterInstance = {
164
165
  push: (href: string) => {
165
166
  const { href: fullHref } = this.#getPathInfo(href);
@@ -407,6 +408,11 @@ class Router {
407
408
  this.#instance.refresh();
408
409
  return undefined as never;
409
410
  }
411
+ /** Client-side redirects so far: a render that saw this change while it ran redirected instead of drawing. A method
412
+ * for the reason `navigation()` is one. */
413
+ redirectCount(): number {
414
+ return this.#redirects;
415
+ }
410
416
  redirect(href: string, options: RedirectOptions = {}): never {
411
417
  const method = options.method ?? "replace";
412
418
  const status = options.status ?? 307;
@@ -422,6 +428,7 @@ class Router {
422
428
  Logger.info(`redirect to:${pathname}`);
423
429
  throw new AkanRedirectError(fullHref, method, status);
424
430
  } else {
431
+ this.#redirects += 1;
425
432
  this.#instance[method](href);
426
433
  }
427
434
  return undefined as never;
@@ -432,6 +439,7 @@ class Router {
432
439
  throw new AkanNotFoundError();
433
440
  }
434
441
  this.#checkInitialized();
442
+ this.#redirects += 1;
435
443
  this.#instance.replace("/404");
436
444
  return undefined as never;
437
445
  }
package/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { AkanNativeConfig } from "./vendor/@akanjs/native/packages/cli/src/config.ts";
1
2
  import type { AkanI18nConfig } from "akanjs/common";
2
3
  import type { AkanImageConfig } from "akanjs/server";
3
4
 
@@ -27,6 +28,41 @@ export interface LibDockerConfig {
27
28
  postRuns: DockerRun[];
28
29
  }
29
30
 
31
+ /** `${process.platform}-${process.arch}` of the computer a desktop app is built on, which is the one it runs on. */
32
+ export const binPlatforms = [
33
+ "darwin-arm64",
34
+ "darwin-x64",
35
+ "linux-arm64",
36
+ "linux-x64",
37
+ "win32-arm64",
38
+ "win32-x64",
39
+ ] as const;
40
+ export type BinPlatform = (typeof binPlatforms)[number];
41
+
42
+ /** Downloaded when the desktop app is built; the file must hash to `sha256`, so plain http is as safe as https. */
43
+ export interface AkanBinUrlSource {
44
+ url: string;
45
+ sha256: string;
46
+ /** The executable inside the archive `url` names (.zip, .tar.gz, .tgz, .tar.xz, .tar.bz2, .tar). */
47
+ file?: string;
48
+ }
49
+
50
+ /** A file on the building computer, relative to the `akan.config.ts` that declares it. */
51
+ export interface AkanBinPathSource {
52
+ path: string;
53
+ /** The executable inside the archive `path` names. */
54
+ file?: string;
55
+ }
56
+
57
+ export type AkanBinSource = AkanBinUrlSource | AkanBinPathSource;
58
+
59
+ /**
60
+ * Executables a desktop app carries, by the name its code spawns and then by platform. Their folder comes first on
61
+ * the app's PATH, so the carried server's `spawn("ffmpeg")` runs the carried file; a native plugin finds it in
62
+ * `ctx.binDir`.
63
+ */
64
+ export type AkanBinConfig = Record<string, { [platform in BinPlatform]?: AkanBinSource }>;
65
+
30
66
  export interface AkanRouteDomains {
31
67
  main?: string[];
32
68
  develop?: string[];
@@ -67,8 +103,10 @@ export type MobileEnv = "local" | "debug" | "develop" | "main";
67
103
  export type MobilePermission = "camera" | "contacts" | "location" | "push" | "speech";
68
104
 
69
105
  export interface AkanMobileTargetAssets {
70
- icon?: string;
71
- splash?: string;
106
+ /** A square PNG, relative to the app folder, or it with the color behind its transparent areas. */
107
+ icon?: string | { image: string; backgroundColor?: string };
108
+ /** A PNG shown centered at launch, or the launch screen's color, image and when it hides. */
109
+ splash?: string | NonNullable<AkanNativeConfig["splash"]>;
72
110
  }
73
111
 
74
112
  export interface AkanMobileTargetDeepLinks {
@@ -106,15 +144,72 @@ export interface AkanMobileNativeConfig {
106
144
  activity?: string[];
107
145
  /** The Firebase project's google-services.json, relative to the app folder, for FCM push on Android. */
108
146
  googleServices?: string;
147
+ /** Media plays with sound without a tap first, as it does on iOS and the desktop: a signage screen. */
148
+ autoplay?: boolean;
149
+ };
150
+ /** Android's notification channel, status bar icon (relative to the app folder) and accent color. */
151
+ push?: AkanNativeConfig["push"];
152
+ /** The app's part of the iOS privacy manifest (PrivacyInfo.xcprivacy), which an App Store upload requires. */
153
+ privacy?: AkanNativeConfig["privacy"];
154
+ desktop?: {
155
+ /**
156
+ * The desktop app carries the app's server (API only, database mode single, on loopback) and its pages call
157
+ * nothing else. `build-desktop`, `start-desktop` and `publish-update` all read it, and an installed app refuses
158
+ * a release that carries a server when it has none, or none when it has one.
159
+ */
160
+ server?: boolean;
161
+ /**
162
+ * `"reload"`: a window whose page's process ends (a crash, a hang) loads it again every time, waiting
163
+ * longer after each end in a row, and the app relaunches when the webview's browser process ends — for an
164
+ * app nobody attends. `"errorPage"` (default): one reload, then an error page, and a quit for the browser.
165
+ */
166
+ recovery?: "errorPage" | "reload";
167
+ /** The main window from its first frame: borderless fullscreen, and no taskbar button (Windows, Linux). */
168
+ window?: { fullscreen?: boolean; skipTaskbar?: boolean };
169
+ /**
170
+ * Windows: `"auto"` answers getDisplayMedia() with the first screen at once, no picker or gesture — remote
171
+ * support on an unattended screen; it covers every media request, so not for an app that asks for a camera.
172
+ */
173
+ screenCapture?: "picker" | "auto";
109
174
  };
110
175
  }
111
176
 
177
+ /**
178
+ * Where an installed app looks for newer releases of itself (the native runtime's updates plugin): the whole app on a
179
+ * desktop, the web bundle on a phone. `akan publish-update` writes and signs a release with a key on this machine;
180
+ * `akan pack-update` writes an unsigned phone bundle for whoever holds the key to sign.
181
+ */
182
+ export interface AkanMobileUpdatesConfig {
183
+ /**
184
+ * A static base URL, https in a release build: `<url>/<os>-<arch>/<channel>.json` (desktop) or `<url>/<platform>/…`
185
+ * (a phone's web bundle).
186
+ */
187
+ url: string;
188
+ /** The update key's public half, the raw 32-byte Ed25519 key in base64 (`akan update-keygen` prints it). */
189
+ publicKey: string;
190
+ /**
191
+ * The manifest the app follows, e.g. a "pilot" target's "pilot". Default: the backend env the app is built for
192
+ * (`main`, `develop`, `debug`, `local`).
193
+ */
194
+ channel?: string;
195
+ /** How long a newly applied release has to call notifyReady() before it is rolled back, ms. Default 10000. */
196
+ readyTimeout?: number;
197
+ }
198
+
199
+ /**
200
+ * One bundle id, or one per platform, for an app whose store listings already carry different ids. A platform without
201
+ * its own takes `default`.
202
+ */
203
+ export type AkanMobileAppId =
204
+ | string
205
+ | { default?: string; ios?: string; android?: string; macos?: string; windows?: string; linux?: string };
206
+
112
207
  export interface AkanMobileTargetConfig {
113
208
  name: string;
114
209
  basePath?: string;
115
210
  indexPath?: string;
116
211
  appName: string;
117
- appId: string;
212
+ appId: AkanMobileAppId;
118
213
  /** Executables, archives and the Swift module; letters, digits, `.`, `_` and `-`. Default: the app's folder name. */
119
214
  fileName?: string;
120
215
  version: string;
@@ -124,16 +219,19 @@ export interface AkanMobileTargetConfig {
124
219
  deepLinks?: AkanMobileTargetDeepLinks;
125
220
  files?: AkanMobileTargetFiles;
126
221
  native?: AkanMobileNativeConfig;
222
+ /** Over mobile.updates, field by field: a pilot target names its own channel. */
223
+ updates?: Partial<AkanMobileUpdatesConfig>;
127
224
  }
128
225
 
129
226
  export interface AkanMobileConfig {
130
227
  appName: string;
131
- appId: string;
228
+ appId: AkanMobileAppId;
132
229
  fileName?: string;
133
230
  version: string;
134
231
  buildNum: number;
135
232
  files?: AkanMobileTargetFiles;
136
233
  native?: AkanMobileNativeConfig;
234
+ updates?: AkanMobileUpdatesConfig;
137
235
  targets: Record<string, AkanMobileTargetConfig>;
138
236
  }
139
237
 
@@ -228,6 +326,10 @@ export interface AppConfigResult {
228
326
  */
229
327
  syncPageLibs?: string[] | boolean;
230
328
  externalLibs: string[];
329
+ /** Dependencies whose install scripts `bun install --production` runs, in the image and in a desktop app's server. */
330
+ trustedDependencies: string[];
331
+ /** Every desktop build, run and dev session carries these, server or not; the image installs through `docker`. */
332
+ bin: AkanBinConfig;
231
333
  barrelImports: string[];
232
334
  optimizeImports: string[];
233
335
  images: AkanImageConfig;
@@ -240,6 +342,9 @@ export interface AppConfigResult {
240
342
 
241
343
  export interface LibConfigResult {
242
344
  externalLibs: string[];
345
+ trustedDependencies: string[];
346
+ /** Carried by the desktop app of every app that depends on this lib; an app's own entry of the same name wins. */
347
+ bin: AkanBinConfig;
243
348
  /** Image steps every app that mounts this lib inherits, unless that app declares a whole Dockerfile. */
244
349
  docker: LibDockerConfig;
245
350
  /** Which of this lib's own public fonts every app that mounts it must keep. */
@@ -260,12 +365,16 @@ export interface LibConfigContext {
260
365
  readonly type: "lib";
261
366
  }
262
367
 
263
- export type AppConfigInput = Omit<DeepPartial<AppConfigResult>, "docker" | "web"> & {
368
+ export type AppConfigInput = Omit<DeepPartial<AppConfigResult>, "docker" | "web" | "bin"> & {
264
369
  docker?: DockerOption;
265
370
  web?: AkanWebOption;
371
+ bin?: AkanBinConfig;
372
+ plugins?: AkanPlugin[];
373
+ };
374
+ export type LibConfigInput = Omit<DeepPartial<LibConfigResult>, "bin"> & {
375
+ bin?: AkanBinConfig;
266
376
  plugins?: AkanPlugin[];
267
377
  };
268
- export type LibConfigInput = DeepPartial<LibConfigResult> & { plugins?: AkanPlugin[] };
269
378
  export interface SubspaceDeclaration {
270
379
  /** Short name used on the command line and as the git remote suffix. */
271
380
  name: string;
@@ -0,0 +1,5 @@
1
+
2
+
3
+ export { AkanNativeError, mimeFor } from "../vendor/@akanjs/native/packages/core/src/index.ts";
4
+ export type { DesktopContext, DesktopPlugin, NativeEvent } from "../vendor/@akanjs/native/packages/desktop/src/plugin.ts";
5
+ export { createPageVeto, defineDesktopPlugin, externalOpenAllowed } from "../vendor/@akanjs/native/packages/desktop/src/plugin.ts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akanjs",
3
- "version": "3.0.0-beta.27",
3
+ "version": "3.0.0-beta.28",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -95,6 +95,16 @@
95
95
  "import": "./client/native.ts",
96
96
  "default": "./client/native.ts"
97
97
  },
98
+ "./client/native/*": {
99
+ "types": "./types/client/native/*.d.ts",
100
+ "import": "./client/native/*.ts",
101
+ "default": "./client/native/*.ts"
102
+ },
103
+ "./native/desktop": {
104
+ "types": "./types/native/desktop.d.ts",
105
+ "import": "./native/desktop.ts",
106
+ "default": "./native/desktop.ts"
107
+ },
98
108
  "./webkit": {
99
109
  "types": "./types/webkit/index.d.ts",
100
110
  "import": "./webkit/index.ts",