@finesoft/front 0.1.78 → 0.2.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/dist/browser.d.mts +2 -2
- package/dist/browser.mjs +1 -1
- package/dist/index.d.mts +14 -3
- package/dist/index.mjs +22 -22
- package/dist/{server-data-DGbiKzMS.d.mts → server-data-DQzknR97.d.mts} +356 -32
- package/dist/start-app-S4DH-40i.mjs +2 -0
- package/package.json +3 -3
- package/dist/start-app-BdXBCcor.mjs +0 -2
package/dist/browser.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as RenderMode, $t as
|
|
2
|
-
export { ACTION_KINDS, Action, ActionDispatcher, ActionHandler, type ActionHandlerDependencies, AfterLoadGuard, AsyncMapper, BaseController, BaseItem, BaseLogger, BasePage, BaseShelf, BeforeLoadGuard, type BrowserAppConfig, BrowserContextOptions, CompositeEventRecorder, CompositeLogger, CompositeLoggerFactory, CompoundAction, ConsoleEventRecorder, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, DefineRoutesOptions, DenyResult, EventRecorder, ExternalUrlAction, type ExternalUrlDependencies, FeatureFlags, FeatureFlagsProvider, FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, FrameworkConfig, History, HttpClient, HttpClientConfig, HttpError, ImpressionEntry, ImpressionObserver, ImpressionObserverOptions, Intent, IntentController, IntentDispatcher, IntersectionImpressionObserver, LocaleAttributes, LocaleInfo, Logger, Logger as LoggerInterface, LoggerFactory, LruMap, MakeDependenciesOptions, Mapper, MessagesLoader, MessagesLoaderContext, MetricsFieldsProvider, MetricsRecorder, MiddlewareResult, NavigationContext, Net, NextResult, None, Optional, PWADisplayMode, PlatformInfo, PluralCategory, PluralRuleProvider, PostLoadContext, PrefetchedIntent, PrefetchedIntents, RedirectResult, RenderMode, ReportCallback, ReportingLogger, ReportingLoggerFactory, ReportingLoggerOptions, RequestInterceptor, ResponseInterceptor, RewriteResult, RouteAddOptions, RouteDefinition, RouteMatch, Router, ServerContextOptions, SimpleTranslator, SimpleTranslatorOptions, Storage, TextDirection, TranslationMessages, Translator, VoidEventRecorder, WithFieldsRecorder, buildUrl, createBrowserContext, createPrefetchedIntentsFromDom, createServerContext, defineRoutes, deny, deserializeServerData, detectPlatform, englishPlural, generateUuid, getBaseUrl, getLocaleAttributes, getPWADisplayMode, getTextDirection, interpolate, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isRtl, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, makeLocaleInfo, mapEach, next, pipe, pipeAsync, redirect, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, removeHost, removeQueryParams, removeScheme, resetFilterCache, resolveConfiguredMessages, resolveLocaleFromUrl, resolveMessages, resolvePluralKey, rewrite, runAfterLoadGuards, runBeforeLoadGuards, setHtmlLocaleAttributes, shouldLog, stableStringify, startBrowserApp, tryScroll };
|
|
1
|
+
import { $ as RenderMode, $n as BaseLogger, $t as RouteAddOptions, A as IntersectionImpressionObserver, An as DEP_KEYS, At as Translator, B as buildUrl, Bn as TranslationMessages, Bt as ParamsFor, C as PluralRuleProvider, Cn as BasePage, Ct as Framework, D as WithFieldsRecorder, Dn as markPublic, Dt as LocaleAttributes, E as resolvePluralKey, En as isPublicMarked, Et as PrefetchedIntents, F as BrowserContextOptions, Fn as Net, Ft as CompositeLogger, G as PWADisplayMode, Gn as EventRecorder, Gt as NumOptions, H as removeHost, Hn as resolveMessages, Ht as StripOptional, I as ServerContextOptions, In as Storage, It as CompositeLoggerFactory, J as Optional, Jn as MetricsFieldsProvider, Jt as int, K as getPWADisplayMode, Kn as ImpressionEntry, Kt as StrOptions, L as createBrowserContext, Ln as makeDependencies, Lt as ExtractParamNames, M as CompositeEventRecorder, Mn as FeatureFlagsProvider, Mt as shouldLog, N as runAfterLoadGuards, Nn as MakeDependenciesOptions, Nt as ConsoleLogger, O as VoidEventRecorder, On as RequestScopedKey, Ot as LocaleInfo, P as runBeforeLoadGuards, Pn as MetricsRecorder, Pt as ConsoleLoggerFactory, Q as DefineRoutesOptions, Qn as ReportingLoggerOptions, Qt as uuid, R as createServerContext, Rn as MessagesLoader, Rt as InferParams, S as PluralCategory, Sn as BASE_PAGE_FIELDS, St as safeErrorPage, T as interpolate, Tn as getPublicFields, Tt as PrefetchedIntent, U as removeQueryParams, Un as PlatformInfo, Ut as optional, V as getBaseUrl, Vn as resolveConfiguredMessages, Vt as QuerySchemaMap, W as removeScheme, Wn as detectPlatform, Wt as withDefault, X as isSome, Xn as ReportingLogger, Xt as oneOf, Y as isNone, Yn as ReportCallback, Yt as num, Z as LruMap, Zn as ReportingLoggerFactory, Zt as str, _ as getTextDirection, _n as RewriteResult, _r as isFlowAction, _t as ResponseInterceptor, a as BrowserAppConfig, an as StandardResult, ar as Intent, at as mapEach, b as resolveLocaleFromUrl, bn as redirect, bt as BaseShelf, c as registerActionHandlers, cn as runStandard, cr as ActionDispatcher, ct as BaseController, d as registerFlowActionHandler, dn as DenyResult, dr as Action, dt as classifyUrl, en as RouteMatch, er as Logger, et as RouteDefinition, f as ExternalUrlDependencies, fn as MiddlewareResult, fr as CompoundAction, ft as HostGuardError, g as getLocaleAttributes, gn as RedirectResult, gr as isExternalUrlAction, gt as RequestInterceptor, h as SimpleTranslatorOptions, hn as PostLoadContext, hr as isCompoundAction, ht as HttpError, i as History, in as StandardIssue, ir as IntentDispatcher, it as Mapper, j as ConsoleEventRecorder, jn as FeatureFlags, jt as resetFilterCache, k as ImpressionObserverOptions, kn as defineRequestScopedKey, kt as TextDirection, l as FlowActionCallbacks, ln as AfterLoadGuard, lr as ActionHandler, lt as HostCheckResult, m as SimpleTranslator, mn as NextResult, mr as FlowAction, mt as HttpClientConfig, n as deserializeServerData, nn as InferOutput, nr as SecureFetchOptions, nt as route, o as startBrowserApp, on as StandardSchemaV1, or as IntentController, ot as pipe, p as registerExternalUrlHandler, pn as NavigationContext, pr as ExternalUrlAction, pt as HttpClient, q as None, qn as ImpressionObserver, qt as bool, r as tryScroll, rn as ParamSchema, rr as secureFetch, rt as AsyncMapper, s as ActionHandlerDependencies, sn as makeSchema, sr as Container, st as pipeAsync, t as createPrefetchedIntentsFromDom, tn as Router, tr as LoggerFactory, tt as defineRoutes, u as FlowActionDependencies, un as BeforeLoadGuard, ur as ACTION_KINDS, ut as classifyHost, v as isRtl, vn as deny, vr as makeExternalUrlAction, vt as stableStringify, w as englishPlural, wn as FINESOFT_PUBLIC, wt as FrameworkConfig, x as setHtmlLocaleAttributes, xn as rewrite, xt as SafeErrorPageOptions, y as makeLocaleInfo, yn as next, yr as makeFlowAction, yt as BaseItem, z as generateUuid, zn as MessagesLoaderContext, zt as InferQuery } from "./server-data-DQzknR97.mjs";
|
|
2
|
+
export { ACTION_KINDS, Action, ActionDispatcher, ActionHandler, type ActionHandlerDependencies, AfterLoadGuard, AsyncMapper, BASE_PAGE_FIELDS, BaseController, BaseItem, BaseLogger, BasePage, BaseShelf, BeforeLoadGuard, type BrowserAppConfig, BrowserContextOptions, CompositeEventRecorder, CompositeLogger, CompositeLoggerFactory, CompoundAction, ConsoleEventRecorder, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, DefineRoutesOptions, DenyResult, EventRecorder, ExternalUrlAction, type ExternalUrlDependencies, ExtractParamNames, FINESOFT_PUBLIC, FeatureFlags, FeatureFlagsProvider, FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, FrameworkConfig, History, HostCheckResult, HostGuardError, HttpClient, HttpClientConfig, HttpError, ImpressionEntry, ImpressionObserver, ImpressionObserverOptions, InferOutput, InferParams, InferQuery, Intent, IntentController, IntentDispatcher, IntersectionImpressionObserver, LocaleAttributes, LocaleInfo, Logger, Logger as LoggerInterface, LoggerFactory, LruMap, MakeDependenciesOptions, Mapper, MessagesLoader, MessagesLoaderContext, MetricsFieldsProvider, MetricsRecorder, MiddlewareResult, NavigationContext, Net, NextResult, None, NumOptions, Optional, PWADisplayMode, ParamSchema, ParamsFor, PlatformInfo, PluralCategory, PluralRuleProvider, PostLoadContext, PrefetchedIntent, PrefetchedIntents, QuerySchemaMap, RedirectResult, RenderMode, ReportCallback, ReportingLogger, ReportingLoggerFactory, ReportingLoggerOptions, RequestInterceptor, RequestScopedKey, ResponseInterceptor, RewriteResult, RouteAddOptions, RouteDefinition, RouteMatch, Router, SafeErrorPageOptions, SecureFetchOptions, ServerContextOptions, SimpleTranslator, SimpleTranslatorOptions, StandardIssue, StandardResult, StandardSchemaV1, Storage, StrOptions, StripOptional, TextDirection, TranslationMessages, Translator, VoidEventRecorder, WithFieldsRecorder, bool, buildUrl, classifyHost, classifyUrl, createBrowserContext, createPrefetchedIntentsFromDom, createServerContext, defineRequestScopedKey, defineRoutes, deny, deserializeServerData, detectPlatform, englishPlural, generateUuid, getBaseUrl, getLocaleAttributes, getPWADisplayMode, getPublicFields, getTextDirection, int, interpolate, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isPublicMarked, isRtl, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, makeLocaleInfo, makeSchema, mapEach, markPublic, next, num, oneOf, optional, pipe, pipeAsync, redirect, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, removeHost, removeQueryParams, removeScheme, resetFilterCache, resolveConfiguredMessages, resolveLocaleFromUrl, resolveMessages, resolvePluralKey, rewrite, route, runAfterLoadGuards, runBeforeLoadGuards, runStandard, safeErrorPage, secureFetch, setHtmlLocaleAttributes, shouldLog, stableStringify, startBrowserApp, str, tryScroll, uuid, withDefault };
|
package/dist/browser.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$ as e,A as t,
|
|
1
|
+
import{$ as e,A as t,At as n,B as r,Bt as i,C as a,Ct as o,D as s,Dt as c,E as l,Et as u,F as d,Ft as f,G as p,H as m,Ht as h,I as g,It as _,J as v,K as y,L as b,Lt as x,M as S,Mt as C,N as w,Nt as T,O as E,Ot as D,P as O,Pt as k,Q as A,R as j,Rt as M,S as N,St as P,T as F,Tt as I,U as L,Ut as R,V as z,Vt as B,W as V,X as H,Y as U,Z as W,_ as G,_t as K,a as q,at as J,b as Y,bt as X,c as Z,ct as Q,d as $,dt as ee,et as te,f as ne,ft as re,g as ie,gt as ae,h as oe,ht as se,i as ce,it as le,j as ue,jt as de,k as fe,kt as pe,l as me,lt as he,m as ge,mt as _e,n as ve,nt as ye,o as be,ot as xe,p as Se,pt as Ce,q as we,r as Te,rt as Ee,s as De,st as Oe,t as ke,tt as Ae,u as je,ut as Me,v as Ne,vt as Pe,w as Fe,wt as Ie,x as Le,xt as Re,y as ze,yt as Be,z as Ve,zt as He}from"./start-app-S4DH-40i.mjs";export{M as ACTION_KINDS,x as ActionDispatcher,g as BASE_PAGE_FIELDS,O as BaseController,_e as BaseLogger,ne as CompositeEventRecorder,se as CompositeLogger,ae as CompositeLoggerFactory,Oe as ConsoleEventRecorder,Me as ConsoleLogger,ee as ConsoleLoggerFactory,f as Container,le as DEP_KEYS,b as FINESOFT_PUBLIC,z as Framework,be as History,n as HostGuardError,de as HttpClient,C as HttpError,_ as IntentDispatcher,$ as IntersectionImpressionObserver,E as LruMap,m as PrefetchedIntents,Q as ReportingLogger,he as ReportingLoggerFactory,te as Router,K as SimpleTranslator,je as VoidEventRecorder,me as WithFieldsRecorder,v as bool,Y as buildUrl,T as classifyHost,k as classifyUrl,G as createBrowserContext,ve as createPrefetchedIntentsFromDom,Ne as createServerContext,Ee as defineRequestScopedKey,fe as defineRoutes,Se as deny,Te as deserializeServerData,xe as detectPlatform,Pe as englishPlural,ze as generateUuid,Le as getBaseUrl,o as getLocaleAttributes,F as getPWADisplayMode,j as getPublicFields,Ie as getTextDirection,U as int,Be as interpolate,He as isCompoundAction,i as isExternalUrlAction,B as isFlowAction,l as isNone,Ve as isPublicMarked,I as isRtl,s as isSome,J as makeDependencies,h as makeExternalUrlAction,R as makeFlowAction,u as makeLocaleInfo,Ae as makeSchema,ue as mapEach,r as markPublic,ge as next,H as num,W as oneOf,y as optional,S as pipe,w as pipeAsync,oe as redirect,ce as registerActionHandlers,Z as registerExternalUrlHandler,q as registerFlowActionHandler,N as removeHost,a as removeQueryParams,Fe as removeScheme,re as resetFilterCache,Re as resolveConfiguredMessages,c as resolveLocaleFromUrl,P as resolveMessages,X as resolvePluralKey,ie as rewrite,t as route,V as runAfterLoadGuards,p as runBeforeLoadGuards,ye as runStandard,d as safeErrorPage,pe as secureFetch,D as setHtmlLocaleAttributes,Ce as shouldLog,L as stableStringify,ke as startBrowserApp,A as str,De as tryScroll,e as uuid,we as withDefault};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as RenderMode, $t as
|
|
1
|
+
import { $ as RenderMode, $n as BaseLogger, $t as RouteAddOptions, A as IntersectionImpressionObserver, An as DEP_KEYS, At as Translator, B as buildUrl, Bn as TranslationMessages, Bt as ParamsFor, C as PluralRuleProvider, Cn as BasePage, Ct as Framework, D as WithFieldsRecorder, Dn as markPublic, Dt as LocaleAttributes, E as resolvePluralKey, En as isPublicMarked, Et as PrefetchedIntents, F as BrowserContextOptions, Fn as Net, Ft as CompositeLogger, G as PWADisplayMode, Gn as EventRecorder, Gt as NumOptions, H as removeHost, Hn as resolveMessages, Ht as StripOptional, I as ServerContextOptions, In as Storage, It as CompositeLoggerFactory, J as Optional, Jn as MetricsFieldsProvider, Jt as int, K as getPWADisplayMode, Kn as ImpressionEntry, Kt as StrOptions, L as createBrowserContext, Ln as makeDependencies, Lt as ExtractParamNames, M as CompositeEventRecorder, Mn as FeatureFlagsProvider, Mt as shouldLog, N as runAfterLoadGuards, Nn as MakeDependenciesOptions, Nt as ConsoleLogger, O as VoidEventRecorder, On as RequestScopedKey, Ot as LocaleInfo, P as runBeforeLoadGuards, Pn as MetricsRecorder, Pt as ConsoleLoggerFactory, Q as DefineRoutesOptions, Qn as ReportingLoggerOptions, Qt as uuid, R as createServerContext, Rn as MessagesLoader, Rt as InferParams, S as PluralCategory, Sn as BASE_PAGE_FIELDS, St as safeErrorPage, T as interpolate, Tn as getPublicFields, Tt as PrefetchedIntent, U as removeQueryParams, Un as PlatformInfo, Ut as optional, V as getBaseUrl, Vn as resolveConfiguredMessages, Vt as QuerySchemaMap, W as removeScheme, Wn as detectPlatform, Wt as withDefault, X as isSome, Xn as ReportingLogger, Xt as oneOf, Y as isNone, Yn as ReportCallback, Yt as num, Z as LruMap, Zn as ReportingLoggerFactory, Zt as str, _ as getTextDirection, _n as RewriteResult, _r as isFlowAction, _t as ResponseInterceptor, a as BrowserAppConfig, an as StandardResult, ar as Intent, at as mapEach, b as resolveLocaleFromUrl, bn as redirect, bt as BaseShelf, c as registerActionHandlers, cn as runStandard, cr as ActionDispatcher, ct as BaseController, d as registerFlowActionHandler, dn as DenyResult, dr as Action, dt as classifyUrl, en as RouteMatch, er as Logger, et as RouteDefinition, f as ExternalUrlDependencies, fn as MiddlewareResult, fr as CompoundAction, ft as HostGuardError, g as getLocaleAttributes, gn as RedirectResult, gr as isExternalUrlAction, gt as RequestInterceptor, h as SimpleTranslatorOptions, hn as PostLoadContext, hr as isCompoundAction, ht as HttpError, i as History, in as StandardIssue, ir as IntentDispatcher, it as Mapper, j as ConsoleEventRecorder, jn as FeatureFlags, jt as resetFilterCache, k as ImpressionObserverOptions, kn as defineRequestScopedKey, kt as TextDirection, l as FlowActionCallbacks, ln as AfterLoadGuard, lr as ActionHandler, lt as HostCheckResult, m as SimpleTranslator, mn as NextResult, mr as FlowAction, mt as HttpClientConfig, n as deserializeServerData, nn as InferOutput, nr as SecureFetchOptions, nt as route, o as startBrowserApp, on as StandardSchemaV1, or as IntentController, ot as pipe, p as registerExternalUrlHandler, pn as NavigationContext, pr as ExternalUrlAction, pt as HttpClient, q as None, qn as ImpressionObserver, qt as bool, r as tryScroll, rn as ParamSchema, rr as secureFetch, rt as AsyncMapper, s as ActionHandlerDependencies, sn as makeSchema, sr as Container, st as pipeAsync, t as createPrefetchedIntentsFromDom, tn as Router, tr as LoggerFactory, tt as defineRoutes, u as FlowActionDependencies, un as BeforeLoadGuard, ur as ACTION_KINDS, ut as classifyHost, v as isRtl, vn as deny, vr as makeExternalUrlAction, vt as stableStringify, w as englishPlural, wn as FINESOFT_PUBLIC, wt as FrameworkConfig, x as setHtmlLocaleAttributes, xn as rewrite, xt as SafeErrorPageOptions, y as makeLocaleInfo, yn as next, yr as makeFlowAction, yt as BaseItem, z as generateUuid, zn as MessagesLoaderContext, zt as InferQuery } from "./server-data-DQzknR97.mjs";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import * as _$node_fs0 from "node:fs";
|
|
4
4
|
import { ViteDevServer } from "vite";
|
|
@@ -137,7 +137,18 @@ declare function injectCSRShell(template: string, locale?: {
|
|
|
137
137
|
}): string;
|
|
138
138
|
//#endregion
|
|
139
139
|
//#region ../ssr/src/server-data.d.ts
|
|
140
|
-
|
|
140
|
+
interface SerializeServerDataOptions {
|
|
141
|
+
/**
|
|
142
|
+
* 没有 `markPublic` 标注的 page 怎么处理:
|
|
143
|
+
*
|
|
144
|
+
* - `"all"` (默认): 全字段序列化 + dev 启动后打印一次告警。向后兼容。
|
|
145
|
+
* - `"base-fields"`: 只保留 BasePage 标准字段 (id/pageType/title/description/url)。
|
|
146
|
+
* 下一个 major 会成为默认。
|
|
147
|
+
* - `"strict"`: 直接抛错。CI / 类型严格的场景用。
|
|
148
|
+
*/
|
|
149
|
+
onUnmarkedPage?: "all" | "base-fields" | "strict";
|
|
150
|
+
}
|
|
151
|
+
declare function serializeServerData(data: PrefetchedIntent[], options?: SerializeServerDataOptions): string;
|
|
141
152
|
//#endregion
|
|
142
153
|
//#region ../server/src/proxy.d.ts
|
|
143
154
|
/** 代理路由认证配置 */
|
|
@@ -537,5 +548,5 @@ declare function finesoftFrontViteConfig(options?: FinesoftFrontViteOptions): {
|
|
|
537
548
|
closeBundle(): Promise<void>;
|
|
538
549
|
};
|
|
539
550
|
//#endregion
|
|
540
|
-
export { ACTION_KINDS, Action, ActionDispatcher, ActionHandler, type ActionHandlerDependencies, type Adapter, type AdapterContext, AfterLoadGuard, AsyncMapper, BaseController, BaseItem, BaseLogger, BasePage, BaseShelf, BeforeLoadGuard, type BrowserAppConfig, BrowserContextOptions, CompositeEventRecorder, CompositeLogger, CompositeLoggerFactory, CompoundAction, ConsoleEventRecorder, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, DefineRoutesOptions, DenyResult, EventRecorder, ExternalUrlAction, type ExternalUrlDependencies, FeatureFlags, FeatureFlagsProvider, type FinesoftFrontViteOptions, FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, FrameworkConfig, History, HttpClient, HttpClientConfig, HttpError, ImpressionEntry, ImpressionObserver, ImpressionObserverOptions, type InjectSSROptions, Intent, IntentController, IntentDispatcher, IntersectionImpressionObserver, LocaleAttributes, LocaleInfo, Logger, Logger as LoggerInterface, LoggerFactory, LruMap, MakeDependenciesOptions, Mapper, MessagesLoader, MessagesLoaderContext, MetricsFieldsProvider, MetricsRecorder, MiddlewareResult, NavigationContext, Net, NextResult, None, Optional, PWADisplayMode, PlatformInfo, PluralCategory, PluralRuleProvider, PostLoadContext, PrefetchedIntent, PrefetchedIntents, type ProxyAuthConfig, type ProxyRouteConfig, RedirectResult, RenderMode, ReportCallback, ReportingLogger, ReportingLoggerFactory, ReportingLoggerOptions, RequestInterceptor, ResponseInterceptor, RewriteResult, RouteAddOptions, RouteDefinition, RouteMatch, Router, type RuntimeInfo, type SSRAppOptions, type SSRContext, type SSRModule, type SSRRenderConfig, type SSRRenderOptions, type SSRRenderResult, SSR_PLACEHOLDERS, type ServerConfig, ServerContextOptions, type ServerInstance, SimpleTranslator, SimpleTranslatorOptions, type StartServerOptions, Storage, TextDirection, TranslationMessages, Translator, VoidEventRecorder, WithFieldsRecorder, autoAdapter, buildUrl, cloudflareAdapter, createBrowserContext, createPrefetchedIntentsFromDom, createSSRApp, createSSRRender, createServer, createServerContext, defineRoutes, deny, deserializeServerData, detectPlatform, detectRuntime, englishPlural, finesoftFrontViteConfig, generateProxyCode, generateUuid, getBaseUrl, getLocaleAttributes, getPWADisplayMode, getTextDirection, injectCSRShell, injectSSRContent, interpolate, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isRtl, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, makeLocaleInfo, mapEach, netlifyAdapter, next, nodeAdapter, parseAcceptLanguage, pipe, pipeAsync, redirect, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, registerProxyRoutes, removeHost, removeQueryParams, removeScheme, resetFilterCache, resolveAdapter, resolveConfiguredMessages, resolveLocaleFromUrl, resolveMessages, resolvePluralKey, resolveRoot, rewrite, runAfterLoadGuards, runBeforeLoadGuards, serializeServerData, setHtmlLocaleAttributes, shouldLog, ssrRender, stableStringify, startBrowserApp, startServer, staticAdapter, tryScroll, vercelAdapter };
|
|
551
|
+
export { ACTION_KINDS, Action, ActionDispatcher, ActionHandler, type ActionHandlerDependencies, type Adapter, type AdapterContext, AfterLoadGuard, AsyncMapper, BASE_PAGE_FIELDS, BaseController, BaseItem, BaseLogger, BasePage, BaseShelf, BeforeLoadGuard, type BrowserAppConfig, BrowserContextOptions, CompositeEventRecorder, CompositeLogger, CompositeLoggerFactory, CompoundAction, ConsoleEventRecorder, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, DefineRoutesOptions, DenyResult, EventRecorder, ExternalUrlAction, type ExternalUrlDependencies, ExtractParamNames, FINESOFT_PUBLIC, FeatureFlags, FeatureFlagsProvider, type FinesoftFrontViteOptions, FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, FrameworkConfig, History, HostCheckResult, HostGuardError, HttpClient, HttpClientConfig, HttpError, ImpressionEntry, ImpressionObserver, ImpressionObserverOptions, InferOutput, InferParams, InferQuery, type InjectSSROptions, Intent, IntentController, IntentDispatcher, IntersectionImpressionObserver, LocaleAttributes, LocaleInfo, Logger, Logger as LoggerInterface, LoggerFactory, LruMap, MakeDependenciesOptions, Mapper, MessagesLoader, MessagesLoaderContext, MetricsFieldsProvider, MetricsRecorder, MiddlewareResult, NavigationContext, Net, NextResult, None, NumOptions, Optional, PWADisplayMode, ParamSchema, ParamsFor, PlatformInfo, PluralCategory, PluralRuleProvider, PostLoadContext, PrefetchedIntent, PrefetchedIntents, type ProxyAuthConfig, type ProxyRouteConfig, QuerySchemaMap, RedirectResult, RenderMode, ReportCallback, ReportingLogger, ReportingLoggerFactory, ReportingLoggerOptions, RequestInterceptor, RequestScopedKey, ResponseInterceptor, RewriteResult, RouteAddOptions, RouteDefinition, RouteMatch, Router, type RuntimeInfo, type SSRAppOptions, type SSRContext, type SSRModule, type SSRRenderConfig, type SSRRenderOptions, type SSRRenderResult, SSR_PLACEHOLDERS, SafeErrorPageOptions, SecureFetchOptions, type SerializeServerDataOptions, type ServerConfig, ServerContextOptions, type ServerInstance, SimpleTranslator, SimpleTranslatorOptions, StandardIssue, StandardResult, StandardSchemaV1, type StartServerOptions, Storage, StrOptions, StripOptional, TextDirection, TranslationMessages, Translator, VoidEventRecorder, WithFieldsRecorder, autoAdapter, bool, buildUrl, classifyHost, classifyUrl, cloudflareAdapter, createBrowserContext, createPrefetchedIntentsFromDom, createSSRApp, createSSRRender, createServer, createServerContext, defineRequestScopedKey, defineRoutes, deny, deserializeServerData, detectPlatform, detectRuntime, englishPlural, finesoftFrontViteConfig, generateProxyCode, generateUuid, getBaseUrl, getLocaleAttributes, getPWADisplayMode, getPublicFields, getTextDirection, injectCSRShell, injectSSRContent, int, interpolate, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isPublicMarked, isRtl, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, makeLocaleInfo, makeSchema, mapEach, markPublic, netlifyAdapter, next, nodeAdapter, num, oneOf, optional, parseAcceptLanguage, pipe, pipeAsync, redirect, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, registerProxyRoutes, removeHost, removeQueryParams, removeScheme, resetFilterCache, resolveAdapter, resolveConfiguredMessages, resolveLocaleFromUrl, resolveMessages, resolvePluralKey, resolveRoot, rewrite, route, runAfterLoadGuards, runBeforeLoadGuards, runStandard, safeErrorPage, secureFetch, serializeServerData, setHtmlLocaleAttributes, shouldLog, ssrRender, stableStringify, startBrowserApp, startServer, staticAdapter, str, tryScroll, uuid, vercelAdapter, withDefault };
|
|
541
552
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{$ as e,A as t,
|
|
1
|
+
import{$ as e,A as t,At as n,B as r,Bt as i,C as a,Ct as o,D as s,Dt as c,E as l,Et as u,F as d,Ft as f,G as p,H as m,Ht as h,I as g,It as _,J as v,K as y,L as b,Lt as x,M as S,Mt as C,N as ee,Nt as w,O as T,Ot as E,P as D,Pt as te,Q as ne,R as re,Rt as ie,S as ae,St as oe,T as se,Tt as ce,U as le,Ut as ue,V as de,Vt as fe,W as pe,X as me,Y as he,Z as ge,_ as _e,_t as ve,a as ye,at as be,b as xe,bt as Se,c as Ce,ct as we,d as Te,dt as Ee,et as De,f as Oe,ft as ke,g as Ae,gt as je,h as Me,ht as Ne,i as Pe,it as O,j as Fe,jt as Ie,k as Le,kt as Re,l as ze,lt as Be,m as Ve,mt as He,n as Ue,nt as We,o as Ge,ot as Ke,p as qe,pt as Je,q as Ye,r as Xe,rt as Ze,s as Qe,st as $e,t as et,tt,u as nt,ut as rt,v as k,vt as it,w as at,wt as ot,x as st,xt as A,y as ct,yt as lt,z as ut,zt as dt}from"./start-app-S4DH-40i.mjs";import{Hono as j}from"hono";async function M(e){return N(e,0)}async function N(e,t){if(t>=5)throw Error(`[SSR] Rewrite recursion depth exceeded (max 5) at "${e.url}"`);let{url:n,frameworkConfig:r,bootstrap:i,getErrorPage:a,renderApp:o,ssrContext:s,resolveLocale:c,loadMessages:l}=e,u=new URL(n,`http://localhost`),d=u.pathname+u.search,f=c?.(n,s?.request),p=f?{...r,locale:f.lang}:r,m=await A({locale:p.locale,loadMessages:l,context:p.locale?{runtime:`server`,fetch:ft(s?.fetch??p.fetch),url:d,request:s?.request}:void 0}),h={...p,fetch:s?.fetch??p.fetch},g=de.create({...h,_resolvedMessages:m});i(g);try{let n=await g.routeUrl(d);if(n?.renderMode===`csr`)return{html:``,head:``,css:``,serverData:[],renderMode:`csr`};let r,i=[],c;if(n){let l=k({url:d,intent:n.intent,container:g.container,request:s?.request}),u=await g.runBeforeLoad(l,n.beforeGuards);if(u.kind===`rewrite`)return N({...e,url:u.url},t+1);if(u.kind!==`next`){let e=await P(u,a,o,g);if(e)return e}try{r=await g.dispatch(n.intent),i=[{intent:n.intent,data:r}]}catch(e){g.container.resolve(O.LOGGER).error(`[SSR] dispatch failed for intent "${n.intent.id}":`,e),r=a(500,`Internal error`)}let f={...l,page:r},p=await g.runAfterLoad(f,n.afterGuards);if(p.kind===`rewrite`)c=p.url;else if(p.kind!==`next`){let e=await P(p,a,o,g);if(e)return e}}else r=a(404,`Page not found`);let l=await o(r,g),u=f??g.getLocale();return{html:l.html,head:l.head,css:l.css,serverData:i,renderMode:n?.renderMode,slots:l.slots,locale:u,rewriteUrl:c}}finally{g.dispose()}}function ft(e){return(e??globalThis.fetch?.bind(globalThis))||(()=>{throw Error(`[ssrRender] loadMessages requires a fetch implementation.`)})}async function P(e,t,n,r){switch(e.kind){case`next`:case`rewrite`:return null;case`redirect`:return{html:``,head:``,css:``,serverData:[],redirect:{url:e.url,status:e.status}};case`deny`:{let i=await n(t(e.status,e.message),r);return{html:i.html,head:i.head,css:i.css,serverData:[],slots:i.slots,status:e.status}}}}function pt(e){let{bootstrap:t,getErrorPage:n,renderApp:r,frameworkConfig:i,resolveLocale:a,loadMessages:o}=e;return(e,s)=>M({url:e,frameworkConfig:i??{},bootstrap:t,getErrorPage:n,renderApp:(e,t)=>r(e,t),ssrContext:s,resolveLocale:a,loadMessages:o})}const mt={HEAD:`<!--ssr-head-->`,BODY:`<!--ssr-body-->`,DATA:`<!--ssr-data-->`},F=/<!--ssr-([a-z][a-z0-9-]*)-->/g;function I(e){let{template:t,head:n,css:r,html:i,serializedData:a,slots:o,locale:s}=e,c={head:`${n}\n${r?`<style>${r}</style>`:``}`,body:i,data:`<script id="serialized-server-data" type="application/json">${a}<\/script>`,...o},l=t.replace(F,(e,t)=>c[t]??``);return s&&(l=R(l,s)),l}function L(e,t){let n=e.replace(F,()=>``);return t&&(n=R(n,t)),n}const ht=/\s+lang=("[^"]*"|'[^']*'|[^\s>]+)/gi,gt=/\s+dir=("[^"]*"|'[^']*'|[^\s>]+)/gi;function R(e,t){return e.replace(/(<html)([^>]*)(>)/i,(e,n,r,i)=>`${n}${r.replace(ht,``).replace(gt,``)} lang="${t.lang}" dir="${t.dir}"${i}`)}const _t={"<":`\\u003C`,">":`\\u003E`,"/":`\\u002F`,"\u2028":`\\u2028`,"\u2029":`\\u2029`},vt=RegExp(`[<>/\\u2028\\u2029]`,`g`);let z=!1;function yt(e,t={}){let n=t.onUnmarkedPage??`all`,r=e.map(e=>bt(e,n));return JSON.stringify(r).replace(vt,e=>_t[e]??e)}function bt(e,t){let n=e.data,r=re(n);if(r===!0)return e;if(Array.isArray(r))return{...e,data:B(n,r)};if(t===`strict`)throw Error(`[serializeServerData] page for intent "${e.intent.id}" has no markPublic marker; wrap it with markPublic(page, ["field", ...]) to declare client-visible fields.`);return t===`base-fields`?{...e,data:B(n,g)}:(xt(e.intent.id),e)}function B(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}function xt(e){z||(z=!0,St()&&console.warn(`[finesoft/ssr] Page for intent "${e}" was serialized without markPublic(); all fields (including any sensitive data) are exposed in the SSR HTML. Wrap your page with markPublic(page, ["field", ...]) to declare client-visible fields explicitly. The next major version will default to BasePage-only fields when no marker is present.`))}function St(){try{return globalThis.process?.env?.NODE_ENV!==`production`}catch{return!1}}const V=new Map,Ct=e=>import(e),wt=typeof process<`u`&&process.env?.FINESOFT_DEBUG===`1`;function Tt(e){wt&&console.debug(`[finesoft:dynamic-import] ${e}`)}async function H(e){let t=!e.startsWith(`file:`)&&!e.startsWith(`/`);if(t){let t=V.get(e);if(t)return Tt(`cache hit → ${e}`),t}Tt(`importing → ${e}`);let n=await Ct(e);return t&&V.set(e,n),n}const U=10*1024*1024;function Et(e){if(e.length>2048)return null;try{if(decodeURIComponent(e)!==e)return null}catch{return null}return e.startsWith(`//`)||!/^[/\w.\-~%:@!$&'()*+,;=]*$/.test(e)?null:e.startsWith(`/`)?e:`/${e}`}function Dt(e){if(!e.prefix.startsWith(`/`))throw Error(`[proxy] prefix must start with "/": "${e.prefix}"`);let t=e.target.startsWith(`https://`),n=e.target.startsWith(`http://`);if(!t&&!n)throw Error(`[proxy] target must start with "https://" or "http://": "${e.target}"`);n&&console.warn(`[proxy] ⚠ target "${e.target}" uses plain HTTP — traffic will not be encrypted. Use HTTPS in production to prevent data interception.`)}function W(e,t){for(let n of t){Dt(n);let t=n.methods??[`all`],r=`${n.prefix}/*`,i=async e=>{let t=Et(e.req.path.replace(n.prefix,``));if(!t)return e.text(`Invalid path`,400);let r=new URL(t,n.target),i=new URL(n.target).origin;if(r.origin!==i)return e.text(`Invalid proxy target`,400);new URL(e.req.url).searchParams.forEach((e,t)=>r.searchParams.set(t,e));let a={...n.headers};if(n.auth){let e=process.env[n.auth.envKey];e?a.Authorization=n.auth.type===`bearer`?`Bearer ${e}`:`Basic ${e}`:console.warn(`[Proxy ${n.prefix}] Auth env var "${n.auth.envKey}" is not set`)}try{let t=await fetch(r.toString(),{headers:a,redirect:n.followRedirects?`follow`:`manual`}),i=t.headers.get(`Content-Length`);if(i&&parseInt(i,10)>U)return e.text(`Proxy response too large`,502);let o=await t.arrayBuffer();if(o.byteLength>U)return e.text(`Proxy response too large`,502);let s={"Content-Type":t.headers.get(`Content-Type`)??`application/json`};return n.cache&&(s[`Cache-Control`]=n.cache),e.newResponse(o,t.status,s)}catch(t){return console.error(`[Proxy ${n.prefix}]`,t),e.json({error:`Proxy request failed`},502)}};for(let n of t)e[n](r,i)}}function Ot(e){if(!e||e.length===0)return``;for(let t of e)Dt(t);let t=[];t.push(`
|
|
2
2
|
// ─── 框架声明式代理路由 ───
|
|
3
3
|
function _sanitizeProxyPath(raw) {
|
|
4
4
|
if (raw.length > 2048) return null;
|
|
@@ -21,12 +21,12 @@ function _sanitizeProxyPath(raw) {
|
|
|
21
21
|
const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${o} });
|
|
22
22
|
// Content-Length 快速拒绝,防止 serverless/edge 加载超大响应到内存
|
|
23
23
|
const _cl = _resp.headers.get("Content-Length");
|
|
24
|
-
if (_cl && parseInt(_cl, 10) > ${
|
|
24
|
+
if (_cl && parseInt(_cl, 10) > ${U}) {
|
|
25
25
|
return c.text("Proxy response too large", 502);
|
|
26
26
|
}
|
|
27
27
|
// arrayBuffer 保留二进制完整性
|
|
28
28
|
const _body = await _resp.arrayBuffer();
|
|
29
|
-
if (_body.byteLength > ${
|
|
29
|
+
if (_body.byteLength > ${U}) {
|
|
30
30
|
return c.text("Proxy response too large", 502);
|
|
31
31
|
}
|
|
32
32
|
const _rh = { "Content-Type": _resp.headers.get("Content-Type") || "application/json" };
|
|
@@ -37,7 +37,7 @@ function _sanitizeProxyPath(raw) {
|
|
|
37
37
|
return c.json({ error: "Proxy request failed" }, 502);
|
|
38
38
|
}
|
|
39
39
|
}`;for(let n of e)t.push(`app.${n}(${r}, ${c});`)}return t.join(`
|
|
40
|
-
`)}const
|
|
40
|
+
`)}const kt=[`vite`,`esbuild`,`rollup`,`fsevents`,`lightningcss`],At=[`node:async_hooks`,`node:buffer`,`node:crypto`,`node:fs`,`node:http`,`node:http2`,`node:module`,`node:net`,`node:os`,`node:path`,`node:stream`,`node:url`,`node:util`,`node:zlib`,`crypto`,`http`,`http2`,`stream`];function G(e,t){let n=e.setupPath?`import _setupDefault from "./${e.setupPath}";`:``,r=e.setupPath?`if (typeof _setupDefault === "function") await _setupDefault(app);`:``,i=JSON.stringify(e.renderModes??{}),a=t.platformCache?t.platformCache:`
|
|
41
41
|
const ISR_CACHE_MAX = 1000;
|
|
42
42
|
const _isrMap = new Map();
|
|
43
43
|
async function platformCacheGet(url) {
|
|
@@ -109,7 +109,7 @@ function matchRenderMode(url) {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
const app = new Hono();
|
|
112
|
-
${
|
|
112
|
+
${Ot(e.proxies??[])}
|
|
113
113
|
${r}
|
|
114
114
|
${t.platformMiddleware??``}
|
|
115
115
|
|
|
@@ -173,8 +173,8 @@ app.get("*", async (c) => {
|
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
${t.platformExport}
|
|
176
|
-
`}async function
|
|
177
|
-
<style>`+i+`</style>`,body:n,data:`<script id="serialized-server-data" type="application/json">`+s+`<\/script>`})[t]??``);if(o){let{getLocaleAttributes:e}=await
|
|
176
|
+
`}async function K(e,t){await e.vite.build({root:e.root,build:{ssr:t.entry,outDir:t.outDir,emptyOutDir:t.emptyOutDir??!0,target:t.target??`node18`,rollupOptions:{output:{entryFileNames:t.fileName??`index.mjs`}}},ssr:{noExternal:t.noExternal!==!1,external:[...t.external??kt,...At]},resolve:e.resolvedResolve,css:e.resolvedCss})}function q(e,t,n){let{fs:r,path:i}=e;r.cpSync(i.resolve(e.root,`dist/client`),t,{recursive:!0}),n?.excludeHtml!==!1&&r.rmSync(i.join(t,`index.html`),{force:!0})}async function J(e){let{fs:t,path:n,root:r,vite:i}=e,{pathToFileURL:a}=await H(`node:url`),o=e.bootstrapEntry??`src/lib/bootstrap.ts`,s=[];if(t.existsSync(n.resolve(r,o))){await i.build({root:r,build:{ssr:o,outDir:n.resolve(r,`dist/server`),emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`_routes_prerender.mjs`}}},resolve:e.resolvedResolve});let c=a(n.resolve(r,`dist/server/_routes_prerender.mjs`)).href,l=await H(c);s=l.routes??l.default??[],t.rmSync(n.resolve(r,`dist/server/_routes_prerender.mjs`),{force:!0})}let c=new Set;for(let e of s)e.renderMode===`prerender`&&e.path&&!e.path.includes(`:`)&&c.add(e.path);if(e.renderModes)for(let[t,n]of Object.entries(e.renderModes))n===`prerender`&&!t.includes(`*`)&&!t.includes(`:`)&&c.add(t);if(e.locales?.length){let t=[...c];for(let n of e.locales)for(let e of t){let t=e===`/`?`/${n}`:`/${n}${e}`;c.add(t)}}if(c.size===0)return[];let l=a(n.resolve(r,`dist/server/ssr.js`)).href,u=await H(l),d=[];for(let t of c)try{let{html:n,head:r,css:i,serverData:a,locale:o}=await u.render(t),s=u.serializeServerData(a),c=e.templateHtml.replace(/<!--ssr-([a-z][a-z0-9-]*)-->/g,(e,t)=>({head:r+`
|
|
177
|
+
<style>`+i+`</style>`,body:n,data:`<script id="serialized-server-data" type="application/json">`+s+`<\/script>`})[t]??``);if(o){let{getLocaleAttributes:e}=await H(`@finesoft/core`),t=e(o);c=c.replace(/<html([^>]*)>/i,(e,n)=>`<html${n.replace(/\s+lang=("[^"]*"|'[^']*'|[^\s>]+)/gi,``).replace(/\s+dir=("[^"]*"|'[^']*'|[^\s>]+)/gi,``)} lang="${t.lang}" dir="${t.dir}">`)}d.push({url:t,html:c})}catch(e){console.warn(` [prerender] Failed to render ${t}:`,e)}return d.length>0&&console.log(` Pre-rendered ${d.length} pages (${c.size} routes)\n`),d}function jt(){return{name:`cloudflare`,async build(e){let{fs:t,path:n,root:r}=e,i=n.resolve(r,`dist/cloudflare`);t.rmSync(i,{recursive:!0,force:!0});let a=G(e,{platformImport:``,platformExport:`export default app;`,platformCache:`
|
|
178
178
|
const ISR_CACHE_TTL = 3600; // 1 hour
|
|
179
179
|
async function platformCacheGet(url) {
|
|
180
180
|
try {
|
|
@@ -194,8 +194,8 @@ async function platformCacheSet(url, html) {
|
|
|
194
194
|
});
|
|
195
195
|
await cache.put(cacheKey, resp);
|
|
196
196
|
} catch {}
|
|
197
|
-
}`}),o=n.resolve(r,`.cf-entry.tmp.mjs`);t.writeFileSync(o,a);try{await
|
|
198
|
-
`)}}}function
|
|
197
|
+
}`}),o=n.resolve(r,`.cf-entry.tmp.mjs`);t.writeFileSync(o,a);try{await K(e,{entry:`.cf-entry.tmp.mjs`,outDir:i,target:`es2022`,fileName:`_worker.js`}),q(e,n.resolve(i,`assets`));let r=await J(e);for(let{url:e,html:a}of r){let r=e===`/`?n.join(i,`assets`,`index.html`):n.join(i,`assets`,e,`index.html`);t.mkdirSync(n.resolve(r,`..`),{recursive:!0}),t.writeFileSync(r,a)}}finally{t.rmSync(o,{force:!0})}console.log(` Cloudflare output → dist/cloudflare/
|
|
198
|
+
`)}}}function Mt(){return{name:`netlify`,async build(e){let{fs:t,path:n,root:r}=e,i=n.resolve(r,`.netlify/functions-internal/ssr`);t.rmSync(n.resolve(r,`.netlify`),{recursive:!0,force:!0});let a=G(e,{platformImport:`import { handle } from "hono/netlify";`,platformExport:`export default handle(app);
|
|
199
199
|
export const config = { path: "/*", preferStatic: true };`,platformCache:`
|
|
200
200
|
const ISR_SWR_TTL = 3600;
|
|
201
201
|
const ISR_CACHE_MAX = 1000;
|
|
@@ -210,10 +210,10 @@ async function platformCacheSet(url, html) {
|
|
|
210
210
|
}
|
|
211
211
|
_isrMap.set(url, html);
|
|
212
212
|
}`,platformPrerenderResponseHook:`c.header("Cache-Control", "public, max-age=0, must-revalidate");
|
|
213
|
-
c.header("Netlify-CDN-Cache-Control", "public, max-age=" + ISR_SWR_TTL + ", stale-while-revalidate=" + ISR_SWR_TTL + ", durable");`}),o=n.resolve(r,`.netlify-entry.tmp.mjs`);t.writeFileSync(o,a);try{await
|
|
214
|
-
`);let s=await
|
|
213
|
+
c.header("Netlify-CDN-Cache-Control", "public, max-age=" + ISR_SWR_TTL + ", stale-while-revalidate=" + ISR_SWR_TTL + ", durable");`}),o=n.resolve(r,`.netlify-entry.tmp.mjs`);t.writeFileSync(o,a);try{await K(e,{entry:`.netlify-entry.tmp.mjs`,outDir:i,target:`node18`})}finally{t.rmSync(o,{force:!0})}t.writeFileSync(n.resolve(r,`dist/client/_redirects`),`/* /.netlify/functions/ssr 200
|
|
214
|
+
`);let s=await J(e),c=n.resolve(r,`dist/client`);for(let{url:e,html:r}of s){let i=e===`/`?n.join(c,`index.html`):n.join(c,e,`index.html`);t.mkdirSync(n.resolve(i,`..`),{recursive:!0}),t.writeFileSync(i,r)}console.log(` Netlify output → .netlify/functions-internal/ssr/
|
|
215
215
|
Publish dir: dist/client/
|
|
216
|
-
`)}}}function
|
|
216
|
+
`)}}}function Nt(){return{name:`node`,async build(e){let{fs:t,path:n,root:r}=e,i=G(e,{platformImport:`import { serve } from "@hono/node-server";
|
|
217
217
|
import { readFileSync, existsSync } from "node:fs";
|
|
218
218
|
import { resolve, dirname } from "node:path";
|
|
219
219
|
import { fileURLToPath } from "node:url";`,platformMiddleware:`
|
|
@@ -241,14 +241,14 @@ const port = +(process.env.PORT || 3000);
|
|
|
241
241
|
serve({ fetch: app.fetch, port }, (info) => {
|
|
242
242
|
console.log(\`Server running at http://localhost:\${info.port}\`);
|
|
243
243
|
});
|
|
244
|
-
`}),a=n.resolve(r,`.node-entry.tmp.mjs`);t.writeFileSync(a,i);try{await
|
|
244
|
+
`}),a=n.resolve(r,`.node-entry.tmp.mjs`);t.writeFileSync(a,i);try{await K(e,{entry:`.node-entry.tmp.mjs`,outDir:n.resolve(r,`dist/server`),target:`node18`,emptyOutDir:!1})}finally{t.rmSync(a,{force:!0})}let o=await J(e);if(o.length>0){let e=n.resolve(r,`dist/prerender`);t.mkdirSync(e,{recursive:!0});for(let{url:r,html:i}of o){let a=r===`/`?n.join(e,`index.html`):n.join(e,r,`index.html`);t.mkdirSync(n.resolve(a,`..`),{recursive:!0}),t.writeFileSync(a,i)}}console.log(` Node output → dist/server/index.mjs
|
|
245
245
|
Run: node dist/server/index.mjs
|
|
246
|
-
`)}}}function
|
|
247
|
-
`)}}}async function
|
|
248
|
-
<style>`+n+`</style>`,body:r,data:`<script id="serialized-server-data" type="application/json">`+i+`<\/script>`};return e.replace(a,(e,t)=>o[t]??``)}function
|
|
249
|
-
`)}),o=n.resolve(r,`.vercel-entry.tmp.mjs`);t.writeFileSync(o,a);try{let i=n.resolve(r,`.vercel/output/functions/ssr.func`);await
|
|
250
|
-
`)}}}function Y(e){if(typeof e!=`string`)return e;switch(e){case`vercel`:return
|
|
251
|
-
`))}if(u)return{vite:a};if(!i){let e=a;if(!e){let{createServer:t}=await
|
|
246
|
+
`)}}}function Pt(e={}){return{name:`static`,async build(t){let{fs:n,path:r,root:i}=t,a=r.resolve(i,`dist/static`);n.rmSync(a,{recursive:!0,force:!0}),n.mkdirSync(a,{recursive:!0});let{pathToFileURL:o}=await H(`node:url`),s=o(r.resolve(i,`dist/server/ssr.js`)).href,c=await H(s);t.copyStaticAssets(a,{excludeHtml:!0});let{paths:l,defs:u}=await Ft(t,e);console.log(` Pre-rendering ${l.length} pages...\n`);for(let e of l)try{let i=Rt(e,u.find(t=>t.path===e)?.renderMode,t.renderModes),o;if(i===`csr`)o=Lt(t.templateHtml);else{let{html:n,head:r,css:i,serverData:a}=await c.render(e),s=c.serializeServerData(a);o=It(t.templateHtml,r,i,n,s)}let s=e===`/`?r.join(a,`index.html`):r.join(a,e,`index.html`);n.mkdirSync(r.resolve(s,`..`),{recursive:!0}),n.writeFileSync(s,o)}catch(t){console.warn(` [static] Failed to render ${e}:`,t)}console.log(` Static output → dist/static/
|
|
247
|
+
`)}}}async function Ft(e,t){let n=t.routesExport??`src/lib/bootstrap.ts`,r=[],i=[];try{let{pathToFileURL:t}=await H(`node:url`);await e.vite.build({root:e.root,build:{ssr:n,outDir:e.path.resolve(e.root,`dist/server`),emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`_routes.mjs`}}},resolve:e.resolvedResolve});let a=t(e.path.resolve(e.root,`dist/server/_routes.mjs`)).href,o=await H(a),s=o.routes??o.default;if(Array.isArray(s))for(let e of s)e.path&&!e.path.includes(`:`)&&(r.push(e.path),i.push({path:e.path,renderMode:e.renderMode}));e.fs.rmSync(e.path.resolve(e.root,`dist/server/_routes.mjs`),{force:!0})}catch(e){console.warn(` [static] Could not load routes from "${n}". Using "/" only.`,e),r.length===0&&r.push(`/`)}if(t.dynamicRoutes)for(let e of t.dynamicRoutes)r.includes(e)||r.push(e);return r.length===0&&r.push(`/`),{paths:r,defs:i}}function It(e,t,n,r,i){let a=/<!--ssr-([a-z][a-z0-9-]*)-->/g,o={head:t+`
|
|
248
|
+
<style>`+n+`</style>`,body:r,data:`<script id="serialized-server-data" type="application/json">`+i+`<\/script>`};return e.replace(a,(e,t)=>o[t]??``)}function Lt(e){return e.replace(/<!--ssr-([a-z][a-z0-9-]*)-->/g,()=>``)}function Rt(e,t,n){if(n){if(n[e])return n[e];for(let[t,r]of Object.entries(n))if(t.includes(`*`)){let n=t.replace(/[.+?^${}()|[\]\\]/g,`\\$&`);if(RegExp(`^`+n.replace(/\*/g,`.*`)+`$`).test(e))return r}}return t??`ssr`}function zt(){return{name:`vercel`,async build(e){let{fs:t,path:n,root:r}=e,i=n.resolve(r,`.vercel/output`);t.rmSync(i,{recursive:!0,force:!0});let a=G(e,{platformImport:`import { getRequestListener } from "@hono/node-server";`,platformExport:[`const _listener = getRequestListener(app.fetch);`,`export default (req, res) => {`,` const m = req.headers["x-now-route-matches"];`,` if (typeof m === "string") {`,` try {`,` const p = new URLSearchParams(m);`,` const c = p.get("1");`,` if (c != null) {`,` const qi = (req.url || "").indexOf("?");`,` const qs = qi !== -1 ? req.url.slice(qi) : "";`,` req.url = "/" + decodeURIComponent(c) + qs;`,` }`,` } catch {}`,` }`,` return _listener(req, res);`,`};`].join(`
|
|
249
|
+
`)}),o=n.resolve(r,`.vercel-entry.tmp.mjs`);t.writeFileSync(o,a);try{let i=n.resolve(r,`.vercel/output/functions/ssr.func`);await K(e,{entry:`.vercel-entry.tmp.mjs`,outDir:i,target:`node18`}),t.writeFileSync(n.resolve(i,`.vc-config.json`),JSON.stringify({runtime:`nodejs20.x`,handler:`index.mjs`,launcherType:`Nodejs`},null,2)),q(e,n.resolve(r,`.vercel/output/static`)),t.writeFileSync(n.resolve(r,`.vercel/output/config.json`),JSON.stringify({version:3,routes:[{handle:`filesystem`},{src:`/(.*)`,dest:`/ssr`}]},null,2))}finally{t.rmSync(o,{force:!0})}let s=await J(e),c=n.resolve(r,`.vercel/output/static`);for(let{url:e,html:r}of s){let i=e===`/`?n.join(c,`index.html`):n.join(c,e,`index.html`);t.mkdirSync(n.resolve(i,`..`),{recursive:!0}),t.writeFileSync(i,r)}if(s.length>0){let e=n.resolve(r,`.vercel/output/config.json`),i=JSON.parse(t.readFileSync(e,`utf-8`));i.overrides=i.overrides??{};for(let{url:e}of s){let t=e===`/`?`index.html`:`${e.replace(/^\//,``)}/index.html`;i.overrides[t]={path:e===`/`?`/`:e,contentType:`text/html; charset=utf-8`}}t.writeFileSync(e,JSON.stringify(i,null,2))}console.log(` Vercel output → .vercel/output/
|
|
250
|
+
`)}}}function Y(e){if(typeof e!=`string`)return e;switch(e){case`vercel`:return zt();case`cloudflare`:return jt();case`netlify`:return Mt();case`node`:return Nt();case`static`:return Pt();case`auto`:return Bt();default:throw Error(`[finesoft] Unknown adapter: "${e}". Available: vercel, cloudflare, netlify, node, static, auto`)}}function Bt(){return{name:`auto`,async build(e){let t=Vt();return console.log(` [auto] Detected platform: ${t}\n`),Y(t).build(e)}}}function Vt(){return process.env.VERCEL?`vercel`:process.env.CF_PAGES?`cloudflare`:process.env.NETLIFY?`netlify`:`node`}function Ht(e,t=1){return((n,r)=>{if(typeof n==`string`&&n.startsWith(`/`)){let i=new Request(`http://localhost${n}`,r);return i.headers.set(`x-ssr-depth`,String(t)),Promise.resolve(e(i))}return globalThis.fetch(n,r)})}function Ut(e,t){if(!t)return null;let n=e.split(`?`)[0];if(t[n])return t[n];for(let[e,r]of Object.entries(t))if(e.includes(`*`)){let t=e.replace(/[.+?^${}()|[\]\\]/g,`\\$&`);if(RegExp(`^`+t.replace(/\*/g,`.*`)+`$`).test(n))return r}return null}function X(e){let{root:t,vite:n,isProduction:r,ssrEntryPath:i=`/src/ssr.ts`,ssrProductionModule:a,parentFetch:s,renderModes:c,defaultLocale:l}=e,u=new j,d=new T(1e3),f;async function p(e){if(!r&&n){let{readFileSync:r}=await H(`node:fs`),i=r((await H(`node:path`)).resolve(t,`index.html`),`utf-8`);return n.transformIndexHtml(e,i)}if(f)return f;if(globalThis.Deno!==void 0){let e=import.meta.url;return f=globalThis.Deno.readTextFileSync(new URL(`../dist/client/index.html`,e)),f}let{readFileSync:i}=await H(`node:fs`);return f=i((await H(`node:path`)).resolve(t,`dist/client/index.html`),`utf-8`),f}async function m(){if(!r&&n)return await n.ssrLoadModule(i);if(a)return H(a);let e=await H(`node:path`),{pathToFileURL:o}=await H(`node:url`),s=o(e.resolve(t,`dist/server/ssr.js`)).href;return H(s)}return u.get(`*`,async e=>{let t=parseInt(e.req.header(`x-ssr-depth`)??`0`,10);if(t>=5)return e.text(`SSR recursion loop detected`,508);let i=e.req.path+(e.req.url.includes(`?`)?`?`+e.req.url.split(`?`)[1]:``);try{let n=await p(i),r=await m();if(typeof r.render!=`function`||typeof r.serializeServerData!=`function`)throw Error(`[SSR] Module missing required exports: render, serializeServerData`);let{render:a,serializeServerData:u}=r,f=Ut(i,c);if(f===`csr`)return e.html(L(n,l?o(l):void 0));let h=d.get(i);if(h)return e.html(h);let g=s?Ht(s,t+1):void 0,_={request:e.req.raw};g&&(_.fetch=g);let{html:v,head:y,css:b,serverData:x,renderMode:S,redirect:C,slots:ee,locale:w,status:T,rewriteUrl:E}=await a(i,_);if(C)return e.redirect(C.url,C.status);if(S===`csr`)return e.html(L(n,w));let D=I({template:n,head:y,css:b,html:v,serializedData:u(x),slots:ee,locale:w});return(S===`prerender`||f===`prerender`)&&!T&&!E&&d.set(i,D),E&&e.header(`Content-Location`,E),T&&T>=400?e.html(D,T):e.html(D)}catch(t){return!r&&n&&n.ssrFixStacktrace(t),console.error(`[SSR Error]`,t),e.text(`Internal Server Error`,500)}}),u}function Z(){return{isDeno:globalThis.Deno!==void 0,isBun:globalThis.Bun!==void 0,isVercel:!!process.env.VERCEL,isProduction:process.env.NODE_ENV===`production`}}async function Wt(e,t=0){if(globalThis.Deno!==void 0){let n=new URL(e);for(let e=0;e<t;e++)n=new URL(`..`,n);return n.pathname}let n=await H(`node:path`),{fileURLToPath:r}=await H(`node:url`),i=n.normalize(n.dirname(r(e)));for(let e=0;e<t;e++)i=n.resolve(i,`..`);return i}async function Gt(e){let{app:t,root:n,port:r=3e3,isProduction:i,vite:a,routes:o,ssrEntryPath:s}=e,{isDeno:c,isBun:l,isVercel:u}=e.runtime??Z();function d(){let e=[`\n Server running at http://localhost:${r}\n`];if(o&&o.length>0){e.push(` Routes:`);for(let t of o)e.push(` ${t}`);e.push(``)}s&&e.push(` SSR Entry: ${s}`),s&&e.push(``),console.log(e.join(`
|
|
251
|
+
`))}if(u)return{vite:a};if(!i){let e=a;if(!e){let{createServer:t}=await H(`vite`);e=await t({root:n,server:{middlewareMode:!0},appType:`custom`})}let{getRequestListener:i}=await H(`@hono/node-server`),{createServer:o}=await H(`node:http`),s=i(t.fetch);return o((t,n)=>{e.middlewares(t,n,()=>s(t,n))}).listen(r,()=>{d()}),{vite:e}}if(c)globalThis.Deno.serve({port:r},t.fetch);else if(!l){let{serveStatic:e}=await H(`@hono/node-server/serve-static`),i=await H(`node:path`),a=new j,o=i.resolve(n,`dist/client`);a.use(`/*`,e({root:o,rewriteRequestPath:e=>e.endsWith(`/`)?`/__nosuchfile__`:e})),a.route(`/`,t);let{serve:s}=await H(`@hono/node-server`);s({fetch:a.fetch,port:r},()=>{d()})}return{vite:a}}async function Kt(e={}){let{root:t,port:n=Number(process.env.PORT)||3e3,setup:r,proxies:i,ssr:a}=e,o=t??process.cwd(),{existsSync:s}=await H(`node:fs`),c=(await H(`node:path`)).resolve(o,`.env`);if(s(c))try{let{config:e}=await H(`dotenv`);e({path:c})}catch(e){console.warn(`[Server] Failed to load .env: ${e.message}`)}let l=Z(),u;if(!l.isProduction&&!l.isVercel){let{createServer:e}=await H(`vite`);u=await e({root:o,server:{middlewareMode:!0},appType:`custom`})}let d=new j;i?.length&&W(d,i),r&&await r(d);let f=X({root:o,vite:u,isProduction:l.isProduction,parentFetch:d.fetch.bind(d),...a});return d.route(`/`,f),await Gt({app:d,root:o,port:n,isProduction:l.isProduction,vite:u,runtime:l,ssrEntryPath:a?.ssrEntryPath}),{app:d,vite:u,runtime:l}}function qt(e,t,n){let r=t??[`zh`,`en`],i=n??r[0]??`en`;if(!e||e.length>1024)return i;let a=e.split(`,`);if(a.length>50)return i;let o=a.map(e=>{let[t,n]=e.trim().split(`;q=`),r=n?parseFloat(n):1;return{lang:t.trim().toLowerCase(),q:Number.isFinite(r)&&r>=0&&r<=1?r:0}}).filter(e=>e.q>0).sort((e,t)=>t.q-e.q);for(let{lang:e}of o){let t=e.split(`-`)[0];if(r.includes(t))return t}return i}const Q=`virtual:finesoft-front/i18n-loader`,Jt=`\0${Q}`;function Yt(e){return typeof e.default==`function`?e.default:typeof e.setup==`function`?e.setup:Object.values(e).find(e=>typeof e==`function`)??null}function Xt(e,t){if(!t)return null;let n=e.split(`?`)[0];if(t[n])return t[n];for(let[e,r]of Object.entries(t))if(e.includes(`*`)){let t=e.replace(/[.+?^${}()|[\]\\]/g,`\\$&`);if(RegExp(`^`+t.replace(/\*/g,`.*`)+`$`).test(n))return r}return null}function Zt(e){return e.replace(/\\/g,`/`)}let $=!1;function Qt(){$||($=!0,console.log(`\n${(e=>`\x1b[33m${e}\x1b[0m`)(`[finesoft]`)} dev server is exposing source via /src/* and /@fs/* (HMR).\n`+(e=>`\x1b[2m${e}\x1b[0m`)(" Do NOT expose this server to untrusted networks; run `vp build && vp preview` for production.\n")))}async function $t(e,t){let{existsSync:n}=await H(`node:fs`),r=await H(`node:path`),i=r.isAbsolute(t)?t:r.resolve(e,t);if(!n(i))throw Error(`[finesoftFrontViteConfig] i18n.messagesDir not found: ${t}`);let a=Zt(r.relative(e,i));if(!a||a.startsWith(`..`))throw Error(`[finesoftFrontViteConfig] i18n.messagesDir must stay inside the project root: ${t}`);return a.replace(/^\.\/+/,``)}function en(e={}){let t=e.ssr?.entry??`src/ssr.ts`,n=process.cwd(),r,i,a,s=/\.(css|scss|less|sass|styl|stylus|pcss|postcss)($|\?)/;return{name:`finesoft-front`,config(t){let n={appType:`custom`,define:{__FINESOFT_I18N_LOADER_SPECIFIER__:e.i18n?.messagesDir?JSON.stringify(Q):`undefined`}};return process.env.__FINESOFT_SUB_BUILD__||(n.build={outDir:t.build?.outDir??`dist/client`}),n},configResolved(e){r=e.command,i=e.resolve,a=e.css,n=e.root},resolveId(t){return t===Q&&e.i18n?.messagesDir?Jt:null},async load(t){if(t!==Jt||!e.i18n?.messagesDir)return null;let r=`/${await $t(n,e.i18n.messagesDir)}`,i=`${r}/*.json`,a=`${r}/`;return`
|
|
252
252
|
const localeModules = import.meta.glob(${JSON.stringify(i)}, { import: "default" });
|
|
253
253
|
|
|
254
254
|
export async function loadMessages(locale) {
|
|
@@ -257,8 +257,8 @@ export async function loadMessages(locale) {
|
|
|
257
257
|
const messages = await loader();
|
|
258
258
|
return messages ?? undefined;
|
|
259
259
|
}
|
|
260
|
-
`},transformIndexHtml:{order:`pre`,async handler(e,t){let n=t.server;if(!n)return;let r=(t.originalUrl||t.path||``).split(`?`)[0];if(/\.\w+$/.test(r)&&!r.endsWith(`.html`))return;let i=[...e.matchAll(/<script\b[^>]*\bsrc=["']([^"']+)["'][^>]*>/g)].find(e=>!e[1].startsWith(`/@`));if(!i)return;let a=i[1];try{await n.transformRequest(a)}catch{return}let
|
|
260
|
+
`},transformIndexHtml:{order:`pre`,async handler(e,t){let n=t.server;if(!n)return;let r=(t.originalUrl||t.path||``).split(`?`)[0];if(/\.\w+$/.test(r)&&!r.endsWith(`.html`))return;let i=[...e.matchAll(/<script\b[^>]*\bsrc=["']([^"']+)["'][^>]*>/g)].find(e=>!e[1].startsWith(`/@`));if(!i)return;let a=i[1];try{await n.transformRequest(a)}catch{return}let o=[],c=new Set;function l(e,t=0){if(!(t>100)&&!(!e?.url||c.has(e.url))&&(c.add(e.url),s.test(e.url)&&!e.url.includes(`.svelte`)&&o.push(e.url),e.importedModules))for(let n of e.importedModules)l(n,t+1)}let u=await n.moduleGraph.getModuleByUrl(a);if(u&&l(u),o.length===0)return;let d=[];for(let e of o)try{let t=(await n.ssrLoadModule(e))?.default;typeof t==`string`&&t.length>0&&d.push({tag:`style`,attrs:{"data-vite-dev-id":e},children:t,injectTo:`head`})}catch{}return d}},configureServer(r){return async()=>{let{Hono:i}=await H(`hono`),{getRequestListener:a}=await H(`@hono/node-server`);Qt();let o=new i;if(e.proxies?.length&&W(o,e.proxies),typeof e.setup==`function`)await e.setup(o);else if(typeof e.setup==`string`){let t=Yt(await r.ssrLoadModule(`/`+e.setup));t&&await t(o)}let s=X({root:n,vite:r,isProduction:!1,ssrEntryPath:`/`+t,parentFetch:o.fetch.bind(o),renderModes:e.renderModes,defaultLocale:e.defaultLocale});o.route(`/`,s);let c=a(o.fetch);r.middlewares.use((e,t)=>{c(e,t)})}},configurePreviewServer(t){return async()=>{let{readFileSync:r}=await H(`node:fs`),i=await H(`node:path`),{pathToFileURL:a}=await H(`node:url`),{Hono:s}=await H(`hono`),{getRequestListener:c}=await H(`@hono/node-server`),l=new s,u=new T(1e3);if(e.proxies?.length&&W(l,e.proxies),typeof e.setup==`function`)await e.setup(l);else if(typeof e.setup==`string`)try{let e=a(i.resolve(n,`dist/server/setup.mjs`)).href,t=Yt(await H(e));t&&await t(l)}catch{console.warn(`[finesoft] Could not load setup module for preview. API routes disabled.`)}let d=r(i.resolve(n,`dist/client/index.html`),`utf-8`),f=a(i.resolve(n,`dist/server/ssr.js`)).href,p=await H(f);l.get(`*`,async t=>{let n=parseInt(t.req.header(`x-ssr-depth`)??`0`,10);if(n>=5)return t.text(`SSR recursion loop detected`,508);let r=t.req.path+(t.req.url.includes(`?`)?`?`+t.req.url.split(`?`)[1]:``);try{let i=Xt(r,e.renderModes);if(i===`csr`)return t.html(L(d,e.defaultLocale?o(e.defaultLocale):void 0));let a=u.get(r);if(a)return t.html(a);let{html:s,head:c,css:f,serverData:m,renderMode:h,redirect:g,slots:_,locale:v,status:y,rewriteUrl:b}=await p.render(r,{fetch:Ht(l.fetch.bind(l),n+1)});if(g)return t.redirect(g.url,g.status);if(h===`csr`)return t.html(L(d,v));let x=I({template:d,head:c,css:f,html:s,serializedData:p.serializeServerData(m),slots:_,locale:v});return(h===`prerender`||i===`prerender`)&&!y&&!b&&u.set(r,x),b&&t.header(`Content-Location`,b),y&&y>=400?t.html(x,y):t.html(x)}catch(e){return console.error(`[SSR Preview Error]`,e),t.text(`Internal Server Error`,500)}});let m=c(l.fetch);t.middlewares.use((e,t)=>{m(e,t)})}},async closeBundle(){if(!process.env.__FINESOFT_SUB_BUILD__&&r===`build`){process.env.__FINESOFT_SUB_BUILD__=`1`;try{let r=await H(`vite`),o=await H(`node:fs`),s=await H(`node:path`);if(console.log(`
|
|
261
261
|
Building SSR bundle...
|
|
262
|
-
`),await r.build({root:n,build:{ssr:t,outDir:`dist/server`},ssr:{external:
|
|
263
|
-
`),await r.build({root:n,build:{ssr:e.setup,outDir:`dist/server`,emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`setup.mjs`}}},resolve:i})),e.adapter){let c=Y(e.adapter),l=o.readFileSync(s.resolve(n,`dist/client/index.html`),`utf-8`),u={root:n,ssrEntry:t,setupPath:typeof e.setup==`string`?e.setup:void 0,bootstrapEntry:e.bootstrapEntry,templateHtml:l,renderModes:e.renderModes,proxies:e.proxies,locales:e.locales,defaultLocale:e.defaultLocale,resolvedResolve:i,resolvedCss:a,vite:r,fs:o,path:s,generateSSREntry(e){return
|
|
262
|
+
`),await r.build({root:n,build:{ssr:t,outDir:`dist/server`},ssr:{external:At},resolve:i,css:a}),typeof e.setup==`string`&&(console.log(` Building setup module...
|
|
263
|
+
`),await r.build({root:n,build:{ssr:e.setup,outDir:`dist/server`,emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`setup.mjs`}}},resolve:i})),e.adapter){let c=Y(e.adapter),l=o.readFileSync(s.resolve(n,`dist/client/index.html`),`utf-8`),u={root:n,ssrEntry:t,setupPath:typeof e.setup==`string`?e.setup:void 0,bootstrapEntry:e.bootstrapEntry,templateHtml:l,renderModes:e.renderModes,proxies:e.proxies,locales:e.locales,defaultLocale:e.defaultLocale,resolvedResolve:i,resolvedCss:a,vite:r,fs:o,path:s,generateSSREntry(e){return G(u,e)},buildBundle(e){return K(u,e)},copyStaticAssets(e,t){return q(u,e,t)}};console.log(` Running adapter: ${c.name}...\n`),await c.build(u)}}finally{delete process.env.__FINESOFT_SUB_BUILD__}}}}}export{ie as ACTION_KINDS,x as ActionDispatcher,g as BASE_PAGE_FIELDS,D as BaseController,He as BaseLogger,Oe as CompositeEventRecorder,Ne as CompositeLogger,je as CompositeLoggerFactory,$e as ConsoleEventRecorder,rt as ConsoleLogger,Ee as ConsoleLoggerFactory,f as Container,O as DEP_KEYS,b as FINESOFT_PUBLIC,de as Framework,Ge as History,n as HostGuardError,Ie as HttpClient,C as HttpError,_ as IntentDispatcher,Te as IntersectionImpressionObserver,T as LruMap,m as PrefetchedIntents,we as ReportingLogger,Be as ReportingLoggerFactory,De as Router,mt as SSR_PLACEHOLDERS,ve as SimpleTranslator,nt as VoidEventRecorder,ze as WithFieldsRecorder,Bt as autoAdapter,v as bool,xe as buildUrl,w as classifyHost,te as classifyUrl,jt as cloudflareAdapter,_e as createBrowserContext,Ue as createPrefetchedIntentsFromDom,X as createSSRApp,pt as createSSRRender,Kt as createServer,k as createServerContext,Ze as defineRequestScopedKey,Le as defineRoutes,qe as deny,Xe as deserializeServerData,Ke as detectPlatform,Z as detectRuntime,it as englishPlural,en as finesoftFrontViteConfig,Ot as generateProxyCode,ct as generateUuid,st as getBaseUrl,o as getLocaleAttributes,se as getPWADisplayMode,re as getPublicFields,ot as getTextDirection,L as injectCSRShell,I as injectSSRContent,he as int,lt as interpolate,dt as isCompoundAction,i as isExternalUrlAction,fe as isFlowAction,l as isNone,ut as isPublicMarked,ce as isRtl,s as isSome,be as makeDependencies,h as makeExternalUrlAction,ue as makeFlowAction,u as makeLocaleInfo,tt as makeSchema,Fe as mapEach,r as markPublic,Mt as netlifyAdapter,Ve as next,Nt as nodeAdapter,me as num,ge as oneOf,y as optional,qt as parseAcceptLanguage,S as pipe,ee as pipeAsync,Me as redirect,Pe as registerActionHandlers,Ce as registerExternalUrlHandler,ye as registerFlowActionHandler,W as registerProxyRoutes,ae as removeHost,a as removeQueryParams,at as removeScheme,ke as resetFilterCache,Y as resolveAdapter,A as resolveConfiguredMessages,c as resolveLocaleFromUrl,oe as resolveMessages,Se as resolvePluralKey,Wt as resolveRoot,Ae as rewrite,t as route,pe as runAfterLoadGuards,p as runBeforeLoadGuards,We as runStandard,d as safeErrorPage,Re as secureFetch,yt as serializeServerData,E as setHtmlLocaleAttributes,Je as shouldLog,M as ssrRender,le as stableStringify,et as startBrowserApp,Gt as startServer,Pt as staticAdapter,ne as str,Qe as tryScroll,e as uuid,zt as vercelAdapter,Ye as withDefault};
|
|
264
264
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -72,6 +72,16 @@ declare class Container {
|
|
|
72
72
|
resolve<T>(key: string): T;
|
|
73
73
|
/** 检查是否已注册(含 parent) */
|
|
74
74
|
has(key: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* 移除当前容器的注册(不影响 parent)。
|
|
77
|
+
*
|
|
78
|
+
* 用途:在 scope 内显式撤销之前覆写的依赖,避免用 `register(() => null)` 这种
|
|
79
|
+
* 反语义的写法。被移除的 key 之后再 resolve 会回退到 parent 容器。
|
|
80
|
+
*
|
|
81
|
+
* 返回 true 表示当前层确实存在过这个注册并被移除,false 表示未注册(含「只在
|
|
82
|
+
* parent 注册」的情况,本方法不向上递归删除 —— scope 不应能影响 parent 状态)。
|
|
83
|
+
*/
|
|
84
|
+
unregister(key: string): boolean;
|
|
75
85
|
/**
|
|
76
86
|
* 创建子容器(请求级 scope)
|
|
77
87
|
*
|
|
@@ -95,8 +105,8 @@ declare class Container {
|
|
|
95
105
|
interface Intent<T = unknown> {
|
|
96
106
|
/** Intent 标识符(用于匹配 Controller) */
|
|
97
107
|
id: string;
|
|
98
|
-
/**
|
|
99
|
-
params?: Record<string,
|
|
108
|
+
/** 意图参数(path/query 经 codec 转换后可能是 number/boolean 等) */
|
|
109
|
+
params?: Record<string, unknown>;
|
|
100
110
|
/** 预期返回的数据(仅用于类型推断) */
|
|
101
111
|
_returnType?: T;
|
|
102
112
|
}
|
|
@@ -119,6 +129,45 @@ declare class IntentDispatcher {
|
|
|
119
129
|
has(intentId: string): boolean;
|
|
120
130
|
}
|
|
121
131
|
//#endregion
|
|
132
|
+
//#region ../core/src/http/secure-fetch.d.ts
|
|
133
|
+
/**
|
|
134
|
+
* secureFetch — `fetch` with SSRF defense baked in.
|
|
135
|
+
*
|
|
136
|
+
* Wraps an existing fetch implementation and refuses targets that resolve to
|
|
137
|
+
* private / loopback / reserved ranges. Use when your controller fetches a
|
|
138
|
+
* URL that the user can influence (image proxies, link previews, callbacks).
|
|
139
|
+
*
|
|
140
|
+
* Defaults to checking IP literals (sync) AND resolving hostnames via DNS
|
|
141
|
+
* (Node only; silently skipped in browsers). Pass `allowInternalHosts: true`
|
|
142
|
+
* to opt out — for example, when you have a legitimate server-to-server call
|
|
143
|
+
* to 10.x or 127.0.0.1 and you trust the URL source.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* import { secureFetch, DEP_KEYS } from "@finesoft/front";
|
|
148
|
+
*
|
|
149
|
+
* class ShareController extends BaseController<{ next?: string }, Page> {
|
|
150
|
+
* async execute(params, container) {
|
|
151
|
+
* const baseFetch = container.resolve<typeof globalThis.fetch>(DEP_KEYS.FETCH);
|
|
152
|
+
* const fetch = secureFetch(baseFetch);
|
|
153
|
+
* const response = await fetch(params.next ?? "https://example.com");
|
|
154
|
+
* ...
|
|
155
|
+
* }
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
interface SecureFetchOptions {
|
|
160
|
+
/** Opt out of SSRF defense entirely (default false). */
|
|
161
|
+
allowInternalHosts?: boolean;
|
|
162
|
+
/** DNS-resolve hostnames and check each resolved IP (default true, Node only). */
|
|
163
|
+
validateDns?: boolean;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Return a `fetch`-shaped function that refuses requests to private hosts
|
|
167
|
+
* before calling through to `baseFetch`.
|
|
168
|
+
*/
|
|
169
|
+
declare function secureFetch(baseFetch: typeof globalThis.fetch, options?: SecureFetchOptions): typeof globalThis.fetch;
|
|
170
|
+
//#endregion
|
|
122
171
|
//#region ../core/src/logger/types.d.ts
|
|
123
172
|
/** 日志级别 */
|
|
124
173
|
type Level = "debug" | "info" | "warn" | "error";
|
|
@@ -323,6 +372,12 @@ declare const DEP_KEYS: {
|
|
|
323
372
|
readonly FEATURE_FLAGS: "featureFlags";
|
|
324
373
|
readonly METRICS: "metrics";
|
|
325
374
|
readonly FETCH: "fetch";
|
|
375
|
+
/**
|
|
376
|
+
* `fetch` 包了 SSRF 防护(拒绝 private / loopback / 保留 IP + DNS resolve 后逐 IP 校验)。
|
|
377
|
+
* 当 controller 用用户可控的 URL 发起请求(图片代理、链接预览、回调等),
|
|
378
|
+
* 优先 resolve 这个 key 而不是 `FETCH`。要 opt-out 可手动调 `secureFetch(baseFetch, { allowInternalHosts: true })`。
|
|
379
|
+
*/
|
|
380
|
+
readonly SAFE_FETCH: "safeFetch";
|
|
326
381
|
readonly EVENT_RECORDER: "eventRecorder";
|
|
327
382
|
readonly LOCALE: "locale";
|
|
328
383
|
readonly PLATFORM: "platform";
|
|
@@ -341,14 +396,51 @@ interface MakeDependenciesOptions {
|
|
|
341
396
|
locale?: string;
|
|
342
397
|
/** 自定义 PlatformInfo(默认通过 UA 自动检测) */
|
|
343
398
|
platform?: PlatformInfo;
|
|
399
|
+
/**
|
|
400
|
+
* 覆盖 `DEP_KEYS.SAFE_FETCH` 默认行为。比如服务正常需要打内网,可以传
|
|
401
|
+
* `{ allowInternalHosts: true }` 整体放行;或自定义 DNS 校验策略。
|
|
402
|
+
*/
|
|
403
|
+
safeFetch?: SecureFetchOptions;
|
|
344
404
|
}
|
|
345
405
|
declare function makeDependencies(container: Container, options?: MakeDependenciesOptions): void;
|
|
346
406
|
//#endregion
|
|
407
|
+
//#region ../core/src/dependencies/request-scoped-key.d.ts
|
|
408
|
+
/** Anything that exposes the per-request DI container — covers NavigationContext, PostLoadContext, and raw Container. */
|
|
409
|
+
type ContainerHolder = Container | {
|
|
410
|
+
container: Container;
|
|
411
|
+
};
|
|
412
|
+
interface RequestScopedKey<T> {
|
|
413
|
+
/** The underlying string key registered with the Container. */
|
|
414
|
+
readonly key: string;
|
|
415
|
+
/** Write the current request's value. Overwrites any prior registration. */
|
|
416
|
+
set(target: ContainerHolder, value: T): void;
|
|
417
|
+
/** Read the current request's value, or `undefined` if not set. */
|
|
418
|
+
get(target: ContainerHolder): T | undefined;
|
|
419
|
+
/**
|
|
420
|
+
* Remove the registration from this request's container. Subsequent `get`
|
|
421
|
+
* calls return `undefined`. Returns true if the key existed.
|
|
422
|
+
*/
|
|
423
|
+
clear(target: ContainerHolder): boolean;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Define a typed, request-scoped DI key.
|
|
427
|
+
*
|
|
428
|
+
* The returned object's `set`/`get`/`clear` work against the container belonging
|
|
429
|
+
* to the request you hand in — typically `ctx.container` from a middleware or
|
|
430
|
+
* the `container` argument inside `BaseController.execute`.
|
|
431
|
+
*/
|
|
432
|
+
declare function defineRequestScopedKey<T>(key: string): RequestScopedKey<T>;
|
|
433
|
+
//#endregion
|
|
347
434
|
//#region ../core/src/models/page.d.ts
|
|
348
435
|
/**
|
|
349
436
|
* BasePage — 所有页面共享的基础属性
|
|
350
437
|
*
|
|
351
438
|
* 具体页面类型由应用层定义并扩展此接口。
|
|
439
|
+
*
|
|
440
|
+
* SSR prefetch 数据序列化时的可见性由 `FINESOFT_PUBLIC` symbol 控制 —— 见
|
|
441
|
+
* `markPublic` / `isPublicMarked`。没有 marker 时 `serializeServerData` 仍按全字段
|
|
442
|
+
* 序列化(向后兼容),但会在 dev 启动后打印一次告警,下一个 major 会改为只序列化
|
|
443
|
+
* `BasePage` 的标准字段(id/pageType/title/description/url)。
|
|
352
444
|
*/
|
|
353
445
|
interface BasePage {
|
|
354
446
|
id: string;
|
|
@@ -357,6 +449,41 @@ interface BasePage {
|
|
|
357
449
|
description?: string;
|
|
358
450
|
url?: string;
|
|
359
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* 显式声明 page 对象里哪些字段可以跨 SSR/CSR 边界进入 HTML。未列出的字段在
|
|
454
|
+
* `serializeServerData` 时会被剥除,杜绝整 page 对象(含 apiToken、内部备注等)
|
|
455
|
+
* 被无意中 hydrate 到客户端的失误。
|
|
456
|
+
*
|
|
457
|
+
* 用 symbol 而非普通字段名:避免和应用自己的字段冲突,且 `JSON.stringify` 自动
|
|
458
|
+
* 忽略 symbol key,所以 marker 永远不会出现在序列化输出里。
|
|
459
|
+
*/
|
|
460
|
+
declare const FINESOFT_PUBLIC: unique symbol;
|
|
461
|
+
/** 标准 BasePage 字段 —— marker 缺失但显式标注时使用。 */
|
|
462
|
+
declare const BASE_PAGE_FIELDS: readonly ["id", "pageType", "title", "description", "url"];
|
|
463
|
+
/**
|
|
464
|
+
* 把 `publicFields` 列表写到 page 上,供 `serializeServerData` 读取。
|
|
465
|
+
* 推荐做法是不要直接渲染原始 page 对象,而是经过这个函数显式声明 contract:
|
|
466
|
+
*
|
|
467
|
+
* ```ts
|
|
468
|
+
* return markPublic(
|
|
469
|
+
* {
|
|
470
|
+
* id: "profile",
|
|
471
|
+
* pageType: "profile",
|
|
472
|
+
* title: user.name,
|
|
473
|
+
* email: user.email,
|
|
474
|
+
* apiToken: user.apiToken, // 仍在对象上,给服务端别处用
|
|
475
|
+
* },
|
|
476
|
+
* ["id", "pageType", "title", "email"], // 但 prefetch 只 serialize 这些
|
|
477
|
+
* );
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* 也可以传 `true` 表示「所有字段都安全」—— 当作 opt-out,等价于不调用本函数。
|
|
481
|
+
*/
|
|
482
|
+
declare function markPublic<P extends BasePage>(page: P, publicFields: readonly (keyof P)[] | true): P;
|
|
483
|
+
/** True 如果 page 用 `markPublic` 显式标过。 */
|
|
484
|
+
declare function isPublicMarked(page: unknown): boolean;
|
|
485
|
+
/** 取出 `markPublic` 写入的字段白名单;`true` 表示全开放,`null` 表示未标注。 */
|
|
486
|
+
declare function getPublicFields(page: unknown): readonly string[] | true | null;
|
|
360
487
|
//#endregion
|
|
361
488
|
//#region ../core/src/middleware/types.d.ts
|
|
362
489
|
/** 导航上下文(beforeLoad 阶段可用) */
|
|
@@ -365,8 +492,8 @@ interface NavigationContext {
|
|
|
365
492
|
readonly url: string;
|
|
366
493
|
/** 仅路径部分 */
|
|
367
494
|
readonly path: string;
|
|
368
|
-
/** 路由参数 +
|
|
369
|
-
readonly params: Record<string,
|
|
495
|
+
/** 路由参数 + 查询参数(codec 转换后可能是 number/boolean 等) */
|
|
496
|
+
readonly params: Record<string, unknown>;
|
|
370
497
|
/** 匹配的 Intent */
|
|
371
498
|
readonly intent: Intent;
|
|
372
499
|
/** 是否在服务端运行 */
|
|
@@ -418,6 +545,50 @@ type BeforeLoadGuard = (ctx: NavigationContext) => MiddlewareResult | Promise<Mi
|
|
|
418
545
|
/** afterLoad 守卫:数据加载后、渲染前 */
|
|
419
546
|
type AfterLoadGuard = (ctx: PostLoadContext) => MiddlewareResult | Promise<MiddlewareResult>;
|
|
420
547
|
//#endregion
|
|
548
|
+
//#region ../core/src/router/params/standard.d.ts
|
|
549
|
+
/**
|
|
550
|
+
* Standard Schema v1 接口的最小本地声明 + 运行助手。
|
|
551
|
+
* 纯 type-level 规范 + 运行时鸭子类型,不依赖 @standard-schema/spec 运行时包。
|
|
552
|
+
* https://standardschema.dev
|
|
553
|
+
*/
|
|
554
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
555
|
+
readonly "~standard": {
|
|
556
|
+
readonly version: 1;
|
|
557
|
+
readonly vendor: string;
|
|
558
|
+
readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
|
|
559
|
+
readonly types?: {
|
|
560
|
+
readonly input: Input;
|
|
561
|
+
readonly output: Output;
|
|
562
|
+
};
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
type StandardResult<Output> = {
|
|
566
|
+
readonly value: Output;
|
|
567
|
+
readonly issues?: undefined;
|
|
568
|
+
} | {
|
|
569
|
+
readonly issues: ReadonlyArray<StandardIssue>;
|
|
570
|
+
};
|
|
571
|
+
interface StandardIssue {
|
|
572
|
+
readonly message: string;
|
|
573
|
+
readonly path?: ReadonlyArray<PropertyKey | {
|
|
574
|
+
readonly key: PropertyKey;
|
|
575
|
+
}>;
|
|
576
|
+
}
|
|
577
|
+
/** 提取 Standard Schema 的输出类型 */
|
|
578
|
+
type InferOutput<S extends StandardSchemaV1> = NonNullable<S["~standard"]["types"]>["output"];
|
|
579
|
+
/** 路由参数 codec:输入恒为 string(缺失时 undefined),输出为目标类型 T */
|
|
580
|
+
type ParamSchema<T = unknown> = StandardSchemaV1<string, T>;
|
|
581
|
+
/** 工厂:从一个 validate 函数构造实现了 ~standard 的 codec */
|
|
582
|
+
declare function makeSchema<T>(validate: (value: unknown) => StandardResult<T> | Promise<StandardResult<T>>): ParamSchema<T>;
|
|
583
|
+
/** 统一执行任意 Standard Schema 的校验,吸收同步/异步差异 */
|
|
584
|
+
declare function runStandard(schema: StandardSchemaV1, raw: string | undefined): Promise<{
|
|
585
|
+
ok: true;
|
|
586
|
+
value: unknown;
|
|
587
|
+
} | {
|
|
588
|
+
ok: false;
|
|
589
|
+
issues: readonly StandardIssue[];
|
|
590
|
+
}>;
|
|
591
|
+
//#endregion
|
|
421
592
|
//#region ../core/src/router/router.d.ts
|
|
422
593
|
/** 路由匹配结果 */
|
|
423
594
|
interface RouteMatch {
|
|
@@ -434,18 +605,58 @@ interface RouteAddOptions {
|
|
|
434
605
|
renderMode?: string;
|
|
435
606
|
beforeGuards?: BeforeLoadGuard[];
|
|
436
607
|
afterGuards?: AfterLoadGuard[];
|
|
608
|
+
paramCodecs?: Record<string, ParamSchema>;
|
|
609
|
+
queryCodecs?: Record<string, StandardSchemaV1<string, unknown>>;
|
|
437
610
|
}
|
|
438
611
|
declare class Router {
|
|
612
|
+
private readonly debug?;
|
|
439
613
|
private routes;
|
|
614
|
+
constructor(debug?: ((message: string) => void) | undefined);
|
|
440
615
|
/** 添加路由规则 */
|
|
441
616
|
add(pattern: string, intentId: string, renderModeOrOptions?: string | RouteAddOptions): this;
|
|
442
|
-
/** 解析 URL → RouteMatch */
|
|
443
|
-
resolve(urlOrPath: string): RouteMatch | null
|
|
617
|
+
/** 解析 URL → RouteMatch(含参数校验;校验失败则 fall-through 到下一条路由) */
|
|
618
|
+
resolve(urlOrPath: string): Promise<RouteMatch | null>;
|
|
444
619
|
/** 获取所有已注册的路由 */
|
|
445
620
|
getRoutes(): string[];
|
|
446
621
|
private parseUrl;
|
|
447
622
|
}
|
|
448
623
|
//#endregion
|
|
624
|
+
//#region ../core/src/router/params/primitives.d.ts
|
|
625
|
+
interface StrOptions {
|
|
626
|
+
minLength?: number;
|
|
627
|
+
maxLength?: number;
|
|
628
|
+
pattern?: RegExp;
|
|
629
|
+
}
|
|
630
|
+
declare function str(opts?: StrOptions): ParamSchema<string>;
|
|
631
|
+
interface NumOptions {
|
|
632
|
+
min?: number;
|
|
633
|
+
max?: number;
|
|
634
|
+
}
|
|
635
|
+
declare function int(opts?: NumOptions): ParamSchema<number>;
|
|
636
|
+
declare function num(opts?: NumOptions): ParamSchema<number>;
|
|
637
|
+
declare function bool(): ParamSchema<boolean>;
|
|
638
|
+
declare function oneOf<const T extends readonly string[]>(values: T): ParamSchema<T[number]>;
|
|
639
|
+
declare function uuid(): ParamSchema<string>;
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region ../core/src/router/params/modifiers.d.ts
|
|
642
|
+
/** 输入缺失(undefined)时跳过校验、产出 undefined;否则委托内部 codec(同步或异步均可)。 */
|
|
643
|
+
declare function optional<T>(codec: ParamSchema<T>): ParamSchema<T | undefined>;
|
|
644
|
+
/** 输入缺失时用 fallback;否则委托内部 codec。 */
|
|
645
|
+
declare function withDefault<T>(codec: ParamSchema<T>, fallback: T): ParamSchema<T>;
|
|
646
|
+
//#endregion
|
|
647
|
+
//#region ../core/src/router/params/infer.d.ts
|
|
648
|
+
/** 剥离可选参数尾随的 "?" */
|
|
649
|
+
type StripOptional<S extends string> = S extends `${infer N}?` ? N : S;
|
|
650
|
+
/** 从 path pattern 字面量提取参数名联合(处理 :param 与 :param?) */
|
|
651
|
+
type ExtractParamNames<Path extends string> = Path extends `${infer _Head}:${infer Rest}` ? Rest extends `${infer Name}/${infer Tail}` ? StripOptional<Name> | ExtractParamNames<`/${Tail}`> : StripOptional<Rest> : never;
|
|
652
|
+
/** path 参数 codec map 的形状:key 只能是 path 中出现的参数名(均可选声明) */
|
|
653
|
+
type ParamsFor<Path extends string> = { [K in ExtractParamNames<Path>]?: ParamSchema };
|
|
654
|
+
/** query 参数 codec map:key 自由开放 */
|
|
655
|
+
type QuerySchemaMap = Record<string, StandardSchemaV1<string, unknown>>;
|
|
656
|
+
/** 从 codec map 推导运行期参数类型 */
|
|
657
|
+
type InferParams<P extends Record<string, ParamSchema>> = { [K in keyof P]: InferOutput<P[K]> };
|
|
658
|
+
type InferQuery<Q extends QuerySchemaMap> = { [K in keyof Q]: InferOutput<Q[K]> };
|
|
659
|
+
//#endregion
|
|
449
660
|
//#region ../core/src/logger/composite.d.ts
|
|
450
661
|
declare class CompositeLoggerFactory implements LoggerFactory {
|
|
451
662
|
private readonly factories;
|
|
@@ -570,7 +781,7 @@ declare class Framework {
|
|
|
570
781
|
/** 执行 Action — 处理用户交互 */
|
|
571
782
|
perform(action: Action): Promise<void>;
|
|
572
783
|
/** 路由 URL — 将 URL 解析为 Intent + Action */
|
|
573
|
-
routeUrl(url: string): RouteMatch | null
|
|
784
|
+
routeUrl(url: string): Promise<RouteMatch | null>;
|
|
574
785
|
/** 记录页面访问事件 */
|
|
575
786
|
didEnterPage(page: BasePage): void;
|
|
576
787
|
/** 获取 locale 信息(如果已配置) */
|
|
@@ -595,6 +806,32 @@ declare class Framework {
|
|
|
595
806
|
dispose(): void;
|
|
596
807
|
}
|
|
597
808
|
//#endregion
|
|
809
|
+
//#region ../core/src/models/safe-error-page.d.ts
|
|
810
|
+
interface SafeErrorPageOptions {
|
|
811
|
+
/** HTTP-style status code used in the page title (e.g. 404, 500). */
|
|
812
|
+
status: number;
|
|
813
|
+
/**
|
|
814
|
+
* The message users / client code may safely see in production. Should
|
|
815
|
+
* contain no stack, file paths, hostnames, or secrets.
|
|
816
|
+
*/
|
|
817
|
+
publicMessage: string;
|
|
818
|
+
/**
|
|
819
|
+
* Optional error / debug payload to surface only in non-production. In
|
|
820
|
+
* production this is dropped entirely; only `publicMessage` is exposed.
|
|
821
|
+
*/
|
|
822
|
+
devError?: unknown;
|
|
823
|
+
/**
|
|
824
|
+
* Override the production detection. Pass `true` to force the prod-safe
|
|
825
|
+
* variant (drops devError). Defaults to detecting `process.env.NODE_ENV`.
|
|
826
|
+
*/
|
|
827
|
+
isProduction?: boolean;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Build a BasePage for an error condition. In production, only `publicMessage`
|
|
831
|
+
* makes it into the page. In dev, `devError` (if provided) is appended.
|
|
832
|
+
*/
|
|
833
|
+
declare function safeErrorPage(options: SafeErrorPageOptions): BasePage;
|
|
834
|
+
//#endregion
|
|
598
835
|
//#region ../core/src/models/shelf.d.ts
|
|
599
836
|
interface BaseShelf {
|
|
600
837
|
id: string;
|
|
@@ -624,6 +861,9 @@ declare function stableStringify(obj: unknown): string;
|
|
|
624
861
|
*
|
|
625
862
|
* 为 API Client 提供标准化的 HTTP 请求能力。
|
|
626
863
|
* 子类继承后只需关注业务端点定义,不需要重复实现 fetch / JSON 解析 / 错误处理。
|
|
864
|
+
*
|
|
865
|
+
* 默认安全:拒绝向内网 / loopback / 保留地址发请求(SSRF 防御)。应用层
|
|
866
|
+
* 显式 opt-out 用 `allowInternalHosts: true`。详见 host-guard.ts。
|
|
627
867
|
*/
|
|
628
868
|
/** HTTP 请求错误 */
|
|
629
869
|
declare class HttpError extends Error {
|
|
@@ -632,6 +872,15 @@ declare class HttpError extends Error {
|
|
|
632
872
|
readonly body?: string | undefined;
|
|
633
873
|
constructor(status: number, statusText: string, body?: string | undefined);
|
|
634
874
|
}
|
|
875
|
+
/**
|
|
876
|
+
* SSRF 防护拦截到不安全的目标地址时抛出。应用层可以 catch 它来给出业务友好的错误,
|
|
877
|
+
* 不需要靠 message 字符串匹配。
|
|
878
|
+
*/
|
|
879
|
+
declare class HostGuardError extends Error {
|
|
880
|
+
readonly url: string;
|
|
881
|
+
readonly reason: string;
|
|
882
|
+
constructor(url: string, reason: string);
|
|
883
|
+
}
|
|
635
884
|
/** 请求拦截器 — 在发送前修改请求 */
|
|
636
885
|
interface RequestInterceptor {
|
|
637
886
|
(url: string, init: RequestInit): RequestInit | Promise<RequestInit>;
|
|
@@ -652,6 +901,22 @@ interface HttpClientConfig {
|
|
|
652
901
|
requestInterceptors?: RequestInterceptor[];
|
|
653
902
|
/** 响应拦截器(按注册顺序执行) */
|
|
654
903
|
responseInterceptors?: ResponseInterceptor[];
|
|
904
|
+
/**
|
|
905
|
+
* 是否允许向私有 / loopback / 保留 IP 段发请求。
|
|
906
|
+
*
|
|
907
|
+
* **默认 false** —— 阻止内网穿透(SSRF)。如果你的服务正常需要打内网(如
|
|
908
|
+
* 微服务对内 API、127.0.0.1 上的开发依赖),把它设为 true 显式 opt-out,并
|
|
909
|
+
* 自己做来源校验。
|
|
910
|
+
*/
|
|
911
|
+
allowInternalHosts?: boolean;
|
|
912
|
+
/**
|
|
913
|
+
* 是否在请求前 DNS 解析 hostname 并对解析结果做 IP 段校验。
|
|
914
|
+
*
|
|
915
|
+
* **默认 true**(仅 Node 环境有效;浏览器静默跳过)。配合 `allowInternalHosts`
|
|
916
|
+
* 防御 DNS rebinding:如果 hostname 不是 IP 字面量,框架会 resolve 它的 A/AAAA
|
|
917
|
+
* 记录并按 IP 段校验。`false` 关闭只剩 IP 字面量同步校验。
|
|
918
|
+
*/
|
|
919
|
+
validateDns?: boolean;
|
|
655
920
|
}
|
|
656
921
|
/**
|
|
657
922
|
* 通用 HTTP 客户端基类
|
|
@@ -673,6 +938,8 @@ declare abstract class HttpClient {
|
|
|
673
938
|
protected readonly fetchFn: typeof globalThis.fetch;
|
|
674
939
|
private readonly requestInterceptors;
|
|
675
940
|
private readonly responseInterceptors;
|
|
941
|
+
private readonly allowInternalHosts;
|
|
942
|
+
private readonly validateDns;
|
|
676
943
|
constructor(config: HttpClientConfig);
|
|
677
944
|
/** 动态添加请求拦截器 */
|
|
678
945
|
useRequestInterceptor(interceptor: RequestInterceptor): this;
|
|
@@ -691,6 +958,7 @@ declare abstract class HttpClient {
|
|
|
691
958
|
*
|
|
692
959
|
* 自动处理:
|
|
693
960
|
* - URL 拼接 (baseUrl + path + params)
|
|
961
|
+
* - SSRF 防护(IP 字面量同步校验 + 可选 DNS 解析校验)
|
|
694
962
|
* - 默认 headers 合并
|
|
695
963
|
* - JSON body 序列化
|
|
696
964
|
* - 响应 JSON 解析
|
|
@@ -703,8 +971,58 @@ declare abstract class HttpClient {
|
|
|
703
971
|
}): Promise<T>;
|
|
704
972
|
/** 构建完整 URL — 子类可覆写以自定义 URL 拼接逻辑 */
|
|
705
973
|
protected buildUrl(path: string, params?: Record<string, string>): string;
|
|
974
|
+
private enforceHostGuard;
|
|
706
975
|
}
|
|
707
976
|
//#endregion
|
|
977
|
+
//#region ../core/src/http/host-guard.d.ts
|
|
978
|
+
/**
|
|
979
|
+
* host-guard — refuse outbound requests to private / loopback / reserved hosts.
|
|
980
|
+
*
|
|
981
|
+
* Why this exists: `HttpClient` and the raw `fetch` injected via DI both used
|
|
982
|
+
* to accept any URL the application built. SSR controllers that take a
|
|
983
|
+
* user-controlled URL (image proxy, link preview, OAuth callback) could be
|
|
984
|
+
* tricked into fetching `http://127.0.0.1/admin` and embedding the response in
|
|
985
|
+
* the SSR HTML. Round 1 of the adversarial drill walked straight through this;
|
|
986
|
+
* round 2's hand-rolled IPv4 regex was bypassed in five minutes with
|
|
987
|
+
* `[::ffff:7f00:1]`. This module centralises the check so applications can stop
|
|
988
|
+
* re-implementing it (badly).
|
|
989
|
+
*
|
|
990
|
+
* Coverage (synchronous, IP-literal forms):
|
|
991
|
+
* - IPv4 dotted-decimal: `127.0.0.1`, `10.0.0.5`, `192.168.1.1`, `172.16.0.1`
|
|
992
|
+
* - IPv4 zero / link-local / multicast / reserved: `0.0.0.0`, `169.254.0.1`,
|
|
993
|
+
* `224.0.0.1`, `240.0.0.0/4`
|
|
994
|
+
* - IPv4 non-dotted forms accepted by some parsers: decimal `2130706433`,
|
|
995
|
+
* hex `0x7f000001`, octal `0177.0.0.1`
|
|
996
|
+
* - IPv6 loopback `::1`, link-local `fe80::/10`, ULA `fc00::/7`, unspecified `::`
|
|
997
|
+
* - IPv4-mapped IPv6: `::ffff:7f00:1`, `::ffff:127.0.0.1`
|
|
998
|
+
* - Names: `localhost`, `*.localhost`
|
|
999
|
+
*
|
|
1000
|
+
* NOT covered here (callers can layer on top):
|
|
1001
|
+
* - DNS resolution of arbitrary hostnames — see `validateUrlWithDns` in
|
|
1002
|
+
* server-only callers. DNS rebinding is impossible to fix at this layer
|
|
1003
|
+
* alone; the right pattern is "resolve once, then fetch by IP".
|
|
1004
|
+
* - IDN / homograph attacks — Node's URL parser punycode-encodes hostnames
|
|
1005
|
+
* already, so the hostname this code sees is the ASCII form.
|
|
1006
|
+
*/
|
|
1007
|
+
type HostCheckResult = {
|
|
1008
|
+
ok: true;
|
|
1009
|
+
} | {
|
|
1010
|
+
ok: false;
|
|
1011
|
+
reason: string;
|
|
1012
|
+
};
|
|
1013
|
+
/**
|
|
1014
|
+
* Inspect a hostname string (the `URL.hostname` value, without brackets, port,
|
|
1015
|
+
* or userinfo). Returns `{ok: false}` for anything in a private/loopback/
|
|
1016
|
+
* reserved range; `{ok: true}` if the literal looks like a public address or a
|
|
1017
|
+
* non-IP name (the caller may then DNS-resolve and re-check).
|
|
1018
|
+
*/
|
|
1019
|
+
declare function classifyHost(rawHost: string): HostCheckResult;
|
|
1020
|
+
/**
|
|
1021
|
+
* Convenience wrapper for callers holding a full URL string. Also rejects
|
|
1022
|
+
* non-http(s) schemes (gopher, file, data, …).
|
|
1023
|
+
*/
|
|
1024
|
+
declare function classifyUrl(rawUrl: string): HostCheckResult;
|
|
1025
|
+
//#endregion
|
|
708
1026
|
//#region ../core/src/intents/base-controller.d.ts
|
|
709
1027
|
/**
|
|
710
1028
|
* 抽象 Controller 基类
|
|
@@ -730,7 +1048,7 @@ declare abstract class HttpClient {
|
|
|
730
1048
|
* }
|
|
731
1049
|
* ```
|
|
732
1050
|
*/
|
|
733
|
-
declare abstract class BaseController<TParams extends Record<string,
|
|
1051
|
+
declare abstract class BaseController<TParams extends Record<string, unknown> = Record<string, unknown>, TResult = unknown> implements IntentController<TResult> {
|
|
734
1052
|
/** Controller 对应的 Intent ID */
|
|
735
1053
|
abstract readonly intentId: string;
|
|
736
1054
|
/**
|
|
@@ -803,34 +1121,40 @@ declare function mapEach<TInput, TOutput>(mapper: Mapper<TInput, TOutput>): Mapp
|
|
|
803
1121
|
/** 渲染模式 */
|
|
804
1122
|
type RenderMode = "ssr" | "csr" | "prerender";
|
|
805
1123
|
/** 单条路由定义 */
|
|
806
|
-
interface RouteDefinition {
|
|
807
|
-
/** URL pattern (如 "/product/:
|
|
808
|
-
path:
|
|
809
|
-
/** Intent ID
|
|
1124
|
+
interface RouteDefinition<Path extends string = string, P extends ParamsFor<Path> = ParamsFor<Path>, Q extends QuerySchemaMap = QuerySchemaMap> {
|
|
1125
|
+
/** URL pattern (如 "/product/:id") */
|
|
1126
|
+
path: Path;
|
|
1127
|
+
/** Intent ID */
|
|
810
1128
|
intentId: string;
|
|
811
|
-
/**
|
|
812
|
-
* Controller 实例(可选)。
|
|
813
|
-
* 同一个 intentId 的多条路由只需在第一条提供 controller。
|
|
814
|
-
*/
|
|
1129
|
+
/** Controller 实例(可选)。同一 intentId 的多条路由只需在第一条提供。 */
|
|
815
1130
|
controller?: IntentController;
|
|
816
|
-
/**
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
*/
|
|
1131
|
+
/** path 参数 codec;key 必须是 path 中出现的 :param 名 */
|
|
1132
|
+
params?: P;
|
|
1133
|
+
/** query 参数 codec;key 自由 */
|
|
1134
|
+
query?: Q;
|
|
1135
|
+
/** 渲染模式(可选,默认 "ssr") */
|
|
822
1136
|
renderMode?: RenderMode;
|
|
823
|
-
/**
|
|
824
|
-
* 路由级 beforeLoad 守卫(可选)。
|
|
825
|
-
* 在全局守卫之后执行,仅对匹配此路由的请求生效。
|
|
826
|
-
*/
|
|
1137
|
+
/** 路由级 beforeLoad 守卫 */
|
|
827
1138
|
beforeLoad?: BeforeLoadGuard[];
|
|
828
|
-
/**
|
|
829
|
-
* 路由级 afterLoad 守卫(可选)。
|
|
830
|
-
* 在全局守卫之后执行,仅对匹配此路由的请求生效。
|
|
831
|
-
*/
|
|
1139
|
+
/** 路由级 afterLoad 守卫 */
|
|
832
1140
|
afterLoad?: AfterLoadGuard[];
|
|
833
1141
|
}
|
|
1142
|
+
/**
|
|
1143
|
+
* 构造一条强类型路由定义。
|
|
1144
|
+
* `params` 的 key 受 `path` 字面量约束——写入 path 中不存在的参数名会编译期报错。
|
|
1145
|
+
*
|
|
1146
|
+
* @example
|
|
1147
|
+
* route("/product/:id", { intentId: "product", controller, params: { id: int() } })
|
|
1148
|
+
*/
|
|
1149
|
+
declare function route<const Path extends string, P extends ParamsFor<Path> = ParamsFor<Path>, Q extends QuerySchemaMap = QuerySchemaMap>(path: Path, def: {
|
|
1150
|
+
intentId: string;
|
|
1151
|
+
controller?: IntentController;
|
|
1152
|
+
params?: P;
|
|
1153
|
+
query?: Q;
|
|
1154
|
+
renderMode?: RenderMode;
|
|
1155
|
+
beforeLoad?: BeforeLoadGuard[];
|
|
1156
|
+
afterLoad?: AfterLoadGuard[];
|
|
1157
|
+
}): RouteDefinition;
|
|
834
1158
|
/** defineRoutes 选项 */
|
|
835
1159
|
interface DefineRoutesOptions {
|
|
836
1160
|
/**
|
|
@@ -1245,5 +1569,5 @@ declare function deserializeServerData(): PrefetchedIntent[] | undefined;
|
|
|
1245
1569
|
*/
|
|
1246
1570
|
declare function createPrefetchedIntentsFromDom(): PrefetchedIntents;
|
|
1247
1571
|
//#endregion
|
|
1248
|
-
export { RenderMode as $,
|
|
1249
|
-
//# sourceMappingURL=server-data-
|
|
1572
|
+
export { RenderMode as $, BaseLogger as $n, RouteAddOptions as $t, IntersectionImpressionObserver as A, DEP_KEYS as An, Translator as At, buildUrl as B, TranslationMessages as Bn, ParamsFor as Bt, PluralRuleProvider as C, BasePage as Cn, Framework as Ct, WithFieldsRecorder as D, markPublic as Dn, LocaleAttributes as Dt, resolvePluralKey as E, isPublicMarked as En, PrefetchedIntents as Et, BrowserContextOptions as F, Net as Fn, CompositeLogger as Ft, PWADisplayMode as G, EventRecorder as Gn, NumOptions as Gt, removeHost as H, resolveMessages as Hn, StripOptional as Ht, ServerContextOptions as I, Storage as In, CompositeLoggerFactory as It, Optional as J, MetricsFieldsProvider as Jn, int as Jt, getPWADisplayMode as K, ImpressionEntry as Kn, StrOptions as Kt, createBrowserContext as L, makeDependencies as Ln, ExtractParamNames as Lt, CompositeEventRecorder as M, FeatureFlagsProvider as Mn, shouldLog as Mt, runAfterLoadGuards as N, MakeDependenciesOptions as Nn, ConsoleLogger as Nt, VoidEventRecorder as O, RequestScopedKey as On, LocaleInfo as Ot, runBeforeLoadGuards as P, MetricsRecorder as Pn, ConsoleLoggerFactory as Pt, DefineRoutesOptions as Q, ReportingLoggerOptions as Qn, uuid as Qt, createServerContext as R, MessagesLoader as Rn, InferParams as Rt, PluralCategory as S, BASE_PAGE_FIELDS as Sn, safeErrorPage as St, interpolate as T, getPublicFields as Tn, PrefetchedIntent as Tt, removeQueryParams as U, PlatformInfo as Un, optional as Ut, getBaseUrl as V, resolveConfiguredMessages as Vn, QuerySchemaMap as Vt, removeScheme as W, detectPlatform as Wn, withDefault as Wt, isSome as X, ReportingLogger as Xn, oneOf as Xt, isNone as Y, ReportCallback as Yn, num as Yt, LruMap as Z, ReportingLoggerFactory as Zn, str as Zt, getTextDirection as _, RewriteResult as _n, isFlowAction as _r, ResponseInterceptor as _t, BrowserAppConfig as a, StandardResult as an, Intent as ar, mapEach as at, resolveLocaleFromUrl as b, redirect as bn, BaseShelf as bt, registerActionHandlers as c, runStandard as cn, ActionDispatcher as cr, BaseController as ct, registerFlowActionHandler as d, DenyResult as dn, Action as dr, classifyUrl as dt, RouteMatch as en, Logger as er, RouteDefinition as et, ExternalUrlDependencies as f, MiddlewareResult as fn, CompoundAction as fr, HostGuardError as ft, getLocaleAttributes as g, RedirectResult as gn, isExternalUrlAction as gr, RequestInterceptor as gt, SimpleTranslatorOptions as h, PostLoadContext as hn, isCompoundAction as hr, HttpError as ht, History as i, StandardIssue as in, IntentDispatcher as ir, Mapper as it, ConsoleEventRecorder as j, FeatureFlags as jn, resetFilterCache as jt, ImpressionObserverOptions as k, defineRequestScopedKey as kn, TextDirection as kt, FlowActionCallbacks as l, AfterLoadGuard as ln, ActionHandler as lr, HostCheckResult as lt, SimpleTranslator as m, NextResult as mn, FlowAction as mr, HttpClientConfig as mt, deserializeServerData as n, InferOutput as nn, SecureFetchOptions as nr, route as nt, startBrowserApp as o, StandardSchemaV1 as on, IntentController as or, pipe as ot, registerExternalUrlHandler as p, NavigationContext as pn, ExternalUrlAction as pr, HttpClient as pt, None as q, ImpressionObserver as qn, bool as qt, tryScroll as r, ParamSchema as rn, secureFetch as rr, AsyncMapper as rt, ActionHandlerDependencies as s, makeSchema as sn, Container as sr, pipeAsync as st, createPrefetchedIntentsFromDom as t, Router as tn, LoggerFactory as tr, defineRoutes as tt, FlowActionDependencies as u, BeforeLoadGuard as un, ACTION_KINDS as ur, classifyHost as ut, isRtl as v, deny as vn, makeExternalUrlAction as vr, stableStringify as vt, englishPlural as w, FINESOFT_PUBLIC as wn, FrameworkConfig as wt, setHtmlLocaleAttributes as x, rewrite as xn, SafeErrorPageOptions as xt, makeLocaleInfo as y, next as yn, makeFlowAction as yr, BaseItem as yt, generateUuid as z, MessagesLoaderContext as zn, InferQuery as zt };
|
|
1573
|
+
//# sourceMappingURL=server-data-DQzknR97.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e={FLOW:`flow`,EXTERNAL_URL:`externalUrl`,COMPOUND:`compound`};function t(t){return t.kind===e.FLOW}function n(t){return t.kind===e.EXTERNAL_URL}function r(t){return t.kind===e.COMPOUND}function i(t,n){return{kind:e.FLOW,url:t,presentationContext:n}}function a(t){return{kind:e.EXTERNAL_URL,url:t}}var o=class{handlers=new Map;onAction(e,t){if(this.handlers.has(e)){console.warn(`[ActionDispatcher] kind="${e}" already registered, skipping`);return}this.handlers.set(e,t)}removeAction(e){return this.handlers.delete(e)}async perform(e,t=0){if(r(e)){if(t>=32)throw Error(`[ActionDispatcher] CompoundAction recursion depth exceeded (max 32)`);for(let n of e.actions)await this.perform(n,t+1);return}let n=this.handlers.get(e.kind);if(!n){console.warn(`[ActionDispatcher] No handler for kind="${e.kind}"`);return}await n(e)}},s=class{controllers=new Map;register(e){this.controllers.set(e.intentId,e)}async dispatch(e,t){let n=this.controllers.get(e.id);if(!n)throw Error(`[IntentDispatcher] No controller for "${e.id}". Registered: [${Array.from(this.controllers.keys()).join(`, `)}]`);return n.perform(e,t)}has(e){return this.controllers.has(e)}},c=class e{registrations=new Map;resolutionStack=new Set;parent;children=new Set;register(e,t,n=!0){return this.registrations.set(e,{factory:t,singleton:n}),this}resolve(e){let t=this.registrations.get(e);if(!t){if(this.parent)return this.parent.resolve(e);throw Error(`[Container] No registration for key: "${e}"`)}if(t.singleton){if(t.instance===void 0){if(this.resolutionStack.has(e))throw Error(`[Container] Circular dependency detected: ${[...this.resolutionStack,e].join(` → `)}`);this.resolutionStack.add(e);try{t.instance=t.factory()}finally{this.resolutionStack.delete(e)}}return t.instance}return t.factory()}has(e){return this.registrations.has(e)||(this.parent?.has(e)??!1)}unregister(e){return this.registrations.delete(e)}createScope(){let t=new e;return t.parent=this,this.children.add(t),t}dispose(){let e=Array.from(this.children);for(let t of e)t.dispose();this.children.clear();for(let e of this.registrations.values())e.instance=void 0;this.registrations.clear(),this.parent&&=(this.parent.children.delete(this),void 0)}};function l(e){if(!e)return{ok:!1,reason:`empty host`};let t=e.toLowerCase(),n=t.startsWith(`[`)&&t.endsWith(`]`)?t.slice(1,-1):t;if(n===`localhost`||n.endsWith(`.localhost`))return{ok:!1,reason:`loopback host forbidden`};if(n.includes(`:`))return m(n);let r=d(n);return r?p(r):{ok:!0}}function u(e){let t;try{t=new URL(e)}catch{return{ok:!1,reason:`invalid URL`}}return t.protocol!==`http:`&&t.protocol!==`https:`?{ok:!1,reason:`scheme "${t.protocol}" not allowed (only http/https)`}:l(t.hostname)}function d(e){if(e.length===0)return null;if(!e.includes(`.`)){let t=f(e);return t===null||t<0||t>4294967295?null:[t>>>24&255,t>>>16&255,t>>>8&255,t&255]}let t=e.split(`.`);if(t.length!==4)return null;let n=[];for(let e of t){let t=f(e);if(t===null||t<0||t>255)return null;n.push(t)}return n}function f(e){if(e.length===0)return null;if(e.startsWith(`0x`)||e.startsWith(`0X`)){let t=e.slice(2);return/^[0-9a-f]+$/i.test(t)?parseInt(t,16):null}return e.length>1&&e.startsWith(`0`)?/^[0-7]+$/.test(e)?parseInt(e,8):null:/^[0-9]+$/.test(e)?parseInt(e,10):null}function p(e){let[t,n]=e;return t===0?{ok:!1,reason:`unspecified IPv4 forbidden`}:t===127?{ok:!1,reason:`loopback IPv4 forbidden`}:t===10?{ok:!1,reason:`private IPv4 (10/8) forbidden`}:t===172&&n>=16&&n<=31?{ok:!1,reason:`private IPv4 (172.16/12) forbidden`}:t===192&&n===168?{ok:!1,reason:`private IPv4 (192.168/16) forbidden`}:t===169&&n===254?{ok:!1,reason:`link-local IPv4 forbidden`}:t===100&&n>=64&&n<=127?{ok:!1,reason:`CGNAT IPv4 forbidden`}:t>=224&&t<=239?{ok:!1,reason:`multicast IPv4 forbidden`}:t>=240?{ok:!1,reason:`reserved IPv4 forbidden`}:{ok:!0}}function m(e){let t=e.toLowerCase();if(t===`::`||t===`::0`)return{ok:!1,reason:`unspecified IPv6 forbidden`};if(t===`::1`)return{ok:!1,reason:`loopback IPv6 forbidden`};if(t.startsWith(`fe8`)||t.startsWith(`fe9`)||t.startsWith(`fea`)||t.startsWith(`feb`))return{ok:!1,reason:`link-local IPv6 forbidden`};if(t.startsWith(`fc`)||t.startsWith(`fd`))return{ok:!1,reason:`ULA IPv6 forbidden`};if(t.startsWith(`ff`))return{ok:!1,reason:`multicast IPv6 forbidden`};let n=h(t);if(n){let e=p(n);if(!e.ok)return{ok:!1,reason:`IPv4-in-IPv6 ${e.reason}`}}return{ok:!0}}function h(e){let t=e.match(/(?:^|:)((?:\d{1,3}\.){3}\d{1,3})$/);if(t){let e=d(t[1]);if(e)return e}let n=e.match(/(?:^|:)([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);if(n&&(e.startsWith(`::ffff:`)||e.includes(`:ffff:`))){let e=parseInt(n[1],16),t=parseInt(n[2],16);return[e>>>8&255,e&255,t>>>8&255,t&255]}return null}var g=class extends Error{constructor(e,t,n){super(`HTTP ${e}: ${t}`),this.status=e,this.statusText=t,this.body=n,this.name=`HttpError`}},_=class extends Error{constructor(e,t){super(`Refused to fetch ${e}: ${t}`),this.url=e,this.reason=t,this.name=`HostGuardError`}},v=class{baseUrl;defaultHeaders;fetchFn;requestInterceptors;responseInterceptors;allowInternalHosts;validateDns;constructor(e){this.baseUrl=e.baseUrl,this.defaultHeaders=e.defaultHeaders??{},this.fetchFn=e.fetch??globalThis.fetch.bind(globalThis),this.requestInterceptors=[...e.requestInterceptors??[]],this.responseInterceptors=[...e.responseInterceptors??[]],this.allowInternalHosts=e.allowInternalHosts??!1,this.validateDns=e.validateDns??!0}useRequestInterceptor(e){return this.requestInterceptors.push(e),this}useResponseInterceptor(e){return this.responseInterceptors.push(e),this}async get(e,t){return this.request(`GET`,e,{params:t})}async post(e,t,n){return this.request(`POST`,e,{body:t,params:n})}async put(e,t,n){return this.request(`PUT`,e,{body:t,params:n})}async del(e,t){return this.request(`DELETE`,e,{params:t})}async request(e,t,n){let r=this.buildUrl(t,n?.params);this.allowInternalHosts||await this.enforceHostGuard(r);let i={...this.defaultHeaders,...n?.headers},a={method:e,headers:i};n?.body!==void 0&&(Object.keys(i).some(e=>e.toLowerCase()===`content-type`)||(i[`Content-Type`]=`application/json`),a.body=JSON.stringify(n.body));for(let e of this.requestInterceptors)a=await e(r,a);let o=await this.fetchFn(r,a);for(let e of this.responseInterceptors)o=await e(o,r);if(!o.ok){let e=await o.text().catch(()=>void 0);throw new g(o.status,o.statusText,e)}try{return await o.json()}catch(e){throw e instanceof SyntaxError?new g(o.status,`Invalid JSON response`,await o.text().catch(()=>void 0)):e}}buildUrl(e,t){let n=this.baseUrl.endsWith(`/`)?this.baseUrl.slice(0,-1):this.baseUrl,r=e.startsWith(`/`)?e:`/${e}`,i=new URL(`${n}${r}`,`http://placeholder`);if(t)for(let[e,n]of Object.entries(t))i.searchParams.set(e,n);return this.baseUrl.startsWith(`http`)?i.toString():`${i.pathname}${i.search}`}async enforceHostGuard(e){let t;try{t=new URL(e)}catch{return}let n=u(e);if(!n.ok)throw new _(e,n.reason);if(this.validateDns&&t.hostname&&!ee(t.hostname)){let n=await te(t.hostname);if(!n.ok)throw new _(e,n.reason)}}};function ee(e){return e.includes(`:`)?!0:/^[0-9.]+$/.test(e)||/^0x[0-9a-f]+$/i.test(e)}async function te(e){let t;try{let e=await import(`node:dns/promises`);t=e.default??e}catch{return{ok:!0}}let n=await Promise.allSettled([t.resolve4(e),t.resolve6(e)]),r=[];for(let e of n)e.status===`fulfilled`&&r.push(...e.value);if(r.length===0)return{ok:!0};for(let e of r){let t=u(`http://${e.includes(`:`)?`[${e}]`:e}/`);if(!t.ok)return{ok:!1,reason:`host resolves to ${e} (${t.reason})`}}return{ok:!0}}function y(e,t={}){let n=t.allowInternalHosts??!1,r=t.validateDns??!0;return async function(t,i){if(!n){let e=re(t);if(e&&ne(e)){let t=u(e);if(!t.ok)throw new _(e,t.reason);if(r){let t=new URL(e);if(t.hostname&&!ie(t.hostname)){let n=await ae(t.hostname);if(!n.ok)throw new _(e,n.reason)}}}}return e(t,i)}}function ne(e){try{return new URL(e),!0}catch{return!1}}function re(e){return typeof e==`string`?e:e instanceof URL?e.toString():typeof Request<`u`&&e instanceof Request?e.url:null}function ie(e){return e.includes(`:`)?!0:/^[0-9.]+$/.test(e)||/^0x[0-9a-f]+$/i.test(e)}async function ae(e){let t;try{let e=await import(`node:dns/promises`);t=e.default??e}catch{return{ok:!0}}let n;try{n=await t.lookup(e,{all:!0})}catch{return{ok:!0}}if(n.length===0)return{ok:!0};for(let{address:e}of n){let t=u(`http://${e.includes(`:`)?`[${e}]`:e}/`);if(!t.ok)return{ok:!1,reason:`host resolves to ${e} (${t.reason})`}}return{ok:!0}}const oe=new Set([`ar`,`arc`,`dv`,`fa`,`ha`,`he`,`khw`,`ks`,`ku`,`ps`,`ur`,`yi`]);function b(e){let t=e.split(`-`)[0].toLowerCase();return oe.has(t)}function x(e){return b(e)?`rtl`:`ltr`}function se(e){return{lang:e,dir:x(e)}}function ce(e,t){return{language:e,region:t,bcp47:t?`${e}-${t}`:e,dir:x(e)}}function le(e){document.documentElement.lang=e.lang,document.documentElement.dir=e.dir}function ue(e,t){let n=e.split(`?`)[0].match(/^\/([^/]+)(\/.*)?$/);if(!n)return null;let r=n[1],i=t.find(e=>e.toLowerCase()===r.toLowerCase());return i?{locale:i,strippedUrl:n[2]||`/`}:null}async function de(e,t){if(!e||!t)return;let n=await fe();if(n)return n(e,t)}async function fe(){if(typeof globalThis.__FINESOFT_I18N_LOADER__==`function`)return globalThis.__FINESOFT_I18N_LOADER__;if(typeof __FINESOFT_I18N_LOADER_SPECIFIER__==`string`)try{let e=await import(__FINESOFT_I18N_LOADER_SPECIFIER__),t=typeof e==`function`?e:typeof e?.loadMessages==`function`?e.loadMessages:void 0;return t?(globalThis.__FINESOFT_I18N_LOADER__=t,t):void 0}catch{return}}async function pe(e){let{locale:t,loadMessages:n,context:r}=e;if(!(!t||!r))return n?n(t,r):de(t,r)}function me(e,t){let n=Object.entries(e);if(n.length===0)return;if(typeof n[0][1]==`string`)return e;let r=e[t];if(!r)return;let i={};for(let[e,t]of Object.entries(r)){if(typeof t==`string`){i[e]=t;continue}for(let[n,r]of Object.entries(t))i[`${e}.${n}`]=r}return i}function he(e,t){return t?e.replace(/\{(\w+)\}/g,(e,n)=>{let r=t[n];return r===void 0?`{${n}}`:String(r)}):e}function ge(e){return e===1?`one`:`other`}function _e(e,t){return`${e}.${t}`}var ve=class{locale;messages;pluralRule;fallback;constructor(e){this.locale=e.locale,this.messages=e.messages,this.pluralRule=e.pluralRule??ge,this.fallback=e.fallback??(e=>e)}t(e,t){let n=this.messages[e];return n===void 0?this.fallback(e):he(n,t)}plural(e,t,n){let r=_e(e,this.pluralRule(t)),i={count:t,...n};return this.t(r,i)}},S=class{constructor(e){this.factories=e}loggerFor(e){return new C(this.factories.map(t=>t.loggerFor(e)))}},C=class{constructor(e){this.loggers=e}debug(...e){return this.callAll(`debug`,e)}info(...e){return this.callAll(`info`,e)}warn(...e){return this.callAll(`warn`,e)}error(...e){return this.callAll(`error`,e)}callAll(e,t){for(let n of this.loggers)n[e](...t);return``}},w=class{category;constructor(e){this.category=e}};const T={"*":4,debug:4,info:3,warn:2,error:1,off:0,"":0};let E,D;function ye(){if(globalThis.localStorage===void 0)return{};let e;try{e=globalThis.localStorage.getItem(`onyxLog`)}catch{return{}}if(!e)return{};if(e===D&&E)return E;D=e;let t={},n=e.split(`,`);for(let e of n){let[n,r]=e.trim().split(`=`);if(!n||r===void 0)continue;let i=T[r.toLowerCase()]??void 0;i!==void 0&&(n===`*`?t.defaultLevel=i:(t.named??={},t.named[n]=i))}return E=t,t}function O(e,t){let n=ye();if(n.defaultLevel===void 0&&!n.named)return!0;let r=T[t]??4;return n.named?.[e]===void 0?n.defaultLevel===void 0?!0:r<=n.defaultLevel:r<=n.named[e]}function be(){E=void 0,D=void 0}var k=class extends w{debug(...e){return O(this.category,`debug`)&&console.debug(`[${this.category}]`,...e),``}info(...e){return O(this.category,`info`)&&console.info(`[${this.category}]`,...e),``}warn(...e){return O(this.category,`warn`)&&console.warn(`[${this.category}]`,...e),``}error(...e){return console.error(`[${this.category}]`,...e),``}},A=class{loggerFor(e){return new k(e)}};const j={debug:0,info:1,warn:2,error:3};var M=class extends w{minPriority;report;constructor(e,t){super(e),this.minPriority=j[t.minLevel??`warn`],this.report=t.report}debug(...e){return this.maybeReport(`debug`,e),``}info(...e){return this.maybeReport(`info`,e),``}warn(...e){return this.maybeReport(`warn`,e),``}error(...e){return this.maybeReport(`error`,e),``}maybeReport(e,t){if(!(j[e]<this.minPriority))try{this.report(e,this.category,t)}catch(e){console.error(`[ReportingLogger] report callback threw:`,e)}}},N=class{options;constructor(e){this.options=e}loggerFor(e){return new M(e,this.options)}},P=class{prefix;constructor(e=`Metrics`){this.prefix=e}record(e,t){console.info(`[${this.prefix}:${e}]`,t??``)}async flush(){}destroy(){}};function F(e){let t=e??(typeof navigator<`u`?navigator.userAgent:``),n=t.toLowerCase();return{os:xe(n),browser:Se(n),engine:Ce(n),isMobile:/mobile|android|iphone|ipad|ipod/i.test(t),isTouch:typeof navigator<`u`&&`maxTouchPoints`in navigator?navigator.maxTouchPoints>0:!1}}function xe(e){return/iphone|ipad|ipod/.test(e)?`ios`:/android/.test(e)?`android`:/macintosh|mac os x/.test(e)?`macos`:/windows/.test(e)?`windows`:/linux/.test(e)?`linux`:`unknown`}function Se(e){return/edg\//.test(e)?`edge`:/opr\/|opera/.test(e)?`opera`:/samsungbrowser/.test(e)?`samsung`:/chrome|crios/.test(e)&&!/edg\//.test(e)?`chrome`:/firefox|fxios/.test(e)?`firefox`:/safari/.test(e)&&!/chrome/.test(e)?`safari`:`unknown`}function Ce(e){return/applewebkit/.test(e)&&!/chrome/.test(e)?`webkit`:/applewebkit/.test(e)&&/chrome/.test(e)?`blink`:/gecko\//.test(e)?`gecko`:`unknown`}const I={LOGGER:`logger`,LOGGER_FACTORY:`loggerFactory`,NET:`net`,STORAGE:`storage`,FEATURE_FLAGS:`featureFlags`,METRICS:`metrics`,FETCH:`fetch`,SAFE_FETCH:`safeFetch`,EVENT_RECORDER:`eventRecorder`,LOCALE:`locale`,PLATFORM:`platform`,TRANSLATOR:`translator`};var we=class{store=new Map;get(e){return this.store.get(e)}set(e,t){this.store.set(e,t)}delete(e){this.store.delete(e)}},Te=class{flags;providers=[];constructor(e={}){this.flags=e}addProvider(e){this.providers.push(e)}isEnabled(e){for(let t=this.providers.length-1;t>=0;t--)if(this.providers[t].isEnabled(e))return!0;return this.flags[e]===!0}getString(e){for(let t=this.providers.length-1;t>=0;t--){let n=this.providers[t].getString?.(e);if(n!==void 0)return n}let t=this.flags[e];return typeof t==`string`?t:void 0}getNumber(e){for(let t=this.providers.length-1;t>=0;t--){let n=this.providers[t].getNumber?.(e);if(n!==void 0)return n}let t=this.flags[e];return typeof t==`number`?t:void 0}},Ee=class{record(e,t){console.info(`[Metrics:${e}]`,t??``)}recordPageView(e,t){this.record(`PageView`,{page:e,...t})}recordEvent(e,t){this.record(`Event`,{name:e,...t})}};function L(e,t={}){let{_resolvedMessages:n}=t,{fetch:r=globalThis.fetch?.bind(globalThis),featureFlags:i={},featureFlagsProviders:a=[],reportCallback:o,eventRecorder:s,locale:c,platform:l}=t,u=new A,d=o?new S([u,new N({report:o})]):u;e.register(I.LOGGER_FACTORY,()=>d),e.register(I.LOGGER,()=>d.loggerFor(`framework`)),e.register(I.NET,()=>({fetch:(e,t)=>r(e,t)})),e.register(I.STORAGE,()=>new we);let f=new Te(i);for(let e of a)f.addProvider(e);if(e.register(I.FEATURE_FLAGS,()=>f),e.register(I.METRICS,()=>new Ee),e.register(I.EVENT_RECORDER,()=>s??new P),c&&e.register(I.LOCALE,()=>se(c)),c&&n){let t=me(n,c);t&&e.register(I.TRANSLATOR,()=>new ve({locale:c,messages:t}))}e.register(I.PLATFORM,()=>l??F(typeof navigator<`u`?navigator.userAgent:void 0)),e.register(I.FETCH,()=>r);let p=t.safeFetch??{};e.register(I.SAFE_FETCH,()=>y(r,p))}function R(e){return`container`in e?e.container:e}function De(e){return{key:e,set(t,n){R(t).register(e,()=>n)},get(t){let n=R(t);return n.has(e)?n.resolve(e):void 0},clear(t){return R(t).unregister(e)}}}function z(e){return{"~standard":{version:1,vendor:`finesoft`,validate:e}}}async function B(e,t){let n=await e[`~standard`].validate(t);return n.issues?{ok:!1,issues:n.issues}:{ok:!0,value:n.value}}function V(e){return Object.assign(Object.create(null),e)}var H=class{routes=[];constructor(e){this.debug=e}add(e,t,n){let r=typeof n==`string`?{renderMode:n}:n??{},i=[],a=e.split(/(\/:[\w]+\??)/).map(t=>{let n=t.match(/^\/:(\w+)(\?)?$/);if(n){if(i.includes(n[1]))throw Error(`[Router] Duplicate parameter name ":${n[1]}" in pattern "${e}"`);return i.push(n[1]),n[2]?`(?:/([^/]+))?`:`/([^/]+)`}return t.replace(/[.+?^${}()|[\]\\]/g,`\\$&`)}).join(``);return this.routes.push({pattern:e,intentId:t,regex:RegExp(`^${a}/?$`),paramNames:i,renderMode:r.renderMode,beforeGuards:r.beforeGuards,afterGuards:r.afterGuards,paramCodecs:r.paramCodecs,queryCodecs:r.queryCodecs}),this}async resolve(e){let{path:t,queryParams:n}=this.parseUrl(e);for(let r of this.routes){let a=t.match(r.regex);if(!a)continue;let o=V(),s=!0;for(let e=0;e<r.paramNames.length;e++){let t=r.paramNames[e],n=a[e+1],i=r.paramCodecs?.[t];if(i){let e=await B(i,n);if(!e.ok){this.debug?.(`[Router] route "${r.pattern}" skipped: path param "${t}" failed validation: ${e.issues[0]?.message??`invalid`}`),s=!1;break}e.value!==void 0&&(o[t]=e.value)}else n&&(o[t]=n)}if(s){if(r.queryCodecs)for(let e of Object.keys(r.queryCodecs)){let t=await B(r.queryCodecs[e],n[e]);if(!t.ok){this.debug?.(`[Router] route "${r.pattern}" skipped: query param "${e}" failed validation: ${t.issues[0]?.message??`invalid`}`),s=!1;break}t.value!==void 0&&(o[e]=t.value)}if(s){for(let e of Object.keys(n))!(e in o)&&!r.queryCodecs?.[e]&&(o[e]=n[e]);return{intent:{id:r.intentId,params:o},action:i(e),renderMode:r.renderMode,beforeGuards:r.beforeGuards,afterGuards:r.afterGuards}}}}return null}getRoutes(){return this.routes.map(e=>`${e.pattern} → ${e.intentId}`)}parseUrl(e){try{let t=new URL(e,`http://localhost`),n=V(Object.fromEntries(t.searchParams));return{path:t.pathname,queryParams:n}}catch{return{path:e.split(`?`)[0].split(`#`)[0],queryParams:V()}}}};const U=e=>({issues:[{message:e}]});function Oe(e={}){return z(t=>typeof t==`string`?e.minLength!==void 0&&t.length<e.minLength?U(`must be at least ${e.minLength} characters`):e.maxLength!==void 0&&t.length>e.maxLength?U(`must be at most ${e.maxLength} characters`):e.pattern&&!e.pattern.test(t)?U(`must match ${e.pattern}`):{value:t}:U(`expected a string`))}function ke(e,t){return t.min!==void 0&&e<t.min?U(`must be >= ${t.min}`):t.max!==void 0&&e>t.max?U(`must be <= ${t.max}`):null}function Ae(e={}){return z(t=>{if(typeof t!=`string`||!/^-?\d+$/.test(t))return U(`"${String(t)}" is not an integer`);let n=Number(t);return ke(n,e)??{value:n}})}function je(e={}){return z(t=>{if(typeof t!=`string`||!/^-?\d+(\.\d+)?$/.test(t))return U(`"${String(t)}" is not a number`);let n=Number(t);return ke(n,e)??{value:n}})}const Me=new Set([`true`,`1`]),Ne=new Set([`false`,`0`]);function Pe(){return z(e=>typeof e==`string`&&Me.has(e)?{value:!0}:typeof e==`string`&&Ne.has(e)?{value:!1}:U(`"${String(e)}" is not a boolean (true/false/1/0)`))}function Fe(e){return z(t=>typeof t==`string`&&e.includes(t)?{value:t}:U(`"${String(t)}" is not one of: ${e.join(`, `)}`))}const Ie=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function Le(){return z(e=>typeof e==`string`&&Ie.test(e)?{value:e}:U(`"${String(e)}" is not a valid UUID`))}function Re(e){return z(t=>t===void 0?{value:void 0}:e[`~standard`].validate(t))}function ze(e,t){return z(n=>n===void 0?{value:t}:e[`~standard`].validate(n))}async function Be(e,t){for(let n of e){let e=await n(t);if(e.kind!==`next`)return e}return{kind:`next`}}async function Ve(e,t){for(let n of e){let e=await n(t);if(e.kind!==`next`)return e}return{kind:`next`}}const He=new WeakMap;function W(e){return G(e,new Set,0)}function G(e,t,n){if(e==null)return String(e);if(typeof e!=`object`)return JSON.stringify(e);let r=He.get(e);if(r!==void 0)return r;if(n>50)return`"[Max Depth]"`;if(t.has(e))return`"[Circular]"`;t.add(e);try{let r;if(Array.isArray(e))r=`[`+e.map(e=>G(e,t,n+1)).join(`,`)+`]`;else{let i=Object.keys(e).sort(),a=[];for(let r of i){let i=e[r];i!==void 0&&a.push(JSON.stringify(r)+`:`+G(i,t,n+1))}r=`{`+a.join(`,`)+`}`}return He.set(e,r),r}finally{t.delete(e)}}var K=class e{intents;constructor(e){this.intents=e}static fromArray(t){let n=new Map;for(let e of t)if(e.intent&&e.data!==void 0){let t=W(e.intent);n.set(t,e.data)}return new e(n)}static empty(){return new e(new Map)}get(e){let t=W(e),n=this.intents.get(t);if(n!==void 0)return this.intents.delete(t),n}has(e){return this.intents.has(W(e))}get size(){return this.intents.size}},Ue=class e{container;intentDispatcher;actionDispatcher;router;prefetchedIntents;beforeGuards=[];afterGuards=[];_logger;constructor(e,t){this.container=e,this.intentDispatcher=new s,this.actionDispatcher=new o,this.router=new H(e=>this.getLogger().debug(e)),this.prefetchedIntents=t}static create(t={}){let n=new c;L(n,t);let r=new e(n,t.prefetchedIntents??K.empty());return t.setupRoutes?.(r.router),r}getLogger(){return this._logger??=this.container.resolve(I.LOGGER)}async dispatch(e){let t=this.getLogger(),n=this.prefetchedIntents.get(e);return n===void 0?(t.debug(`[Framework] dispatch intent: ${e.id}`,e.params),this.intentDispatcher.dispatch(e,this.container)):(t.debug(`[Framework] re-using prefetched intent response for: ${e.id}`,e.params),n)}async perform(e){return this.getLogger().debug(`[Framework] perform action: ${e.kind}`),this.actionDispatcher.perform(e)}async routeUrl(e){return this.router.resolve(e)}didEnterPage(e){this.container.resolve(I.METRICS).recordPageView(e.pageType,{pageId:e.id,title:e.title})}getLocale(){return this.container.has(I.LOCALE)?this.container.resolve(I.LOCALE):void 0}getTranslator(){return this.container.has(I.TRANSLATOR)?this.container.resolve(I.TRANSLATOR):void 0}getPlatform(){return this.container.resolve(I.PLATFORM)}onAction(e,t){this.actionDispatcher.onAction(e,t)}registerIntent(e){this.intentDispatcher.register(e)}beforeLoad(e){this.beforeGuards.push(e)}afterLoad(e){this.afterGuards.push(e)}runBeforeLoad(e,t){return Be(t?.length?[...this.beforeGuards,...t]:this.beforeGuards,e)}runAfterLoad(e,t){return Ve(t?.length?[...this.afterGuards,...t]:this.afterGuards,e)}dispose(){this.container.dispose()}};const q=Symbol.for(`finesoft.publicFields`),We=[`id`,`pageType`,`title`,`description`,`url`];function Ge(e,t){return t===!0?(Object.defineProperty(e,q,{value:!0,enumerable:!1,configurable:!0,writable:!1}),e):(Object.defineProperty(e,q,{value:Object.freeze([...t]),enumerable:!1,configurable:!0,writable:!1}),e)}function Ke(e){return typeof e==`object`&&!!e&&e[q]!==void 0}function qe(e){if(typeof e!=`object`||!e)return null;let t=e[q];return t===void 0?null:t===!0?!0:Array.isArray(t)?t:null}function Je(){try{let e=globalThis.process?.env?.NODE_ENV;return e===void 0?!0:e===`production`}catch{return!0}}function Ye(e){if(e instanceof Error)return e.stack??`${e.name}: ${e.message}`;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function Xe(e){let{status:t,publicMessage:n,devError:r,isProduction:i=Je()}=e,a=!i&&r!==void 0;return{id:`error`,pageType:`error`,title:`Error ${t}`,description:a?`${n}\n\n[dev only]\n${Ye(r)}`:n}}var Ze=class{fallback(e,t){throw t}async perform(e,t){let n=e.params??{};try{return await this.execute(n,t)}catch(e){return this.fallback(n,e instanceof Error?e:Error(String(e)))}}};function Qe(...e){return t=>e.reduce((e,t)=>t(e),t)}function $e(...e){return async t=>{let n=t;for(let t of e)n=await t(n);return n}}function et(e){return t=>t.map(e)}function tt(e,t){return{path:e,...t}}function nt(e,t,n){let r=new Set;for(let i of t){i.controller&&!r.has(i.intentId)&&(e.registerIntent(i.controller),r.add(i.intentId));let t={renderMode:i.renderMode,beforeGuards:i.beforeLoad,afterGuards:i.afterLoad,paramCodecs:i.params,queryCodecs:i.query};if(e.router.add(i.path,i.intentId,t),n?.locales?.length){let n=i.path===`/`?`/:locale`:`/:locale${i.path}`;e.router.add(n,i.intentId,t)}}}var rt=class{map=new Map;capacity;constructor(e){if(e<1)throw Error(`[LruMap] capacity must be >= 1, got ${e}`);this.capacity=e}get(e){if(!this.map.has(e))return;let t=this.map.get(e);return this.map.delete(e),this.map.set(e,t),t}set(e,t){if(this.map.has(e))this.map.delete(e);else if(this.map.size>=this.capacity){let e=this.map.keys().next().value;e!==void 0&&this.map.delete(e)}this.map.set(e,t)}has(e){return this.map.has(e)}delete(e){return this.map.delete(e)}get size(){return this.map.size}clear(){this.map.clear()}};function it(e){return e!=null}function at(e){return e==null}function ot(){return typeof window>`u`?`browser`:document.referrer.startsWith(`android-app://`)?`twa`:window.matchMedia(`(display-mode: standalone)`).matches||`standalone`in window.navigator&&window.navigator.standalone===!0?`standalone`:`browser`}function st(e){return e.replace(/^https?:\/\//,``)}function ct(e){try{let t=new URL(e);return t.pathname+t.search+t.hash}catch{return e}}function lt(e){return e.split(`?`)[0]}function ut(e){return e.split(`?`)[0].split(`#`)[0]}function dt(e,t){if(!t)return e;let n=new URLSearchParams;for(let[e,r]of Object.entries(t))r!==void 0&&n.set(e,r);let r=n.toString();return r?`${e}?${r}`:e}function J(){return typeof crypto<`u`&&crypto.randomUUID?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)})}function ft(e){let t=new Map;if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim(),i=n.slice(e+1).trim();r&&t.set(r,i)}return t}function pt(e){let{url:t,intent:n,container:r,request:i}=e,a=new URL(t,`http://localhost`),o=ft(i?.headers.get(`cookie`)??``);return{url:t,path:a.pathname,params:n.params??{},intent:n,isServer:!0,container:r,getCookie:e=>o.get(e),getHeader:e=>i?.headers.get(e)??void 0}}function Y(e){let{url:t,intent:n,container:r}=e;return{url:t,path:new URL(t,window.location.origin).pathname,params:n.params??{},intent:n,isServer:!1,container:r,getCookie:e=>ft(document.cookie).get(e),getHeader:()=>void 0}}function mt(){return{kind:`next`}}function ht(e,t=302){return{kind:`redirect`,url:e,status:t}}function gt(e){return{kind:`rewrite`,url:e}}function _t(e=403,t=`Forbidden`){return{kind:`deny`,status:e,message:t}}var vt=class{recorders;constructor(e){this.recorders=e}record(e,t){for(let n of this.recorders)n.record(e,t)}async flush(){let e=[];for(let t of this.recorders)t.flush&&e.push(t.flush());await Promise.all(e)}destroy(){for(let e of this.recorders)e.destroy?.()}},yt=class{observer;tracked=new Map;captured=[];minDuration;constructor(e={}){this.minDuration=e.minVisibleDuration??1e3,this.observer=new IntersectionObserver(e=>{let t=Date.now();for(let n of e){let e=this.tracked.get(n.target);e&&(n.isIntersecting?e.visibleSince===null&&(e.visibleSince=t):e.visibleSince!==null&&(t-e.visibleSince>=this.minDuration&&this.captured.push({id:e.id,timestamp:e.visibleSince,metadata:e.metadata}),e.visibleSince=null))}},{threshold:e.threshold??.5})}observe(e,t,n){this.tracked.set(e,{id:t,metadata:n,visibleSince:null}),this.observer.observe(e)}unobserve(e){this.observer.unobserve(e),this.tracked.delete(e)}consume(){let e=Date.now();for(let[,t]of this.tracked)t.visibleSince!==null&&e-t.visibleSince>=this.minDuration&&(this.captured.push({id:t.id,timestamp:t.visibleSince,metadata:t.metadata}),t.visibleSince=e);return this.captured.splice(0)}destroy(){this.observer.disconnect(),this.tracked.clear(),this.captured.length=0}},bt=class{record(){}async flush(){}destroy(){}},xt=class{constructor(e,t){this.inner=e,this.providers=t}record(e,t){let n={};for(let e of this.providers)Object.assign(n,e.getFields());t&&Object.assign(n,t),this.inner.record(e,n)}async flush(){return this.inner.flush?.()}destroy(){this.inner.destroy?.()}};function St(t){let{framework:n,log:r}=t;n.onAction(e.EXTERNAL_URL,e=>{r.debug(`ExternalUrlAction → ${e.url}`),window.open(e.url,`_blank`,`noopener,noreferrer`)})}const X=5e3;let Z=null;function Q(){Z?.()}function Ct(e,t,n){Q();let r=Math.max(0,n),i=Date.now(),a=!1,o=null,s=null,c=null,l=null;Z=p,f(),document.addEventListener(`load`,u,!0),s=setInterval(u,100),c=setTimeout(u,X),u();function u(){a||o!==null||(o=requestAnimationFrame(()=>{o=null,d()}))}function d(){if(a)return;let n=Date.now()-i,o=t();if(!o){n>=X&&(e.warn(`tryScroll: timed out waiting for the scrollable element`,{target:r,elapsedMs:n}),p());return}o.scrollTop=r;let s=o.scrollTop;if(s>=r-2){e.info(`scroll restored`,{target:r,actual:s,elapsedMs:n}),p();return}n>=X&&(e.warn(`tryScroll: timed out before reaching the target`,{target:r,actual:s,elapsedMs:n,scrollHeight:o.scrollHeight,clientHeight:o.clientHeight}),p())}function f(){if(typeof MutationObserver>`u`)return;let e=document.body??document.documentElement;e&&(l=new MutationObserver(()=>{u()}),l.observe(e,{childList:!0,subtree:!0}))}function p(){a||(a=!0,Z===p&&(Z=null),o!==null&&(cancelAnimationFrame(o),o=null),s!==null&&(clearInterval(s),s=null),c!==null&&(clearTimeout(c),c=null),l?.disconnect(),l=null,document.removeEventListener(`load`,u,!0))}}var wt=class{entries;log;getScrollablePageElement;currentStateId;constructor(e,t,n=10){this.entries=new rt(n),this.log=e,this.getScrollablePageElement=t.getScrollablePageElement}replaceState(e,t){Q();let n=J();window.history.replaceState({id:n},``,t),this.currentStateId=n,this.entries.set(n,{state:e,scrollY:0}),this.scrollTop=0,this.log.info(`replaceState`,e,t,n)}pushState(e,t){Q();let n=J();window.history.pushState({id:n},``,t),this.currentStateId=n,this.entries.set(n,{state:e,scrollY:0}),this.scrollTop=0,this.log.info(`pushState`,e,t,n)}beforeTransition(){Q();let{state:e}=window.history;if(!e)return;let t=this.entries.get(e.id);if(!t){this.log.info(`current history state evicted from LRU, not saving scroll position`);return}let{scrollTop:n}=this;this.entries.set(e.id,{...t,scrollY:n}),this.log.info(`saving scroll position`,n)}onPopState(e){window.addEventListener(`popstate`,t=>{Q(),this.currentStateId=t.state?.id,this.currentStateId||this.log.warn(`encountered a null event.state.id in onPopState event:`,window.location.href),this.log.info(`popstate`,this.entries,this.currentStateId);let n=this.currentStateId?this.entries.get(this.currentStateId):void 0;if(Promise.resolve(e(window.location.href,n?.state)).catch(e=>{this.log.error(`onPopState listener error:`,e)}),!n)return;let{scrollY:r}=n;this.log.info(`restoring scroll to`,r),Ct(this.log,()=>this.getScrollablePageElement(),r)})}pushUrl(e){Q();let t=J();window.history.pushState({id:t},``,e),this.currentStateId=t,this.scrollTop=0,this.log.info(`pushUrl (no state)`,e,t)}replaceUrl(e){Q();let t=J();window.history.replaceState({id:t},``,e),this.currentStateId=t,this.scrollTop=0,this.log.info(`replaceUrl (no state)`,e,t)}updateState(e){if(!this.currentStateId){this.log.warn(`failed: encountered a null currentStateId inside updateState`);return}let t=this.entries.get(this.currentStateId),n=e(t?.state);this.log.info(`updateState`,n,this.currentStateId),this.entries.set(this.currentStateId,{scrollY:t?.scrollY??0,state:n})}get scrollTop(){return this.getScrollablePageElement()?.scrollTop||0}set scrollTop(e){let t=this.getScrollablePageElement();t&&(t.scrollTop=e)}};function Tt(t){let{framework:n,log:r,callbacks:i,updateApp:a}=t,o=!0,s=0,c=new wt(r,{getScrollablePageElement:t.getScrollablePageElement??(()=>document.getElementById(`scrollable-page-override`)||document.getElementById(`scrollable-page`)||document.documentElement)});async function l(e,t,d){if(t>=5){r.error(`Navigation redirect loop detected (5 redirects), stopping at: ${e}`);return}let f=o||e===window.location.pathname+window.location.search,p=await n.routeUrl(e);if(!p){r.warn(`FlowAction: no route for ${e}`);return}let m=Y({url:e,intent:p.intent,container:n.container}),h=await n.runBeforeLoad(m,p.beforeGuards);if(h.kind===`redirect`){r.debug(`beforeLoad → redirect to ${h.url}`),await l(h.url,t+1,d);return}if(h.kind===`deny`){r.warn(`beforeLoad → denied (${h.status}): ${h.message}`);return}if(h.kind===`rewrite`){r.debug(`beforeLoad → rewrite to ${h.url}`),await l(h.url,t+1,d);return}let g=n.dispatch(p.intent);if(await Promise.race([g,new Promise(e=>setTimeout(e,500))]).catch(()=>{}),d!==s){r.info(`FlowAction superseded by newer navigation`,e);return}c.beforeTransition(),a({page:g.then(async a=>{if(d!==s)return r.info(`FlowAction commit superseded`,e),a;let o={...m,page:a},h=await n.runAfterLoad(o,p.afterGuards);if(h.kind===`redirect`)return r.debug(`afterLoad → redirect to ${h.url}`),l(h.url,t+1,d),a;let g=e;return h.kind===`rewrite`&&(g=h.url,r.debug(`afterLoad → rewrite URL to ${g}`)),h.kind===`deny`?(r.warn(`afterLoad → denied (${h.status})`),a):(f?c.replaceState({page:a},g):c.pushState({page:a},g),i.onNavigate(new URL(g,window.location.origin).pathname),u(a),a)},t=>{if(d===s){let t=e;f?c.replaceUrl(t):c.pushUrl(t),i.onNavigate(new URL(t,window.location.origin).pathname)}throw t}),isFirstPage:o}),o=!1}n.onAction(e.FLOW,async e=>{let t=e,a=t.url;if(r.debug(`FlowAction → ${a}`),t.presentationContext===`modal`){let e=await n.routeUrl(a);if(e){let t=await n.dispatch(e.intent);i.onModal(t)}return}await l(a,0,++s)}),c.onPopState(async(e,t)=>{if(r.debug(`popstate → ${e}, cached=${!!t}`),i.onNavigate(new URL(e).pathname),t){let{page:e}=t;u(e),a({page:e,isFirstPage:o});return}let c=new URL(e),d=await n.routeUrl(c.pathname+c.search);if(!d){r.error(`received popstate without data, but URL was unroutable:`,e),u(null),a({page:Promise.reject(Error(`404`)),isFirstPage:o});return}let f=Y({url:c.pathname+c.search,intent:d.intent,container:n.container}),p=await n.runBeforeLoad(f,d.beforeGuards);if(p.kind===`redirect`){r.debug(`popstate beforeLoad → redirect to ${p.url}`);let e=++s;await l(p.url,0,e);return}if(p.kind===`deny`||p.kind===`rewrite`){if(p.kind===`deny`)r.warn(`popstate beforeLoad → denied`);else{let e=++s;await l(p.url,0,e)}return}let m=n.dispatch(d.intent);await Promise.race([m,new Promise(e=>setTimeout(e,500))]).catch(()=>{}),a({page:m.then(async e=>{let t={...f,page:e},a=await n.runAfterLoad(t,d.afterGuards);if(a.kind===`redirect`){r.debug(`popstate afterLoad → redirect to ${a.url}`);let t=++s;return l(a.url,0,t),e}if(a.kind===`rewrite`){r.debug(`popstate afterLoad → rewrite URL to ${a.url}`);let t=window.history.state?.id;return window.history.replaceState({id:t},``,a.url),i.onNavigate(new URL(a.url,window.location.origin).pathname),u(e),e}return a.kind===`deny`?(r.warn(`popstate afterLoad → denied (${a.status})`),e):(u(e),e)}),isFirstPage:o})});function u(e){(async()=>{try{e&&n.didEnterPage(e)}catch(e){r.error(`didEnterPage error:`,e)}})()}}function $(e){let{framework:t,log:n,callbacks:r,updateApp:i}=e;Tt({framework:t,log:n,callbacks:r,updateApp:i,getScrollablePageElement:e.getScrollablePageElement}),St({framework:t,log:n})}function Et(){let e=document.getElementById(`serialized-server-data`);if(e?.textContent){e.parentNode?.removeChild(e);try{return JSON.parse(e.textContent)}catch{return}}}function Dt(){let e=Et();return!e||!Array.isArray(e)?K.empty():K.fromArray(e)}async function Ot(e){let{bootstrap:t,mountId:n=`app`,mount:r,callbacks:i,onBeforeStart:a,onAfterStart:o,frameworkConfig:s={},loadMessages:c}=e,l=Dt(),u=window.location.pathname+window.location.search,d=kt(s.locale),f=await pe({locale:d,loadMessages:c,context:d?{runtime:`browser`,fetch:At(s.fetch),url:u}:void 0}),p=Ue.create({...s,locale:d,_resolvedMessages:f,prefetchedIntents:l});t(p);let m=p.container.resolve(I.LOGGER_FACTORY).loggerFor(`browser`),h=p.getLocale();h&&(le(h),m.debug(`[startBrowserApp] Applied locale attributes:`,h)),await a?.(p);let g=await p.routeUrl(u),_=document.getElementById(n);if(!_)throw Error(`[startBrowserApp] Mount target not found: #${n}. Ensure your HTML has <div id="${n}"></div>.`);let v=r(_,{framework:p});$({framework:p,log:m,callbacks:i,updateApp:v,getScrollablePageElement:e.getScrollablePageElement}),g?await p.perform(g.action):v({page:Promise.reject(Error(`404`)),isFirstPage:!0}),await o?.(p)}function kt(e){return e||document.documentElement.lang.trim()||void 0}function At(e){return(e??globalThis.fetch?.bind(globalThis))||(()=>{throw Error(`[startBrowserApp] loadMessages requires a fetch implementation.`)})}export{Le as $,tt as A,_ as At,Ge as B,n as Bt,lt as C,se as Ct,it as D,ue as Dt,at as E,ce as Et,Xe as F,c as Ft,Be as G,K as H,a as Ht,We as I,s as It,Pe as J,Re as K,q as L,o as Lt,Qe as M,g as Mt,$e as N,l as Nt,rt as O,le as Ot,Ze as P,u as Pt,Oe as Q,qe as R,e as Rt,ct as S,me as St,ot as T,b as Tt,W as U,i as Ut,Ue as V,t as Vt,Ve as W,je as X,Ae as Y,Fe as Z,Y as _,ve as _t,Tt as a,L as at,dt as b,_e as bt,St as c,M as ct,yt as d,A as dt,H as et,vt as f,be as ft,gt as g,S as gt,ht as h,C as ht,$ as i,I as it,et as j,v as jt,nt as k,y as kt,xt as l,N as lt,mt as m,w as mt,Dt as n,B as nt,wt as o,F as ot,_t as p,O as pt,ze as q,Et as r,De as rt,Ct as s,P as st,Ot as t,z as tt,bt as u,k as ut,pt as v,ge as vt,st as w,x as wt,ut as x,pe as xt,J as y,he as yt,Ke as z,r as zt};
|
|
2
|
+
//# sourceMappingURL=start-app-S4DH-40i.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finesoft/front",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Full-stack framework: router, DI, actions, SSR, and server — all in one package",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"dist/browser.mjs",
|
|
9
9
|
"dist/index.d.mts",
|
|
10
10
|
"dist/index.mjs",
|
|
11
|
-
"dist/server-data-
|
|
12
|
-
"dist/start-app-
|
|
11
|
+
"dist/server-data-DQzknR97.d.mts",
|
|
12
|
+
"dist/start-app-S4DH-40i.mjs",
|
|
13
13
|
"docs",
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e={FLOW:`flow`,EXTERNAL_URL:`externalUrl`,COMPOUND:`compound`};function t(t){return t.kind===e.FLOW}function n(t){return t.kind===e.EXTERNAL_URL}function r(t){return t.kind===e.COMPOUND}function i(t,n){return{kind:e.FLOW,url:t,presentationContext:n}}function a(t){return{kind:e.EXTERNAL_URL,url:t}}var o=class{handlers=new Map;onAction(e,t){if(this.handlers.has(e)){console.warn(`[ActionDispatcher] kind="${e}" already registered, skipping`);return}this.handlers.set(e,t)}removeAction(e){return this.handlers.delete(e)}async perform(e,t=0){if(r(e)){if(t>=32)throw Error(`[ActionDispatcher] CompoundAction recursion depth exceeded (max 32)`);for(let n of e.actions)await this.perform(n,t+1);return}let n=this.handlers.get(e.kind);if(!n){console.warn(`[ActionDispatcher] No handler for kind="${e.kind}"`);return}await n(e)}},s=class{controllers=new Map;register(e){this.controllers.set(e.intentId,e)}async dispatch(e,t){let n=this.controllers.get(e.id);if(!n)throw Error(`[IntentDispatcher] No controller for "${e.id}". Registered: [${Array.from(this.controllers.keys()).join(`, `)}]`);return n.perform(e,t)}has(e){return this.controllers.has(e)}},c=class e{registrations=new Map;resolutionStack=new Set;parent;children=new Set;register(e,t,n=!0){return this.registrations.set(e,{factory:t,singleton:n}),this}resolve(e){let t=this.registrations.get(e);if(!t){if(this.parent)return this.parent.resolve(e);throw Error(`[Container] No registration for key: "${e}"`)}if(t.singleton){if(t.instance===void 0){if(this.resolutionStack.has(e))throw Error(`[Container] Circular dependency detected: ${[...this.resolutionStack,e].join(` → `)}`);this.resolutionStack.add(e);try{t.instance=t.factory()}finally{this.resolutionStack.delete(e)}}return t.instance}return t.factory()}has(e){return this.registrations.has(e)||(this.parent?.has(e)??!1)}createScope(){let t=new e;return t.parent=this,this.children.add(t),t}dispose(){let e=Array.from(this.children);for(let t of e)t.dispose();this.children.clear();for(let e of this.registrations.values())e.instance=void 0;this.registrations.clear(),this.parent&&=(this.parent.children.delete(this),void 0)}};const l=new Set([`ar`,`arc`,`dv`,`fa`,`ha`,`he`,`khw`,`ks`,`ku`,`ps`,`ur`,`yi`]);function u(e){let t=e.split(`-`)[0].toLowerCase();return l.has(t)}function d(e){return u(e)?`rtl`:`ltr`}function f(e){return{lang:e,dir:d(e)}}function p(e,t){return{language:e,region:t,bcp47:t?`${e}-${t}`:e,dir:d(e)}}function m(e){document.documentElement.lang=e.lang,document.documentElement.dir=e.dir}function h(e,t){let n=e.split(`?`)[0].match(/^\/([^/]+)(\/.*)?$/);if(!n)return null;let r=n[1],i=t.find(e=>e.toLowerCase()===r.toLowerCase());return i?{locale:i,strippedUrl:n[2]||`/`}:null}async function g(e,t){if(!e||!t)return;let n=await _();if(n)return n(e,t)}async function _(){if(typeof globalThis.__FINESOFT_I18N_LOADER__==`function`)return globalThis.__FINESOFT_I18N_LOADER__;if(typeof __FINESOFT_I18N_LOADER_SPECIFIER__==`string`)try{let e=await import(__FINESOFT_I18N_LOADER_SPECIFIER__),t=typeof e==`function`?e:typeof e?.loadMessages==`function`?e.loadMessages:void 0;return t?(globalThis.__FINESOFT_I18N_LOADER__=t,t):void 0}catch{return}}async function v(e){let{locale:t,loadMessages:n,context:r}=e;if(!(!t||!r))return n?n(t,r):g(t,r)}function y(e,t){let n=Object.entries(e);if(n.length===0)return;if(typeof n[0][1]==`string`)return e;let r=e[t];if(!r)return;let i={};for(let[e,t]of Object.entries(r)){if(typeof t==`string`){i[e]=t;continue}for(let[n,r]of Object.entries(t))i[`${e}.${n}`]=r}return i}function b(e,t){return t?e.replace(/\{(\w+)\}/g,(e,n)=>{let r=t[n];return r===void 0?`{${n}}`:String(r)}):e}function x(e){return e===1?`one`:`other`}function S(e,t){return`${e}.${t}`}var C=class{locale;messages;pluralRule;fallback;constructor(e){this.locale=e.locale,this.messages=e.messages,this.pluralRule=e.pluralRule??x,this.fallback=e.fallback??(e=>e)}t(e,t){let n=this.messages[e];return n===void 0?this.fallback(e):b(n,t)}plural(e,t,n){let r=S(e,this.pluralRule(t)),i={count:t,...n};return this.t(r,i)}},w=class{constructor(e){this.factories=e}loggerFor(e){return new T(this.factories.map(t=>t.loggerFor(e)))}},T=class{constructor(e){this.loggers=e}debug(...e){return this.callAll(`debug`,e)}info(...e){return this.callAll(`info`,e)}warn(...e){return this.callAll(`warn`,e)}error(...e){return this.callAll(`error`,e)}callAll(e,t){for(let n of this.loggers)n[e](...t);return``}},E=class{category;constructor(e){this.category=e}};const ee={"*":4,debug:4,info:3,warn:2,error:1,off:0,"":0};let D,O;function te(){if(globalThis.localStorage===void 0)return{};let e;try{e=globalThis.localStorage.getItem(`onyxLog`)}catch{return{}}if(!e)return{};if(e===O&&D)return D;O=e;let t={},n=e.split(`,`);for(let e of n){let[n,r]=e.trim().split(`=`);if(!n||r===void 0)continue;let i=ee[r.toLowerCase()]??void 0;i!==void 0&&(n===`*`?t.defaultLevel=i:(t.named??={},t.named[n]=i))}return D=t,t}function k(e,t){let n=te();if(n.defaultLevel===void 0&&!n.named)return!0;let r=ee[t]??4;return n.named?.[e]===void 0?n.defaultLevel===void 0?!0:r<=n.defaultLevel:r<=n.named[e]}function ne(){D=void 0,O=void 0}var A=class extends E{debug(...e){return k(this.category,`debug`)&&console.debug(`[${this.category}]`,...e),``}info(...e){return k(this.category,`info`)&&console.info(`[${this.category}]`,...e),``}warn(...e){return k(this.category,`warn`)&&console.warn(`[${this.category}]`,...e),``}error(...e){return console.error(`[${this.category}]`,...e),``}},re=class{loggerFor(e){return new A(e)}};const j={debug:0,info:1,warn:2,error:3};var M=class extends E{minPriority;report;constructor(e,t){super(e),this.minPriority=j[t.minLevel??`warn`],this.report=t.report}debug(...e){return this.maybeReport(`debug`,e),``}info(...e){return this.maybeReport(`info`,e),``}warn(...e){return this.maybeReport(`warn`,e),``}error(...e){return this.maybeReport(`error`,e),``}maybeReport(e,t){if(!(j[e]<this.minPriority))try{this.report(e,this.category,t)}catch(e){console.error(`[ReportingLogger] report callback threw:`,e)}}},N=class{options;constructor(e){this.options=e}loggerFor(e){return new M(e,this.options)}},P=class{prefix;constructor(e=`Metrics`){this.prefix=e}record(e,t){console.info(`[${this.prefix}:${e}]`,t??``)}async flush(){}destroy(){}};function F(e){let t=e??(typeof navigator<`u`?navigator.userAgent:``),n=t.toLowerCase();return{os:ie(n),browser:ae(n),engine:oe(n),isMobile:/mobile|android|iphone|ipad|ipod/i.test(t),isTouch:typeof navigator<`u`&&`maxTouchPoints`in navigator?navigator.maxTouchPoints>0:!1}}function ie(e){return/iphone|ipad|ipod/.test(e)?`ios`:/android/.test(e)?`android`:/macintosh|mac os x/.test(e)?`macos`:/windows/.test(e)?`windows`:/linux/.test(e)?`linux`:`unknown`}function ae(e){return/edg\//.test(e)?`edge`:/opr\/|opera/.test(e)?`opera`:/samsungbrowser/.test(e)?`samsung`:/chrome|crios/.test(e)&&!/edg\//.test(e)?`chrome`:/firefox|fxios/.test(e)?`firefox`:/safari/.test(e)&&!/chrome/.test(e)?`safari`:`unknown`}function oe(e){return/applewebkit/.test(e)&&!/chrome/.test(e)?`webkit`:/applewebkit/.test(e)&&/chrome/.test(e)?`blink`:/gecko\//.test(e)?`gecko`:`unknown`}const I={LOGGER:`logger`,LOGGER_FACTORY:`loggerFactory`,NET:`net`,STORAGE:`storage`,FEATURE_FLAGS:`featureFlags`,METRICS:`metrics`,FETCH:`fetch`,EVENT_RECORDER:`eventRecorder`,LOCALE:`locale`,PLATFORM:`platform`,TRANSLATOR:`translator`};var se=class{store=new Map;get(e){return this.store.get(e)}set(e,t){this.store.set(e,t)}delete(e){this.store.delete(e)}},ce=class{flags;providers=[];constructor(e={}){this.flags=e}addProvider(e){this.providers.push(e)}isEnabled(e){for(let t=this.providers.length-1;t>=0;t--)if(this.providers[t].isEnabled(e))return!0;return this.flags[e]===!0}getString(e){for(let t=this.providers.length-1;t>=0;t--){let n=this.providers[t].getString?.(e);if(n!==void 0)return n}let t=this.flags[e];return typeof t==`string`?t:void 0}getNumber(e){for(let t=this.providers.length-1;t>=0;t--){let n=this.providers[t].getNumber?.(e);if(n!==void 0)return n}let t=this.flags[e];return typeof t==`number`?t:void 0}},le=class{record(e,t){console.info(`[Metrics:${e}]`,t??``)}recordPageView(e,t){this.record(`PageView`,{page:e,...t})}recordEvent(e,t){this.record(`Event`,{name:e,...t})}};function L(e,t={}){let{_resolvedMessages:n}=t,{fetch:r=globalThis.fetch?.bind(globalThis),featureFlags:i={},featureFlagsProviders:a=[],reportCallback:o,eventRecorder:s,locale:c,platform:l}=t,u=new re,d=o?new w([u,new N({report:o})]):u;e.register(I.LOGGER_FACTORY,()=>d),e.register(I.LOGGER,()=>d.loggerFor(`framework`)),e.register(I.NET,()=>({fetch:(e,t)=>r(e,t)})),e.register(I.STORAGE,()=>new se);let p=new ce(i);for(let e of a)p.addProvider(e);if(e.register(I.FEATURE_FLAGS,()=>p),e.register(I.METRICS,()=>new le),e.register(I.EVENT_RECORDER,()=>s??new P),c&&e.register(I.LOCALE,()=>f(c)),c&&n){let t=y(n,c);t&&e.register(I.TRANSLATOR,()=>new C({locale:c,messages:t}))}e.register(I.PLATFORM,()=>l??F(typeof navigator<`u`?navigator.userAgent:void 0)),e.register(I.FETCH,()=>r)}function R(e){return Object.assign(Object.create(null),e)}var z=class{routes=[];add(e,t,n){let r=typeof n==`string`?{renderMode:n}:n??{},i=[],a=e.split(/(\/:[\w]+\??)/).map(t=>{let n=t.match(/^\/:(\w+)(\?)?$/);if(n){if(i.includes(n[1]))throw Error(`[Router] Duplicate parameter name ":${n[1]}" in pattern "${e}"`);return i.push(n[1]),n[2]?`(?:/([^/]+))?`:`/([^/]+)`}return t.replace(/[.+?^${}()|[\]\\]/g,`\\$&`)}).join(``);return this.routes.push({pattern:e,intentId:t,regex:RegExp(`^${a}/?$`),paramNames:i,renderMode:r.renderMode,beforeGuards:r.beforeGuards,afterGuards:r.afterGuards}),this}resolve(e){let{path:t,queryParams:n}=this.parseUrl(e);for(let r of this.routes){let a=t.match(r.regex);if(a){let t=R(n);return r.paramNames.forEach((e,n)=>{let r=a[n+1];r&&(t[e]=r)}),{intent:{id:r.intentId,params:t},action:i(e),renderMode:r.renderMode,beforeGuards:r.beforeGuards,afterGuards:r.afterGuards}}}return null}getRoutes(){return this.routes.map(e=>`${e.pattern} → ${e.intentId}`)}parseUrl(e){try{let t=new URL(e,`http://localhost`),n=R(Object.fromEntries(t.searchParams));return{path:t.pathname,queryParams:n}}catch{return{path:e.split(`?`)[0].split(`#`)[0],queryParams:R()}}}};async function B(e,t){for(let n of e){let e=await n(t);if(e.kind!==`next`)return e}return{kind:`next`}}async function V(e,t){for(let n of e){let e=await n(t);if(e.kind!==`next`)return e}return{kind:`next`}}const H=new WeakMap;function U(e){return W(e,new Set,0)}function W(e,t,n){if(e==null)return String(e);if(typeof e!=`object`)return JSON.stringify(e);let r=H.get(e);if(r!==void 0)return r;if(n>50)return`"[Max Depth]"`;if(t.has(e))return`"[Circular]"`;t.add(e);try{let r;if(Array.isArray(e))r=`[`+e.map(e=>W(e,t,n+1)).join(`,`)+`]`;else{let i=Object.keys(e).sort(),a=[];for(let r of i){let i=e[r];i!==void 0&&a.push(JSON.stringify(r)+`:`+W(i,t,n+1))}r=`{`+a.join(`,`)+`}`}return H.set(e,r),r}finally{t.delete(e)}}var G=class e{intents;constructor(e){this.intents=e}static fromArray(t){let n=new Map;for(let e of t)if(e.intent&&e.data!==void 0){let t=U(e.intent);n.set(t,e.data)}return new e(n)}static empty(){return new e(new Map)}get(e){let t=U(e),n=this.intents.get(t);if(n!==void 0)return this.intents.delete(t),n}has(e){return this.intents.has(U(e))}get size(){return this.intents.size}},K=class e{container;intentDispatcher;actionDispatcher;router;prefetchedIntents;beforeGuards=[];afterGuards=[];_logger;constructor(e,t){this.container=e,this.intentDispatcher=new s,this.actionDispatcher=new o,this.router=new z,this.prefetchedIntents=t}static create(t={}){let n=new c;L(n,t);let r=new e(n,t.prefetchedIntents??G.empty());return t.setupRoutes?.(r.router),r}getLogger(){return this._logger??=this.container.resolve(I.LOGGER)}async dispatch(e){let t=this.getLogger(),n=this.prefetchedIntents.get(e);return n===void 0?(t.debug(`[Framework] dispatch intent: ${e.id}`,e.params),this.intentDispatcher.dispatch(e,this.container)):(t.debug(`[Framework] re-using prefetched intent response for: ${e.id}`,e.params),n)}async perform(e){return this.getLogger().debug(`[Framework] perform action: ${e.kind}`),this.actionDispatcher.perform(e)}routeUrl(e){return this.router.resolve(e)}didEnterPage(e){this.container.resolve(I.METRICS).recordPageView(e.pageType,{pageId:e.id,title:e.title})}getLocale(){return this.container.has(I.LOCALE)?this.container.resolve(I.LOCALE):void 0}getTranslator(){return this.container.has(I.TRANSLATOR)?this.container.resolve(I.TRANSLATOR):void 0}getPlatform(){return this.container.resolve(I.PLATFORM)}onAction(e,t){this.actionDispatcher.onAction(e,t)}registerIntent(e){this.intentDispatcher.register(e)}beforeLoad(e){this.beforeGuards.push(e)}afterLoad(e){this.afterGuards.push(e)}runBeforeLoad(e,t){return B(t?.length?[...this.beforeGuards,...t]:this.beforeGuards,e)}runAfterLoad(e,t){return V(t?.length?[...this.afterGuards,...t]:this.afterGuards,e)}dispose(){this.container.dispose()}},q=class extends Error{constructor(e,t,n){super(`HTTP ${e}: ${t}`),this.status=e,this.statusText=t,this.body=n,this.name=`HttpError`}},ue=class{baseUrl;defaultHeaders;fetchFn;requestInterceptors;responseInterceptors;constructor(e){this.baseUrl=e.baseUrl,this.defaultHeaders=e.defaultHeaders??{},this.fetchFn=e.fetch??globalThis.fetch.bind(globalThis),this.requestInterceptors=[...e.requestInterceptors??[]],this.responseInterceptors=[...e.responseInterceptors??[]]}useRequestInterceptor(e){return this.requestInterceptors.push(e),this}useResponseInterceptor(e){return this.responseInterceptors.push(e),this}async get(e,t){return this.request(`GET`,e,{params:t})}async post(e,t,n){return this.request(`POST`,e,{body:t,params:n})}async put(e,t,n){return this.request(`PUT`,e,{body:t,params:n})}async del(e,t){return this.request(`DELETE`,e,{params:t})}async request(e,t,n){let r=this.buildUrl(t,n?.params),i={...this.defaultHeaders,...n?.headers},a={method:e,headers:i};n?.body!==void 0&&(Object.keys(i).some(e=>e.toLowerCase()===`content-type`)||(i[`Content-Type`]=`application/json`),a.body=JSON.stringify(n.body));for(let e of this.requestInterceptors)a=await e(r,a);let o=await this.fetchFn(r,a);for(let e of this.responseInterceptors)o=await e(o,r);if(!o.ok){let e=await o.text().catch(()=>void 0);throw new q(o.status,o.statusText,e)}try{return await o.json()}catch(e){throw e instanceof SyntaxError?new q(o.status,`Invalid JSON response`,await o.text().catch(()=>void 0)):e}}buildUrl(e,t){let n=this.baseUrl.endsWith(`/`)?this.baseUrl.slice(0,-1):this.baseUrl,r=e.startsWith(`/`)?e:`/${e}`,i=new URL(`${n}${r}`,`http://placeholder`);if(t)for(let[e,n]of Object.entries(t))i.searchParams.set(e,n);return this.baseUrl.startsWith(`http`)?i.toString():`${i.pathname}${i.search}`}},de=class{fallback(e,t){throw t}async perform(e,t){let n=e.params??{};try{return await this.execute(n,t)}catch(e){return this.fallback(n,e instanceof Error?e:Error(String(e)))}}};function fe(...e){return t=>e.reduce((e,t)=>t(e),t)}function pe(...e){return async t=>{let n=t;for(let t of e)n=await t(n);return n}}function me(e){return t=>t.map(e)}function he(e,t,n){let r=new Set;for(let i of t){i.controller&&!r.has(i.intentId)&&(e.registerIntent(i.controller),r.add(i.intentId));let t={renderMode:i.renderMode,beforeGuards:i.beforeLoad,afterGuards:i.afterLoad};if(e.router.add(i.path,i.intentId,t),n?.locales?.length){let n=i.path===`/`?`/:locale`:`/:locale${i.path}`;e.router.add(n,i.intentId,t)}}}var ge=class{map=new Map;capacity;constructor(e){if(e<1)throw Error(`[LruMap] capacity must be >= 1, got ${e}`);this.capacity=e}get(e){if(!this.map.has(e))return;let t=this.map.get(e);return this.map.delete(e),this.map.set(e,t),t}set(e,t){if(this.map.has(e))this.map.delete(e);else if(this.map.size>=this.capacity){let e=this.map.keys().next().value;e!==void 0&&this.map.delete(e)}this.map.set(e,t)}has(e){return this.map.has(e)}delete(e){return this.map.delete(e)}get size(){return this.map.size}clear(){this.map.clear()}};function _e(e){return e!=null}function ve(e){return e==null}function ye(){return typeof window>`u`?`browser`:document.referrer.startsWith(`android-app://`)?`twa`:window.matchMedia(`(display-mode: standalone)`).matches||`standalone`in window.navigator&&window.navigator.standalone===!0?`standalone`:`browser`}function be(e){return e.replace(/^https?:\/\//,``)}function xe(e){try{let t=new URL(e);return t.pathname+t.search+t.hash}catch{return e}}function Se(e){return e.split(`?`)[0]}function Ce(e){return e.split(`?`)[0].split(`#`)[0]}function we(e,t){if(!t)return e;let n=new URLSearchParams;for(let[e,r]of Object.entries(t))r!==void 0&&n.set(e,r);let r=n.toString();return r?`${e}?${r}`:e}function J(){return typeof crypto<`u`&&crypto.randomUUID?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)})}function Y(e){let t=new Map;if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim(),i=n.slice(e+1).trim();r&&t.set(r,i)}return t}function Te(e){let{url:t,intent:n,container:r,request:i}=e,a=new URL(t,`http://localhost`),o=Y(i?.headers.get(`cookie`)??``);return{url:t,path:a.pathname,params:n.params??{},intent:n,isServer:!0,container:r,getCookie:e=>o.get(e),getHeader:e=>i?.headers.get(e)??void 0}}function X(e){let{url:t,intent:n,container:r}=e;return{url:t,path:new URL(t,window.location.origin).pathname,params:n.params??{},intent:n,isServer:!1,container:r,getCookie:e=>Y(document.cookie).get(e),getHeader:()=>void 0}}function Ee(){return{kind:`next`}}function De(e,t=302){return{kind:`redirect`,url:e,status:t}}function Oe(e){return{kind:`rewrite`,url:e}}function ke(e=403,t=`Forbidden`){return{kind:`deny`,status:e,message:t}}var Ae=class{recorders;constructor(e){this.recorders=e}record(e,t){for(let n of this.recorders)n.record(e,t)}async flush(){let e=[];for(let t of this.recorders)t.flush&&e.push(t.flush());await Promise.all(e)}destroy(){for(let e of this.recorders)e.destroy?.()}},je=class{observer;tracked=new Map;captured=[];minDuration;constructor(e={}){this.minDuration=e.minVisibleDuration??1e3,this.observer=new IntersectionObserver(e=>{let t=Date.now();for(let n of e){let e=this.tracked.get(n.target);e&&(n.isIntersecting?e.visibleSince===null&&(e.visibleSince=t):e.visibleSince!==null&&(t-e.visibleSince>=this.minDuration&&this.captured.push({id:e.id,timestamp:e.visibleSince,metadata:e.metadata}),e.visibleSince=null))}},{threshold:e.threshold??.5})}observe(e,t,n){this.tracked.set(e,{id:t,metadata:n,visibleSince:null}),this.observer.observe(e)}unobserve(e){this.observer.unobserve(e),this.tracked.delete(e)}consume(){let e=Date.now();for(let[,t]of this.tracked)t.visibleSince!==null&&e-t.visibleSince>=this.minDuration&&(this.captured.push({id:t.id,timestamp:t.visibleSince,metadata:t.metadata}),t.visibleSince=e);return this.captured.splice(0)}destroy(){this.observer.disconnect(),this.tracked.clear(),this.captured.length=0}},Me=class{record(){}async flush(){}destroy(){}},Ne=class{constructor(e,t){this.inner=e,this.providers=t}record(e,t){let n={};for(let e of this.providers)Object.assign(n,e.getFields());t&&Object.assign(n,t),this.inner.record(e,n)}async flush(){return this.inner.flush?.()}destroy(){this.inner.destroy?.()}};function Pe(t){let{framework:n,log:r}=t;n.onAction(e.EXTERNAL_URL,e=>{r.debug(`ExternalUrlAction → ${e.url}`),window.open(e.url,`_blank`,`noopener,noreferrer`)})}const Z=5e3;let Q=null;function $(){Q?.()}function Fe(e,t,n){$();let r=Math.max(0,n),i=Date.now(),a=!1,o=null,s=null,c=null,l=null;Q=p,f(),document.addEventListener(`load`,u,!0),s=setInterval(u,100),c=setTimeout(u,Z),u();function u(){a||o!==null||(o=requestAnimationFrame(()=>{o=null,d()}))}function d(){if(a)return;let n=Date.now()-i,o=t();if(!o){n>=Z&&(e.warn(`tryScroll: timed out waiting for the scrollable element`,{target:r,elapsedMs:n}),p());return}o.scrollTop=r;let s=o.scrollTop;if(s>=r-2){e.info(`scroll restored`,{target:r,actual:s,elapsedMs:n}),p();return}n>=Z&&(e.warn(`tryScroll: timed out before reaching the target`,{target:r,actual:s,elapsedMs:n,scrollHeight:o.scrollHeight,clientHeight:o.clientHeight}),p())}function f(){if(typeof MutationObserver>`u`)return;let e=document.body??document.documentElement;e&&(l=new MutationObserver(()=>{u()}),l.observe(e,{childList:!0,subtree:!0}))}function p(){a||(a=!0,Q===p&&(Q=null),o!==null&&(cancelAnimationFrame(o),o=null),s!==null&&(clearInterval(s),s=null),c!==null&&(clearTimeout(c),c=null),l?.disconnect(),l=null,document.removeEventListener(`load`,u,!0))}}var Ie=class{entries;log;getScrollablePageElement;currentStateId;constructor(e,t,n=10){this.entries=new ge(n),this.log=e,this.getScrollablePageElement=t.getScrollablePageElement}replaceState(e,t){$();let n=J();window.history.replaceState({id:n},``,t),this.currentStateId=n,this.entries.set(n,{state:e,scrollY:0}),this.scrollTop=0,this.log.info(`replaceState`,e,t,n)}pushState(e,t){$();let n=J();window.history.pushState({id:n},``,t),this.currentStateId=n,this.entries.set(n,{state:e,scrollY:0}),this.scrollTop=0,this.log.info(`pushState`,e,t,n)}beforeTransition(){$();let{state:e}=window.history;if(!e)return;let t=this.entries.get(e.id);if(!t){this.log.info(`current history state evicted from LRU, not saving scroll position`);return}let{scrollTop:n}=this;this.entries.set(e.id,{...t,scrollY:n}),this.log.info(`saving scroll position`,n)}onPopState(e){window.addEventListener(`popstate`,t=>{$(),this.currentStateId=t.state?.id,this.currentStateId||this.log.warn(`encountered a null event.state.id in onPopState event:`,window.location.href),this.log.info(`popstate`,this.entries,this.currentStateId);let n=this.currentStateId?this.entries.get(this.currentStateId):void 0;if(Promise.resolve(e(window.location.href,n?.state)).catch(e=>{this.log.error(`onPopState listener error:`,e)}),!n)return;let{scrollY:r}=n;this.log.info(`restoring scroll to`,r),Fe(this.log,()=>this.getScrollablePageElement(),r)})}pushUrl(e){$();let t=J();window.history.pushState({id:t},``,e),this.currentStateId=t,this.scrollTop=0,this.log.info(`pushUrl (no state)`,e,t)}replaceUrl(e){$();let t=J();window.history.replaceState({id:t},``,e),this.currentStateId=t,this.scrollTop=0,this.log.info(`replaceUrl (no state)`,e,t)}updateState(e){if(!this.currentStateId){this.log.warn(`failed: encountered a null currentStateId inside updateState`);return}let t=this.entries.get(this.currentStateId),n=e(t?.state);this.log.info(`updateState`,n,this.currentStateId),this.entries.set(this.currentStateId,{scrollY:t?.scrollY??0,state:n})}get scrollTop(){return this.getScrollablePageElement()?.scrollTop||0}set scrollTop(e){let t=this.getScrollablePageElement();t&&(t.scrollTop=e)}};function Le(t){let{framework:n,log:r,callbacks:i,updateApp:a}=t,o=!0,s=0,c=new Ie(r,{getScrollablePageElement:t.getScrollablePageElement??(()=>document.getElementById(`scrollable-page-override`)||document.getElementById(`scrollable-page`)||document.documentElement)});async function l(e,t,d){if(t>=5){r.error(`Navigation redirect loop detected (5 redirects), stopping at: ${e}`);return}let f=o||e===window.location.pathname+window.location.search,p=n.routeUrl(e);if(!p){r.warn(`FlowAction: no route for ${e}`);return}let m=X({url:e,intent:p.intent,container:n.container}),h=await n.runBeforeLoad(m,p.beforeGuards);if(h.kind===`redirect`){r.debug(`beforeLoad → redirect to ${h.url}`),await l(h.url,t+1,d);return}if(h.kind===`deny`){r.warn(`beforeLoad → denied (${h.status}): ${h.message}`);return}if(h.kind===`rewrite`){r.debug(`beforeLoad → rewrite to ${h.url}`),await l(h.url,t+1,d);return}let g=n.dispatch(p.intent);if(await Promise.race([g,new Promise(e=>setTimeout(e,500))]).catch(()=>{}),d!==s){r.info(`FlowAction superseded by newer navigation`,e);return}c.beforeTransition(),a({page:g.then(async a=>{if(d!==s)return r.info(`FlowAction commit superseded`,e),a;let o={...m,page:a},h=await n.runAfterLoad(o,p.afterGuards);if(h.kind===`redirect`)return r.debug(`afterLoad → redirect to ${h.url}`),l(h.url,t+1,d),a;let g=e;return h.kind===`rewrite`&&(g=h.url,r.debug(`afterLoad → rewrite URL to ${g}`)),h.kind===`deny`?(r.warn(`afterLoad → denied (${h.status})`),a):(f?c.replaceState({page:a},g):c.pushState({page:a},g),i.onNavigate(new URL(g,window.location.origin).pathname),u(a),a)},t=>{if(d===s){let t=e;f?c.replaceUrl(t):c.pushUrl(t),i.onNavigate(new URL(t,window.location.origin).pathname)}throw t}),isFirstPage:o}),o=!1}n.onAction(e.FLOW,async e=>{let t=e,a=t.url;if(r.debug(`FlowAction → ${a}`),t.presentationContext===`modal`){let e=n.routeUrl(a);if(e){let t=await n.dispatch(e.intent);i.onModal(t)}return}await l(a,0,++s)}),c.onPopState(async(e,t)=>{if(r.debug(`popstate → ${e}, cached=${!!t}`),i.onNavigate(new URL(e).pathname),t){let{page:e}=t;u(e),a({page:e,isFirstPage:o});return}let c=new URL(e),d=n.routeUrl(c.pathname+c.search);if(!d){r.error(`received popstate without data, but URL was unroutable:`,e),u(null),a({page:Promise.reject(Error(`404`)),isFirstPage:o});return}let f=X({url:c.pathname+c.search,intent:d.intent,container:n.container}),p=await n.runBeforeLoad(f,d.beforeGuards);if(p.kind===`redirect`){r.debug(`popstate beforeLoad → redirect to ${p.url}`);let e=++s;await l(p.url,0,e);return}if(p.kind===`deny`||p.kind===`rewrite`){if(p.kind===`deny`)r.warn(`popstate beforeLoad → denied`);else{let e=++s;await l(p.url,0,e)}return}let m=n.dispatch(d.intent);await Promise.race([m,new Promise(e=>setTimeout(e,500))]).catch(()=>{}),a({page:m.then(async e=>{let t={...f,page:e},a=await n.runAfterLoad(t,d.afterGuards);if(a.kind===`redirect`){r.debug(`popstate afterLoad → redirect to ${a.url}`);let t=++s;return l(a.url,0,t),e}if(a.kind===`rewrite`){r.debug(`popstate afterLoad → rewrite URL to ${a.url}`);let t=window.history.state?.id;return window.history.replaceState({id:t},``,a.url),i.onNavigate(new URL(a.url,window.location.origin).pathname),u(e),e}return a.kind===`deny`?(r.warn(`popstate afterLoad → denied (${a.status})`),e):(u(e),e)}),isFirstPage:o})});function u(e){(async()=>{try{e&&n.didEnterPage(e)}catch(e){r.error(`didEnterPage error:`,e)}})()}}function Re(e){let{framework:t,log:n,callbacks:r,updateApp:i}=e;Le({framework:t,log:n,callbacks:r,updateApp:i,getScrollablePageElement:e.getScrollablePageElement}),Pe({framework:t,log:n})}function ze(){let e=document.getElementById(`serialized-server-data`);if(e?.textContent){e.parentNode?.removeChild(e);try{return JSON.parse(e.textContent)}catch{return}}}function Be(){let e=ze();return!e||!Array.isArray(e)?G.empty():G.fromArray(e)}async function Ve(e){let{bootstrap:t,mountId:n=`app`,mount:r,callbacks:i,onBeforeStart:a,onAfterStart:o,frameworkConfig:s={},loadMessages:c}=e,l=Be(),u=window.location.pathname+window.location.search,d=He(s.locale),f=await v({locale:d,loadMessages:c,context:d?{runtime:`browser`,fetch:Ue(s.fetch),url:u}:void 0}),p=K.create({...s,locale:d,_resolvedMessages:f,prefetchedIntents:l});t(p);let h=p.container.resolve(I.LOGGER_FACTORY).loggerFor(`browser`),g=p.getLocale();g&&(m(g),h.debug(`[startBrowserApp] Applied locale attributes:`,g)),await a?.(p);let _=p.routeUrl(u),y=document.getElementById(n);if(!y)throw Error(`[startBrowserApp] Mount target not found: #${n}. Ensure your HTML has <div id="${n}"></div>.`);let b=r(y,{framework:p});Re({framework:p,log:h,callbacks:i,updateApp:b,getScrollablePageElement:e.getScrollablePageElement}),_?await p.perform(_.action):b({page:Promise.reject(Error(`404`)),isFirstPage:!0}),await o?.(p)}function He(e){return e||document.documentElement.lang.trim()||void 0}function Ue(e){return(e??globalThis.fetch?.bind(globalThis))||(()=>{throw Error(`[startBrowserApp] loadMessages requires a fetch implementation.`)})}export{T as $,me as A,B,Se as C,_e as D,ve as E,q as F,P as G,I as H,K as I,A as J,M as K,G as L,pe as M,de as N,ge as O,ue as P,E as Q,U as R,xe as S,ye as T,L as U,z as V,F as W,ne as X,re as Y,k as Z,X as _,r as _t,Le as a,v as at,we as b,a as bt,Pe as c,d as ct,je as d,h as dt,w as et,Ae as f,m as ft,Oe as g,e as gt,De as h,o as ht,Re as i,S as it,fe as j,he as k,Ne as l,u as lt,Ee as m,s as mt,Be as n,x as nt,Ie as o,y as ot,ke as p,c as pt,N as q,ze as r,b as rt,Fe as s,f as st,Ve as t,C as tt,Me as u,p as ut,Te as v,n as vt,be as w,Ce as x,i as xt,J as y,t as yt,V as z};
|
|
2
|
-
//# sourceMappingURL=start-app-BdXBCcor.mjs.map
|