@ramme-io/kernel 1.3.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 (124) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/LICENSE +21 -0
  3. package/dist/components/AutoForm.d.ts +24 -0
  4. package/dist/components/AutoForm.d.ts.map +1 -0
  5. package/dist/components/AutoForm.js +78 -0
  6. package/dist/components/AutoForm.js.map +1 -0
  7. package/dist/components/SmartTable.d.ts +14 -0
  8. package/dist/components/SmartTable.d.ts.map +1 -0
  9. package/dist/components/SmartTable.js +128 -0
  10. package/dist/components/SmartTable.js.map +1 -0
  11. package/dist/config/app.manifest.d.ts +7 -0
  12. package/dist/config/app.manifest.d.ts.map +1 -0
  13. package/dist/config/app.manifest.js +8 -0
  14. package/dist/config/app.manifest.js.map +1 -0
  15. package/dist/engine/renderers/DynamicBlock.d.ts +9 -0
  16. package/dist/engine/renderers/DynamicBlock.d.ts.map +1 -0
  17. package/dist/engine/renderers/DynamicBlock.js +67 -0
  18. package/dist/engine/renderers/DynamicBlock.js.map +1 -0
  19. package/dist/engine/renderers/DynamicPage.d.ts +11 -0
  20. package/dist/engine/renderers/DynamicPage.d.ts.map +1 -0
  21. package/dist/engine/renderers/DynamicPage.js +91 -0
  22. package/dist/engine/renderers/DynamicPage.js.map +1 -0
  23. package/dist/engine/renderers/route-generator.d.ts +16 -0
  24. package/dist/engine/renderers/route-generator.d.ts.map +1 -0
  25. package/dist/engine/renderers/route-generator.js +30 -0
  26. package/dist/engine/renderers/route-generator.js.map +1 -0
  27. package/dist/engine/renderers/sitemap-entry.d.ts +7 -0
  28. package/dist/engine/renderers/sitemap-entry.d.ts.map +1 -0
  29. package/dist/engine/renderers/sitemap-entry.js +2 -0
  30. package/dist/engine/renderers/sitemap-entry.js.map +1 -0
  31. package/dist/engine/runtime/ManifestContext.d.ts +115 -0
  32. package/dist/engine/runtime/ManifestContext.d.ts.map +1 -0
  33. package/dist/engine/runtime/ManifestContext.js +56 -0
  34. package/dist/engine/runtime/ManifestContext.js.map +1 -0
  35. package/dist/engine/runtime/MqttContext.d.ts +14 -0
  36. package/dist/engine/runtime/MqttContext.d.ts.map +1 -0
  37. package/dist/engine/runtime/MqttContext.js +70 -0
  38. package/dist/engine/runtime/MqttContext.js.map +1 -0
  39. package/dist/engine/runtime/SitemapContext.d.ts +31 -0
  40. package/dist/engine/runtime/SitemapContext.d.ts.map +1 -0
  41. package/dist/engine/runtime/SitemapContext.js +54 -0
  42. package/dist/engine/runtime/SitemapContext.js.map +1 -0
  43. package/dist/engine/runtime/data-seeder.d.ts +10 -0
  44. package/dist/engine/runtime/data-seeder.d.ts.map +1 -0
  45. package/dist/engine/runtime/data-seeder.js +35 -0
  46. package/dist/engine/runtime/data-seeder.js.map +1 -0
  47. package/dist/engine/runtime/useAction.d.ts +4 -0
  48. package/dist/engine/runtime/useAction.d.ts.map +1 -0
  49. package/dist/engine/runtime/useAction.js +55 -0
  50. package/dist/engine/runtime/useAction.js.map +1 -0
  51. package/dist/engine/runtime/useCrudLocalStorage.d.ts +19 -0
  52. package/dist/engine/runtime/useCrudLocalStorage.d.ts.map +1 -0
  53. package/dist/engine/runtime/useCrudLocalStorage.js +73 -0
  54. package/dist/engine/runtime/useCrudLocalStorage.js.map +1 -0
  55. package/dist/engine/runtime/useDataQuery.d.ts +39 -0
  56. package/dist/engine/runtime/useDataQuery.d.ts.map +1 -0
  57. package/dist/engine/runtime/useDataQuery.js +50 -0
  58. package/dist/engine/runtime/useDataQuery.js.map +1 -0
  59. package/dist/engine/runtime/useDynamicSitemap.d.ts +9 -0
  60. package/dist/engine/runtime/useDynamicSitemap.d.ts.map +1 -0
  61. package/dist/engine/runtime/useDynamicSitemap.js +38 -0
  62. package/dist/engine/runtime/useDynamicSitemap.js.map +1 -0
  63. package/dist/engine/runtime/useJustInTimeSeeder.d.ts +11 -0
  64. package/dist/engine/runtime/useJustInTimeSeeder.d.ts.map +1 -0
  65. package/dist/engine/runtime/useJustInTimeSeeder.js +88 -0
  66. package/dist/engine/runtime/useJustInTimeSeeder.js.map +1 -0
  67. package/dist/engine/runtime/useLiveBridge.d.ts +109 -0
  68. package/dist/engine/runtime/useLiveBridge.d.ts.map +1 -0
  69. package/dist/engine/runtime/useLiveBridge.js +21 -0
  70. package/dist/engine/runtime/useLiveBridge.js.map +1 -0
  71. package/dist/engine/runtime/useSignal.d.ts +11 -0
  72. package/dist/engine/runtime/useSignal.d.ts.map +1 -0
  73. package/dist/engine/runtime/useSignal.js +26 -0
  74. package/dist/engine/runtime/useSignal.js.map +1 -0
  75. package/dist/engine/runtime/useSignalStore.d.ts +31 -0
  76. package/dist/engine/runtime/useSignalStore.d.ts.map +1 -0
  77. package/dist/engine/runtime/useSignalStore.js +60 -0
  78. package/dist/engine/runtime/useSignalStore.js.map +1 -0
  79. package/dist/engine/runtime/useWorkflowEngine.d.ts +4 -0
  80. package/dist/engine/runtime/useWorkflowEngine.d.ts.map +1 -0
  81. package/dist/engine/runtime/useWorkflowEngine.js +85 -0
  82. package/dist/engine/runtime/useWorkflowEngine.js.map +1 -0
  83. package/dist/engine/types/manifest-types.d.ts +38 -0
  84. package/dist/engine/types/manifest-types.d.ts.map +1 -0
  85. package/dist/engine/types/manifest-types.js +5 -0
  86. package/dist/engine/types/manifest-types.js.map +1 -0
  87. package/dist/engine/types/sitemap-entry.d.ts +58 -0
  88. package/dist/engine/types/sitemap-entry.d.ts.map +1 -0
  89. package/dist/engine/types/sitemap-entry.js +19 -0
  90. package/dist/engine/types/sitemap-entry.js.map +1 -0
  91. package/dist/engine/validation/schema.d.ts +383 -0
  92. package/dist/engine/validation/schema.d.ts.map +1 -0
  93. package/dist/engine/validation/schema.js +156 -0
  94. package/dist/engine/validation/schema.js.map +1 -0
  95. package/dist/index.d.ts +22 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +24 -0
  98. package/dist/index.js.map +1 -0
  99. package/package.json +36 -0
  100. package/src/components/AutoForm.tsx +141 -0
  101. package/src/components/SmartTable.tsx +316 -0
  102. package/src/config/app.manifest.ts +7 -0
  103. package/src/engine/renderers/DynamicBlock.tsx +84 -0
  104. package/src/engine/renderers/DynamicPage.tsx +196 -0
  105. package/src/engine/renderers/route-generator.tsx +47 -0
  106. package/src/engine/renderers/sitemap-entry.ts +6 -0
  107. package/src/engine/runtime/ManifestContext.tsx +81 -0
  108. package/src/engine/runtime/MqttContext.tsx +94 -0
  109. package/src/engine/runtime/SitemapContext.tsx +61 -0
  110. package/src/engine/runtime/data-seeder.ts +39 -0
  111. package/src/engine/runtime/useAction.ts +64 -0
  112. package/src/engine/runtime/useCrudLocalStorage.ts +82 -0
  113. package/src/engine/runtime/useDataQuery.ts +98 -0
  114. package/src/engine/runtime/useDynamicSitemap.tsx +43 -0
  115. package/src/engine/runtime/useJustInTimeSeeder.ts +101 -0
  116. package/src/engine/runtime/useLiveBridge.ts +24 -0
  117. package/src/engine/runtime/useSignal.ts +40 -0
  118. package/src/engine/runtime/useSignalStore.ts +94 -0
  119. package/src/engine/runtime/useWorkflowEngine.ts +89 -0
  120. package/src/engine/types/manifest-types.ts +45 -0
  121. package/src/engine/types/sitemap-entry.ts +66 -0
  122. package/src/engine/validation/schema.ts +189 -0
  123. package/src/index.ts +27 -0
  124. package/tsconfig.json +28 -0
