@llmnative/react 0.1.1 → 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 (185) hide show
  1. package/README.md +397 -364
  2. package/bin/cli.js +117 -98
  3. package/dist/index.css +1 -1
  4. package/dist/index.js +21 -823
  5. package/dist/index.mjs +14984 -9345
  6. package/dist/style.css +1 -0
  7. package/dist/types/src/App.d.ts +75 -14
  8. package/dist/types/src/Config.d.ts +28 -5
  9. package/dist/types/src/Global.d.ts +2 -2
  10. package/dist/types/src/I18n.d.ts +186 -0
  11. package/dist/types/src/Theme.d.ts +153 -81
  12. package/dist/types/src/auth.d.ts +13 -1
  13. package/dist/types/src/components/Component.d.ts +13 -27
  14. package/dist/types/src/components/ErrorBoundary.d.ts +30 -0
  15. package/dist/types/src/components/blocks/Brand.d.ts +9 -4
  16. package/dist/types/src/components/blocks/Breadcrumbs.d.ts +50 -4
  17. package/dist/types/src/components/blocks/Carousel.d.ts +7 -5
  18. package/dist/types/src/components/blocks/Dropdown.d.ts +38 -20
  19. package/dist/types/src/components/blocks/ListCard.d.ts +38 -0
  20. package/dist/types/src/components/blocks/Menu.d.ts +15 -16
  21. package/dist/types/src/components/blocks/Notifications.d.ts +11 -3
  22. package/dist/types/src/components/blocks/ProviderSwitcher.d.ts +65 -0
  23. package/dist/types/src/components/blocks/Search.d.ts +3 -2
  24. package/dist/types/src/components/blocks/SideNav.d.ts +45 -0
  25. package/dist/types/src/components/blocks/ThemeSwitcher.d.ts +28 -0
  26. package/dist/types/src/components/blocks/Toolbar.d.ts +23 -0
  27. package/dist/types/src/components/index.d.ts +28 -7
  28. package/dist/types/src/components/types.d.ts +10 -3
  29. package/dist/types/src/components/ui/Alert.d.ts +20 -4
  30. package/dist/types/src/components/ui/Badge.d.ts +12 -5
  31. package/dist/types/src/components/ui/Buttons.d.ts +16 -12
  32. package/dist/types/src/components/ui/Card.d.ts +11 -7
  33. package/dist/types/src/components/ui/Code.d.ts +5 -1
  34. package/dist/types/src/components/ui/Gallery.d.ts +16 -16
  35. package/dist/types/src/components/ui/GridSystem.d.ts +5 -2
  36. package/dist/types/src/components/ui/Icon.d.ts +6 -1
  37. package/dist/types/src/components/ui/Image.d.ts +7 -1
  38. package/dist/types/src/components/ui/ImageAvatar.d.ts +4 -1
  39. package/dist/types/src/components/ui/Loader.d.ts +3 -1
  40. package/dist/types/src/components/ui/LocaleSwitcher.d.ts +14 -0
  41. package/dist/types/src/components/ui/Modal.d.ts +46 -15
  42. package/dist/types/src/components/ui/Pagination.d.ts +16 -3
  43. package/dist/types/src/components/ui/Percentage.d.ts +14 -5
  44. package/dist/types/src/components/ui/Repeat.d.ts +14 -6
  45. package/dist/types/src/components/ui/Tab.d.ts +29 -2
  46. package/dist/types/src/components/ui/TabDynamic.d.ts +4 -3
  47. package/dist/types/src/components/ui/Table.d.ts +18 -14
  48. package/dist/types/src/components/ui/fields/CodeEditor.d.ts +46 -0
  49. package/dist/types/src/components/ui/fields/ContextMenu.d.ts +87 -0
  50. package/dist/types/src/components/ui/fields/Crop.d.ts +4 -2
  51. package/dist/types/src/components/ui/fields/ImageField.d.ts +31 -0
  52. package/dist/types/src/components/ui/fields/Input.d.ts +43 -14
  53. package/dist/types/src/components/ui/fields/Prompt.d.ts +2 -31
  54. package/dist/types/src/components/ui/fields/RichText.d.ts +89 -0
  55. package/dist/types/src/components/ui/fields/Select.d.ts +13 -10
  56. package/dist/types/src/components/ui/fields/Upload.d.ts +50 -2
  57. package/dist/types/src/components/ui/fields/UploadCSV.d.ts +2 -0
  58. package/dist/types/src/components/ui/useRecordSelection.d.ts +1 -2
  59. package/dist/types/src/components/widgets/Form.d.ts +80 -43
  60. package/dist/types/src/components/widgets/ImageEditor.d.ts +4 -5
  61. package/dist/types/src/components/widgets/MarkdownReader.d.ts +4 -4
  62. package/dist/types/src/components/widgets/Prompt.d.ts +90 -22
  63. package/dist/types/src/components/widgets/TabDynamic.d.ts +4 -3
  64. package/dist/types/src/components/widgets/form-controller.d.ts +42 -0
  65. package/dist/types/src/components/widgets/grid-core/GridCore.d.ts +1 -1
  66. package/dist/types/src/components/widgets/grid-core/GridDB.d.ts +1 -1
  67. package/dist/types/src/components/widgets/grid-core/GridGalleryView.d.ts +1 -1
  68. package/dist/types/src/components/widgets/grid-core/GridTableView.d.ts +1 -1
  69. package/dist/types/src/components/widgets/grid-core/types.d.ts +77 -27
  70. package/dist/types/src/components/widgets/grid-core/useGridActions.d.ts +4 -8
  71. package/dist/types/src/components/widgets/grid-core/useGridColumns.d.ts +2 -2
  72. package/dist/types/src/components/widgets/grid-core/useGridDBRecords.d.ts +1 -2
  73. package/dist/types/src/components/widgets/grid-core/useGridPreparedRecords.d.ts +2 -2
  74. package/dist/types/src/components/widgets/grid-core/useGridSelection.d.ts +4 -5
  75. package/dist/types/src/components/widgets/grid-core/utils.d.ts +11 -3
  76. package/dist/types/src/conf/Prompt.d.ts +1 -1
  77. package/dist/types/src/conf/i18n/ar.d.ts +2 -0
  78. package/dist/types/src/conf/i18n/de.d.ts +2 -0
  79. package/dist/types/src/conf/i18n/en.d.ts +2 -0
  80. package/dist/types/src/conf/i18n/index.d.ts +6 -0
  81. package/dist/types/src/conf/i18n/it.d.ts +2 -0
  82. package/dist/types/src/conf/i18n/ru.d.ts +2 -0
  83. package/dist/types/src/conf/i18n/zh.d.ts +2 -0
  84. package/dist/types/src/constant.d.ts +1 -1
  85. package/dist/types/src/index.d.ts +48 -13
  86. package/dist/types/src/libs/converter.d.ts +4 -4
  87. package/dist/types/src/libs/editorHeight.d.ts +12 -0
  88. package/dist/types/src/libs/fetch.d.ts +4 -4
  89. package/dist/types/src/libs/imageBuilder.d.ts +63 -14
  90. package/dist/types/src/libs/imageVariants.d.ts +35 -0
  91. package/dist/types/src/libs/index.d.ts +1 -4
  92. package/dist/types/src/libs/promptUtils.d.ts +24 -0
  93. package/dist/types/src/libs/sanitizer.d.ts +2 -2
  94. package/dist/types/src/libs/utils.d.ts +9 -10
  95. package/dist/types/src/pages/index.d.ts +0 -2
  96. package/dist/types/src/providers/ProviderConfiguration.d.ts +6 -0
  97. package/dist/types/src/providers/ProviderDescriptor.d.ts +18 -0
  98. package/dist/types/src/providers/ProviderRegistryContext.d.ts +51 -0
  99. package/dist/types/src/providers/ProviderSession.d.ts +68 -0
  100. package/dist/types/src/providers/ai/AIProvider.d.ts +57 -0
  101. package/dist/types/src/providers/ai/AIProviderContext.d.ts +13 -0
  102. package/dist/types/src/providers/ai/anthropic.d.ts +2 -0
  103. package/dist/types/src/providers/ai/deepseek.d.ts +1 -0
  104. package/dist/types/src/providers/ai/gemini.d.ts +2 -0
  105. package/dist/types/src/providers/ai/glm.d.ts +1 -0
  106. package/dist/types/src/providers/ai/index.d.ts +20 -134
  107. package/dist/types/src/providers/ai/mistral.d.ts +1 -0
  108. package/dist/types/src/providers/ai/openai.d.ts +1 -0
  109. package/dist/types/src/providers/ai/openaiCompatible.d.ts +19 -0
  110. package/dist/types/src/providers/ai/opencode.d.ts +2 -0
  111. package/dist/types/src/providers/ai/openrouter.d.ts +1 -0
  112. package/dist/types/src/providers/ai/shared.d.ts +55 -0
  113. package/dist/types/src/providers/api/ApiProvider.d.ts +43 -0
  114. package/dist/types/src/providers/api/direct.d.ts +14 -0
  115. package/dist/types/src/providers/api/firebase.d.ts +14 -0
  116. package/dist/types/src/providers/api/mock.d.ts +7 -0
  117. package/dist/types/src/providers/api/supabase.d.ts +14 -0
  118. package/dist/types/src/providers/auth/AuthProvider.d.ts +10 -2
  119. package/dist/types/src/providers/auth/firebase/FirebaseAuthProvider.d.ts +49 -0
  120. package/dist/types/src/providers/auth/google/GoogleAuth.d.ts +2 -2
  121. package/dist/types/src/providers/auth/supabase/SupabaseAuthProvider.d.ts +48 -0
  122. package/dist/types/src/providers/credentials/CredentialsProvider.d.ts +3 -0
  123. package/dist/types/src/providers/credentials/CredentialsProviderContext.d.ts +12 -0
  124. package/dist/types/src/providers/credentials/google/GoogleServiceAccountProvider.d.ts +8 -0
  125. package/dist/types/src/providers/data/DataProvider.d.ts +27 -1
  126. package/dist/types/src/providers/data/firebase.d.ts +5 -4
  127. package/dist/types/src/providers/data/firestore.d.ts +45 -0
  128. package/dist/types/src/providers/data/mock.d.ts +8 -1
  129. package/dist/types/src/providers/data/supabase.d.ts +36 -10
  130. package/dist/types/src/providers/email/definitions.d.ts +3 -0
  131. package/dist/types/src/providers/firebase-init.d.ts +24 -7
  132. package/dist/types/src/providers/icon/PhosphorIconProvider.d.ts +1 -1
  133. package/dist/types/src/providers/manifest.d.ts +20 -14
  134. package/dist/types/src/providers/proxy/index.d.ts +7 -0
  135. package/dist/types/src/providers/proxy/vite.d.ts +3 -0
  136. package/dist/types/src/providers/publish/PublishProvider.d.ts +29 -0
  137. package/dist/types/src/providers/publish/definitions.d.ts +3 -0
  138. package/dist/types/src/providers/scrape/index.d.ts +2 -1
  139. package/dist/types/src/providers/seo/google/keyword.d.ts +6 -1
  140. package/dist/types/src/providers/storage/StorageProvider.d.ts +155 -4
  141. package/dist/types/src/providers/storage/dropbox.d.ts +3 -3
  142. package/dist/types/src/providers/storage/firebase.d.ts +44 -7
  143. package/dist/types/src/providers/storage/supabase.d.ts +47 -7
  144. package/dist/types/src/providers/supabase-init.d.ts +35 -0
  145. package/dist/types/src/types/FormFields.d.ts +4 -2
  146. package/dist/types/src/types/FormSchema.d.ts +29 -0
  147. package/dist/types/themes/tokyo-night-light.d.ts +3 -0
  148. package/dist/types/themes/tokyo-night.d.ts +3 -0
  149. package/dist/types/themes/vscode-dark-plus.d.ts +3 -0
  150. package/dist/types/themes/vscode-light-plus.d.ts +3 -0
  151. package/dist/vite.js +1 -0
  152. package/dist/vite.mjs +54 -0
  153. package/package.json +46 -8
  154. package/scripts/cli/proxy-templates/cloudflare.ts +34 -0
  155. package/scripts/cli/proxy-templates/express.ts +77 -0
  156. package/scripts/cli/proxy-templates/nextjs-app.ts +42 -0
  157. package/scripts/cli/proxy-templates/nextjs-pages.ts +41 -0
  158. package/scripts/cli/proxy-templates/scaffold.json +33 -0
  159. package/scripts/cli/setup-devtools.js +155 -85
  160. package/scripts/cli/setup-project.js +618 -484
  161. package/themes/cyber.ts +469 -405
  162. package/themes/default.ts +469 -405
  163. package/themes/flat.ts +469 -405
  164. package/themes/tokyo-night-light.ts +38 -0
  165. package/themes/tokyo-night.ts +38 -0
  166. package/themes/vscode-dark-plus.ts +29 -0
  167. package/themes/vscode-light-plus.ts +29 -0
  168. package/dist/index.js.map +0 -1
  169. package/dist/index.mjs.map +0 -1
  170. package/dist/types/src/components/FormEnhancer.d.ts +0 -26
  171. package/dist/types/src/components/Template.d.ts +0 -18
  172. package/dist/types/src/components/ui/fields/AssistantAI.d.ts +0 -23
  173. package/dist/types/src/components/ui/fields/Command.d.ts +0 -15
  174. package/dist/types/src/components/ui/fields/ImageUrl.d.ts +0 -7
  175. package/dist/types/src/libs/cache.d.ts +0 -9
  176. package/dist/types/src/libs/database.d.ts +0 -3
  177. package/dist/types/src/libs/log.d.ts +0 -2
  178. package/dist/types/src/libs/seo.d.ts +0 -8
  179. package/dist/types/src/libs/storage.d.ts +0 -2
  180. package/dist/types/src/pages/Blog.d.ts +0 -3
  181. package/dist/types/src/pages/BlogPost.d.ts +0 -16
  182. package/dist/types/src/pages/Helper.d.ts +0 -8
  183. package/dist/types/src/providers/auth/google/apis/auth.d.ts +0 -4
  184. package/dist/types/src/types/Block.d.ts +0 -4
  185. package/dist/types/src/types/Section.d.ts +0 -4
