@finesoft/front 0.1.75 → 0.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,421 +1,12 @@
1
1
  # @finesoft/front
2
2
 
3
- Full-stack TypeScript framework — router, DI, actions, SSR, and server — all in one package.
4
-
5
- Works with **Vue**, **React**, and **Svelte**. Deploy to Node.js, Vercel, Cloudflare Workers, Netlify, or static hosting.
6
-
7
- ## Install
3
+ Full-stack TypeScript framework — router, DI, actions, SSR, and server — all in one package. Works with **Vue**, **React**, or **Svelte**. Deploys to Node.js, Vercel, Cloudflare Workers, Netlify, or static hosting.
8
4
 
9
5
  ```bash
10
6
  npx @finesoft/create-app my-app
11
7
  ```
12
8
 
13
- Or add to an existing project:
14
-
15
- ```bash
16
- npm install @finesoft/front
17
- ```
18
-
19
- Peer dependencies: `hono >= 4.0.0`. Optional: `@hono/node-server`, `vite >= 5.0.0`.
20
-
21
- ## Setup
22
-
23
- ```ts
24
- // vite.config.ts
25
- import { finesoftFrontViteConfig } from "@finesoft/front";
26
- import vue from "@vitejs/plugin-vue";
27
- import { defineConfig } from "vite";
28
-
29
- export default defineConfig({
30
- plugins: [
31
- vue(),
32
- finesoftFrontViteConfig({
33
- ssr: { entry: "src/ssr.ts" },
34
- i18n: { messagesDir: "src/locales" },
35
- proxies: [{ prefix: "/api", target: "https://api.example.com" }],
36
- adapter: "auto",
37
- }),
38
- ],
39
- });
40
- ```
41
-
42
- ## Routing
43
-
44
- ```ts
45
- // src/bootstrap.ts
46
- import { type Framework, defineRoutes } from "@finesoft/front";
47
- import { HomeController } from "./lib/controllers/home";
48
- import { authGuard } from "./lib/guards/auth";
49
-
50
- export function bootstrap(framework: Framework): void {
51
- defineRoutes(framework, [
52
- { path: "/", intentId: "home", controller: new HomeController() },
53
- {
54
- path: "/about",
55
- intentId: "about",
56
- controller: new AboutController(),
57
- renderMode: "csr",
58
- },
59
- { path: "/admin", intentId: "home", beforeLoad: [authGuard] },
60
- ]);
61
- }
62
- ```
63
-
64
- ## Controllers
65
-
66
- ```ts
67
- import { BaseController, type Container } from "@finesoft/front";
68
-
69
- class HomeController extends BaseController<Record<string, string>, HomePage> {
70
- readonly intentId = "home";
71
-
72
- async execute(_params: Record<string, string>, container: Container) {
73
- const http = container.resolve<HttpClient>("http");
74
- return http.get("/api/home");
75
- }
76
- }
77
- ```
78
-
79
- ## Middleware
80
-
81
- Two-phase guards shared between SSR and CSR:
82
-
83
- ```ts
84
- import { next, redirect, type NavigationContext } from "@finesoft/front";
85
-
86
- function authGuard(ctx: NavigationContext) {
87
- return ctx.getCookie("token") ? next() : redirect("/login");
88
- }
89
- ```
90
-
91
- Results: `next()`, `redirect(url, status?)`, `rewrite(url)`, `deny(status?, message?)`.
92
-
93
- ## Lifecycle Hooks
94
-
95
- `startBrowserApp` provides hooks for initialization:
96
-
97
- ```ts
98
- import { startBrowserApp } from "@finesoft/front/browser";
99
-
100
- startBrowserApp({
101
- bootstrap,
102
- // Pass framework config so locale/reporting/etc. are wired into Framework
103
- frameworkConfig: {
104
- locale: "zh-Hans",
105
- },
106
- mount: (target, { framework }) => {
107
- /* ... */
108
- },
109
- callbacks: { onNavigate, onExternalUrl },
110
- onBeforeStart(framework) {
111
- // Runs after Framework creation, before mount.
112
- // Good for: error monitoring, analytics SDK, i18n init.
113
- },
114
- onAfterStart(framework) {
115
- // Runs after initial page trigger.
116
- // Good for: service worker registration, performance marks.
117
- },
118
- });
119
- ```
120
-
121
- ## Locale (i18n)
122
-
123
- Pass `locale` in `FrameworkConfig` to enable automatic locale handling:
124
-
125
- ```ts
126
- const framework = Framework.create({
127
- locale: "zh-Hans", // or "en-US", "ar-SA", etc.
128
- });
129
-
130
- // SSR: automatically injects <html lang="zh-Hans" dir="ltr">
131
- // Browser: automatically sets document.documentElement.lang/dir on startup
132
- ```
133
-
134
- For SSR, locale is resolved in this order:
135
-
136
- 1. Explicit `resolveLocale` callback (if provided)
137
- 2. `locale` from `FrameworkConfig` (via DI container)
138
-
139
- Access at runtime:
140
-
141
- ```ts
142
- const locale = framework.getLocale();
143
- // { lang: "zh-Hans", dir: "ltr" }
144
- ```
145
-
146
- ### Translator
147
-
148
- For synchronous in-memory i18n translation, use `SimpleTranslator`:
149
-
150
- ```ts
151
- import { SimpleTranslator } from "@finesoft/front";
152
-
153
- const t = new SimpleTranslator({
154
- locale: "zh-Hans",
155
- messages: {
156
- hello: "你好",
157
- "items.one": "{count} 个项目",
158
- "items.other": "{count} 个项目",
159
- },
160
- });
161
-
162
- t.t("hello"); // "你好"
163
- t.t("hello", { name: "World" }); // "你好"
164
- t.plural("items", 5); // "5 个项目"
165
- ```
166
-
167
- For locale dictionaries, prefer JSON files plus `finesoftFrontViteConfig()`. The framework
168
- will automatically load `${locale}.json` before SSR render and before browser hydration,
169
- without serializing the translations into HTML.
170
-
171
- ```ts
172
- // vite.config.ts
173
- import { finesoftFrontViteConfig } from "@finesoft/front";
174
- import { defineConfig } from "vite-plus";
175
-
176
- export default defineConfig({
177
- plugins: [
178
- finesoftFrontViteConfig({
179
- ssr: { entry: "src/ssr.ts" },
180
- i18n: {
181
- messagesDir: "src/locales",
182
- },
183
- }),
184
- ],
185
- });
186
-
187
- // src/locales/zh-Hans.json
188
- {
189
- "hello": "你好"
190
- }
191
-
192
- // src/locales/en-US.json
193
- {
194
- "hello": "Hello"
195
- }
196
- ```
197
-
198
- If you need a non-file source such as a CDN or API, `loadMessages` is still supported on
199
- `createSSRRender()` / `startBrowserApp()` and overrides the Vite-generated loader.
200
-
201
- ### RTL Support
202
-
203
- ```ts
204
- import { isRtl, getTextDirection, getLocaleAttributes } from "@finesoft/front";
205
-
206
- isRtl("ar"); // true
207
- getTextDirection("he"); // "rtl"
208
- getLocaleAttributes("ar-SA"); // { lang: "ar-SA", dir: "rtl" }
209
- ```
210
-
211
- ## Metrics & Event Recording
212
-
213
- ### EventRecorder (recommended)
214
-
215
- New pipeline for structured event recording. Default: `ConsoleEventRecorder` (logs to console).
216
-
217
- ```ts
218
- import { Framework, type EventRecorder } from "@finesoft/front";
219
-
220
- // Custom recorder
221
- const framework = Framework.create({
222
- eventRecorder: myAnalyticsRecorder,
223
- });
224
-
225
- // Framework automatically records PageView events via didEnterPage()
226
- ```
227
-
228
- Compose multiple recorders:
229
-
230
- ```ts
231
- import { CompositeEventRecorder, ConsoleEventRecorder } from "@finesoft/front";
232
-
233
- const recorder = new CompositeEventRecorder([new ConsoleEventRecorder(), myProductionRecorder]);
234
- ```
235
-
236
- Inject common fields into every event:
237
-
238
- ```ts
239
- import { WithFieldsRecorder } from "@finesoft/front";
240
-
241
- const recorder = new WithFieldsRecorder(baseRecorder, [
242
- { getFields: () => ({ app: "myApp", version: "1.0" }) },
243
- ]);
244
- ```
245
-
246
- ### Impression Tracking
247
-
248
- Track element visibility using `IntersectionObserver`:
249
-
250
- ```ts
251
- import { IntersectionImpressionObserver } from "@finesoft/front";
252
-
253
- const observer = new IntersectionImpressionObserver((entries) => {
254
- for (const entry of entries) {
255
- analytics.track("impression", { id: entry.id, ...entry.metadata });
256
- }
257
- });
258
-
259
- observer.observe(element, "product-card-123", { category: "featured" });
260
- // Later:
261
- observer.unobserve(element);
262
- observer.destroy();
263
- ```
264
-
265
- ## Error Reporting
266
-
267
- Send `warn`/`error` logs to an external monitoring service (Sentry, Datadog, etc.):
268
-
269
- ```ts
270
- import { Framework, type ReportCallback } from "@finesoft/front";
271
-
272
- const framework = Framework.create({
273
- reportCallback(level, category, args) {
274
- sentry.captureMessage(`[${category}] ${args.join(" ")}`, level);
275
- },
276
- });
277
-
278
- // Automatically composes with ConsoleLogger — console output is preserved.
279
- // All framework.getLogger().warn(...) and .error(...) calls are forwarded.
280
- ```
281
-
282
- ## HTTP Client
283
-
284
- Subclass `HttpClient` to create typed API clients:
285
-
286
- ```ts
287
- import { HttpClient } from "@finesoft/front";
288
-
289
- class MyApi extends HttpClient {
290
- async getUser(id: string) {
291
- return this.get<User>(`/users/${id}`);
292
- }
293
- async createUser(data: NewUser) {
294
- return this.post<User>("/users", data);
295
- }
296
- }
297
- ```
298
-
299
- ### Interceptors
300
-
301
- Add request/response interceptors for auth, logging, retries, etc.:
302
-
303
- ```ts
304
- const api = new MyApi({
305
- baseUrl: "/api",
306
- requestInterceptors: [
307
- (url, init) => {
308
- init.headers = {
309
- ...init.headers,
310
- Authorization: `Bearer ${token}`,
311
- };
312
- return init;
313
- },
314
- ],
315
- responseInterceptors: [
316
- (response, url) => {
317
- if (response.status === 401) refreshToken();
318
- return response;
319
- },
320
- ],
321
- });
322
-
323
- // Or add dynamically:
324
- api.useRequestInterceptor((url, init) => {
325
- /* ... */ return init;
326
- });
327
- ```
328
-
329
- ## Platform Detection
330
-
331
- Automatically detected from User-Agent and available via DI:
332
-
333
- ```ts
334
- const platform = framework.getPlatform();
335
- // { os: "ios", browser: "safari", engine: "webkit", isMobile: true, isTouch: true }
336
- ```
337
-
338
- Standalone usage:
339
-
340
- ```ts
341
- import { detectPlatform } from "@finesoft/front";
342
- const info = detectPlatform(); // auto-reads navigator.userAgent
343
- ```
344
-
345
- ## PWA Detection
346
-
347
- ```ts
348
- import { getPWADisplayMode } from "@finesoft/front";
349
-
350
- const mode = getPWADisplayMode();
351
- // "standalone" | "twa" | "browser"
352
- ```
353
-
354
- ## Feature Flags
355
-
356
- ```ts
357
- const framework = Framework.create({
358
- featureFlags: { darkMode: true, maxRetries: 3 },
359
- });
360
-
361
- // Add remote providers (last registered wins):
362
- import { type FeatureFlagsProvider } from "@finesoft/front";
363
-
364
- const framework = Framework.create({
365
- featureFlags: { darkMode: false },
366
- featureFlagsProviders: [remoteConfigProvider],
367
- });
368
- ```
369
-
370
- ## DI Container
371
-
372
- Scoped containers for request isolation (SSR):
373
-
374
- ```ts
375
- const requestScope = framework.container.createScope();
376
- requestScope.register("user", () => currentUser);
377
- // Falls back to parent container if key not found
378
- ```
379
-
380
- ## SSR
381
-
382
- ```ts
383
- // src/ssr.ts
384
- import { createSSRRender, serializeServerData } from "@finesoft/front";
385
- import { createSSRApp } from "vue";
386
- import { renderToString } from "vue/server-renderer";
387
- import App from "./App.vue";
388
- import { bootstrap } from "./bootstrap";
389
-
390
- export const render = createSSRRender({
391
- bootstrap,
392
- getErrorPage: () => ({ title: "Error", kind: "error" }),
393
- async renderApp(page) {
394
- const html = await renderToString(createSSRApp(App, { page }));
395
- return { html, head: `<title>${page.title}</title>`, css: "" };
396
- },
397
- });
398
-
399
- export { serializeServerData };
400
- ```
401
-
402
- ## Adapters
403
-
404
- | Adapter | Target |
405
- | -------------- | -------------------------- |
406
- | `"node"` | Standalone Node.js server |
407
- | `"vercel"` | Vercel Build Output API v3 |
408
- | `"cloudflare"` | Cloudflare Workers |
409
- | `"netlify"` | Netlify Functions v2 |
410
- | `"static"` | Pre-rendered static files |
411
- | `"auto"` | Auto-detect at build time |
412
-
413
- ## Entry Points
414
-
415
- | Import | Contents |
416
- | ------------------------- | ------------------------------------------ |
417
- | `@finesoft/front` | Everything (core + browser + SSR + server) |
418
- | `@finesoft/front/browser` | Browser-only (no server code) |
9
+ **Documentation: [English](./docs/README.md) · [简体中文](./docs/zh/README.md)** getting started, engineering practices, pitfalls, and advanced recipes.
419
10
 
