@llmnative/react 2.1.0 → 2.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.
Files changed (38) hide show
  1. package/dist/index.css +1 -1
  2. package/dist/index.js +21 -21
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +10310 -8468
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/types/src/App.d.ts +10 -1
  7. package/dist/types/src/I18n.d.ts +91 -0
  8. package/dist/types/src/components/auth/AuthGate.d.ts +26 -0
  9. package/dist/types/src/components/auth/AuthLayout.d.ts +38 -0
  10. package/dist/types/src/components/auth/ForgotPassword.d.ts +19 -0
  11. package/dist/types/src/components/auth/OneTimeCodeInput.d.ts +27 -0
  12. package/dist/types/src/components/auth/ResetPassword.d.ts +31 -0
  13. package/dist/types/src/components/auth/SignIn.d.ts +42 -0
  14. package/dist/types/src/components/auth/SignUp.d.ts +43 -0
  15. package/dist/types/src/components/auth/VerifyCode.d.ts +32 -0
  16. package/dist/types/src/components/auth/VerifyEmail.d.ts +31 -0
  17. package/dist/types/src/components/auth/index.d.ts +12 -0
  18. package/dist/types/src/components/auth/providers.d.ts +22 -0
  19. package/dist/types/src/components/auth/shared.d.ts +124 -0
  20. package/dist/types/src/components/auth/useAuthFlows.d.ts +46 -0
  21. package/dist/types/src/index.d.ts +5 -1
  22. package/dist/types/src/providers/auth/AuthProvider.d.ts +51 -0
  23. package/dist/types/src/providers/auth/firebase/FirebaseAuthProvider.d.ts +8 -1
  24. package/dist/types/src/providers/auth/github/GitHubAuthProvider.d.ts +2 -0
  25. package/dist/types/src/providers/auth/mock/MockAuthProvider.d.ts +55 -0
  26. package/dist/types/src/providers/auth/supabase/SupabaseAuthProvider.d.ts +16 -1
  27. package/dist/types/src/providers/manifest.d.ts +4 -1
  28. package/llms-full.txt +66 -2
  29. package/package.json +1 -1
  30. package/scripts/cli/setup-project.js +678 -667
  31. package/templates/_shared/conf/access.tsx +23 -0
  32. package/templates/_shared/pages/access/ForgotPasswordPage.tsx +13 -0
  33. package/templates/_shared/pages/access/ResetPasswordPage.tsx +19 -0
  34. package/templates/_shared/pages/access/SignInPage.tsx +21 -0
  35. package/templates/_shared/pages/access/SignUpPage.tsx +23 -0
  36. package/templates/_shared/pages/access/VerifyEmailPage.tsx +20 -0
  37. package/templates/_shared/pages/access/paths.ts +12 -0
  38. package/templates/_shared/sections/Header.tsx +1 -1