@@ -1,7 +1,158 @@
1
1
  import type { ProviderConfigurable } from '../ProviderConfiguration';
2
+ export interface UploadOptions {
3
+ /** Target bucket. Falls back to the provider's default bucket if omitted. */
4
+ bucket?: string;
5
+ /** MIME type hint (e.g. 'image/png'). Provider may infer it from the file when omitted. */
6
+ contentType?: string;
7
+ /** Called during upload with the completion percentage (0-100). */
8
+ onProgress?: (percent: number) => void;
9
+ }
10
+ export interface StorageOptions {
11
+ /** Target bucket. Falls back to the provider's default bucket if omitted. */
12
+ bucket?: string;
13
+ }
14
+ export interface DeleteOptions extends StorageOptions {
15
+ /**
16
+ * When true, deletes all files under the given path prefix (folder delete).
17
+ * Returns the total number of files deleted.
18
+ * Default: false - deletes a single file and returns 0 (not found) or 1 (deleted).
19
+ */
20
+ recursive?: boolean;
21
+ }
22
+ export interface MoveOptions extends StorageOptions {
23
+ /**
24
+ * Destination bucket. Falls back to the source bucket if omitted.
25
+ * Only relevant for cross-bucket moves.
26
+ */
27
+ destBucket?: string;
28
+ /**
29
+ * When true, treats `from` as a folder prefix and moves every file under it
30
+ * to the corresponding path under `to`. Returns the number of files moved.
31
+ * Default: false - moves a single file.
32
+ */
33
+ recursive?: boolean;
34
+ }
35
+ export interface ListOptions extends StorageOptions {
36
+ /** Traverse sub-folders and return files at any depth. Default: false (direct children only). */
37
+ recursive?: boolean;
38
+ /**
39
+ * Include file entries in the results.
40
+ * Default: true.
41
+ */
42
+ includeFiles?: boolean;
43
+ /**
44
+ * Include virtual folder/directory entries in the results.
45
+ * Default: false. When true, folder entries have isFolder: true.
46
+ */
47
+ includeFolders?: boolean;
48
+ /**
49
+ * Only return files whose extension matches.
50
+ * Case-insensitive. Pass a single string ('jpg') or an array (['jpg', 'png']).
51
+ * Has no effect on folder entries.
52
+ */
53
+ filterByExtension?: string | string[];
54
+ /**
55
+ * Maximum number of entries to return (applied after all other filters).
56
+ * Omit for no limit.
57
+ */
58
+ limit?: number;
59
+ /**
60
+ * When true, fetches size / contentType / updatedAt for each file.
61
+ * On Firebase this requires one extra network call per file (N+1).
62
+ * On Supabase metadata is always available at no extra cost.
63
+ * Default: false.
64
+ */
65
+ metadata?: boolean;
66
+ }
67
+ export interface StorageFileInfo {
68
+ /** Filename without the directory prefix. */
69
+ name: string;
70
+ /** Full path as stored in the provider (e.g. "images/avatar.png"). */
71
+ path: string;
72
+ size?: number;
73
+ contentType?: string;
74
+ updatedAt?: string;
75
+ /** Present and true when this entry represents a virtual folder (only when includeFolders: true). */
76
+ isFolder?: boolean;
77
+ }
78
+ /**
79
+ * Handle returned by createUpload - allows pause, resume and cancel mid-flight.
80
+ * pause() and resume() are no-ops on providers that do not support them (e.g. Supabase via fetch).
81
+ */
82
+ export interface UploadHandle {
83
+ /** Resolves to the public download URL when the upload completes, or undefined on failure/cancel. */
84
+ readonly url: Promise<string | undefined>;
85
+ /** Pauses the upload. No-op if the provider does not support it. */
86
+ pause(): void;
87
+ /** Resumes a paused upload. No-op if the provider does not support it. */
88
+ resume(): void;
89
+ /** Cancels the upload. Always supported. */
90
+ cancel(): void;
91
+ }
92
+ /**
93
+ * Common storage interface (Ports & Adapters).
94
+ * Concrete implementations: FirebaseStorageProvider, SupabaseStorageProvider.
95
+ *
96
+ * All methods accept an optional `opts.bucket` to target a specific bucket
97
+ * instead of the provider's configured default.
98
+ */
2
99
  export interface StorageProviderAdapter extends ProviderConfigurable {
3
- upload(file: string, path: string): Promise<string | undefined>;
4
- getURL(path: string): Promise<string | undefined>;
5
- download(path: string): Promise<Blob | undefined>;
6
- delete(path: string): Promise<boolean>;
100
+ /**
101
+ * Upload a file and return its public download URL.
102
+ * Accepts a data URL string, a File, or a Blob.
103
+ * Fire-and-forget: no pause/resume. Use createUpload() for controllable uploads.
104
+ */
105
+ upload(file: string | File | Blob, path: string, opts?: UploadOptions): Promise<string | undefined>;
106
+ /**
107
+ * Start a controllable upload and return a handle with pause / resume / cancel.
108
+ * pause() and resume() are no-ops on Supabase (only Firebase supports them natively).
109
+ */
110
+ createUpload(file: string | File | Blob, path: string, opts?: UploadOptions): UploadHandle;
111
+ /**
112
+ * Rename a file or folder in place (same parent directory, new name).
113
+ * For folder rename, set opts.recursive = true.
114
+ * Semantically equivalent to move() - use rename() when only the name changes,
115
+ * move() when relocating across directories or buckets.
116
+ * Returns true if at least one file was successfully renamed.
117
+ */
118
+ rename(from: string, to: string, opts?: MoveOptions): Promise<boolean>;
119
+ /**
120
+ * Move a file or folder to a different path, directory, or bucket.
121
+ * For folder move, set opts.recursive = true.
122
+ * Use opts.destBucket to move across buckets.
123
+ * Returns the number of files successfully moved (0 on failure, 1 for single file).
124
+ */
125
+ move(from: string, to: string, opts?: MoveOptions): Promise<number>;
126
+ /** Return the public download URL for a stored file. */
127
+ getURL(path: string, opts?: StorageOptions): Promise<string | undefined>;
128
+ /**
129
+ * Return metadata for a single file.
130
+ * Returns undefined if the file does not exist.
131
+ */
132
+ getFileInfo(path: string, opts?: StorageOptions): Promise<StorageFileInfo | undefined>;
133
+ /** Download a file as a Blob. */
134
+ download(path: string, opts?: StorageOptions): Promise<Blob | undefined>;
135
+ /**
136
+ * Delete a file or all files under a folder prefix.
137
+ * Returns the number of files deleted:
138
+ * - Single file (default): 0 if not found, 1 if deleted.
139
+ * - Folder (opts.recursive = true): total files deleted.
140
+ */
141
+ delete(path: string, opts?: DeleteOptions): Promise<number>;
142
+ /**
143
+ * List files (and optionally folders) under a path prefix.
144
+ *
145
+ * Key options:
146
+ * recursive - traverse sub-folders (default: false, direct children only)
147
+ * includeFiles - include file entries (default: true)
148
+ * includeFolders - include folder entries with isFolder: true (default: false)
149
+ * filterByExtension - case-insensitive extension filter: 'jpg' or ['jpg','png']
150
+ * limit - cap the number of results after all other filters
151
+ * metadata - fetch size/contentType/updatedAt (N+1 cost on Firebase)
152
+ */
153
+ list(path: string, opts?: ListOptions): Promise<StorageFileInfo[]>;
7
154
  }
