@devlusoft/devix 0.4.4 → 0.5.0
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 +64 -9
- package/dist/cli/build.js +27 -17
- package/dist/cli/build.js.map +3 -3
- package/dist/cli/dev-server.js +31 -21
- package/dist/cli/dev-server.js.map +4 -4
- package/dist/cli/generate.js +29 -19
- package/dist/cli/generate.js.map +3 -3
- package/dist/cli/index.js +30 -20
- package/dist/cli/index.js.map +4 -4
- package/dist/cli/start.js +1 -1
- package/dist/cli/start.js.map +4 -4
- package/dist/config.d.ts +61 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +3 -3
- package/dist/runtime/api-context.d.ts +9 -4
- package/dist/runtime/api-context.js +1 -1
- package/dist/runtime/api-context.js.map +3 -3
- package/dist/runtime/context.d.ts +1 -0
- package/dist/runtime/context.js.map +2 -2
- package/dist/runtime/create-handler.d.ts +52 -2
- package/dist/runtime/create-handler.js +1 -1
- package/dist/runtime/create-handler.js.map +3 -3
- package/dist/runtime/error-boundary.d.ts +7 -1
- package/dist/runtime/error-boundary.js +1 -1
- package/dist/runtime/error-boundary.js.map +3 -3
- package/dist/runtime/fetch.d.ts +1 -0
- package/dist/runtime/fetch.js +1 -1
- package/dist/runtime/fetch.js.map +3 -3
- package/dist/runtime/index.d.ts +6 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +4 -4
- package/dist/runtime/link.js.map +2 -2
- package/dist/runtime/router-provider.d.ts +24 -1
- package/dist/runtime/router-provider.js +1 -1
- package/dist/runtime/router-provider.js.map +3 -3
- package/dist/runtime/server-app.d.ts +2 -1
- package/dist/runtime/server-app.js +1 -1
- package/dist/runtime/server-app.js.map +3 -3
- package/dist/runtime/server-client.d.ts +66 -0
- package/dist/runtime/server-client.js +2 -0
- package/dist/runtime/server-client.js.map +7 -0
- package/dist/server/api.d.ts +2 -1
- package/dist/server/api.js +1 -1
- package/dist/server/api.js.map +4 -4
- package/dist/server/handler-store.d.ts +12 -0
- package/dist/server/handler-store.js.map +2 -2
- package/dist/server/public-index.js.map +2 -2
- package/dist/server/render.d.ts +8 -0
- package/dist/server/render.js +1 -1
- package/dist/server/render.js.map +4 -4
- package/dist/server/routes.d.ts +4 -2
- package/dist/server/routes.js +1 -1
- package/dist/server/routes.js.map +4 -4
- package/dist/server/server-bound.d.ts +11 -0
- package/dist/server/server-bound.js +2 -0
- package/dist/server/server-bound.js.map +7 -0
- package/dist/server/server-proxy.d.ts +15 -0
- package/dist/server/server-proxy.js +2 -0
- package/dist/server/server-proxy.js.map +7 -0
- package/dist/server/types.d.ts +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/utils/banner.js +1 -1
- package/dist/utils/glob.d.ts +11 -0
- package/dist/utils/glob.js +2 -0
- package/dist/utils/glob.js.map +7 -0
- package/dist/utils/response.d.ts +33 -1
- package/dist/utils/response.js +1 -1
- package/dist/utils/response.js.map +3 -3
- package/dist/utils/standard-schema.d.ts +39 -0
- package/dist/utils/standard-schema.js +1 -0
- package/dist/utils/standard-schema.js.map +7 -0
- package/dist/vite/codegen/entry-client.js +5 -3
- package/dist/vite/codegen/entry-client.js.map +2 -2
- package/dist/vite/codegen/page-types.d.ts +11 -2
- package/dist/vite/codegen/page-types.js +3 -3
- package/dist/vite/codegen/page-types.js.map +3 -3
- package/dist/vite/codegen/server-entry.js +16 -8
- package/dist/vite/codegen/server-entry.js.map +2 -2
- package/dist/vite/index.js +26 -16
- package/dist/vite/index.js.map +3 -3
- package/package.json +5 -5
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,44 @@
|
|
|
1
1
|
import type { UserConfig } from "vite";
|
|
2
|
+
export interface PrepareContext {
|
|
3
|
+
/** Request entrante del cliente. */
|
|
4
|
+
request: Request;
|
|
5
|
+
/** Headers mutables que se enviarán al backend. Agrega aquí auth, tracing, tenant, etc. */
|
|
6
|
+
headers: Headers;
|
|
7
|
+
/** URL mutable de destino. Puedes reescribir `pathname` antes de proxear. */
|
|
8
|
+
url: URL;
|
|
9
|
+
}
|
|
10
|
+
export interface ServerBackendConfig {
|
|
11
|
+
/**
|
|
12
|
+
* URL base del backend. Todas las paths del namespace se anteponen a esta URL.
|
|
13
|
+
* Ej: `process.env.API_URL` → `'http://localhost:8080'`
|
|
14
|
+
*/
|
|
15
|
+
url: string;
|
|
16
|
+
/**
|
|
17
|
+
* Hook que corre antes de proxear cada request. Recibe el `Request` del cliente,
|
|
18
|
+
* los `headers` mutables que irán al backend, y la `url` mutable de destino.
|
|
19
|
+
*
|
|
20
|
+
* - Retorna `void` para continuar con el proxy.
|
|
21
|
+
* - Retorna `Response` para cortar y devolverle ese response al cliente (útil para 401, 429, etc.).
|
|
22
|
+
*
|
|
23
|
+
* Solo úsalo para pass-through de credenciales del usuario (cookies, sesión). Para
|
|
24
|
+
* APIs de terceros con keys del server (Stripe, SendGrid), usa un handler explícito en
|
|
25
|
+
* `app/api/` con autorización propia.
|
|
26
|
+
*/
|
|
27
|
+
prepare?: (ctx: PrepareContext) => Response | void | Promise<Response | void>;
|
|
28
|
+
/**
|
|
29
|
+
* Lista de paths permitidos (glob). Sin esto, el proxy responde 403 a todo
|
|
30
|
+
* (deny-all por defecto). Defense in depth.
|
|
31
|
+
*
|
|
32
|
+
* Ej: `['/v1/**', '/v2/users/**']`
|
|
33
|
+
*/
|
|
34
|
+
allowedPaths?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Lista de paths explícitamente denegados, evaluada después de `allowedPaths`.
|
|
37
|
+
*
|
|
38
|
+
* Ej: `['/v1/admin/internal/**']`
|
|
39
|
+
*/
|
|
40
|
+
deniedPaths?: string[];
|
|
41
|
+
}
|
|
2
42
|
export interface DevixConfig {
|
|
3
43
|
port?: number;
|
|
4
44
|
host?: string | boolean;
|
|
@@ -12,6 +52,27 @@ export interface DevixConfig {
|
|
|
12
52
|
vite?: UserConfig;
|
|
13
53
|
loaderTimeout?: number | string;
|
|
14
54
|
output?: 'server' | 'static';
|
|
55
|
+
/**
|
|
56
|
+
* Backends remotos accesibles vía `$server.<namespace>.<method>(path)`.
|
|
57
|
+
*
|
|
58
|
+
* Cada namespace se proxy-ea en `/_devix/server/<namespace>/<path>` para el cliente,
|
|
59
|
+
* y se hace fetch directo desde el server (loaders/handlers vía `ctx.$server`).
|
|
60
|
+
*
|
|
61
|
+
* Ejemplo:
|
|
62
|
+
* ```ts
|
|
63
|
+
* server: {
|
|
64
|
+
* api: {
|
|
65
|
+
* url: process.env.API_URL!,
|
|
66
|
+
* prepare: ({ request, headers }) => {
|
|
67
|
+
* const sid = getCookie(request, 'sid')
|
|
68
|
+
* if (sid) headers.set('Authorization', `Bearer ${sid}`)
|
|
69
|
+
* },
|
|
70
|
+
* allowedPaths: ['/v1/**'],
|
|
71
|
+
* },
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
server?: Record<string, ServerBackendConfig>;
|
|
15
76
|
}
|
|
16
77
|
export interface ResolvedDirs {
|
|
17
78
|
appDir: string;
|
package/dist/config.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function
|
|
1
|
+
function s(r){return n(r.server),r}function o(r){let e=r.appDir??"app";return{appDir:e,pagesDir:`${e}/pages`,apiDir:`${e}/api`}}var t=/^[a-zA-Z][a-zA-Z0-9_]*$/;function n(r){if(r)for(let[e,i]of Object.entries(r)){if(!t.test(e))throw new Error(`[devix] Invalid server namespace "${e}". Must match /^[a-zA-Z][a-zA-Z0-9_]*$/.`);if(!i.url||typeof i.url!="string")throw new Error(`[devix] server.${e}.url is required and must be a string.`);try{new URL(i.url)}catch{throw new Error(`[devix] server.${e}.url is not a valid URL: "${i.url}".`)}(!i.allowedPaths||i.allowedPaths.length===0)&&console.warn(`[devix] server.${e} has no allowedPaths configured \u2014 proxy will respond 403 to all requests. Add at least one glob (e.g. allowedPaths: ['/v1/**']) to enable the proxy.`)}}export{s as defineConfig,o as resolveDirs};
|
|
2
2
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/config.ts"],
|
|
4
|
-
"sourcesContent": ["import type { UserConfig } from \"vite\"\n\nexport interface DevixConfig {\n port?: number\n host?: string | boolean\n css?: string[]\n appDir?: string\n publicDir?: string\n envPrefix?: string | string[]\n html?: { lang?: string }\n vite?: UserConfig\n loaderTimeout?: number | string\n output?: 'server' | 'static'\n}\n\nexport interface ResolvedDirs {\n appDir: string\n pagesDir: string\n apiDir: string\n}\n\nexport function defineConfig(config: DevixConfig): DevixConfig {
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["defineConfig", "config", "resolveDirs", "appDir"]
|
|
4
|
+
"sourcesContent": ["import type { UserConfig } from \"vite\"\n\nexport interface PrepareContext {\n /** Request entrante del cliente. */\n request: Request\n /** Headers mutables que se enviar\u00E1n al backend. Agrega aqu\u00ED auth, tracing, tenant, etc. */\n headers: Headers\n /** URL mutable de destino. Puedes reescribir `pathname` antes de proxear. */\n url: URL\n}\n\nexport interface ServerBackendConfig {\n /**\n * URL base del backend. Todas las paths del namespace se anteponen a esta URL.\n * Ej: `process.env.API_URL` \u2192 `'http://localhost:8080'`\n */\n url: string\n\n /**\n * Hook que corre antes de proxear cada request. Recibe el `Request` del cliente,\n * los `headers` mutables que ir\u00E1n al backend, y la `url` mutable de destino.\n *\n * - Retorna `void` para continuar con el proxy.\n * - Retorna `Response` para cortar y devolverle ese response al cliente (\u00FAtil para 401, 429, etc.).\n *\n * Solo \u00FAsalo para pass-through de credenciales del usuario (cookies, sesi\u00F3n). Para\n * APIs de terceros con keys del server (Stripe, SendGrid), usa un handler expl\u00EDcito en\n * `app/api/` con autorizaci\u00F3n propia.\n */\n prepare?: (ctx: PrepareContext) => Response | void | Promise<Response | void>\n\n /**\n * Lista de paths permitidos (glob). Sin esto, el proxy responde 403 a todo\n * (deny-all por defecto). Defense in depth.\n *\n * Ej: `['/v1/**', '/v2/users/**']`\n */\n allowedPaths?: string[]\n\n /**\n * Lista de paths expl\u00EDcitamente denegados, evaluada despu\u00E9s de `allowedPaths`.\n *\n * Ej: `['/v1/admin/internal/**']`\n */\n deniedPaths?: string[]\n}\n\nexport interface DevixConfig {\n port?: number\n host?: string | boolean\n css?: string[]\n appDir?: string\n publicDir?: string\n envPrefix?: string | string[]\n html?: { lang?: string }\n vite?: UserConfig\n loaderTimeout?: number | string\n output?: 'server' | 'static'\n /**\n * Backends remotos accesibles v\u00EDa `$server.<namespace>.<method>(path)`.\n *\n * Cada namespace se proxy-ea en `/_devix/server/<namespace>/<path>` para el cliente,\n * y se hace fetch directo desde el server (loaders/handlers v\u00EDa `ctx.$server`).\n *\n * Ejemplo:\n * ```ts\n * server: {\n * api: {\n * url: process.env.API_URL!,\n * prepare: ({ request, headers }) => {\n * const sid = getCookie(request, 'sid')\n * if (sid) headers.set('Authorization', `Bearer ${sid}`)\n * },\n * allowedPaths: ['/v1/**'],\n * },\n * }\n * ```\n */\n server?: Record<string, ServerBackendConfig>\n}\n\nexport interface ResolvedDirs {\n appDir: string\n pagesDir: string\n apiDir: string\n}\n\nexport function defineConfig(config: DevixConfig): DevixConfig {\n validateServerConfig(config.server)\n return config\n}\n\nexport function resolveDirs(config: DevixConfig): ResolvedDirs {\n const appDir = config.appDir ?? \"app\"\n return {\n appDir,\n pagesDir: `${appDir}/pages`,\n apiDir: `${appDir}/api`,\n }\n}\n\nconst NAMESPACE_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/\n\nfunction validateServerConfig(server: DevixConfig['server']): void {\n if (!server) return\n for (const [name, cfg] of Object.entries(server)) {\n if (!NAMESPACE_RE.test(name)) {\n throw new Error(\n `[devix] Invalid server namespace \"${name}\". Must match /^[a-zA-Z][a-zA-Z0-9_]*$/.`\n )\n }\n if (!cfg.url || typeof cfg.url !== 'string') {\n throw new Error(`[devix] server.${name}.url is required and must be a string.`)\n }\n try {\n new URL(cfg.url)\n } catch {\n throw new Error(`[devix] server.${name}.url is not a valid URL: \"${cfg.url}\".`)\n }\n if (!cfg.allowedPaths || cfg.allowedPaths.length === 0) {\n console.warn(\n `[devix] server.${name} has no allowedPaths configured \u2014 proxy will respond 403 to all requests. ` +\n `Add at least one glob (e.g. allowedPaths: ['/v1/**']) to enable the proxy.`\n )\n }\n }\n}"],
|
|
5
|
+
"mappings": "AAuFO,SAASA,EAAaC,EAAkC,CAC3D,OAAAC,EAAqBD,EAAO,MAAM,EAC3BA,CACX,CAEO,SAASE,EAAYF,EAAmC,CAC3D,IAAMG,EAASH,EAAO,QAAU,MAChC,MAAO,CACH,OAAAG,EACA,SAAU,GAAGA,CAAM,SACnB,OAAQ,GAAGA,CAAM,MACrB,CACJ,CAEA,IAAMC,EAAe,0BAErB,SAASH,EAAqBI,EAAqC,CAC/D,GAAKA,EACL,OAAW,CAACC,EAAMC,CAAG,IAAK,OAAO,QAAQF,CAAM,EAAG,CAC9C,GAAI,CAACD,EAAa,KAAKE,CAAI,EACvB,MAAM,IAAI,MACN,qCAAqCA,CAAI,0CAC7C,EAEJ,GAAI,CAACC,EAAI,KAAO,OAAOA,EAAI,KAAQ,SAC/B,MAAM,IAAI,MAAM,kBAAkBD,CAAI,wCAAwC,EAElF,GAAI,CACA,IAAI,IAAIC,EAAI,GAAG,CACnB,MAAQ,CACJ,MAAM,IAAI,MAAM,kBAAkBD,CAAI,6BAA6BC,EAAI,GAAG,IAAI,CAClF,EACI,CAACA,EAAI,cAAgBA,EAAI,aAAa,SAAW,IACjD,QAAQ,KACJ,kBAAkBD,CAAI,2JAE1B,CAER,CACJ",
|
|
6
|
+
"names": ["defineConfig", "config", "validateServerConfig", "resolveDirs", "appDir", "NAMESPACE_RE", "server", "name", "cfg"]
|
|
7
7
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import type { DevixHandler } from './create-handler';
|
|
2
|
+
import type { RouteError } from '../utils/response';
|
|
3
|
+
import type { BackendClient } from './server-client';
|
|
2
4
|
export declare class RouteContext {
|
|
3
5
|
readonly params: Record<string, string>;
|
|
6
|
+
readonly request: Request;
|
|
7
|
+
readonly url: URL;
|
|
8
|
+
readonly $server: Record<string, BackendClient<string>>;
|
|
4
9
|
private _state;
|
|
5
|
-
constructor(params?: Record<string, string
|
|
10
|
+
constructor(params: Record<string, string>, request: Request, url: URL, $server?: Record<string, BackendClient<string>>);
|
|
6
11
|
set<T>(key: string, value: T): void;
|
|
7
12
|
get<T>(key: string): T | undefined;
|
|
8
13
|
}
|
|
9
|
-
export type RouteResult = Response | Record<string, unknown> | unknown[] | null | void;
|
|
10
|
-
export type RouteHandler = (ctx: RouteContext
|
|
14
|
+
export type RouteResult = Response | RouteError | Record<string, unknown> | unknown[] | null | void;
|
|
15
|
+
export type RouteHandler = (ctx: RouteContext) => Promise<RouteResult> | RouteResult;
|
|
11
16
|
export interface MiddlewareModule {
|
|
12
|
-
middleware: (ctx: RouteContext
|
|
17
|
+
middleware: (ctx: RouteContext) => Promise<Response | null> | Response | null;
|
|
13
18
|
}
|
|
14
19
|
type AnyHandler = RouteHandler | DevixHandler<any, any>;
|
|
15
20
|
export interface RouteModule {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var t=class{params;request;url;$server;_state=new Map;constructor(e,r,n,s={}){this.params=e,this.request=r,this.url=n,this.$server=s}set(e,r){this._state.set(e,r)}get(e){return this._state.get(e)}};export{t as RouteContext};
|
|
2
2
|
//# sourceMappingURL=api-context.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/runtime/api-context.ts"],
|
|
4
|
-
"sourcesContent": ["import type {DevixHandler} from './create-handler'\n\nexport class RouteContext {\n readonly params: Record<string, string>\n private _state = new Map<string, unknown>()\n\n constructor(params: Record<string, string
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["RouteContext", "params", "key", "value"]
|
|
4
|
+
"sourcesContent": ["import type {DevixHandler} from './create-handler'\nimport type {RouteError} from '../utils/response'\nimport type {BackendClient} from './server-client'\n\nexport class RouteContext {\n readonly params: Record<string, string>\n readonly request: Request\n readonly url: URL\n readonly $server: Record<string, BackendClient<string>>\n private _state = new Map<string, unknown>()\n\n constructor(\n params: Record<string, string>,\n request: Request,\n url: URL,\n $server: Record<string, BackendClient<string>> = {},\n ) {\n this.params = params\n this.request = request\n this.url = url\n this.$server = $server\n }\n\n set<T>(key: string, value: T): void {\n this._state.set(key, value)\n }\n\n get<T>(key: string): T | undefined {\n return this._state.get(key) as T\n }\n}\n\nexport type RouteResult = Response | RouteError | Record<string, unknown> | unknown[] | null | void\n\nexport type RouteHandler = (ctx: RouteContext) => Promise<RouteResult> | RouteResult\n\nexport interface MiddlewareModule {\n middleware: (ctx: RouteContext) => Promise<Response | null> | Response | null\n}\n\ntype AnyHandler = RouteHandler | DevixHandler<any, any>\n\nexport interface RouteModule {\n GET?: AnyHandler\n POST?: AnyHandler\n PUT?: AnyHandler\n PATCH?: AnyHandler\n DELETE?: AnyHandler\n HEAD?: AnyHandler\n OPTIONS?: AnyHandler\n}\n"],
|
|
5
|
+
"mappings": "AAIO,IAAMA,EAAN,KAAmB,CACb,OACA,QACA,IACA,QACD,OAAS,IAAI,IAErB,YACIC,EACAC,EACAC,EACAC,EAAiD,CAAC,EACpD,CACE,KAAK,OAASH,EACd,KAAK,QAAUC,EACf,KAAK,IAAMC,EACX,KAAK,QAAUC,CACnB,CAEA,IAAOC,EAAaC,EAAgB,CAChC,KAAK,OAAO,IAAID,EAAKC,CAAK,CAC9B,CAEA,IAAOD,EAA4B,CAC/B,OAAO,KAAK,OAAO,IAAIA,CAAG,CAC9B,CACJ",
|
|
6
|
+
"names": ["RouteContext", "params", "request", "url", "$server", "key", "value"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/runtime/context.tsx"],
|
|
4
|
-
"sourcesContent": ["import {createContext, Context, ComponentType} from \"react\";\nimport {Metadata, Viewport} from \"../types\";\nimport {LayoutProps, PageProps} from \"../server/types\";\n\nexport interface NavigateOptions {\n replace?: boolean\n viewTransition?: boolean\n}\n\nexport interface RouterContextValue {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n navigate: (to: string, options?: NavigateOptions) => Promise<void>\n revalidate: () => Promise<void>\n prefetchRoute: (href: string) => void\n isNavigating: boolean\n}\n\nexport interface PageMetaContextValue {\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry?: string\n}\n\nexport interface RouteDataContextValue {\n loaderData: unknown\n params: Record<string, string>\n}\n\nconst g = globalThis as any\n\ng.__devix_RouterContext__ ??= createContext<RouterContextValue | null>(null)\nexport const RouterContext: Context<RouterContextValue | null> = g.__devix_RouterContext__\n\ng.__devix_PageMetaContext__ ??= createContext<PageMetaContextValue | null>(null)\ng.__devix_RouteDataContext__ ??= createContext<RouteDataContextValue | null>(null)\n\nexport const PageMetaContext: Context<PageMetaContextValue | null> = g.__devix_PageMetaContext__\nexport const RouteDataContext: Context<RouteDataContextValue | null> = g.__devix_RouteDataContext__\n\n"],
|
|
5
|
-
"mappings": "AAAA,OAAQ,iBAAAA,MAA4C,
|
|
4
|
+
"sourcesContent": ["import {createContext, Context, ComponentType} from \"react\";\nimport {Metadata, Viewport} from \"../types\";\nimport {LayoutProps, PageProps} from \"../server/types\";\n\nexport interface NavigateOptions {\n replace?: boolean\n viewTransition?: boolean\n}\n\nexport interface RouterContextValue {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n guardData: unknown\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n navigate: (to: string, options?: NavigateOptions) => Promise<void>\n revalidate: () => Promise<void>\n prefetchRoute: (href: string) => void\n isNavigating: boolean\n}\n\nexport interface PageMetaContextValue {\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry?: string\n}\n\nexport interface RouteDataContextValue {\n loaderData: unknown\n params: Record<string, string>\n}\n\nconst g = globalThis as any\n\ng.__devix_RouterContext__ ??= createContext<RouterContextValue | null>(null)\nexport const RouterContext: Context<RouterContextValue | null> = g.__devix_RouterContext__\n\ng.__devix_PageMetaContext__ ??= createContext<PageMetaContextValue | null>(null)\ng.__devix_RouteDataContext__ ??= createContext<RouteDataContextValue | null>(null)\n\nexport const PageMetaContext: Context<PageMetaContextValue | null> = g.__devix_PageMetaContext__\nexport const RouteDataContext: Context<RouteDataContextValue | null> = g.__devix_RouteDataContext__\n\n"],
|
|
5
|
+
"mappings": "AAAA,OAAQ,iBAAAA,MAA4C,QAoCpD,IAAMC,EAAI,WAEVA,EAAE,0BAA4BD,EAAyC,IAAI,EACpE,IAAME,EAAoDD,EAAE,wBAEnEA,EAAE,4BAA8BD,EAA2C,IAAI,EAC/EC,EAAE,6BAA+BD,EAA4C,IAAI,EAE1E,IAAMG,EAAwDF,EAAE,0BAC1DG,EAA0DH,EAAE",
|
|
6
6
|
"names": ["createContext", "g", "RouterContext", "PageMetaContext", "RouteDataContext"]
|
|
7
7
|
}
|
|
@@ -1,10 +1,60 @@
|
|
|
1
|
+
import type { RouteContext } from './api-context';
|
|
2
|
+
import type { StandardSchemaV1 } from '../utils/standard-schema';
|
|
1
3
|
export declare const HANDLER_BRAND: "__devix_handler__";
|
|
2
4
|
export interface DevixHandler<TBody = undefined, TReturn = unknown> {
|
|
3
5
|
readonly [HANDLER_BRAND]: true;
|
|
4
6
|
readonly fn: (...args: any[]) => any;
|
|
7
|
+
readonly schema?: StandardSchemaV1;
|
|
5
8
|
readonly __body: TBody;
|
|
6
9
|
readonly __return: TReturn;
|
|
7
10
|
}
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Crea un handler API tipado.
|
|
13
|
+
*
|
|
14
|
+
* El primer argumento (si lo declaras) es el body parseado automáticamente:
|
|
15
|
+
* - `application/json` → objeto JS
|
|
16
|
+
* - `multipart/form-data` o `application/x-www-form-urlencoded` → FormData
|
|
17
|
+
* - cualquier otro → string
|
|
18
|
+
*
|
|
19
|
+
* El segundo argumento es `ctx: RouteContext` con `request`, `url`, `params`,
|
|
20
|
+
* y los helpers `get`/`set` para state heredado de middleware.
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* // sin body
|
|
24
|
+
* export const GET = createHandler(async () => ({ ok: true }))
|
|
25
|
+
*
|
|
26
|
+
* // con body tipado
|
|
27
|
+
* export const POST = createHandler(async (body: Login) => ...)
|
|
28
|
+
*
|
|
29
|
+
* // con body y ctx
|
|
30
|
+
* export const POST = createHandler(async (body: Login, ctx) => {
|
|
31
|
+
* const user = ctx.get<User>('user')
|
|
32
|
+
* const ua = ctx.request.headers.get('User-Agent')
|
|
33
|
+
* })
|
|
34
|
+
*
|
|
35
|
+
* // solo ctx, sin body (ej. GET que necesita query params)
|
|
36
|
+
* export const GET = createHandler(async (_body, ctx) => {
|
|
37
|
+
* const filter = ctx.url.searchParams.get('filter')
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
type ExtractBody<TFn> = TFn extends () => any ? undefined : TFn extends (body: infer B, ...rest: any[]) => any ? B : undefined;
|
|
42
|
+
type HandlerFn = ((body: any, ctx: RouteContext) => any) | (() => any);
|
|
43
|
+
export declare function createHandler<TFn extends HandlerFn>(fn: TFn): DevixHandler<ExtractBody<TFn>, Awaited<ReturnType<TFn>>>;
|
|
44
|
+
/**
|
|
45
|
+
* Overload con Standard Schema. devix valida el body automáticamente y, si
|
|
46
|
+
* falla, devuelve `400` con shape `ErrorBody` y `code: 'VALIDATION_ERROR'`.
|
|
47
|
+
* El body recibido por el handler está ya validado y tipado al output del schema.
|
|
48
|
+
*
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { z } from 'zod'
|
|
51
|
+
*
|
|
52
|
+
* const Input = z.object({ email: z.email(), password: z.string().min(8) })
|
|
53
|
+
*
|
|
54
|
+
* export const POST = createHandler(Input, async (body, ctx) => {
|
|
55
|
+
* // body: z.infer<typeof Input>, ya validado
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function createHandler<TSchema extends StandardSchemaV1, TReturn>(schema: TSchema, fn: (body: StandardSchemaV1.InferOutput<TSchema>, ctx: RouteContext) => TReturn | Promise<TReturn>): DevixHandler<StandardSchemaV1.InferInput<TSchema>, Awaited<TReturn>>;
|
|
10
60
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var a="__devix_handler__";function t(n,e){return e?{[a]:!0,fn:e,schema:n}:{[a]:!0,fn:n}}export{a as HANDLER_BRAND,t as createHandler};
|
|
2
2
|
//# sourceMappingURL=create-handler.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/runtime/create-handler.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["HANDLER_BRAND", "createHandler", "
|
|
4
|
+
"sourcesContent": ["import type {RouteContext} from './api-context'\nimport type {StandardSchemaV1} from '../utils/standard-schema'\n\nexport const HANDLER_BRAND = '__devix_handler__' as const\n\nexport interface DevixHandler<TBody = undefined, TReturn = unknown> {\n readonly [HANDLER_BRAND]: true\n readonly fn: (...args: any[]) => any\n readonly schema?: StandardSchemaV1\n readonly __body: TBody\n readonly __return: TReturn\n}\n\n/**\n * Crea un handler API tipado.\n *\n * El primer argumento (si lo declaras) es el body parseado autom\u00E1ticamente:\n * - `application/json` \u2192 objeto JS\n * - `multipart/form-data` o `application/x-www-form-urlencoded` \u2192 FormData\n * - cualquier otro \u2192 string\n *\n * El segundo argumento es `ctx: RouteContext` con `request`, `url`, `params`,\n * y los helpers `get`/`set` para state heredado de middleware.\n *\n * ```ts\n * // sin body\n * export const GET = createHandler(async () => ({ ok: true }))\n *\n * // con body tipado\n * export const POST = createHandler(async (body: Login) => ...)\n *\n * // con body y ctx\n * export const POST = createHandler(async (body: Login, ctx) => {\n * const user = ctx.get<User>('user')\n * const ua = ctx.request.headers.get('User-Agent')\n * })\n *\n * // solo ctx, sin body (ej. GET que necesita query params)\n * export const GET = createHandler(async (_body, ctx) => {\n * const filter = ctx.url.searchParams.get('filter')\n * })\n * ```\n */\ntype ExtractBody<TFn> =\n TFn extends () => any ? undefined :\n TFn extends (body: infer B, ...rest: any[]) => any ? B :\n undefined\n\ntype HandlerFn = ((body: any, ctx: RouteContext) => any) | (() => any)\n\nexport function createHandler<TFn extends HandlerFn>(\n fn: TFn,\n): DevixHandler<ExtractBody<TFn>, Awaited<ReturnType<TFn>>>\n\n/**\n * Overload con Standard Schema. devix valida el body autom\u00E1ticamente y, si\n * falla, devuelve `400` con shape `ErrorBody` y `code: 'VALIDATION_ERROR'`.\n * El body recibido por el handler est\u00E1 ya validado y tipado al output del schema.\n *\n * ```ts\n * import { z } from 'zod'\n *\n * const Input = z.object({ email: z.email(), password: z.string().min(8) })\n *\n * export const POST = createHandler(Input, async (body, ctx) => {\n * // body: z.infer<typeof Input>, ya validado\n * })\n * ```\n */\nexport function createHandler<TSchema extends StandardSchemaV1, TReturn>(\n schema: TSchema,\n fn: (body: StandardSchemaV1.InferOutput<TSchema>, ctx: RouteContext) => TReturn | Promise<TReturn>,\n): DevixHandler<StandardSchemaV1.InferInput<TSchema>, Awaited<TReturn>>\n\nexport function createHandler(\n schemaOrFn: StandardSchemaV1 | ((...args: any[]) => any),\n maybeFn?: (...args: any[]) => any,\n): DevixHandler<any, any> {\n if (maybeFn) {\n return {\n [HANDLER_BRAND]: true,\n fn: maybeFn,\n schema: schemaOrFn as StandardSchemaV1,\n } as unknown as DevixHandler<any, any>\n }\n return {\n [HANDLER_BRAND]: true,\n fn: schemaOrFn as (...args: any[]) => any,\n } as unknown as DevixHandler<any, any>\n}\n"],
|
|
5
|
+
"mappings": "AAGO,IAAMA,EAAgB,oBAuEtB,SAASC,EACZC,EACAC,EACsB,CACtB,OAAIA,EACO,CACH,CAACH,CAAa,EAAG,GACjB,GAAIG,EACJ,OAAQD,CACZ,EAEG,CACH,CAACF,CAAa,EAAG,GACjB,GAAIE,CACR,CACJ",
|
|
6
|
+
"names": ["HANDLER_BRAND", "createHandler", "schemaOrFn", "maybeFn"]
|
|
7
7
|
}
|
|
@@ -12,8 +12,14 @@ export declare class DevixErrorBoundary extends Component<Props, State> {
|
|
|
12
12
|
static getDerivedStateFromError(err: unknown): State;
|
|
13
13
|
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
14
14
|
}
|
|
15
|
+
export interface DevixErrorOptions {
|
|
16
|
+
code?: string;
|
|
17
|
+
data?: unknown;
|
|
18
|
+
}
|
|
15
19
|
export declare class DevixError extends Error {
|
|
16
20
|
statusCode: number;
|
|
17
|
-
|
|
21
|
+
code?: string;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
constructor(statusCode: number, message: string, options?: DevixErrorOptions);
|
|
18
24
|
}
|
|
19
25
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Component as
|
|
1
|
+
import{Component as i}from"react";import{jsx as s}from"react/jsx-runtime";var o=class extends i{state={error:null};static getDerivedStateFromError(r){return r instanceof t?{error:{statusCode:r.statusCode,message:r.message}}:{error:{statusCode:500,message:r instanceof Error?r.message:"Unknown error"}}}render(){return this.state.error&&this.props.ErrorPage?s(this.props.ErrorPage,{...this.state.error}):this.state.error?s("h1",{children:this.state.error.statusCode}):this.props.children}},t=class extends Error{statusCode;code;data;constructor(r,a,e){super(a),this.name="DevixError",this.statusCode=r,this.code=e?.code,this.data=e?.data}};export{t as DevixError,o as DevixErrorBoundary};
|
|
2
2
|
//# sourceMappingURL=error-boundary.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/runtime/error-boundary.tsx"],
|
|
4
|
-
"sourcesContent": ["import {Component, ComponentType, ReactNode} from \"react\";\nimport {ErrorProps} from \"../server/types\";\n\ninterface Props {\n ErrorPage?: ComponentType<ErrorProps>\n children: ReactNode\n}\n\ninterface State {\n error: ErrorProps | null\n}\n\nexport class DevixErrorBoundary extends Component<Props, State> {\n state: State = { error: null }\n\n static getDerivedStateFromError(err: unknown): State {\n if (err instanceof DevixError) {\n return {\n error: {statusCode: err.statusCode, message: err.message}\n }\n }\n return {\n error: {statusCode: 500, message: err instanceof Error ? err.message : 'Unknown error'}\n }\n }\n\n render() {\n if (this.state.error && this.props.ErrorPage) {\n return <this.props.ErrorPage {...this.state.error} />\n }\n if (this.state.error) {\n return <h1>{this.state.error.statusCode}</h1>\n }\n return this.props.children\n }\n}\n\nexport class DevixError extends Error {\n statusCode: number\n constructor(statusCode: number, message: string) {\n super(message)\n this.statusCode = statusCode\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,OAAQ,aAAAA,MAA0C,QA4B/B,cAAAC,MAAA,oBAhBZ,IAAMC,EAAN,cAAiCF,CAAwB,CAC5D,MAAe,CAAE,MAAO,IAAK,EAE7B,OAAO,yBAAyBG,EAAqB,CACjD,OAAIA,aAAeC,EACR,CACH,MAAO,CAAC,WAAYD,EAAI,WAAY,QAASA,EAAI,OAAO,CAC5D,EAEI,CACJ,MAAO,CAAC,WAAY,IAAK,QAASA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAC1F,CACJ,CAEA,QAAS,CACL,OAAI,KAAK,MAAM,OAAS,KAAK,MAAM,UACxBF,EAAC,KAAK,MAAM,UAAX,CAAsB,GAAG,KAAK,MAAM,MAAO,EAEnD,KAAK,MAAM,MACJA,EAAC,MAAI,cAAK,MAAM,MAAM,WAAW,EAErC,KAAK,MAAM,QACtB,CACJ,
|
|
6
|
-
"names": ["Component", "jsx", "DevixErrorBoundary", "err", "DevixError", "statusCode", "message"]
|
|
4
|
+
"sourcesContent": ["import {Component, ComponentType, ReactNode} from \"react\";\nimport {ErrorProps} from \"../server/types\";\n\ninterface Props {\n ErrorPage?: ComponentType<ErrorProps>\n children: ReactNode\n}\n\ninterface State {\n error: ErrorProps | null\n}\n\nexport class DevixErrorBoundary extends Component<Props, State> {\n state: State = { error: null }\n\n static getDerivedStateFromError(err: unknown): State {\n if (err instanceof DevixError) {\n return {\n error: {statusCode: err.statusCode, message: err.message}\n }\n }\n return {\n error: {statusCode: 500, message: err instanceof Error ? err.message : 'Unknown error'}\n }\n }\n\n render() {\n if (this.state.error && this.props.ErrorPage) {\n return <this.props.ErrorPage {...this.state.error} />\n }\n if (this.state.error) {\n return <h1>{this.state.error.statusCode}</h1>\n }\n return this.props.children\n }\n}\n\nexport interface DevixErrorOptions {\n code?: string\n data?: unknown\n}\n\nexport class DevixError extends Error {\n statusCode: number\n code?: string\n data?: unknown\n constructor(statusCode: number, message: string, options?: DevixErrorOptions) {\n super(message)\n this.name = 'DevixError'\n this.statusCode = statusCode\n this.code = options?.code\n this.data = options?.data\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAQ,aAAAA,MAA0C,QA4B/B,cAAAC,MAAA,oBAhBZ,IAAMC,EAAN,cAAiCF,CAAwB,CAC5D,MAAe,CAAE,MAAO,IAAK,EAE7B,OAAO,yBAAyBG,EAAqB,CACjD,OAAIA,aAAeC,EACR,CACH,MAAO,CAAC,WAAYD,EAAI,WAAY,QAASA,EAAI,OAAO,CAC5D,EAEI,CACJ,MAAO,CAAC,WAAY,IAAK,QAASA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAC1F,CACJ,CAEA,QAAS,CACL,OAAI,KAAK,MAAM,OAAS,KAAK,MAAM,UACxBF,EAAC,KAAK,MAAM,UAAX,CAAsB,GAAG,KAAK,MAAM,MAAO,EAEnD,KAAK,MAAM,MACJA,EAAC,MAAI,cAAK,MAAM,MAAM,WAAW,EAErC,KAAK,MAAM,QACtB,CACJ,EAOaG,EAAN,cAAyB,KAAM,CAClC,WACA,KACA,KACA,YAAYC,EAAoBC,EAAiBC,EAA6B,CAC1E,MAAMD,CAAO,EACb,KAAK,KAAO,aACZ,KAAK,WAAaD,EAClB,KAAK,KAAOE,GAAS,KACrB,KAAK,KAAOA,GAAS,IACzB,CACJ",
|
|
6
|
+
"names": ["Component", "jsx", "DevixErrorBoundary", "err", "DevixError", "statusCode", "message", "options"]
|
|
7
7
|
}
|
package/dist/runtime/fetch.d.ts
CHANGED
package/dist/runtime/fetch.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
function i(e){if(e&&typeof e=="object"&&"message"in e){let n=e.message;if(typeof n=="string"&&n.length>0)return n}return null}var s=class extends Error{constructor(t,o,u,r){super(i(r)??`HTTP ${t}: ${o}`);this.status=t;this.statusText=o;this.response=u;this.body=r;this.name="FetchError"}get code(){if(this.body&&typeof this.body=="object"&&"code"in this.body){let t=this.body.code;return typeof t=="string"?t:void 0}}};export{s as FetchError};
|
|
2
2
|
//# sourceMappingURL=fetch.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/runtime/fetch.ts"],
|
|
4
|
-
"sourcesContent": ["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'\n\nexport class FetchError<E = unknown> extends Error {\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly response: Response,\n public readonly body?: E,\n ) {\n super(`HTTP ${status}: ${statusText}`)\n this.name = 'FetchError'\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["FetchError", "status", "statusText", "response", "
|
|
4
|
+
"sourcesContent": ["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'\n\nfunction extractMessage(body: unknown): string | null {\n if (body && typeof body === 'object' && 'message' in body) {\n const m = (body as {message: unknown}).message\n if (typeof m === 'string' && m.length > 0) return m\n }\n return null\n}\n\nexport class FetchError<E = unknown> extends Error {\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly response: Response,\n public readonly body?: E,\n ) {\n super(extractMessage(body) ?? `HTTP ${status}: ${statusText}`)\n this.name = 'FetchError'\n }\n\n get code(): string | undefined {\n if (this.body && typeof this.body === 'object' && 'code' in this.body) {\n const c = (this.body as {code: unknown}).code\n return typeof c === 'string' ? c : undefined\n }\n return undefined\n }\n}\n"],
|
|
5
|
+
"mappings": "AAEA,SAASA,EAAeC,EAA8B,CAClD,GAAIA,GAAQ,OAAOA,GAAS,UAAY,YAAaA,EAAM,CACvD,IAAMC,EAAKD,EAA4B,QACvC,GAAI,OAAOC,GAAM,UAAYA,EAAE,OAAS,EAAG,OAAOA,CACtD,CACA,OAAO,IACX,CAEO,IAAMC,EAAN,cAAsC,KAAM,CAC/C,YACoBC,EACAC,EACAC,EACAL,EAClB,CACE,MAAMD,EAAeC,CAAI,GAAK,QAAQG,CAAM,KAAKC,CAAU,EAAE,EAL7C,YAAAD,EACA,gBAAAC,EACA,cAAAC,EACA,UAAAL,EAGhB,KAAK,KAAO,YAChB,CAEA,IAAI,MAA2B,CAC3B,GAAI,KAAK,MAAQ,OAAO,KAAK,MAAS,UAAY,SAAU,KAAK,KAAM,CACnE,IAAMM,EAAK,KAAK,KAAyB,KACzC,OAAO,OAAOA,GAAM,SAAWA,EAAI,MACvC,CAEJ,CACJ",
|
|
6
|
+
"names": ["extractMessage", "body", "m", "FetchError", "status", "statusText", "response", "c"]
|
|
7
7
|
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { useRouter, useNavigate, useRevalidate, useParams, useLoaderData, RouterProvider } from "./router-provider";
|
|
1
|
+
export { useRouter, useNavigate, useRevalidate, useParams, useLoaderData, useGuardData, RouterProvider } from "./router-provider";
|
|
2
2
|
export { Link } from "./link";
|
|
3
3
|
export type { Metadata, MetadataIcon, Viewport, LoaderContext, LoaderContextWithGuard, LoaderFunction, GuardFunction } from '../types';
|
|
4
4
|
export type { NavigateOptions } from './context';
|
|
@@ -7,11 +7,15 @@ export type { RouteHandler, RouteResult, MiddlewareModule } from './api-context'
|
|
|
7
7
|
export { getCookie, setCookie, deleteCookie } from '../utils/cookies';
|
|
8
8
|
export type { CookieOptions } from '../utils/cookies';
|
|
9
9
|
export { json, text, redirect, error } from '../utils/response';
|
|
10
|
-
export type { JsonResponse, Redirect, RedirectOptions, RouteError } from '../utils/response';
|
|
10
|
+
export type { JsonResponse, Redirect, RedirectOptions, RouteError, ErrorOptions, ErrorBody } from '../utils/response';
|
|
11
11
|
export { createHandler } from './create-handler';
|
|
12
12
|
export type { DevixHandler } from './create-handler';
|
|
13
|
+
export type { StandardSchemaV1 } from '../utils/standard-schema';
|
|
13
14
|
export { FetchError } from './fetch';
|
|
15
|
+
export { $server } from './server-client';
|
|
16
|
+
export type { BackendRoutes, BackendClient, ServerFetchOptions } from './server-client';
|
|
14
17
|
export { DevixError } from './error-boundary';
|
|
18
|
+
export type { DevixErrorOptions } from './error-boundary';
|
|
15
19
|
export type { HttpMethod } from './fetch';
|
|
16
20
|
import { type HttpMethod } from './fetch';
|
|
17
21
|
export interface ApiRoutes {
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useCallback as I,useContext as H,useEffect as ge,useRef as te,useState as re}from"react";import{RouterContext as F}from"virtual:devix/context";import{getDefaultErrorPage as ne,loadErrorPage as oe,matchClientRoute as ae}from"virtual:devix/client-routes";import{Fragment as X,jsx as A}from"react/jsx-runtime";function ce(e,t){let r=[];e.title&&r.push({tag:"title",children:e.title}),e.description&&r.push({tag:"meta",name:"description",content:e.description}),e.keywords?.length&&r.push({tag:"meta",name:"keywords",content:e.keywords.join(", ")});let n=e.og?.title??e.title;n&&r.push({tag:"meta",property:"og:title",content:n});let o=e.og?.description??e.description;o&&r.push({tag:"meta",property:"og:description",content:o}),e.og?.image&&r.push({tag:"meta",property:"og:image",content:e.og.image}),e.og?.type&&r.push({tag:"meta",property:"og:type",content:e.og.type}),e.og?.url&&r.push({tag:"meta",property:"og:url",content:e.og.url});let p=e.twitter?.title??e.title;p&&r.push({tag:"meta",name:"twitter:title",content:p});let y=e.twitter?.description??e.description;if(y&&r.push({tag:"meta",name:"twitter:description",content:y}),e.twitter?.card&&r.push({tag:"meta",name:"twitter:card",content:e.twitter.card}),e.twitter?.image&&r.push({tag:"meta",name:"twitter:image",content:e.twitter.image}),e.twitter?.creator&&r.push({tag:"meta",name:"twitter:creator",content:e.twitter.creator}),e.canonical&&r.push({tag:"link",rel:"canonical",href:e.canonical}),e.robots&&r.push({tag:"meta",name:"robots",content:e.robots}),e.alternates)for(let[c,f]of Object.entries(e.alternates))r.push({tag:"link",rel:"alternate",href:f,hrefLang:c});if(e.icons){let c=Array.isArray(e.icons)?e.icons:[e.icons];for(let f of c){let m=typeof f=="string"?{href:f}:f;r.push({tag:"link",rel:m.rel??"icon",href:m.href,...m.type&&{type:m.type},...m.sizes&&{sizes:m.sizes}})}}if(t){let c=[];t.width!==void 0&&c.push(`width=${t.width}`),t.initialScale!==void 0&&c.push(`initial-scale=${t.initialScale}`),t.maximumScale!==void 0&&c.push(`maximum-scale=${t.maximumScale}`),t.userScalable!==void 0&&c.push(`user-scalable=${t.userScalable?"yes":"no"}`),c.length&&r.push({tag:"meta",name:"viewport",content:c.join(", ")}),t.themeColor&&r.push({tag:"meta",name:"theme-color",content:t.themeColor})}return r}function Q({metadata:e,viewport:t}){return typeof window>"u"||!e?null:A(X,{children:de(e,t)})}function de(e,t){let r=ce(e,t);return A(X,{children:r.map((n,o)=>n.tag==="title"?A("title",{children:n.children},o):n.tag==="link"?A("link",{rel:n.rel,href:n.href,hrefLang:n.hrefLang,type:n.type,sizes:n.sizes},o):A("meta",{name:n.name,property:n.property,content:n.content},o))})}import{createContext as G}from"react";var b=globalThis;b.__devix_RouterContext__??=G(null);var Y=b.__devix_RouterContext__;b.__devix_PageMetaContext__??=G(null);b.__devix_RouteDataContext__??=G(null);var Z=b.__devix_PageMetaContext__,S=b.__devix_RouteDataContext__;import{Component as fe}from"react";import{jsx as ee}from"react/jsx-runtime";var $=class extends fe{state={error:null};static getDerivedStateFromError(t){return t instanceof j?{error:{statusCode:t.statusCode,message:t.message}}:{error:{statusCode:500,message:t instanceof Error?t.message:"Unknown error"}}}render(){return this.state.error&&this.props.ErrorPage?ee(this.props.ErrorPage,{...this.state.error}):this.state.error?ee("h1",{children:this.state.error.statusCode}):this.props.children}},j=class extends Error{statusCode;constructor(t,r){super(r),this.statusCode=t}};function L(e){let t=new URL(window.location.href);t.pathname.endsWith("/")||(t.pathname+="/");let r=new URL(e,t);if(r.origin!==window.location.origin)return{kind:"external",url:r};let n=r.pathname.length>1?r.pathname.replace(/\/$/,""):r.pathname;return{kind:"internal",pathname:n,href:n+r.search+r.hash}}import{jsx as x,jsxs as Ee}from"react/jsx-runtime";var me={width:"device-width",initialScale:1};function ye(){return H(F)}var he=()=>Promise.resolve(),xe=()=>Promise.resolve();function Re(){return H(F)?.navigate??he}function we(){return H(F)?.revalidate??xe}function Pe(){let e=H(S);if(!e)throw new Error("useParams must be used within a route or layout");return e.params}function Te(){let e=H(S);if(!e)throw new Error("useLoaderData must be used within a route or layout");return e.loaderData}function Ce({initialData:e,initialParams:t,initialPage:r,initialLayouts:n=[],initialLayoutsData:o=[],initialMeta:p,initialViewport:y,initialError:c,initialErrorPage:f,clientEntry:m}){let[a,E]=re({pathname:window.location.pathname,params:t,loaderData:e,layoutsData:o,Page:r,layouts:n,metadata:p??null,viewport:y,pendingError:c,ErrorPage:f}),v=te(null),[W,R]=re(!1),T=te(new Map),se=I(u=>{let s=L(u);if(s.kind==="external")return;let l=s.href;if(T.current.has(l))return;let i=ae(s.pathname);if(!i)return;let d=new AbortController,h=Promise.all([Promise.all([i.load(),...i.loadLayouts.map(w=>w())]),fetch(`/_data${l}`,{headers:{Accept:"application/json"},signal:d.signal})]).then(async([[w,...g],D])=>{if(!D.ok||!w.default)return null;let V=await D.json();return{pageMod:w,layoutMods:g,data:V}}).catch(()=>null),k=setTimeout(()=>{d.abort(),T.current.delete(l)},3e3);h.finally(()=>clearTimeout(k)),T.current.set(l,{promise:h,controller:d})},[]),M=I(async(u,s)=>{let l=u.split("?")[0].split("#")[0],i=ae(l);if(!i){let P=await oe()??ne();E(J=>({...J,pathname:l,pendingError:{statusCode:404,message:"Not found"},ErrorPage:P??void 0}));return}let d=T.current.get(u);d&&T.current.delete(u);let h=d?await d.promise:null;if(s.signal.aborted)return;let k,w,g;if(h)({pageMod:k,layoutMods:w,data:g}=h);else{let[[P,...J],C]=await Promise.all([Promise.all([i.load(),...i.loadLayouts.map(O=>O())]),fetch(`/_data${u}`,{headers:{Accept:"application/json"},signal:s.signal})]);if(s.signal.aborted||!P.default)return;if(!C.ok){let O=C.headers.get("Content-Type")??"",_=null;try{O.includes("application/json")?_=await C.json():O.includes("text/plain")&&(_={message:await C.text()})}catch{}let q={};C.headers.forEach((z,ue)=>{q[ue]=z});let pe=await oe()??ne();E(z=>({...z,pathname:l,pendingError:{statusCode:_?.statusCode??C.status,message:_?.message??"Server error",data:_?.data,headers:q},ErrorPage:pe??void 0}));return}k=P,w=J,g=await C.json()}if(g.redirect){g.redirectReplace?window.history.replaceState(null,"",g.redirect):window.history.pushState(null,"",g.redirect),await M(g.redirect,s);return}E({pathname:l,params:g.params??{},loaderData:g.loaderData,layoutsData:(g.layouts??[]).map(P=>P.loaderData),Page:k.default,layouts:w.map(P=>P.default),metadata:g.metadata??null,viewport:g.viewport??me});let D=u.includes("#")?u.split("#")[1]:null,V=getComputedStyle(document.documentElement).scrollBehavior;D?requestAnimationFrame(()=>{document.getElementById(D)?.scrollIntoView({behavior:V})}):window.scrollTo({top:0,behavior:V})},[]),K=I(async(u,s)=>{let l=L(u);if(l.kind==="external"){window.location.href=l.url.href;return}let i=l.href;v.current?.abort();let d=new AbortController;v.current=d,R(!0);let h=async()=>{window.history[s?.replace?"replaceState":"pushState"](null,"",i),await M(i,d)};try{s?.viewTransition&&"startViewTransition"in document?await document.startViewTransition(h).finished:await h()}finally{d.signal.aborted||R(!1)}},[M]),le=I(async()=>{let u=window.location.pathname+window.location.search,s=new AbortController,l=await fetch(`/_data${u}`,{headers:{Accept:"application/json"},signal:s.signal});if(!l.ok)return;let i=await l.json();if(i.redirect){await K(i.redirect,{replace:i.redirectReplace});return}E(d=>({...d,loaderData:i.loaderData,layoutsData:(i.layouts??[]).map(h=>h.loaderData),params:i.params??d.params,metadata:i.metadata??d.metadata,viewport:i.viewport??d.viewport}))},[K]);ge(()=>{let u=()=>{v.current?.abort();let s=new AbortController;v.current=s;let l=window.location.pathname+window.location.search;M(l,s).catch(i=>{i.name!=="AbortError"&&console.error("[router] popstate error:",i)})};return window.addEventListener("popstate",u),()=>window.removeEventListener("popstate",u)},[M]);let U;if(a.pendingError)U=a.ErrorPage?x(a.ErrorPage,{...a.pendingError}):x("h1",{children:a.pendingError.statusCode});else{let u=x(S,{value:{loaderData:a.loaderData,params:a.params},children:x(a.Page,{data:a.loaderData,params:a.params,url:a.pathname})});for(let s=a.layouts.length-1;s>=0;s--){let l=a.layouts[s],i=a.layoutsData[s];u=x(S,{value:{loaderData:i,params:a.params},children:x(l,{data:i,params:a.params,children:u})})}U=x($,{ErrorPage:a.ErrorPage,children:u},a.pathname)}return Ee(Z,{value:{metadata:a.metadata,viewport:a.viewport,clientEntry:m},children:[x(Q,{metadata:a.metadata,viewport:a.viewport}),x(F,{value:{...a,isNavigating:W,navigate:K,revalidate:le,prefetchRoute:se},children:U})]})}import{useCallback as N,useContext as ve,useRef as be}from"react";import{jsx as ke}from"react/jsx-runtime";function Me({href:e,prefetch:t="hover",replace:r=!1,viewTransition:n=!1,children:o,...p}){let y=ve(Y),c=be(null),f=N(()=>{c.current!==null&&(clearTimeout(c.current),c.current=null)},[]),m=N(()=>{!y||t==="none"||y.prefetchRoute(e)},[e,t,y]),a=N(()=>{t!=="none"&&(c.current=setTimeout(m,50))},[t,m]),E=N(()=>{f()},[f]),v=N(()=>{f(),m()},[f,m]);return ke("a",{href:e,onClick:R=>{if(f(),!y||R.ctrlKey||R.metaKey||R.shiftKey||R.button!==0||L(e).kind==="external")return;R.preventDefault();let T={replace:r,viewTransition:n};y.navigate(e,T)},onMouseEnter:a,onMouseLeave:E,onTouchStart:v,...p,children:o})}function De(e,t){let r=e.headers.get("cookie");if(r)for(let n of r.split(";")){let[o,...p]=n.trim().split("=");if(o.trim()===t)return decodeURIComponent(p.join("="))}}function ie(e,t,r,n={}){let o=`${t}=${encodeURIComponent(r)}; Path=${n.path??"/"}`;n.domain&&(o+=`; Domain=${n.domain}`),n.maxAge!==void 0&&(o+=`; Max-Age=${n.maxAge}`),n.expires&&(o+=`; Expires=${n.expires.toUTCString()}`),n.httpOnly&&(o+="; HttpOnly"),n.secure&&(o+="; Secure"),n.sameSite&&(o+=`; SameSite=${n.sameSite}`),e.append("Set-Cookie",o)}function _e(e,t,r={}){ie(e,t,"",{...r,maxAge:0,expires:new Date(0)})}function Ae(e,t=200){return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":"application/json"}})}var Se=(e,t=200)=>new Response(e,{status:t,headers:{"Content-Type":"text/plain; charset=utf-8"}}),Le=Symbol.for("devix.redirect");function He(e,t){let r=typeof t=="number"?t:t?.status??302,n=typeof t=="object"?t?.replace??!1:!1;return{[Le]:!0,url:e,status:r,replace:n}}var Ne=Symbol.for("devix.loaderError");function Be(e,t,r){return{[Ne]:!0,statusCode:e,message:t,data:r}}var Ve="__devix_handler__";function Oe(e){return{[Ve]:!0,fn:e}}var B=class extends Error{constructor(r,n,o,p){super(`HTTP ${r}: ${n}`);this.status=r;this.statusText=n;this.response=o;this.body=p;this.name="FetchError"}};async function Tt(e,t){let r=t?.method??"GET",n=new Headers(t?.headers),o;t?.body!==void 0&&(t.body instanceof FormData||t.body instanceof Blob||t.body instanceof ArrayBuffer?o=t.body:(o=JSON.stringify(t.body),n.has("Content-Type")||n.set("Content-Type","application/json")));let p=await fetch(e,{method:r,headers:n,body:o,signal:t?.signal});if(!p.ok){let f=(p.headers.get("Content-Type")??"").includes("application/json")?await p.json():void 0;throw new B(p.status,p.statusText,p,f)}return(p.headers.get("Content-Type")??"").includes("application/json")?p.json():p.text()}export{Tt as $fetch,j as DevixError,B as FetchError,Me as Link,Ce as RouterProvider,Oe as createHandler,_e as deleteCookie,Be as error,De as getCookie,Ae as json,He as redirect,ie as setCookie,Se as text,Te as useLoaderData,Re as useNavigate,Pe as useParams,we as useRevalidate,ye as useRouter};
|
|
1
|
+
import{useCallback as U,useContext as v,useEffect as xe,useRef as Y,useState as ae}from"react";import{RouterContext as L}from"virtual:devix/context";import{getDefaultErrorPage as se,loadErrorPage as ie,matchClientRoute as de}from"virtual:devix/client-routes";import{Fragment as te,jsx as _}from"react/jsx-runtime";function ge(e,t){let n=[];e.title&&n.push({tag:"title",children:e.title}),e.description&&n.push({tag:"meta",name:"description",content:e.description}),e.keywords?.length&&n.push({tag:"meta",name:"keywords",content:e.keywords.join(", ")});let r=e.og?.title??e.title;r&&n.push({tag:"meta",property:"og:title",content:r});let a=e.og?.description??e.description;a&&n.push({tag:"meta",property:"og:description",content:a}),e.og?.image&&n.push({tag:"meta",property:"og:image",content:e.og.image}),e.og?.type&&n.push({tag:"meta",property:"og:type",content:e.og.type}),e.og?.url&&n.push({tag:"meta",property:"og:url",content:e.og.url});let i=e.twitter?.title??e.title;i&&n.push({tag:"meta",name:"twitter:title",content:i});let g=e.twitter?.description??e.description;if(g&&n.push({tag:"meta",name:"twitter:description",content:g}),e.twitter?.card&&n.push({tag:"meta",name:"twitter:card",content:e.twitter.card}),e.twitter?.image&&n.push({tag:"meta",name:"twitter:image",content:e.twitter.image}),e.twitter?.creator&&n.push({tag:"meta",name:"twitter:creator",content:e.twitter.creator}),e.canonical&&n.push({tag:"link",rel:"canonical",href:e.canonical}),e.robots&&n.push({tag:"meta",name:"robots",content:e.robots}),e.alternates)for(let[o,f]of Object.entries(e.alternates))n.push({tag:"link",rel:"alternate",href:f,hrefLang:o});if(e.icons){let o=Array.isArray(e.icons)?e.icons:[e.icons];for(let f of o){let y=typeof f=="string"?{href:f}:f;n.push({tag:"link",rel:y.rel??"icon",href:y.href,...y.type&&{type:y.type},...y.sizes&&{sizes:y.sizes}})}}if(t){let o=[];t.width!==void 0&&o.push(`width=${t.width}`),t.initialScale!==void 0&&o.push(`initial-scale=${t.initialScale}`),t.maximumScale!==void 0&&o.push(`maximum-scale=${t.maximumScale}`),t.userScalable!==void 0&&o.push(`user-scalable=${t.userScalable?"yes":"no"}`),o.length&&n.push({tag:"meta",name:"viewport",content:o.join(", ")}),t.themeColor&&n.push({tag:"meta",name:"theme-color",content:t.themeColor})}return n}function ee({metadata:e,viewport:t}){return typeof window>"u"||!e?null:_(te,{children:he(e,t)})}function he(e,t){let n=ge(e,t);return _(te,{children:n.map((r,a)=>r.tag==="title"?_("title",{children:r.children},a):r.tag==="link"?_("link",{rel:r.rel,href:r.href,hrefLang:r.hrefLang,type:r.type,sizes:r.sizes},a):_("meta",{name:r.name,property:r.property,content:r.content},a))})}import{createContext as X}from"react";var C=globalThis;C.__devix_RouterContext__??=X(null);var ne=C.__devix_RouterContext__;C.__devix_PageMetaContext__??=X(null);C.__devix_RouteDataContext__??=X(null);var re=C.__devix_PageMetaContext__,H=C.__devix_RouteDataContext__;import{Component as me}from"react";import{jsx as oe}from"react/jsx-runtime";var G=class extends me{state={error:null};static getDerivedStateFromError(t){return t instanceof K?{error:{statusCode:t.statusCode,message:t.message}}:{error:{statusCode:500,message:t instanceof Error?t.message:"Unknown error"}}}render(){return this.state.error&&this.props.ErrorPage?oe(this.props.ErrorPage,{...this.state.error}):this.state.error?oe("h1",{children:this.state.error.statusCode}):this.props.children}},K=class extends Error{statusCode;code;data;constructor(t,n,r){super(n),this.name="DevixError",this.statusCode=t,this.code=r?.code,this.data=r?.data}};function O(e){let t=new URL(window.location.href);t.pathname.endsWith("/")||(t.pathname+="/");let n=new URL(e,t);if(n.origin!==window.location.origin)return{kind:"external",url:n};let r=n.pathname.length>1?n.pathname.replace(/\/$/,""):n.pathname;return{kind:"internal",pathname:r,href:r+n.search+n.hash}}import{jsx as x,jsxs as be}from"react/jsx-runtime";var Pe={width:"device-width",initialScale:1};function Re(){return v(L)}var we=()=>Promise.resolve(),ke=()=>Promise.resolve();function Te(){return v(L)?.navigate??we}function Ee(){return v(L)?.revalidate??ke}function Se(){let e=v(H);if(!e)throw new Error("useParams must be used within a route or layout");return e.params}function Ce(){let e=v(H);if(!e)throw new Error("useLoaderData must be used within a route or layout");return e.loaderData}function ve(){let e=v(L);if(!e)throw new Error("useGuardData must be used within a route or layout");return e.guardData}function Me({initialData:e,initialParams:t,initialPage:n,initialLayouts:r=[],initialLayoutsData:a=[],initialGuardData:i=null,initialMeta:g,initialViewport:o,initialError:f,initialErrorPage:y,clientEntry:M}){let[s,E]=ae({pathname:window.location.pathname,params:t,loaderData:e,layoutsData:a,guardData:i,Page:n,layouts:r,metadata:g??null,viewport:o,pendingError:f,ErrorPage:y}),b=Y(null),[w,$]=ae(!1),B=Y(new Map),le=U(u=>{let c=O(u);if(c.kind==="external")return;let l=c.href;if(B.current.has(l))return;let d=de(c.pathname);if(!d)return;let p=new AbortController,m=Promise.all([Promise.all([d.load(),...d.loadLayouts.map(P=>P())]),fetch(`/_data${l}`,{headers:{Accept:"application/json"},signal:p.signal})]).then(async([[P,...h],A])=>{if(!A.ok||!P.default)return null;let F=await A.json();return{pageMod:P,layoutMods:h,data:F}}).catch(()=>null),N=setTimeout(()=>{p.abort(),B.current.delete(l)},3e3);m.finally(()=>clearTimeout(N)),B.current.set(l,{promise:m,controller:p})},[]),D=U(async(u,c)=>{let l=u.split("?")[0].split("#")[0],d=de(l);if(!d){let R=await ie()??se();E(W=>({...W,pathname:l,pendingError:{statusCode:404,message:"Not found"},ErrorPage:R??void 0}));return}let p=B.current.get(u);p&&B.current.delete(u);let m=p?await p.promise:null;if(c.signal.aborted)return;let N,P,h;if(m)({pageMod:N,layoutMods:P,data:h}=m);else{let[[R,...W],k]=await Promise.all([Promise.all([d.load(),...d.loadLayouts.map(j=>j())]),fetch(`/_data${u}`,{headers:{Accept:"application/json"},signal:c.signal})]);if(c.signal.aborted||!R.default)return;if(!k.ok){let j=k.headers.get("Content-Type")??"",S=null;try{j.includes("application/json")?S=await k.json():j.includes("text/plain")&&(S={message:await k.text()})}catch{}let Z={};k.headers.forEach((q,ye)=>{Z[ye]=q});let fe=await ie()??se();E(q=>({...q,pathname:l,pendingError:{statusCode:S?.statusCode??k.status,message:S?.message??"Server error",code:S?.code,data:S?.data,headers:Z},ErrorPage:fe??void 0}));return}N=R,P=W,h=await k.json()}if(h.redirect){h.redirectReplace?window.history.replaceState(null,"",h.redirect):window.history.pushState(null,"",h.redirect),await D(h.redirect,c);return}E({pathname:l,params:h.params??{},loaderData:h.loaderData,layoutsData:(h.layouts??[]).map(R=>R.loaderData),guardData:h.guardData??null,Page:N.default,layouts:P.map(R=>R.default),metadata:h.metadata??null,viewport:h.viewport??Pe});let A=u.includes("#")?u.split("#")[1]:null,F=getComputedStyle(document.documentElement).scrollBehavior;A?requestAnimationFrame(()=>{document.getElementById(A)?.scrollIntoView({behavior:F})}):window.scrollTo({top:0,behavior:F})},[]),J=U(async(u,c)=>{let l=O(u);if(l.kind==="external"){window.location.href=l.url.href;return}let d=l.href;b.current?.abort();let p=new AbortController;b.current=p,$(!0);let m=async()=>{window.history[c?.replace?"replaceState":"pushState"](null,"",d),await D(d,p)};try{c?.viewTransition&&"startViewTransition"in document?await document.startViewTransition(m).finished:await m()}finally{p.signal.aborted||$(!1)}},[D]),Q=Y(null),pe=U(async()=>{Q.current?.abort();let u=new AbortController;Q.current=u;let c=window.location.pathname+window.location.search,l;try{l=await fetch(`/_data${c}`,{headers:{Accept:"application/json"},signal:u.signal})}catch(p){if(p.name==="AbortError")return;throw p}if(u.signal.aborted||!l.ok)return;let d=await l.json();if(!u.signal.aborted){if(d.redirect){await J(d.redirect,{replace:d.redirectReplace});return}E(p=>({...p,loaderData:d.loaderData,layoutsData:(d.layouts??[]).map(m=>m.loaderData),guardData:d.guardData??null,params:d.params??p.params,metadata:d.metadata??p.metadata,viewport:d.viewport??p.viewport}))}},[J]);xe(()=>{let u=()=>{b.current?.abort();let c=new AbortController;b.current=c;let l=window.location.pathname+window.location.search;D(l,c).catch(d=>{d.name!=="AbortError"&&console.error("[router] popstate error:",d)})};return window.addEventListener("popstate",u),()=>window.removeEventListener("popstate",u)},[D]);let z;if(s.pendingError)z=s.ErrorPage?x(s.ErrorPage,{...s.pendingError}):x("h1",{children:s.pendingError.statusCode});else{let u=x(H,{value:{loaderData:s.loaderData,params:s.params},children:x(s.Page,{data:s.loaderData,params:s.params,url:s.pathname})});for(let c=s.layouts.length-1;c>=0;c--){let l=s.layouts[c],d=s.layoutsData[c];u=x(H,{value:{loaderData:d,params:s.params},children:x(l,{data:d,params:s.params,children:u})})}z=x(G,{ErrorPage:s.ErrorPage,children:u},s.pathname)}return be(re,{value:{metadata:s.metadata,viewport:s.viewport,clientEntry:M},children:[x(ee,{metadata:s.metadata,viewport:s.viewport}),x(L,{value:{...s,isNavigating:w,navigate:J,revalidate:pe,prefetchRoute:le},children:z})]})}import{useCallback as I,useContext as Be,useRef as De}from"react";import{jsx as Ae}from"react/jsx-runtime";function Ne({href:e,prefetch:t="hover",replace:n=!1,viewTransition:r=!1,children:a,...i}){let g=Be(ne),o=De(null),f=I(()=>{o.current!==null&&(clearTimeout(o.current),o.current=null)},[]),y=I(()=>{!g||t==="none"||g.prefetchRoute(e)},[e,t,g]),M=I(()=>{t!=="none"&&(o.current=setTimeout(y,50))},[t,y]),s=I(()=>{f()},[f]),E=I(()=>{f(),y()},[f,y]);return Ae("a",{href:e,onClick:w=>{if(f(),!g||w.ctrlKey||w.metaKey||w.shiftKey||w.button!==0||O(e).kind==="external")return;w.preventDefault();let $={replace:n,viewTransition:r};g.navigate(e,$)},onMouseEnter:M,onMouseLeave:s,onTouchStart:E,...i,children:a})}function _e(e,t){let n=e.headers.get("cookie");if(n)for(let r of n.split(";")){let[a,...i]=r.trim().split("=");if(a.trim()===t)return decodeURIComponent(i.join("="))}}function ue(e,t,n,r={}){let a=`${t}=${encodeURIComponent(n)}; Path=${r.path??"/"}`;r.domain&&(a+=`; Domain=${r.domain}`),r.maxAge!==void 0&&(a+=`; Max-Age=${r.maxAge}`),r.expires&&(a+=`; Expires=${r.expires.toUTCString()}`),r.httpOnly&&(a+="; HttpOnly"),r.secure&&(a+="; Secure"),r.sameSite&&(a+=`; SameSite=${r.sameSite}`),e.append("Set-Cookie",a)}function He(e,t,n={}){ue(e,t,"",{...n,maxAge:0,expires:new Date(0)})}function Oe(e,t=200){return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":"application/json"}})}var Le=(e,t=200)=>new Response(e,{status:t,headers:{"Content-Type":"text/plain; charset=utf-8"}}),Ie=Symbol.for("devix.redirect");function Ve(e,t){let n=typeof t=="number"?t:t?.status??302,r=typeof t=="object"?t?.replace??!1:!1;return{[Ie]:!0,url:e,status:n,replace:r}}var $e=Symbol.for("devix.loaderError");function Fe(e,t,n){return{[$e]:!0,statusCode:e,message:t,code:n?.code,data:n?.data}}var ce="__devix_handler__";function je(e,t){return t?{[ce]:!0,fn:t,schema:e}:{[ce]:!0,fn:e}}function Ge(e){if(e&&typeof e=="object"&&"message"in e){let t=e.message;if(typeof t=="string"&&t.length>0)return t}return null}var T=class extends Error{constructor(n,r,a,i){super(Ge(i)??`HTTP ${n}: ${r}`);this.status=n;this.statusText=r;this.response=a;this.body=i;this.name="FetchError"}get code(){if(this.body&&typeof this.body=="object"&&"code"in this.body){let n=this.body.code;return typeof n=="string"?n:void 0}}};var Ke="/_devix/server";async function V(e,t,n,r){let a=new Headers(r?.headers),i;r?.body!==void 0&&(r.body instanceof FormData||r.body instanceof Blob||r.body instanceof ArrayBuffer?i=r.body:(i=JSON.stringify(r.body),a.has("Content-Type")||a.set("Content-Type","application/json")));let g=`${Ke}/${e}${n}`,o=await fetch(g,{method:t,headers:a,body:i,signal:r?.signal}),f=o.status===204||o.headers.get("Content-Length")==="0";if(!o.ok){let M=o.headers.get("Content-Type")??"",s;if(!f&&M.includes("application/json"))try{s=await o.json()}catch{}throw new T(o.status,o.statusText,o,s)}return f?null:(o.headers.get("Content-Type")??"").includes("application/json")?o.json():o.text()}function Ue(e){return{get:(t,n)=>V(e,"GET",t,n),post:(t,n,r)=>V(e,"POST",t,{...r,body:n}),put:(t,n,r)=>V(e,"PUT",t,{...r,body:n}),patch:(t,n,r)=>V(e,"PATCH",t,{...r,body:n}),delete:(t,n)=>V(e,"DELETE",t,n)}}var Je=new Proxy({},{get(e,t){if(typeof t=="string")return e[t]||(e[t]=Ue(t)),e[t]}});async function Nt(e,t){let n=t?.method??"GET",r=new Headers(t?.headers),a;t?.body!==void 0&&(t.body instanceof FormData||t.body instanceof Blob||t.body instanceof ArrayBuffer?a=t.body:(a=JSON.stringify(t.body),r.has("Content-Type")||r.set("Content-Type","application/json")));let i=await fetch(e,{method:n,headers:r,body:a,signal:t?.signal}),g=i.status===204||i.headers.get("Content-Length")==="0";if(!i.ok){let f=i.headers.get("Content-Type")??"",y;if(!g&&f.includes("application/json"))try{y=await i.json()}catch{}throw new T(i.status,i.statusText,i,y)}return g?null:(i.headers.get("Content-Type")??"").includes("application/json")?i.json():i.text()}export{Nt as $fetch,Je as $server,K as DevixError,T as FetchError,Ne as Link,Me as RouterProvider,je as createHandler,He as deleteCookie,Fe as error,_e as getCookie,Oe as json,Ve as redirect,ue as setCookie,Le as text,ve as useGuardData,Ce as useLoaderData,Te as useNavigate,Se as useParams,Ee as useRevalidate,Re as useRouter};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|