akanjs 2.3.0 → 2.3.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base/primitiveRegistry.ts +19 -12
- package/client/csrTypes.ts +16 -0
- package/constant/fieldInfo.ts +11 -9
- package/constant/getDefault.ts +1 -1
- package/fetch/requestStorage.ts +5 -0
- package/package.json +4 -4
- package/server/akanApp.ts +26 -3
- package/server/akanServer.ts +5 -1
- package/server/cachePolicy.ts +99 -5
- package/server/imageOptimizer.ts +14 -1
- package/server/metadata.tsx +117 -33
- package/server/resolver/database.resolver.ts +4 -4
- package/server/routeElementComposer.tsx +46 -14
- package/server/routeState.ts +379 -0
- package/server/routeTreeBuilder.ts +3 -2
- package/server/rscClient.tsx +316 -46
- package/server/rscClientFetch.ts +57 -0
- package/server/rscClientPatch.ts +157 -0
- package/server/rscHeadPatch.ts +80 -0
- package/server/rscNavigationState.ts +315 -0
- package/server/rscPartialCommit.ts +3 -0
- package/server/rscPatchSafety.ts +57 -0
- package/server/rscSegmentOutlet.tsx +69 -0
- package/server/rscSegmentOutletReference.ts +24 -0
- package/server/rscWorker.tsx +380 -53
- package/server/rscWorkerCache.ts +180 -0
- package/server/rscWorkerHost.ts +40 -12
- package/server/rscWorkerReplay.ts +11 -2
- package/server/ssrFromRscRenderer.tsx +15 -10
- package/server/ssrTypes.ts +18 -0
- package/server/types.tsx +4 -0
- package/server/webRouter.ts +198 -42
- package/service/predefinedAdaptor/database.adaptor.ts +72 -25
- package/signal/signalContext.ts +1 -1
- package/types/base/primitiveRegistry.d.ts +6 -6
- package/types/client/csrTypes.d.ts +16 -0
- package/types/constant/fieldInfo.d.ts +8 -7
- package/types/fetch/requestStorage.d.ts +2 -0
- package/types/server/cachePolicy.d.ts +36 -0
- package/types/server/metadata.d.ts +10 -1
- package/types/server/routeElementComposer.d.ts +9 -1
- package/types/server/routeState.d.ts +94 -0
- package/types/server/rscClient.d.ts +1 -0
- package/types/server/rscClientFetch.d.ts +24 -0
- package/types/server/rscClientPatch.d.ts +21 -0
- package/types/server/rscHeadPatch.d.ts +12 -0
- package/types/server/rscNavigationState.d.ts +78 -0
- package/types/server/rscPartialCommit.d.ts +1 -0
- package/types/server/rscPatchSafety.d.ts +8 -0
- package/types/server/rscSegmentOutlet.d.ts +17 -0
- package/types/server/rscSegmentOutletReference.d.ts +2 -0
- package/types/server/rscWorker.d.ts +5 -0
- package/types/server/rscWorkerCache.d.ts +63 -0
- package/types/server/rscWorkerHost.d.ts +8 -4
- package/types/server/rscWorkerReplay.d.ts +3 -0
- package/types/server/ssrFromRscRenderer.d.ts +1 -0
- package/types/server/ssrTypes.d.ts +17 -0
- package/types/server/types.d.ts +4 -0
- package/types/server/webRouter.d.ts +7 -3
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +6 -0
- package/types/ui/Button.d.ts +1 -1
- package/types/ui/ClientSide.d.ts +1 -1
- package/types/ui/Constant/Doc.d.ts +6 -6
- package/types/ui/Constant/Mermaid.d.ts +1 -1
- package/types/ui/Constant/index.d.ts +1 -1
- package/types/ui/Constant/schemaDoc.d.ts +1 -1
- package/types/ui/Copy.d.ts +1 -1
- package/types/ui/CsrImage.d.ts +1 -1
- package/types/ui/Data/CardList.d.ts +1 -1
- package/types/ui/Data/Dashboard.d.ts +1 -1
- package/types/ui/Data/Insight.d.ts +1 -1
- package/types/ui/Data/Item.d.ts +6 -6
- package/types/ui/Data/ListContainer.d.ts +1 -1
- package/types/ui/Data/Pagination.d.ts +1 -1
- package/types/ui/Data/TableList.d.ts +1 -1
- package/types/ui/DatePicker.d.ts +3 -3
- package/types/ui/Dialog/Close.d.ts +1 -1
- package/types/ui/Dialog/Content.d.ts +1 -1
- package/types/ui/Dialog/Provider.d.ts +1 -1
- package/types/ui/Dialog/Trigger.d.ts +1 -1
- package/types/ui/Dialog/index.d.ts +3 -3
- package/types/ui/DragAction.d.ts +4 -4
- package/types/ui/DraggableList.d.ts +3 -3
- package/types/ui/Dropdown.d.ts +1 -1
- package/types/ui/Empty.d.ts +1 -1
- package/types/ui/Field.d.ts +22 -22
- package/types/ui/Image.d.ts +1 -1
- package/types/ui/InfiniteScroll.d.ts +1 -1
- package/types/ui/Input.d.ts +6 -6
- package/types/ui/KeyboardAvoiding.d.ts +1 -1
- package/types/ui/Layout/BottomAction.d.ts +1 -1
- package/types/ui/Layout/BottomInset.d.ts +1 -1
- package/types/ui/Layout/BottomTab.d.ts +1 -1
- package/types/ui/Layout/Header.d.ts +1 -1
- package/types/ui/Layout/LeftSider.d.ts +1 -1
- package/types/ui/Layout/Navbar.d.ts +1 -1
- package/types/ui/Layout/RightSider.d.ts +1 -1
- package/types/ui/Layout/Sider.d.ts +1 -1
- package/types/ui/Layout/Template.d.ts +1 -1
- package/types/ui/Layout/TopLeftAction.d.ts +1 -1
- package/types/ui/Layout/Unit.d.ts +1 -1
- package/types/ui/Layout/View.d.ts +1 -1
- package/types/ui/Layout/Zone.d.ts +1 -1
- package/types/ui/Layout/index.d.ts +12 -12
- package/types/ui/Link/Back.d.ts +1 -1
- package/types/ui/Link/Close.d.ts +1 -1
- package/types/ui/Link/CsrLink.d.ts +1 -1
- package/types/ui/Link/Lang.d.ts +1 -1
- package/types/ui/Link/SsrLink.d.ts +1 -1
- package/types/ui/Link/index.d.ts +1 -1
- package/types/ui/Load/Edit.d.ts +1 -1
- package/types/ui/Load/Edit_Client.d.ts +1 -1
- package/types/ui/Load/PageCSR.d.ts +1 -1
- package/types/ui/Load/Pagination.d.ts +1 -1
- package/types/ui/Load/Units.d.ts +1 -1
- package/types/ui/Load/View.d.ts +1 -1
- package/types/ui/Loading/Area.d.ts +1 -1
- package/types/ui/Loading/Button.d.ts +1 -1
- package/types/ui/Loading/Input.d.ts +1 -1
- package/types/ui/Loading/ProgressBar.d.ts +1 -1
- package/types/ui/Loading/Skeleton.d.ts +1 -1
- package/types/ui/Loading/Spin.d.ts +1 -1
- package/types/ui/Loading/index.d.ts +6 -6
- package/types/ui/Menu.d.ts +1 -1
- package/types/ui/Modal.d.ts +1 -1
- package/types/ui/Model/AdminPanel.d.ts +1 -1
- package/types/ui/Model/Edit.d.ts +1 -1
- package/types/ui/Model/EditModal.d.ts +1 -1
- package/types/ui/Model/EditWrapper.d.ts +1 -1
- package/types/ui/Model/LoadInit.d.ts +1 -1
- package/types/ui/Model/New.d.ts +1 -1
- package/types/ui/Model/NewWrapper.d.ts +1 -1
- package/types/ui/Model/NewWrapper_Client.d.ts +1 -1
- package/types/ui/Model/Remove.d.ts +1 -1
- package/types/ui/Model/RemoveWrapper.d.ts +1 -1
- package/types/ui/Model/SureToRemove.d.ts +1 -1
- package/types/ui/Model/View.d.ts +1 -1
- package/types/ui/Model/ViewEditModal.d.ts +1 -1
- package/types/ui/Model/ViewModal.d.ts +1 -1
- package/types/ui/Model/ViewWrapper.d.ts +1 -1
- package/types/ui/More.d.ts +1 -1
- package/types/ui/ObjectId.d.ts +1 -1
- package/types/ui/Popconfirm.d.ts +1 -1
- package/types/ui/Radio.d.ts +2 -2
- package/types/ui/RecentTime.d.ts +1 -1
- package/types/ui/Refresh.d.ts +1 -1
- package/types/ui/ScreenNavigator.d.ts +3 -3
- package/types/ui/Select.d.ts +1 -1
- package/types/ui/Signal/Arg.d.ts +13 -13
- package/types/ui/Signal/Doc.d.ts +6 -6
- package/types/ui/Signal/Listener.d.ts +2 -2
- package/types/ui/Signal/Message.d.ts +4 -4
- package/types/ui/Signal/Object.d.ts +4 -4
- package/types/ui/Signal/PubSub.d.ts +4 -4
- package/types/ui/Signal/Request.d.ts +2 -2
- package/types/ui/Signal/Response.d.ts +3 -3
- package/types/ui/Signal/RestApi.d.ts +5 -5
- package/types/ui/Signal/WebSocket.d.ts +2 -2
- package/types/ui/System/CSR.d.ts +5 -5
- package/types/ui/System/Client.d.ts +8 -8
- package/types/ui/System/Common.d.ts +2 -2
- package/types/ui/System/DevModeToggle.d.ts +1 -1
- package/types/ui/System/Gtag.d.ts +1 -1
- package/types/ui/System/Messages.d.ts +1 -1
- package/types/ui/System/Reconnect.d.ts +1 -1
- package/types/ui/System/Root.d.ts +1 -1
- package/types/ui/System/SSR.d.ts +4 -4
- package/types/ui/System/SelectLanguage.d.ts +1 -1
- package/types/ui/System/ThemeToggle.d.ts +1 -1
- package/types/ui/System/index.d.ts +7 -7
- package/types/ui/Tab/Menu.d.ts +1 -1
- package/types/ui/Tab/Menus.d.ts +1 -1
- package/types/ui/Tab/Panel.d.ts +1 -1
- package/types/ui/Tab/Provider.d.ts +1 -1
- package/types/ui/Tab/index.d.ts +4 -4
- package/types/ui/Table.d.ts +1 -1
- package/types/ui/ToggleSelect.d.ts +2 -2
- package/types/ui/Unauthorized.d.ts +1 -1
- package/ui/Constant/schemaDoc.ts +1 -1
- package/server/resolver/resolver.contract.fixture.ts +0 -222
package/server/metadata.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AkanMetadata, Head, ResolvedHead, ResolveHeadResult } from "akanjs/client";
|
|
2
|
-
import type
|
|
2
|
+
import { AKAN_RSC_HEAD_SNAPSHOT_VERSION, type AkanHeadSnapshotNode, type AkanHeadSnapshotV1 } from "./routeState";
|
|
3
3
|
|
|
4
4
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
5
5
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
@@ -10,44 +10,70 @@ function normalizeStringArray(value: string | string[] | undefined): string[] {
|
|
|
10
10
|
return Array.isArray(value) ? value : [value];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function
|
|
13
|
+
function createMetaNode(attrs: Record<string, string | undefined>): AkanHeadSnapshotNode | null {
|
|
14
|
+
if (attrs.content === undefined || attrs.content === "") return null;
|
|
15
|
+
const normalizedAttrs = Object.fromEntries(
|
|
16
|
+
Object.entries(attrs).filter((entry): entry is [string, string] => typeof entry[1] === "string" && entry[1] !== ""),
|
|
17
|
+
);
|
|
18
|
+
return Object.keys(normalizedAttrs).length > 0 ? { tag: "meta", attrs: normalizedAttrs } : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createLinkNode(attrs: Record<string, string | undefined>): AkanHeadSnapshotNode | null {
|
|
22
|
+
if (attrs.href === undefined || attrs.href === "") return null;
|
|
23
|
+
const normalizedAttrs = Object.fromEntries(
|
|
24
|
+
Object.entries(attrs).filter((entry): entry is [string, string] => typeof entry[1] === "string" && entry[1] !== ""),
|
|
25
|
+
);
|
|
26
|
+
return Object.keys(normalizedAttrs).length > 0 ? { tag: "link", attrs: normalizedAttrs } : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createOpenGraphHeadSnapshotNodes(metadata: AkanMetadata): AkanHeadSnapshotNode[] {
|
|
14
30
|
const openGraph = metadata.openGraph;
|
|
15
31
|
if (!openGraph) return [];
|
|
16
|
-
const nodes:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
nodes.push(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
const nodes: AkanHeadSnapshotNode[] = [];
|
|
33
|
+
const pushMeta = (property: string, content: string | undefined) => {
|
|
34
|
+
const node = createMetaNode({ property, content });
|
|
35
|
+
if (node) nodes.push(node);
|
|
36
|
+
};
|
|
37
|
+
pushMeta("og:title", openGraph.title);
|
|
38
|
+
pushMeta("og:description", openGraph.description);
|
|
39
|
+
pushMeta("og:type", openGraph.type);
|
|
40
|
+
pushMeta("og:url", openGraph.url);
|
|
41
|
+
pushMeta("og:site_name", openGraph.siteName);
|
|
42
|
+
for (const image of normalizeStringArray(openGraph.images)) {
|
|
43
|
+
const node = createMetaNode({ property: "og:image", content: image });
|
|
44
|
+
if (node) nodes.push(node);
|
|
25
45
|
}
|
|
26
46
|
return nodes;
|
|
27
47
|
}
|
|
28
48
|
|
|
29
|
-
function
|
|
49
|
+
function createTwitterHeadSnapshotNodes(metadata: AkanMetadata): AkanHeadSnapshotNode[] {
|
|
30
50
|
const twitter = metadata.twitter;
|
|
31
51
|
if (!twitter) return [];
|
|
32
|
-
const nodes:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
const nodes: AkanHeadSnapshotNode[] = [];
|
|
53
|
+
const pushMeta = (name: string, content: string | undefined) => {
|
|
54
|
+
const node = createMetaNode({ name, content });
|
|
55
|
+
if (node) nodes.push(node);
|
|
56
|
+
};
|
|
57
|
+
pushMeta("twitter:card", twitter.card);
|
|
58
|
+
pushMeta("twitter:title", twitter.title);
|
|
59
|
+
pushMeta("twitter:description", twitter.description);
|
|
60
|
+
for (const image of normalizeStringArray(twitter.images)) {
|
|
61
|
+
const node = createMetaNode({ name: "twitter:image", content: image });
|
|
62
|
+
if (node) nodes.push(node);
|
|
39
63
|
}
|
|
40
64
|
return nodes;
|
|
41
65
|
}
|
|
42
66
|
|
|
43
|
-
function
|
|
67
|
+
function createAlternateHeadSnapshotNodes(metadata: AkanMetadata): AkanHeadSnapshotNode[] {
|
|
44
68
|
const alternates = metadata.alternates;
|
|
45
69
|
if (!alternates) return [];
|
|
46
|
-
const nodes:
|
|
47
|
-
|
|
70
|
+
const nodes: AkanHeadSnapshotNode[] = [];
|
|
71
|
+
const canonical = createLinkNode({ rel: "canonical", href: alternates.canonical });
|
|
72
|
+
if (canonical) nodes.push(canonical);
|
|
48
73
|
if (alternates.languages) {
|
|
49
74
|
for (const [lang, href] of Object.entries(alternates.languages)) {
|
|
50
|
-
|
|
75
|
+
const alternate = createLinkNode({ rel: "alternate", hrefLang: lang, href });
|
|
76
|
+
if (alternate) nodes.push(alternate);
|
|
51
77
|
}
|
|
52
78
|
}
|
|
53
79
|
return nodes;
|
|
@@ -65,19 +91,67 @@ export function isAkanMetadata(value: unknown): value is AkanMetadata {
|
|
|
65
91
|
);
|
|
66
92
|
}
|
|
67
93
|
|
|
68
|
-
export function
|
|
94
|
+
export function createAkanMetadataHeadSnapshot(metadata: AkanMetadata): AkanHeadSnapshotV1 {
|
|
95
|
+
const nodes: AkanHeadSnapshotNode[] = [];
|
|
96
|
+
if (metadata.title) nodes.push({ tag: "title", text: metadata.title });
|
|
97
|
+
const description = createMetaNode({ name: "description", content: metadata.description });
|
|
98
|
+
if (description) nodes.push(description);
|
|
99
|
+
const robots = createMetaNode({ name: "robots", content: metadata.robots });
|
|
100
|
+
if (robots) nodes.push(robots);
|
|
101
|
+
nodes.push(...createOpenGraphHeadSnapshotNodes(metadata));
|
|
102
|
+
nodes.push(...createTwitterHeadSnapshotNodes(metadata));
|
|
103
|
+
nodes.push(...createAlternateHeadSnapshotNodes(metadata));
|
|
104
|
+
return { version: AKAN_RSC_HEAD_SNAPSHOT_VERSION, nodes };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function createAkanLocaleAlternateHeadSnapshot(languages: Record<string, string>): AkanHeadSnapshotV1 {
|
|
108
|
+
return {
|
|
109
|
+
version: AKAN_RSC_HEAD_SNAPSHOT_VERSION,
|
|
110
|
+
nodes: Object.entries(languages).map(([lang, href]) => ({
|
|
111
|
+
tag: "link",
|
|
112
|
+
attrs: { rel: "alternate", hrefLang: lang, href },
|
|
113
|
+
})),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function mergeAkanHeadSnapshots(
|
|
118
|
+
...snapshots: Array<AkanHeadSnapshotV1 | null | undefined>
|
|
119
|
+
): AkanHeadSnapshotV1 | undefined {
|
|
120
|
+
const nodes = snapshots.flatMap((snapshot) => snapshot?.nodes ?? []);
|
|
121
|
+
return snapshots.some(Boolean) ? { version: AKAN_RSC_HEAD_SNAPSHOT_VERSION, nodes } : undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function renderAkanHeadSnapshot(snapshot: AkanHeadSnapshotV1, options: { markRouteOwned?: boolean } = {}): Head {
|
|
125
|
+
const markRouteOwned = options.markRouteOwned ?? true;
|
|
69
126
|
return (
|
|
70
127
|
<>
|
|
71
|
-
{
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
128
|
+
{snapshot.nodes.map((node, index) => {
|
|
129
|
+
const marker = markRouteOwned
|
|
130
|
+
? {
|
|
131
|
+
"data-akan-head": "route",
|
|
132
|
+
"data-akan-head-key": `${node.tag}:${index}`,
|
|
133
|
+
}
|
|
134
|
+
: {};
|
|
135
|
+
if (node.tag === "title") {
|
|
136
|
+
return (
|
|
137
|
+
<title key={`${node.tag}:${index}`} {...marker}>
|
|
138
|
+
{node.text ?? ""}
|
|
139
|
+
</title>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
if (node.tag === "meta") {
|
|
143
|
+
return <meta key={`${node.tag}:${index}`} {...node.attrs} {...marker} />;
|
|
144
|
+
}
|
|
145
|
+
return <link key={`${node.tag}:${index}`} {...node.attrs} {...marker} />;
|
|
146
|
+
})}
|
|
77
147
|
</>
|
|
78
148
|
);
|
|
79
149
|
}
|
|
80
150
|
|
|
151
|
+
export function renderMetadata(metadata: AkanMetadata): Head {
|
|
152
|
+
return renderAkanHeadSnapshot(createAkanMetadataHeadSnapshot(metadata));
|
|
153
|
+
}
|
|
154
|
+
|
|
81
155
|
export function hasExplicitLanguageAlternates(metadata: AkanMetadata | null | undefined): boolean {
|
|
82
156
|
return Boolean(metadata?.alternates?.languages && Object.keys(metadata.alternates.languages).length > 0);
|
|
83
157
|
}
|
|
@@ -94,14 +168,24 @@ export function isResolvedHead(value: unknown): value is ResolvedHead {
|
|
|
94
168
|
}
|
|
95
169
|
|
|
96
170
|
export function resolveMetadataHead(metadata: AkanMetadata): ResolvedHead {
|
|
171
|
+
const headSnapshot = createAkanMetadataHeadSnapshot(metadata);
|
|
97
172
|
return {
|
|
98
|
-
node:
|
|
173
|
+
node: renderAkanHeadSnapshot(headSnapshot),
|
|
99
174
|
hasExplicitLanguageAlternates: hasExplicitLanguageAlternates(metadata),
|
|
175
|
+
headSnapshot,
|
|
100
176
|
};
|
|
101
177
|
}
|
|
102
178
|
|
|
103
|
-
export function resolveHeadExport(
|
|
104
|
-
|
|
179
|
+
export function resolveHeadExport(
|
|
180
|
+
value: Head | AkanMetadata | null | undefined,
|
|
181
|
+
options: { includeHeadSnapshot?: boolean } = {},
|
|
182
|
+
): ResolvedHead {
|
|
183
|
+
if (!isAkanMetadata(value)) return { node: value, hasExplicitLanguageAlternates: false };
|
|
184
|
+
if (options.includeHeadSnapshot !== false) return resolveMetadataHead(value);
|
|
185
|
+
return {
|
|
186
|
+
node: renderAkanHeadSnapshot(createAkanMetadataHeadSnapshot(value), { markRouteOwned: false }),
|
|
187
|
+
hasExplicitLanguageAlternates: hasExplicitLanguageAlternates(value),
|
|
188
|
+
};
|
|
105
189
|
}
|
|
106
190
|
|
|
107
191
|
export function resolveHeadResult(value: ResolveHeadResult): ResolvedHead {
|
|
@@ -246,16 +246,16 @@ export class DatabaseResolver {
|
|
|
246
246
|
return await timedQuery(() => this.__store.findIds(find, { sort, skip, limit, sample }));
|
|
247
247
|
}
|
|
248
248
|
async __find(query?: QueryOf<any>, queryOption?: FindQueryOption): Promise<any | null> {
|
|
249
|
-
const { find, sort, skip, sample } = getFindQuery(query, queryOption);
|
|
250
|
-
return await timedQuery(() => this.__store.findOne(find, { sort, skip, sample }));
|
|
249
|
+
const { find, sort, skip, sample, select } = getFindQuery(query, queryOption);
|
|
250
|
+
return await timedQuery(() => this.__store.findOne(find, { sort, skip, sample, select }));
|
|
251
251
|
}
|
|
252
252
|
async __findId(query?: QueryOf<any>, queryOption?: FindQueryOption): Promise<string | null> {
|
|
253
253
|
const { find, sort, skip, sample } = getFindQuery(query, queryOption);
|
|
254
254
|
return await timedQuery(() => this.__store.findId(find, { sort, skip, sample }));
|
|
255
255
|
}
|
|
256
256
|
async __pick(query?: QueryOf<any>, queryOption?: FindQueryOption): Promise<any> {
|
|
257
|
-
const { find, sort, skip, sample } = getFindQuery(query, queryOption);
|
|
258
|
-
return await this.__store.pickOne(find, { sort, skip, sample });
|
|
257
|
+
const { find, sort, skip, sample, select } = getFindQuery(query, queryOption);
|
|
258
|
+
return await this.__store.pickOne(find, { sort, skip, sample, select });
|
|
259
259
|
}
|
|
260
260
|
async __pickId(query?: QueryOf<any>, queryOption?: FindQueryOption): Promise<string> {
|
|
261
261
|
const { find, sort, skip, sample } = getFindQuery(query, queryOption);
|
|
@@ -9,6 +9,9 @@ import type {
|
|
|
9
9
|
} from "akanjs/client";
|
|
10
10
|
import { Children, cloneElement, isValidElement, type ReactElement, type ReactNode, Suspense } from "react";
|
|
11
11
|
import { resolveHeadResult } from "./metadata";
|
|
12
|
+
import { type AkanRouteSegmentState, createAkanRouteSegments, createAkanSegmentOutletKey } from "./routeState";
|
|
13
|
+
import { isAkanRscPartialCommitEnabled } from "./rscPartialCommit";
|
|
14
|
+
import { AkanSegmentOutletReference } from "./rscSegmentOutletReference";
|
|
12
15
|
|
|
13
16
|
export class RouteElementComposer {
|
|
14
17
|
static compose({
|
|
@@ -20,20 +23,32 @@ export class RouteElementComposer {
|
|
|
20
23
|
params: Record<string, string>;
|
|
21
24
|
searchParams: Record<string, string | string[]>;
|
|
22
25
|
}): ReactNode {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
return RouteElementComposer.composeRenders({
|
|
27
|
+
renders: RouteElementComposer.#getRenderStack(pathRoute),
|
|
28
|
+
segments: isAkanRscPartialCommitEnabled() ? createAkanRouteSegments(pathRoute) : undefined,
|
|
29
|
+
params,
|
|
30
|
+
searchParams,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static composeSuffix({
|
|
35
|
+
pathRoute,
|
|
36
|
+
params,
|
|
37
|
+
searchParams,
|
|
38
|
+
patchStartIndex,
|
|
39
|
+
}: {
|
|
40
|
+
pathRoute: PathRoute;
|
|
41
|
+
params: Record<string, string>;
|
|
42
|
+
searchParams: Record<string, string | string[]>;
|
|
43
|
+
patchStartIndex: number;
|
|
44
|
+
}): ReactNode | null {
|
|
45
|
+
const renders = RouteElementComposer.#getRenderStack(pathRoute);
|
|
46
|
+
if (!Number.isInteger(patchStartIndex) || patchStartIndex < 0 || patchStartIndex >= renders.length) return null;
|
|
47
|
+
return RouteElementComposer.composeRenders({
|
|
48
|
+
renders: renders.slice(patchStartIndex),
|
|
49
|
+
params,
|
|
50
|
+
searchParams,
|
|
51
|
+
});
|
|
37
52
|
}
|
|
38
53
|
|
|
39
54
|
static async resolveHead({
|
|
@@ -109,10 +124,12 @@ export class RouteElementComposer {
|
|
|
109
124
|
|
|
110
125
|
static composeRenders({
|
|
111
126
|
renders,
|
|
127
|
+
segments,
|
|
112
128
|
params,
|
|
113
129
|
searchParams,
|
|
114
130
|
}: {
|
|
115
131
|
renders: RouteRender[];
|
|
132
|
+
segments?: AkanRouteSegmentState[];
|
|
116
133
|
params: Record<string, string>;
|
|
117
134
|
searchParams: Record<string, string | string[]>;
|
|
118
135
|
}): ReactNode {
|
|
@@ -127,6 +144,17 @@ export class RouteElementComposer {
|
|
|
127
144
|
</RouteElementComposer.AsyncRender>
|
|
128
145
|
</Suspense>
|
|
129
146
|
);
|
|
147
|
+
const segment = segments?.[i];
|
|
148
|
+
if (segment?.kind === "page") {
|
|
149
|
+
const routeSegments = segments;
|
|
150
|
+
if (!routeSegments) continue;
|
|
151
|
+
const outletKey =
|
|
152
|
+
createAkanSegmentOutletKey(
|
|
153
|
+
routeSegments.slice(0, i + 1).map((item) => item.key),
|
|
154
|
+
i,
|
|
155
|
+
) ?? segment.key;
|
|
156
|
+
element = <AkanSegmentOutletReference segmentKey={outletKey}>{element}</AkanSegmentOutletReference>;
|
|
157
|
+
}
|
|
130
158
|
}
|
|
131
159
|
return element;
|
|
132
160
|
}
|
|
@@ -199,6 +227,10 @@ export class RouteElementComposer {
|
|
|
199
227
|
return RouteElementComposer.#normalizeReactNode(children);
|
|
200
228
|
}
|
|
201
229
|
|
|
230
|
+
static #getRenderStack(pathRoute: PathRoute): RouteRender[] {
|
|
231
|
+
return [...pathRoute.renderRootLayouts, ...pathRoute.renderLayouts, pathRoute.renderPage];
|
|
232
|
+
}
|
|
233
|
+
|
|
202
234
|
static #composeLoadingFallback(renders: RouteRender[], params: Record<string, string>): ReactNode {
|
|
203
235
|
let element: ReactNode = null;
|
|
204
236
|
for (let i = renders.length - 1; i >= 0; i--) {
|