@@ -13,6 +13,7 @@ export type { I18nDict, I18nConfig, I18nController, I18nTranslations, I18nLocale
13
13
  export * as locales from './conf/i18n';
14
14
  export type { AppThemeProviderConfig, BuiltInThemeId, CardTheme, ColorScale, GalleryTheme, ListCardTheme, MenuTheme, ModalTheme, ProviderSwitcherTheme, ToolbarTheme, TableTheme, Theme, ThemeConfig, ThemeController, ThemeMode, ThemeDefinition, ThemePresetConfig, } from './Theme';
15
15
  export { AuthButton, useAccessToken, getAccessToken } from './auth';
16
+ export * from './components/auth';
16
17
  export { useGlobalVars, getGlobalVars, setGlobalVars, removeGlobalVars } from './Global';
17
18
  export type { DataProviderAdapter, FieldValue, RecordProps, RecordArray, DatabaseOptions, DBConfig, ReadOptions, WhereClause, OrderClause, Condition } from './providers/data/DataProvider';
18
19
  export type { OrderConfig, OrderDirection } from './libs/order';
@@ -50,7 +51,10 @@ export { FirebaseStorageProvider } from './providers/storage/firebase';
50
51
  export type { FirebaseStorageProviderConfig } from './providers/storage/firebase';
51
52
  export { SupabaseStorageProvider } from './providers/storage/supabase';
52
53
  export { useStorageProvider, StorageProvider } from './providers/storage/StorageProviderContext';
53
- export type { AuthProviderAdapter, AuthIntent, AuthSignInOptions, UserProfile } from './providers/auth/AuthProvider';
54
+ export type { AuthProviderAdapter, AuthIntent, AuthSignInOptions, UserProfile, AuthSignUpInput, AuthSignUpResult, AuthLinkOptions, AuthEmailCodeOptions, AuthErrorReason, } from './providers/auth/AuthProvider';
55
+ export { AuthFlowError } from './providers/auth/AuthProvider';
56
+ export { MockAuthProvider } from './providers/auth/mock/MockAuthProvider';
57
+ export type { MockAuthProviderOptions, MockAuthAccount } from './providers/auth/mock/MockAuthProvider';
54
58
  export { useAuthProvider, AuthProvider } from './providers/auth/AuthProviderContext';
55
59
  export { GoogleAuthProvider } from './providers/auth/google/GoogleAuthProvider';
56
60
  export type { FirebaseAuthProviderOptions, FirebaseSignInOptions } from './providers/auth/firebase/FirebaseAuthProvider';
@@ -27,4 +27,55 @@ export interface AuthProviderAdapter extends ProviderConfigurable {
27
27
  * re-verifies the raw token itself rather than trusting client-read claims.
28
28
  */
29
29
  getIdTokenClaims?(forceRefresh?: boolean): Promise<Record<string, unknown> | null>;
30
+ /** Resolves once the session of the last visit is restored (signed in or not): `AuthGate` waits for it. */
31
+ whenReady?(): Promise<void>;
32
+ /** Creates an account with email and password; says whether the email must be confirmed first. */
33
+ signUp?(input: AuthSignUpInput): Promise<AuthSignUpResult>;
34
+ /** Sends the link to choose a new password. Never says whether the account exists. */
35
+ sendPasswordReset?(email: string, options?: AuthLinkOptions): Promise<void>;
36
+ /** Sets the new password with the code of the link (`oobCode`, `token_hash`, …). */
37
+ confirmPasswordReset?(code: string, newPassword: string): Promise<void>;
38
+ /** Sends again the link that confirms the email: of the signed-in user, or of `email` when the service allows it. */
39
+ sendEmailVerification?(options?: AuthLinkOptions & {
40
+ email?: string;
41
+ }): Promise<void>;
42
+ /** Confirms the email with the code of the link. */
43
+ verifyEmail?(code: string): Promise<void>;
44
+ /** Sends a one-time code by email to sign in. */
45
+ requestEmailCode?(email: string, options?: AuthEmailCodeOptions): Promise<void>;
46
+ /** Signs in with the code received by email. */
47
+ verifyEmailCode?(email: string, code: string): Promise<UserProfile | null>;
48
+ }
49
+ export interface AuthSignUpInput {
50
+ email: string;
51
+ password: string;
52
+ /** The full name, when the screen asks for it. */
53
+ name?: string;
54
+ /** Where the confirmation link brings back (the page that calls `verifyEmail`). */
55
+ redirectTo?: string;
56
+ }
57
+ export interface AuthSignUpResult {
58
+ user: UserProfile | null;
59
+ /** The account works once the email is confirmed: the screen says to check the inbox. */
60
+ needsEmailVerification: boolean;
61
+ }
62
+ export interface AuthLinkOptions {
63
+ /** The page the link of the email opens. */
64
+ redirectTo?: string;
65
+ }
66
+ export interface AuthEmailCodeOptions {
67
+ /** Creates the account when the email has none (default `false`: only existing accounts sign in). */
68
+ createUser?: boolean;
69
+ }
70
+ /** Why an access flow failed, in words a screen can translate (`authErrorMessage`). */
71
+ export type AuthErrorReason = 'credentials' | 'emailInUse' | 'weakPassword' | 'invalidEmail' | 'tooManyRequests' | 'network' | 'invalidCode' | 'expiredLink' | 'disabled' | 'cancelled' | 'notSupported' | 'generic';
72
+ /**
73
+ * An error of an access flow with its reason: a screen shows the translated message of the reason,
74
+ * never the raw text of the service. Throw it from your own functions (e.g. a code checked by your server).
75
+ */
76
+ export declare class AuthFlowError extends Error {
77
+ readonly reason: AuthErrorReason;
78
+ constructor(reason: AuthErrorReason, message?: string, options?: {
79
+ cause?: unknown;
80
+ });
30
81
  }
@@ -1,4 +1,4 @@
1
- import type { AuthProviderAdapter, AuthSignInOptions, UserProfile } from '../AuthProvider';
1
+ import type { AuthLinkOptions, AuthProviderAdapter, AuthSignInOptions, AuthSignUpInput, AuthSignUpResult, UserProfile } from '../AuthProvider';
2
2
  import type { ProviderConfigurationState } from '../../ProviderConfiguration';
3
3
  import type { FirebaseConfig } from '../../../Config';
4
4
  /**
@@ -46,4 +46,11 @@ export declare class FirebaseAuthProvider implements AuthProviderAdapter {
46
46
  onAuthChange(callback: (user: UserProfile | null) => void): () => void;
47
47
  getAccessToken(): Promise<string>;
48
48
  getIdTokenClaims(forceRefresh?: boolean): Promise<Record<string, unknown> | null>;
49
+ private requireAuth;
50
+ whenReady(): Promise<void>;
51
+ signUp({ email, password, name, redirectTo }: AuthSignUpInput): Promise<AuthSignUpResult>;
52
+ sendPasswordReset(email: string, options?: AuthLinkOptions): Promise<void>;
53
+ confirmPasswordReset(code: string, newPassword: string): Promise<void>;
54
+ sendEmailVerification(options?: AuthLinkOptions): Promise<void>;
55
+ verifyEmail(code: string): Promise<void>;
49
56
  }
@@ -32,6 +32,8 @@ export declare class GitHubAuthProvider implements AuthProviderAdapter {
32
32
  refresh(): Promise<UserProfile | null>;
33
33
  /** Leaves for GitHub through the server, and comes back to the page it left from. */
34
34
  signIn(options?: AuthSignInOptions): Promise<UserProfile | null>;
35
+ /** Resolves once the server said who is signed in (CR-127): `AuthGate` waits for it. */
36
+ whenReady(): Promise<void>;
35
37
  signOut(): Promise<void>;
36
38
  onAuthChange(callback: (user: UserProfile | null) => void): () => void;
37
39
  private setUser;
@@ -0,0 +1,55 @@
1
+ import type { AuthEmailCodeOptions, AuthProviderAdapter, AuthSignInOptions, AuthSignUpInput, AuthSignUpResult, UserProfile } from '../AuthProvider';
2
+ import type { ProviderConfigurationState } from '../../ProviderConfiguration';
3
+ /** An account of the mock: its password, and whether its email is confirmed. */
4
+ export interface MockAuthAccount {
5
+ email: string;
6
+ password: string;
7
+ displayName?: string;
8
+ emailVerified?: boolean;
9
+ }
10
+ export interface MockAuthProviderOptions {
11
+ /**
12
+ * The accounts that exist. Omitted: any email and any password sign in (a demo); given: only these,
13
+ * and a wrong password fails as a real service would.
14
+ */
15
+ accounts?: MockAuthAccount[];
16
+ /** The code every email "receives" (default `123456`); any other code fails. */
17
+ code?: string;
18
+ /** Where the session is kept between reloads (default `sessionStorage`); `null` keeps it in memory only. */
19
+ storage?: Storage | null;
20
+ /** A pause before each answer, in ms, to see the loading states (default `400`). */
21
+ latency?: number;
22
+ }
23
+ /**
24
+ * An auth provider for demos and tests, with no service behind it (CR-127): every flow of the access
25
+ * screens works in memory. Never use it in production: it trusts any credential it is configured to.
26
+ */
27
+ export declare class MockAuthProvider implements AuthProviderAdapter {
28
+ private user;
29
+ private readonly listeners;
30
+ private readonly accounts;
31
+ private readonly open;
32
+ private readonly code;
33
+ private readonly storage;
34
+ private readonly latency;
35
+ constructor(options?: MockAuthProviderOptions);
36
+ getConfigurationState(): ProviderConfigurationState;
37
+ isConfigured(): boolean;
38
+ getUser(): UserProfile | null;
39
+ isAuthenticated(): boolean;
40
+ whenReady(): Promise<void>;
41
+ onAuthChange(callback: (user: UserProfile | null) => void): () => void;
42
+ signIn(options?: AuthSignInOptions): Promise<UserProfile | null>;
43
+ signOut(): Promise<void>;
44
+ signUp({ email, password, name }: AuthSignUpInput): Promise<AuthSignUpResult>;
45
+ sendPasswordReset(): Promise<void>;
46
+ confirmPasswordReset(code: string, newPassword: string): Promise<void>;
47
+ sendEmailVerification(): Promise<void>;
48
+ verifyEmail(code: string): Promise<void>;
49
+ requestEmailCode(email: string, options?: AuthEmailCodeOptions): Promise<void>;
50
+ verifyEmailCode(email: string, code: string): Promise<UserProfile | null>;
51
+ private profile;
52
+ private setUser;
53
+ private restore;
54
+ private pause;
55
+ }
@@ -1,4 +1,4 @@
1
- import type { AuthProviderAdapter, AuthSignInOptions, UserProfile } from '../AuthProvider';
1
+ import type { AuthEmailCodeOptions, AuthLinkOptions, AuthProviderAdapter, AuthSignInOptions, AuthSignUpInput, AuthSignUpResult, UserProfile } from '../AuthProvider';
2
2
  import type { ProviderConfigurationState } from '../../ProviderConfiguration';
3
3
  export interface SupabaseAuthConfig {
4
4
  url: string;
@@ -45,4 +45,19 @@ export declare class SupabaseAuthProvider implements AuthProviderAdapter {
45
45
  signOut(): Promise<void>;
46
46
  onAuthChange(callback: (user: UserProfile | null) => void): () => void;
47
47
  getAccessToken(): Promise<string>;
48
+ whenReady(): Promise<void>;
49
+ signUp({ email, password, name, redirectTo }: AuthSignUpInput): Promise<AuthSignUpResult>;
50
+ sendPasswordReset(email: string, options?: AuthLinkOptions): Promise<void>;
51
+ /**
52
+ * `code` is the `token_hash` of the recovery email (template `{{ .TokenHash }}`); empty when the link
53
+ * already opened a recovery session (the default template), and then only the password is set.
54
+ */
55
+ confirmPasswordReset(code: string, newPassword: string): Promise<void>;
56
+ sendEmailVerification(options?: AuthLinkOptions & {
57
+ email?: string;
58
+ }): Promise<void>;
59
+ /** `code` is the `token_hash` of the confirmation email (template `{{ .TokenHash }}`). */
60
+ verifyEmail(code: string): Promise<void>;
61
+ requestEmailCode(email: string, options?: AuthEmailCodeOptions): Promise<void>;
62
+ verifyEmailCode(email: string, code: string): Promise<UserProfile | null>;
48
63
  }
@@ -1,5 +1,6 @@
1
1
  import type { CredentialsAdapter } from './credentials/CredentialsProvider';
2
2
  import { MockDataProvider } from './data/mock';
3
+ import { type MockAuthProviderOptions } from './auth/mock/MockAuthProvider';
3
4
  import type { AIProviderAdapter } from './ai/AIProvider';
4
5
  import type { DataProviderAdapter } from './data/DataProvider';
5
6
  import type { StorageProviderAdapter } from './storage/StorageProvider';
@@ -23,6 +24,8 @@ export type GoogleProviderConfig = GoogleOAuth2 & {
23
24
  export type SupabaseProviderConfig = SupabaseConfig;
24
25
  export type MockProviderConfig = {
25
26
  data?: ConstructorParameters<typeof MockDataProvider>[0];
27
+ /** Registers `mockAuth` (CR-127), a provider of access with no service behind it: demos and tests only. */
28
+ auth?: MockAuthProviderOptions | boolean;
26
29
  };
27
30
  export declare const FIREBASE_MANIFEST: DriverManifest<FirebaseConfig>;
28
31
  export declare const GOOGLE_MANIFEST: DriverManifest<GoogleProviderConfig>;
@@ -34,7 +37,7 @@ export declare const AI_MANIFEST: DriverManifest<AIConfig>;
34
37
  export declare const PROVIDER_MANIFESTS: Record<string, DriverManifest<any>>;
35
38
  export type DataDriverName = 'dbRealtime' | 'firestoreDb' | 'supabaseDb' | 'mock';
36
39
  export type StorageDriverName = 'firestorage' | 'supabaseStorage';
37
- export type AuthDriverName = 'googleAuth' | 'firebaseAuth' | 'dropboxAuth' | 'supabaseAuth' | 'githubAuth';
40
+ export type AuthDriverName = 'googleAuth' | 'firebaseAuth' | 'dropboxAuth' | 'supabaseAuth' | 'githubAuth' | 'mockAuth';
38
41
  export type EmailDriverName = 'gmail';
39
42
  export type AIDriverName = 'openai' | 'openrouter' | 'opencode' | 'opencode-go' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral' | 'cloudflare' | 'groq';
40
43
  export type CredentialsDriverName = 'googleServiceAccount';
package/llms-full.txt CHANGED
@@ -248,6 +248,66 @@ await auth.signIn({ method: 'oauth', provider: 'github' })
248
248
  const token = await auth.getAccessToken('https://www.googleapis.com/auth/gmail.send')
249
249
  ```
250
250
 
251
+ ### Schermate di accesso e gate senza redirect (CR-127)
252
+
253
+ Le schermate sono pronte: non scriverne a mano. Non conoscono il backend: ricevono le funzioni da
254
+ chiamare (una promessa) e mostrano l'errore lanciato tradotto, mai il testo grezzo del servizio
255
+ (`authErrorMessage`: codici di Firebase e Supabase, `AuthFlowError(reason)` per le funzioni tue).
256
+ Testi nel namespace `access` delle 6 lingue. Ognuna ha `brand`, `toolbar`, `footer`, `bare` (solo il
257
+ contenuto, in una modale), `errorMessage(error)`.
258
+
259
+ | Componente | Cosa fa | Funzioni |
260
+ |---|---|---|
261
+ | `SignIn` | provider esterni, email + password, codice via email, in qualsiasi combinazione | `onPasswordSignIn({email,password})`, `onRequestCode(email)` + `onVerifyCode(email,code)`, `providers` + `onProviderSignIn(id)` |
262
+ | `SignUp` | nome, email, password con i requisiti mentre si scrive, termini; poi "controlla la tua email" | `onSignUp({name,email,password})` → `{ needsEmailVerification }`, `onResendVerification(email)` |
263
+ | `ForgotPassword` | email → stessa risposta con o senza account, nuovo invio dopo un'attesa | `onSendReset(email)` |
264
+ | `ResetPassword` | nuova password dal link dell'email; link scaduto | `onResetPassword(password)`, `invalidLink` |
265
+ | `VerifyEmail` | attivazione: con `code` verifica subito, senza aspetta la conferma | `onVerify(code)`, `onResend()`, `onContinue()` |
266
+ | `VerifyCode` | codice di N cifre in caselle, inviato a codice completo | `onVerify(code)`, `onResend()`, `onChangeEmail()` |
267
+ | `OneTimeCodeInput` | le caselle da sole (incolla, avanti/indietro, `one-time-code`) | `value`, `onChange`, `onComplete` |
268
+ | `AuthLayout` | la cornice di una schermata (marchio, card, titolo, piè di pagina) | — |
269
+ | `AuthGate` | la pagina solo con la sessione; senza, `fallback` al suo posto | `allow(user)`, `denied`, `loading` |
270
+
271
+ ```tsx
272
+ import { App, SignIn, AuthFlowError } from '@llmnative/react';
273
+
274
+ // Tutta l'app riservata: senza sessione ogni pagina mostra l'accesso al suo posto, l'indirizzo
275
+ // resta quello aperto e dopo l'accesso compare la pagina. Nessuna pagina /login, nessun redirect.
276
+ <App
277
+ menuConfig={{ main: [...], access: [{ path: '/invito/:token', page: InvitePage, public: true }] }}
278
+ authGate={{
279
+ fallback: <SignIn providers={['google', 'apple']} onProviderSignIn={enter}
280
+ onRequestCode={sendCode} onVerifyCode={checkCode} appName="CRM" />,
281
+ allow: async (user) => (await isMember(user)), // altrimenti "Accesso non consentito"
282
+ }}
283
+ />
284
+
285
+ // Una funzione tua che rifiuta: la schermata dice "Il codice non è corretto o è scaduto."
286
+ async function checkCode(email: string, code: string) {
287
+ const { token } = await callFunction('verifyLoginCode', { email, code }).catch(() => {
288
+ throw new AuthFlowError('invalidCode');
289
+ });
290
+ await signInWithCustomToken(token);
291
+ }
292
+ ```
293
+
294
+ Con gli adapter del framework `useAuthFlows(provider?, { verifyEmailPath, resetPasswordPath })` dà le
295
+ funzioni pronte (`<SignIn {...flows.signIn} />`, `flows.signUp`, `flows.forgotPassword`,
296
+ `flows.resetPassword(linkCode())`, `flows.verifyEmail`). Metodi opzionali di `AuthProviderAdapter`:
297
+
298
+ | Metodo | Firebase | Supabase | `mockAuth` |
299
+ |---|---|---|---|
300
+ | `whenReady` (il gate aspetta la sessione) | ✅ | ✅ | ✅ (anche `githubAuth`) |
301
+ | `signUp`, `sendPasswordReset`, `confirmPasswordReset` | ✅ | ✅ | ✅ |
302
+ | `sendEmailVerification`, `verifyEmail` | ✅ | ✅ | ✅ |
303
+ | `requestEmailCode`, `verifyEmailCode` | — (serve una funzione tua) | ✅ | ✅ |
304
+
305
+ `useAuthSession(provider?)` dà `{ user, ready, signOut }`. `linkCode()` legge il codice del link
306
+ (`oobCode`, `token_hash`, `code`). `mockAuth` (`providers.mock.auth: true`) è solo per demo e test:
307
+ qualsiasi email e password, codice `123456`; con `accounts` rifiuta le credenziali sbagliate.
308
+ Link delle email: in Firebase imposta l'URL di azione sulle tue pagine (`/reset-password`,
309
+ `/verify-email`); in Supabase usa `{{ .TokenHash }}` nei template delle email.
310
+
251
311
  ### CredentialsAdapter (Google Service Account)
252
312
  ```tsx
253
313
  // Chiama Google APIs lato browser senza Node.js
@@ -1466,6 +1526,7 @@ src/
1466
1526
  conf/
1467
1527
  app.ts ← providers config letta da .env (VITE_PROVIDER, VITE_AI_PROVIDER...)
1468
1528
  menu.ts ← MenuConfig con path, title, icon, page (layout opzionale: c'è LayoutDefault)
1529
+ access.tsx ← rotte pubbliche delle pagine di accesso (CR-127)
1469
1530
  data/
1470
1531
  mockData.ts ← dati fake per MockDataProvider
1471
1532
  layouts/
@@ -1474,6 +1535,7 @@ src/
1474
1535
  Header.tsx / Sidebar.tsx / PageHeader.tsx / Footer.tsx ← solo componenti pubblici (SideNav, AuthButton, ActionButton, Brand, Breadcrumbs)
1475
1536
  pages/
1476
1537
  home/HomePage.tsx
1538
+ access/ ← SignInPage (il fallback del gate), SignUp, ForgotPassword, ResetPassword, VerifyEmail
1477
1539
  [altre pagine dal template scelto]
1478
1540
  styles/
1479
1541
  globals.css ← @import '@llmnative/react/dist/index.css' + Tailwind override
@@ -1491,11 +1553,12 @@ const env = import.meta.env
1491
1553
  export const providers: AppProvidersConfig = {
1492
1554
  mock: { data: mockData },
1493
1555
  ai: { openaiApiKey: env.VITE_OPENAI_API_KEY ?? '' }, // AI dentro providers, non prop <App>
1494
- services: { data: 'mock', auth: 'googleAuth' },
1556
+ mock: { data: mockData, auth: true }, // mockAuth: accesso di prova
1557
+ services: { data: 'mock', auth: 'mockAuth' },
1495
1558
  }
1496
1559
  ```
1497
1560
 
1498
- Driver per `VITE_PROVIDER`: `firebase` → `firestoreDb` + `firestorage` + `firebaseAuth`; `supabase` → `supabaseDb` + `supabaseStorage` + `supabaseAuth`; `mock` → `mock` + `googleAuth`. `index.tsx` passa `LayoutDefault={Default}` ad `<App>`.
1561
+ Driver per `VITE_PROVIDER`: `firebase` → `firestoreDb` + `firestorage` + `firebaseAuth`; `supabase` → `supabaseDb` + `supabaseStorage` + `supabaseAuth`; `mock` → `mock` + `mockAuth`. `index.tsx` passa `LayoutDefault={Default}`, le traduzioni del framework (`translations: { ...locales }`) e `authGate={{ fallback: <SignInPage /> }}`: senza sessione ogni pagina mostra l'accesso al suo posto. Le pagine di accesso (`pages/access/`: SignInPage, SignUpPage, ForgotPasswordPage, ResetPasswordPage, VerifyEmailPage) e le loro rotte pubbliche (`conf/access.tsx`) sono uguali per ogni template; per un'app aperta a tutti togli `authGate`.
1499
1562
 
1500
1563
  ---
1501
1564
 
@@ -1507,6 +1570,7 @@ Driver per `VITE_PROVIDER`: `firebase` → `firestoreDb` + `firestorage` + `fire
1507
1570
  | `inputType` o `Input.Number`/`Input.Email` non esistono | Il tipo HTML è la prop `type` | `<Input type="number">`, `<Input type="email">`, `<Input type="date">` |
1508
1571
  | `Menu context=` non esiste | La prop si chiama `menuKey` | `<Menu menuKey="main" />` |
1509
1572
  | `SignInButton` non esiste | Rinominato | `<AuthButton />` |
1573
+ | Pagina `/login` con redirect, form di accesso fatti a mano | Le schermate e il gate ci sono (CR-127) | `<App authGate={{ fallback: <SignIn … /> }}>`, rotte aperte con `public: true` |
1510
1574
  | `firebase: { config: ... }` errato | FirebaseConfig è flat | `firebase: { apiKey, authDomain, databaseURL, ... }` |
1511
1575
  | `google: { oAuth2: { clientId } }` errato | GoogleProviderConfig è flat | `google: { clientId, scope }` |
1512
1576
  | `children` su `Grid` | Grid non accetta children | Usa `form={<Fields />}` per il form inline |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnative/react",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "LLM-native React framework for deterministic UI generation. Data-driven by default, schema-driven optional. Ultra-low token consumption — built for AI agents, not just humans.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",