155
+ /** Returns true if `filename` matches any of the allowed extensions. Case-insensitive. */
156
+ export declare function matchesExtension(filename: string, filter: string | string[]): boolean;
157
+ /** Apply limit and extension filter to a list of StorageFileInfo entries. */
158
+ export declare function applyListFilters(items: StorageFileInfo[], opts: ListOptions): StorageFileInfo[];
@@ -10,7 +10,7 @@ type PathEntry = {
10
10
  };
11
11
  type ThumbnailEntry = {
12
12
  path: string;
13
- [key: string]: any;
13
+ [key: string]: unknown;
14
14
  };
15
15
  type ThumbnailRequestOptions = {
16
16
  thumbnailsRequest: ThumbnailEntry[];
@@ -25,7 +25,7 @@ type ThumbnailResult = {
25
25
  mimetype: string;
26
26
  width: number;
27
27
  height: number;
28
- [key: string]: any;
28
+ [key: string]: unknown;
29
29
  };
30
30
  };
31
31
  export declare const resolvePath: (path: string, includeHost?: boolean) => string;
@@ -36,7 +36,7 @@ export declare const dropBox: {
36
36
  setRootPath: (path: string) => void;
37
37
  resolvePath: (path: string, includeHost?: boolean) => string;
38
38
  createFolders: (paths: string[], basePath?: string) => Promise<any>;
39
- deleteBulk: (paths: string[], basePath?: string) => Promise<any>;
39
+ deleteBulk: (paths: string[], basePath?: string) => Promise<unknown[] | undefined>;
40
40
  addTags: (paths: Record<string, string[]>, basePath?: string) => Promise<void>;
41
41
  listFolders: ({ path, recursive }?: ListFoldersParams) => Promise<any[]>;
42
42
  getThumbnails: ({ thumbnailsRequest, size, format, mode, }: ThumbnailRequestOptions, setThumbnails?: (thumbs: ThumbnailResult) => void) => Promise<ThumbnailResult>;
@@ -1,13 +1,50 @@
1
- import "firebase/compat/storage";
2
- import { StorageProviderAdapter } from "./StorageProvider";
3
- import type { ProviderConfigurationState } from "../ProviderConfiguration";
1
+ import type { StorageProviderAdapter, UploadOptions, StorageOptions, DeleteOptions, MoveOptions, ListOptions, StorageFileInfo, UploadHandle } from './StorageProvider';
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
+ }
4
7
  export declare class FirebaseStorageProvider implements StorageProviderAdapter {
8
+ private static listenerRegistered;
9
+ private defaultBucket?;
10
+ constructor(config?: FirebaseStorageProviderConfig);
11
+ private resolveBucket;
5
12
  getConfigurationState(): ProviderConfigurationState;
6
13
  isConfigured(): boolean;
7
- upload: (file: string, path: string) => Promise<string | undefined>;
8
- getURL: (path: string) => Promise<string | undefined>;
9
- download: (path: string) => Promise<Blob | undefined>;
10
- delete: (path: string) => Promise<boolean>;
14
+ upload: (file: string | File | Blob, path: string, opts?: UploadOptions) => Promise<string | undefined>;
15
+ createUpload: (file: string | File | Blob, path: string, opts?: UploadOptions) => UploadHandle;
16
+ /**
17
+ * Rename a file or folder. Semantically: change the name in place.
18
+ * Internally identical to move() - Firebase has no native rename/move API.
19
+ */
20
+ rename: (from: string, to: string, opts?: MoveOptions) => Promise<boolean>;
21
+ /**
22
+ * Move a file or folder (download → upload to new path → delete old).
23
+ * Firebase has no native move/rename API.
24
+ * For folder moves, set opts.recursive = true.
25
+ * Returns the number of files successfully moved.
26
+ */
27
+ move: (from: string, to: string, opts?: MoveOptions) => Promise<number>;
28
+ private _moveFile;
29
+ getURL: (path: string, opts?: StorageOptions) => Promise<string | undefined>;
30
+ getFileInfo: (path: string, opts?: StorageOptions) => Promise<StorageFileInfo | undefined>;
31
+ download: (path: string, opts?: StorageOptions) => Promise<Blob | undefined>;
32
+ /**
33
+ * Delete a single file or all files under a folder prefix.
34
+ * Returns the number of files deleted (0 or 1 for single file, N for recursive).
35
+ */
36
+ delete: (path: string, opts?: DeleteOptions) => Promise<number>;
37
+ private _deleteFolder;
38
+ /**
39
+ * List files (and optionally folders) under a path prefix.
40
+ *
41
+ * Firebase note: the SDK's listAll() means "list all pages without pagination" -
42
+ * it is NOT recursive. Recursion over sub-folders is performed manually here.
43
+ *
44
+ * opts.metadata = true fetches size/contentType/updatedAt (one extra call per file).
45
+ */
46
+ list: (path: string, opts?: ListOptions) => Promise<StorageFileInfo[]>;
47
+ private _listLevel;
11
48
  }
