@larose-ui/enterprise 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 laRose contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.css ADDED
@@ -0,0 +1,62 @@
1
+ /* src/audit/AuditHistory.module.css */
2
+ .panel {
3
+ border: 1px solid var(--lr-color-border);
4
+ border-radius: var(--lr-radius-md);
5
+ padding: var(--lr-space-3);
6
+ background: var(--lr-color-surface-elevated);
7
+ }
8
+ .header {
9
+ display: flex;
10
+ justify-content: space-between;
11
+ align-items: center;
12
+ margin-bottom: var(--lr-space-2);
13
+ }
14
+ .header button {
15
+ border: none;
16
+ background: none;
17
+ font-size: 1.25rem;
18
+ cursor: pointer;
19
+ line-height: 1;
20
+ }
21
+ .empty {
22
+ margin: 0;
23
+ color: var(--lr-color-text-muted);
24
+ font-size: var(--lr-font-size-sm);
25
+ }
26
+ .list {
27
+ list-style: none;
28
+ margin: 0;
29
+ padding: 0;
30
+ }
31
+ .list li {
32
+ padding: var(--lr-space-2) 0;
33
+ border-bottom: 1px solid var(--lr-color-border);
34
+ }
35
+ .list li:last-child {
36
+ border-bottom: none;
37
+ }
38
+ .change {
39
+ font-weight: var(--lr-font-weight-medium);
40
+ }
41
+ .meta {
42
+ font-size: var(--lr-font-size-sm);
43
+ color: var(--lr-color-text-muted);
44
+ margin-top: var(--lr-space-1);
45
+ }
46
+
47
+ /* src/audit/AuditedInput.module.css */
48
+ .wrapper {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: var(--lr-space-2);
52
+ }
53
+ .historyButton {
54
+ align-self: flex-start;
55
+ font-size: var(--lr-font-size-sm);
56
+ color: var(--lr-color-primary);
57
+ background: none;
58
+ border: none;
59
+ cursor: pointer;
60
+ padding: 0;
61
+ text-decoration: underline;
62
+ }
@@ -0,0 +1,111 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { InputProps } from '@larose-ui/react';
4
+ import { VersionInfo } from '@larose-ui/core';
5
+ import { FormFieldSchema, FormSchema } from '@larose-ui/forms';
6
+
7
+ interface AuditEntry {
8
+ id: string;
9
+ field: string;
10
+ actor: string;
11
+ before: string;
12
+ after: string;
13
+ timestamp: string;
14
+ resourceId?: string;
15
+ }
16
+ interface AuditContextValue {
17
+ actor: string;
18
+ entries: AuditEntry[];
19
+ recordChange: (entry: Omit<AuditEntry, 'id' | 'timestamp' | 'actor'>) => void;
20
+ getHistory: (field: string, resourceId?: string) => AuditEntry[];
21
+ }
22
+
23
+ interface AuditProviderProps {
24
+ actor?: string;
25
+ children: ReactNode;
26
+ }
27
+ declare function AuditProvider({ actor, children }: AuditProviderProps): react.JSX.Element;
28
+ declare function useAudit(): AuditContextValue;
29
+ declare function useOptionalAudit(): AuditContextValue | null;
30
+
31
+ interface AuditedInputProps extends Omit<InputProps, 'onChange'> {
32
+ field: string;
33
+ resourceId?: string;
34
+ showHistory?: boolean;
35
+ onChange?: (value: string) => void;
36
+ }
37
+ declare function AuditedInput({ field, resourceId, showHistory, value, defaultValue, onChange, ...props }: AuditedInputProps): react.JSX.Element;
38
+
39
+ interface AuditHistoryProps {
40
+ field: string;
41
+ resourceId?: string;
42
+ onClose?: () => void;
43
+ }
44
+ declare function AuditHistory({ field, resourceId, onClose }: AuditHistoryProps): react.JSX.Element;
45
+
46
+ interface VersionCheckOptions {
47
+ frontend?: string;
48
+ backend?: string;
49
+ minBackend?: string;
50
+ maxBackend?: string;
51
+ deprecatedFeatures?: string[];
52
+ requiredFeatures?: string[];
53
+ }
54
+ declare function checkVersionCompatibility(options: VersionCheckOptions): VersionInfo;
55
+
56
+ interface VersionProviderProps extends VersionCheckOptions {
57
+ children: ReactNode;
58
+ showBanner?: boolean;
59
+ }
60
+ declare function VersionProvider({ children, showBanner, ...options }: VersionProviderProps): react.JSX.Element;
61
+ declare function useVersion(): VersionInfo;
62
+ declare function useOptionalVersion(): VersionInfo | null;
63
+
64
+ type UISchemaType = 'form' | 'page' | 'table';
65
+ interface UISchemaField {
66
+ type: FormFieldSchema['type'];
67
+ name: string;
68
+ label?: string;
69
+ placeholder?: string;
70
+ required?: boolean;
71
+ hint?: string;
72
+ permission?: string;
73
+ options?: FormFieldSchema['options'];
74
+ showWhen?: FormFieldSchema['showWhen'];
75
+ }
76
+ interface UISchema {
77
+ type: UISchemaType;
78
+ id: string;
79
+ title?: string;
80
+ permission?: string;
81
+ fields?: UISchemaField[];
82
+ submitUrl?: string;
83
+ }
84
+ declare function compileFormSchema(schema: UISchema): FormSchema;
85
+ declare function validateUISchema(schema: UISchema): string[];
86
+
87
+ interface SchemaRendererProps {
88
+ schema: UISchema;
89
+ onSubmit?: (values: Record<string, string>) => Promise<void> | void;
90
+ }
91
+ declare function SchemaRenderer({ schema, onSubmit }: SchemaRendererProps): react.JSX.Element;
92
+
93
+ interface SensitiveActionProps {
94
+ label: string;
95
+ description?: string;
96
+ confirmLabel?: string;
97
+ cancelLabel?: string;
98
+ requireProductionConfirm?: boolean;
99
+ onConfirm: () => void | Promise<void>;
100
+ }
101
+ declare function SensitiveAction({ label, description, confirmLabel, cancelLabel, requireProductionConfirm, onConfirm, }: SensitiveActionProps): react.JSX.Element;
102
+
103
+ interface SessionGuardProps {
104
+ children: ReactNode;
105
+ onSessionExpired?: (returnUrl: string) => void;
106
+ loginUrl?: string;
107
+ }
108
+ declare function SessionGuard({ children, onSessionExpired, loginUrl, }: SessionGuardProps): react.JSX.Element;
109
+ declare function notifySessionExpired(code?: number): void;
110
+
111
+ export { type AuditContextValue, type AuditEntry, AuditHistory, type AuditHistoryProps, AuditProvider, type AuditProviderProps, AuditedInput, type AuditedInputProps, SchemaRenderer, type SchemaRendererProps, SensitiveAction, type SensitiveActionProps, SessionGuard, type SessionGuardProps, type UISchema, type UISchemaField, type UISchemaType, type VersionCheckOptions, VersionProvider, type VersionProviderProps, checkVersionCompatibility, compileFormSchema, notifySessionExpired, useAudit, useOptionalAudit, useOptionalVersion, useVersion, validateUISchema };
package/dist/index.js ADDED
@@ -0,0 +1,392 @@
1
+ // src/audit/AuditProvider.tsx
2
+ import {
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useMemo,
7
+ useState
8
+ } from "react";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var AuditContext = createContext(null);
11
+ function AuditProvider({ actor = "system", children }) {
12
+ const [entries, setEntries] = useState([]);
13
+ const recordChange = useCallback(
14
+ (entry) => {
15
+ setEntries((prev) => [
16
+ {
17
+ ...entry,
18
+ id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
19
+ actor,
20
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
21
+ },
22
+ ...prev
23
+ ]);
24
+ },
25
+ [actor]
26
+ );
27
+ const getHistory = useCallback(
28
+ (field, resourceId) => entries.filter(
29
+ (e) => e.field === field && (resourceId === void 0 || e.resourceId === resourceId)
30
+ ),
31
+ [entries]
32
+ );
33
+ const value = useMemo(
34
+ () => ({ actor, entries, recordChange, getHistory }),
35
+ [actor, entries, recordChange, getHistory]
36
+ );
37
+ return /* @__PURE__ */ jsx(AuditContext.Provider, { value, children });
38
+ }
39
+ function useAudit() {
40
+ const ctx = useContext(AuditContext);
41
+ if (!ctx) {
42
+ throw new Error("useAudit must be used within AuditProvider");
43
+ }
44
+ return ctx;
45
+ }
46
+ function useOptionalAudit() {
47
+ return useContext(AuditContext);
48
+ }
49
+
50
+ // src/audit/AuditedInput.tsx
51
+ import { useState as useState2 } from "react";
52
+ import { Input } from "@larose-ui/react";
53
+ import { useOptionalObservability } from "@larose-ui/observability";
54
+
55
+ // src/audit/AuditHistory.module.css
56
+ var AuditHistory_default = {};
57
+
58
+ // src/audit/AuditHistory.tsx
59
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
60
+ function AuditHistory({ field, resourceId, onClose }) {
61
+ const { getHistory } = useAudit();
62
+ const history = getHistory(field, resourceId);
63
+ return /* @__PURE__ */ jsxs("aside", { className: AuditHistory_default.panel, "aria-label": `Audit history for ${field}`, children: [
64
+ /* @__PURE__ */ jsxs("header", { className: AuditHistory_default.header, children: [
65
+ /* @__PURE__ */ jsxs("strong", { children: [
66
+ field,
67
+ " history"
68
+ ] }),
69
+ onClose && /* @__PURE__ */ jsx2("button", { type: "button", onClick: onClose, "aria-label": "Close history", children: "\xD7" })
70
+ ] }),
71
+ history.length === 0 ? /* @__PURE__ */ jsx2("p", { className: AuditHistory_default.empty, children: "No changes recorded." }) : /* @__PURE__ */ jsx2("ul", { className: AuditHistory_default.list, children: history.map((entry) => /* @__PURE__ */ jsxs("li", { children: [
72
+ /* @__PURE__ */ jsxs("div", { className: AuditHistory_default.change, children: [
73
+ entry.before || "(empty)",
74
+ " \u2192 ",
75
+ entry.after || "(empty)"
76
+ ] }),
77
+ /* @__PURE__ */ jsxs("div", { className: AuditHistory_default.meta, children: [
78
+ "Changed by ",
79
+ entry.actor,
80
+ " \xB7 ",
81
+ new Date(entry.timestamp).toLocaleString()
82
+ ] })
83
+ ] }, entry.id)) })
84
+ ] });
85
+ }
86
+
87
+ // src/audit/AuditedInput.module.css
88
+ var AuditedInput_default = {};
89
+
90
+ // src/audit/AuditedInput.tsx
91
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
92
+ function AuditedInput({
93
+ field,
94
+ resourceId,
95
+ showHistory = true,
96
+ value,
97
+ defaultValue,
98
+ onChange,
99
+ ...props
100
+ }) {
101
+ const audit = useOptionalAudit();
102
+ const observability = useOptionalObservability();
103
+ const [internal, setInternal] = useState2(String(defaultValue ?? ""));
104
+ const [historyOpen, setHistoryOpen] = useState2(false);
105
+ const current = value !== void 0 ? String(value) : internal;
106
+ const handleChange = (e) => {
107
+ const next = e.target.value;
108
+ const previous = current;
109
+ if (audit && previous !== next) {
110
+ audit.recordChange({ field, before: previous, after: next, resourceId });
111
+ }
112
+ observability?.track({
113
+ type: "interaction",
114
+ component: "AuditedInput",
115
+ metadata: { field, resourceId, action: "change" }
116
+ });
117
+ if (value === void 0) setInternal(next);
118
+ onChange?.(next);
119
+ };
120
+ return /* @__PURE__ */ jsxs2("div", { className: AuditedInput_default.wrapper, "data-lr-audited-field": field, children: [
121
+ /* @__PURE__ */ jsx3(Input, { ...props, value: current, onChange: handleChange }),
122
+ showHistory && audit && /* @__PURE__ */ jsxs2(Fragment, { children: [
123
+ /* @__PURE__ */ jsx3(
124
+ "button",
125
+ {
126
+ type: "button",
127
+ className: AuditedInput_default.historyButton,
128
+ onClick: () => setHistoryOpen((v) => !v),
129
+ children: "View History"
130
+ }
131
+ ),
132
+ historyOpen && /* @__PURE__ */ jsx3(AuditHistory, { field, resourceId, onClose: () => setHistoryOpen(false) })
133
+ ] })
134
+ ] });
135
+ }
136
+
137
+ // src/version/checkVersion.ts
138
+ import { LAROSE_VERSION } from "@larose-ui/core";
139
+ function parseMajor(version) {
140
+ const match = version.match(/^(\d+)/);
141
+ return match ? Number(match[1]) : 0;
142
+ }
143
+ function checkVersionCompatibility(options) {
144
+ const frontend = options.frontend ?? LAROSE_VERSION;
145
+ const backend = options.backend;
146
+ const warnings = [];
147
+ let compatible = true;
148
+ if (backend && options.minBackend) {
149
+ if (parseMajor(backend) < parseMajor(options.minBackend)) {
150
+ compatible = false;
151
+ warnings.push(
152
+ `Backend v${backend} is below minimum v${options.minBackend}. Some features may be unavailable.`
153
+ );
154
+ }
155
+ }
156
+ if (backend && options.maxBackend) {
157
+ if (parseMajor(backend) > parseMajor(options.maxBackend)) {
158
+ compatible = false;
159
+ warnings.push(
160
+ `Backend v${backend} exceeds supported maximum v${options.maxBackend}. Application update required.`
161
+ );
162
+ }
163
+ }
164
+ for (const feature of options.requiredFeatures ?? []) {
165
+ if (options.deprecatedFeatures?.includes(feature)) {
166
+ compatible = false;
167
+ warnings.push(`Feature "${feature}" requires an application update.`);
168
+ }
169
+ }
170
+ for (const deprecated of options.deprecatedFeatures ?? []) {
171
+ warnings.push(`API "${deprecated}" is deprecated and may be removed.`);
172
+ }
173
+ return { frontend, backend, compatible, warnings };
174
+ }
175
+
176
+ // src/version/VersionProvider.tsx
177
+ import {
178
+ createContext as createContext2,
179
+ useContext as useContext2,
180
+ useMemo as useMemo2
181
+ } from "react";
182
+ import { Alert } from "@larose-ui/react";
183
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
184
+ var VersionContext = createContext2(null);
185
+ function VersionProvider({
186
+ children,
187
+ showBanner = true,
188
+ ...options
189
+ }) {
190
+ const info = useMemo2(
191
+ () => checkVersionCompatibility(options),
192
+ [
193
+ options.frontend,
194
+ options.backend,
195
+ options.minBackend,
196
+ options.maxBackend,
197
+ options.deprecatedFeatures?.join(","),
198
+ options.requiredFeatures?.join(",")
199
+ ]
200
+ );
201
+ return /* @__PURE__ */ jsxs3(VersionContext.Provider, { value: info, children: [
202
+ showBanner && !info.compatible && /* @__PURE__ */ jsx4(Alert, { variant: "warning", title: "Version mismatch", children: info.warnings[0] ?? "This feature requires an application update." }),
203
+ children
204
+ ] });
205
+ }
206
+ function useVersion() {
207
+ const ctx = useContext2(VersionContext);
208
+ if (!ctx) {
209
+ throw new Error("useVersion must be used within VersionProvider");
210
+ }
211
+ return ctx;
212
+ }
213
+ function useOptionalVersion() {
214
+ return useContext2(VersionContext);
215
+ }
216
+
217
+ // src/schema/uiSchema.ts
218
+ function compileFormSchema(schema) {
219
+ if (schema.type !== "form") {
220
+ throw new Error(`Expected form schema, got "${schema.type}"`);
221
+ }
222
+ return {
223
+ id: schema.id,
224
+ title: schema.title,
225
+ fields: (schema.fields ?? []).map((field) => ({
226
+ name: field.name,
227
+ type: field.type,
228
+ label: field.label ?? field.name,
229
+ placeholder: field.placeholder,
230
+ required: field.required,
231
+ hint: field.hint,
232
+ options: field.options,
233
+ showWhen: field.showWhen
234
+ }))
235
+ };
236
+ }
237
+ function validateUISchema(schema) {
238
+ const errors = [];
239
+ if (!schema.id) errors.push("Schema id is required");
240
+ if (!schema.type) errors.push("Schema type is required");
241
+ if (schema.type === "form" && (!schema.fields || schema.fields.length === 0)) {
242
+ errors.push("Form schema requires at least one field");
243
+ }
244
+ for (const field of schema.fields ?? []) {
245
+ if (!field.name) errors.push("Field name is required");
246
+ if (!field.type) errors.push(`Field "${field.name}" requires a type`);
247
+ }
248
+ return errors;
249
+ }
250
+
251
+ // src/schema/SchemaRenderer.tsx
252
+ import { Form } from "@larose-ui/forms";
253
+ import { Can } from "@larose-ui/permissions";
254
+ import { Alert as Alert2 } from "@larose-ui/react";
255
+ import { jsx as jsx5 } from "react/jsx-runtime";
256
+ function SchemaRenderer({ schema, onSubmit }) {
257
+ const errors = validateUISchema(schema);
258
+ if (errors.length > 0) {
259
+ return /* @__PURE__ */ jsx5(Alert2, { variant: "error", title: "Invalid UI schema", children: /* @__PURE__ */ jsx5("ul", { style: { margin: 0, paddingInlineStart: "1.25rem" }, children: errors.map((e) => /* @__PURE__ */ jsx5("li", { children: e }, e)) }) });
260
+ }
261
+ if (schema.type !== "form") {
262
+ return /* @__PURE__ */ jsx5(Alert2, { variant: "info", title: "Schema type not rendered", children: "Page and table schemas are composed at the app layer. Use compileFormSchema for forms." });
263
+ }
264
+ const formSchema = compileFormSchema(schema);
265
+ const form = /* @__PURE__ */ jsx5(
266
+ Form,
267
+ {
268
+ schema: formSchema,
269
+ submitUrl: schema.submitUrl,
270
+ onSubmit,
271
+ submitLabel: "Save"
272
+ }
273
+ );
274
+ if (schema.permission) {
275
+ return /* @__PURE__ */ jsx5(Can, { permission: schema.permission, fallback: "forbidden", children: form });
276
+ }
277
+ return form;
278
+ }
279
+
280
+ // src/security/SensitiveAction.tsx
281
+ import { useCallback as useCallback2, useState as useState3 } from "react";
282
+ import { Dialog, Button } from "@larose-ui/react";
283
+ import { useEnvironment } from "@larose-ui/runtime";
284
+ import { useOptionalObservability as useOptionalObservability2 } from "@larose-ui/observability";
285
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
286
+ function SensitiveAction({
287
+ label,
288
+ description = "This action may have irreversible consequences.",
289
+ confirmLabel = "Confirm",
290
+ cancelLabel = "Cancel",
291
+ requireProductionConfirm = true,
292
+ onConfirm
293
+ }) {
294
+ const [open, setOpen] = useState3(false);
295
+ const [busy, setBusy] = useState3(false);
296
+ const environment = useEnvironment();
297
+ const observability = useOptionalObservability2();
298
+ const isProduction = environment === "production";
299
+ const handleConfirm = useCallback2(async () => {
300
+ setBusy(true);
301
+ try {
302
+ observability?.track({
303
+ type: "interaction",
304
+ component: "SensitiveAction",
305
+ metadata: { label, environment }
306
+ });
307
+ await onConfirm();
308
+ setOpen(false);
309
+ } finally {
310
+ setBusy(false);
311
+ }
312
+ }, [environment, label, observability, onConfirm]);
313
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
314
+ /* @__PURE__ */ jsx6(Button, { variant: "destructive", onClick: () => setOpen(true), children: label }),
315
+ /* @__PURE__ */ jsx6(
316
+ Dialog,
317
+ {
318
+ open,
319
+ onClose: () => setOpen(false),
320
+ title: label,
321
+ description: isProduction && requireProductionConfirm ? `${description} You are in production.` : description,
322
+ confirmLabel,
323
+ cancelLabel,
324
+ onConfirm: () => void handleConfirm(),
325
+ loading: busy,
326
+ variant: "destructive"
327
+ }
328
+ )
329
+ ] });
330
+ }
331
+
332
+ // src/security/SessionGuard.tsx
333
+ import { useCallback as useCallback3, useEffect, useState as useState4 } from "react";
334
+ import { Dialog as Dialog2 } from "@larose-ui/react";
335
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
336
+ function SessionGuard({
337
+ children,
338
+ onSessionExpired,
339
+ loginUrl = "/login"
340
+ }) {
341
+ const [expired, setExpired] = useState4(false);
342
+ useEffect(() => {
343
+ const handler = (event) => {
344
+ const detail = event.detail;
345
+ if (detail?.code === 401) setExpired(true);
346
+ };
347
+ window.addEventListener("larose:session-expired", handler);
348
+ return () => window.removeEventListener("larose:session-expired", handler);
349
+ }, []);
350
+ const handleRedirect = useCallback3(() => {
351
+ const returnUrl = window.location.pathname + window.location.search;
352
+ onSessionExpired?.(returnUrl);
353
+ window.location.href = `${loginUrl}?returnUrl=${encodeURIComponent(returnUrl)}`;
354
+ }, [loginUrl, onSessionExpired]);
355
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
356
+ children,
357
+ /* @__PURE__ */ jsx7(
358
+ Dialog2,
359
+ {
360
+ open: expired,
361
+ onClose: () => setExpired(false),
362
+ title: "Session expired",
363
+ description: "Your session has expired. Sign in again to continue.",
364
+ confirmLabel: "Sign in",
365
+ cancelLabel: "Dismiss",
366
+ onConfirm: handleRedirect
367
+ }
368
+ )
369
+ ] });
370
+ }
371
+ function notifySessionExpired(code = 401) {
372
+ if (typeof window !== "undefined") {
373
+ window.dispatchEvent(new CustomEvent("larose:session-expired", { detail: { code } }));
374
+ }
375
+ }
376
+ export {
377
+ AuditHistory,
378
+ AuditProvider,
379
+ AuditedInput,
380
+ SchemaRenderer,
381
+ SensitiveAction,
382
+ SessionGuard,
383
+ VersionProvider,
384
+ checkVersionCompatibility,
385
+ compileFormSchema,
386
+ notifySessionExpired,
387
+ useAudit,
388
+ useOptionalAudit,
389
+ useOptionalVersion,
390
+ useVersion,
391
+ validateUISchema
392
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@larose-ui/enterprise",
3
+ "version": "0.1.0",
4
+ "description": "Enterprise features — audit trails, version compatibility, UI schema IaC, security patterns",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@larose-ui/core": "0.1.0",
20
+ "@larose-ui/permissions": "0.1.0",
21
+ "@larose-ui/observability": "0.1.0",
22
+ "@larose-ui/forms": "0.1.0",
23
+ "@larose-ui/react": "0.1.0",
24
+ "@larose-ui/runtime": "0.1.0"
25
+ },
26
+ "peerDependencies": {
27
+ "react": ">=18"
28
+ },
29
+ "devDependencies": {
30
+ "@testing-library/jest-dom": "^6.6.3",
31
+ "@testing-library/react": "^16.1.0",
32
+ "@testing-library/user-event": "^14.5.2",
33
+ "@vitejs/plugin-react": "^4.3.4",
34
+ "jsdom": "^25.0.1",
35
+ "react": "^19.0.0",
36
+ "react-dom": "^19.0.0",
37
+ "tsup": "^8.3.5",
38
+ "typescript": "^5.7.2",
39
+ "vitest": "^2.1.8"
40
+ },
41
+ "license": "MIT",
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/larose-ui/larose.git",
48
+ "directory": "packages/enterprise"
49
+ },
50
+ "keywords": [
51
+ "larose",
52
+ "react",
53
+ "ui-platform",
54
+ "design-system",
55
+ "saas"
56
+ ],
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "test": "vitest run",
60
+ "typecheck": "tsc --noEmit",
61
+ "clean": "rm -rf dist"
62
+ }
63
+ }