420
11
  ## License
421
12
 
@@ -0,0 +1,2 @@
1
+ import { $ as RenderMode, $t as Storage, A as IntersectionImpressionObserver, An as isCompoundAction, At as RouteAddOptions, B as buildUrl, Bt as RedirectResult, C as PluralRuleProvider, Cn as ActionDispatcher, Ct as Translator, D as WithFieldsRecorder, Dn as CompoundAction, Dt as ConsoleLoggerFactory, E as resolvePluralKey, En as Action, Et as ConsoleLogger, F as BrowserContextOptions, Ft as DenyResult, G as PWADisplayMode, Gt as rewrite, H as removeHost, Ht as deny, I as ServerContextOptions, It as MiddlewareResult, J as Optional, Jt as FeatureFlags, K as getPWADisplayMode, Kt as BasePage, L as createBrowserContext, Lt as NavigationContext, M as CompositeEventRecorder, Mn as isFlowAction, Mt as Router, N as runAfterLoadGuards, Nn as makeExternalUrlAction, Nt as AfterLoadGuard, O as VoidEventRecorder, On as ExternalUrlAction, Ot as CompositeLogger, P as runBeforeLoadGuards, Pn as makeFlowAction, Pt as BeforeLoadGuard, Q as DefineRoutesOptions, Qt as Net, R as createServerContext, Rt as NextResult, S as PluralCategory, Sn as Container, St as TextDirection, T as interpolate, Tn as ACTION_KINDS, Tt as shouldLog, U as removeQueryParams, Ut as next, V as getBaseUrl, Vt as RewriteResult, W as removeScheme, Wt as redirect, X as isSome, Xt as MakeDependenciesOptions, Y as isNone, Yt as FeatureFlagsProvider, Z as LruMap, Zt as MetricsRecorder, _ as getTextDirection, _n as Logger, _t as FrameworkConfig, a as BrowserAppConfig, an as resolveMessages, at as pipe, b as resolveLocaleFromUrl, bn as Intent, bt as LocaleAttributes, c as registerActionHandlers, cn as EventRecorder, ct as HttpClient, d as registerFlowActionHandler, dn as MetricsFieldsProvider, dt as RequestInterceptor, en as makeDependencies, et as RouteDefinition, f as ExternalUrlDependencies, fn as ReportCallback, ft as ResponseInterceptor, g as getLocaleAttributes, gn as BaseLogger, gt as Framework, h as SimpleTranslatorOptions, hn as ReportingLoggerOptions, ht as BaseShelf, i as History, in as resolveConfiguredMessages, it as mapEach, j as ConsoleEventRecorder, jn as isExternalUrlAction, jt as RouteMatch, k as ImpressionObserverOptions, kn as FlowAction, kt as CompositeLoggerFactory, l as FlowActionCallbacks, ln as ImpressionEntry, lt as HttpClientConfig, m as SimpleTranslator, mn as ReportingLoggerFactory, mt as BaseItem, n as deserializeServerData, nn as MessagesLoaderContext, nt as AsyncMapper, o as startBrowserApp, on as PlatformInfo, ot as pipeAsync, p as registerExternalUrlHandler, pn as ReportingLogger, pt as stableStringify, q as None, qt as DEP_KEYS, r as tryScroll, rn as TranslationMessages, rt as Mapper, s as ActionHandlerDependencies, sn as detectPlatform, st as BaseController, t as createPrefetchedIntentsFromDom, tn as MessagesLoader, tt as defineRoutes, u as FlowActionDependencies, un as ImpressionObserver, ut as HttpError, v as isRtl, vn as LoggerFactory, vt as PrefetchedIntent, w as englishPlural, wn as ActionHandler, wt as resetFilterCache, x as setHtmlLocaleAttributes, xn as IntentController, xt as LocaleInfo, y as makeLocaleInfo, yn as IntentDispatcher, yt as PrefetchedIntents, z as generateUuid, zt as PostLoadContext } from "./server-data-DGbiKzMS.mjs";
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 };
@@ -0,0 +1 @@
1
+ import{$ as e,A as t,B as n,C as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,Q as _,R as v,S as y,T as b,U as x,V as S,W as C,X as w,Y as T,Z as E,_ as D,_t as O,a as k,at as A,b as j,bt as M,c as N,ct as P,d as F,dt as I,et as L,f as R,ft as z,g as B,gt as V,h as H,ht as U,i as W,it as G,j as K,k as q,l as J,lt as Y,m as X,mt as Z,n as Q,nt as $,o as ee,ot as te,p as ne,pt as re,q as ie,r as ae,rt as oe,s as se,st as ce,t as le,tt as ue,u as de,ut as fe,v as pe,vt as me,w as he,x as ge,xt as _e,y as ve,yt as ye,z as be}from"./start-app-BdXBCcor.mjs";export{V as ACTION_KINDS,U as ActionDispatcher,m as BaseController,_ as BaseLogger,R as CompositeEventRecorder,e as CompositeLogger,L as CompositeLoggerFactory,s as ConsoleEventRecorder,u as ConsoleLogger,T as ConsoleLoggerFactory,re as Container,c as DEP_KEYS,l as Framework,ee as History,g as HttpClient,o as HttpError,Z as IntentDispatcher,F as IntersectionImpressionObserver,h as LruMap,f as PrefetchedIntents,d as ReportingLogger,ie as ReportingLoggerFactory,S as Router,ue as SimpleTranslator,de as VoidEventRecorder,J as WithFieldsRecorder,j as buildUrl,D as createBrowserContext,Q as createPrefetchedIntentsFromDom,pe as createServerContext,q as defineRoutes,ne as deny,ae as deserializeServerData,C as detectPlatform,$ as englishPlural,ve as generateUuid,ge as getBaseUrl,ce as getLocaleAttributes,b as getPWADisplayMode,P as getTextDirection,oe as interpolate,O as isCompoundAction,me as isExternalUrlAction,ye as isFlowAction,a as isNone,Y as isRtl,i as isSome,x as makeDependencies,M as makeExternalUrlAction,_e as makeFlowAction,fe as makeLocaleInfo,t as mapEach,X as next,K as pipe,p as pipeAsync,H as redirect,W as registerActionHandlers,N as registerExternalUrlHandler,k as registerFlowActionHandler,y as removeHost,r as removeQueryParams,he as removeScheme,w as resetFilterCache,A as resolveConfiguredMessages,I as resolveLocaleFromUrl,te as resolveMessages,G as resolvePluralKey,B as rewrite,be as runAfterLoadGuards,n as runBeforeLoadGuards,z as setHtmlLocaleAttributes,E as shouldLog,v as stableStringify,le as startBrowserApp,se as tryScroll};