12
49
  declare const _default: FirebaseStorageProvider;
13
50
  export default _default;
@@ -1,19 +1,59 @@
1
- import { StorageProviderAdapter } from "./StorageProvider";
2
- import { type ProviderConfigurationState } from "../ProviderConfiguration";
1
+ import type { StorageProviderAdapter, UploadOptions, StorageOptions, DeleteOptions, MoveOptions, ListOptions, StorageFileInfo, UploadHandle } from './StorageProvider';
2
+ import { type ProviderConfigurationState } from '../ProviderConfiguration';
3
3
  interface SupabaseStorageConfig {
4
4
  url: string;
5
5
  anonKey: string;
6
+ /** Default bucket name. Falls back to "public" if omitted. */
6
7
  bucket?: string;
8
+ /**
9
+ * Tenant-session JWT signed by the control-plane, scoped to this project.
10
+ * When present, requests authenticate as this session instead of the bare
11
+ * anon key — needed for RLS-protected buckets. `apikey` stays the anon key
12
+ * regardless (Supabase always requires it alongside the bearer token).
13
+ */
14
+ accessToken?: string;
7
15
  }
8
16
  export declare class SupabaseStorageProvider implements StorageProviderAdapter {
9
17
  private config;
10
18
  constructor(config: SupabaseStorageConfig);
11
19
  getConfigurationState(): ProviderConfigurationState;
12
20
  isConfigured(): boolean;
13
- private get bucket();
14
- upload: (file: string, path: string) => Promise<string | undefined>;
15
- getURL: (path: string) => Promise<string | undefined>;
16
- download: (path: string) => Promise<Blob | undefined>;
17
- delete: (path: string) => Promise<boolean>;
21
+ private resolveBucket;
22
+ private authHeaders;
23
+ upload: (file: string | File | Blob, path: string, opts?: UploadOptions) => Promise<string | undefined>;
24
+ /**
25
+ * Supabase upload with cancel support via AbortController.
26
+ * pause() and resume() are no-ops - Supabase fetch has no native pause/resume.
27
+ */
28
+ createUpload: (file: string | File | Blob, path: string, opts?: UploadOptions) => UploadHandle;
29
+ /**
30
+ * Rename a file or folder. Internally calls move().
31
+ * For Supabase, single-file rename uses the native move API (one round-trip).
32
+ */
33
+ rename: (from: string, to: string, opts?: MoveOptions) => Promise<boolean>;
34
+ /**
35
+ * Move a file or folder.
36
+ * Single file: uses Supabase's native move API (one round-trip).
37
+ * Folder (opts.recursive = true): lists all files then moves each via native API.
38
+ * Returns the number of files successfully moved.
39
+ */
40
+ move: (from: string, to: string, opts?: MoveOptions) => Promise<number>;
41
+ private _moveFile;
42
+ getURL: (path: string, opts?: StorageOptions) => Promise<string | undefined>;
43
+ getFileInfo: (path: string, opts?: StorageOptions) => Promise<StorageFileInfo | undefined>;
44
+ download: (path: string, opts?: StorageOptions) => Promise<Blob | undefined>;
45
+ /**
46
+ * Delete a single file or all files under a folder prefix.
47
+ * Uses Supabase's bulk-delete API - single request even for N files.
48
+ * Returns the number of files deleted.
49
+ */
50
+ delete: (path: string, opts?: DeleteOptions) => Promise<number>;
51
+ /**
52
+ * List files (and optionally folders) under a path prefix.
53
+ * Supabase always returns metadata in the same response (no N+1 cost).
54
+ * Folder entries have id === null in the Supabase response.
55
+ */
56
+ list: (path: string, opts?: ListOptions) => Promise<StorageFileInfo[]>;
57
+ private _listLevel;
18
58
  }
