kimu-core 0.4.1 → 0.4.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.
Files changed (67) hide show
  1. package/.editorconfig +116 -30
  2. package/.gitattributes +81 -11
  3. package/.github/FUNDING.yml +8 -8
  4. package/.github/kimu-copilot-instructions.md +3779 -3779
  5. package/.github/workflows/deploy-demo.yml +39 -39
  6. package/.nvmrc +1 -0
  7. package/.prettierignore +44 -0
  8. package/.prettierrc +16 -0
  9. package/FUNDING.md +31 -31
  10. package/icon.svg +10 -10
  11. package/package.json +9 -2
  12. package/scripts/minify-css-assets.js +82 -82
  13. package/src/core/index.ts +47 -47
  14. package/src/core/kimu-global-styles.ts +136 -136
  15. package/src/core/kimu-reactive.ts +196 -196
  16. package/src/modules-repository/api-axios/CHANGELOG.md +48 -48
  17. package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -178
  18. package/src/modules-repository/api-axios/README.md +304 -304
  19. package/src/modules-repository/api-axios/api-axios-service.ts +355 -355
  20. package/src/modules-repository/api-axios/examples.ts +293 -293
  21. package/src/modules-repository/api-axios/index.ts +19 -19
  22. package/src/modules-repository/api-axios/interfaces.ts +71 -71
  23. package/src/modules-repository/api-axios/module.ts +41 -41
  24. package/src/modules-repository/api-core/CHANGELOG.md +42 -42
  25. package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -192
  26. package/src/modules-repository/api-core/README.md +435 -435
  27. package/src/modules-repository/api-core/api-core-service.ts +289 -289
  28. package/src/modules-repository/api-core/examples.ts +432 -432
  29. package/src/modules-repository/api-core/index.ts +8 -8
  30. package/src/modules-repository/api-core/interfaces.ts +83 -83
  31. package/src/modules-repository/api-core/module.ts +30 -30
  32. package/src/modules-repository/event-bus/README.md +273 -273
  33. package/src/modules-repository/event-bus/event-bus-service.ts +176 -176
  34. package/src/modules-repository/event-bus/module.ts +30 -30
  35. package/src/modules-repository/notification/README.md +423 -423
  36. package/src/modules-repository/notification/module.ts +30 -30
  37. package/src/modules-repository/notification/notification-service.ts +436 -436
  38. package/src/modules-repository/router/README.it.md +61 -10
  39. package/src/modules-repository/router/README.md +61 -10
  40. package/src/modules-repository/router/router-config.ts.example +61 -0
  41. package/src/modules-repository/router/router.ts +18 -0
  42. package/src/modules-repository/state/README.md +409 -409
  43. package/src/modules-repository/state/module.ts +30 -30
  44. package/src/modules-repository/state/state-service.ts +296 -296
  45. package/src/modules-repository/theme/README.md +311 -267
  46. package/src/modules-repository/theme/module.ts +30 -30
  47. package/src/modules-repository/theme/pre-build.js +40 -40
  48. package/src/modules-repository/theme/theme-service.ts +411 -389
  49. package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -78
  50. package/src/modules-repository/theme/themes/theme-cozy.css +111 -111
  51. package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -150
  52. package/src/modules-repository/theme/themes/theme-dark.css +79 -79
  53. package/src/modules-repository/theme/themes/theme-forest.css +171 -171
  54. package/src/modules-repository/theme/themes/theme-gold.css +100 -100
  55. package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -126
  56. package/src/modules-repository/theme/themes/theme-lava.css +101 -101
  57. package/src/modules-repository/theme/themes/theme-lavender.css +90 -90
  58. package/src/modules-repository/theme/themes/theme-light.css +79 -79
  59. package/src/modules-repository/theme/themes/theme-matrix.css +103 -103
  60. package/src/modules-repository/theme/themes/theme-midnight.css +81 -81
  61. package/src/modules-repository/theme/themes/theme-nord.css +94 -94
  62. package/src/modules-repository/theme/themes/theme-ocean.css +84 -84
  63. package/src/modules-repository/theme/themes/theme-retro80s.css +343 -343
  64. package/src/modules-repository/theme/themes/theme-sunset.css +62 -62
  65. package/src/modules-repository/theme/themes-config-default.json +19 -0
  66. package/src/modules-repository/theme/themes-config.d.ts +27 -27
  67. package/src/modules-repository/theme/{themes-config.json → themes-config.json.example} +223 -213
