@llmnative/react 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +1 -1
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3095 -2619
- package/dist/index.mjs.map +1 -0
- package/dist/logHeader-Busbc8OO.mjs +2 -0
- package/dist/logHeader-Busbc8OO.mjs.map +1 -0
- package/dist/logHeader-CbzOhx-u.js +2 -1
- package/dist/logHeader-CbzOhx-u.js.map +1 -0
- package/dist/types/src/App.d.ts +6 -3
- package/dist/types/src/I18n.d.ts +7 -0
- package/dist/types/src/Theme.d.ts +6 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/ui/Card.d.ts +3 -1
- package/dist/types/src/components/ui/Loader.d.ts +3 -1
- package/dist/types/src/components/ui/fields/AddressAutocomplete.d.ts +80 -0
- package/dist/types/src/components/widgets/grid-core/GridCore.d.ts +1 -1
- package/dist/types/src/components/widgets/grid-core/GridTableView.d.ts +1 -1
- package/dist/types/src/components/widgets/grid-core/types.d.ts +57 -0
- package/dist/types/src/index.d.ts +4 -1
- package/dist/types/src/providers/auth/AuthProvider.d.ts +1 -1
- package/dist/types/src/providers/auth/firebase/FirebaseAuthProvider.d.ts +1 -1
- package/dist/types/src/providers/googleMaps/GoogleMapsProviderContext.d.ts +8 -0
- package/dist/types/src/providers/googleMaps/loadGoogleMaps.d.ts +20 -0
- package/dist/vite.js +2 -1
- package/dist/vite.js.map +1 -0
- package/dist/vite.mjs +2 -0
- package/dist/vite.mjs.map +1 -0
- package/package.json +2 -1
- package/themes/cyber.ts +6 -0
- package/themes/default.ts +6 -0
- package/themes/flat.ts +6 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logHeader-Busbc8OO.mjs","names":[],"sources":["../src/providers/proxy/logHeader.ts"],"sourcesContent":["/** Nome dell'header che trasporta l'id di conversazione dal client (provider AI, via\n * `AICompleteRequest.logId`) al proxy dev di Vite (`vite.ts`), che lo usa per accodare\n * request/response allo stesso file di log per l'intera conversazione. File separato e\n * privo di import Node-specific — i provider AI lato browser (anthropic.ts/gemini.ts/\n * openaiCompatible.ts) lo importano per impostare l'header, senza portarsi dietro le\n * dipendenze Node di vite.ts nel proprio bundle. */\nexport const LLM_LOG_ID_HEADER = 'x-llmnative-log-id';\n"],"mappings":";AAMA,IAAa,IAAoB"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),l=`x-llmnative-log-id`;Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return l}});
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),l=`x-llmnative-log-id`;Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return l}});
|
|
2
|
+
//# sourceMappingURL=logHeader-CbzOhx-u.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logHeader-CbzOhx-u.js","names":[],"sources":["../src/providers/proxy/logHeader.ts"],"sourcesContent":["/** Nome dell'header che trasporta l'id di conversazione dal client (provider AI, via\n * `AICompleteRequest.logId`) al proxy dev di Vite (`vite.ts`), che lo usa per accodare\n * request/response allo stesso file di log per l'intera conversazione. File separato e\n * privo di import Node-specific — i provider AI lato browser (anthropic.ts/gemini.ts/\n * openaiCompatible.ts) lo importano per impostare l'header, senza portarsi dietro le\n * dipendenze Node di vite.ts nel proprio bundle. */\nexport const LLM_LOG_ID_HEADER = 'x-llmnative-log-id';\n"],"mappings":"slBAMa,EAAoB"}
|
package/dist/types/src/App.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { AuthProviderAdapter } from "./providers/auth/AuthProvider";
|
|
|
8
8
|
import type { EmailProviderAdapter } from "./providers/email/EmailProvider";
|
|
9
9
|
import type { CredentialsAdapter } from "./providers/credentials/CredentialsProvider";
|
|
10
10
|
import { type AppIconProviderConfig } from "./providers/icon/IconProviderContext";
|
|
11
|
+
import type { GoogleMapsConfig } from "./providers/googleMaps/loadGoogleMaps";
|
|
11
12
|
import { type I18nConfig } from "./I18n";
|
|
12
13
|
import { type ServicesConfig, type GoogleProviderConfig, type SupabaseProviderConfig, type MockProviderConfig } from "./providers/manifest";
|
|
13
14
|
interface MenuItem {
|
|
@@ -81,6 +82,8 @@ export type AppProviderProps = {
|
|
|
81
82
|
providers?: AppProvidersConfig;
|
|
82
83
|
/** Icon provider registry config. String shorthand selects the default provider id. */
|
|
83
84
|
iconProvider?: AppIconProviderConfig;
|
|
85
|
+
/** Google Maps/Places config consumed by `<AddressAutocomplete>`. Omit to leave it unconfigured. */
|
|
86
|
+
googleMaps?: GoogleMapsConfig;
|
|
84
87
|
/** Theme registry config. String shorthand selects the active theme id. */
|
|
85
88
|
themeProvider?: AppThemeProviderConfig;
|
|
86
89
|
/** Internationalization config: locale and per-locale translation overrides. */
|
|
@@ -110,8 +113,8 @@ export declare const getContextMenu: () => string[];
|
|
|
110
113
|
*
|
|
111
114
|
* Wraps children with: ErrorBoundary → BrowserRouter → RuntimeProvider →
|
|
112
115
|
* AuthProvider → CredentialsProvider → DataProvider → StorageProvider →
|
|
113
|
-
* EmailProvider → AIProvider → IconProvider →
|
|
114
|
-
* ThemeProvider → [contextProviders] → children.
|
|
116
|
+
* EmailProvider → AIProvider → IconProvider → GoogleMapsProvider → HeadProvider →
|
|
117
|
+
* I18nProvider → ThemeProvider → [contextProviders] → children.
|
|
115
118
|
*
|
|
116
119
|
* `contextProviders` runs inside DataProvider, so vertical-specific providers
|
|
117
120
|
* mounted there can call `useDataProvider()`, `useI18n()`, etc. directly.
|
|
@@ -119,7 +122,7 @@ export declare const getContextMenu: () => string[];
|
|
|
119
122
|
* `App` uses `AppProvider` internally. Use `AppProvider` directly only when
|
|
120
123
|
* you need the provider stack without the routing layer (e.g. tests, Storybook).
|
|
121
124
|
*/
|
|
122
|
-
export declare function AppProvider({ contextProviders, providers, appName, scrapeConfig, iconProvider, themeProvider, i18n, children, errorReportUrl, debug, basename, }: AppProviderProps): React.JSX.Element;
|
|
125
|
+
export declare function AppProvider({ contextProviders, providers, appName, scrapeConfig, iconProvider, googleMaps, themeProvider, i18n, children, errorReportUrl, debug, basename, }: AppProviderProps): React.JSX.Element;
|
|
123
126
|
declare function App({ importPage, LayoutDefault, menuConfig, children, ...providerProps }: AppProps): React.JSX.Element;
|
|
124
127
|
export declare const useMenu: (type: string) => UseMenuItem[];
|
|
125
128
|
export default App;
|
package/dist/types/src/I18n.d.ts
CHANGED
|
@@ -156,6 +156,13 @@ export interface I18nDict {
|
|
|
156
156
|
dragToResize: string;
|
|
157
157
|
dragHere: string;
|
|
158
158
|
};
|
|
159
|
+
addressAutocomplete: {
|
|
160
|
+
placeholder: string;
|
|
161
|
+
noResults: string;
|
|
162
|
+
searching: string;
|
|
163
|
+
notConfigured: string;
|
|
164
|
+
loadError: string;
|
|
165
|
+
};
|
|
159
166
|
}
|
|
160
167
|
type DeepPartial<T> = {
|
|
161
168
|
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
|
|
@@ -271,6 +271,12 @@ export interface ThemeConfig {
|
|
|
271
271
|
wrapperClassName?: string;
|
|
272
272
|
className?: string;
|
|
273
273
|
};
|
|
274
|
+
AddressAutocomplete?: {
|
|
275
|
+
wrapperClassName?: string;
|
|
276
|
+
className?: string;
|
|
277
|
+
menuClassName?: string;
|
|
278
|
+
itemClassName?: string;
|
|
279
|
+
};
|
|
274
280
|
Form?: {
|
|
275
281
|
wrapperClassName?: string;
|
|
276
282
|
buttonSaveClass?: string;
|
|
@@ -43,6 +43,7 @@ export { default as Icon } from './ui/Icon';
|
|
|
43
43
|
export { LayoutBuilder } from './ui/LayoutBuilder';
|
|
44
44
|
export * from './ui/fields/Input';
|
|
45
45
|
export * from './ui/fields/Select';
|
|
46
|
+
export * from './ui/fields/AddressAutocomplete';
|
|
46
47
|
export * from './ui/fields/Upload';
|
|
47
48
|
export * from './ui/fields/Crop';
|
|
48
49
|
export * from './ui/fields/UploadCSV';
|
|
@@ -12,8 +12,10 @@ export interface CardProps extends UIProps {
|
|
|
12
12
|
footerClassName?: string;
|
|
13
13
|
/** Show a loading skeleton instead of content. */
|
|
14
14
|
loading?: boolean;
|
|
15
|
+
/** Minimum height reserved for the loading overlay. Defaults to `200px`. */
|
|
16
|
+
loaderMinHeight?: string | number;
|
|
15
17
|
before?: React.ReactNode;
|
|
16
18
|
after?: React.ReactNode;
|
|
17
19
|
}
|
|
18
|
-
declare const Card: ({ children, title, header, footer, loading, wrapperClassName, className, headerClassName, bodyClassName, footerClassName, before, after, }: CardProps) => React.JSX.Element;
|
|
20
|
+
declare const Card: ({ children, title, header, footer, loading, loaderMinHeight, wrapperClassName, className, headerClassName, bodyClassName, footerClassName, before, after, }: CardProps) => React.JSX.Element;
|
|
19
21
|
export default Card;
|
|
@@ -8,6 +8,8 @@ interface LoaderProps extends UIProps {
|
|
|
8
8
|
icon?: string;
|
|
9
9
|
title?: string;
|
|
10
10
|
description?: string;
|
|
11
|
+
/** Minimum height reserved for the overlay while there is no content to size against. Defaults to `200px`. */
|
|
12
|
+
minHeight?: string | number;
|
|
11
13
|
}
|
|
12
|
-
declare function Loader({ children, show, icon, title, description, before, after, wrapperClassName, className }: LoaderProps): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
14
|
+
declare function Loader({ children, show, icon, title, description, minHeight, before, after, wrapperClassName, className }: LoaderProps): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
|
|
13
15
|
export default Loader;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FormFieldProps } from '../../widgets/Form';
|
|
3
|
+
import type { FieldValue } from '../../../providers/data/DataProvider';
|
|
4
|
+
export interface ParsedAddress {
|
|
5
|
+
street?: string;
|
|
6
|
+
city?: string;
|
|
7
|
+
/** Province (administrative_area_level_2), falling back to the region when a country has no province level. */
|
|
8
|
+
state?: string;
|
|
9
|
+
zip?: string;
|
|
10
|
+
country?: string;
|
|
11
|
+
countryCode?: string;
|
|
12
|
+
lat?: number;
|
|
13
|
+
lng?: number;
|
|
14
|
+
formatted?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Overrides the default sub-field paths. Each key defaults to `${name}.<key>` (e.g. `name="address"`
|
|
18
|
+
* → `address.street`) — set any of these to an unrelated, absolute field path to write there instead.
|
|
19
|
+
*/
|
|
20
|
+
export interface AddressAutocompleteFieldNames {
|
|
21
|
+
street?: string;
|
|
22
|
+
city?: string;
|
|
23
|
+
state?: string;
|
|
24
|
+
zip?: string;
|
|
25
|
+
country?: string;
|
|
26
|
+
countryCode?: string;
|
|
27
|
+
lat?: string;
|
|
28
|
+
lng?: string;
|
|
29
|
+
zoom?: string;
|
|
30
|
+
formatted?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface AddressAutocompleteMapOptions {
|
|
33
|
+
/** Where the map renders relative to the search box. Defaults to `'below'`. */
|
|
34
|
+
position?: 'above' | 'below';
|
|
35
|
+
/** Zoom applied when a location is first placed (via search selection or map click) and no zoom is stored yet. Defaults to `15`. */
|
|
36
|
+
defaultZoom?: number;
|
|
37
|
+
/** Map height in pixels. Defaults to `240`. */
|
|
38
|
+
height?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface AddressAutocompleteProps extends FormFieldProps {
|
|
41
|
+
/** Base field path; see {@link AddressAutocompleteFieldNames} for the default sub-field layout. */
|
|
42
|
+
name: string;
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
feedback?: string;
|
|
46
|
+
/** Restrict suggestions to these ISO 3166-1 alpha-2 country codes, e.g. `['it']`. */
|
|
47
|
+
countries?: string[];
|
|
48
|
+
/** Overrides the provider-level language/region bias for this instance only. */
|
|
49
|
+
language?: string;
|
|
50
|
+
region?: string;
|
|
51
|
+
validator?: (value: FieldValue) => string | undefined | Promise<string | undefined>;
|
|
52
|
+
/** Called with the fully parsed address whenever it changes (search selection, pin drag/click)
|
|
53
|
+
* — use this if the consumer needs fields beyond the ones auto-written. */
|
|
54
|
+
onSelect?: (address: ParsedAddress) => void;
|
|
55
|
+
/** Remaps the sub-field paths this component reads/writes. Omit to use `${name}.<field>`. */
|
|
56
|
+
fieldNames?: AddressAutocompleteFieldNames;
|
|
57
|
+
/**
|
|
58
|
+
* Shows an embeddable map with a draggable/clickable pin, so the user can fine-tune the exact
|
|
59
|
+
* location beyond what the address search resolves. Pass `true` for defaults or an options
|
|
60
|
+
* object. Requires the **Geocoding API** enabled in the same Google Cloud project, in addition
|
|
61
|
+
* to Places API (New) + Maps JavaScript API.
|
|
62
|
+
*/
|
|
63
|
+
map?: boolean | AddressAutocompleteMapOptions;
|
|
64
|
+
id?: string;
|
|
65
|
+
labelClassName?: string;
|
|
66
|
+
menuClassName?: string;
|
|
67
|
+
itemClassName?: string;
|
|
68
|
+
mapClassName?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Address search field backed by the Google Places Autocomplete (New) API. Selecting a
|
|
72
|
+
* suggestion fills the structured subfields below `name` — they stay independently editable
|
|
73
|
+
* afterward, same as every other CRM-override field in this app. Optionally pairs with an
|
|
74
|
+
* embeddable map (`map` prop) with a draggable/clickable pin for fine adjustment.
|
|
75
|
+
*
|
|
76
|
+
* Requires `<App googleMaps={{ apiKey }}>` (or `<GoogleMapsProvider config={...}>`) somewhere
|
|
77
|
+
* above in the tree; without it the field renders disabled with an explanatory message.
|
|
78
|
+
*/
|
|
79
|
+
export declare const AddressAutocomplete: ({ name, label, required, placeholder, disabled, feedback, countries, language, region, validator, onSelect, fieldNames, map, id, labelClassName, inheritWrapperClassName, wrapperClassName, className, menuClassName, itemClassName, mapClassName, }: AddressAutocompleteProps) => React.ReactElement;
|
|
80
|
+
export default AddressAutocomplete;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { type RecordProps } from "../../../providers/data/DataProvider";
|
|
3
3
|
import { type GridCoreProps } from "./types";
|
|
4
|
-
declare function GridCore<TRecord extends RecordProps>({ records, recordId, sourcePath, columns, actions, form, editDeepLink, header, footer, view, views, sticky, wrapperClassName, loading, title, before, after, sortable, pagination, selection, onRowClick, reorderable, onReorder, groupBy, onSave, onDelete, onComplete, audit, onLoad, }: GridCoreProps<TRecord>): React.JSX.Element;
|
|
4
|
+
declare function GridCore<TRecord extends RecordProps>({ records, recordId, sourcePath, columns, actions, form, editDeepLink, header, footer, view, views, sticky, wrapperClassName, cardClassName, bodyClassName, loading, title, before, after, sortable, pagination, selection, onRowClick, reorderable, onReorder, groupBy, searchable, onSave, onDelete, onComplete, audit, onLoad, }: GridCoreProps<TRecord>): React.JSX.Element;
|
|
5
5
|
export default GridCore;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { type RecordProps } from "../../../providers/data/DataProvider";
|
|
3
3
|
import { type GridTableViewProps } from "./types";
|
|
4
|
-
declare function GridTableView<TRecord extends RecordProps>({ records, recordId, columns, runAction, sortable, pagination, selection, selectedKeys, onSelectionChange, onRowClick, reorderable, onReorder, activeKey, groupBy, wrapperClassName, before, after, }: GridTableViewProps<TRecord>): React.JSX.Element;
|
|
4
|
+
declare function GridTableView<TRecord extends RecordProps>({ records, recordId, columns, runAction, sortable, pagination, selection, selectedKeys, onSelectionChange, onRowClick, reorderable, onReorder, activeKey, groupBy, wrapperClassName, className, heightClassName, scrollClassName, headerClassName, before, after, }: GridTableViewProps<TRecord>): React.JSX.Element;
|
|
5
5
|
export default GridTableView;
|
|
@@ -29,6 +29,26 @@ export type GridGalleryField<TRecord> = {
|
|
|
29
29
|
export type GridTableViewConfig = {
|
|
30
30
|
/** Show a built-in "Columns" dropdown letting the user show/hide table columns. Default `false`. */
|
|
31
31
|
columnPicker?: boolean;
|
|
32
|
+
/** CSS classes on the underlying `<table>` element — forwarded to `Table`'s own `className`.
|
|
33
|
+
* A `<table>` with `table-layout: auto` (the default) shrinks its columns to fit the
|
|
34
|
+
* container instead of overflowing it, so wide/many-column content never triggers a
|
|
35
|
+
* horizontal scrollbar on its own — set a `min-w-[…]` here (combined with `views.table`'s
|
|
36
|
+
* ancestor allowing horizontal overflow, e.g. via `wrapperClassName="overflow-x-auto"`) to
|
|
37
|
+
* force the table wider than its container when needed. */
|
|
38
|
+
className?: string;
|
|
39
|
+
/** Tailwind height/max-height class for the inner viewport — forwarded to `Table`'s own
|
|
40
|
+
* `heightClassName`. When set, `Table` enables internal vertical scrolling automatically AND
|
|
41
|
+
* pins its own `<thead>`/`<tfoot>` to the top/bottom of that same scrolling viewport, so only
|
|
42
|
+
* the body rows move — no extra prop needed for that, it's `Table`'s own default behavior
|
|
43
|
+
* whenever it is height-bound. */
|
|
44
|
+
heightClassName?: string;
|
|
45
|
+
/** Additional class on the inner scrolling viewport — forwarded to `Table`'s own
|
|
46
|
+
* `scrollClassName`. Use as an addon for overflow styling or fine-grained tweaks. */
|
|
47
|
+
scrollClassName?: string;
|
|
48
|
+
/** Optional extra classes on `<thead>` — forwarded to `Table`'s own `headerClassName`. Purely
|
|
49
|
+
* cosmetic (e.g. extra padding/typography); the sticky-header-when-scrollable behavior itself
|
|
50
|
+
* is automatic (see `heightClassName` above) and does not depend on this prop being set. */
|
|
51
|
+
headerClassName?: string;
|
|
32
52
|
};
|
|
33
53
|
/** Gallery-specific view options, grouped under `views.gallery`. */
|
|
34
54
|
export type GridGalleryViewConfig<TRecord> = {
|
|
@@ -220,6 +240,22 @@ export type GridPresentation<TRecord> = {
|
|
|
220
240
|
sticky?: GridSticky;
|
|
221
241
|
/** CSS classes on the outermost wrapper element. */
|
|
222
242
|
wrapperClassName?: string;
|
|
243
|
+
/** CSS classes on the Card's own root box — the bordered element itself (`ui/Card.tsx`'s
|
|
244
|
+
* `cardRootClassName`), distinct from `wrapperClassName` (the element AROUND the card,
|
|
245
|
+
* e.g. for `before`/`after` layout) and `bodyClassName` (the padded area inside the card).
|
|
246
|
+
* The root box has no `display: flex`/height by default — its body only actually gets a
|
|
247
|
+
* bounded height (and therefore an internal scrollbar) when THIS box is also a flex column
|
|
248
|
+
* with a real height, e.g. `"flex h-full min-h-0 flex-col"`. Needed together with
|
|
249
|
+
* `bodyClassName`/`views.table.heightClassName` for a full-height Grid to scroll internally
|
|
250
|
+
* instead of growing past its container. */
|
|
251
|
+
cardClassName?: string;
|
|
252
|
+
/** CSS classes on the Card body — the container directly around the table/gallery view.
|
|
253
|
+
* Grid always renders inside a `Card` (`ui/Card.tsx`); its body defaults to a fixed padding
|
|
254
|
+
* with no height constraint. Use this (typically with `flex-1 min-h-0 overflow-hidden p-0`,
|
|
255
|
+
* paired with `wrapperClassName`/`cardClassName` making the card itself a bounded flex
|
|
256
|
+
* column, and `views.table.heightClassName`) to make the table's own internal scroll fill
|
|
257
|
+
* the remaining height of a flex ancestor instead of growing the page. */
|
|
258
|
+
bodyClassName?: string;
|
|
223
259
|
/** Show a loading skeleton instead of rows. */
|
|
224
260
|
loading?: boolean;
|
|
225
261
|
/** Title rendered in the Grid header area. */
|
|
@@ -229,6 +265,15 @@ export type GridPresentation<TRecord> = {
|
|
|
229
265
|
/** Content rendered after the Grid. */
|
|
230
266
|
after?: React.ReactNode;
|
|
231
267
|
};
|
|
268
|
+
/** Config for `GridBehavior.searchable` beyond a plain `true` — restrict which fields match,
|
|
269
|
+
* or override the input's placeholder. */
|
|
270
|
+
export type GridSearchConfig<TRecord> = {
|
|
271
|
+
/** Placeholder text for the search input — defaults to the localized `common.search`
|
|
272
|
+
* ("Search"). */
|
|
273
|
+
placeholder?: string;
|
|
274
|
+
/** Field keys to match against — omit to search every string-valued field on each record. */
|
|
275
|
+
fields?: Array<keyof TRecord | string>;
|
|
276
|
+
};
|
|
232
277
|
/** Interaction / behaviour props for `<Grid>`. */
|
|
233
278
|
export type GridBehavior<TRecord> = {
|
|
234
279
|
/** Enable global sorting. Pass an `OrderConfig` to set a default sort. */
|
|
@@ -245,6 +290,14 @@ export type GridBehavior<TRecord> = {
|
|
|
245
290
|
onReorder?: GridReorderHandler<TRecord>;
|
|
246
291
|
/** Group rows by a field or array of fields. */
|
|
247
292
|
groupBy?: keyof TRecord | string | Array<keyof TRecord | string>;
|
|
293
|
+
/** Enable a built-in search box in Grid's own default header — filters the records actually
|
|
294
|
+
* rendered (table/gallery, and whatever they in turn compute: sort/pagination/selection all
|
|
295
|
+
* see the FILTERED set, not the original one) by a case-insensitive substring match. `true`
|
|
296
|
+
* searches every string-valued field on each record; pass a `GridSearchConfig` to restrict to
|
|
297
|
+
* specific fields or customize the placeholder. Only rendered as part of Grid's OWN default
|
|
298
|
+
* header — same as `views.table.columnPicker`/`views.toggle`, a fully custom `header` prop
|
|
299
|
+
* bypasses it entirely (render your own search input there instead). */
|
|
300
|
+
searchable?: boolean | GridSearchConfig<TRecord>;
|
|
248
301
|
};
|
|
249
302
|
/** Data-mutation hooks for `<Grid>`. */
|
|
250
303
|
export type GridPersistence<TRecord> = {
|
|
@@ -329,6 +382,10 @@ export type GridTableViewProps<TRecord extends RecordProps> = {
|
|
|
329
382
|
activeKey?: string | null;
|
|
330
383
|
groupBy?: keyof TRecord | string | Array<keyof TRecord | string>;
|
|
331
384
|
wrapperClassName?: string;
|
|
385
|
+
className?: string;
|
|
386
|
+
heightClassName?: string;
|
|
387
|
+
scrollClassName?: string;
|
|
388
|
+
headerClassName?: string;
|
|
332
389
|
before?: React.ReactNode;
|
|
333
390
|
after?: React.ReactNode;
|
|
334
391
|
};
|
|
@@ -21,7 +21,7 @@ export { PromptUtils } from './libs/promptUtils';
|
|
|
21
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
|
-
export type { GridAction, GridActions, GridAfterActionArgs, GridAfterActionHandler, GridArrayProps, GridColumn, GridCoreProps, GridDBPath, GridDBQuery, GridDBProps, GridFooterContext, GridFormContext, GridGalleryField, GridGalleryViewProps, GridGalleryViewConfig, GridHeaderContext, GridLayout, GridMutationDeleteArgs, GridMutationDeleteHandler, GridMutationSaveArgs, GridMutationSaveHandler, GridReorderHandler, GridReorderMeta, GridRecordKey, GridProps, GridSelectionChangeHandler, GridSelectionMode, GridSelectionState, GridSticky, GridTableViewProps, GridTableViewConfig, GridViewsConfig, GridCellContext, } from './components/widgets/Grid';
|
|
24
|
+
export type { GridAction, GridActions, GridAfterActionArgs, GridAfterActionHandler, GridArrayProps, GridColumn, GridCoreProps, GridDBPath, GridDBQuery, GridDBProps, GridFooterContext, GridFormContext, GridGalleryField, GridGalleryViewProps, GridGalleryViewConfig, GridHeaderContext, GridLayout, GridMutationDeleteArgs, GridMutationDeleteHandler, GridMutationSaveArgs, GridMutationSaveHandler, GridReorderHandler, GridReorderMeta, GridRecordKey, GridProps, GridSearchConfig, GridSelectionChangeHandler, GridSelectionMode, GridSelectionState, GridSticky, GridTableViewProps, GridTableViewConfig, GridViewsConfig, GridCellContext, } from './components/widgets/Grid';
|
|
25
25
|
export type { ProviderConfigurable, ProviderConfigurationState } from './providers/ProviderConfiguration';
|
|
26
26
|
export { getProviderConfigurationState } from './providers/ProviderConfiguration';
|
|
27
27
|
export type { ProviderAdapterMap, ProviderService, SetProviderFn, ProviderRegistrySnapshot } from './providers/ProviderRegistryContext';
|
|
@@ -73,6 +73,9 @@ export { PhosphorIconProvider } from './providers/icon/PhosphorIconProvider';
|
|
|
73
73
|
export type { PhosphorWeight } from './providers/icon/PhosphorIconProvider';
|
|
74
74
|
export { IconProvider, useIconProvider, useIconController } from './providers/icon/IconProviderContext';
|
|
75
75
|
export type { AppIconProviderConfig, IconController } from './providers/icon/IconProviderContext';
|
|
76
|
+
export { GoogleMapsProvider, useGoogleMapsConfig } from './providers/googleMaps/GoogleMapsProviderContext';
|
|
77
|
+
export { loadGoogleMaps } from './providers/googleMaps/loadGoogleMaps';
|
|
78
|
+
export type { GoogleMapsConfig } from './providers/googleMaps/loadGoogleMaps';
|
|
76
79
|
export { useEmailProvider, EmailProvider } from './providers/email/EmailProviderContext';
|
|
77
80
|
export { GmailEmailProvider } from './providers/email/google/GmailEmailProvider';
|
|
78
81
|
export type { AIRequestOptions, AIAttachment, AIProviderAdapter, AIKeyValidationResult, AIModelDescriptor, AIProviderCapabilities, AIModelCatalog, AIProviderDefinition, AICompleteRequest, AICompleteResult, AIConversationTurn, AIToolDefinition, AIToolCall, AIToolResult, } from './providers/ai';
|
|
@@ -26,5 +26,5 @@ export interface AuthProviderAdapter extends ProviderConfigurable {
|
|
|
26
26
|
* Read-only/UI convenience — never a security boundary, the server always
|
|
27
27
|
* re-verifies the raw token itself rather than trusting client-read claims.
|
|
28
28
|
*/
|
|
29
|
-
getIdTokenClaims?(): Promise<Record<string, unknown> | null>;
|
|
29
|
+
getIdTokenClaims?(forceRefresh?: boolean): Promise<Record<string, unknown> | null>;
|
|
30
30
|
}
|
|
@@ -45,5 +45,5 @@ export declare class FirebaseAuthProvider implements AuthProviderAdapter {
|
|
|
45
45
|
signOut(): Promise<void>;
|
|
46
46
|
onAuthChange(callback: (user: UserProfile | null) => void): () => void;
|
|
47
47
|
getAccessToken(): Promise<string>;
|
|
48
|
-
getIdTokenClaims(): Promise<Record<string, unknown> | null>;
|
|
48
|
+
getIdTokenClaims(forceRefresh?: boolean): Promise<Record<string, unknown> | null>;
|
|
49
49
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { GoogleMapsConfig } from './loadGoogleMaps';
|
|
3
|
+
export declare function GoogleMapsProvider({ config, children }: {
|
|
4
|
+
config?: GoogleMapsConfig;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
}): React.JSX.Element;
|
|
7
|
+
/** `undefined` when `<App>`/`<GoogleMapsProvider>` was not given a `googleMaps` config. */
|
|
8
|
+
export declare function useGoogleMapsConfig(): GoogleMapsConfig | undefined;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface GoogleMapsConfig {
|
|
2
|
+
/** Google Cloud API key with the "Places API (New)" enabled. */
|
|
3
|
+
apiKey: string;
|
|
4
|
+
/** BCP-47 language for results, e.g. `'it'`. Defaults to the browser's language. */
|
|
5
|
+
language?: string;
|
|
6
|
+
/** Region bias (ccTLD), e.g. `'it'`. */
|
|
7
|
+
region?: string;
|
|
8
|
+
}
|
|
9
|
+
declare global {
|
|
10
|
+
interface Window {
|
|
11
|
+
[key: `__googleMapsLoader_${string}`]: (() => void) | undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Loads the Google Maps JS API (places library) exactly once per page, regardless of how
|
|
16
|
+
* many `<AddressAutocomplete>` instances mount. Safe to call repeatedly with the same config;
|
|
17
|
+
* throws if called again with a *different* apiKey than the one already loading/loaded, since
|
|
18
|
+
* the script tag can't be swapped out once injected.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadGoogleMaps(config: GoogleMapsConfig): Promise<typeof google>;
|
package/dist/vite.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./logHeader-CbzOhx-u.js");let t=require("node:fs/promises"),n=require("node:path");n=e.r(n);var r=`x-llmnative-proxy`,i=`/api/proxy`,a=async e=>{let t=[];for await(let n of e)t.push(Buffer.isBuffer(n)?n:Buffer.from(n));return t.length===0?void 0:Buffer.concat(t)};function o(e){return e.replace(/[^a-zA-Z0-9_-]/g,``).slice(0,128)||`unknown`}function s(e){if(!e.trim())return`(empty body)`;try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}}async function c(e,r,i,a,c,l){try{await(0,t.mkdir)(e.dir,{recursive:!0});let u=[``,`=`.repeat(80),`Turn @ ${new Date().toISOString()}`,`Target: ${i}`,`--- REQUEST BODY ---`,s(a),`--- RESPONSE BODY (status ${c}) ---`,s(l),`=`.repeat(80),``].join(`
|
|
2
|
-
`);await(0,t.appendFile)(n.default.join(e.dir,`${o(r)}.txt`),u,`utf-8`)}catch(e){console.warn(`[llmnative-dev-proxy] Failed to write LLM log:`,e)}}var l=async(t,n,i,o)=>{let s=new URL(t.url||`/`,`http://localhost`).searchParams.get(`url`);if(t.headers[r]!==`1`){n.statusCode=403,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:`Proxy access denied.`}));return}if(!s){n.statusCode=400,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:`Missing "url" query parameter.`}));return}try{let l=new URL(s);if(l.pathname.startsWith(i)&&[`localhost`,`127.0.0.1`].includes(l.hostname)){n.statusCode=508,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:`Recursive proxy target detected.`,target:s}));return}let u=await a(t),d=t.headers[e.t],f=new Headers,p=new Set([r,e.t,`host`,`origin`,`referer`,`content-length`,`transfer-encoding`,`connection`]);Object.entries(t.headers).forEach(([e,t])=>{!t||p.has(e.toLowerCase())||f.set(e,Array.isArray(t)?t.join(`, `):t)});let m=await fetch(s,{method:t.method||`GET`,headers:f,body:u&&![`GET`,`HEAD`].includes((t.method||`GET`).toUpperCase())?Uint8Array.from(u):void 0,redirect:`follow`}),h=Buffer.from(await m.arrayBuffer());o?.enabled&&typeof d==`string`&&d&&c(o,d,s,u?.toString(`utf-8`)??``,m.status,h.toString(`utf-8`)),n.statusCode=m.status,m.headers.forEach((e,t)=>{t.toLowerCase()!==`content-encoding`&&n.setHeader(t,e)}),n.end(h)}catch(e){n.statusCode=502,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:e instanceof Error?e.message:`Proxy request failed.`}))}},u=(e=i,t)=>({name:`llmnative-dev-proxy`,configureServer(n){n.middlewares.use(e,(n,r)=>{l(n,r,e,t)})},configurePreviewServer(n){n.middlewares.use(e,(n,r)=>{l(n,r,e,t)})}});exports.PROXY_PATH=i,exports.createProxyPlugin=u;
|
|
2
|
+
`);await(0,t.appendFile)(n.default.join(e.dir,`${o(r)}.txt`),u,`utf-8`)}catch(e){console.warn(`[llmnative-dev-proxy] Failed to write LLM log:`,e)}}var l=async(t,n,i,o)=>{let s=new URL(t.url||`/`,`http://localhost`).searchParams.get(`url`);if(t.headers[r]!==`1`){n.statusCode=403,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:`Proxy access denied.`}));return}if(!s){n.statusCode=400,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:`Missing "url" query parameter.`}));return}try{let l=new URL(s);if(l.pathname.startsWith(i)&&[`localhost`,`127.0.0.1`].includes(l.hostname)){n.statusCode=508,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:`Recursive proxy target detected.`,target:s}));return}let u=await a(t),d=t.headers[e.t],f=new Headers,p=new Set([r,e.t,`host`,`origin`,`referer`,`content-length`,`transfer-encoding`,`connection`]);Object.entries(t.headers).forEach(([e,t])=>{!t||p.has(e.toLowerCase())||f.set(e,Array.isArray(t)?t.join(`, `):t)});let m=await fetch(s,{method:t.method||`GET`,headers:f,body:u&&![`GET`,`HEAD`].includes((t.method||`GET`).toUpperCase())?Uint8Array.from(u):void 0,redirect:`follow`}),h=Buffer.from(await m.arrayBuffer());o?.enabled&&typeof d==`string`&&d&&c(o,d,s,u?.toString(`utf-8`)??``,m.status,h.toString(`utf-8`)),n.statusCode=m.status,m.headers.forEach((e,t)=>{t.toLowerCase()!==`content-encoding`&&n.setHeader(t,e)}),n.end(h)}catch(e){n.statusCode=502,n.setHeader(`Content-Type`,`application/json`),n.end(JSON.stringify({error:e instanceof Error?e.message:`Proxy request failed.`}))}},u=(e=i,t)=>({name:`llmnative-dev-proxy`,configureServer(n){n.middlewares.use(e,(n,r)=>{l(n,r,e,t)})},configurePreviewServer(n){n.middlewares.use(e,(n,r)=>{l(n,r,e,t)})}});exports.PROXY_PATH=i,exports.createProxyPlugin=u;
|
|
3
|
+
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","names":[],"sources":["../src/providers/proxy/vite.ts"],"sourcesContent":["import { appendFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Plugin } from 'vite';\nimport { LLM_LOG_ID_HEADER } from './logHeader';\n\nconst PROXY_CALLER_HEADER = 'x-llmnative-proxy';\nexport const PROXY_PATH = '/api/proxy';\n\n/** Logging file di richiesta/risposta LLM — SOLO dev, mai attivo di default. Un file per\n * conversazione: il client (useAgent, CMS) genera un `logId` stabile per l'intera sessione e\n * lo manda su ogni chiamata come header `x-llmnative-log-id`; il proxy accoda ogni turno allo\n * stesso file, non lo sovrascrive. Vedi AICompleteRequest.logId per il lato client. */\nexport interface ProxyLogOptions {\n enabled: boolean;\n /** Cartella di destinazione, relativa alla cwd del dev server (il progetto consumer, es.\n * il CMS) o assoluta. Creata se assente. */\n dir: string;\n}\n\nconst readRequestBody = async (req: IncomingMessage): Promise<Buffer | undefined> => {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return chunks.length === 0 ? undefined : Buffer.concat(chunks);\n};\n\n/** Solo caratteri sicuri per un nome file — l'id è generato da noi (crypto.randomUUID() lato\n * client), ma niente path traversal per costruzione anche se un client si comportasse male. */\nfunction sanitizeLogId(logId: string): string {\n return logId.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128) || 'unknown';\n}\n\nfunction prettyJsonOrRaw(text: string): string {\n if (!text.trim()) return '(empty body)';\n try {\n return JSON.stringify(JSON.parse(text), null, 2);\n } catch {\n return text;\n }\n}\n\nasync function appendLogBlock(logOptions: ProxyLogOptions, logId: string, target: string, requestBody: string, status: number, responseBody: string) {\n try {\n await mkdir(logOptions.dir, { recursive: true });\n const block = [\n '',\n '='.repeat(80),\n `Turn @ ${new Date().toISOString()}`,\n `Target: ${target}`,\n '--- REQUEST BODY ---',\n prettyJsonOrRaw(requestBody),\n `--- RESPONSE BODY (status ${status}) ---`,\n prettyJsonOrRaw(responseBody),\n '='.repeat(80),\n '',\n ].join('\\n');\n await appendFile(path.join(logOptions.dir, `${sanitizeLogId(logId)}.txt`), block, 'utf-8');\n } catch (error) {\n // Un log fallito non deve mai far fallire la vera richiesta — solo un avviso in console.\n console.warn('[llmnative-dev-proxy] Failed to write LLM log:', error);\n }\n}\n\nconst writeProxyResponse = async (req: IncomingMessage, res: ServerResponse, route: string, logOptions?: ProxyLogOptions) => {\n const requestUrl = new URL(req.url || '/', 'http://localhost');\n const target = requestUrl.searchParams.get('url');\n\n if (req.headers[PROXY_CALLER_HEADER] !== '1') {\n res.statusCode = 403;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Proxy access denied.' }));\n return;\n }\n\n if (!target) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Missing \"url\" query parameter.' }));\n return;\n }\n\n try {\n const targetUrl = new URL(target);\n if (targetUrl.pathname.startsWith(route) && ['localhost', '127.0.0.1'].includes(targetUrl.hostname)) {\n res.statusCode = 508;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Recursive proxy target detected.', target }));\n return;\n }\n\n const body = await readRequestBody(req);\n const logId = req.headers[LLM_LOG_ID_HEADER];\n const headers = new Headers();\n // L'header di log è consumato QUI, mai inoltrato al provider upstream (stesso\n // trattamento del PROXY_CALLER_HEADER) — è un dettaglio nostro, non dell'API esterna.\n const skipHeaders = new Set([PROXY_CALLER_HEADER, LLM_LOG_ID_HEADER, 'host', 'origin', 'referer', 'content-length', 'transfer-encoding', 'connection']);\n\n Object.entries(req.headers).forEach(([key, value]) => {\n if (!value || skipHeaders.has(key.toLowerCase())) return;\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\n });\n\n const upstream = await fetch(target, {\n method: req.method || 'GET',\n headers,\n body: body && !['GET', 'HEAD'].includes((req.method || 'GET').toUpperCase())\n ? Uint8Array.from(body)\n : undefined,\n redirect: 'follow',\n });\n\n const responseBuffer = Buffer.from(await upstream.arrayBuffer());\n\n if (logOptions?.enabled && typeof logId === 'string' && logId) {\n void appendLogBlock(logOptions, logId, target, body?.toString('utf-8') ?? '', upstream.status, responseBuffer.toString('utf-8'));\n }\n\n res.statusCode = upstream.status;\n upstream.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'content-encoding') return;\n res.setHeader(key, value);\n });\n res.end(responseBuffer);\n } catch (error) {\n res.statusCode = 502;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Proxy request failed.' }));\n }\n};\n\nexport const createProxyPlugin = (route = PROXY_PATH, logOptions?: ProxyLogOptions): Plugin => ({\n name: 'llmnative-dev-proxy',\n configureServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n configurePreviewServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n});\n"],"mappings":"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"}
|
package/dist/vite.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.mjs","names":[],"sources":["../src/providers/proxy/vite.ts"],"sourcesContent":["import { appendFile, mkdir } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Plugin } from 'vite';\nimport { LLM_LOG_ID_HEADER } from './logHeader';\n\nconst PROXY_CALLER_HEADER = 'x-llmnative-proxy';\nexport const PROXY_PATH = '/api/proxy';\n\n/** Logging file di richiesta/risposta LLM — SOLO dev, mai attivo di default. Un file per\n * conversazione: il client (useAgent, CMS) genera un `logId` stabile per l'intera sessione e\n * lo manda su ogni chiamata come header `x-llmnative-log-id`; il proxy accoda ogni turno allo\n * stesso file, non lo sovrascrive. Vedi AICompleteRequest.logId per il lato client. */\nexport interface ProxyLogOptions {\n enabled: boolean;\n /** Cartella di destinazione, relativa alla cwd del dev server (il progetto consumer, es.\n * il CMS) o assoluta. Creata se assente. */\n dir: string;\n}\n\nconst readRequestBody = async (req: IncomingMessage): Promise<Buffer | undefined> => {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return chunks.length === 0 ? undefined : Buffer.concat(chunks);\n};\n\n/** Solo caratteri sicuri per un nome file — l'id è generato da noi (crypto.randomUUID() lato\n * client), ma niente path traversal per costruzione anche se un client si comportasse male. */\nfunction sanitizeLogId(logId: string): string {\n return logId.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128) || 'unknown';\n}\n\nfunction prettyJsonOrRaw(text: string): string {\n if (!text.trim()) return '(empty body)';\n try {\n return JSON.stringify(JSON.parse(text), null, 2);\n } catch {\n return text;\n }\n}\n\nasync function appendLogBlock(logOptions: ProxyLogOptions, logId: string, target: string, requestBody: string, status: number, responseBody: string) {\n try {\n await mkdir(logOptions.dir, { recursive: true });\n const block = [\n '',\n '='.repeat(80),\n `Turn @ ${new Date().toISOString()}`,\n `Target: ${target}`,\n '--- REQUEST BODY ---',\n prettyJsonOrRaw(requestBody),\n `--- RESPONSE BODY (status ${status}) ---`,\n prettyJsonOrRaw(responseBody),\n '='.repeat(80),\n '',\n ].join('\\n');\n await appendFile(path.join(logOptions.dir, `${sanitizeLogId(logId)}.txt`), block, 'utf-8');\n } catch (error) {\n // Un log fallito non deve mai far fallire la vera richiesta — solo un avviso in console.\n console.warn('[llmnative-dev-proxy] Failed to write LLM log:', error);\n }\n}\n\nconst writeProxyResponse = async (req: IncomingMessage, res: ServerResponse, route: string, logOptions?: ProxyLogOptions) => {\n const requestUrl = new URL(req.url || '/', 'http://localhost');\n const target = requestUrl.searchParams.get('url');\n\n if (req.headers[PROXY_CALLER_HEADER] !== '1') {\n res.statusCode = 403;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Proxy access denied.' }));\n return;\n }\n\n if (!target) {\n res.statusCode = 400;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Missing \"url\" query parameter.' }));\n return;\n }\n\n try {\n const targetUrl = new URL(target);\n if (targetUrl.pathname.startsWith(route) && ['localhost', '127.0.0.1'].includes(targetUrl.hostname)) {\n res.statusCode = 508;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: 'Recursive proxy target detected.', target }));\n return;\n }\n\n const body = await readRequestBody(req);\n const logId = req.headers[LLM_LOG_ID_HEADER];\n const headers = new Headers();\n // L'header di log è consumato QUI, mai inoltrato al provider upstream (stesso\n // trattamento del PROXY_CALLER_HEADER) — è un dettaglio nostro, non dell'API esterna.\n const skipHeaders = new Set([PROXY_CALLER_HEADER, LLM_LOG_ID_HEADER, 'host', 'origin', 'referer', 'content-length', 'transfer-encoding', 'connection']);\n\n Object.entries(req.headers).forEach(([key, value]) => {\n if (!value || skipHeaders.has(key.toLowerCase())) return;\n headers.set(key, Array.isArray(value) ? value.join(', ') : value);\n });\n\n const upstream = await fetch(target, {\n method: req.method || 'GET',\n headers,\n body: body && !['GET', 'HEAD'].includes((req.method || 'GET').toUpperCase())\n ? Uint8Array.from(body)\n : undefined,\n redirect: 'follow',\n });\n\n const responseBuffer = Buffer.from(await upstream.arrayBuffer());\n\n if (logOptions?.enabled && typeof logId === 'string' && logId) {\n void appendLogBlock(logOptions, logId, target, body?.toString('utf-8') ?? '', upstream.status, responseBuffer.toString('utf-8'));\n }\n\n res.statusCode = upstream.status;\n upstream.headers.forEach((value, key) => {\n if (key.toLowerCase() === 'content-encoding') return;\n res.setHeader(key, value);\n });\n res.end(responseBuffer);\n } catch (error) {\n res.statusCode = 502;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ error: error instanceof Error ? error.message : 'Proxy request failed.' }));\n }\n};\n\nexport const createProxyPlugin = (route = PROXY_PATH, logOptions?: ProxyLogOptions): Plugin => ({\n name: 'llmnative-dev-proxy',\n configureServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n configurePreviewServer(server) {\n server.middlewares.use(route, (req, res) => { void writeProxyResponse(req, res, route, logOptions); });\n },\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llmnative/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
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",
|
|
@@ -101,6 +101,7 @@
|
|
|
101
101
|
"@testing-library/jest-dom": "^7.0.0",
|
|
102
102
|
"@testing-library/react": "^16.3.2",
|
|
103
103
|
"@testing-library/user-event": "^14.6.1",
|
|
104
|
+
"@types/google.maps": "^3.65.4",
|
|
104
105
|
"@types/papaparse": "^5.5.2",
|
|
105
106
|
"@types/prismjs": "^1.26.6",
|
|
106
107
|
"@types/react": "^19.2.17",
|
package/themes/cyber.ts
CHANGED
|
@@ -318,6 +318,12 @@ export const components: Theme = {
|
|
|
318
318
|
wrapperClassName: '',
|
|
319
319
|
className: '',
|
|
320
320
|
},
|
|
321
|
+
AddressAutocomplete: {
|
|
322
|
+
wrapperClassName: '',
|
|
323
|
+
className: '',
|
|
324
|
+
menuClassName: 'rounded-none border-border/70 bg-popover/95 shadow-[0_0_0_1px_hsl(var(--border)/0.55),0_12px_32px_rgba(0,0,0,0.35)] supports-[backdrop-filter]:bg-popover/92',
|
|
325
|
+
itemClassName: '',
|
|
326
|
+
},
|
|
321
327
|
Form: {
|
|
322
328
|
wrapperClassName: '',
|
|
323
329
|
buttonSaveClass: 'btn-outline-primary',
|
package/themes/default.ts
CHANGED
|
@@ -332,6 +332,12 @@ export const components: Theme = {
|
|
|
332
332
|
wrapperClassName: '',
|
|
333
333
|
className: '',
|
|
334
334
|
},
|
|
335
|
+
AddressAutocomplete: {
|
|
336
|
+
wrapperClassName: '',
|
|
337
|
+
className: '',
|
|
338
|
+
menuClassName: 'border-border/60 bg-popover/95 shadow-xl shadow-black/5 backdrop-blur supports-[backdrop-filter]:bg-popover/90 dark:shadow-black/20',
|
|
339
|
+
itemClassName: '',
|
|
340
|
+
},
|
|
335
341
|
Form: {
|
|
336
342
|
wrapperClassName: '',
|
|
337
343
|
buttonSaveClass: 'btn-outline-primary',
|
package/themes/flat.ts
CHANGED
|
@@ -318,6 +318,12 @@ export const components: Theme = {
|
|
|
318
318
|
wrapperClassName: '',
|
|
319
319
|
className: '',
|
|
320
320
|
},
|
|
321
|
+
AddressAutocomplete: {
|
|
322
|
+
wrapperClassName: '',
|
|
323
|
+
className: '',
|
|
324
|
+
menuClassName: 'border-border/60 bg-popover/95 shadow-lg shadow-black/5 supports-[backdrop-filter]:bg-popover/92',
|
|
325
|
+
itemClassName: '',
|
|
326
|
+
},
|
|
321
327
|
Form: {
|
|
322
328
|
wrapperClassName: '',
|
|
323
329
|
buttonSaveClass: 'btn-outline-primary',
|