19
59
  export {};
@@ -0,0 +1,35 @@
1
+ import { type SupabaseClient } from '@supabase/supabase-js';
2
+ import { type ProviderConfigurationState } from './ProviderConfiguration';
3
+ /**
4
+ * Returns a shared SupabaseClient for the given project.
5
+ * One client per URL - subsequent calls with the same URL return the same instance.
6
+ * For single-project apps only. Multi-tenant session switching must use
7
+ * createSupabaseClient() instead — see below.
8
+ */
9
+ export declare function getSupabaseClient(url: string, anonKey: string): SupabaseClient;
10
+ /**
11
+ * Creates a fresh, uncached SupabaseClient scoped to one tenant session.
12
+ *
13
+ * Unlike getSupabaseClient(), this never persists a session (Supabase's default
14
+ * client persists to localStorage) and is never reused across calls — each tenant
15
+ * switch must produce a brand new instance with the freshly-resolved credential,
16
+ * never a stale one left over from a previous project.
17
+ *
18
+ * Supabase has no "sign in with custom token" step equivalent to Firebase: the
19
+ * control-plane mints a JWT signed with the tenant project's own JWT secret, and
20
+ * that JWT is simply attached as the Authorization header on every request —
21
+ * PostgREST/Realtime verify it directly, no separate session exchange call.
22
+ */
23
+ export declare function createSupabaseClient(url: string, anonKey: string, accessToken?: string): SupabaseClient;
24
+ /**
25
+ * Tears down a scoped client before it's discarded: force-closes any realtime
26
+ * channels a caller may have failed to unsubscribe from. Safety net, not a
27
+ * replacement for callers unsubscribing their own subscribe() calls.
28
+ */
29
+ export declare function disposeSupabaseClient(client: SupabaseClient): Promise<void>;
30
+ export declare function getSupabaseConfigurationState(config: {
31
+ url?: string;
32
+ anonKey?: string;
33
+ } | undefined): ProviderConfigurationState;
34
+ /** Clears all cached clients - useful for tests. */
35
+ export declare function _resetSupabaseClients(): void;
@@ -1,9 +1,10 @@
1
1
  import { FieldFactory } from "../components/Component";