@@ -1,289 +1,289 @@
1
- /**
2
- * KIMU API Core Service
3
- * Lightweight HTTP client based on native fetch API
4
- * Zero dependencies, Promise-based, TypeScript-first
5
- */
6
-
7
- import {
8
- ApiRequestOptions,
9
- ApiResponse,
10
- ApiError,
11
- ApiConfig
12
- } from './interfaces';
13
-
14
- /**
15
- * Main API service class for making HTTP requests
16
- */
17
- export class ApiCoreService {
18
- private config: ApiConfig = {};
19
-
20
- /**
21
- * Configure the API service with global settings
22
- * @param config - Global configuration options
23
- */
24
- configure(config: ApiConfig): void {
25
- this.config = { ...this.config, ...config };
26
- }
27
-
28
- /**
29
- * Make a GET request
30
- * @param url - Request URL (relative to baseURL if configured)
31
- * @param options - Request options
32
- * @returns Promise with response data
33
- */
34
- async get<T = any>(url: string, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
35
- return this.request<T>(url, { ...options, method: 'GET' });
36
- }
37
-
38
- /**
39
- * Make a POST request
40
- * @param url - Request URL
41
- * @param data - Request body data
42
- * @param options - Request options
43
- * @returns Promise with response data
44
- */
45
- async post<T = any>(url: string, data?: any, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
46
- return this.request<T>(url, { ...options, method: 'POST', body: data });
47
- }
48
-
49
- /**
50
- * Make a PUT request
51
- * @param url - Request URL
52
- * @param data - Request body data
53
- * @param options - Request options
54
- * @returns Promise with response data
55
- */
56
- async put<T = any>(url: string, data?: any, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
57
- return this.request<T>(url, { ...options, method: 'PUT', body: data });
58
- }
59
-
60
- /**
61
- * Make a PATCH request
62
- * @param url - Request URL
63
- * @param data - Request body data
64
- * @param options - Request options
65
- * @returns Promise with response data
66
- */
67
- async patch<T = any>(url: string, data?: any, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
68
- return this.request<T>(url, { ...options, method: 'PATCH', body: data });
69
- }
70
-
71
- /**
72
- * Make a DELETE request
73
- * @param url - Request URL
74
- * @param options - Request options
75
- * @returns Promise with response data
76
- */
77
- async delete<T = any>(url: string, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
78
- return this.request<T>(url, { ...options, method: 'DELETE' });
79
- }
80
-
81
- /**
82
- * Make a generic HTTP request
83
- * @param url - Request URL
84
- * @param options - Request options
85
- * @returns Promise with response data
86
- */
87
- async request<T = any>(url: string, options: ApiRequestOptions = {}): Promise<ApiResponse<T>> {
88
- try {
89
- // Apply request interceptor if configured
90
- let finalOptions = options;
91
- if (this.config.requestInterceptor) {
92
- finalOptions = await this.config.requestInterceptor(options);
93
- }
94
-
95
- // Build final URL with baseURL and query params
96
- const finalUrl = this.buildUrl(url, finalOptions.params);
97
-
98
- // Build headers
99
- const headers = this.buildHeaders(finalOptions);
100
-
101
- // Build request body
102
- const body = this.buildBody(finalOptions.body, headers);
103
-
104
- // Setup timeout if specified
105
- const controller = new AbortController();
106
- const signal = finalOptions.signal || controller.signal;
107
- const timeout = finalOptions.timeout || this.config.timeout;
108
-
109
- let timeoutId: NodeJS.Timeout | undefined;
110
- if (timeout) {
111
- timeoutId = setTimeout(() => controller.abort(), timeout);
112
- }
113
-
114
- // Make fetch request
115
- const response = await fetch(finalUrl, {
116
- method: finalOptions.method || 'GET',
117
- headers,
118
- body,
119
- credentials: finalOptions.credentials,
120
- cache: finalOptions.cache,
121
- signal
122
- });
123
-
124
- // Clear timeout
125
- if (timeoutId) {
126
- clearTimeout(timeoutId);
127
- }
128
-
129
- // Parse response
130
- const responseData = await this.parseResponse<T>(response, finalOptions.responseType);
131
-
132
- // Build API response object
133
- let apiResponse: ApiResponse<T> = {
134
- data: responseData,
135
- status: response.status,
136
- statusText: response.statusText,
137
- headers: response.headers,
138
- raw: response
139
- };
140
-
141
- // Apply response interceptor if configured
142
- if (this.config.responseInterceptor) {
143
- apiResponse = await this.config.responseInterceptor(apiResponse);
144
- }
145
-
146
- // Check if response is ok
147
- if (!response.ok) {
148
- throw this.createError(
149
- `HTTP Error ${response.status}: ${response.statusText}`,
150
- response.status,
151
- response.statusText,
152
- responseData
153
- );
154
- }
155
-
156
- return apiResponse;
157
-
158
- } catch (error: any) {
159
- // Create API error
160
- let apiError: ApiError;
161
-
162
- if (error.name === 'AbortError') {
163
- apiError = this.createError('Request timeout', undefined, undefined, undefined, error);
164
- } else if (error.message?.includes('HTTP Error')) {
165
- apiError = error;
166
- } else {
167
- apiError = this.createError(
168
- error.message || 'Network error',
169
- undefined,
170
- undefined,
171
- undefined,
172
- error
173
- );
174
- }
175
-
176
- // Apply error interceptor if configured
177
- if (this.config.errorInterceptor) {
178
- apiError = await this.config.errorInterceptor(apiError);
179
- }
180
-
181
- throw apiError;
182
- }
183
- }
184
-
185
- /**
186
- * Build final URL with baseURL and query parameters
187
- */
188
- private buildUrl(url: string, params?: Record<string, string | number | boolean>): string {
189
- let finalUrl = url;
190
-
191
- // Add baseURL if configured and URL is relative
192
- if (this.config.baseURL && !url.startsWith('http')) {
193
- finalUrl = `${this.config.baseURL.replace(/\/$/, '')}/${url.replace(/^\//, '')}`;
194
- }
195
-
196
- // Add query parameters
197
- if (params) {
198
- const queryString = Object.entries(params)
199
- .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
200
- .join('&');
201
-
202
- finalUrl += (finalUrl.includes('?') ? '&' : '?') + queryString;
203
- }
204
-
205
- return finalUrl;
206
- }
207
-
208
- /**
209
- * Build request headers
210
- */
211
- private buildHeaders(options: ApiRequestOptions): HeadersInit {
212
- const headers: Record<string, string> = {
213
- ...this.config.headers,
214
- ...options.headers
215
- };
216
-
217
- // Auto-add Content-Type for JSON body if not specified
218
- if (options.body && typeof options.body === 'object' && !headers['Content-Type']) {
219
- headers['Content-Type'] = 'application/json';
220
- }
221
-
222
- return headers;
223
- }
224
-
225
- /**
226
- * Build request body
227
- */
228
- private buildBody(body: any, _headers: HeadersInit): BodyInit | undefined {
229
- if (!body) {
230
- return undefined;
231
- }
232
-
233
- // If body is already a string, FormData, Blob, etc., return as-is
234
- if (typeof body === 'string' || body instanceof FormData || body instanceof Blob) {
235
- return body;
236
- }
237
-
238
- // Otherwise, stringify as JSON
239
- return JSON.stringify(body);
240
- }
241
-
242
- /**
243
- * Parse response based on response type
244
- */
245
- private async parseResponse<T>(response: Response, responseType?: string): Promise<T> {
246
- const type = responseType || 'json';
247
-
248
- switch (type) {
249
- case 'json':
250
- try {
251
- return await response.json();
252
- } catch {
253
- return null as T;
254
- }
255
- case 'text':
256
- return await response.text() as T;
257
- case 'blob':
258
- return await response.blob() as T;
259
- case 'arraybuffer':
260
- return await response.arrayBuffer() as T;
261
- default:
262
- return await response.json();
263
- }
264
- }
265
-
266
- /**
267
- * Create an API error object
268
- */
269
- private createError(
270
- message: string,
271
- status?: number,
272
- statusText?: string,
273
- data?: any,
274
- originalError?: Error
275
- ): ApiError {
276
- return {
277
- message,
278
- status,
279
- statusText,
280
- data,
281
- originalError: originalError || new Error(message)
282
- };
283
- }
284
- }
285
-
286
- /**
287
- * Singleton instance of API Core Service
288
- */
289
- export const apiCoreService = new ApiCoreService();
1
+ /**
2
+ * KIMU API Core Service
3
+ * Lightweight HTTP client based on native fetch API
4
+ * Zero dependencies, Promise-based, TypeScript-first
5
+ */
6
+
7
+ import {
8
+ ApiRequestOptions,
9
+ ApiResponse,
10
+ ApiError,
11
+ ApiConfig
12
+ } from './interfaces';
13
+
14
+ /**
15
+ * Main API service class for making HTTP requests
16
+ */
17
+ export class ApiCoreService {
18
+ private config: ApiConfig = {};
19
+
20
+ /**
21
+ * Configure the API service with global settings
22
+ * @param config - Global configuration options
23
+ */
24
+ configure(config: ApiConfig): void {
25
+ this.config = { ...this.config, ...config };
26
+ }
27
+
28
+ /**
29
+ * Make a GET request
30
+ * @param url - Request URL (relative to baseURL if configured)
31
+ * @param options - Request options
32
+ * @returns Promise with response data
33
+ */
34
+ async get<T = any>(url: string, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
35
+ return this.request<T>(url, { ...options, method: 'GET' });
36
+ }
37
+
38
+ /**
39
+ * Make a POST request
40
+ * @param url - Request URL
41
+ * @param data - Request body data
42
+ * @param options - Request options
43
+ * @returns Promise with response data
44
+ */
45
+ async post<T = any>(url: string, data?: any, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
46
+ return this.request<T>(url, { ...options, method: 'POST', body: data });
47
+ }
48
+
49
+ /**
50
+ * Make a PUT request
51
+ * @param url - Request URL
52
+ * @param data - Request body data
53
+ * @param options - Request options
54
+ * @returns Promise with response data
55
+ */
56
+ async put<T = any>(url: string, data?: any, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
57
+ return this.request<T>(url, { ...options, method: 'PUT', body: data });
58
+ }
59
+
60
+ /**
61
+ * Make a PATCH request
62
+ * @param url - Request URL
63
+ * @param data - Request body data
64
+ * @param options - Request options
65
+ * @returns Promise with response data
66
+ */
67
+ async patch<T = any>(url: string, data?: any, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
68
+ return this.request<T>(url, { ...options, method: 'PATCH', body: data });
69
+ }
70
+
71
+ /**
72
+ * Make a DELETE request
73
+ * @param url - Request URL
74
+ * @param options - Request options
75
+ * @returns Promise with response data
76
+ */
77
+ async delete<T = any>(url: string, options?: ApiRequestOptions): Promise<ApiResponse<T>> {
78
+ return this.request<T>(url, { ...options, method: 'DELETE' });
79
+ }
80
+
81
+ /**
82
+ * Make a generic HTTP request
83
+ * @param url - Request URL
84
+ * @param options - Request options
85
+ * @returns Promise with response data
86
+ */
87
+ async request<T = any>(url: string, options: ApiRequestOptions = {}): Promise<ApiResponse<T>> {
88
+ try {
89
+ // Apply request interceptor if configured
90
+ let finalOptions = options;
91
+ if (this.config.requestInterceptor) {
92
+ finalOptions = await this.config.requestInterceptor(options);
93
+ }
94
+
95
+ // Build final URL with baseURL and query params
96
+ const finalUrl = this.buildUrl(url, finalOptions.params);
97
+
98
+ // Build headers
99
+ const headers = this.buildHeaders(finalOptions);
100
+
101
+ // Build request body
102
+ const body = this.buildBody(finalOptions.body, headers);
103
+
104
+ // Setup timeout if specified
105
+ const controller = new AbortController();
106
+ const signal = finalOptions.signal || controller.signal;
107
+ const timeout = finalOptions.timeout || this.config.timeout;
108
+
109
+ let timeoutId: NodeJS.Timeout | undefined;
110
+ if (timeout) {
111
+ timeoutId = setTimeout(() => controller.abort(), timeout);
112
+ }
113
+
114
+ // Make fetch request
115
+ const response = await fetch(finalUrl, {
116
+ method: finalOptions.method || 'GET',
117
+ headers,
118
+ body,
119
+ credentials: finalOptions.credentials,
120
+ cache: finalOptions.cache,
121
+ signal
122
+ });
123
+
124
+ // Clear timeout
125
+ if (timeoutId) {
126
+ clearTimeout(timeoutId);
127
+ }
128
+
129
+ // Parse response
130
+ const responseData = await this.parseResponse<T>(response, finalOptions.responseType);
131
+
132
+ // Build API response object
133
+ let apiResponse: ApiResponse<T> = {
134
+ data: responseData,
135
+ status: response.status,
136
+ statusText: response.statusText,
137
+ headers: response.headers,
138
+ raw: response
139
+ };
140
+
141
+ // Apply response interceptor if configured
142
+ if (this.config.responseInterceptor) {
143
+ apiResponse = await this.config.responseInterceptor(apiResponse);
144
+ }
145
+
146
+ // Check if response is ok
147
+ if (!response.ok) {
148
+ throw this.createError(
149
+ `HTTP Error ${response.status}: ${response.statusText}`,
150
+ response.status,
151
+ response.statusText,
152
+ responseData
153
+ );
154
+ }
155
+
156
+ return apiResponse;
157
+
158
+ } catch (error: any) {
159
+ // Create API error
160
+ let apiError: ApiError;
161
+
162
+ if (error.name === 'AbortError') {
163
+ apiError = this.createError('Request timeout', undefined, undefined, undefined, error);
164
+ } else if (error.message?.includes('HTTP Error')) {
165
+ apiError = error;
166
+ } else {
167
+ apiError = this.createError(
168
+ error.message || 'Network error',
169
+ undefined,
170
+ undefined,
171
+ undefined,
172
+ error
173
+ );
174
+ }
175
+
176
+ // Apply error interceptor if configured
177
+ if (this.config.errorInterceptor) {
178
+ apiError = await this.config.errorInterceptor(apiError);
179
+ }
180
+
181
+ throw apiError;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Build final URL with baseURL and query parameters
187
+ */
188
+ private buildUrl(url: string, params?: Record<string, string | number | boolean>): string {
189
+ let finalUrl = url;
190
+
191
+ // Add baseURL if configured and URL is relative
192
+ if (this.config.baseURL && !url.startsWith('http')) {
193
+ finalUrl = `${this.config.baseURL.replace(/\/$/, '')}/${url.replace(/^\//, '')}`;
194
+ }
195
+
196
+ // Add query parameters
197
+ if (params) {
198
+ const queryString = Object.entries(params)
199
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
200
+ .join('&');
201
+
202
+ finalUrl += (finalUrl.includes('?') ? '&' : '?') + queryString;
203
+ }
204
+
205
+ return finalUrl;
206
+ }
207
+
208
+ /**
209
+ * Build request headers
210
+ */
211
+ private buildHeaders(options: ApiRequestOptions): HeadersInit {
212
+ const headers: Record<string, string> = {
213
+ ...this.config.headers,
214
+ ...options.headers
215
+ };
216
+
217
+ // Auto-add Content-Type for JSON body if not specified
218
+ if (options.body && typeof options.body === 'object' && !headers['Content-Type']) {
219
+ headers['Content-Type'] = 'application/json';
220
+ }
221
+
222
+ return headers;
223
+ }
224
+
225
+ /**
226
+ * Build request body
227
+ */
228
+ private buildBody(body: any, _headers: HeadersInit): BodyInit | undefined {
229
+ if (!body) {
230
+ return undefined;
231
+ }
232
+
233
+ // If body is already a string, FormData, Blob, etc., return as-is
234
+ if (typeof body === 'string' || body instanceof FormData || body instanceof Blob) {
235
+ return body;
236
+ }
237
+
238
+ // Otherwise, stringify as JSON
239
+ return JSON.stringify(body);
240
+ }
241
+
242
+ /**
243
+ * Parse response based on response type
244
+ */
245
+ private async parseResponse<T>(response: Response, responseType?: string): Promise<T> {
246
+ const type = responseType || 'json';
247
+
248
+ switch (type) {
249
+ case 'json':
250
+ try {
251
+ return await response.json();
252
+ } catch {
253
+ return null as T;
254
+ }
255
+ case 'text':
256
+ return await response.text() as T;
257
+ case 'blob':
258
+ return await response.blob() as T;
259
+ case 'arraybuffer':
260
+ return await response.arrayBuffer() as T;
261
+ default:
262
+ return await response.json();
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Create an API error object
268
+ */
269
+ private createError(
270
+ message: string,
271
+ status?: number,
272
+ statusText?: string,
273
+ data?: any,
274
+ originalError?: Error
275
+ ): ApiError {
276
+ return {
277
+ message,
278
+ status,
279
+ statusText,
280
+ data,
281
+ originalError: originalError || new Error(message)
282
+ };
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Singleton instance of API Core Service
288
+ */
289
+ export const apiCoreService = new ApiCoreService();