@finesoft/front 0.1.53 → 0.1.55

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
@@ -89,6 +89,259 @@ function authGuard(ctx: NavigationContext) {
89
89
 
90
90
  Results: `next()`, `redirect(url, status?)`, `rewrite(url)`, `deny(status?, message?)`.
91
91
 
92
+ ## Lifecycle Hooks
93
+
94
+ `startBrowserApp` provides hooks for initialization:
95
+
96
+ ```ts
97
+ import { startBrowserApp } from "@finesoft/front/browser";
98
+
99
+ startBrowserApp({
100
+ bootstrap,
101
+ // Pass framework config so locale/reporting/etc. are wired into Framework
102
+ frameworkConfig: {
103
+ locale: "zh-Hans",
104
+ },
105
+ mount: (target, { framework }) => {
106
+ /* ... */
107
+ },
108
+ callbacks: { onNavigate, onExternalUrl },
109
+ onBeforeStart(framework) {
110
+ // Runs after Framework creation, before mount.
111
+ // Good for: error monitoring, analytics SDK, i18n init.
112
+ },
113
+ onAfterStart(framework) {
114
+ // Runs after initial page trigger.
115
+ // Good for: service worker registration, performance marks.
116
+ },
117
+ });
118
+ ```
119
+
120
+ ## Locale (i18n)
121
+
122
+ Pass `locale` in `FrameworkConfig` to enable automatic locale handling:
123
+
124
+ ```ts
125
+ const framework = Framework.create({
126
+ locale: "zh-Hans", // or "en-US", "ar-SA", etc.
127
+ });
128
+
129
+ // SSR: automatically injects <html lang="zh-Hans" dir="ltr">
130
+ // Browser: automatically sets document.documentElement.lang/dir on startup
131
+ ```
132
+
133
+ For SSR, locale is resolved in this order:
134
+
135
+ 1. Explicit `resolveLocale` callback (if provided)
136
+ 2. `locale` from `FrameworkConfig` (via DI container)
137
+
138
+ Access at runtime:
139
+
140
+ ```ts
141
+ const locale = framework.getLocale();
142
+ // { lang: "zh-Hans", dir: "ltr" }
143
+ ```
144
+
145
+ ### Translator
146
+
147
+ For full i18n translation, use `SimpleTranslator`:
148
+
149
+ ```ts
150
+ import { SimpleTranslator } from "@finesoft/front";
151
+
152
+ const t = new SimpleTranslator({
153
+ locale: "zh-Hans",
154
+ messages: {
155
+ hello: "你好",
156
+ "items.one": "{count} 个项目",
157
+ "items.other": "{count} 个项目",
158
+ },
159
+ });
160
+
161
+ t.t("hello"); // "你好"
162
+ t.t("hello", { name: "World" }); // "你好"
163
+ t.plural("items", 5); // "5 个项目"
164
+ ```
165
+
166
+ ### RTL Support
167
+
168
+ ```ts
169
+ import { isRtl, getTextDirection, getLocaleAttributes } from "@finesoft/front";
170
+
171
+ isRtl("ar"); // true
172
+ getTextDirection("he"); // "rtl"
173
+ getLocaleAttributes("ar-SA"); // { lang: "ar-SA", dir: "rtl" }
174
+ ```
175
+
176
+ ## Metrics & Event Recording
177
+
178
+ ### EventRecorder (recommended)
179
+
180
+ New pipeline for structured event recording. Default: `ConsoleEventRecorder` (logs to console).
181
+
182
+ ```ts
183
+ import { Framework, type EventRecorder } from "@finesoft/front";
184
+
185
+ // Custom recorder
186
+ const framework = Framework.create({
187
+ eventRecorder: myAnalyticsRecorder,
188
+ });
189
+
190
+ // Framework automatically records PageView events via didEnterPage()
191
+ ```
192
+
193
+ Compose multiple recorders:
194
+
195
+ ```ts
196
+ import { CompositeEventRecorder, ConsoleEventRecorder } from "@finesoft/front";
197
+
198
+ const recorder = new CompositeEventRecorder([new ConsoleEventRecorder(), myProductionRecorder]);
199
+ ```
200
+
201
+ Inject common fields into every event:
202
+
203
+ ```ts
204
+ import { WithFieldsRecorder } from "@finesoft/front";
205
+
206
+ const recorder = new WithFieldsRecorder(baseRecorder, [
207
+ { getFields: () => ({ app: "myApp", version: "1.0" }) },
208
+ ]);
209
+ ```
210
+
211
+ ### Impression Tracking
212
+
213
+ Track element visibility using `IntersectionObserver`:
214
+
215
+ ```ts
216
+ import { IntersectionImpressionObserver } from "@finesoft/front";
217
+
218
+ const observer = new IntersectionImpressionObserver((entries) => {
219
+ for (const entry of entries) {
220
+ analytics.track("impression", { id: entry.id, ...entry.metadata });
221
+ }
222
+ });
223
+
224
+ observer.observe(element, "product-card-123", { category: "featured" });
225
+ // Later:
226
+ observer.unobserve(element);
227
+ observer.destroy();
228
+ ```
229
+
230
+ ## Error Reporting
231
+
232
+ Send `warn`/`error` logs to an external monitoring service (Sentry, Datadog, etc.):
233
+
234
+ ```ts
235
+ import { Framework, type ReportCallback } from "@finesoft/front";
236
+
237
+ const framework = Framework.create({
238
+ reportCallback(level, category, args) {
239
+ sentry.captureMessage(`[${category}] ${args.join(" ")}`, level);
240
+ },
241
+ });
242
+
243
+ // Automatically composes with ConsoleLogger — console output is preserved.
244
+ // All framework.getLogger().warn(...) and .error(...) calls are forwarded.
245
+ ```
246
+
247
+ ## HTTP Client
248
+
249
+ Subclass `HttpClient` to create typed API clients:
250
+
251
+ ```ts
252
+ import { HttpClient } from "@finesoft/front";
253
+
254
+ class MyApi extends HttpClient {
255
+ async getUser(id: string) {
256
+ return this.get<User>(`/users/${id}`);
257
+ }
258
+ async createUser(data: NewUser) {
259
+ return this.post<User>("/users", data);
260
+ }
261
+ }
262
+ ```
263
+
264
+ ### Interceptors
265
+
266
+ Add request/response interceptors for auth, logging, retries, etc.:
267
+
268
+ ```ts
269
+ const api = new MyApi({
270
+ baseUrl: "/api",
271
+ requestInterceptors: [
272
+ (url, init) => {
273
+ init.headers = {
274
+ ...init.headers,
275
+ Authorization: `Bearer ${token}`,
276
+ };
277
+ return init;
278
+ },
279
+ ],
280
+ responseInterceptors: [
281
+ (response, url) => {
282
+ if (response.status === 401) refreshToken();
283
+ return response;
284
+ },
285
+ ],
286
+ });
287
+
288
+ // Or add dynamically:
289
+ api.useRequestInterceptor((url, init) => {
290
+ /* ... */ return init;
291
+ });
292
+ ```
293
+
294
+ ## Platform Detection
295
+
296
+ Automatically detected from User-Agent and available via DI:
297
+
298
+ ```ts
299
+ const platform = framework.getPlatform();
300
+ // { os: "ios", browser: "safari", engine: "webkit", isMobile: true, isTouch: true }
301
+ ```
302
+
303
+ Standalone usage:
304
+
305
+ ```ts
306
+ import { detectPlatform } from "@finesoft/front";
307
+ const info = detectPlatform(); // auto-reads navigator.userAgent
308
+ ```
309
+
310
+ ## PWA Detection
311
+
312
+ ```ts
313
+ import { getPWADisplayMode } from "@finesoft/front";
314
+
315
+ const mode = getPWADisplayMode();
316
+ // "standalone" | "twa" | "browser"
317
+ ```
318
+
319
+ ## Feature Flags
320
+
321
+ ```ts
322
+ const framework = Framework.create({
323
+ featureFlags: { darkMode: true, maxRetries: 3 },
324
+ });
325
+
326
+ // Add remote providers (last registered wins):
327
+ import { type FeatureFlagsProvider } from "@finesoft/front";
328
+
329
+ const framework = Framework.create({
330
+ featureFlags: { darkMode: false },
331
+ featureFlagsProviders: [remoteConfigProvider],
332
+ });
333
+ ```
334
+
335
+ ## DI Container
336
+
337
+ Scoped containers for request isolation (SSR):
338
+
339
+ ```ts
340
+ const requestScope = framework.container.createScope();
341
+ requestScope.register("user", () => currentUser);
342
+ // Falls back to parent container if key not found
343
+ ```
344
+
92
345
  ## SSR
93
346
 
94
347
  ```ts