2
2
  import { InputProps, TextAreaProps, CheckboxProps } from "../components/ui/fields/Input";
3
3
  import { SelectProps } from "../components/ui/fields/Select";
4
- import { ImageUrlProps } from "../components/ui/fields/ImageUrl";
4
+ import { ImageFieldProps } from "../components/ui/fields/ImageField";
5
5
  import { UploadDocumentProps, UploadImageProps } from "../components/ui/fields/Upload";
6
6
  import { PromptProps } from "../components/widgets/Prompt";
7
+ import { CodeEditorProps } from "../components/ui/fields/CodeEditor";
7
8
  export interface ComponentFormFieldsMap {
8
9
  string: FieldFactory<Partial<InputProps>>;
9
10
  number: FieldFactory<Partial<InputProps>>;
@@ -24,10 +25,11 @@ export interface ComponentFormFieldsMap {
24
25
  uploadImage: FieldFactory<Partial<UploadImageProps>>;
25
26
  uploadDocument: FieldFactory<Partial<UploadDocumentProps>>;
26
27
  prompt: FieldFactory<Partial<PromptProps>>;
27
- imageUrl: FieldFactory<Partial<ImageUrlProps>>;
28
+ imageField: FieldFactory<Partial<ImageFieldProps>>;
28
29
  menu: FieldFactory<{
29
30
  defaultValue?: string;
30
31
  }>;
32
+ codeEditor: FieldFactory<Partial<CodeEditorProps>>;
31
33
  }
32
34
  declare const componentFormFields: ComponentFormFieldsMap;
33
35
  export default componentFormFields;
@@ -0,0 +1,29 @@
1
+ import { FieldFactory } from "../components/Component";
2
+ import { InputProps, TextAreaProps, CheckboxProps } from "../components/ui/fields/Input";
3
+ import { SelectProps, AutocompleteProps, ChecklistProps } from "../components/ui/fields/Select";
4
+ import { UploadImageProps, UploadDocumentProps } from "../components/ui/fields/Upload";
5
+ import { ImageFieldProps } from "../components/ui/fields/ImageField";
6
+ type SchemaFields = Record<string, ReturnType<FieldFactory>>;
7
+ export interface ComponentFormSchemaMap {
8
+ string: (overrides?: Partial<InputProps>) => SchemaFields;
9
+ number: (overrides?: Partial<InputProps>) => SchemaFields;
10
+ email: (overrides?: Partial<InputProps>) => SchemaFields;
11
+ password: (overrides?: Partial<InputProps>) => SchemaFields;
12
+ color: (overrides?: Partial<InputProps>) => SchemaFields;
13
+ date: (overrides?: Partial<InputProps>) => SchemaFields;
14
+ time: (overrides?: Partial<InputProps>) => SchemaFields;
15
+ datetime: (overrides?: Partial<InputProps>) => SchemaFields;
16
+ week: (overrides?: Partial<InputProps>) => SchemaFields;
17
+ month: (overrides?: Partial<InputProps>) => SchemaFields;
18
+ textarea: (overrides?: Partial<TextAreaProps>) => SchemaFields;
19
+ checkbox: (overrides?: Partial<CheckboxProps>) => SchemaFields;
20
+ switch: (overrides?: Partial<CheckboxProps>) => SchemaFields;
21
+ select: (overrides?: Partial<SelectProps>) => SchemaFields;
22
+ autocomplete: (overrides?: Partial<AutocompleteProps>) => SchemaFields;
23
+ checklist: (overrides?: Partial<ChecklistProps>) => SchemaFields;
24
+ uploadImage: (overrides?: Partial<UploadImageProps>) => SchemaFields;
25
+ uploadDocument: (overrides?: Partial<UploadDocumentProps>) => SchemaFields;
26
+ imageField: (overrides?: Partial<ImageFieldProps>) => SchemaFields;
27
+ }
28
+ declare const componentFormSchema: ComponentFormSchemaMap;
29
+ export default componentFormSchema;
@@ -0,0 +1,3 @@
1
+ import type { ThemeDefinition } from '../src/Theme';
2
+ declare const definition: ThemeDefinition;
3
+ export default definition;
@@ -0,0 +1,3 @@
1
+ import type { ThemeDefinition } from '../src/Theme';
2
+ declare const definition: ThemeDefinition;
3
+ export default definition;
@@ -0,0 +1,3 @@
1
+ import type { ThemeDefinition } from '../src/Theme';
2
+ declare const definition: ThemeDefinition;
3
+ export default definition;
@@ -0,0 +1,3 @@
1
+ import type { ThemeDefinition } from '../src/Theme';
2
+ declare const definition: ThemeDefinition;
3
+ export default definition;
package/dist/vite.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u="x-llmnative-proxy",p="/api/proxy",h=async t=>{const e=[];for await(const r of t)e.push(Buffer.isBuffer(r)?r:Buffer.from(r));return e.length===0?void 0:Buffer.concat(e)},l=async(t,e,r)=>{const a=new URL(t.url||"/","http://localhost").searchParams.get("url");if(t.headers[u]!=="1"){e.statusCode=403,e.setHeader("Content-Type","application/json"),e.end(JSON.stringify({error:"Proxy access denied."}));return}if(!a){e.statusCode=400,e.setHeader("Content-Type","application/json"),e.end(JSON.stringify({error:'Missing "url" query parameter.'}));return}try{const o=new URL(a);if(o.pathname.startsWith(r)&&["localhost","127.0.0.1"].includes(o.hostname)){e.statusCode=508,e.setHeader("Content-Type","application/json"),e.end(JSON.stringify({error:"Recursive proxy target detected.",target:a}));return}const d=await h(t),f=new Headers,y=new Set([u,"host","origin","referer","content-length","transfer-encoding","connection"]);Object.entries(t.headers).forEach(([i,n])=>{!n||y.has(i.toLowerCase())||f.set(i,Array.isArray(n)?n.join(", "):n)});const c=await fetch(a,{method:t.method||"GET",headers:f,body:d&&!["GET","HEAD"].includes((t.method||"GET").toUpperCase())?d:void 0,redirect:"follow"});e.statusCode=c.status,c.headers.forEach((i,n)=>{n.toLowerCase()!=="content-encoding"&&e.setHeader(n,i)}),e.end(Buffer.from(await c.arrayBuffer()))}catch(o){e.statusCode=502,e.setHeader("Content-Type","application/json"),e.end(JSON.stringify({error:o instanceof Error?o.message:"Proxy request failed."}))}},g=(t=p)=>({name:"llmnative-dev-proxy",configureServer(e){e.middlewares.use(t,(r,s)=>{l(r,s,t)})},configurePreviewServer(e){e.middlewares.use(t,(r,s)=>{l(r,s,t)})}});exports.PROXY_PATH=p;exports.createProxyPlugin=g;
package/dist/vite.mjs ADDED
@@ -0,0 +1,54 @@
1
+ const u = "x-llmnative-proxy", l = "/api/proxy", y = async (t) => {
2
+ const e = [];
3
+ for await (const r of t)
4
+ e.push(Buffer.isBuffer(r) ? r : Buffer.from(r));
5
+ return e.length === 0 ? void 0 : Buffer.concat(e);
6
+ }, p = async (t, e, r) => {
7
+ const a = new URL(t.url || "/", "http://localhost").searchParams.get("url");
8
+ if (t.headers[u] !== "1") {
9
+ e.statusCode = 403, e.setHeader("Content-Type", "application/json"), e.end(JSON.stringify({ error: "Proxy access denied." }));
10
+ return;
11
+ }
12
+ if (!a) {
13
+ e.statusCode = 400, e.setHeader("Content-Type", "application/json"), e.end(JSON.stringify({ error: 'Missing "url" query parameter.' }));
14
+ return;
15
+ }
16
+ try {
17
+ const o = new URL(a);
18
+ if (o.pathname.startsWith(r) && ["localhost", "127.0.0.1"].includes(o.hostname)) {
19
+ e.statusCode = 508, e.setHeader("Content-Type", "application/json"), e.end(JSON.stringify({ error: "Recursive proxy target detected.", target: a }));
20
+ return;
21
+ }
22
+ const d = await y(t), f = new Headers(), h = /* @__PURE__ */ new Set([u, "host", "origin", "referer", "content-length", "transfer-encoding", "connection"]);
23
+ Object.entries(t.headers).forEach(([i, n]) => {
24
+ !n || h.has(i.toLowerCase()) || f.set(i, Array.isArray(n) ? n.join(", ") : n);
25
+ });
26
+ const c = await fetch(a, {
27
+ method: t.method || "GET",
28
+ headers: f,
29
+ body: d && !["GET", "HEAD"].includes((t.method || "GET").toUpperCase()) ? d : void 0,
30
+ redirect: "follow"
31
+ });
32
+ e.statusCode = c.status, c.headers.forEach((i, n) => {
33
+ n.toLowerCase() !== "content-encoding" && e.setHeader(n, i);
34
+ }), e.end(Buffer.from(await c.arrayBuffer()));
35
+ } catch (o) {
36
+ e.statusCode = 502, e.setHeader("Content-Type", "application/json"), e.end(JSON.stringify({ error: o instanceof Error ? o.message : "Proxy request failed." }));
37
+ }
38
+ }, g = (t = l) => ({
39
+ name: "llmnative-dev-proxy",
40
+ configureServer(e) {
41
+ e.middlewares.use(t, (r, s) => {
42
+ p(r, s, t);
43
+ });
44
+ },
45
+ configurePreviewServer(e) {
46
+ e.middlewares.use(t, (r, s) => {
47
+ p(r, s, t);
48
+ });
49
+ }
50
+ });
51
+ export {
52
+ l as PROXY_PATH,
53
+ g as createProxyPlugin
54
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnative/react",
3
- "version": "0.1.1",
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",
@@ -12,17 +12,23 @@
12
12
  "import": "./dist/index.mjs",
13
13
  "require": "./dist/index.js"
14
14
  },
15
+ "./vite": "./dist/vite.mjs",
15
16
  "./dist/index.css": "./dist/index.css"
16
17
  },
