dynim-react 1.0.28 → 1.0.30
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/DynimProvider.d.ts +67 -0
- package/dist/DynimProvider.d.ts.map +1 -0
- package/dist/DynimProvider.js +362 -0
- package/dist/builder/BuilderProvider.d.ts +3 -14
- package/dist/builder/BuilderProvider.d.ts.map +1 -1
- package/dist/builder/BuilderProvider.js +56 -102
- package/dist/builder/CodeChatPanel.d.ts.map +1 -1
- package/dist/builder/CodeChatPanel.js +84 -79
- package/dist/builder/useChatbot.d.ts +5 -1
- package/dist/builder/useChatbot.d.ts.map +1 -1
- package/dist/builder/useChatbot.js +29 -54
- package/dist/index.d.ts +14 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -19
- package/dist/inference/InferenceProvider.d.ts +1 -20
- package/dist/inference/InferenceProvider.d.ts.map +1 -1
- package/dist/inference/InferenceProvider.js +65 -57
- package/dist/inference/sharedContext.d.ts +11 -1
- package/dist/inference/sharedContext.d.ts.map +1 -1
- package/dist/inference/sharedContext.js +40 -18
- package/dist/inference/types.d.ts +7 -24
- package/dist/inference/types.d.ts.map +1 -1
- package/dist/theme.d.ts +99 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +147 -0
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/vite/plugin.js +2 -1
- package/package.json +3 -23
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DynimProvider - Single provider for all Dynim functionality
|
|
3
|
+
*
|
|
4
|
+
* Handles:
|
|
5
|
+
* - Loading tenant bundles
|
|
6
|
+
* - Visual builder UI (when user has edit permissions)
|
|
7
|
+
* - Shared context for bundles to access React, packages, etc.
|
|
8
|
+
*/
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
|
+
import type { CodeMessage } from 'dynim-core';
|
|
11
|
+
export interface DynimConfig {
|
|
12
|
+
/** Function to fetch a new session when current one expires */
|
|
13
|
+
getSession?: () => Promise<{
|
|
14
|
+
token: string;
|
|
15
|
+
refreshToken?: string;
|
|
16
|
+
}>;
|
|
17
|
+
/** Called when an error occurs */
|
|
18
|
+
onError?: (error: Event | Error) => void;
|
|
19
|
+
/** NPM packages to expose to bundles (e.g., { 'react-router-dom': ReactRouterDOM }) */
|
|
20
|
+
packages?: Record<string, unknown>;
|
|
21
|
+
/** Custom hooks to expose to bundles */
|
|
22
|
+
hooks?: Record<string, unknown>;
|
|
23
|
+
/** React contexts to expose to bundles */
|
|
24
|
+
contexts?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface DynimContextValue {
|
|
27
|
+
/** Enter edit mode (shows builder UI) */
|
|
28
|
+
enterBuilder: () => void;
|
|
29
|
+
/** Exit edit mode */
|
|
30
|
+
exitBuilder: () => void;
|
|
31
|
+
/** Whether builder/edit mode is active */
|
|
32
|
+
isEditing: boolean;
|
|
33
|
+
/** Send a code edit request to AI */
|
|
34
|
+
sendCode: (query: string) => Promise<void>;
|
|
35
|
+
/** Save current edits */
|
|
36
|
+
saveCode: () => Promise<void>;
|
|
37
|
+
/** Abandon/discard current edits */
|
|
38
|
+
abandonCode: () => Promise<void>;
|
|
39
|
+
/** Current code message state (thinking, edits, etc.) */
|
|
40
|
+
codeMessage: CodeMessage;
|
|
41
|
+
/** Whether a bundle is currently loaded */
|
|
42
|
+
isBundleLoaded: boolean;
|
|
43
|
+
/** Whether bundle is loading */
|
|
44
|
+
isBundleLoading: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface DynimProviderProps {
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
config?: DynimConfig;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* DynimProvider - Wrap your app with this to enable Dynim functionality
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* import { DynimProvider } from 'dynim-react';
|
|
56
|
+
*
|
|
57
|
+
* <DynimProvider>
|
|
58
|
+
* <App />
|
|
59
|
+
* </DynimProvider>
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function DynimProvider({ children, config, }: DynimProviderProps): JSX.Element;
|
|
63
|
+
/**
|
|
64
|
+
* Hook to access Dynim functionality
|
|
65
|
+
*/
|
|
66
|
+
export declare function useDynim(): DynimContextValue;
|
|
67
|
+
//# sourceMappingURL=DynimProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DynimProvider.d.ts","sourceRoot":"","sources":["../src/DynimProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAc,EAQZ,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAUf,OAAO,KAAK,EAKV,WAAW,EAEZ,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,kCAAkC;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,KAAK,IAAI,CAAC;IACzC,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,qBAAqB;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,yBAAyB;IACzB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,oCAAoC;IACpC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,yDAAyD;IACzD,WAAW,EAAE,WAAW,CAAC;IACzB,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;IACxB,gCAAgC;IAChC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAID,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,MAAW,GACZ,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAyXlC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C"}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { jsxs as _jsxs, Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* DynimProvider - Single provider for all Dynim functionality
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Loading tenant bundles
|
|
7
|
+
* - Visual builder UI (when user has edit permissions)
|
|
8
|
+
* - Shared context for bundles to access React, packages, etc.
|
|
9
|
+
*/
|
|
10
|
+
import React, { createContext, useContext, useEffect, useRef, useCallback, useMemo, useState, } from 'react';
|
|
11
|
+
import ReactDOM from 'react-dom';
|
|
12
|
+
import { createBuilderClient, createBuilder, createCodeClient, createBundleLoader, BundleNotFoundError, isSharedRegistryReady, } from 'dynim-core';
|
|
13
|
+
import { createSharedContext } from './inference/sharedContext';
|
|
14
|
+
import { generateThemeCSS } from './theme';
|
|
15
|
+
const DynimContext = createContext(null);
|
|
16
|
+
/**
|
|
17
|
+
* DynimProvider - Wrap your app with this to enable Dynim functionality
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import { DynimProvider } from 'dynim-react';
|
|
22
|
+
*
|
|
23
|
+
* <DynimProvider>
|
|
24
|
+
* <App />
|
|
25
|
+
* </DynimProvider>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function DynimProvider({ children, config = {}, }) {
|
|
29
|
+
const builderClientRef = useRef(null);
|
|
30
|
+
const builderRef = useRef(null);
|
|
31
|
+
const codeClientRef = useRef(null);
|
|
32
|
+
const bundleLoaderRef = useRef(null);
|
|
33
|
+
// Track when we're exiting to prevent auto-load from re-triggering
|
|
34
|
+
const isExitingRef = useRef(false);
|
|
35
|
+
const hasAttemptedInitialLoadRef = useRef(false);
|
|
36
|
+
const isBuilderActiveRef = useRef(false);
|
|
37
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
38
|
+
const [isBundleLoaded, setIsBundleLoaded] = useState(false);
|
|
39
|
+
const [isBundleLoading, setIsBundleLoading] = useState(false);
|
|
40
|
+
const [isInitialLoadComplete, setIsInitialLoadComplete] = useState(false);
|
|
41
|
+
const [TenantApp, setTenantApp] = useState(null);
|
|
42
|
+
const [bundleError, setBundleError] = useState(null);
|
|
43
|
+
const [codeMessage, setCodeMessage] = useState({
|
|
44
|
+
thinking: '',
|
|
45
|
+
text: '',
|
|
46
|
+
edits: [],
|
|
47
|
+
status: 'idle',
|
|
48
|
+
bundleReady: false,
|
|
49
|
+
bundleError: undefined,
|
|
50
|
+
});
|
|
51
|
+
// Cached auth token
|
|
52
|
+
const cachedTokenRef = useRef(null);
|
|
53
|
+
const tokenPromiseRef = useRef(null);
|
|
54
|
+
// Bundle load signal
|
|
55
|
+
const [bundleLoadSignal, setBundleLoadSignal] = useState(0);
|
|
56
|
+
const pendingBundleProjectIdRef = useRef(null);
|
|
57
|
+
// Theme state (fetched from API per project)
|
|
58
|
+
const [theme, setTheme] = useState(null);
|
|
59
|
+
const hasAttemptedThemeLoadRef = useRef(false);
|
|
60
|
+
// Keep config callbacks in refs
|
|
61
|
+
const configCallbacksRef = useRef({ onError: config.onError });
|
|
62
|
+
configCallbacksRef.current = { onError: config.onError };
|
|
63
|
+
// Set up shared context for bundles
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!isSharedRegistryReady()) {
|
|
66
|
+
const { packages = {}, hooks = {}, contexts = {} } = config;
|
|
67
|
+
createSharedContext({
|
|
68
|
+
React,
|
|
69
|
+
ReactDOM,
|
|
70
|
+
packages: {
|
|
71
|
+
'dynim-react': { DynimProvider, useDynim },
|
|
72
|
+
...packages,
|
|
73
|
+
},
|
|
74
|
+
hooks,
|
|
75
|
+
contexts,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}, [config]);
|
|
79
|
+
// Get auth token
|
|
80
|
+
const getAuthToken = useCallback(async () => {
|
|
81
|
+
if (cachedTokenRef.current)
|
|
82
|
+
return cachedTokenRef.current;
|
|
83
|
+
if (tokenPromiseRef.current)
|
|
84
|
+
return tokenPromiseRef.current;
|
|
85
|
+
const { getSession } = config;
|
|
86
|
+
if (getSession) {
|
|
87
|
+
tokenPromiseRef.current = (async () => {
|
|
88
|
+
try {
|
|
89
|
+
const session = await getSession();
|
|
90
|
+
cachedTokenRef.current = session.token;
|
|
91
|
+
return session.token;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
tokenPromiseRef.current = null;
|
|
98
|
+
}
|
|
99
|
+
})();
|
|
100
|
+
return tokenPromiseRef.current;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}, [config]);
|
|
104
|
+
// Initialize code client
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
const { getSession, onError } = config;
|
|
107
|
+
codeClientRef.current = createCodeClient({
|
|
108
|
+
getSession,
|
|
109
|
+
onMessageUpdate: setCodeMessage,
|
|
110
|
+
onError: (error) => {
|
|
111
|
+
console.error('[DynimProvider] Code error:', error);
|
|
112
|
+
onError?.(error);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}, [config]);
|
|
116
|
+
// Load bundle ref
|
|
117
|
+
const loadBundleRef = useRef(null);
|
|
118
|
+
// Initialize builder
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
const { getSession } = config;
|
|
121
|
+
builderRef.current = createBuilder({
|
|
122
|
+
getSession,
|
|
123
|
+
codeClient: codeClientRef.current ?? undefined,
|
|
124
|
+
onExitStart: () => {
|
|
125
|
+
isExitingRef.current = true;
|
|
126
|
+
isBuilderActiveRef.current = false;
|
|
127
|
+
codeClientRef.current?.abort();
|
|
128
|
+
codeClientRef.current?.resetMessage();
|
|
129
|
+
},
|
|
130
|
+
loadBundle: (bundleUrl) => {
|
|
131
|
+
isExitingRef.current = true;
|
|
132
|
+
return loadBundleRef.current?.(bundleUrl) ?? Promise.resolve();
|
|
133
|
+
},
|
|
134
|
+
onEnter: () => {
|
|
135
|
+
isExitingRef.current = false;
|
|
136
|
+
isBuilderActiveRef.current = true;
|
|
137
|
+
setIsEditing(true);
|
|
138
|
+
},
|
|
139
|
+
onExit: () => {
|
|
140
|
+
setIsEditing(false);
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
return () => {
|
|
144
|
+
builderRef.current?.destroy();
|
|
145
|
+
};
|
|
146
|
+
}, [config]);
|
|
147
|
+
// Initialize builder client
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
const { getSession, onError } = config;
|
|
150
|
+
builderClientRef.current = createBuilderClient({
|
|
151
|
+
getSession,
|
|
152
|
+
onError: (error) => {
|
|
153
|
+
console.error('[DynimProvider] Error:', error);
|
|
154
|
+
onError?.(error);
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}, [config]);
|
|
158
|
+
// Get bundle loader
|
|
159
|
+
const getBundleLoader = useCallback(() => {
|
|
160
|
+
if (!bundleLoaderRef.current) {
|
|
161
|
+
bundleLoaderRef.current = createBundleLoader({
|
|
162
|
+
getAuthToken,
|
|
163
|
+
includeCredentials: true,
|
|
164
|
+
onError: (error) => {
|
|
165
|
+
console.error('[DynimProvider] Bundle load failed:', error);
|
|
166
|
+
configCallbacksRef.current.onError?.(error);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return bundleLoaderRef.current;
|
|
171
|
+
}, [getAuthToken]);
|
|
172
|
+
// Load bundle
|
|
173
|
+
const loadBundle = useCallback(async (bundleUrl) => {
|
|
174
|
+
const loader = getBundleLoader();
|
|
175
|
+
if (loader.isLoading())
|
|
176
|
+
return;
|
|
177
|
+
setIsBundleLoading(true);
|
|
178
|
+
setBundleError(null);
|
|
179
|
+
try {
|
|
180
|
+
const { App, cleanup } = await loader.load(bundleUrl);
|
|
181
|
+
setTenantApp(() => App);
|
|
182
|
+
setIsBundleLoaded(true);
|
|
183
|
+
cleanup();
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
if (error instanceof BundleNotFoundError) {
|
|
187
|
+
setTenantApp(null);
|
|
188
|
+
setIsBundleLoaded(false);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
setBundleError(error);
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
setIsBundleLoading(false);
|
|
195
|
+
}
|
|
196
|
+
}, [getBundleLoader]);
|
|
197
|
+
// Keep ref updated
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
loadBundleRef.current = loadBundle;
|
|
200
|
+
}, [loadBundle]);
|
|
201
|
+
// Prefetch auth token
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
if (config.getSession) {
|
|
204
|
+
getAuthToken();
|
|
205
|
+
}
|
|
206
|
+
}, []);
|
|
207
|
+
// Fetch theme from API (per project)
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
if (hasAttemptedThemeLoadRef.current)
|
|
210
|
+
return;
|
|
211
|
+
if (!config.getSession)
|
|
212
|
+
return;
|
|
213
|
+
hasAttemptedThemeLoadRef.current = true;
|
|
214
|
+
const fetchTheme = async () => {
|
|
215
|
+
try {
|
|
216
|
+
const token = await getAuthToken();
|
|
217
|
+
const headers = {};
|
|
218
|
+
if (token) {
|
|
219
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
220
|
+
}
|
|
221
|
+
const response = await fetch('/api/code/theme', {
|
|
222
|
+
headers,
|
|
223
|
+
credentials: 'include',
|
|
224
|
+
});
|
|
225
|
+
if (response.ok) {
|
|
226
|
+
const data = await response.json();
|
|
227
|
+
setTheme(data);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
// Theme fetch failed - use defaults (non-critical)
|
|
232
|
+
console.warn('[DynimProvider] Failed to fetch theme:', error);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
fetchTheme();
|
|
236
|
+
}, [config.getSession, getAuthToken]);
|
|
237
|
+
// Auto-load bundle on mount
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
if (hasAttemptedInitialLoadRef.current)
|
|
240
|
+
return;
|
|
241
|
+
if (!config.getSession) {
|
|
242
|
+
setIsInitialLoadComplete(true);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
hasAttemptedInitialLoadRef.current = true;
|
|
246
|
+
const doInitialLoad = async () => {
|
|
247
|
+
const bundleUrl = '/api/code/bundle';
|
|
248
|
+
if (loadBundleRef.current) {
|
|
249
|
+
try {
|
|
250
|
+
await loadBundleRef.current(bundleUrl);
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
setIsInitialLoadComplete(true);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
setIsInitialLoadComplete(true);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
doInitialLoad();
|
|
261
|
+
}, [config.getSession]);
|
|
262
|
+
// Load saved bundle
|
|
263
|
+
const loadSavedBundle = useCallback(async () => {
|
|
264
|
+
await loadBundle('/api/code/bundle');
|
|
265
|
+
}, [loadBundle]);
|
|
266
|
+
// Watch for bundleReady
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
if (codeMessage.bundleReady && codeMessage.projectId) {
|
|
269
|
+
if (isBuilderActiveRef.current && !isExitingRef.current) {
|
|
270
|
+
pendingBundleProjectIdRef.current = codeMessage.projectId;
|
|
271
|
+
setBundleLoadSignal(s => s + 1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}, [codeMessage.bundleReady, codeMessage.projectId]);
|
|
275
|
+
// Load temp bundle on signal
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
if (bundleLoadSignal === 0)
|
|
278
|
+
return;
|
|
279
|
+
const projectId = pendingBundleProjectIdRef.current;
|
|
280
|
+
if (!projectId || isExitingRef.current) {
|
|
281
|
+
pendingBundleProjectIdRef.current = null;
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
const bundleUrl = `/api/code/bundle?temp=true&_t=${Date.now()}`;
|
|
285
|
+
loadBundleRef.current?.(bundleUrl);
|
|
286
|
+
pendingBundleProjectIdRef.current = null;
|
|
287
|
+
}, [bundleLoadSignal]);
|
|
288
|
+
// Public methods
|
|
289
|
+
const enterBuilder = useCallback(() => {
|
|
290
|
+
if (builderRef.current && !builderRef.current.isActive()) {
|
|
291
|
+
builderRef.current.enter();
|
|
292
|
+
}
|
|
293
|
+
}, []);
|
|
294
|
+
const exitBuilder = useCallback(() => {
|
|
295
|
+
if (builderRef.current && builderRef.current.isActive()) {
|
|
296
|
+
builderRef.current.exit();
|
|
297
|
+
}
|
|
298
|
+
}, []);
|
|
299
|
+
const sendCode = useCallback(async (query) => {
|
|
300
|
+
await codeClientRef.current?.sendCode(query);
|
|
301
|
+
}, []);
|
|
302
|
+
const saveCode = useCallback(async () => {
|
|
303
|
+
await codeClientRef.current?.saveCode();
|
|
304
|
+
await loadSavedBundle();
|
|
305
|
+
}, [loadSavedBundle]);
|
|
306
|
+
const abandonCode = useCallback(async () => {
|
|
307
|
+
await codeClientRef.current?.abandonCode();
|
|
308
|
+
await loadSavedBundle();
|
|
309
|
+
}, [loadSavedBundle]);
|
|
310
|
+
const contextValue = useMemo(() => ({
|
|
311
|
+
enterBuilder,
|
|
312
|
+
exitBuilder,
|
|
313
|
+
isEditing,
|
|
314
|
+
sendCode,
|
|
315
|
+
saveCode,
|
|
316
|
+
abandonCode,
|
|
317
|
+
codeMessage,
|
|
318
|
+
isBundleLoaded,
|
|
319
|
+
isBundleLoading,
|
|
320
|
+
}), [
|
|
321
|
+
enterBuilder,
|
|
322
|
+
exitBuilder,
|
|
323
|
+
isEditing,
|
|
324
|
+
sendCode,
|
|
325
|
+
saveCode,
|
|
326
|
+
abandonCode,
|
|
327
|
+
codeMessage,
|
|
328
|
+
isBundleLoaded,
|
|
329
|
+
isBundleLoading,
|
|
330
|
+
]);
|
|
331
|
+
// Render content
|
|
332
|
+
const renderContent = () => {
|
|
333
|
+
if (!isInitialLoadComplete)
|
|
334
|
+
return null;
|
|
335
|
+
if (bundleError) {
|
|
336
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { style: {
|
|
337
|
+
padding: 12,
|
|
338
|
+
background: '#fef3c7',
|
|
339
|
+
borderBottom: '1px solid #fcd34d',
|
|
340
|
+
fontSize: 13,
|
|
341
|
+
color: '#92400e',
|
|
342
|
+
}, children: ["Bundle error: ", bundleError.message] }), children] }));
|
|
343
|
+
}
|
|
344
|
+
if (TenantApp) {
|
|
345
|
+
return _jsx(TenantApp, {});
|
|
346
|
+
}
|
|
347
|
+
return children;
|
|
348
|
+
};
|
|
349
|
+
// Generate theme CSS from API-fetched theme
|
|
350
|
+
const themeCSS = useMemo(() => generateThemeCSS(theme ?? undefined), [theme]);
|
|
351
|
+
return (_jsxs(DynimContext.Provider, { value: contextValue, children: [_jsx("style", { children: themeCSS }), renderContent()] }));
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Hook to access Dynim functionality
|
|
355
|
+
*/
|
|
356
|
+
export function useDynim() {
|
|
357
|
+
const context = useContext(DynimContext);
|
|
358
|
+
if (!context) {
|
|
359
|
+
throw new Error('useDynim must be used within a DynimProvider');
|
|
360
|
+
}
|
|
361
|
+
return context;
|
|
362
|
+
}
|
|
@@ -5,12 +5,8 @@
|
|
|
5
5
|
* Loads tenant bundles via dynamic import() and renders them as React components.
|
|
6
6
|
*/
|
|
7
7
|
import { type ReactNode } from 'react';
|
|
8
|
-
import type { BuilderInstance, CodeEdit,
|
|
8
|
+
import type { BuilderInstance, CodeEdit, CodeMessage } from 'dynim-core';
|
|
9
9
|
export interface BuilderConfig {
|
|
10
|
-
apiBase?: string;
|
|
11
|
-
pageId?: string;
|
|
12
|
-
logo?: string;
|
|
13
|
-
contentRoot?: HTMLElement;
|
|
14
10
|
/** JWT session token for authentication */
|
|
15
11
|
sessionToken?: string;
|
|
16
12
|
/** Refresh token for getting new session tokens */
|
|
@@ -20,19 +16,12 @@ export interface BuilderConfig {
|
|
|
20
16
|
token: string;
|
|
21
17
|
refreshToken?: string;
|
|
22
18
|
}>;
|
|
19
|
+
/** Called when an error occurs */
|
|
23
20
|
onError?: (error: Event | Error) => void;
|
|
24
21
|
/** Called when the structured code message updates (recommended) */
|
|
25
22
|
onCodeMessageUpdate?: (message: CodeMessage) => void;
|
|
26
23
|
/** Called when a code edit is received */
|
|
27
24
|
onCodeEdit?: (edit: CodeEdit) => void;
|
|
28
|
-
/** @deprecated Use onCodeMessageUpdate instead */
|
|
29
|
-
onCodeMessage?: (event: CodeEvent) => void;
|
|
30
|
-
/** Function to resolve bundle URL from project ID */
|
|
31
|
-
getBundleUrl?: (projectId: string) => string | Promise<string>;
|
|
32
|
-
/** Called when bundle starts loading */
|
|
33
|
-
onBundleLoadStart?: (bundleUrl: string) => void;
|
|
34
|
-
/** Called when bundle finishes loading */
|
|
35
|
-
onBundleLoadComplete?: (bundleUrl: string) => void;
|
|
36
25
|
/** NPM packages to expose to bundles (e.g., { 'react-router-dom': ReactRouterDOM }) */
|
|
37
26
|
packages?: Record<string, unknown>;
|
|
38
27
|
/** Custom hooks to expose to bundles */
|
|
@@ -57,7 +46,7 @@ export interface BuilderContextValue {
|
|
|
57
46
|
codeEdits: CodeEdit[];
|
|
58
47
|
/** Load a bundle by URL */
|
|
59
48
|
loadBundle: (bundleUrl: string) => Promise<void>;
|
|
60
|
-
/** Load bundle for a project
|
|
49
|
+
/** Load bundle for a project */
|
|
61
50
|
loadProjectBundle: (projectId: string) => Promise<void>;
|
|
62
51
|
/** Load saved (permanent) bundle for a project */
|
|
63
52
|
loadSavedBundle: (projectId: string) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BuilderProvider.d.ts","sourceRoot":"","sources":["../../src/builder/BuilderProvider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAc,EAQZ,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"BuilderProvider.d.ts","sourceRoot":"","sources":["../../src/builder/BuilderProvider.tsx"],"names":[],"mappings":"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"}
|