@apptimate/core-lib 3.5.0 → 3.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apptimate/core-lib",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "main": "src/index.ts",
5
5
  "types": "src/index.ts",
6
6
  "publishConfig": {
@@ -3,6 +3,7 @@ export interface SubMenuItem {
3
3
  label: string;
4
4
  path: string;
5
5
  permission?: string | null;
6
+ iconName?: string;
6
7
  }
7
8
 
8
9
  export interface SubMenuGroup {
@@ -211,6 +212,16 @@ export const MENU_ITEM_REGISTRY: RegistryItem[] = [
211
212
  { key: 'reports__all', label: 'All Reports', path: '/reports', module: 'Reporting', defaultGroup: 'General', permission: null },
212
213
  { key: 'reports__builder', label: 'Report Builder', path: '/reports/admin/reports', module: 'Reporting', defaultGroup: 'Administration', permission: null },
213
214
  { key: 'reports__configurator', label: 'Dashboard Configurator', path: '/reports/admin/dashboards', module: 'Reporting', defaultGroup: 'Administration', permission: null },
215
+
216
+ // ── AI Analytics Module ──
217
+ { key: 'ai_analytics__dashboard', label: 'Overview', path: '/ai-analytics', module: 'AI Analytics', defaultGroup: 'Overview', permission: null },
218
+ { key: 'ai_analytics__recommendations', label: 'Recommendations', path: '/ai-analytics/recommendations', module: 'AI Analytics', defaultGroup: 'Insights', permission: null },
219
+ { key: 'ai_analytics__reports', label: 'AI Reports', path: '/ai-analytics/reports', module: 'AI Analytics', defaultGroup: 'Insights', permission: null },
220
+ { key: 'ai_analytics__usage', label: 'Usage Analytics', path: '/ai-analytics/usage', module: 'AI Analytics', defaultGroup: 'Insights', permission: null },
221
+ { key: 'ai_analytics__forecasting', label: 'Forecasting', path: '/ai-analytics/forecasting', module: 'AI Analytics', defaultGroup: 'Advanced Models', permission: null },
222
+ { key: 'ai_analytics__anomalies', label: 'Anomaly Detection', path: '/ai-analytics/anomalies', module: 'AI Analytics', defaultGroup: 'Advanced Models', permission: null },
223
+ { key: 'ai_analytics__customer_intel', label: 'Customer Intel', path: '/ai-analytics/customer-intel', module: 'AI Analytics', defaultGroup: 'Intelligence', permission: null },
224
+ { key: 'ai_analytics__pricing_intel', label: 'Pricing Intel', path: '/ai-analytics/pricing-intel', module: 'AI Analytics', defaultGroup: 'Intelligence', permission: null },
214
225
  ];
215
226
 
216
227
  /**
@@ -400,6 +411,21 @@ export const MENU_PRESETS: MenuPreset[] = [
400
411
  'reports__jewelry', 'reports__inventory', 'reports__finance',
401
412
  'reports__all', 'reports__builder', 'reports__configurator'
402
413
  ]
414
+ },
415
+ {
416
+ id: 'ai_analytics',
417
+ label: 'AI',
418
+ iconName: 'BrainCircuit',
419
+ secondaryItems: [
420
+ 'ai_analytics__dashboard',
421
+ 'ai_analytics__recommendations',
422
+ 'ai_analytics__reports',
423
+ 'ai_analytics__usage',
424
+ 'ai_analytics__forecasting',
425
+ 'ai_analytics__anomalies',
426
+ 'ai_analytics__customer_intel',
427
+ 'ai_analytics__pricing_intel',
428
+ ],
403
429
  }
404
430
  ],
405
431
  },
@@ -436,7 +462,7 @@ export function filterMenusByPermission(menus: MainMenuItem[], can: (code: strin
436
462
  });
437
463
  return { ...group, items: filteredItems };
438
464
  }).filter(group => group.items.length > 0);
439
-
465
+
440
466
  return { ...mainMenu, groups: filteredGroups };
441
467
  }).filter(mainMenu => mainMenu.groups.length > 0);
442
468
  }
@@ -86,7 +86,10 @@ export function createSessionLogoutResponse(): Response {
86
86
  }
87
87
 
88
88
  export async function forwardApiProxyRequest(request: Request, pathSegments: string[]): Promise<Response> {
89
- const apiBaseUrl = process.env.NEXT_PUBLIC_API_URL;
89
+ const targetApi = request.headers.get("x-target-api");
90
+ const apiBaseUrl = targetApi === 'ai_analytics'
91
+ ? (process.env.NEXT_PUBLIC_AI_ANALYTICS_API_URL || "http://localhost:8002")
92
+ : process.env.NEXT_PUBLIC_API_URL;
90
93
 
91
94
  if (!apiBaseUrl) {
92
95
  return new Response(JSON.stringify({
@@ -143,7 +146,8 @@ export async function forwardApiProxyRequest(request: Request, pathSegments: str
143
146
 
144
147
  const responseHeaders = new Headers();
145
148
  upstreamResponse.headers.forEach((value, key) => {
146
- if (!HOP_BY_HOP_HEADERS.has(key.toLowerCase())) {
149
+ const lowerKey = key.toLowerCase();
150
+ if (!HOP_BY_HOP_HEADERS.has(lowerKey) && lowerKey !== "x-target-api") {
147
151
  responseHeaders.set(key, value);
148
152
  }
149
153
  });
@@ -93,6 +93,15 @@ export async function sendRequest<T = any>({ url, method, data, params, headers,
93
93
  // Client-side requests are routed through a same-origin proxy so the
94
94
  // browser never needs direct access to the bearer token.
95
95
  if (typeof window !== 'undefined') {
96
+ try {
97
+ const aiApiUrl = process.env.NEXT_PUBLIC_AI_ANALYTICS_API_URL;
98
+ if (aiApiUrl && finalUrl.startsWith(aiApiUrl)) {
99
+ defaultHeaders['X-Target-Api'] = 'ai_analytics';
100
+ }
101
+ } catch {
102
+ // ignore
103
+ }
104
+
96
105
  finalUrl = buildBrowserProxyUrl(finalUrl);
97
106
 
98
107
  // Automatically inject selected organization ID into every request
@@ -119,6 +128,7 @@ export async function sendRequest<T = any>({ url, method, data, params, headers,
119
128
  headers: { ...defaultHeaders, ...headers },
120
129
  body: data instanceof FormData ? data : (data ? JSON.stringify(data) : undefined),
121
130
  signal,
131
+ cache: 'no-store'
122
132
  });
123
133
 
124
134
  // Handle 401 Unauthorized globally — clear auth and redirect to login