17
18
  "scripts": {
18
19
  "prebuild": "node scripts/dev/build-local.js --restore-only",
19
- "build": "vite build && tsc --emitDeclarationOnly",
20
- "build:dev": "vite build --mode development && tsc --emitDeclarationOnly",
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",
21
23
  "watch:dev": "vite build --watch",
22
24
  "build:local": "node scripts/dev/build-local.js",
23
25
  "prepublishOnly": "npm run build",
24
26
  "updateReadme": "node scripts/dev/updateReadme.js",
25
27
  "test": "vitest run",
28
+ "test:e2e": "npx playwright test",
29
+ "test:e2e:proxy-scaffold": "node scripts/e2e/test-proxy-scaffold.js",
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\"",
26
32
  "test:watch": "vitest",
27
33
  "test:coverage": "vitest run --coverage"
28
34
  },
@@ -65,11 +71,12 @@
65
71
  "homepage": "https://github.com/sherpadvisorylab/llmnative-react#readme",
66
72
  "peerDependencies": {
67
73
  "@phosphor-icons/react": "^2.0.0",
74
+ "@supabase/supabase-js": "^2.107.0",
68
75
  "firebase": "^10.14.0",
69
76
  "lucide-react": "^0.400.0",
70
- "react": "^18.2.0",
71
- "react-dom": "^18.2.0",
72
- "react-router-dom": "^6.22.0"
77
+ "react": "^19.0.0",
78
+ "react-dom": "^19.0.0",
79
+ "react-router-dom": "^6.30.0"
73
80
  },
