Initial commit: bface library, build fixes, and refreshed docs
- Externalize all @tamagui/* and tamagui subpaths so dist no longer vendors Tamagui. - Emit TypeScript declarations with vite-plugin-dts; fix package exports types for ui/*. - Align initEnv with profiles: displayName, brandLogo, api.baseURL, themeColor, uiShell. - Stabilize tests with Node localStorage file; env tests pass. - Update README and component docs for services, menus, API client, and development.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* API Client
|
||||
* Fetch wrappers for /api/* endpoints with offline support
|
||||
*/
|
||||
|
||||
class APIClient {
|
||||
constructor(baseURL = '/api') {
|
||||
this.baseURL = baseURL;
|
||||
this.interceptors = {
|
||||
request: [],
|
||||
response: []
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add request interceptor
|
||||
* @param {Function} interceptor - (config) => config
|
||||
*/
|
||||
addRequestInterceptor(interceptor) {
|
||||
this.interceptors.request.push(interceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add response interceptor
|
||||
* @param {Function} interceptor - (response) => response
|
||||
*/
|
||||
addResponseInterceptor(interceptor) {
|
||||
this.interceptors.response.push(interceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute request interceptors
|
||||
* @param {RequestInit} config
|
||||
* @returns {RequestInit}
|
||||
*/
|
||||
_applyRequestInterceptors(config) {
|
||||
return this.interceptors.request.reduce(
|
||||
(acc, interceptor) => interceptor(acc),
|
||||
config
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute response interceptors
|
||||
* @param {Response} response
|
||||
* @returns {Response}
|
||||
*/
|
||||
_applyResponseInterceptors(response) {
|
||||
return this.interceptors.response.reduce(
|
||||
(acc, interceptor) => interceptor(acc),
|
||||
response
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make API request
|
||||
* @param {string} endpoint
|
||||
* @param {RequestInit} options
|
||||
* @returns {Promise<Response>}
|
||||
*/
|
||||
async request(endpoint, options = {}) {
|
||||
const url = `${this.baseURL}${endpoint}`;
|
||||
const config = this._applyRequestInterceptors({
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await fetch(url, config);
|
||||
return this._applyResponseInterceptors(response);
|
||||
} catch (error) {
|
||||
// TODO: Implement offline queue management
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET request
|
||||
* @param {string} endpoint
|
||||
* @param {RequestInit} options
|
||||
* @returns {Promise<Response>}
|
||||
*/
|
||||
async get(endpoint, options = {}) {
|
||||
return this.request(endpoint, { ...options, method: 'GET' });
|
||||
}
|
||||
|
||||
/**
|
||||
* POST request
|
||||
* @param {string} endpoint
|
||||
* @param {any} data
|
||||
* @param {RequestInit} options
|
||||
* @returns {Promise<Response>}
|
||||
*/
|
||||
async post(endpoint, data, options = {}) {
|
||||
return this.request(endpoint, {
|
||||
...options,
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT request
|
||||
* @param {string} endpoint
|
||||
* @param {any} data
|
||||
* @param {RequestInit} options
|
||||
* @returns {Promise<Response>}
|
||||
*/
|
||||
async put(endpoint, data, options = {}) {
|
||||
return this.request(endpoint, {
|
||||
...options,
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE request
|
||||
* @param {string} endpoint
|
||||
* @param {RequestInit} options
|
||||
* @returns {Promise<Response>}
|
||||
*/
|
||||
async delete(endpoint, options = {}) {
|
||||
return this.request(endpoint, { ...options, method: 'DELETE' });
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const api = new APIClient();
|
||||
|
||||
Reference in New Issue
Block a user