teraprox-core-sdk 0.2.0 → 0.3.2

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.
@@ -0,0 +1,318 @@
1
+ // src/context/CoreServiceContext.ts
2
+ import { createContext } from "react";
3
+ var CoreServiceContext = createContext(null);
4
+
5
+ // src/federation/FederatedBridge.tsx
6
+ import { useEffect } from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ function FederatedBridge({ coreService, children }) {
9
+ useEffect(() => {
10
+ if (typeof window === "undefined") return;
11
+ window.__TERAPROX_HOSTED_BY_CORE__ = true;
12
+ return () => {
13
+ ;
14
+ window.__TERAPROX_HOSTED_BY_CORE__ = false;
15
+ };
16
+ }, []);
17
+ return /* @__PURE__ */ jsx(CoreServiceContext.Provider, { value: coreService, children });
18
+ }
19
+
20
+ // src/federation/createReducersBundle.ts
21
+ function createReducersBundle(config) {
22
+ const { reducers, contextMap, defaults = [] } = config;
23
+ const allKeys = Object.keys(reducers);
24
+ const getReducerKeysByContext = (context) => {
25
+ const contextKeys = contextMap[context];
26
+ if (!contextKeys) return allKeys;
27
+ return [.../* @__PURE__ */ new Set([...defaults, ...contextKeys])];
28
+ };
29
+ const getReducersForKeys = async (keys = []) => {
30
+ const uniqueKeys = [...new Set(keys)].filter((key) => !!reducers[key]);
31
+ const loaded = await Promise.all(
32
+ uniqueKeys.map(async (key) => {
33
+ const module = await reducers[key]();
34
+ return [key, module.default || module];
35
+ })
36
+ );
37
+ return Object.fromEntries(loaded);
38
+ };
39
+ const getReducersForModule = async ({
40
+ context
41
+ } = {}) => {
42
+ const keys = getReducerKeysByContext(context || "");
43
+ return getReducersForKeys(keys);
44
+ };
45
+ const loadAllReducers = () => getReducersForKeys(allKeys);
46
+ return {
47
+ getReducerKeysByContext,
48
+ getReducersForKeys,
49
+ getReducersForModule,
50
+ loadAllReducers,
51
+ baseReducers: {}
52
+ };
53
+ }
54
+
55
+ // src/federation/StandaloneProvider.tsx
56
+ import { useMemo, useCallback, useState, useEffect as useEffect2, useRef } from "react";
57
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
58
+ async function probeEmulator(host, port) {
59
+ try {
60
+ const res = await fetch(`http://${host}:${port}/.json`, {
61
+ signal: AbortSignal.timeout(1500)
62
+ });
63
+ return res.ok || res.status === 404;
64
+ } catch (e) {
65
+ return false;
66
+ }
67
+ }
68
+ async function resolveRtdbStrategy(firebaseConfig) {
69
+ var _a;
70
+ const emulatorHostEnv = typeof process !== "undefined" && process.env.REACT_APP_RTDB_EMULATOR_HOST || void 0;
71
+ if (emulatorHostEnv) {
72
+ const [host, portStr] = emulatorHostEnv.split(":");
73
+ const port = parseInt(portStr != null ? portStr : "9000", 10);
74
+ const namespace = (_a = process.env.REACT_APP_RTDB_EMULATOR_NS) != null ? _a : "demo-local";
75
+ return { type: "emulator", host, port, namespace };
76
+ }
77
+ if (firebaseConfig && Object.keys(firebaseConfig).length > 0) {
78
+ return { type: "cloud", config: firebaseConfig };
79
+ }
80
+ const alive = await probeEmulator("localhost", 9e3);
81
+ if (alive) {
82
+ return { type: "emulator", host: "localhost", port: 9e3, namespace: "demo-local" };
83
+ }
84
+ return { type: "none" };
85
+ }
86
+ var _emulatorConnected = /* @__PURE__ */ new Set();
87
+ function RtdbConfigWarning({ onDismiss }) {
88
+ return /* @__PURE__ */ jsxs(
89
+ "div",
90
+ {
91
+ style: {
92
+ position: "fixed",
93
+ bottom: 24,
94
+ right: 24,
95
+ zIndex: 99999,
96
+ background: "#1a1a2e",
97
+ color: "#fff",
98
+ borderRadius: 8,
99
+ padding: "16px 20px",
100
+ maxWidth: 420,
101
+ boxShadow: "0 4px 24px rgba(0,0,0,0.5)",
102
+ borderLeft: "4px solid #f59e0b",
103
+ fontFamily: "monospace",
104
+ fontSize: 13,
105
+ lineHeight: 1.6
106
+ },
107
+ children: [
108
+ /* @__PURE__ */ jsx2("div", { style: { fontWeight: "bold", marginBottom: 8, color: "#f59e0b", fontSize: 14 }, children: "\u26A0 RTDB n\xE3o configurado" }),
109
+ /* @__PURE__ */ jsxs("div", { children: [
110
+ "Matching Objects em tempo real desativados.",
111
+ /* @__PURE__ */ jsx2("br", {}),
112
+ "Configure no ",
113
+ /* @__PURE__ */ jsx2("code", { children: ".env.dev" }),
114
+ ":",
115
+ /* @__PURE__ */ jsx2("br", {}),
116
+ /* @__PURE__ */ jsx2("code", { style: { color: "#86efac" }, children: "REACT_APP_RTDB_EMULATOR_HOST=localhost:9000" }),
117
+ /* @__PURE__ */ jsx2("br", {}),
118
+ /* @__PURE__ */ jsxs("span", { style: { color: "#94a3b8", fontSize: 11 }, children: [
119
+ "ou inicie o backend com ",
120
+ /* @__PURE__ */ jsx2("code", { children: "RtdbEmulatorPlugin" }),
121
+ " do @onroad/core"
122
+ ] }),
123
+ /* @__PURE__ */ jsx2("br", {}),
124
+ /* @__PURE__ */ jsxs("span", { style: { color: "#94a3b8", fontSize: 11 }, children: [
125
+ "e rode o emulator com ",
126
+ /* @__PURE__ */ jsx2("code", { children: "firebase emulators:start --only database" })
127
+ ] })
128
+ ] }),
129
+ /* @__PURE__ */ jsx2(
130
+ "button",
131
+ {
132
+ onClick: onDismiss,
133
+ style: {
134
+ marginTop: 12,
135
+ padding: "4px 14px",
136
+ background: "#374151",
137
+ color: "#fff",
138
+ border: "none",
139
+ borderRadius: 4,
140
+ cursor: "pointer",
141
+ fontSize: 12
142
+ },
143
+ children: "Fechar"
144
+ }
145
+ )
146
+ ]
147
+ }
148
+ );
149
+ }
150
+ function StandaloneProvider({ createController, addToast, firebaseConfig, tenant, children }) {
151
+ const [subscriptions] = useState([]);
152
+ const subscriptionsRef = useRef(subscriptions);
153
+ subscriptionsRef.current = subscriptions;
154
+ const [rtdbWarning, setRtdbWarning] = useState(false);
155
+ const toast = useMemo(
156
+ () => ({
157
+ success: (msg, opts) => addToast(msg, { appearance: "success", autoDismiss: true, ...opts }),
158
+ warning: (msg, opts) => addToast(msg, { appearance: "warning", autoDismiss: true, ...opts }),
159
+ error: (msg, opts) => addToast(msg, { appearance: "error", autoDismiss: true, ...opts }),
160
+ info: (msg, opts) => addToast(msg, { appearance: "info", autoDismiss: true, ...opts })
161
+ }),
162
+ [addToast]
163
+ );
164
+ const subscribe = useCallback(
165
+ (mo) => {
166
+ subscriptions.push(mo);
167
+ },
168
+ [subscriptions]
169
+ );
170
+ const unsubscribe = useCallback(
171
+ (mo) => {
172
+ const idx = subscriptions.findIndex(
173
+ (s) => s.context === mo.context && s.location === mo.location
174
+ );
175
+ if (idx >= 0) subscriptions.splice(idx, 1);
176
+ },
177
+ [subscriptions]
178
+ );
179
+ useEffect2(() => {
180
+ if (!tenant) return;
181
+ let cleanup;
182
+ let cancelled = false;
183
+ (async () => {
184
+ var _a;
185
+ const strategy = await resolveRtdbStrategy(firebaseConfig);
186
+ if (cancelled) return;
187
+ if (strategy.type === "none") {
188
+ if (process.env.NODE_ENV !== "production") setRtdbWarning(true);
189
+ return;
190
+ }
191
+ try {
192
+ const { initializeApp, getApps } = await import("firebase/app");
193
+ const { getDatabase, ref, onChildAdded } = await import("firebase/database");
194
+ let db;
195
+ if (strategy.type === "emulator") {
196
+ const appName = `onroad-rtdb-emulator-${strategy.port}`;
197
+ const existingApp = getApps().find((a) => a.name === appName);
198
+ const emulatorApp = existingApp != null ? existingApp : initializeApp(
199
+ {
200
+ projectId: strategy.namespace,
201
+ databaseURL: `http://${strategy.host}:${strategy.port}?ns=${strategy.namespace}`
202
+ },
203
+ appName
204
+ );
205
+ db = getDatabase(emulatorApp);
206
+ if (!_emulatorConnected.has(appName)) {
207
+ const { connectDatabaseEmulator } = await import("firebase/database");
208
+ try {
209
+ connectDatabaseEmulator(db, strategy.host, strategy.port);
210
+ _emulatorConnected.add(appName);
211
+ } catch (e) {
212
+ _emulatorConnected.add(appName);
213
+ }
214
+ }
215
+ console.info(
216
+ `[StandaloneProvider] RTDB emulator at ${strategy.host}:${strategy.port} (ns=${strategy.namespace})`
217
+ );
218
+ } else {
219
+ const existingApp = (_a = getApps().find((a) => a.name === "[DEFAULT]")) != null ? _a : getApps()[0];
220
+ const cloudApp = existingApp != null ? existingApp : initializeApp(strategy.config);
221
+ db = getDatabase(cloudApp);
222
+ }
223
+ const moRef = ref(db, `${tenant}/matchingObjects`);
224
+ const unsub = onChildAdded(moRef, (snapshot) => {
225
+ const data = snapshot.val();
226
+ if (!data) return;
227
+ const items = Array.isArray(data) ? data : [data];
228
+ for (const mo of items) {
229
+ if (typeof mo !== "object") continue;
230
+ const subs = subscriptionsRef.current || [];
231
+ for (const sub of subs) {
232
+ const sameContext = sub.context === mo.context;
233
+ const sameLocation = sub.location === mo.location || sub.location === "*" || mo.location === "*" || !sub.location || !mo.location;
234
+ if (sameContext && sameLocation && sub.refresher) {
235
+ try {
236
+ sub.refresher(mo.payload, () => {
237
+ });
238
+ } catch (e) {
239
+ }
240
+ }
241
+ }
242
+ }
243
+ });
244
+ cleanup = () => unsub();
245
+ } catch (err) {
246
+ console.warn("[StandaloneProvider] Firebase RTDB listener failed:", err);
247
+ }
248
+ })();
249
+ return () => {
250
+ cancelled = true;
251
+ cleanup == null ? void 0 : cleanup();
252
+ };
253
+ }, [firebaseConfig, tenant]);
254
+ const value = useMemo(
255
+ () => ({
256
+ createController,
257
+ toast,
258
+ subscribe,
259
+ unsubscribe,
260
+ subscribeEvent: () => {
261
+ },
262
+ unsubscribeEvent: () => {
263
+ },
264
+ handleLogout: () => {
265
+ },
266
+ hostedByCore: false
267
+ }),
268
+ [createController, toast, subscribe, unsubscribe]
269
+ );
270
+ return /* @__PURE__ */ jsxs(CoreServiceContext.Provider, { value, children: [
271
+ children,
272
+ rtdbWarning && /* @__PURE__ */ jsx2(RtdbConfigWarning, { onDismiss: () => setRtdbWarning(false) })
273
+ ] });
274
+ }
275
+
276
+ // src/federation/DevAutoLogin.tsx
277
+ import { useEffect as useEffect3 } from "react";
278
+ import { useDispatch, useSelector } from "react-redux";
279
+ import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
280
+ var DEFAULT_DEV_USER = {
281
+ firstName: "Dev",
282
+ lastName: "User",
283
+ token: "dev-standalone-token",
284
+ email: "dev@teraprox.local",
285
+ id: "dev-user-id",
286
+ role: "admin",
287
+ user: "devuser",
288
+ userName: "devuser",
289
+ setor: "Desenvolvimento",
290
+ userSetor: { setorId: "dev-setor-id" },
291
+ companyName: "Dev Company",
292
+ companyId: "dev-company-id",
293
+ filters: []
294
+ };
295
+ function DevAutoLogin({ actions, devUser, children }) {
296
+ const dispatch = useDispatch();
297
+ const token = useSelector((state) => {
298
+ var _a;
299
+ return (_a = state.global) == null ? void 0 : _a.token;
300
+ });
301
+ const hostedByCore = typeof window !== "undefined" && window.__TERAPROX_HOSTED_BY_CORE__ === true;
302
+ useEffect3(() => {
303
+ if (process.env.NODE_ENV === "development" && !hostedByCore && !token) {
304
+ const user = { ...DEFAULT_DEV_USER, ...devUser };
305
+ dispatch(actions.setCompany(user.companyId));
306
+ dispatch(actions.logIn(user));
307
+ }
308
+ }, [dispatch, hostedByCore, token, actions, devUser]);
309
+ return /* @__PURE__ */ jsx3(Fragment, { children });
310
+ }
311
+
312
+ export {
313
+ CoreServiceContext,
314
+ FederatedBridge,
315
+ createReducersBundle,
316
+ StandaloneProvider,
317
+ DevAutoLogin
318
+ };
package/dist/dev.d.mts ADDED
@@ -0,0 +1,39 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface DevRoute {
4
+ /** Display label for the route */
5
+ label: string;
6
+ /** Route path (e.g., "/ordensDeServico") */
7
+ path: string;
8
+ /** Category for grouping (e.g., "Operação", "Cadastros") */
9
+ category?: string;
10
+ }
11
+ interface DevShellProps {
12
+ appName: string;
13
+ routes: DevRoute[];
14
+ children: React.ReactNode;
15
+ }
16
+
17
+ declare function DevShell({ appName, routes, children }: DevShellProps): react_jsx_runtime.JSX.Element;
18
+
19
+ interface RouteConfigEntry {
20
+ configuration?: {
21
+ path?: string;
22
+ [key: string]: any;
23
+ };
24
+ [key: string]: any;
25
+ }
26
+ interface ServiceRouteConfig {
27
+ service?: string;
28
+ routes?: RouteConfigEntry[];
29
+ }
30
+ /**
31
+ * Extracts DevRoute[] from the standard routesConfig format used by SGM/SGP.
32
+ *
33
+ * @example
34
+ * import { routesConfig } from '../models/routesConfig'
35
+ * const devRoutes = extractDevRoutes(routesConfig)
36
+ */
37
+ declare function extractDevRoutes(routesConfig: ServiceRouteConfig[]): DevRoute[];
38
+
39
+ export { type DevRoute, DevShell, type DevShellProps, extractDevRoutes };
package/dist/dev.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface DevRoute {
4
+ /** Display label for the route */
5
+ label: string;
6
+ /** Route path (e.g., "/ordensDeServico") */
7
+ path: string;
8
+ /** Category for grouping (e.g., "Operação", "Cadastros") */
9
+ category?: string;
10
+ }
11
+ interface DevShellProps {
12
+ appName: string;
13
+ routes: DevRoute[];
14
+ children: React.ReactNode;
15
+ }
16
+
17
+ declare function DevShell({ appName, routes, children }: DevShellProps): react_jsx_runtime.JSX.Element;
18
+
19
+ interface RouteConfigEntry {
20
+ configuration?: {
21
+ path?: string;
22
+ [key: string]: any;
23
+ };
24
+ [key: string]: any;
25
+ }
26
+ interface ServiceRouteConfig {
27
+ service?: string;
28
+ routes?: RouteConfigEntry[];
29
+ }
30
+ /**
31
+ * Extracts DevRoute[] from the standard routesConfig format used by SGM/SGP.
32
+ *
33
+ * @example
34
+ * import { routesConfig } from '../models/routesConfig'
35
+ * const devRoutes = extractDevRoutes(routesConfig)
36
+ */
37
+ declare function extractDevRoutes(routesConfig: ServiceRouteConfig[]): DevRoute[];
38
+
39
+ export { type DevRoute, DevShell, type DevShellProps, extractDevRoutes };