74
81
  "peerDependenciesMeta": {
75
82
  "@phosphor-icons/react": {
@@ -86,8 +93,12 @@
86
93
  "@babel/preset-env": "^7.25.7",
87
94
  "@babel/preset-react": "^7.25.7",
88
95
  "@babel/preset-typescript": "^7.25.7",
96
+ "@firebase/rules-unit-testing": "^5.0.1",
89
97
  "@phosphor-icons/react": "^2.1.10",
98
+ "@playwright/test": "^1.61.1",
99
+ "@supabase/supabase-js": "^2.107.0",
90
100
  "@tailwindcss/postcss": "^4.2.4",
101
+ "@testing-library/dom": "^10.4.1",
91
102
  "@testing-library/jest-dom": "^6.9.1",
92
103
  "@testing-library/react": "^16.3.2",
93
104
  "@testing-library/user-event": "^14.6.1",
@@ -97,6 +108,7 @@
97
108
  "@types/react-dom": "^18.2.0",
98
109
  "@vitest/coverage-v8": "2.1",
99
110
  "autoprefixer": "^10.5.0",
111
+ "firebase": "^12.0.0",
100
112
  "googleapis": "^171.4.0",
101
113
  "happy-dom": "^20.9.0",
102
114
  "jsdom": "^29.1.1",
@@ -108,13 +120,36 @@
108
120
  "tailwindcss": "^4.2.4",
109
121
  "typescript": "^5.6.2",
110
122
  "vite": "^5.4.21",
111
- "vitest": "2.1"
123
+ "vitest": "2.1",
124
+ "ws": "^8.21.0"
112
125
  },
113
126
  "dependencies": {
127
+ "@codemirror/autocomplete": "^6.20.3",
128
+ "@codemirror/commands": "^6.10.3",
129
+ "@codemirror/lang-css": "^6.3.1",
130
+ "@codemirror/lang-html": "^6.4.11",
131
+ "@codemirror/lang-javascript": "^6.2.5",
132
+ "@codemirror/lang-json": "^6.0.2",
133
+ "@codemirror/lang-liquid": "^6.3.2",
134
+ "@codemirror/language": "^6.12.3",
135
+ "@codemirror/lint": "^6.9.7",
136
+ "@codemirror/search": "^6.7.1",
137
+ "@codemirror/state": "^6.6.0",
138
+ "@codemirror/view": "^6.43.1",
139
+ "@tiptap/extension-character-count": "^3.26.1",
140
+ "@tiptap/extension-image": "^3.26.1",
141
+ "@tiptap/extension-link": "^3.26.1",
142
+ "@tiptap/extension-placeholder": "^3.26.1",
143
+ "@tiptap/extension-table": "^3.26.1",
144
+ "@tiptap/extension-underline": "^3.26.1",
145
+ "@tiptap/react": "^3.26.1",
146
+ "@tiptap/starter-kit": "^3.26.1",
114
147
  "buffer": "^6.0.3",
115
148
  "clsx": "^2.1.1",
149
+ "codemirror": "^6.0.2",
150
+ "liquidjs": "^10.27.0",
116
151
  "papaparse": "^5.5.3",
117
- "prismjs": "^ 1.30.0",
152
+ "prismjs": "^1.30.0",
118
153
  "react-markdown": "^10.1.0",
119
154
  "rehype-autolink-headings": "^7.1.0",
120
155
  "rehype-sanitize": "^6.0.0",
@@ -122,5 +157,8 @@
122
157
  "remark-gfm": "^4.0.1",
123
158
  "tailwind-merge": "^3.5.0",
124
159
  "tui-image-editor": "^3.15.3"
160
+ },
161
+ "publishConfig": {
162
+ "access": "public"
125
163
  }
126
164
  }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * LLMNative proxy - Cloudflare Worker.
3
+ *
4
+ * Deploy as a Worker or use as a Pages Function at:
5
+ * functions/api/proxy.ts
6
+ */
7
+ export default {
8
+ async fetch(request: Request): Promise<Response> {
9
+ const { searchParams } = new URL(request.url);
10
+ const targetUrl = searchParams.get('url');
11
+
12
+ if (!targetUrl) {
13
+ return Response.json({ error: 'Missing url query parameter' }, { status: 400 });
14
+ }
15
+
16
+ const headers = new Headers(request.headers);
17
+ headers.delete('host');
18
+ headers.delete('x-llmnative-proxy');
19
+
20
+ const hasBody = !['GET', 'HEAD'].includes(request.method.toUpperCase());
21
+
22
+ const upstream = await fetch(targetUrl, {
23
+ method: request.method,
24
+ headers,
25
+ body: hasBody ? request.body : undefined,
26
+ ...(hasBody ? { duplex: 'half' } : {}),
27
+ } as RequestInit);
28
+
29
+ return new Response(upstream.body, {
30
+ status: upstream.status,
31
+ headers: upstream.headers,
32
+ });
33
+ },
34
+ };