akanjs 3.0.0-beta.23 → 3.0.0-beta.24
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/client/csrTypes.ts +27 -1
- package/client/native.ts +3 -0
- package/client/route/RouteDefinition.ts +41 -1
- package/package.json +16 -6
- package/server/akanApp.ts +2 -3
- package/server/artifact/builderRpc.ts +5 -0
- package/server/artifact/ipcTypes.ts +10 -0
- package/server/hmr/clientScript.ts +31 -2
- package/server/hmr/csrDevManifest.ts +25 -0
- package/server/hmr/csrDevRuntime.ts +474 -0
- package/server/hmr/csrDevShell.ts +111 -0
- package/server/hmr/csrDevSourceMap.ts +142 -0
- package/server/hmr/devHmrController.ts +33 -16
- package/server/hmr/runtimeMetadataFile.ts +17 -0
- package/server/hmr/wsHub.ts +30 -4
- package/server/routing/apiRouter.ts +2 -0
- package/server/types.tsx +2 -0
- package/server/vendor/react-dom.ts +1 -0
- package/server/vendor/react-refresh-runtime.ts +13 -1
- package/server/vendor/react.ts +2 -0
- package/server/webRouter.ts +32 -2
- package/store/agent/ScreenTarget.ts +1 -2
- package/store/agent/StoreSurfaceSource.ts +3 -1
- package/store/storeInstance.ts +28 -21
- package/types/client/csrTypes.d.ts +22 -1
- package/types/client/native.d.ts +1 -0
- package/types/client/route/RouteDefinition.d.ts +14 -0
- package/types/server/artifact/builderRpc.d.ts +2 -1
- package/types/server/artifact/ipcTypes.d.ts +11 -0
- package/types/server/hmr/csrDevManifest.d.ts +18 -0
- package/types/server/hmr/csrDevRuntime.d.ts +71 -0
- package/types/server/hmr/csrDevShell.d.ts +14 -0
- package/types/server/hmr/csrDevSourceMap.d.ts +17 -0
- package/types/server/hmr/devHmrController.d.ts +2 -1
- package/types/server/hmr/runtimeMetadataFile.d.ts +1 -0
- package/types/server/hmr/wsHub.d.ts +11 -0
- package/types/server/routing/apiRouter.d.ts +1 -0
- package/types/server/types.d.ts +2 -0
- package/types/server/vendor/react-dom.d.ts +1 -1
- package/types/server/vendor/react-refresh-runtime.d.ts +1 -1
- package/types/server/vendor/react.d.ts +1 -1
- package/types/store/storeInstance.d.ts +4 -3
- package/types/ui/System/Client.d.ts +5 -3
- package/types/vendor/@akanjs/native/plugins/app/src/index.d.ts +17 -0
- package/types/vendor/@akanjs/native/plugins/app-state/src/index.d.ts +6 -0
- package/types/vendor/use-agentic/AgentActivity.d.ts +11 -0
- package/types/vendor/use-agentic/AgentGate.d.ts +10 -0
- package/types/vendor/use-agentic/AgenticSurface.d.ts +15 -5
- package/types/vendor/use-agentic/index.d.ts +2 -0
- package/types/vendor/use-agentic/surfaceContext.d.ts +3 -0
- package/types/webkit/CsrRouteTable.d.ts +32 -0
- package/types/webkit/CsrStack.d.ts +45 -0
- package/types/webkit/RenderLayer.d.ts +2 -2
- package/types/webkit/bootCsr.d.ts +7 -8
- package/types/webkit/index.d.ts +4 -1
- package/types/webkit/nativeNavigation.d.ts +13 -0
- package/types/webkit/useCsrValues.d.ts +6 -4
- package/types/webkit/useFetch.d.ts +3 -1
- package/types/webkit/useHistory.d.ts +5 -1
- package/types/webkit/usePageActivity.d.ts +2 -0
- package/types/webkit/usePageFocusEffect.d.ts +7 -0
- package/types/webkit/usePageLocation.d.ts +13 -0
- package/ui/Data/Dashboard.tsx +2 -2
- package/ui/Data/ListContainer.tsx +2 -2
- package/ui/Layout/BottomInset.tsx +1 -1
- package/ui/Layout/Navbar.tsx +1 -1
- package/ui/Layout/TopInset.tsx +4 -3
- package/ui/System/CSR.tsx +40 -79
- package/ui/System/Client.tsx +28 -13
- package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativeActivity.kt +53 -9
- package/vendor/@akanjs/native/native/android/src/com/akanjs/runtime/AkanNativePlugin.kt +16 -0
- package/vendor/@akanjs/native/plugins/app/android/AppPlugin.kt +20 -0
- package/vendor/@akanjs/native/plugins/app/native-plugin.json +4 -4
- package/vendor/@akanjs/native/plugins/app/src/desktop.ts +3 -0
- package/vendor/@akanjs/native/plugins/app/src/index.ts +14 -2
- package/vendor/@akanjs/native/plugins/app-state/android/AppStatePlugin.kt +38 -2
- package/vendor/@akanjs/native/plugins/app-state/ios/AppStatePlugin.swift +19 -0
- package/vendor/@akanjs/native/plugins/app-state/native-plugin.json +1 -1
- package/vendor/@akanjs/native/plugins/app-state/src/index.ts +6 -1
- package/vendor/use-agentic/AgentActivity.tsx +26 -0
- package/vendor/use-agentic/AgentGate.ts +25 -0
- package/vendor/use-agentic/AgenticSurface.ts +92 -34
- package/vendor/use-agentic/index.ts +2 -0
- package/vendor/use-agentic/surfaceContext.ts +3 -0
- package/webkit/CsrRouteTable.ts +298 -0
- package/webkit/CsrStack.ts +98 -0
- package/webkit/RenderLayer.tsx +30 -8
- package/webkit/bootCsr.tsx +13 -217
- package/webkit/index.ts +4 -1
- package/webkit/nativeNavigation.ts +78 -5
- package/webkit/useCsrValues.ts +118 -22
- package/webkit/useFetch.ts +9 -2
- package/webkit/useHistory.ts +23 -6
- package/webkit/useLocation.ts +6 -3
- package/webkit/usePageActivity.ts +6 -0
- package/webkit/usePageFocusEffect.ts +13 -0
- package/webkit/usePageLocation.ts +17 -0
package/client/csrTypes.ts
CHANGED
|
@@ -103,6 +103,9 @@ export type LayoutErrorRender = (props: LayoutErrorProps) => PromiseOrObject<Rea
|
|
|
103
103
|
export interface RouteRender {
|
|
104
104
|
render: LayoutRender | PageRender;
|
|
105
105
|
isAsync?: boolean;
|
|
106
|
+
/** CSR: a page's render reads the query; a layout's reads only the params of its own path (`paramNames`). */
|
|
107
|
+
kind?: "page" | "layout";
|
|
108
|
+
paramNames?: string[];
|
|
106
109
|
Loading?: LayoutLoadingRender | PageLoadingRender;
|
|
107
110
|
/** Loads the module and fills `Loading` without running `render`/`resolveHead` (the suffix compose path). */
|
|
108
111
|
resolveLoading?: () => void | Promise<void>;
|
|
@@ -221,6 +224,7 @@ export interface Location {
|
|
|
221
224
|
searchParams: { [key: string]: string | string[] };
|
|
222
225
|
pathRoute: PathRoute;
|
|
223
226
|
hash: string;
|
|
227
|
+
entryId?: string;
|
|
224
228
|
}
|
|
225
229
|
export type CsrNavigationPhase = "idle" | "preparing" | "transitioning";
|
|
226
230
|
export type CsrNavigationKind = "push" | "replace" | "back" | "popForward" | "popBack";
|
|
@@ -247,6 +251,7 @@ export interface History {
|
|
|
247
251
|
idxMap: Map<string, number>;
|
|
248
252
|
cachedLocationMap: Map<string, Location>;
|
|
249
253
|
idx: number;
|
|
254
|
+
dormant?: Set<string>;
|
|
250
255
|
}
|
|
251
256
|
|
|
252
257
|
export interface RouterProps {
|
|
@@ -256,14 +261,24 @@ export interface RouterProps {
|
|
|
256
261
|
back: () => void | Promise<void>;
|
|
257
262
|
}
|
|
258
263
|
|
|
264
|
+
export type CsrPageType = "current" | "prev" | "pending" | "cached";
|
|
265
|
+
export interface CsrStackEntry {
|
|
266
|
+
key: string;
|
|
267
|
+
location: Location;
|
|
268
|
+
pageType: CsrPageType;
|
|
269
|
+
zIndex: number;
|
|
270
|
+
}
|
|
271
|
+
|
|
259
272
|
export interface RouteState {
|
|
260
273
|
clientWidth: number;
|
|
261
274
|
clientHeight: number;
|
|
262
275
|
location: Location;
|
|
263
276
|
prevLocation: Location | null;
|
|
264
277
|
pendingLocation: Location | null;
|
|
278
|
+
stackEntries: CsrStackEntry[];
|
|
265
279
|
navigationIntent: NavigationIntent | null;
|
|
266
280
|
phase: CsrNavigationPhase;
|
|
281
|
+
isBackgrounded: boolean;
|
|
267
282
|
history: RefObject<History>;
|
|
268
283
|
topSafeAreaRef: RefObject<HTMLDivElement | null>;
|
|
269
284
|
bottomSafeAreaRef: RefObject<HTMLDivElement | null>;
|
|
@@ -304,7 +319,8 @@ export const useCsr = () => {
|
|
|
304
319
|
};
|
|
305
320
|
|
|
306
321
|
export interface PathContextType {
|
|
307
|
-
pageType:
|
|
322
|
+
pageType: CsrPageType;
|
|
323
|
+
pageKey?: string;
|
|
308
324
|
location: Location;
|
|
309
325
|
prefix?: string;
|
|
310
326
|
gestureEnabled: boolean;
|
|
@@ -317,6 +333,16 @@ export const usePathCtx = () => {
|
|
|
317
333
|
return contextValues;
|
|
318
334
|
};
|
|
319
335
|
|
|
336
|
+
export type PageActivity = "current" | "prev" | "pending" | "hidden";
|
|
337
|
+
export interface PageActivityState {
|
|
338
|
+
activity: PageActivity;
|
|
339
|
+
focused: boolean;
|
|
340
|
+
}
|
|
341
|
+
export const pageActivityContext = sharedContext<PageActivityState>("pageActivity", {
|
|
342
|
+
activity: "current",
|
|
343
|
+
focused: true,
|
|
344
|
+
});
|
|
345
|
+
|
|
320
346
|
export interface PathRoute {
|
|
321
347
|
path: string;
|
|
322
348
|
pathSegments: string[];
|
package/client/native.ts
CHANGED
|
@@ -35,6 +35,9 @@ export const isNativeApp = () => isNative && (platform === "ios" || platform ===
|
|
|
35
35
|
|
|
36
36
|
export const nativePlatform = () => (isNativeApp() ? (platform as "ios" | "android") : null);
|
|
37
37
|
|
|
38
|
+
export const desktopPlatform = () =>
|
|
39
|
+
isNative && (platform === "macos" || platform === "windows" || platform === "linux") ? platform : null;
|
|
40
|
+
|
|
38
41
|
/** http(s) in the in-app browser, anything else (mailto:, tel:) in the app the system picks. */
|
|
39
42
|
export const openExternalUrl = async (url: string) => {
|
|
40
43
|
if (!isNativeApp()) {
|
|
@@ -17,6 +17,8 @@ export type RouteArgsShape = Record<string, unknown>;
|
|
|
17
17
|
export type RouteKind = "page" | "layout" | "rootLayout";
|
|
18
18
|
/** Interned: a definition built inside the pages bundle must be recognised by a loader bundled apart from it. */
|
|
19
19
|
export const routeDefinitionMarker = Symbol.for("akan.routeDefinition");
|
|
20
|
+
/** Interned like the marker: the declared args ride on the module's render function, read by the CSR render cache. */
|
|
21
|
+
export const routeArgsMarker = Symbol.for("akan.routeArgs");
|
|
20
22
|
|
|
21
23
|
type HeadStage<Args> = Head | ((args: Args) => PromiseOrObject<Head | null | undefined>);
|
|
22
24
|
|
|
@@ -44,6 +46,11 @@ export abstract class RouteDefinition<
|
|
|
44
46
|
#head?: HeadStage<never>;
|
|
45
47
|
#loading?: (args: never) => PromiseOrObject<ReactNode>;
|
|
46
48
|
#render?: (args: never) => PromiseOrObject<ReactNode>;
|
|
49
|
+
#renderRoute?: {
|
|
50
|
+
render: (args: never) => PromiseOrObject<ReactNode>;
|
|
51
|
+
argCount: number;
|
|
52
|
+
route: (props: RouteRenderProps) => Promise<ReactNode>;
|
|
53
|
+
};
|
|
47
54
|
|
|
48
55
|
config(config: PageConfig) {
|
|
49
56
|
this.#config = config;
|
|
@@ -122,7 +129,7 @@ export abstract class RouteDefinition<
|
|
|
122
129
|
const head = this.#head;
|
|
123
130
|
const loading = this.#loading;
|
|
124
131
|
const module: PageModule & LayoutModule = {
|
|
125
|
-
default:
|
|
132
|
+
default: this.#renderRouteOf(render) as never,
|
|
126
133
|
...(this.#config ? { pageConfig: this.#config } : {}),
|
|
127
134
|
...(head === undefined
|
|
128
135
|
? {}
|
|
@@ -143,6 +150,39 @@ export abstract class RouteDefinition<
|
|
|
143
150
|
return module;
|
|
144
151
|
}
|
|
145
152
|
|
|
153
|
+
#renderRouteOf(render: (args: never) => PromiseOrObject<ReactNode>) {
|
|
154
|
+
const kept = this.#renderRoute;
|
|
155
|
+
if (kept?.render === render && kept.argCount === this.args.length) return kept.route;
|
|
156
|
+
const route = async (props: RouteRenderProps) => await render(this.#argsOf(props) as never);
|
|
157
|
+
Object.defineProperty(route, routeArgsMarker, { value: this.args.map(({ kind, name }) => ({ kind, name })) });
|
|
158
|
+
this.#renderRoute = { render, argCount: this.args.length, route };
|
|
159
|
+
return route;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* What a route's render output depends on: a chain's declared args plus `lang`. A legacy module declares nothing,
|
|
164
|
+
* so it depends on the params of its own path (`paramNames`, every param when unknown) and, for a page, every
|
|
165
|
+
* search value — a layout reads no query.
|
|
166
|
+
*/
|
|
167
|
+
static renderArgsKey(
|
|
168
|
+
render: unknown,
|
|
169
|
+
props: { params: Record<string, string>; searchParams?: Record<string, string | string[]> },
|
|
170
|
+
{ isPage, paramNames }: { isPage: boolean; paramNames?: string[] },
|
|
171
|
+
): string {
|
|
172
|
+
const declared = (render as { [routeArgsMarker]?: Pick<RouteArgInfo, "kind" | "name">[] } | null)?.[
|
|
173
|
+
routeArgsMarker
|
|
174
|
+
];
|
|
175
|
+
const searchParams = props.searchParams ?? {};
|
|
176
|
+
if (!declared) {
|
|
177
|
+
const params = paramNames ? paramNames.map((name) => props.params[name]) : props.params;
|
|
178
|
+
return JSON.stringify([params, isPage ? searchParams : null]);
|
|
179
|
+
}
|
|
180
|
+
return JSON.stringify([
|
|
181
|
+
props.params.lang,
|
|
182
|
+
...declared.map(({ kind, name }) => (kind === "param" ? props.params[name] : searchParams[name])),
|
|
183
|
+
]);
|
|
184
|
+
}
|
|
185
|
+
|
|
146
186
|
#argsOf(props: RouteRenderProps): RouteBaseArgs & Args & Extra {
|
|
147
187
|
const { lang = parseAkanI18nEnv().defaultLocale } = props.params;
|
|
148
188
|
const resolved = this.resolveArgs({ params: props.params, searchParams: props.searchParams ?? {} });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akanjs",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.24",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -200,6 +200,16 @@
|
|
|
200
200
|
"types": "./types/server/logging/logTailClient.d.ts",
|
|
201
201
|
"import": "./server/logging/logTailClient.ts",
|
|
202
202
|
"default": "./server/logging/logTailClient.ts"
|
|
203
|
+
},
|
|
204
|
+
"./server/hmr/csrDevManifest": {
|
|
205
|
+
"types": "./types/server/hmr/csrDevManifest.d.ts",
|
|
206
|
+
"import": "./server/hmr/csrDevManifest.ts",
|
|
207
|
+
"default": "./server/hmr/csrDevManifest.ts"
|
|
208
|
+
},
|
|
209
|
+
"./server/hmr/runtimeMetadataFile": {
|
|
210
|
+
"types": "./types/server/hmr/runtimeMetadataFile.d.ts",
|
|
211
|
+
"import": "./server/hmr/runtimeMetadataFile.ts",
|
|
212
|
+
"default": "./server/hmr/runtimeMetadataFile.ts"
|
|
203
213
|
}
|
|
204
214
|
},
|
|
205
215
|
"dependencies": {
|
|
@@ -224,13 +234,13 @@
|
|
|
224
234
|
"ioredis": "^5.10.1",
|
|
225
235
|
"postgres": "^3.4.9",
|
|
226
236
|
"protobufjs": "^8.4.0",
|
|
227
|
-
"react": "19.
|
|
228
|
-
"react-dom": "19.
|
|
237
|
+
"react": "19.3.0",
|
|
238
|
+
"react-dom": "19.3.0",
|
|
229
239
|
"react-icons": "^5.6.0",
|
|
230
|
-
"react-refresh": "^0.
|
|
231
|
-
"react-server-dom-webpack": "^19.
|
|
240
|
+
"react-refresh": "^0.19.0",
|
|
241
|
+
"react-server-dom-webpack": "^19.3.0",
|
|
232
242
|
"react-spring": "^10.0.4",
|
|
233
|
-
"scheduler": "^0.
|
|
243
|
+
"scheduler": "^0.28.0",
|
|
234
244
|
"tailwind-scrollbar": "^4.0.2",
|
|
235
245
|
"typescript": "^6.0.3"
|
|
236
246
|
},
|
package/server/akanApp.ts
CHANGED
|
@@ -762,9 +762,7 @@ export class AkanApp {
|
|
|
762
762
|
return await this.#proxyResponse(req, upstreamRes);
|
|
763
763
|
} catch (error) {
|
|
764
764
|
if (AkanApp.#isUpstreamOpenFailure(error)) {
|
|
765
|
-
this.logger.error(
|
|
766
|
-
`Child ${child.idx}/${child.role} upstream is unreachable (${socketPath}); restarting`,
|
|
767
|
-
);
|
|
765
|
+
this.logger.error(`Child ${child.idx}/${child.role} upstream is unreachable (${socketPath}); restarting`);
|
|
768
766
|
this.#scheduleChildRestart(child, child.proc, "upstream-open-failed");
|
|
769
767
|
return AkanApp.#unavailableResponse(req, "Federation child upstream is unreachable; restarting");
|
|
770
768
|
}
|
|
@@ -1055,6 +1053,7 @@ export class AkanApp {
|
|
|
1055
1053
|
case "invalidate":
|
|
1056
1054
|
case "css-updated":
|
|
1057
1055
|
case "pages-updated":
|
|
1056
|
+
case "csr-updated":
|
|
1058
1057
|
case "build-status":
|
|
1059
1058
|
this.#fanoutToFederation(message);
|
|
1060
1059
|
return;
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
BuilderRes,
|
|
9
9
|
BuildRouteClientResult,
|
|
10
10
|
BuildRouteResultPayload,
|
|
11
|
+
CsrUpdatedPayload,
|
|
11
12
|
CssPayload,
|
|
12
13
|
DevBuildStatus,
|
|
13
14
|
PagesBundlePayload,
|
|
@@ -19,6 +20,7 @@ export interface BuilderRpcEventHandlers {
|
|
|
19
20
|
onCssUpdated?: (css: CssPayload) => void;
|
|
20
21
|
/** A fresh `pages-*.js` bundle: re-import it in the running worker (`RscWorker.reload`) rather than respawning. */
|
|
21
22
|
onPagesUpdated?: (bundle: PagesBundlePayload) => void;
|
|
23
|
+
onCsrUpdated?: (update: CsrUpdatedPayload) => void;
|
|
22
24
|
onBuildStatus?: (status: DevBuildStatus) => void;
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -59,6 +61,9 @@ export class BuilderRpc {
|
|
|
59
61
|
case "pages-updated":
|
|
60
62
|
handlers.onPagesUpdated?.(ev.data);
|
|
61
63
|
return;
|
|
64
|
+
case "csr-updated":
|
|
65
|
+
handlers.onCsrUpdated?.(ev.data);
|
|
66
|
+
return;
|
|
62
67
|
case "build-status":
|
|
63
68
|
handlers.onBuildStatus?.(ev.data);
|
|
64
69
|
return;
|
|
@@ -94,6 +94,15 @@ export interface BuilderMetrics {
|
|
|
94
94
|
workCount: number;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
export interface CsrUpdatedPayload {
|
|
98
|
+
generation: number;
|
|
99
|
+
mode: "registry" | "artifact";
|
|
100
|
+
reload: boolean;
|
|
101
|
+
reason?: string;
|
|
102
|
+
patchUrl?: string;
|
|
103
|
+
changedIds?: string[];
|
|
104
|
+
}
|
|
105
|
+
|
|
97
106
|
export type BuilderEvent =
|
|
98
107
|
|
|
99
108
|
| { type: "builder-ready"; buildId?: string }
|
|
@@ -107,6 +116,7 @@ export type BuilderEvent =
|
|
|
107
116
|
}
|
|
108
117
|
| { type: "css-updated"; data: CssPayload }
|
|
109
118
|
| { type: "pages-updated"; data: PagesBundlePayload }
|
|
119
|
+
| { type: "csr-updated"; data: CsrUpdatedPayload }
|
|
110
120
|
| { type: "build-status"; data: DevBuildStatus }
|
|
111
121
|
| { type: "builder-metrics"; data: BuilderMetrics };
|
|
112
122
|
|
|
@@ -5,8 +5,9 @@ export const HMR_CLIENT_SCRIPT = `(function(){
|
|
|
5
5
|
self.__AKAN_HMR_INSTALLED__ = true;
|
|
6
6
|
var syncNavigationEnabled = ${JSON.stringify(isSyncNavigationEnabled())};
|
|
7
7
|
var syncNavigationClientId = Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
8
|
+
var clientKind = self.__AKAN_HMR_CLIENT__ === "csr" ? "csr" : "ssr";
|
|
8
9
|
var proto = location.protocol === "https:" ? "wss:" : "ws:";
|
|
9
|
-
var url = proto + "//" + location.host + "/_akan/hmr";
|
|
10
|
+
var url = proto + "//" + location.host + "/_akan/hmr" + (clientKind === "csr" ? "?client=csr" : "");
|
|
10
11
|
var attempts = 0;
|
|
11
12
|
var socket = null;
|
|
12
13
|
var lastBuildId = null;
|
|
@@ -43,7 +44,7 @@ export const HMR_CLIENT_SCRIPT = `(function(){
|
|
|
43
44
|
else pendingRefreshRegistrations.push([type, id]);
|
|
44
45
|
};
|
|
45
46
|
self.$RefreshSig$ = self.$RefreshSig$ || function(){ return function(type){ return type; }; };
|
|
46
|
-
ensureRefreshRuntime().catch(function(err){
|
|
47
|
+
if (clientKind === "ssr") ensureRefreshRuntime().catch(function(err){
|
|
47
48
|
console.warn("[akan-hmr] React Refresh runtime preload failed", err);
|
|
48
49
|
});
|
|
49
50
|
|
|
@@ -56,6 +57,10 @@ export const HMR_CLIENT_SCRIPT = `(function(){
|
|
|
56
57
|
try { msg = JSON.parse(ev.data); } catch (e){ return; }
|
|
57
58
|
if (!msg || typeof msg.type !== "string") return;
|
|
58
59
|
if (msg.type === "hello") {
|
|
60
|
+
if (clientKind === "csr") {
|
|
61
|
+
if (csrGenerationMoved(msg.csrGeneration)) reloadForCsr("missed a CSR update while disconnected");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
59
64
|
if (lastBuildId !== null && msg.buildId !== lastBuildId) {
|
|
60
65
|
location.reload();
|
|
61
66
|
return;
|
|
@@ -77,6 +82,10 @@ export const HMR_CLIENT_SCRIPT = `(function(){
|
|
|
77
82
|
refreshClient(msg);
|
|
78
83
|
return;
|
|
79
84
|
}
|
|
85
|
+
if (msg.type === "csr-update") {
|
|
86
|
+
applyCsrUpdate(msg);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
80
89
|
if (msg.type === "css-update") {
|
|
81
90
|
var cssUrl = selectCssUrl(msg.cssAssets);
|
|
82
91
|
if (cssUrl) swapCss(cssUrl);
|
|
@@ -112,6 +121,26 @@ export const HMR_CLIENT_SCRIPT = `(function(){
|
|
|
112
121
|
socket.addEventListener("error", function(){ try { socket && socket.close(); } catch(e){} });
|
|
113
122
|
}
|
|
114
123
|
|
|
124
|
+
function csrGenerationMoved(generation){
|
|
125
|
+
if (typeof generation !== "number") return false;
|
|
126
|
+
var current = self.__akan ? self.__akan.generation : self.__AKAN_CSR_GENERATION__;
|
|
127
|
+
return typeof current === "number" && current !== generation;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function reloadForCsr(reason){
|
|
131
|
+
console.warn("[akan-hmr] reloading the CSR page: " + reason);
|
|
132
|
+
beginHmrOverlay("Reloading...", true);
|
|
133
|
+
setTimeout(function(){ location.reload(); }, 30);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function applyCsrUpdate(msg){
|
|
137
|
+
if (msg.reload || !self.__akan || typeof self.__akan.hot !== "function") {
|
|
138
|
+
reloadForCsr(msg.reason || "the CSR bundle was rebuilt");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
self.__akan.hot(msg);
|
|
142
|
+
}
|
|
143
|
+
|
|
115
144
|
function schedule(){
|
|
116
145
|
attempts = Math.min(attempts + 1, 6);
|
|
117
146
|
var delay = Math.min(30000, 250 * Math.pow(2, attempts - 1));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const CSR_DEV_DIRNAME = "csr-dev";
|
|
2
|
+
export const CSR_DEV_ROUTE_PREFIX = "/_akan/csr-dev/";
|
|
3
|
+
export const CSR_DEV_APP_FILE = "app.js";
|
|
4
|
+
export const CSR_DEV_MANIFEST_FILE = "manifest.json";
|
|
5
|
+
|
|
6
|
+
export type DevCsrMode = "registry" | "artifact";
|
|
7
|
+
|
|
8
|
+
export interface CsrDevManifest {
|
|
9
|
+
version: 1;
|
|
10
|
+
generation: number;
|
|
11
|
+
vendorFile: string;
|
|
12
|
+
entries: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Where each module's generated code starts in a combined file (`app.js`, a patch), for its source map. */
|
|
16
|
+
export interface CsrDevLayout {
|
|
17
|
+
lineCount: number;
|
|
18
|
+
modules: [id: string, line: number][];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const csrDevModuleFile = (id: string, extension: ".js" | ".js.map") =>
|
|
22
|
+
`modules/${Bun.hash(id).toString(36)}${extension}`;
|
|
23
|
+
|
|
24
|
+
export const resolveDevCsrMode = (env: Record<string, string | undefined> = process.env): DevCsrMode =>
|
|
25
|
+
env.AKAN_DEV_CSR === "artifact" ? "artifact" : "registry";
|