EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
apiRouting.ts
Go to the documentation of this file.
1/**
2 * API Request Routing Logic
3 *
4 * Determines the correct API endpoint based on:
5 * - Request type (openapi, gnap, elink)
6 * - Current store context
7 * - User session
8 *
9 * Store URLs are built dynamically from environment variable:
10 * NEXT_PUBLIC_FIELDPINE_STORE_DOMAIN (default: cwanz.online)
11 * Format: https://{store-id}.{domain}
12 * Examples: https://cowra.cwanz.online, https://iig.cwanz.online
13 */
14
15import { Store } from './stores';
16
17export type RequestType = 'openapi' | 'gnap' | 'elink';
18
19export interface RoutingContext {
20 store: Store;
21 requestType: RequestType;
22}
23
24/**
25 * Get the appropriate endpoint URL based on request type and store
26 *
27 * Rules:
28 * - OpenAPI: Routes to store URL (e.g., cowra.cwanz.online/openapi)
29 * Only available for store types, NOT for management portal
30 *
31 * - GNAP: Always routes to IIG management portal (iig.cwanz.online/GNAP/j)
32 * Used for central reporting and cross-store operations
33 *
34 * - ELINK: Routes to store URL (e.g., cowra.cwanz.online/GNAP/j)
35 * Used for store-specific configuration
36 */
37export function getEndpointUrl(
38 requestType: RequestType,
39 store: Store
40): string {
41 switch (requestType) {
42 case 'openapi':
43 if (store.type === 'management') {
44 throw new Error(
45 'OpenAPI endpoints are not available when logged into the management portal. ' +
46 'Please log into a specific store to access POS functions.'
47 );
48 }
49 return `${store.url}/openapi`;
50
51 case 'gnap':
52 // GNAP requests always go to IIG management portal for central operations
53 return 'https://iig.cwanz.online/GNAP/j';
54
55 case 'elink':
56 // ELINK requests go to the current store for store-specific config
57 return `${store.url}/GNAP/j`;
58
59 default:
60 throw new Error(`Unknown request type: ${requestType}`);
61 }
62}
63
64/**
65 * Validate that a request is allowed for the current store context
66 *
67 * Security Rules:
68 * - Retail stores: Can ONLY access ELINK endpoints
69 * - Management portal: Can access OpenAPI, GNAP, and ELINK
70 * - OpenAPI: Management portal ONLY (for centralized POS operations)
71 * - GNAP: Management portal ONLY (for reporting and analytics)
72 * - ELINK: Both retail stores and management portal (store-specific operations)
73 */
74export function validateRequest(
75 requestType: RequestType,
76 store: Store
77): { valid: boolean; error?: string } {
78 // Management portal has full access
79 if (store.type === 'management') {
80 return { valid: true };
81 }
82
83 // Retail stores can ONLY use ELINK
84 if (store.type === 'store') {
85 if (requestType === 'openapi') {
86 return {
87 valid: false,
88 error: 'Security: Retail stores cannot access OpenAPI. Use ELINK endpoints for store operations.'
89 };
90 }
91
92 if (requestType === 'gnap') {
93 return {
94 valid: false,
95 error: 'Security: Retail stores cannot access GNAP. This is restricted to management portal.'
96 };
97 }
98
99 if (requestType === 'elink') {
100 return { valid: true };
101 }
102 }
103
104 return {
105 valid: false,
106 error: 'Invalid request type or store type'
107 };
108}
109
110/**
111 * Get the appropriate request type for common operations
112 */
113export function getRequestTypeForOperation(operation: string): RequestType {
114 // POS Operations - OpenAPI
115 if (operation.match(/^(products|sales|customers|inventory|stock)/i)) {
116 return 'openapi';
117 }
118
119 // Reporting and cross-store - GNAP
120 if (operation.match(/^(report|analytics|cross-store)/i)) {
121 return 'gnap';
122 }
123
124 // Store configuration - ELINK
125 if (operation.match(/^(config|settings|store-setup)/i)) {
126 return 'elink';
127 }
128
129 // Default to GNAP for unknown operations
130 return 'gnap';
131}
132
133/**
134 * Build full API URL with query parameters
135 */
136export function buildApiUrl(
137 baseUrl: string,
138 path: string,
139 params?: Record<string, string>
140): string {
141 const url = new URL(path, baseUrl);
142
143 if (params) {
144 Object.entries(params).forEach(([key, value]) => {
145 url.searchParams.append(key, value);
146 });
147 }
148
149 return url.toString();
150}