@lolyjs/core 0.2.0-alpha.15 → 0.2.0-alpha.17
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/README.md +1074 -842
- package/dist/{bootstrap-DgvWWDim.d.mts → bootstrap-BfGTMUkj.d.mts} +12 -0
- package/dist/{bootstrap-DgvWWDim.d.ts → bootstrap-BfGTMUkj.d.ts} +12 -0
- package/dist/cli.cjs +3739 -1370
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3726 -1357
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +3292 -589
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +294 -60
- package/dist/index.d.ts +294 -60
- package/dist/index.js +3291 -589
- package/dist/index.js.map +1 -1
- package/dist/index.types-DMOO-uvF.d.mts +221 -0
- package/dist/index.types-DMOO-uvF.d.ts +221 -0
- package/dist/react/cache.cjs.map +1 -1
- package/dist/react/cache.d.mts +21 -2
- package/dist/react/cache.d.ts +21 -2
- package/dist/react/cache.js.map +1 -1
- package/dist/react/components.cjs.map +1 -1
- package/dist/react/components.js.map +1 -1
- package/dist/react/hooks.cjs.map +1 -1
- package/dist/react/hooks.js.map +1 -1
- package/dist/react/sockets.cjs +11 -10
- package/dist/react/sockets.cjs.map +1 -1
- package/dist/react/sockets.js +11 -10
- package/dist/react/sockets.js.map +1 -1
- package/dist/runtime.cjs +359 -95
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +359 -95
- package/dist/runtime.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
|
|
3
|
+
type GenerateStaticParams = () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>;
|
|
4
|
+
interface ServerContext {
|
|
5
|
+
req: Request;
|
|
6
|
+
res: Response;
|
|
7
|
+
params: Record<string, string>;
|
|
8
|
+
pathname: string;
|
|
9
|
+
locals: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
interface WssActions {
|
|
12
|
+
/**
|
|
13
|
+
* Emit to current socket only (reply)
|
|
14
|
+
*/
|
|
15
|
+
reply(event: string, payload?: any): void;
|
|
16
|
+
/**
|
|
17
|
+
* Emit an event to all clients in the namespace
|
|
18
|
+
*/
|
|
19
|
+
emit: (event: string, ...args: any[]) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Emit to everyone except current socket
|
|
22
|
+
*/
|
|
23
|
+
broadcast(event: string, payload?: any, opts?: {
|
|
24
|
+
excludeSelf?: boolean;
|
|
25
|
+
}): void;
|
|
26
|
+
/**
|
|
27
|
+
* Join a room
|
|
28
|
+
*/
|
|
29
|
+
join(room: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Leave a room
|
|
32
|
+
*/
|
|
33
|
+
leave(room: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Emit to a specific room
|
|
36
|
+
*/
|
|
37
|
+
toRoom(room: string): {
|
|
38
|
+
emit(event: string, payload?: any): void;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Emit to a specific user (by userId)
|
|
42
|
+
* Uses presence mapping to find user's sockets
|
|
43
|
+
*/
|
|
44
|
+
toUser(userId: string): {
|
|
45
|
+
emit(event: string, payload?: any): void;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Emit error event (reserved event: __loly:error)
|
|
49
|
+
*/
|
|
50
|
+
error(code: string, message: string, details?: any): void;
|
|
51
|
+
/**
|
|
52
|
+
* Emit an event to a specific socket by Socket.IO socket ID
|
|
53
|
+
* @deprecated Use toUser() for user targeting
|
|
54
|
+
*/
|
|
55
|
+
emitTo?: (socketId: string, event: string, ...args: any[]) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Emit an event to a specific client by custom clientId
|
|
58
|
+
* @deprecated Use toUser() for user targeting
|
|
59
|
+
*/
|
|
60
|
+
emitToClient?: (clientId: string, event: string, ...args: any[]) => void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Route middleware function type.
|
|
64
|
+
* Middlewares run before getServerSideProps and can modify ctx.locals, set headers, redirect, etc.
|
|
65
|
+
*
|
|
66
|
+
* @param ctx - Server context with optional theme
|
|
67
|
+
* @param next - Function to call the next middleware in the chain (must be awaited if used)
|
|
68
|
+
* @returns Promise<void> | void
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Simple middleware that adds data to ctx.locals
|
|
72
|
+
* export const beforeServerData: RouteMiddleware[] = [
|
|
73
|
+
* async (ctx, next) => {
|
|
74
|
+
* ctx.locals.user = await getUser(ctx.req);
|
|
75
|
+
* await next();
|
|
76
|
+
* }
|
|
77
|
+
* ];
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Middleware that redirects
|
|
81
|
+
* export const beforeServerData: RouteMiddleware[] = [
|
|
82
|
+
* async (ctx, next) => {
|
|
83
|
+
* if (!ctx.locals.user) {
|
|
84
|
+
* ctx.res.redirect('/login');
|
|
85
|
+
* return; // Don't call next() if redirecting
|
|
86
|
+
* }
|
|
87
|
+
* await next();
|
|
88
|
+
* }
|
|
89
|
+
* ];
|
|
90
|
+
*/
|
|
91
|
+
type RouteMiddleware = (ctx: ServerContext & {
|
|
92
|
+
theme?: string;
|
|
93
|
+
}, next: () => Promise<void>) => Promise<void> | void;
|
|
94
|
+
/**
|
|
95
|
+
* Result returned by a server loader (getServerSideProps).
|
|
96
|
+
* @template TProps - Type of props that will be passed to the component (defaults to Record<string, any>)
|
|
97
|
+
*/
|
|
98
|
+
interface LoaderResult<TProps extends Record<string, any> = Record<string, any>> {
|
|
99
|
+
props?: TProps;
|
|
100
|
+
redirect?: {
|
|
101
|
+
destination: string;
|
|
102
|
+
permanent?: boolean;
|
|
103
|
+
};
|
|
104
|
+
notFound?: boolean;
|
|
105
|
+
metadata?: PageMetadata | null;
|
|
106
|
+
className?: string;
|
|
107
|
+
theme?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Server loader function type (getServerSideProps).
|
|
111
|
+
* This function is exported from server.hook.ts files.
|
|
112
|
+
*
|
|
113
|
+
* @template TProps - Type of props that will be returned (defaults to Record<string, any>)
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* // Typed loader
|
|
117
|
+
* export const getServerSideProps: ServerLoader<{ user: User; posts: Post[] }> = async (ctx) => ({
|
|
118
|
+
* props: { user: await getUser(), posts: await getPosts() }
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* // Untyped loader (backward compatible)
|
|
123
|
+
* export const getServerSideProps: ServerLoader = async (ctx) => ({
|
|
124
|
+
* props: { any: 'data' }
|
|
125
|
+
* });
|
|
126
|
+
*/
|
|
127
|
+
type ServerLoader<TProps extends Record<string, any> = Record<string, any>> = (ctx: ServerContext) => Promise<LoaderResult<TProps>>;
|
|
128
|
+
/**
|
|
129
|
+
* Comprehensive page metadata for SEO and social sharing.
|
|
130
|
+
* Supports standard HTML meta tags, Open Graph, Twitter Cards, and more.
|
|
131
|
+
*/
|
|
132
|
+
interface PageMetadata {
|
|
133
|
+
/** Page title (sets <title> tag) */
|
|
134
|
+
title?: string;
|
|
135
|
+
/** Page description (sets <meta name="description">) */
|
|
136
|
+
description?: string;
|
|
137
|
+
/** Language code (sets <html lang="...">) */
|
|
138
|
+
lang?: string;
|
|
139
|
+
/** Canonical URL (sets <link rel="canonical">) */
|
|
140
|
+
canonical?: string;
|
|
141
|
+
/** Robots directive (sets <meta name="robots">) */
|
|
142
|
+
robots?: string;
|
|
143
|
+
/** Theme color (sets <meta name="theme-color">) */
|
|
144
|
+
themeColor?: string;
|
|
145
|
+
/** Viewport configuration (sets <meta name="viewport">) */
|
|
146
|
+
viewport?: string;
|
|
147
|
+
/** Open Graph metadata for social sharing */
|
|
148
|
+
openGraph?: {
|
|
149
|
+
title?: string;
|
|
150
|
+
description?: string;
|
|
151
|
+
type?: string;
|
|
152
|
+
url?: string;
|
|
153
|
+
image?: string | {
|
|
154
|
+
url: string;
|
|
155
|
+
width?: number;
|
|
156
|
+
height?: number;
|
|
157
|
+
alt?: string;
|
|
158
|
+
};
|
|
159
|
+
siteName?: string;
|
|
160
|
+
locale?: string;
|
|
161
|
+
};
|
|
162
|
+
/** Twitter Card metadata */
|
|
163
|
+
twitter?: {
|
|
164
|
+
card?: "summary" | "summary_large_image" | "app" | "player";
|
|
165
|
+
title?: string;
|
|
166
|
+
description?: string;
|
|
167
|
+
image?: string;
|
|
168
|
+
imageAlt?: string;
|
|
169
|
+
site?: string;
|
|
170
|
+
creator?: string;
|
|
171
|
+
};
|
|
172
|
+
/** Additional custom meta tags */
|
|
173
|
+
metaTags?: {
|
|
174
|
+
name?: string;
|
|
175
|
+
property?: string;
|
|
176
|
+
httpEquiv?: string;
|
|
177
|
+
content: string;
|
|
178
|
+
}[];
|
|
179
|
+
/** Additional link tags (e.g., preconnect, dns-prefetch) */
|
|
180
|
+
links?: {
|
|
181
|
+
rel: string;
|
|
182
|
+
href: string;
|
|
183
|
+
as?: string;
|
|
184
|
+
crossorigin?: string;
|
|
185
|
+
type?: string;
|
|
186
|
+
}[];
|
|
187
|
+
}
|
|
188
|
+
type MetadataLoader = (ctx: ServerContext) => PageMetadata | Promise<PageMetadata>;
|
|
189
|
+
interface ApiContext {
|
|
190
|
+
req: Request;
|
|
191
|
+
res: Response;
|
|
192
|
+
Response: (body?: any, status?: number) => Response<any, Record<string, any>>;
|
|
193
|
+
NotFound: (body?: any) => Response<any, Record<string, any>>;
|
|
194
|
+
params: Record<string, string>;
|
|
195
|
+
pathname: string;
|
|
196
|
+
locals: Record<string, any>;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* API middleware function type.
|
|
200
|
+
* Middlewares run before the API handler and can modify ctx.locals, set headers, etc.
|
|
201
|
+
*
|
|
202
|
+
* @param ctx - API context
|
|
203
|
+
* @param next - Function to call the next middleware in the chain (must be awaited if used)
|
|
204
|
+
* @returns Promise<void> | void
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* // Authentication middleware
|
|
208
|
+
* export const middlewares: ApiMiddleware[] = [
|
|
209
|
+
* async (ctx, next) => {
|
|
210
|
+
* const token = ctx.req.headers.authorization;
|
|
211
|
+
* if (!token) {
|
|
212
|
+
* return ctx.Response({ error: 'Unauthorized' }, 401);
|
|
213
|
+
* }
|
|
214
|
+
* ctx.locals.user = await verifyToken(token);
|
|
215
|
+
* await next();
|
|
216
|
+
* }
|
|
217
|
+
* ];
|
|
218
|
+
*/
|
|
219
|
+
type ApiMiddleware = (ctx: ApiContext, next: () => Promise<void>) => void | Promise<void>;
|
|
220
|
+
|
|
221
|
+
export type { ApiMiddleware as A, GenerateStaticParams as G, LoaderResult as L, MetadataLoader as M, PageMetadata as P, RouteMiddleware as R, ServerContext as S, WssActions as W, ApiContext as a, ServerLoader as b };
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Request, Response } from 'express';
|
|
2
|
+
|
|
3
|
+
type GenerateStaticParams = () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>;
|
|
4
|
+
interface ServerContext {
|
|
5
|
+
req: Request;
|
|
6
|
+
res: Response;
|
|
7
|
+
params: Record<string, string>;
|
|
8
|
+
pathname: string;
|
|
9
|
+
locals: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
interface WssActions {
|
|
12
|
+
/**
|
|
13
|
+
* Emit to current socket only (reply)
|
|
14
|
+
*/
|
|
15
|
+
reply(event: string, payload?: any): void;
|
|
16
|
+
/**
|
|
17
|
+
* Emit an event to all clients in the namespace
|
|
18
|
+
*/
|
|
19
|
+
emit: (event: string, ...args: any[]) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Emit to everyone except current socket
|
|
22
|
+
*/
|
|
23
|
+
broadcast(event: string, payload?: any, opts?: {
|
|
24
|
+
excludeSelf?: boolean;
|
|
25
|
+
}): void;
|
|
26
|
+
/**
|
|
27
|
+
* Join a room
|
|
28
|
+
*/
|
|
29
|
+
join(room: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Leave a room
|
|
32
|
+
*/
|
|
33
|
+
leave(room: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Emit to a specific room
|
|
36
|
+
*/
|
|
37
|
+
toRoom(room: string): {
|
|
38
|
+
emit(event: string, payload?: any): void;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Emit to a specific user (by userId)
|
|
42
|
+
* Uses presence mapping to find user's sockets
|
|
43
|
+
*/
|
|
44
|
+
toUser(userId: string): {
|
|
45
|
+
emit(event: string, payload?: any): void;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Emit error event (reserved event: __loly:error)
|
|
49
|
+
*/
|
|
50
|
+
error(code: string, message: string, details?: any): void;
|
|
51
|
+
/**
|
|
52
|
+
* Emit an event to a specific socket by Socket.IO socket ID
|
|
53
|
+
* @deprecated Use toUser() for user targeting
|
|
54
|
+
*/
|
|
55
|
+
emitTo?: (socketId: string, event: string, ...args: any[]) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Emit an event to a specific client by custom clientId
|
|
58
|
+
* @deprecated Use toUser() for user targeting
|
|
59
|
+
*/
|
|
60
|
+
emitToClient?: (clientId: string, event: string, ...args: any[]) => void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Route middleware function type.
|
|
64
|
+
* Middlewares run before getServerSideProps and can modify ctx.locals, set headers, redirect, etc.
|
|
65
|
+
*
|
|
66
|
+
* @param ctx - Server context with optional theme
|
|
67
|
+
* @param next - Function to call the next middleware in the chain (must be awaited if used)
|
|
68
|
+
* @returns Promise<void> | void
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Simple middleware that adds data to ctx.locals
|
|
72
|
+
* export const beforeServerData: RouteMiddleware[] = [
|
|
73
|
+
* async (ctx, next) => {
|
|
74
|
+
* ctx.locals.user = await getUser(ctx.req);
|
|
75
|
+
* await next();
|
|
76
|
+
* }
|
|
77
|
+
* ];
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Middleware that redirects
|
|
81
|
+
* export const beforeServerData: RouteMiddleware[] = [
|
|
82
|
+
* async (ctx, next) => {
|
|
83
|
+
* if (!ctx.locals.user) {
|
|
84
|
+
* ctx.res.redirect('/login');
|
|
85
|
+
* return; // Don't call next() if redirecting
|
|
86
|
+
* }
|
|
87
|
+
* await next();
|
|
88
|
+
* }
|
|
89
|
+
* ];
|
|
90
|
+
*/
|
|
91
|
+
type RouteMiddleware = (ctx: ServerContext & {
|
|
92
|
+
theme?: string;
|
|
93
|
+
}, next: () => Promise<void>) => Promise<void> | void;
|
|
94
|
+
/**
|
|
95
|
+
* Result returned by a server loader (getServerSideProps).
|
|
96
|
+
* @template TProps - Type of props that will be passed to the component (defaults to Record<string, any>)
|
|
97
|
+
*/
|
|
98
|
+
interface LoaderResult<TProps extends Record<string, any> = Record<string, any>> {
|
|
99
|
+
props?: TProps;
|
|
100
|
+
redirect?: {
|
|
101
|
+
destination: string;
|
|
102
|
+
permanent?: boolean;
|
|
103
|
+
};
|
|
104
|
+
notFound?: boolean;
|
|
105
|
+
metadata?: PageMetadata | null;
|
|
106
|
+
className?: string;
|
|
107
|
+
theme?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Server loader function type (getServerSideProps).
|
|
111
|
+
* This function is exported from server.hook.ts files.
|
|
112
|
+
*
|
|
113
|
+
* @template TProps - Type of props that will be returned (defaults to Record<string, any>)
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* // Typed loader
|
|
117
|
+
* export const getServerSideProps: ServerLoader<{ user: User; posts: Post[] }> = async (ctx) => ({
|
|
118
|
+
* props: { user: await getUser(), posts: await getPosts() }
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* // Untyped loader (backward compatible)
|
|
123
|
+
* export const getServerSideProps: ServerLoader = async (ctx) => ({
|
|
124
|
+
* props: { any: 'data' }
|
|
125
|
+
* });
|
|
126
|
+
*/
|
|
127
|
+
type ServerLoader<TProps extends Record<string, any> = Record<string, any>> = (ctx: ServerContext) => Promise<LoaderResult<TProps>>;
|
|
128
|
+
/**
|
|
129
|
+
* Comprehensive page metadata for SEO and social sharing.
|
|
130
|
+
* Supports standard HTML meta tags, Open Graph, Twitter Cards, and more.
|
|
131
|
+
*/
|
|
132
|
+
interface PageMetadata {
|
|
133
|
+
/** Page title (sets <title> tag) */
|
|
134
|
+
title?: string;
|
|
135
|
+
/** Page description (sets <meta name="description">) */
|
|
136
|
+
description?: string;
|
|
137
|
+
/** Language code (sets <html lang="...">) */
|
|
138
|
+
lang?: string;
|
|
139
|
+
/** Canonical URL (sets <link rel="canonical">) */
|
|
140
|
+
canonical?: string;
|
|
141
|
+
/** Robots directive (sets <meta name="robots">) */
|
|
142
|
+
robots?: string;
|
|
143
|
+
/** Theme color (sets <meta name="theme-color">) */
|
|
144
|
+
themeColor?: string;
|
|
145
|
+
/** Viewport configuration (sets <meta name="viewport">) */
|
|
146
|
+
viewport?: string;
|
|
147
|
+
/** Open Graph metadata for social sharing */
|
|
148
|
+
openGraph?: {
|
|
149
|
+
title?: string;
|
|
150
|
+
description?: string;
|
|
151
|
+
type?: string;
|
|
152
|
+
url?: string;
|
|
153
|
+
image?: string | {
|
|
154
|
+
url: string;
|
|
155
|
+
width?: number;
|
|
156
|
+
height?: number;
|
|
157
|
+
alt?: string;
|
|
158
|
+
};
|
|
159
|
+
siteName?: string;
|
|
160
|
+
locale?: string;
|
|
161
|
+
};
|
|
162
|
+
/** Twitter Card metadata */
|
|
163
|
+
twitter?: {
|
|
164
|
+
card?: "summary" | "summary_large_image" | "app" | "player";
|
|
165
|
+
title?: string;
|
|
166
|
+
description?: string;
|
|
167
|
+
image?: string;
|
|
168
|
+
imageAlt?: string;
|
|
169
|
+
site?: string;
|
|
170
|
+
creator?: string;
|
|
171
|
+
};
|
|
172
|
+
/** Additional custom meta tags */
|
|
173
|
+
metaTags?: {
|
|
174
|
+
name?: string;
|
|
175
|
+
property?: string;
|
|
176
|
+
httpEquiv?: string;
|
|
177
|
+
content: string;
|
|
178
|
+
}[];
|
|
179
|
+
/** Additional link tags (e.g., preconnect, dns-prefetch) */
|
|
180
|
+
links?: {
|
|
181
|
+
rel: string;
|
|
182
|
+
href: string;
|
|
183
|
+
as?: string;
|
|
184
|
+
crossorigin?: string;
|
|
185
|
+
type?: string;
|
|
186
|
+
}[];
|
|
187
|
+
}
|
|
188
|
+
type MetadataLoader = (ctx: ServerContext) => PageMetadata | Promise<PageMetadata>;
|
|
189
|
+
interface ApiContext {
|
|
190
|
+
req: Request;
|
|
191
|
+
res: Response;
|
|
192
|
+
Response: (body?: any, status?: number) => Response<any, Record<string, any>>;
|
|
193
|
+
NotFound: (body?: any) => Response<any, Record<string, any>>;
|
|
194
|
+
params: Record<string, string>;
|
|
195
|
+
pathname: string;
|
|
196
|
+
locals: Record<string, any>;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* API middleware function type.
|
|
200
|
+
* Middlewares run before the API handler and can modify ctx.locals, set headers, etc.
|
|
201
|
+
*
|
|
202
|
+
* @param ctx - API context
|
|
203
|
+
* @param next - Function to call the next middleware in the chain (must be awaited if used)
|
|
204
|
+
* @returns Promise<void> | void
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* // Authentication middleware
|
|
208
|
+
* export const middlewares: ApiMiddleware[] = [
|
|
209
|
+
* async (ctx, next) => {
|
|
210
|
+
* const token = ctx.req.headers.authorization;
|
|
211
|
+
* if (!token) {
|
|
212
|
+
* return ctx.Response({ error: 'Unauthorized' }, 401);
|
|
213
|
+
* }
|
|
214
|
+
* ctx.locals.user = await verifyToken(token);
|
|
215
|
+
* await next();
|
|
216
|
+
* }
|
|
217
|
+
* ];
|
|
218
|
+
*/
|
|
219
|
+
type ApiMiddleware = (ctx: ApiContext, next: () => Promise<void>) => void | Promise<void>;
|
|
220
|
+
|
|
221
|
+
export type { ApiMiddleware as A, GenerateStaticParams as G, LoaderResult as L, MetadataLoader as M, PageMetadata as P, RouteMiddleware as R, ServerContext as S, WssActions as W, ApiContext as a, ServerLoader as b };
|
package/dist/react/cache.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../modules/react/cache/index.ts","../../modules/react/cache/client-data-cache/index.ts"],"sourcesContent":["export * from \"./client-data-cache\";","type RouteData = {\n ok: boolean;\n status: number;\n json: any;\n};\n\ntype CacheEntry =\n | { status: \"pending\"; promise: Promise<RouteData> }\n | { status: \"fulfilled\"; value: RouteData }\n | { status: \"rejected\"; error: any };\n\n// Use window to guarantee a single shared cache instance\n// across all bundles/modules\nconst CACHE_KEY = \"__FW_DATA_CACHE__\";\n\n// Maximum number of entries in the cache (LRU)\nconst MAX_CACHE_SIZE = 100;\n\ntype CacheStore = {\n data: Map<string, CacheEntry>;\n index: Map<string, Set<string>>; // pathBase -> Set of keys\n lru: string[]; // Ordered list: most recent at end, oldest at start\n};\n\nfunction getCacheStore(): CacheStore {\n if (typeof window !== \"undefined\") {\n if (!(window as any)[CACHE_KEY]) {\n (window as any)[CACHE_KEY] = {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n }\n return (window as any)[CACHE_KEY];\n }\n // Fallback for SSR (though this shouldn't be used on the client)\n return {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n}\n\nconst cacheStore = getCacheStore();\nconst dataCache = cacheStore.data;\nconst pathIndex = cacheStore.index;\nconst lru = cacheStore.lru;\n\n// Helper functions for cache management\n\n/**\n * Extract base path from a cache key (removes query params)\n */\nfunction extractPathBase(key: string): string {\n return key.split(\"?\")[0];\n}\n\n/**\n * Add key to path index\n */\nfunction addToIndex(key: string): void {\n const pathBase = extractPathBase(key);\n if (!pathIndex.has(pathBase)) {\n pathIndex.set(pathBase, new Set());\n }\n pathIndex.get(pathBase)!.add(key);\n}\n\n/**\n * Remove key from path index\n */\nfunction removeFromIndex(key: string): void {\n const pathBase = extractPathBase(key);\n const keys = pathIndex.get(pathBase);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n pathIndex.delete(pathBase);\n }\n }\n}\n\n/**\n * Update LRU order - move key to end (most recent)\n */\nfunction updateLRU(key: string): void {\n const index = lru.indexOf(key);\n if (index !== -1) {\n lru.splice(index, 1);\n }\n lru.push(key);\n}\n\n/**\n * Remove oldest entries if cache exceeds MAX_CACHE_SIZE\n */\nfunction evictOldest(): void {\n while (lru.length >= MAX_CACHE_SIZE && lru.length > 0) {\n const oldestKey = lru.shift()!;\n dataCache.delete(oldestKey);\n removeFromIndex(oldestKey);\n }\n}\n\n/**\n * Set cache entry and maintain indexes\n */\nfunction setCacheEntry(key: string, entry: CacheEntry): void {\n const existingEntry = dataCache.get(key);\n const wasFulfilled = existingEntry?.status === \"fulfilled\";\n \n dataCache.set(key, entry);\n \n // Only track fulfilled entries in LRU and index (not pending/rejected)\n if (entry.status === \"fulfilled\") {\n // Add to index if it wasn't already fulfilled (new entry or transition from pending/rejected)\n if (!wasFulfilled) {\n addToIndex(key);\n }\n updateLRU(key);\n evictOldest();\n } else if (wasFulfilled) {\n // If entry was fulfilled and now isn't (transitioning to pending/rejected), remove from index\n removeFromIndex(key);\n }\n}\n\n/**\n * Delete cache entry and clean up indexes\n */\nfunction deleteCacheEntry(key: string): void {\n if (dataCache.has(key)) {\n dataCache.delete(key);\n removeFromIndex(key);\n const lruIndex = lru.indexOf(key);\n if (lruIndex !== -1) {\n lru.splice(lruIndex, 1);\n }\n }\n}\n\nfunction buildDataUrl(url: string): string {\n return url + (url.includes(\"?\") ? \"&\" : \"?\") + \"__fw_data=1\";\n}\n\nasync function fetchRouteDataOnce(url: string): Promise<RouteData> {\n const dataUrl = buildDataUrl(url);\n\n const res = await fetch(dataUrl, {\n headers: {\n \"x-fw-data\": \"1\",\n Accept: \"application/json\",\n },\n });\n\n let json: any = {};\n\n try {\n const text = await res.text();\n if (text) {\n json = JSON.parse(text);\n }\n } catch (parseError) {\n console.error(\n \"[client][cache] Failed to parse response as JSON:\",\n parseError\n );\n }\n\n const result: RouteData = {\n ok: res.ok,\n status: res.status,\n json,\n };\n\n return result;\n}\n\n/**\n * Revalidates route data by removing it from the cache.\n * The next time you navigate to this route, fresh data will be fetched from the server.\n * This is a client-side function and does not require a server-side revalidation.\n *\n * @param path - The route path to revalidate (e.g., '/posts/1' or '/posts/1?page=2')\n * If query params are not included, revalidates all variants of that route.\n *\n * @example\n * ```ts\n * // After saving something to the DB, revalidate the route\n * await saveToDatabase(data);\n * revalidatePath('/posts');\n * \n * // Revalidate a specific route with query params\n * revalidatePath('/posts?page=2');\n * ```\n */\nexport function revalidatePath(path: string): void {\n // Normalize the base path (without query params)\n const normalizedPath = path.split(\"?\")[0];\n const hasQueryParams = path.includes(\"?\");\n \n // Get all keys for this path base from index (O(1) lookup)\n const keysForPath = pathIndex.get(normalizedPath);\n \n if (!keysForPath || keysForPath.size === 0) {\n return; // No entries to revalidate\n }\n \n // If the path includes specific query params, extract them\n let specificQueryParams: string | undefined;\n if (hasQueryParams) {\n const queryPart = path.split(\"?\")[1];\n // Sort query params for consistent comparison\n specificQueryParams = queryPart\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n }\n \n // Iterate only over keys for this path (much smaller set)\n const keysToDelete: string[] = [];\n for (const key of keysForPath) {\n // If specific query params were specified, check if they match\n if (hasQueryParams && specificQueryParams) {\n const [, keyQuery = \"\"] = key.split(\"?\");\n const keyQueryParams = keyQuery\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (keyQueryParams === specificQueryParams) {\n keysToDelete.push(key);\n }\n } else {\n // If no specific query params, revalidate all variants\n keysToDelete.push(key);\n }\n }\n \n // Delete matching entries\n keysToDelete.forEach((key) => {\n deleteCacheEntry(key);\n });\n \n // If the revalidated path matches the current route, automatically refresh data\n if (typeof window !== \"undefined\") {\n const currentPathname = window.location.pathname;\n const currentSearch = window.location.search;\n const matchesCurrentPath = normalizedPath === currentPathname;\n \n if (matchesCurrentPath) {\n if (hasQueryParams && specificQueryParams) {\n const currentQueryParams = currentSearch\n .replace(\"?\", \"\")\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (currentQueryParams === specificQueryParams) {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n } else {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n }\n }\n}\n\n/**\n * Revalidates and refreshes the current page data.\n * Similar to Next.js's `router.refresh()`.\n * \n * This function:\n * 1. Removes the current route from cache\n * 2. Fetches fresh data from the server\n * 3. Updates window.__FW_DATA__ with the new data\n * 4. Dispatches a 'fw-data-refresh' event for components to listen to\n * \n * @returns Promise that resolves with the fresh route data\n * \n * @example\n * ```ts\n * // Refresh current page data after a mutation\n * await revalidate();\n * ```\n */\nexport async function revalidate(): Promise<RouteData> {\n if (typeof window === \"undefined\") {\n throw new Error(\"revalidate() can only be called on the client\");\n }\n\n const pathname = window.location.pathname + window.location.search;\n \n // Revalidate the path (remove from cache)\n revalidatePath(pathname);\n \n // Fetch fresh data\n const freshData = await getRouteData(pathname, { revalidate: true });\n \n // Update window.__FW_DATA__ if it exists\n if ((window as any).__FW_DATA__ && freshData.ok && freshData.json) {\n const currentData = (window as any).__FW_DATA__;\n (window as any).__FW_DATA__ = {\n ...currentData,\n pathname: pathname.split(\"?\")[0],\n params: freshData.json.params || currentData.params || {},\n props: freshData.json.props || currentData.props || {},\n metadata: freshData.json.metadata ?? currentData.metadata ?? null,\n notFound: freshData.json.notFound ?? false,\n error: freshData.json.error ?? false,\n };\n \n // Dispatch event for components to listen to\n window.dispatchEvent(new CustomEvent(\"fw-data-refresh\", {\n detail: { data: freshData },\n }));\n }\n \n return freshData;\n}\n\n/**\n * @deprecated Use `revalidatePath()` instead. This function is kept for backwards compatibility.\n */\nexport function revalidateRouteData(url: string): void {\n revalidatePath(url);\n}\n\nexport function prefetchRouteData(url: string): void {\n const key = buildDataUrl(url);\n\n const cached = dataCache.get(key);\n\n if (cached && cached.status !== \"rejected\") {\n // Update LRU if it exists and is fulfilled\n if (cached.status === \"fulfilled\") {\n updateLRU(key);\n }\n return;\n }\n\n const promise = fetchRouteDataOnce(url)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error prefetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n}\n\nexport type GetRouteDataOptions = {\n /**\n * If true, forces revalidation of route data,\n * ignoring the cache and fetching fresh data from the server.\n * Similar to Next.js's `router.refresh()` behavior.\n */\n revalidate?: boolean;\n};\n\nexport async function getRouteData(\n url: string,\n options?: GetRouteDataOptions\n): Promise<RouteData> {\n const key = buildDataUrl(url);\n\n // If revalidation is requested, remove the entry from cache\n if (options?.revalidate) {\n deleteCacheEntry(key);\n }\n\n const entry = dataCache.get(key);\n\n if (entry) {\n if (entry.status === \"fulfilled\") {\n // Update LRU: mark as recently used\n updateLRU(key);\n return entry.value;\n }\n if (entry.status === \"pending\") {\n return entry.promise;\n }\n }\n\n // No entry in cache, fetch it\n const promise = fetchRouteDataOnce(url)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error fetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n return promise;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../modules/react/cache/index.ts","../../modules/react/cache/client-data-cache/index.ts"],"sourcesContent":["export * from \"./client-data-cache\";","import type { PageMetadata } from \"@router/index\";\n\n/**\n * Response data structure from server for route data requests\n */\nexport type RouteDataResponse = {\n props?: Record<string, unknown>;\n metadata?: PageMetadata | null;\n theme?: string;\n redirect?: { destination: string; permanent?: boolean };\n notFound?: boolean;\n error?: boolean;\n message?: string;\n params?: Record<string, string>;\n};\n\ntype RouteData = {\n ok: boolean;\n status: number;\n json: RouteDataResponse;\n};\n\ntype CacheEntry =\n | { status: \"pending\"; promise: Promise<RouteData> }\n | { status: \"fulfilled\"; value: RouteData }\n | { status: \"rejected\"; error: any };\n\n// Use window to guarantee a single shared cache instance\n// across all bundles/modules\nconst CACHE_KEY = \"__FW_DATA_CACHE__\";\n\n// Maximum number of entries in the cache (LRU)\nconst MAX_CACHE_SIZE = 100;\n\ntype CacheStore = {\n data: Map<string, CacheEntry>;\n index: Map<string, Set<string>>; // pathBase -> Set of keys\n lru: string[]; // Ordered list: most recent at end, oldest at start\n};\n\nfunction getCacheStore(): CacheStore {\n if (typeof window !== \"undefined\") {\n if (!(window as any)[CACHE_KEY]) {\n (window as any)[CACHE_KEY] = {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n }\n return (window as any)[CACHE_KEY];\n }\n // Fallback for SSR (though this shouldn't be used on the client)\n return {\n data: new Map<string, CacheEntry>(),\n index: new Map<string, Set<string>>(),\n lru: [],\n };\n}\n\nconst cacheStore = getCacheStore();\nconst dataCache = cacheStore.data;\nconst pathIndex = cacheStore.index;\nconst lru = cacheStore.lru;\n\n// Helper functions for cache management\n\n/**\n * Extract base path from a cache key (removes query params)\n */\nfunction extractPathBase(key: string): string {\n return key.split(\"?\")[0];\n}\n\n/**\n * Add key to path index\n */\nfunction addToIndex(key: string): void {\n const pathBase = extractPathBase(key);\n if (!pathIndex.has(pathBase)) {\n pathIndex.set(pathBase, new Set());\n }\n pathIndex.get(pathBase)!.add(key);\n}\n\n/**\n * Remove key from path index\n */\nfunction removeFromIndex(key: string): void {\n const pathBase = extractPathBase(key);\n const keys = pathIndex.get(pathBase);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n pathIndex.delete(pathBase);\n }\n }\n}\n\n/**\n * Update LRU order - move key to end (most recent)\n */\nfunction updateLRU(key: string): void {\n const index = lru.indexOf(key);\n if (index !== -1) {\n lru.splice(index, 1);\n }\n lru.push(key);\n}\n\n/**\n * Remove oldest entries if cache exceeds MAX_CACHE_SIZE\n */\nfunction evictOldest(): void {\n while (lru.length >= MAX_CACHE_SIZE && lru.length > 0) {\n const oldestKey = lru.shift()!;\n dataCache.delete(oldestKey);\n removeFromIndex(oldestKey);\n }\n}\n\n/**\n * Set cache entry and maintain indexes\n */\nfunction setCacheEntry(key: string, entry: CacheEntry): void {\n const existingEntry = dataCache.get(key);\n const wasFulfilled = existingEntry?.status === \"fulfilled\";\n \n dataCache.set(key, entry);\n \n // Only track fulfilled entries in LRU and index (not pending/rejected)\n if (entry.status === \"fulfilled\") {\n // Add to index if it wasn't already fulfilled (new entry or transition from pending/rejected)\n if (!wasFulfilled) {\n addToIndex(key);\n }\n updateLRU(key);\n evictOldest();\n } else if (wasFulfilled) {\n // If entry was fulfilled and now isn't (transitioning to pending/rejected), remove from index\n removeFromIndex(key);\n }\n}\n\n/**\n * Delete cache entry and clean up indexes\n */\nfunction deleteCacheEntry(key: string): void {\n if (dataCache.has(key)) {\n dataCache.delete(key);\n removeFromIndex(key);\n const lruIndex = lru.indexOf(key);\n if (lruIndex !== -1) {\n lru.splice(lruIndex, 1);\n }\n }\n}\n\nfunction buildDataUrl(url: string): string {\n return url + (url.includes(\"?\") ? \"&\" : \"?\") + \"__fw_data=1\";\n}\n\nasync function fetchRouteDataOnce(url: string): Promise<RouteData> {\n const dataUrl = buildDataUrl(url);\n\n const res = await fetch(dataUrl, {\n headers: {\n \"x-fw-data\": \"1\",\n Accept: \"application/json\",\n },\n });\n\n let json: any = {};\n\n try {\n const text = await res.text();\n if (text) {\n json = JSON.parse(text);\n }\n } catch (parseError) {\n console.error(\n \"[client][cache] Failed to parse response as JSON:\",\n parseError\n );\n }\n\n const result: RouteData = {\n ok: res.ok,\n status: res.status,\n json,\n };\n\n return result;\n}\n\n/**\n * Revalidates route data by removing it from the cache.\n * The next time you navigate to this route, fresh data will be fetched from the server.\n * This is a client-side function and does not require a server-side revalidation.\n *\n * @param path - The route path to revalidate (e.g., '/posts/1' or '/posts/1?page=2')\n * If query params are not included, revalidates all variants of that route.\n *\n * @example\n * ```ts\n * // After saving something to the DB, revalidate the route\n * await saveToDatabase(data);\n * revalidatePath('/posts');\n * \n * // Revalidate a specific route with query params\n * revalidatePath('/posts?page=2');\n * ```\n */\nexport function revalidatePath(path: string): void {\n // Normalize the base path (without query params)\n const normalizedPath = path.split(\"?\")[0];\n const hasQueryParams = path.includes(\"?\");\n \n // Get all keys for this path base from index (O(1) lookup)\n const keysForPath = pathIndex.get(normalizedPath);\n \n if (!keysForPath || keysForPath.size === 0) {\n return; // No entries to revalidate\n }\n \n // If the path includes specific query params, extract them\n let specificQueryParams: string | undefined;\n if (hasQueryParams) {\n const queryPart = path.split(\"?\")[1];\n // Sort query params for consistent comparison\n specificQueryParams = queryPart\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n }\n \n // Iterate only over keys for this path (much smaller set)\n const keysToDelete: string[] = [];\n for (const key of keysForPath) {\n // If specific query params were specified, check if they match\n if (hasQueryParams && specificQueryParams) {\n const [, keyQuery = \"\"] = key.split(\"?\");\n const keyQueryParams = keyQuery\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (keyQueryParams === specificQueryParams) {\n keysToDelete.push(key);\n }\n } else {\n // If no specific query params, revalidate all variants\n keysToDelete.push(key);\n }\n }\n \n // Delete matching entries\n keysToDelete.forEach((key) => {\n deleteCacheEntry(key);\n });\n \n // If the revalidated path matches the current route, automatically refresh data\n if (typeof window !== \"undefined\") {\n const currentPathname = window.location.pathname;\n const currentSearch = window.location.search;\n const matchesCurrentPath = normalizedPath === currentPathname;\n \n if (matchesCurrentPath) {\n if (hasQueryParams && specificQueryParams) {\n const currentQueryParams = currentSearch\n .replace(\"?\", \"\")\n .split(\"&\")\n .filter((p) => !p.startsWith(\"__fw_data=\"))\n .sort()\n .join(\"&\");\n \n if (currentQueryParams === specificQueryParams) {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n } else {\n revalidate().catch((err) => {\n console.error(\n \"[client][cache] Error revalidating current route:\",\n err\n );\n });\n }\n }\n }\n}\n\n/**\n * Revalidates and refreshes the current page data.\n * Similar to Next.js's `router.refresh()`.\n * \n * This function:\n * 1. Removes the current route from cache\n * 2. Fetches fresh data from the server\n * 3. Updates window.__FW_DATA__ with the new data\n * 4. Dispatches a 'fw-data-refresh' event for components to listen to\n * \n * @returns Promise that resolves with the fresh route data\n * \n * @example\n * ```ts\n * // Refresh current page data after a mutation\n * await revalidate();\n * ```\n */\nexport async function revalidate(): Promise<RouteData> {\n if (typeof window === \"undefined\") {\n throw new Error(\"revalidate() can only be called on the client\");\n }\n\n const pathname = window.location.pathname + window.location.search;\n \n // Revalidate the path (remove from cache)\n revalidatePath(pathname);\n \n // Fetch fresh data\n const freshData = await getRouteData(pathname, { revalidate: true });\n \n // Update window.__FW_DATA__ if it exists\n if ((window as any).__FW_DATA__ && freshData.ok && freshData.json) {\n const currentData = (window as any).__FW_DATA__;\n (window as any).__FW_DATA__ = {\n ...currentData,\n pathname: pathname.split(\"?\")[0],\n params: freshData.json.params || currentData.params || {},\n props: freshData.json.props || currentData.props || {},\n metadata: freshData.json.metadata ?? currentData.metadata ?? null,\n notFound: freshData.json.notFound ?? false,\n error: freshData.json.error ?? false,\n };\n \n // Dispatch event for components to listen to\n window.dispatchEvent(new CustomEvent(\"fw-data-refresh\", {\n detail: { data: freshData },\n }));\n }\n \n return freshData;\n}\n\n/**\n * @deprecated Use `revalidatePath()` instead. This function is kept for backwards compatibility.\n */\nexport function revalidateRouteData(url: string): void {\n revalidatePath(url);\n}\n\nexport function prefetchRouteData(url: string): void {\n const key = buildDataUrl(url);\n\n const cached = dataCache.get(key);\n\n if (cached && cached.status !== \"rejected\") {\n // Update LRU if it exists and is fulfilled\n if (cached.status === \"fulfilled\") {\n updateLRU(key);\n }\n return;\n }\n\n const promise = fetchRouteDataOnce(url)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error prefetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n}\n\nexport type GetRouteDataOptions = {\n /**\n * If true, forces revalidation of route data,\n * ignoring the cache and fetching fresh data from the server.\n * Similar to Next.js's `router.refresh()` behavior.\n */\n revalidate?: boolean;\n};\n\nexport async function getRouteData(\n url: string,\n options?: GetRouteDataOptions\n): Promise<RouteData> {\n const key = buildDataUrl(url);\n\n // If revalidation is requested, remove the entry from cache\n if (options?.revalidate) {\n deleteCacheEntry(key);\n }\n\n const entry = dataCache.get(key);\n\n if (entry) {\n if (entry.status === \"fulfilled\") {\n // Update LRU: mark as recently used\n updateLRU(key);\n return entry.value;\n }\n if (entry.status === \"pending\") {\n return entry.promise;\n }\n }\n\n // No entry in cache, fetch it\n const promise = fetchRouteDataOnce(url)\n .then((value) => {\n setCacheEntry(key, { status: \"fulfilled\", value });\n return value;\n })\n .catch((error) => {\n console.error(\"[client][cache] Error fetching route data:\", error);\n dataCache.set(key, { status: \"rejected\", error });\n throw error;\n });\n\n dataCache.set(key, { status: \"pending\", promise });\n return promise;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC6BA,IAAM,YAAY;AAGlB,IAAM,iBAAiB;AAQvB,SAAS,gBAA4B;AACnC,MAAI,OAAO,WAAW,aAAa;AACjC,QAAI,CAAE,OAAe,SAAS,GAAG;AAC/B,MAAC,OAAe,SAAS,IAAI;AAAA,QAC3B,MAAM,oBAAI,IAAwB;AAAA,QAClC,OAAO,oBAAI,IAAyB;AAAA,QACpC,KAAK,CAAC;AAAA,MACR;AAAA,IACF;AACA,WAAQ,OAAe,SAAS;AAAA,EAClC;AAEA,SAAO;AAAA,IACL,MAAM,oBAAI,IAAwB;AAAA,IAClC,OAAO,oBAAI,IAAyB;AAAA,IACpC,KAAK,CAAC;AAAA,EACR;AACF;AAEA,IAAM,aAAa,cAAc;AACjC,IAAM,YAAY,WAAW;AAC7B,IAAM,YAAY,WAAW;AAC7B,IAAM,MAAM,WAAW;AAOvB,SAAS,gBAAgB,KAAqB;AAC5C,SAAO,IAAI,MAAM,GAAG,EAAE,CAAC;AACzB;AAKA,SAAS,WAAW,KAAmB;AACrC,QAAM,WAAW,gBAAgB,GAAG;AACpC,MAAI,CAAC,UAAU,IAAI,QAAQ,GAAG;AAC5B,cAAU,IAAI,UAAU,oBAAI,IAAI,CAAC;AAAA,EACnC;AACA,YAAU,IAAI,QAAQ,EAAG,IAAI,GAAG;AAClC;AAKA,SAAS,gBAAgB,KAAmB;AAC1C,QAAM,WAAW,gBAAgB,GAAG;AACpC,QAAM,OAAO,UAAU,IAAI,QAAQ;AACnC,MAAI,MAAM;AACR,SAAK,OAAO,GAAG;AACf,QAAI,KAAK,SAAS,GAAG;AACnB,gBAAU,OAAO,QAAQ;AAAA,IAC3B;AAAA,EACF;AACF;AAKA,SAAS,UAAU,KAAmB;AACpC,QAAM,QAAQ,IAAI,QAAQ,GAAG;AAC7B,MAAI,UAAU,IAAI;AAChB,QAAI,OAAO,OAAO,CAAC;AAAA,EACrB;AACA,MAAI,KAAK,GAAG;AACd;AAKA,SAAS,cAAoB;AAC3B,SAAO,IAAI,UAAU,kBAAkB,IAAI,SAAS,GAAG;AACrD,UAAM,YAAY,IAAI,MAAM;AAC5B,cAAU,OAAO,SAAS;AAC1B,oBAAgB,SAAS;AAAA,EAC3B;AACF;AAKA,SAAS,cAAc,KAAa,OAAyB;AAC3D,QAAM,gBAAgB,UAAU,IAAI,GAAG;AACvC,QAAM,eAAe,eAAe,WAAW;AAE/C,YAAU,IAAI,KAAK,KAAK;AAGxB,MAAI,MAAM,WAAW,aAAa;AAEhC,QAAI,CAAC,cAAc;AACjB,iBAAW,GAAG;AAAA,IAChB;AACA,cAAU,GAAG;AACb,gBAAY;AAAA,EACd,WAAW,cAAc;AAEvB,oBAAgB,GAAG;AAAA,EACrB;AACF;AAKA,SAAS,iBAAiB,KAAmB;AAC3C,MAAI,UAAU,IAAI,GAAG,GAAG;AACtB,cAAU,OAAO,GAAG;AACpB,oBAAgB,GAAG;AACnB,UAAM,WAAW,IAAI,QAAQ,GAAG;AAChC,QAAI,aAAa,IAAI;AACnB,UAAI,OAAO,UAAU,CAAC;AAAA,IACxB;AAAA,EACF;AACF;AAEA,SAAS,aAAa,KAAqB;AACzC,SAAO,OAAO,IAAI,SAAS,GAAG,IAAI,MAAM,OAAO;AACjD;AAEA,eAAe,mBAAmB,KAAiC;AACjE,QAAM,UAAU,aAAa,GAAG;AAEhC,QAAM,MAAM,MAAM,MAAM,SAAS;AAAA,IAC/B,SAAS;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,MAAI,OAAY,CAAC;AAEjB,MAAI;AACF,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,MAAM;AACR,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB;AAAA,EACF,SAAS,YAAY;AACnB,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAoB;AAAA,IACxB,IAAI,IAAI;AAAA,IACR,QAAQ,IAAI;AAAA,IACZ;AAAA,EACF;AAEA,SAAO;AACT;AAoBO,SAAS,eAAe,MAAoB;AAEjD,QAAM,iBAAiB,KAAK,MAAM,GAAG,EAAE,CAAC;AACxC,QAAM,iBAAiB,KAAK,SAAS,GAAG;AAGxC,QAAM,cAAc,UAAU,IAAI,cAAc;AAEhD,MAAI,CAAC,eAAe,YAAY,SAAS,GAAG;AAC1C;AAAA,EACF;AAGA,MAAI;AACJ,MAAI,gBAAgB;AAClB,UAAM,YAAY,KAAK,MAAM,GAAG,EAAE,CAAC;AAEnC,0BAAsB,UACnB,MAAM,GAAG,EACT,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,YAAY,CAAC,EACzC,KAAK,EACL,KAAK,GAAG;AAAA,EACb;AAGA,QAAM,eAAyB,CAAC;AAChC,aAAW,OAAO,aAAa;AAE7B,QAAI,kBAAkB,qBAAqB;AACzC,YAAM,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI,MAAM,GAAG;AACvC,YAAM,iBAAiB,SACpB,MAAM,GAAG,EACT,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,YAAY,CAAC,EACzC,KAAK,EACL,KAAK,GAAG;AAEX,UAAI,mBAAmB,qBAAqB;AAC1C,qBAAa,KAAK,GAAG;AAAA,MACvB;AAAA,IACF,OAAO;AAEL,mBAAa,KAAK,GAAG;AAAA,IACvB;AAAA,EACF;AAGA,eAAa,QAAQ,CAAC,QAAQ;AAC5B,qBAAiB,GAAG;AAAA,EACtB,CAAC;AAGD,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,kBAAkB,OAAO,SAAS;AACxC,UAAM,gBAAgB,OAAO,SAAS;AACtC,UAAM,qBAAqB,mBAAmB;AAE9C,QAAI,oBAAoB;AACtB,UAAI,kBAAkB,qBAAqB;AACzC,cAAM,qBAAqB,cACxB,QAAQ,KAAK,EAAE,EACf,MAAM,GAAG,EACT,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,YAAY,CAAC,EACzC,KAAK,EACL,KAAK,GAAG;AAEX,YAAI,uBAAuB,qBAAqB;AAC9C,qBAAW,EAAE,MAAM,CAAC,QAAQ;AAC1B,oBAAQ;AAAA,cACN;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,mBAAW,EAAE,MAAM,CAAC,QAAQ;AAC1B,kBAAQ;AAAA,YACN;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAoBA,eAAsB,aAAiC;AACrD,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,QAAM,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS;AAG5D,iBAAe,QAAQ;AAGvB,QAAM,YAAY,MAAM,aAAa,UAAU,EAAE,YAAY,KAAK,CAAC;AAGnE,MAAK,OAAe,eAAe,UAAU,MAAM,UAAU,MAAM;AACjE,UAAM,cAAe,OAAe;AACpC,IAAC,OAAe,cAAc;AAAA,MAC5B,GAAG;AAAA,MACH,UAAU,SAAS,MAAM,GAAG,EAAE,CAAC;AAAA,MAC/B,QAAQ,UAAU,KAAK,UAAU,YAAY,UAAU,CAAC;AAAA,MACxD,OAAO,UAAU,KAAK,SAAS,YAAY,SAAS,CAAC;AAAA,MACrD,UAAU,UAAU,KAAK,YAAY,YAAY,YAAY;AAAA,MAC7D,UAAU,UAAU,KAAK,YAAY;AAAA,MACrC,OAAO,UAAU,KAAK,SAAS;AAAA,IACjC;AAGA,WAAO,cAAc,IAAI,YAAY,mBAAmB;AAAA,MACtD,QAAQ,EAAE,MAAM,UAAU;AAAA,IAC5B,CAAC,CAAC;AAAA,EACJ;AAEA,SAAO;AACT;AAKO,SAAS,oBAAoB,KAAmB;AACrD,iBAAe,GAAG;AACpB;AAEO,SAAS,kBAAkB,KAAmB;AACnD,QAAM,MAAM,aAAa,GAAG;AAE5B,QAAM,SAAS,UAAU,IAAI,GAAG;AAEhC,MAAI,UAAU,OAAO,WAAW,YAAY;AAE1C,QAAI,OAAO,WAAW,aAAa;AACjC,gBAAU,GAAG;AAAA,IACf;AACA;AAAA,EACF;AAEA,QAAM,UAAU,mBAAmB,GAAG,EACnC,KAAK,CAAC,UAAU;AACf,kBAAc,KAAK,EAAE,QAAQ,aAAa,MAAM,CAAC;AACjD,WAAO;AAAA,EACT,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,YAAQ,MAAM,iDAAiD,KAAK;AACpE,cAAU,IAAI,KAAK,EAAE,QAAQ,YAAY,MAAM,CAAC;AAChD,UAAM;AAAA,EACR,CAAC;AAEH,YAAU,IAAI,KAAK,EAAE,QAAQ,WAAW,QAAQ,CAAC;AACnD;AAWA,eAAsB,aACpB,KACA,SACoB;AACpB,QAAM,MAAM,aAAa,GAAG;AAG5B,MAAI,SAAS,YAAY;AACvB,qBAAiB,GAAG;AAAA,EACtB;AAEA,QAAM,QAAQ,UAAU,IAAI,GAAG;AAE/B,MAAI,OAAO;AACT,QAAI,MAAM,WAAW,aAAa;AAEhC,gBAAU,GAAG;AACb,aAAO,MAAM;AAAA,IACf;AACA,QAAI,MAAM,WAAW,WAAW;AAC9B,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAGA,QAAM,UAAU,mBAAmB,GAAG,EACnC,KAAK,CAAC,UAAU;AACf,kBAAc,KAAK,EAAE,QAAQ,aAAa,MAAM,CAAC;AACjD,WAAO;AAAA,EACT,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,YAAQ,MAAM,8CAA8C,KAAK;AACjE,cAAU,IAAI,KAAK,EAAE,QAAQ,YAAY,MAAM,CAAC;AAChD,UAAM;AAAA,EACR,CAAC;AAEH,YAAU,IAAI,KAAK,EAAE,QAAQ,WAAW,QAAQ,CAAC;AACjD,SAAO;AACT;","names":[]}
|
package/dist/react/cache.d.mts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
+
import { P as PageMetadata } from '../index.types-DMOO-uvF.mjs';
|
|
2
|
+
import 'express';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Response data structure from server for route data requests
|
|
6
|
+
*/
|
|
7
|
+
type RouteDataResponse = {
|
|
8
|
+
props?: Record<string, unknown>;
|
|
9
|
+
metadata?: PageMetadata | null;
|
|
10
|
+
theme?: string;
|
|
11
|
+
redirect?: {
|
|
12
|
+
destination: string;
|
|
13
|
+
permanent?: boolean;
|
|
14
|
+
};
|
|
15
|
+
notFound?: boolean;
|
|
16
|
+
error?: boolean;
|
|
17
|
+
message?: string;
|
|
18
|
+
params?: Record<string, string>;
|
|
19
|
+
};
|
|
1
20
|
type RouteData = {
|
|
2
21
|
ok: boolean;
|
|
3
22
|
status: number;
|
|
4
|
-
json:
|
|
23
|
+
json: RouteDataResponse;
|
|
5
24
|
};
|
|
6
25
|
/**
|
|
7
26
|
* Revalidates route data by removing it from the cache.
|
|
@@ -56,4 +75,4 @@ type GetRouteDataOptions = {
|
|
|
56
75
|
};
|
|
57
76
|
declare function getRouteData(url: string, options?: GetRouteDataOptions): Promise<RouteData>;
|
|
58
77
|
|
|
59
|
-
export { type GetRouteDataOptions, getRouteData, prefetchRouteData, revalidate, revalidatePath, revalidateRouteData };
|
|
78
|
+
export { type GetRouteDataOptions, type RouteDataResponse, getRouteData, prefetchRouteData, revalidate, revalidatePath, revalidateRouteData };
|
package/dist/react/cache.d.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
+
import { P as PageMetadata } from '../index.types-DMOO-uvF.js';
|
|
2
|
+
import 'express';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Response data structure from server for route data requests
|
|
6
|
+
*/
|
|
7
|
+
type RouteDataResponse = {
|
|
8
|
+
props?: Record<string, unknown>;
|
|
9
|
+
metadata?: PageMetadata | null;
|
|
10
|
+
theme?: string;
|
|
11
|
+
redirect?: {
|
|
12
|
+
destination: string;
|
|
13
|
+
permanent?: boolean;
|
|
14
|
+
};
|
|
15
|
+
notFound?: boolean;
|
|
16
|
+
error?: boolean;
|
|
17
|
+
message?: string;
|
|
18
|
+
params?: Record<string, string>;
|
|
19
|
+
};
|
|
1
20
|
type RouteData = {
|
|
2
21
|
ok: boolean;
|
|
3
22
|
status: number;
|
|
4
|
-
json:
|
|
23
|
+
json: RouteDataResponse;
|
|
5
24
|
};
|
|
6
25
|
/**
|
|
7
26
|
* Revalidates route data by removing it from the cache.
|
|
@@ -56,4 +75,4 @@ type GetRouteDataOptions = {
|
|
|
56
75
|
};
|
|
57
76
|
declare function getRouteData(url: string, options?: GetRouteDataOptions): Promise<RouteData>;
|
|
58
77
|
|
|
59
|
-
export { type GetRouteDataOptions, getRouteData, prefetchRouteData, revalidate, revalidatePath, revalidateRouteData };
|
|
78
|
+
export { type GetRouteDataOptions, type RouteDataResponse, getRouteData, prefetchRouteData, revalidate, revalidatePath, revalidateRouteData };
|