@llmnative/react 1.0.0 → 1.1.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 (54) hide show
  1. package/README.md +10 -0
  2. package/dist/index.css +1 -1
  3. package/dist/index.js +19 -19
  4. package/dist/index.mjs +6926 -6237
  5. package/dist/style.css +1 -1
  6. package/dist/types/src/App.d.ts +4 -1
  7. package/dist/types/src/I18n.d.ts +1 -0
  8. package/dist/types/src/components/blocks/Brand.d.ts +5 -0
  9. package/dist/types/src/components/blocks/Carousel.d.ts +2 -0
  10. package/dist/types/src/components/blocks/Dropdown.d.ts +12 -0
  11. package/dist/types/src/components/blocks/ListCard.d.ts +7 -0
  12. package/dist/types/src/components/blocks/Menu.d.ts +2 -0
  13. package/dist/types/src/components/blocks/Notifications.d.ts +4 -1
  14. package/dist/types/src/components/blocks/ProviderSwitcher.d.ts +3 -1
  15. package/dist/types/src/components/blocks/Search.d.ts +1 -0
  16. package/dist/types/src/components/blocks/ThemeSwitcher.d.ts +6 -2
  17. package/dist/types/src/components/blocks/Toolbar.d.ts +4 -0
  18. package/dist/types/src/components/index.d.ts +2 -2
  19. package/dist/types/src/components/ui/Alert.d.ts +4 -0
  20. package/dist/types/src/components/ui/Badge.d.ts +6 -0
  21. package/dist/types/src/components/ui/Buttons.d.ts +5 -2
  22. package/dist/types/src/components/ui/Card.d.ts +3 -0
  23. package/dist/types/src/components/ui/Code.d.ts +4 -0
  24. package/dist/types/src/components/ui/Gallery.d.ts +3 -2
  25. package/dist/types/src/components/ui/GridSystem.d.ts +4 -1
  26. package/dist/types/src/components/ui/Icon.d.ts +3 -0
  27. package/dist/types/src/components/ui/Image.d.ts +6 -0
  28. package/dist/types/src/components/ui/ImageAvatar.d.ts +3 -0
  29. package/dist/types/src/components/ui/Loader.d.ts +2 -0
  30. package/dist/types/src/components/ui/Modal.d.ts +4 -0
  31. package/dist/types/src/components/ui/Pagination.d.ts +2 -0
  32. package/dist/types/src/components/ui/Percentage.d.ts +9 -0
  33. package/dist/types/src/components/ui/Repeat.d.ts +0 -1
  34. package/dist/types/src/components/ui/Table.d.ts +3 -0
  35. package/dist/types/src/components/ui/fields/CodeEditor.d.ts +3 -0
  36. package/dist/types/src/components/ui/fields/ContextMenu.d.ts +50 -1
  37. package/dist/types/src/components/ui/fields/RichText.d.ts +4 -1
  38. package/dist/types/src/components/ui/fields/Select.d.ts +2 -2
  39. package/dist/types/src/components/ui/fields/Upload.d.ts +16 -3
  40. package/dist/types/src/components/widgets/Prompt.d.ts +35 -15
  41. package/dist/types/src/index.d.ts +14 -4
  42. package/dist/types/src/providers/ProviderDescriptor.d.ts +18 -0
  43. package/dist/types/src/providers/ai/index.d.ts +12 -1
  44. package/dist/types/src/providers/ai/openaiCompatible.d.ts +3 -1
  45. package/dist/types/src/providers/ai/shared.d.ts +10 -1
  46. package/dist/types/src/providers/auth/AuthProvider.d.ts +8 -0
  47. package/dist/types/src/providers/auth/firebase/FirebaseAuthProvider.d.ts +23 -0
  48. package/dist/types/src/providers/data/firestore.d.ts +8 -1
  49. package/dist/types/src/providers/email/definitions.d.ts +3 -0
  50. package/dist/types/src/providers/firebase-init.d.ts +11 -5
  51. package/dist/types/src/providers/publish/PublishProvider.d.ts +29 -0
  52. package/dist/types/src/providers/publish/definitions.d.ts +3 -0
  53. package/dist/types/src/providers/storage/firebase.d.ts +7 -1
  54. package/package.json +14 -7
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { FormFieldProps } from "../../widgets/Form";
3
+ import type { StorageProviderAdapter } from "../../../providers/storage/StorageProvider";
3
4
  export interface FileProps {
4
5
  key: string;
5
6
  fileName: string;
@@ -28,8 +29,16 @@ export interface UseFileUploadCoreOptions {
28
29
  srcsetWidths?: number[];
29
30
  /** Initial file list (e.g. from a form record on load). */
30
31
  initialFiles?: FileProps[];
32
+ /** Named storage provider slot to upload through — omit for the default. */
33
+ storageKey?: string;
34
+ /**
35
+ * Direct adapter instance — takes priority over `storageKey` when set. For callers that
36
+ * already computed the right adapter themselves (e.g. a per-record bucket resolved from
37
+ * that record's own fields, not from a registry key) rather than one registered globally.
38
+ */
39
+ storageProvider?: StorageProviderAdapter | null;
31
40
  }
32
- export declare const useFileUploadCore: ({ onFilesChange, onFileReady, uploadPath, srcsetWidths, initialFiles, }: UseFileUploadCoreOptions) => {
41
+ export declare const useFileUploadCore: ({ onFilesChange, onFileReady, uploadPath, srcsetWidths, initialFiles, storageKey, storageProvider, }: UseFileUploadCoreOptions) => {
33
42
  files: FileProps[];
34
43
  setFiles: React.Dispatch<React.SetStateAction<FileProps[]>>;
35
44
  fileInputRef: React.MutableRefObject<HTMLInputElement | null>;
@@ -46,6 +55,10 @@ export interface UploadDocumentProps extends FormFieldProps {
46
55
  max?: number;
47
56
  /** StorageProvider path — when set, files are auto-uploaded on selection. */
48
57
  uploadPath?: string;
58
+ /** Named storage provider slot to upload through — omit for the default. */
59
+ storageKey?: string;
60
+ /** Direct adapter instance — takes priority over `storageKey` when set. */
61
+ storageProvider?: StorageProviderAdapter | null;
49
62
  }
50
63
  export interface UploadImageProps extends UploadDocumentProps {
51
64
  previewHeight?: number;
@@ -56,5 +69,5 @@ export interface UploadImageProps extends UploadDocumentProps {
56
69
  srcsetWidths?: number[];
57
70
  }
58
71
  export declare const getFileUrl: (file: FileProps, suffix?: string) => string;
59
- export declare const UploadDocument: ({ name, onChange, label, required, editable, multiple, max, accept, uploadPath, before, after, wrapperClassName, className, }: UploadDocumentProps) => React.JSX.Element;
60
- export declare const UploadImage: ({ name, onChange, label, feedback, editable, multiple, accept, required, max, previewHeight, previewWidth, uploadPath, srcsetWidths, before, after, wrapperClassName, className, }: UploadImageProps) => React.JSX.Element;
72
+ export declare const UploadDocument: ({ name, onChange, label, required, editable, multiple, max, accept, uploadPath, storageKey, storageProvider, before, after, wrapperClassName, className, }: UploadDocumentProps) => React.JSX.Element;
73
+ export declare const UploadImage: ({ name, onChange, label, feedback, editable, multiple, accept, required, max, previewHeight, previewWidth, uploadPath, srcsetWidths, storageKey, storageProvider, before, after, wrapperClassName, className, }: UploadImageProps) => React.JSX.Element;
@@ -1,17 +1,13 @@
1
1
  import React from 'react';
2
2
  import { PromptVariables } from '../../conf/Prompt';
3
3
  import { type AIProviderAdapter, type AIRequestOptions, type AIAttachment } from '../../providers/ai/AIProvider';
4
+ import { RecordProps } from '../../providers/data/DataProvider';
5
+ import { type EditorCommand } from '../ui/fields/ContextMenu';
4
6
  import { FormFieldProps } from './Form';
5
7
  export declare enum PromptMode {
6
8
  EDIT = "edit",
7
9
  RUN = "run"
8
10
  }
9
- export type PromptCommand = {
10
- name: string;
11
- description?: string;
12
- icon?: string;
13
- handler?: (currentValue: string) => string | Promise<string>;
14
- };
15
11
  export type PromptAction = {
16
12
  key: string;
17
13
  icon: string;
@@ -33,6 +29,9 @@ export type PromptRunStats = {
33
29
  type PromptOptions = AIRequestOptions & {
34
30
  value: string;
35
31
  };
32
+ type PromptConfig = Partial<PromptOptions> & {
33
+ enabled?: boolean;
34
+ };
36
35
  type OnRunPrompt = (prompt: string, options: AIRequestOptions, data?: PromptVariables) => Promise<string>;
37
36
  type PromptDefaultValue = {
38
37
  value?: string;
@@ -51,26 +50,47 @@ type RenderAIUnavailable = (props: {
51
50
  reason?: string;
52
51
  configured: boolean;
53
52
  }) => React.ReactNode;
54
- type PromptSharedProps = FormFieldProps & {
53
+ interface PromptFieldBase {
54
+ name: string;
55
+ label?: string;
56
+ required?: boolean;
57
+ onChange?: FormFieldProps["onChange"];
58
+ before?: React.ReactNode;
59
+ after?: React.ReactNode;
60
+ wrapperClassName?: string;
61
+ className?: string;
55
62
  minHeight?: number;
56
63
  maxHeight?: number;
64
+ }
65
+ interface PromptWithAI extends PromptFieldBase {
57
66
  defaultValue?: PromptDefaultValue;
58
67
  renderAIUnavailable?: RenderAIUnavailable;
68
+ }
69
+ interface PromptEditorProps extends PromptWithAI {
70
+ value?: RecordProps & {
71
+ prompt?: PromptConfig;
72
+ };
73
+ }
74
+ interface PromptRunProps extends PromptWithAI {
75
+ value?: RecordProps & {
76
+ prompt?: PromptConfig;
77
+ };
59
78
  variables?: PromptVariables;
60
- };
61
- type PromptEditProps = PromptSharedProps & {
62
- mode?: PromptMode.EDIT;
63
- };
64
- type PromptRunProps = PromptSharedProps & {
65
- mode: PromptMode.RUN;
66
79
  onRunPrompt?: OnRunPrompt;
67
80
  renderFallback?: RenderPlainFallback;
68
- commands?: PromptCommand[];
81
+ commands?: EditorCommand[];
82
+ commandsTrigger?: string;
69
83
  attachments?: boolean;
70
84
  actions?: PromptAction[];
71
85
  statusItems?: PromptStatusItem[];
86
+ }
87
+ type PromptEditBranch = PromptEditorProps & {
88
+ mode?: PromptMode.EDIT;
89
+ };
90
+ type PromptRunBranch = PromptRunProps & {
91
+ mode: PromptMode.RUN;
72
92
  };
73
- export type PromptProps = PromptEditProps | PromptRunProps;
93
+ export type PromptProps = PromptEditBranch | PromptRunBranch;
74
94
  export declare const Prompt: ({ mode, ...props }: PromptProps) => React.JSX.Element;
75
95
  export declare const runPrompt: (options: PromptOptions, data?: PromptVariables, onRunPrompt?: OnRunPrompt, provider?: AIProviderAdapter, attachments?: AIAttachment[], messages?: {
76
96
  noProvider?: string;
@@ -2,7 +2,7 @@ import './globals.css';
2
2
  export { default as App, AppProvider } from './App';
3
3
  export { useMenu } from './App';
4
4
  export type { AppProps, AppProviderProps, AppProvidersConfig, MenuConfig } from './App';
5
- export type { AIConfig } from './Config';
5
+ export type { AIConfig, FirebaseConfig } from './Config';
6
6
  export type { ServicesConfig, SupabaseProviderConfig, GoogleProviderConfig, MockProviderConfig, DataDriverName, StorageDriverName, AuthDriverName, EmailDriverName, AIDriverName, } from './providers/manifest';
7
7
  export type { ProxyConfig } from './Config';
8
8
  export { Head, HeadProvider, DEFAULT_DOCUMENT_HEAD, DEFAULT_HEAD_APP_NAME, DEFAULT_LANGUAGE_HEAD, useAssetsHead, useDocumentHead, useHead, useHeadLinks, useLanguageHead, usePaginationHead, usePwaHead, useSchemaOrgHead, useSocialHead, } from './Head';
@@ -18,7 +18,7 @@ export type { DataProviderAdapter, FieldValue, RecordProps, RecordArray, Databas
18
18
  export type { OrderConfig, OrderDirection } from './libs/order';
19
19
  export { Order } from './libs/order';
20
20
  export { PromptUtils } from './libs/promptUtils';
21
- export type { PromptCommand, PromptAction, PromptStatusItem, PromptRunStats } from './components/widgets/Prompt';
21
+ export type { PromptAction, PromptStatusItem, PromptRunStats } from './components/widgets/Prompt';
22
22
  export type { TableHeaderProp, TableReorderHandler, TableReorderMeta, TableSelectionChangeHandler, TableSelectionState } from './components/ui/Table';
23
23
  export type { GalleryRecord, GallerySelectionChangeHandler, GallerySelectionState } from './components/ui/Gallery';
24
24
  export type { GridAction, GridActions, GridAfterActionArgs, GridAfterActionHandler, GridArrayProps, GridColumn, GridCoreProps, GridDBPath, GridDBQuery, GridDBProps, GridFooterContext, GridFormContext, GridGalleryViewProps, GridHeaderContext, GridLayout, GridMutationDeleteArgs, GridMutationDeleteHandler, GridMutationSaveArgs, GridMutationSaveHandler, GridReorderHandler, GridReorderMeta, GridRecordKey, GridProps, GridSelectionChangeHandler, GridSelectionMode, GridSelectionState, GridSticky, GridTableViewProps, GridCellContext, } from './components/widgets/Grid';
@@ -41,23 +41,32 @@ export type { MotionEffect, MotionReference, MotionRegistry, MotionStyle, Motion
41
41
  export { createMotionTransition, resolveMotionEffect, useEnterMotion, useMotionEffect, useMotionState, usePressMotion } from './motion';
42
42
  export { FirebaseDataProvider } from './providers/data/firebase';
43
43
  export { FirestoreDataProvider } from './providers/data/firestore';
44
+ export type { FirestoreDataProviderConfig } from './providers/data/firestore';
44
45
  export { SupabaseDataProvider } from './providers/data/supabase';
45
46
  export { MockDataProvider } from './providers/data/mock';
46
47
  export { useDataProvider, DataProvider } from './providers/data/DataProviderContext';
47
48
  export type { StorageProviderAdapter, UploadOptions, StorageOptions, DeleteOptions, MoveOptions, ListOptions, StorageFileInfo, UploadHandle } from './providers/storage/StorageProvider';
48
49
  export { FirebaseStorageProvider } from './providers/storage/firebase';
50
+ export type { FirebaseStorageProviderConfig } from './providers/storage/firebase';
49
51
  export { SupabaseStorageProvider } from './providers/storage/supabase';
50
52
  export { useStorageProvider, StorageProvider } from './providers/storage/StorageProviderContext';
51
53
  export type { AuthProviderAdapter, AuthIntent, AuthSignInOptions, UserProfile } from './providers/auth/AuthProvider';
52
54
  export { useAuthProvider, AuthProvider } from './providers/auth/AuthProviderContext';
53
55
  export { GoogleAuthProvider } from './providers/auth/google/GoogleAuthProvider';
56
+ export type { FirebaseAuthProviderOptions, FirebaseSignInOptions } from './providers/auth/firebase/FirebaseAuthProvider';
54
57
  export { FirebaseAuthProvider } from './providers/auth/firebase/FirebaseAuthProvider';
58
+ export { callFirebaseFunction } from './providers/firebase-init';
55
59
  export { SupabaseAuthProvider } from './providers/auth/supabase/SupabaseAuthProvider';
56
60
  export { DropboxAuthProvider } from './providers/auth/dropbox/DropboxAuthProvider';
57
61
  export type { CredentialsAdapter } from './providers/credentials/CredentialsProvider';
58
62
  export { useCredentialsProvider } from './providers/credentials/CredentialsProviderContext';
59
63
  export { GoogleServiceAccountProvider } from './providers/credentials/google/GoogleServiceAccountProvider';
60
64
  export type { EmailProviderAdapter, EmailSendParams } from './providers/email/EmailProvider';
65
+ export type { EmailProviderId } from './providers/email/definitions';
66
+ export { EMAIL_PROVIDER_DEFINITIONS } from './providers/email/definitions';
67
+ export type { BuildManifest, BuildArtifacts, DeployOptions, DeployResult, Deployment, PublishProviderAdapter } from './providers/publish/PublishProvider';
68
+ export type { PublishProviderId } from './providers/publish/definitions';
69
+ export { PUBLISH_PROVIDER_DEFINITIONS } from './providers/publish/definitions';
61
70
  export type { IconProviderAdapter, IconComponentProps } from './providers/icon/IconProvider';
62
71
  export { LucideIconProvider } from './providers/icon/LucideIconProvider';
63
72
  export { PhosphorIconProvider } from './providers/icon/PhosphorIconProvider';
@@ -66,8 +75,9 @@ export { IconProvider, useIconProvider, useIconController } from './providers/ic
66
75
  export type { AppIconProviderConfig, IconController } from './providers/icon/IconProviderContext';
67
76
  export { useEmailProvider, EmailProvider } from './providers/email/EmailProviderContext';
68
77
  export { GmailEmailProvider } from './providers/email/google/GmailEmailProvider';
69
- export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIModelCatalog } from './providers/ai';
70
- export { createAIProviderRegistry, getAIModelCatalog, formatAIModelRef, parseAIModelRef } from './providers/ai';
78
+ export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition } from './providers/ai';
79
+ export { createAIProviderRegistry, getAIModelCatalog, formatAIModelRef, parseAIModelRef, AI_PROVIDER_DEFINITIONS, AI_PROVIDER_DESCRIPTORS, OPENAI_COMPATIBLE_PROVIDER_DESCRIPTOR, toProviderDescriptor } from './providers/ai';
80
+ export type { ProviderDescriptor, ProviderCredentialField } from './providers/ProviderDescriptor';
71
81
  export { useAIProvider, useAIProviderRegistry, AIProvider } from './providers/ai/AIProviderContext';
72
82
  export { proxyFetch, useProxy, configureProxy, isProxyEnabled } from './providers/proxy';
73
83
  export { googleGetAccessToken } from './providers/auth/google/GoogleAuth';
@@ -0,0 +1,18 @@
1
+ export type ProviderCredentialField = {
2
+ key: string;
3
+ label: string;
4
+ type: 'text' | 'password' | 'textarea';
5
+ placeholder?: string;
6
+ };
7
+ export type ProviderDescriptor = {
8
+ id: string;
9
+ label: string;
10
+ description: string;
11
+ credentialFields: ProviderCredentialField[];
12
+ /** Where to go find/generate this credential (the provider's own dashboard/API keys page). */
13
+ credentialsUrl?: string;
14
+ /** Short guidance on where in that dashboard to look, when the URL alone isn't obvious. */
15
+ credentialsHint?: string;
16
+ /** Numbered walkthrough for setups too involved for a one-line hint (e.g. multi-console flows). Rendered instead of credentialsHint when present. */
17
+ credentialsSteps?: string[];
18
+ };
@@ -1,9 +1,20 @@
1
1
  import type { AIConfig } from '../../Config';
2
+ import type { ProviderDescriptor } from '../ProviderDescriptor';
2
3
  import type { AIProviderAdapter } from './AIProvider';
3
4
  import { type AIProviderDefinition } from './shared';
4
5
  export type { AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIRequestOptions, AIAttachment } from './AIProvider';
5
6
  export { formatAIModelRef, parseAIModelRef } from './AIProvider';
6
- export type { AIModelCatalog } from './shared';
7
+ export type { AIModelCatalog, AIProviderDefinition } from './shared';
7
8
  export { getAIModelCatalog } from './shared';
8
9
  export declare const AI_PROVIDER_DEFINITIONS: AIProviderDefinition[];
10
+ /** Generic "connect this provider" view of an AIProviderDefinition — the shape a CMS/admin
11
+ * UI needs (label, description, credential fields, where to find them), independent of the
12
+ * runtime completion contract (discoverModels/complete) it also carries. */
13
+ export declare const toProviderDescriptor: (definition: AIProviderDefinition) => ProviderDescriptor;
14
+ export declare const AI_PROVIDER_DESCRIPTORS: ProviderDescriptor[];
15
+ /** The user-configurable "bring your own endpoint" slot — metadata-only counterpart of the
16
+ * dynamic definition getDynamicAIProviderDefinitions() builds once a baseUrl is actually
17
+ * known. Not part of AI_PROVIDER_DEFINITIONS (there's nothing to build a working adapter
18
+ * from until the user supplies that URL), but a "connect" UI still needs to offer it. */
19
+ export declare const OPENAI_COMPATIBLE_PROVIDER_DESCRIPTOR: ProviderDescriptor;
9
20
  export declare const createAIProviderRegistry: (aiConfig?: AIConfig) => Record<string, AIProviderAdapter>;
@@ -2,6 +2,7 @@ import type { AIProviderDefinition, BuiltInAIProviderId } from './shared';
2
2
  type OpenAICompatibleDefinitionOptions = {
3
3
  id: BuiltInAIProviderId;
4
4
  label: string;
5
+ description: string;
5
6
  configKey: string;
6
7
  requiredConfigKeys?: string[];
7
8
  defaultModel: string;
@@ -10,8 +11,9 @@ type OpenAICompatibleDefinitionOptions = {
10
11
  modelsUrl?: string;
11
12
  chatCompletionsUrl?: string;
12
13
  dashboardUrl?: string;
14
+ credentialsHint?: string;
13
15
  /** Override the default validateApiKey when the models endpoint is public or uses a non-standard error format. */
14
16
  validateApiKey?: AIProviderDefinition['validateApiKey'];
15
17
  };
16
- export declare const createOpenAICompatibleProviderDefinition: ({ id, label, configKey, requiredConfigKeys, defaultModel, fallbackModels, baseUrl, modelsUrl, chatCompletionsUrl, dashboardUrl, validateApiKey: validateApiKeyOverride, }: OpenAICompatibleDefinitionOptions) => AIProviderDefinition;
18
+ export declare const createOpenAICompatibleProviderDefinition: ({ id, label, description, configKey, requiredConfigKeys, defaultModel, fallbackModels, baseUrl, modelsUrl, chatCompletionsUrl, dashboardUrl, credentialsHint, validateApiKey: validateApiKeyOverride, }: OpenAICompatibleDefinitionOptions) => AIProviderDefinition;
17
19
  export {};
@@ -1,15 +1,24 @@
1
1
  import { type ProviderConfigurationState } from '../ProviderConfiguration';
2
+ import type { ProviderCredentialField } from '../ProviderDescriptor';
2
3
  import type { AICompleteRequest, AIKeyValidationResult, AIModelDescriptor, AIProviderAdapter, AIProviderCapabilities, AIRequestOptions } from './AIProvider';
3
4
  export type BuiltInAIProviderId = 'openai' | 'openrouter' | 'opencode' | 'openai-compatible' | 'deepseek' | 'gemini' | 'anthropic' | 'mistral' | 'glm';
4
5
  export type AIProviderDefinition = {
5
6
  id: BuiltInAIProviderId;
6
7
  label: string;
8
+ /** One-line description shown in a "connect this provider" UI. */
9
+ description?: string;
7
10
  configKey?: string;
8
11
  requiredConfigKeys?: string[];
9
12
  defaultModel: string;
10
13
  fallbackModels: string[];
11
- /** URL to the provider's API key management page (shown in UI on validation error). */
14
+ /** URL to the provider's API key management page (shown in UI on validation error, and
15
+ * surfaced as ProviderDescriptor.credentialsUrl via toProviderDescriptor()). */
12
16
  dashboardUrl?: string;
17
+ /** Credential fields a "connect" UI should collect (defaults to a single apiKey field
18
+ * when omitted — see toProviderDescriptor() in ./index.ts). */
19
+ credentialFields?: ProviderCredentialField[];
20
+ /** Short guidance on where in the dashboard to find the credential. */
21
+ credentialsHint?: string;
13
22
  capabilities?: Omit<AIProviderCapabilities, 'models'>;
14
23
  discoverModels: (apiKey: string) => Promise<string[]>;
15
24
  complete: (apiKey: string, request: Required<Pick<AICompleteRequest, 'prompt' | 'model'>> & AIRequestOptions) => Promise<string | null>;
@@ -19,4 +19,12 @@ export interface AuthProviderAdapter extends ProviderConfigurable {
19
19
  onAuthChange(callback: (user: UserProfile | null) => void): () => void;
20
20
  getAccessToken?(scopes?: string[]): Promise<string>;
21
21
  isAuthenticated?(): boolean;
22
+ /**
23
+ * Custom claims embedded in the current session's token (e.g. a JWT's payload),
24
+ * for providers backed by one — Firebase custom claims, a Supabase JWT, etc.
25
+ * Optional: providers with no token-claims concept (e.g. plain OAuth) omit it.
26
+ * Read-only/UI convenience — never a security boundary, the server always
27
+ * re-verifies the raw token itself rather than trusting client-read claims.
28
+ */
29
+ getIdTokenClaims?(): Promise<Record<string, unknown> | null>;
22
30
  }
@@ -1,5 +1,6 @@
1
1
  import type { AuthProviderAdapter, AuthSignInOptions, UserProfile } from '../AuthProvider';
2
2
  import type { ProviderConfigurationState } from '../../ProviderConfiguration';
3
+ import type { FirebaseConfig } from '../../../Config';
3
4
  /**
4
5
  * Firebase-specific sign-in options.
5
6
  *
@@ -14,7 +15,28 @@ export interface FirebaseSignInOptions extends AuthSignInOptions {
14
15
  password?: string;
15
16
  provider?: string;
16
17
  }
18
+ export interface FirebaseAuthProviderOptions {
19
+ /**
20
+ * Static config for this provider's own Firebase app. Omit when relying on
21
+ * another consumer (e.g. providers.firebase + FirebaseDataProvider, or the
22
+ * tenant-switching session factories in ProviderSession.tsx) to have already
23
+ * initialized the target app — matches the provider's original zero-arg behavior.
24
+ */
25
+ config?: FirebaseConfig;
26
+ /**
27
+ * Firebase app name this provider's session lives under. Defaults to the SDK's
28
+ * unnamed default app. Give this a dedicated name (e.g. 'control-plane') when a
29
+ * long-lived login session must coexist with the default app used by tenant
30
+ * switching — ProviderSession's 'data'/'storage' firebase factories reinitialize
31
+ * the default app on every switch, which would otherwise tear down this session.
32
+ */
33
+ appName?: string;
34
+ }
17
35
  export declare class FirebaseAuthProvider implements AuthProviderAdapter {
36
+ private readonly options;
37
+ private readonly appName?;
38
+ private readonly initPromise;
39
+ constructor(options?: FirebaseAuthProviderOptions);
18
40
  getConfigurationState(): ProviderConfigurationState;
19
41
  isConfigured(): boolean;
20
42
  getUser(): UserProfile | null;
@@ -23,4 +45,5 @@ export declare class FirebaseAuthProvider implements AuthProviderAdapter {
23
45
  signOut(): Promise<void>;
24
46
  onAuthChange(callback: (user: UserProfile | null) => void): () => void;
25
47
  getAccessToken(): Promise<string>;
48
+ getIdTokenClaims(): Promise<Record<string, unknown> | null>;
26
49
  }
@@ -1,8 +1,15 @@
1
1
  import { DataProviderAdapter, DatabaseOptions, ReadOptions, SetChunksOptions, RecordProps } from './DataProvider';
2
2
  import type { ProviderConfigurationState } from '../ProviderConfiguration';
3
+ export interface FirestoreDataProviderConfig {
4
+ /** Named database within the current app's project — omit for the "(default)" database. */
5
+ databaseId?: string;
6
+ }
3
7
  export declare class FirestoreDataProvider implements DataProviderAdapter {
4
8
  private static listenerRegistered;
5
- constructor();
9
+ private databaseId?;
10
+ constructor(config?: FirestoreDataProviderConfig);
11
+ /** Same "(default)" database as before when no databaseId was configured. */
12
+ private getDb;
6
13
  getConfigurationState(): ProviderConfigurationState;
7
14
  isConfigured(): boolean;
8
15
  read: (path: string, { where, order, toArray, exception }?: ReadOptions) => Promise<any>;
@@ -0,0 +1,3 @@
1
+ import type { ProviderDescriptor } from '../ProviderDescriptor';
2
+ export type EmailProviderId = 'resend' | 'sendgrid' | 'mailgun' | 'postmark' | 'ses' | 'smtp';
3
+ export declare const EMAIL_PROVIDER_DEFINITIONS: ProviderDescriptor[];
@@ -2,10 +2,10 @@ import { type FirebaseApp } from 'firebase/app';
2
2
  import { type Auth } from "firebase/auth";
3
3
  import { FirebaseConfig } from "../Config";
4
4
  import { type ProviderConfigurationState } from "./ProviderConfiguration";
5
- export declare const setFirebaseConfigState: (config: FirebaseConfig | undefined) => void;
6
- export declare const getFirebaseConfigurationState: () => ProviderConfigurationState;
7
- export declare const getFirestoreConfigurationState: () => ProviderConfigurationState;
8
- export declare const getSafeAuth: () => Auth | null;
5
+ export declare const setFirebaseConfigState: (config: FirebaseConfig | undefined, appName?: string) => void;
6
+ export declare const getFirebaseConfigurationState: (appName?: string) => ProviderConfigurationState;
7
+ export declare const getFirestoreConfigurationState: (appName?: string) => ProviderConfigurationState;
8
+ export declare const getSafeAuth: (appName?: string) => Auth | null;
9
9
  export declare const getFirebaseAuthorization: () => Promise<boolean>;
10
10
  /**
11
11
  * Signs into the currently-initialized Firebase app using a custom token minted
@@ -17,5 +17,11 @@ export declare const getFirebaseAuthorization: () => Promise<boolean>;
17
17
  * Call init(config) to point the app at the right project *before* calling this.
18
18
  */
19
19
  export declare const signInWithFirebaseCustomToken: (token: string) => Promise<boolean>;
20
- declare const init: (config: FirebaseConfig) => Promise<FirebaseApp>;
20
+ declare const init: (config: FirebaseConfig, appName?: string) => Promise<FirebaseApp>;
21
+ /**
22
+ * Invokes a Firebase Callable Function against a given app (the SDK auto-attaches
23
+ * that app's current auth session's ID token — no manual header wiring). Lazily
24
+ * imports 'firebase/functions' so it's not bundled for apps that never call one.
25
+ */
26
+ export declare function callFirebaseFunction<T = unknown>(functionName: string, data: unknown, appName?: string, region?: string): Promise<T>;
21
27
  export default init;
@@ -0,0 +1,29 @@
1
+ import type { ProviderConfigurable } from '../ProviderConfiguration';
2
+ export interface BuildManifest {
3
+ pages: number;
4
+ sizeBytes: number;
5
+ generatedAt: string;
6
+ }
7
+ export interface BuildArtifacts {
8
+ buildId: string;
9
+ outputPath: string;
10
+ manifest: BuildManifest;
11
+ }
12
+ export type DeployOptions = Record<string, never>;
13
+ export interface DeployResult {
14
+ success: boolean;
15
+ buildId: string;
16
+ url?: string;
17
+ error?: string;
18
+ }
19
+ export interface Deployment {
20
+ buildId: string;
21
+ timestamp: string;
22
+ status: 'success' | 'failed' | 'in_progress';
23
+ url?: string;
24
+ }
25
+ export interface PublishProviderAdapter extends ProviderConfigurable {
26
+ deploy(artifacts: BuildArtifacts, options?: DeployOptions): Promise<DeployResult>;
27
+ rollback(buildId: string): Promise<DeployResult>;
28
+ getDeployments(limit?: number): Promise<Deployment[]>;
29
+ }
@@ -0,0 +1,3 @@
1
+ import type { ProviderDescriptor } from '../ProviderDescriptor';
2
+ export type PublishProviderId = 'cloudflare_pages' | 'firebase_hosting' | 'supabase_storage' | 'ftp' | 'sftp' | 'netlify' | 'github_pages' | 's3_cloudfront' | 'static_export';
3
+ export declare const PUBLISH_PROVIDER_DEFINITIONS: ProviderDescriptor[];
@@ -1,8 +1,14 @@
1
1
  import type { StorageProviderAdapter, UploadOptions, StorageOptions, DeleteOptions, MoveOptions, ListOptions, StorageFileInfo, UploadHandle } from './StorageProvider';
2
2
  import type { ProviderConfigurationState } from '../ProviderConfiguration';
3
+ export interface FirebaseStorageProviderConfig {
4
+ /** Used when a call doesn't pass its own `opts.bucket` — omit for the project's default bucket. */
5
+ defaultBucket?: string;
6
+ }
3
7
  export declare class FirebaseStorageProvider implements StorageProviderAdapter {
4
8
  private static listenerRegistered;
5
- constructor();
9
+ private defaultBucket?;
10
+ constructor(config?: FirebaseStorageProviderConfig);
11
+ private resolveBucket;
6
12
  getConfigurationState(): ProviderConfigurationState;
7
13
  isConfigured(): boolean;
8
14
  upload: (file: string | File | Blob, path: string, opts?: UploadOptions) => Promise<string | undefined>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnative/react",
3
- "version": "1.0.0",
3
+ "version": "1.1.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",
@@ -15,18 +15,20 @@
15
15
  "./vite": "./dist/vite.mjs",
16
16
  "./dist/index.css": "./dist/index.css"
17
17
  },
18
- "scripts": {
19
- "prebuild": "node scripts/dev/build-local.js --restore-only",
20
- "themes:compile:vscode": "node scripts/themes/compile-vscode-themes.js",
21
- "build": "npm run themes:compile:vscode && vite build && tsc --emitDeclarationOnly",
22
- "build:dev": "npm run themes:compile:vscode && vite build --mode development && tsc --emitDeclarationOnly",
18
+ "scripts": {
19
+ "prebuild": "node scripts/dev/build-local.js --restore-only",
20
+ "themes:compile:vscode": "node scripts/themes/compile-vscode-themes.js",
21
+ "build": "npm run themes:compile:vscode && vite build && tsc --emitDeclarationOnly",
22
+ "build:dev": "npm run themes:compile:vscode && vite build --mode development && tsc --emitDeclarationOnly",
23
23
  "watch:dev": "vite build --watch",
24
24
  "build:local": "node scripts/dev/build-local.js",
25
25
  "prepublishOnly": "npm run build",
26
26
  "updateReadme": "node scripts/dev/updateReadme.js",
27
27
  "test": "vitest run",
28
+ "test:e2e": "npx playwright test",
28
29
  "test:e2e:proxy-scaffold": "node scripts/e2e/test-proxy-scaffold.js",
29
30
  "test:e2e:proxy-runtime": "vitest run tests/e2e/proxy-runtime.test.ts --environment node",
31
+ "test:integration": "npx firebase emulators:exec --only database,firestore,storage --project demo-test \"npx vitest run --config vitest.integration.config.mts\"",
30
32
  "test:watch": "vitest",
31
33
  "test:coverage": "vitest run --coverage"
32
34
  },
@@ -91,9 +93,12 @@
91
93
  "@babel/preset-env": "^7.25.7",
92
94
  "@babel/preset-react": "^7.25.7",
93
95
  "@babel/preset-typescript": "^7.25.7",
96
+ "@firebase/rules-unit-testing": "^5.0.1",
94
97
  "@phosphor-icons/react": "^2.1.10",
98
+ "@playwright/test": "^1.61.1",
95
99
  "@supabase/supabase-js": "^2.107.0",
96
100
  "@tailwindcss/postcss": "^4.2.4",
101
+ "@testing-library/dom": "^10.4.1",
97
102
  "@testing-library/jest-dom": "^6.9.1",
98
103
  "@testing-library/react": "^16.3.2",
99
104
  "@testing-library/user-event": "^14.6.1",
@@ -103,6 +108,7 @@
103
108
  "@types/react-dom": "^18.2.0",
104
109
  "@vitest/coverage-v8": "2.1",
105
110
  "autoprefixer": "^10.5.0",
111
+ "firebase": "^12.0.0",
106
112
  "googleapis": "^171.4.0",
107
113
  "happy-dom": "^20.9.0",
108
114
  "jsdom": "^29.1.1",
@@ -114,7 +120,8 @@
114
120
  "tailwindcss": "^4.2.4",
115
121
  "typescript": "^5.6.2",
116
122
  "vite": "^5.4.21",
117
- "vitest": "2.1"
123
+ "vitest": "2.1",
124
+ "ws": "^8.21.0"
118
125
  },
119
126
  "dependencies": {
120
127
  "@codemirror/autocomplete": "^6.20.3",