@@ -0,0 +1,7 @@
1
+ export interface SitemapEntry {
2
+ id: string;
3
+ path: string;
4
+ component: React.ComponentType;
5
+ children?: SitemapEntry[];
6
+ }
7
+ //# sourceMappingURL=sitemap-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap-entry.d.ts","sourceRoot":"","sources":["../../../src/engine/renderers/sitemap-entry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;IAC/B,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sitemap-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap-entry.js","sourceRoot":"","sources":["../../../src/engine/renderers/sitemap-entry.ts"],"names":[],"mappings":""}
@@ -0,0 +1,115 @@
1
+ import React from 'react';
2
+ import type { AppSpecification } from '../validation/schema';
3
+ interface ManifestProviderProps {
4
+ children: React.ReactNode;
5
+ manifest: AppSpecification;
6
+ }
7
+ export declare const ManifestProvider: React.FC<ManifestProviderProps>;
8
+ export declare const useManifest: () => {
9
+ meta: {
10
+ name: string;
11
+ version: string;
12
+ description?: string;
13
+ author?: string;
14
+ createdAt?: string;
15
+ };
16
+ config: {
17
+ theme: "light" | "dark" | "system" | "corporate" | "midnight" | "blueprint";
18
+ mockMode: boolean;
19
+ brokerUrl?: string;
20
+ };
21
+ domain: {
22
+ signals: {
23
+ id: string;
24
+ label: string;
25
+ kind: "status" | "sensor" | "actuator" | "setpoint" | "metric" | "kpi";
26
+ source: "mock" | "mqtt" | "http" | "derived" | "local";
27
+ refreshRate: number;
28
+ description?: string;
29
+ topic?: string;
30
+ endpoint?: string;
31
+ jsonPath?: string;
32
+ defaultValue?: any;
33
+ unit?: string;
34
+ min?: number;
35
+ max?: number;
36
+ }[];
37
+ entities: {
38
+ id: string;
39
+ name: string;
40
+ type: string;
41
+ category: string;
42
+ signals: string[];
43
+ description?: string;
44
+ ui?: {
45
+ icon?: string;
46
+ color?: string;
47
+ dashboardComponent?: string;
48
+ };
49
+ }[];
50
+ workflows?: {
51
+ id: string;
52
+ name: string;
53
+ active: boolean;
54
+ trigger: {
55
+ id: string;
56
+ type: "signal_change" | "manual_action" | "schedule" | "webhook";
57
+ config: Record<string, any>;
58
+ };
59
+ actions: {
60
+ id: string;
61
+ type: "update_resource" | "send_notification" | "mqtt_publish" | "api_call" | "navigate" | "agent_task";
62
+ config: Record<string, any>;
63
+ }[];
64
+ }[];
65
+ };
66
+ modules?: string[];
67
+ resources?: {
68
+ id: string;
69
+ name: string;
70
+ fields: {
71
+ key: string;
72
+ label: string;
73
+ type: "number" | "boolean" | "text" | "currency" | "date" | "status" | "email" | "image" | "textarea";
74
+ required?: boolean;
75
+ description?: string;
76
+ defaultValue?: any;
77
+ }[];
78
+ defaultView?: "table" | "grid" | "list";
79
+ features?: {
80
+ searchable?: boolean;
81
+ creatable?: boolean;
82
+ editable?: boolean;
83
+ deletable?: boolean;
84
+ exportable?: boolean;
85
+ };
86
+ }[];
87
+ pages?: {
88
+ id: string;
89
+ slug: string;
90
+ title: string;
91
+ sections: {
92
+ id: string;
93
+ blocks: {
94
+ id: string;
95
+ type: string;
96
+ props: Record<string, any>;
97
+ layout?: {
98
+ colSpan?: number;
99
+ rowSpan?: number;
100
+ };
101
+ }[];
102
+ title?: string;
103
+ description?: string;
104
+ layout?: {
105
+ columns?: number;
106
+ variant?: "grid" | "stack" | "split";
107
+ };
108
+ }[];
109
+ description?: string;
110
+ icon?: string;
111
+ }[];
112
+ };
113
+ export declare const useBridgeStatus: () => "live" | "static";
114
+ export {};
115
+ //# sourceMappingURL=ManifestContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManifestContext.d.ts","sourceRoot":"","sources":["../../../src/engine/runtime/ManifestContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiE,MAAM,OAAO,CAAC;AAEtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAS7D,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAgD5D,CAAC;AAIF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMvB,CAAC;AAGF,eAAO,MAAM,eAAe,yBAG3B,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useState, useRef } from 'react';
3
+ const ManifestContext = createContext(null);
4
+ export const ManifestProvider = ({ children, manifest: initialManifest }) => {
5
+ // 1. Initialize State
6
+ const [manifest, setManifest] = useState(initialManifest);
7
+ const [isLive, setIsLive] = useState(false);
8
+ // 2. Global Listener Guard (Refs persist across re-renders)
9
+ const isListening = useRef(false);
10
+ useEffect(() => {
11
+ // Prevent double-attaching listeners in StrictMode
12
+ if (isListening.current)
13
+ return;
14
+ isListening.current = true;
15
+ // A. Define the Listener
16
+ const handleMessage = (event) => {
17
+ // Security: Filter out noise, listen only for our specific event
18
+ if (event.data?.type === 'RAMME_SYNC_MANIFEST') {
19
+ const payload = event.data.payload;
20
+ // console.log("⚡️ [Context] Sync Received");
21
+ setManifest(payload);
22
+ setIsLive(true);
23
+ }
24
+ };
25
+ // B. Attach Listener
26
+ window.addEventListener('message', handleMessage);
27
+ // C. Send Handshake (ONCE per session)
28
+ // We check a global window property to ensure we never spam the parent,
29
+ // even if this Provider is unmounted and remounted by React Router.
30
+ if (window.parent !== window && !window.__RAMME_HANDSHAKE_SENT) {
31
+ console.log("🔌 [Context] Handshake Sent 🤝");
32
+ window.parent.postMessage({ type: 'RAMME_CLIENT_READY' }, '*');
33
+ window.__RAMME_HANDSHAKE_SENT = true;
34
+ }
35
+ // Cleanup
36
+ return () => {
37
+ window.removeEventListener('message', handleMessage);
38
+ isListening.current = false;
39
+ };
40
+ }, []);
41
+ return (_jsx(ManifestContext.Provider, { value: { manifest, isLive }, children: children }));
42
+ };
43
+ // --- CONSUMER HOOKS ---
44
+ export const useManifest = () => {
45
+ const context = useContext(ManifestContext);
46
+ if (!context) {
47
+ throw new Error('useManifest must be used within a ManifestProvider');
48
+ }
49
+ return context.manifest;
50
+ };
51
+ // Returns 'live' | 'static' string to match your UI components
52
+ export const useBridgeStatus = () => {
53
+ const context = useContext(ManifestContext);
54
+ return context?.isLive ? 'live' : 'static';
55
+ };
56
+ //# sourceMappingURL=ManifestContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManifestContext.js","sourceRoot":"","sources":["../../../src/engine/runtime/ManifestContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAStF,MAAM,eAAe,GAAG,aAAa,CAA6B,IAAI,CAAC,CAAC;AAOxE,MAAM,CAAC,MAAM,gBAAgB,GAAoC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,EAAE,EAAE;IAC3G,sBAAsB;IACtB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAmB,eAAe,CAAC,CAAC;IAC5E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,4DAA4D;IAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAElC,SAAS,CAAC,GAAG,EAAE;QACb,mDAAmD;QACnD,IAAI,WAAW,CAAC,OAAO;YAAE,OAAO;QAChC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC;QAE3B,yBAAyB;QACzB,MAAM,aAAa,GAAG,CAAC,KAAmB,EAAE,EAAE;YAC5C,iEAAiE;YACjE,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;gBACnC,6CAA6C;gBAC7C,WAAW,CAAC,OAAO,CAAC,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;QAEF,qBAAqB;QACrB,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAElD,uCAAuC;QACvC,wEAAwE;QACxE,oEAAoE;QACpE,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,CAAE,MAAc,CAAC,sBAAsB,EAAE,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;YAC9C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;YAC9D,MAAc,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACjD,CAAC;QAED,UAAU;QACV,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YACrD,WAAW,CAAC,OAAO,GAAG,KAAK,CAAC;QAC9B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,KAAC,eAAe,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YAClD,QAAQ,GACgB,CAC5B,CAAC;AACJ,CAAC,CAAC;AAEF,yBAAyB;AAEzB,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE;IAC9B,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,OAAO,CAAC,QAAQ,CAAC;AAC1B,CAAC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE;IAClC,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC5C,OAAO,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC7C,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ interface MqttContextType {
3
+ isConnected: boolean;
4
+ lastMessage: Record<string, string>;
5
+ publish: (topic: string, message: string) => void;
6
+ subscribe: (topic: string) => void;
7
+ unsubscribe: (topic: string) => void;
8
+ }
9
+ export declare const MqttProvider: React.FC<{
10
+ children: React.ReactNode;
11
+ }>;
12
+ export declare const useMqtt: () => MqttContextType;
13
+ export {};
14
+ //# sourceMappingURL=MqttContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MqttContext.d.ts","sourceRoot":"","sources":["../../../src/engine/runtime/MqttContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiE,MAAM,OAAO,CAAC;AAMtF,UAAU,eAAe;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAuEhE,CAAC;AAEF,eAAO,MAAM,OAAO,uBAInB,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useRef, useState } from 'react';
3
+ import mqtt from 'mqtt';
4
+ // ❌ REMOVED: import { appManifest } from '../../config/app.manifest';
5
+ // ✅ ADDED: Live Context
6
+ import { useManifest } from './ManifestContext';
7
+ const MqttContext = createContext(null);
8
+ export const MqttProvider = ({ children }) => {
9
+ const [isConnected, setIsConnected] = useState(false);
10
+ const [lastMessage, setLastMessage] = useState({});
11
+ const clientRef = useRef(null);
12
+ const subscriptions = useRef(new Set());
13
+ // ✅ 1. Consume Live Manifest
14
+ const appManifest = useManifest();
15
+ useEffect(() => {
16
+ // ✅ 2. Hot-Swap Broker Connection
17
+ // If you change the Broker URL in the Builder, this effect will re-run!
18
+ const brokerUrl = appManifest.config.brokerUrl || 'wss://test.mosquitto.org:8081';
19
+ console.log(`[MQTT] Connecting to ${brokerUrl}...`);
20
+ // Disconnect previous if exists
21
+ if (clientRef.current) {
22
+ clientRef.current.end();
23
+ }
24
+ const client = mqtt.connect(brokerUrl);
25
+ clientRef.current = client;
26
+ client.on('connect', () => {
27
+ console.log('[MQTT] Connected ✅');
28
+ setIsConnected(true);
29
+ // Re-subscribe to previous topics if needed
30
+ subscriptions.current.forEach(t => client.subscribe(t));
31
+ });
32
+ client.on('message', (topic, payload) => {
33
+ const messageStr = payload.toString();
34
+ setLastMessage((prev) => ({ ...prev, [topic]: messageStr }));
35
+ });
36
+ client.on('error', (err) => {
37
+ console.error('[MQTT] Connection error: ', err);
38
+ client.end();
39
+ });
40
+ return () => {
41
+ console.log('[MQTT] Disconnecting...');
42
+ client.end();
43
+ };
44
+ }, [appManifest.config.brokerUrl]); // Only re-connect if URL changes
45
+ const subscribe = (topic) => {
46
+ if (clientRef.current && !subscriptions.current.has(topic)) {
47
+ clientRef.current.subscribe(topic);
48
+ subscriptions.current.add(topic);
49
+ }
50
+ };
51
+ const unsubscribe = (topic) => {
52
+ if (clientRef.current && subscriptions.current.has(topic)) {
53
+ clientRef.current.unsubscribe(topic);
54
+ subscriptions.current.delete(topic);
55
+ }
56
+ };
57
+ const publish = (topic, message) => {
58
+ if (clientRef.current) {
59
+ clientRef.current.publish(topic, message);
60
+ }
61
+ };
62
+ return (_jsx(MqttContext.Provider, { value: { isConnected, lastMessage, subscribe, unsubscribe, publish }, children: children }));
63
+ };
64
+ export const useMqtt = () => {
65
+ const context = useContext(MqttContext);
66
+ if (!context)
67
+ throw new Error('useMqtt must be used within an MqttProvider');
68
+ return context;
69
+ };
70
+ //# sourceMappingURL=MqttContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MqttContext.js","sourceRoot":"","sources":["../../../src/engine/runtime/MqttContext.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @file SitemapContext.tsx
3
+ * @repository ramme-app-starter
4
+ * @description This file implements a React Context for the sitemap.
5
+ *
6
+ * STRATEGIC IMPORTANCE:
7
+ * This context is the "plumbing" that makes our swappable layout
8
+ * strategy possible. It allows a top-level layout component (like
9
+ * `DashboardLayout.tsx` or `DocsLayout.tsx`) to "provide" its specific
10
+ * sitemap array (e.g., `dashboard.sitemap.ts`) to all of its children.
11
+ *
12
+ * Any component deep in the tree (like a sidebar, breadcrumbs, or page
13
+ * header) can then "consume" this sitemap data using the `useSitemap`
14
+ * hook to render the correct navigation, titles, and icons.
15
+ *
16
+ * This effectively decouples the navigation UI from the sitemap data,
17
+ * allowing us to change the entire application's IA simply by changing
18
+ * the data provided by the `SitemapProvider`.
19
+ */
20
+ import type { SitemapEntry } from '../types/sitemap-entry';
21
+ /**
22
+ * A custom hook to easily access the active sitemap array.
23
+ * This abstracts the `useContext` logic and provides a clean API
24
+ * for components that need to read the sitemap.
25
+ *
26
+ * @returns {SitemapEntry[]} The sitemap array provided by the nearest
27
+ * `SitemapProvider`.
28
+ */
29
+ export declare const useSitemap: () => SitemapEntry[];
30
+ export declare const SitemapProvider: import("react").Provider<SitemapEntry[]>;
31
+ //# sourceMappingURL=SitemapContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SitemapContext.d.ts","sourceRoot":"","sources":["../../../src/engine/runtime/SitemapContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAO3D;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,sBAWtB,CAAC;AAYF,eAAO,MAAM,eAAe,0CAA0B,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @file SitemapContext.tsx
3
+ * @repository ramme-app-starter
4
+ * @description This file implements a React Context for the sitemap.
5
+ *
6
+ * STRATEGIC IMPORTANCE:
7
+ * This context is the "plumbing" that makes our swappable layout
8
+ * strategy possible. It allows a top-level layout component (like
9
+ * `DashboardLayout.tsx` or `DocsLayout.tsx`) to "provide" its specific
10
+ * sitemap array (e.g., `dashboard.sitemap.ts`) to all of its children.
11
+ *
12
+ * Any component deep in the tree (like a sidebar, breadcrumbs, or page
13
+ * header) can then "consume" this sitemap data using the `useSitemap`
14
+ * hook to render the correct navigation, titles, and icons.
15
+ *
16
+ * This effectively decouples the navigation UI from the sitemap data,
17
+ * allowing us to change the entire application's IA simply by changing
18
+ * the data provided by the `SitemapProvider`.
19
+ */
20
+ import { createContext, useContext } from 'react';
21
+ // 1. Create the context
22
+ // We initialize it with an empty array as a safe default.
23
+ // This context will hold the sitemap array specific to the active layout.
24
+ const SitemapContext = createContext([]);
25
+ /**
26
+ * A custom hook to easily access the active sitemap array.
27
+ * This abstracts the `useContext` logic and provides a clean API
28
+ * for components that need to read the sitemap.
29
+ *
30
+ * @returns {SitemapEntry[]} The sitemap array provided by the nearest
31
+ * `SitemapProvider`.
32
+ */
33
+ export const useSitemap = () => {
34
+ const context = useContext(SitemapContext);
35
+ // This is a critical developer-friendly check.
36
+ // If a component tries to call `useSitemap` outside of a layout
37
+ // that provides the context, we throw an explicit error.
38
+ if (context === undefined) {
39
+ throw new Error('useSitemap must be used within a SitemapProvider');
40
+ }
41
+ return context;
42
+ };
43
+ // 3. Export the Provider
44
+ // We export the Provider component directly. This is what our layout
45
+ // components will use to wrap their content and supply the sitemap data.
46
+ //
47
+ // Example Usage (in a layout file):
48
+ // <SitemapProvider value={dashboardSitemap}>
49
+ // <AppHeader />
50
+ // <AppSidebar />
51
+ // <Outlet />
52
+ // </SitemapProvider>
53
+ export const SitemapProvider = SitemapContext.Provider;
54
+ //# sourceMappingURL=SitemapContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SitemapContext.js","sourceRoot":"","sources":["../../../src/engine/runtime/SitemapContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAIlD,wBAAwB;AACxB,0DAA0D;AAC1D,0EAA0E;AAC1E,MAAM,cAAc,GAAG,aAAa,CAAiB,EAAE,CAAC,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE;IAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAE3C,+CAA+C;IAC/C,gEAAgE;IAChE,yDAAyD;IACzD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,yBAAyB;AACzB,qEAAqE;AACrE,yEAAyE;AACzE,EAAE;AACF,oCAAoC;AACpC,6CAA6C;AAC7C,kBAAkB;AAClB,mBAAmB;AACnB,eAAe;AACf,qBAAqB;AACrB,MAAM,CAAC,MAAM,eAAe,GAAG,cAAc,CAAC,QAAQ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @file data-seeder.ts
3
+ * @description The "Big Bang" for the client-side database.
4
+ * * ARCHITECTURAL ROLE:
5
+ * This utility ensures that the LocalStorage "Data Lake" is never empty.
6
+ * On app launch, it checks if data exists. If not, it writes the seed data
7
+ * provided by the Kernel/Manifest into the browser's storage.
8
+ */
9
+ export declare const initializeDataLake: (registry: Record<string, any[]>) => void;
10
+ //# sourceMappingURL=data-seeder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-seeder.d.ts","sourceRoot":"","sources":["../../../src/engine/runtime/data-seeder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,SAyBjE,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @file data-seeder.ts
3
+ * @description The "Big Bang" for the client-side database.
4
+ * * ARCHITECTURAL ROLE:
5
+ * This utility ensures that the LocalStorage "Data Lake" is never empty.
6
+ * On app launch, it checks if data exists. If not, it writes the seed data
7
+ * provided by the Kernel/Manifest into the browser's storage.
8
+ */
9
+ // 🔒 CRITICAL FIX: Changed from 'ramme_mock_' to 'ramme_db_' to match AuthContext
10
+ // This ensures that the AuthProvider can actually find the 'users' table we seed.
11
+ const DB_PREFIX = 'ramme_db_';
12
+ export const initializeDataLake = (registry) => {
13
+ if (typeof window === 'undefined')
14
+ return;
15
+ // Safety check: Don't crash if the registry is missing (e.g. during early boot)
16
+ if (!registry) {
17
+ console.warn('⚠️ [Data Lake] No registry provided to seeder. Skipping initialization.');
18
+ return;
19
+ }
20
+ console.groupCollapsed('🌊 [Data Lake] Initialization');
21
+ Object.entries(registry).forEach(([key, seedData]) => {
22
+ const storageKey = `${DB_PREFIX}${key}`;
23
+ const existing = localStorage.getItem(storageKey);
24
+ if (!existing) {
25
+ console.log(`✨ Seeding collection: ${key}`);
26
+ localStorage.setItem(storageKey, JSON.stringify(seedData));
27
+ }
28
+ else {
29
+ // Optional: Debug log for existing data (helps verify persistence)
30
+ // console.log(`✅ Found existing data for: ${key}`);
31
+ }
32
+ });
33
+ console.groupEnd();
34
+ };
35
+ //# sourceMappingURL=data-seeder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-seeder.js","sourceRoot":"","sources":["../../../src/engine/runtime/data-seeder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,kFAAkF;AAClF,kFAAkF;AAClF,MAAM,SAAS,GAAG,WAAW,CAAC;AAE9B,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAA+B,EAAE,EAAE;IACpE,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO;IAE1C,gFAAgF;IAChF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;QACxF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,cAAc,CAAC,+BAA+B,CAAC,CAAC;IAExD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE;QACnD,MAAM,UAAU,GAAG,GAAG,SAAS,GAAG,GAAG,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;YAC5C,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YACJ,mEAAmE;YACnE,oDAAoD;QACxD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,QAAQ,EAAE,CAAC;AACrB,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const useAction: () => {
2
+ sendAction: (entityId: string, value: any) => Promise<void>;
3
+ };
4
+ //# sourceMappingURL=useAction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAction.d.ts","sourceRoot":"","sources":["../../../src/engine/runtime/useAction.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,SAAS;2BAO4B,MAAM,SAAS,GAAG;CAkDnE,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { useCallback } from 'react';
2
+ import { useMqtt } from './MqttContext';
3
+ // ❌ REMOVED: import { appManifest } from '../../config/app.manifest';
4
+ // ✅ ADDED: Live Context
5
+ import { useManifest } from './ManifestContext';
6
+ export const useAction = () => {
7
+ const { publish, isConnected } = useMqtt();
8
+ // ✅ 1. Consume Live Manifest
9
+ const appManifest = useManifest();
10
+ const { config, domain } = appManifest;
11
+ const sendAction = useCallback(async (entityId, value) => {
12
+ // 2. Find the Entity definition (Live)
13
+ const entity = domain.entities.find(e => e.id === entityId);
14
+ if (!entity) {
15
+ console.warn(`[Action] Entity ID '${entityId}' not found in manifest.`);
16
+ return;
17
+ }
18
+ const signalId = entity.signals[0];
19
+ const signal = domain.signals.find(s => s.id === signalId);
20
+ if (!signal) {
21
+ console.warn(`[Action] No signal linked to entity: ${entityId}`);
22
+ return;
23
+ }
24
+ // --- Mock Mode ---
25
+ if (config.mockMode) {
26
+ console.log(`%c[Mock Action] Setting ${entity.name} to:`, 'color: #10b981; font-weight: bold;', value);
27
+ return;
28
+ }
29
+ // --- Live Mode (MQTT) ---
30
+ if (signal.source === 'mqtt' && signal.topic) {
31
+ if (!isConnected) {
32
+ console.warn('[Action] Cannot send: MQTT disconnected');
33
+ return;
34
+ }
35
+ const payload = typeof value === 'object' ? JSON.stringify(value) : String(value);
36
+ console.log(`[MQTT] Publishing to '${signal.topic}': ${payload}`);
37
+ publish(signal.topic, payload);
38
+ }
39
+ // --- Live Mode (HTTP) ---
40
+ if (signal.source === 'http' && signal.endpoint) {
41
+ try {
42
+ await fetch(signal.endpoint, {
43
+ method: 'POST',
44
+ headers: { 'Content-Type': 'application/json' },
45
+ body: JSON.stringify({ id: signal.id, value })
46
+ });
47
+ }
48
+ catch (err) {
49
+ console.log('[HTTP] (Simulation) Request sent.');
50
+ }
51
+ }
52
+ }, [config.mockMode, isConnected, publish, domain]);
53
+ return { sendAction };
54
+ };
55
+ //# sourceMappingURL=useAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAction.js","sourceRoot":"","sources":["../../../src/engine/runtime/useAction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @hook useCrudLocalStorage
3
+ * @description A generic hook for performing CRUD (Create, Read, Update, Delete)
4
+ * operations on an array of items stored in the browser's localStorage.
5
+ * * It serves as the "Database Engine" for the mock runtime.
6
+ *
7
+ * @param storageKey The unique key for this data in localStorage (e.g., 'ramme_db_users').
8
+ * @param initialData The default data to seed localStorage with if it's empty.
9
+ * @returns An object with the current data and functions to manipulate it.
10
+ */
11
+ export declare const useCrudLocalStorage: <T extends {
12
+ id: any;
13
+ }>(storageKey: string, initialData: T[]) => {
14
+ data: T[];
15
+ createItem: (newItem: Omit<T, "id">) => void;
16
+ updateItem: (updatedItem: T) => void;
17
+ deleteItem: (id: T["id"]) => void;
18
+ };
19
+ //# sourceMappingURL=useCrudLocalStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCrudLocalStorage.d.ts","sourceRoot":"","sources":["../../../src/engine/runtime/useCrudLocalStorage.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EACvD,YAAY,MAAM,EAClB,aAAa,CAAC,EAAE;;0BAuByB,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;8BAwBT,CAAC;qBAWV,CAAC,CAAC,IAAI,CAAC;CAS5C,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { useState, useCallback } from 'react';
2
+ /**
3
+ * @hook useCrudLocalStorage
4
+ * @description A generic hook for performing CRUD (Create, Read, Update, Delete)
5
+ * operations on an array of items stored in the browser's localStorage.
6
+ * * It serves as the "Database Engine" for the mock runtime.
7
+ *
8
+ * @param storageKey The unique key for this data in localStorage (e.g., 'ramme_db_users').
9
+ * @param initialData The default data to seed localStorage with if it's empty.
10
+ * @returns An object with the current data and functions to manipulate it.
11
+ */
12
+ export const useCrudLocalStorage = (storageKey, initialData) => {
13
+ // 1. Initialize State from LocalStorage
14
+ const [data, setData] = useState(() => {
15
+ // Safety check for Server-Side Rendering
16
+ if (typeof window === 'undefined')
17
+ return initialData;
18
+ try {
19
+ const item = window.localStorage.getItem(storageKey);
20
+ if (item) {
21
+ return JSON.parse(item);
22
+ }
23
+ else {
24
+ // Seed the "DB" if empty
25
+ window.localStorage.setItem(storageKey, JSON.stringify(initialData));
26
+ return initialData;
27
+ }
28
+ }
29
+ catch (error) {
30
+ console.error(`[Data Lake] Error reading key "${storageKey}":`, error);
31
+ return initialData;
32
+ }
33
+ });
34
+ // 2. CREATE
35
+ const createItem = useCallback((newItem) => {
36
+ setData(prevData => {
37
+ // ✅ ROBUST ID GENERATION (Zero Jank)
38
+ // Detects if existing IDs are Numbers or Strings to prevent type conflicts.
39
+ let newId;
40
+ const isNumeric = prevData.length > 0 && typeof prevData[0].id === 'number';
41
+ if (isNumeric) {
42
+ const maxId = prevData.reduce((max, item) => (typeof item.id === 'number' && item.id > max ? item.id : max), 0);
43
+ newId = maxId + 1;
44
+ }
45
+ else {
46
+ // Fallback for string IDs (e.g. 'usr_17354...')
47
+ newId = `id_${Date.now()}`;
48
+ }
49
+ const fullNewItem = { ...newItem, id: newId };
50
+ const updatedData = [...prevData, fullNewItem];
51
+ window.localStorage.setItem(storageKey, JSON.stringify(updatedData));
52
+ return updatedData;
53
+ });
54
+ }, [storageKey]);
55
+ // 3. UPDATE
56
+ const updateItem = useCallback((updatedItem) => {
57
+ setData(prevData => {
58
+ const updatedData = prevData.map(item => item.id === updatedItem.id ? updatedItem : item);
59
+ window.localStorage.setItem(storageKey, JSON.stringify(updatedData));
60
+ return updatedData;
61
+ });
62
+ }, [storageKey]);
63
+ // 4. DELETE
64
+ const deleteItem = useCallback((id) => {
65
+ setData(prevData => {
66
+ const updatedData = prevData.filter(item => item.id !== id);
67
+ window.localStorage.setItem(storageKey, JSON.stringify(updatedData));
68
+ return updatedData;
69
+ });
70
+ }, [storageKey]);
71
+ return { data, createItem, updateItem, deleteItem };
72
+ };
73
+ //# sourceMappingURL=useCrudLocalStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCrudLocalStorage.js","sourceRoot":"","sources":["../../../src/engine/runtime/useCrudLocalStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,UAAkB,EAClB,WAAgB,EAChB,EAAE;IACF,wCAAwC;IACxC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAM,GAAG,EAAE;QACzC,yCAAyC;QACzC,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,WAAW,CAAC;QAEtD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACrD,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,yBAAyB;gBACzB,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;gBACrE,OAAO,WAAW,CAAC;YACrB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,UAAU,IAAI,EAAE,KAAK,CAAC,CAAC;YACvE,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,YAAY;IACZ,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,OAAsB,EAAE,EAAE;QACxD,OAAO,CAAC,QAAQ,CAAC,EAAE;YACjB,qCAAqC;YACrC,4EAA4E;YAC5E,IAAI,KAAU,CAAC;YACf,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;YAE5E,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChH,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,gDAAgD;gBAChD,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAC7B,CAAC;YAED,MAAM,WAAW,GAAG,EAAE,GAAG,OAAO,EAAE,EAAE,EAAE,KAAK,EAAO,CAAC;YAEnD,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,EAAE,WAAW,CAAC,CAAC;YAC/C,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;YACrE,OAAO,WAAW,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,YAAY;IACZ,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,WAAc,EAAE,EAAE;QAChD,OAAO,CAAC,QAAQ,CAAC,EAAE;YACjB,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACtC,IAAI,CAAC,EAAE,KAAK,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAChD,CAAC;YACF,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;YACrE,OAAO,WAAW,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,YAAY;IACZ,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,EAAW,EAAE,EAAE;QAC7C,OAAO,CAAC,QAAQ,CAAC,EAAE;YACjB,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5D,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;YACrE,OAAO,WAAW,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AACtD,CAAC,CAAC"}