juxscript 1.1.4 → 1.1.6
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/index.d.ts +10 -10
- package/index.d.ts.map +1 -0
- package/lib/components/alert.d.ts +32 -0
- package/lib/components/alert.d.ts.map +1 -0
- package/lib/components/alert.js +153 -0
- package/lib/components/alert.ts +200 -0
- package/lib/components/app.d.ts +89 -0
- package/lib/components/app.d.ts.map +1 -0
- package/lib/components/app.js +175 -0
- package/lib/components/app.ts +247 -0
- package/lib/components/badge.d.ts +27 -0
- package/lib/components/badge.d.ts.map +1 -0
- package/lib/components/badge.js +70 -0
- package/lib/components/badge.ts +101 -0
- package/lib/components/base/BaseComponent.d.ts +142 -0
- package/lib/components/base/BaseComponent.d.ts.map +1 -0
- package/lib/components/base/BaseComponent.js +363 -0
- package/lib/components/base/BaseComponent.ts +421 -0
- package/lib/components/base/FormInput.d.ts +73 -0
- package/lib/components/base/FormInput.d.ts.map +1 -0
- package/lib/components/base/FormInput.js +163 -0
- package/lib/components/base/FormInput.ts +227 -0
- package/lib/components/button.d.ts +48 -0
- package/lib/components/button.d.ts.map +1 -0
- package/lib/components/button.js +121 -0
- package/lib/components/button.ts +178 -0
- package/lib/components/card.d.ts +34 -0
- package/lib/components/card.d.ts.map +1 -0
- package/lib/components/card.js +127 -0
- package/lib/components/card.ts +173 -0
- package/lib/components/chart.d.ts +45 -0
- package/lib/components/chart.d.ts.map +1 -0
- package/lib/components/chart.js +186 -0
- package/lib/components/chart.ts +231 -0
- package/lib/components/checkbox.d.ts +31 -0
- package/lib/components/checkbox.d.ts.map +1 -0
- package/lib/components/checkbox.js +185 -0
- package/lib/components/checkbox.ts +242 -0
- package/lib/components/code.d.ts +24 -0
- package/lib/components/code.d.ts.map +1 -0
- package/lib/components/code.js +88 -0
- package/lib/components/code.ts +123 -0
- package/lib/components/container.d.ts +42 -0
- package/lib/components/container.d.ts.map +1 -0
- package/lib/components/container.js +93 -0
- package/lib/components/container.ts +140 -0
- package/lib/components/data.d.ts +36 -0
- package/lib/components/data.d.ts.map +1 -0
- package/lib/components/data.js +110 -0
- package/lib/components/data.ts +135 -0
- package/lib/components/datepicker.d.ts +38 -0
- package/lib/components/datepicker.d.ts.map +1 -0
- package/lib/components/datepicker.js +177 -0
- package/lib/components/datepicker.ts +234 -0
- package/lib/components/dialog.d.ts +38 -0
- package/lib/components/dialog.d.ts.map +1 -0
- package/lib/components/dialog.js +126 -0
- package/lib/components/dialog.ts +172 -0
- package/lib/components/divider.d.ts +30 -0
- package/lib/components/divider.d.ts.map +1 -0
- package/lib/components/divider.js +69 -0
- package/lib/components/divider.ts +100 -0
- package/lib/components/dropdown.d.ts +39 -0
- package/lib/components/dropdown.d.ts.map +1 -0
- package/lib/components/dropdown.js +133 -0
- package/lib/components/dropdown.ts +186 -0
- package/lib/components/element.d.ts +50 -0
- package/lib/components/element.d.ts.map +1 -0
- package/lib/components/element.js +206 -0
- package/lib/components/element.ts +267 -0
- package/lib/components/fileupload.d.ts +40 -0
- package/lib/components/fileupload.d.ts.map +1 -0
- package/lib/components/fileupload.js +241 -0
- package/lib/components/fileupload.ts +309 -0
- package/lib/components/grid.d.ts +87 -0
- package/lib/components/grid.d.ts.map +1 -0
- package/lib/components/grid.js +205 -0
- package/lib/components/grid.ts +291 -0
- package/lib/components/guard.d.ts +41 -0
- package/lib/components/guard.d.ts.map +1 -0
- package/lib/components/guard.js +56 -0
- package/lib/components/guard.ts +92 -0
- package/lib/components/heading.d.ts +24 -0
- package/lib/components/heading.d.ts.map +1 -0
- package/lib/components/heading.js +67 -0
- package/lib/components/heading.ts +96 -0
- package/lib/components/helpers.d.ts +9 -0
- package/lib/components/helpers.d.ts.map +1 -0
- package/lib/components/helpers.js +30 -0
- package/lib/components/helpers.ts +41 -0
- package/lib/components/hero.d.ts +45 -0
- package/lib/components/hero.d.ts.map +1 -0
- package/lib/components/hero.js +165 -0
- package/lib/components/hero.ts +224 -0
- package/lib/components/icon.d.ts +35 -0
- package/lib/components/icon.d.ts.map +1 -0
- package/lib/components/icon.js +132 -0
- package/lib/components/icon.ts +178 -0
- package/lib/components/icons.d.ts +25 -0
- package/lib/components/icons.d.ts.map +1 -0
- package/lib/components/icons.js +440 -0
- package/lib/components/icons.ts +464 -0
- package/lib/components/include.d.ts +120 -0
- package/lib/components/include.d.ts.map +1 -0
- package/lib/components/include.js +350 -0
- package/lib/components/include.ts +410 -0
- package/lib/components/input.d.ts +83 -0
- package/lib/components/input.d.ts.map +1 -0
- package/lib/components/input.js +348 -0
- package/lib/components/input.ts +457 -0
- package/lib/components/list.d.ts +82 -0
- package/lib/components/list.d.ts.map +1 -0
- package/lib/components/list.js +311 -0
- package/lib/components/list.ts +419 -0
- package/lib/components/loading.d.ts +24 -0
- package/lib/components/loading.d.ts.map +1 -0
- package/lib/components/loading.js +73 -0
- package/lib/components/loading.ts +100 -0
- package/lib/components/menu.d.ts +37 -0
- package/lib/components/menu.d.ts.map +1 -0
- package/lib/components/menu.js +202 -0
- package/lib/components/menu.ts +275 -0
- package/lib/components/modal.d.ts +51 -0
- package/lib/components/modal.d.ts.map +1 -0
- package/lib/components/modal.js +227 -0
- package/lib/components/modal.ts +284 -0
- package/lib/components/nav.d.ts +45 -0
- package/lib/components/nav.d.ts.map +1 -0
- package/lib/components/nav.js +190 -0
- package/lib/components/nav.ts +257 -0
- package/lib/components/paragraph.d.ts +21 -0
- package/lib/components/paragraph.d.ts.map +1 -0
- package/lib/components/paragraph.js +70 -0
- package/lib/components/paragraph.ts +97 -0
- package/lib/components/progress.d.ts +39 -0
- package/lib/components/progress.d.ts.map +1 -0
- package/lib/components/progress.js +113 -0
- package/lib/components/progress.ts +159 -0
- package/lib/components/radio.d.ts +41 -0
- package/lib/components/radio.d.ts.map +1 -0
- package/lib/components/radio.js +203 -0
- package/lib/components/radio.ts +278 -0
- package/lib/components/req.d.ts +155 -0
- package/lib/components/req.d.ts.map +1 -0
- package/lib/components/req.js +253 -0
- package/lib/components/req.ts +303 -0
- package/lib/components/script.d.ts +14 -0
- package/lib/components/script.d.ts.map +1 -0
- package/lib/components/script.js +33 -0
- package/lib/components/script.ts +41 -0
- package/lib/components/select.d.ts +40 -0
- package/lib/components/select.d.ts.map +1 -0
- package/lib/components/select.js +183 -0
- package/lib/components/select.ts +252 -0
- package/lib/components/sidebar.d.ts +48 -0
- package/lib/components/sidebar.d.ts.map +1 -0
- package/lib/components/sidebar.js +207 -0
- package/lib/components/sidebar.ts +275 -0
- package/lib/components/style.d.ts +14 -0
- package/lib/components/style.d.ts.map +1 -0
- package/lib/components/style.js +33 -0
- package/lib/components/style.ts +41 -0
- package/lib/components/switch.d.ts +32 -0
- package/lib/components/switch.d.ts.map +1 -0
- package/lib/components/switch.js +186 -0
- package/lib/components/switch.ts +246 -0
- package/lib/components/table.d.ts +137 -0
- package/lib/components/table.d.ts.map +1 -0
- package/lib/components/table.js +1045 -0
- package/lib/components/table.ts +1249 -0
- package/lib/components/tabs.d.ts +36 -0
- package/lib/components/tabs.d.ts.map +1 -0
- package/lib/components/tabs.js +198 -0
- package/lib/components/tabs.ts +250 -0
- package/lib/components/theme-toggle.d.ts +44 -0
- package/lib/components/theme-toggle.d.ts.map +1 -0
- package/lib/components/theme-toggle.js +215 -0
- package/lib/components/theme-toggle.ts +293 -0
- package/lib/components/tooltip.d.ts +30 -0
- package/lib/components/tooltip.d.ts.map +1 -0
- package/lib/components/tooltip.js +109 -0
- package/lib/components/tooltip.ts +144 -0
- package/lib/components/view.d.ts +48 -0
- package/lib/components/view.d.ts.map +1 -0
- package/lib/components/view.js +149 -0
- package/lib/components/view.ts +190 -0
- package/lib/components/write.d.ts +107 -0
- package/lib/components/write.d.ts.map +1 -0
- package/lib/components/write.js +222 -0
- package/lib/components/write.ts +272 -0
- package/lib/layouts/default.css +260 -0
- package/lib/layouts/figma.css +334 -0
- package/lib/reactivity/state.d.ts +36 -0
- package/lib/reactivity/state.d.ts.map +1 -0
- package/lib/reactivity/state.js +67 -0
- package/lib/reactivity/state.ts +78 -0
- package/lib/utils/fetch.d.ts +176 -0
- package/lib/utils/fetch.d.ts.map +1 -0
- package/lib/utils/fetch.js +427 -0
- package/lib/utils/fetch.ts +553 -0
- package/machinery/compiler3.js +78 -0
- package/machinery/doc-generator.js +136 -0
- package/machinery/imports.js +155 -0
- package/machinery/ts-shim.js +46 -0
- package/package.json +9 -15
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple reactive state container
|
|
3
|
+
*/
|
|
4
|
+
export class State<T> {
|
|
5
|
+
private _value: T;
|
|
6
|
+
private _subscribers: Set<(value: T) => void> = new Set();
|
|
7
|
+
|
|
8
|
+
constructor(initialValue: T) {
|
|
9
|
+
this._value = initialValue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get current value
|
|
14
|
+
*/
|
|
15
|
+
get value(): T {
|
|
16
|
+
return this._value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Set new value and notify subscribers
|
|
21
|
+
*/
|
|
22
|
+
set(newValue: T): void {
|
|
23
|
+
this._value = newValue;
|
|
24
|
+
this._notify();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Subscribe to value changes
|
|
29
|
+
*/
|
|
30
|
+
subscribe(callback: (value: T) => void): () => void {
|
|
31
|
+
this._subscribers.add(callback);
|
|
32
|
+
// Call immediately with current value
|
|
33
|
+
callback(this._value);
|
|
34
|
+
// Return unsubscribe function
|
|
35
|
+
return () => this._subscribers.delete(callback);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Notify all subscribers
|
|
40
|
+
*/
|
|
41
|
+
private _notify(): void {
|
|
42
|
+
this._subscribers.forEach(callback => callback(this._value));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Helper methods for numeric state
|
|
47
|
+
*/
|
|
48
|
+
increment(): void {
|
|
49
|
+
if (typeof this._value === 'number') {
|
|
50
|
+
this.set((this._value + 1) as T);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
decrement(): void {
|
|
55
|
+
if (typeof this._value === 'number') {
|
|
56
|
+
this.set((this._value - 1) as T);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
add(amount: number): void {
|
|
61
|
+
if (typeof this._value === 'number') {
|
|
62
|
+
this.set((this._value + amount) as T);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
subtract(amount: number): void {
|
|
67
|
+
if (typeof this._value === 'number') {
|
|
68
|
+
this.set((this._value - amount) as T);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Factory function to create reactive state
|
|
75
|
+
*/
|
|
76
|
+
export function state<T>(initialValue: T): State<T> {
|
|
77
|
+
return new State(initialValue);
|
|
78
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jux Fetch Utility
|
|
3
|
+
*
|
|
4
|
+
* A lightweight fetch wrapper with sensible defaults, error handling, and method chaining.
|
|
5
|
+
* Includes configuration helpers for juxconfig.js integration.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* // Configure once (optional)
|
|
9
|
+
* jux.fetch.config({
|
|
10
|
+
* baseUrl: 'https://api.example.com',
|
|
11
|
+
* credentials: 'include',
|
|
12
|
+
* timeout: 10000,
|
|
13
|
+
* log: 'errors',
|
|
14
|
+
* onUnauthorized: () => window.location.href = '/login'
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Simple GET
|
|
18
|
+
* const { data, error } = await jux.fetch('/users').send();
|
|
19
|
+
*
|
|
20
|
+
* // Method chaining
|
|
21
|
+
* const { data, error } = await jux.fetch('/users')
|
|
22
|
+
* .method('POST')
|
|
23
|
+
* .body({ name: 'John' })
|
|
24
|
+
* .params({ limit: 10 })
|
|
25
|
+
* .timeout(5000)
|
|
26
|
+
* .log(true)
|
|
27
|
+
* .send();
|
|
28
|
+
*
|
|
29
|
+
* // With juxconfig services
|
|
30
|
+
* const { data } = await jux.fetch('/users')
|
|
31
|
+
* .baseUrl(jux.fetch.getServiceUrl('database'))
|
|
32
|
+
* .send();
|
|
33
|
+
*
|
|
34
|
+
* // Service client helper
|
|
35
|
+
* const db = jux.fetch.serviceClient('database');
|
|
36
|
+
* const { data } = await db.fetch('/users').send();
|
|
37
|
+
*/
|
|
38
|
+
export type LogLevel = boolean | 'errors';
|
|
39
|
+
export interface FetchConfig {
|
|
40
|
+
baseUrl?: string;
|
|
41
|
+
credentials?: RequestCredentials;
|
|
42
|
+
headers?: Record<string, string>;
|
|
43
|
+
timeout?: number;
|
|
44
|
+
log?: LogLevel;
|
|
45
|
+
onUnauthorized?: () => void;
|
|
46
|
+
onError?: (error: FetchError) => void;
|
|
47
|
+
}
|
|
48
|
+
export interface FetchOptions extends Omit<RequestInit, 'body'> {
|
|
49
|
+
params?: Record<string, any>;
|
|
50
|
+
body?: any;
|
|
51
|
+
timeout?: number;
|
|
52
|
+
log?: LogLevel;
|
|
53
|
+
onUnauthorized?: () => void;
|
|
54
|
+
onError?: (error: FetchError) => void;
|
|
55
|
+
parseResponse?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface FetchError {
|
|
58
|
+
message: string;
|
|
59
|
+
status?: number;
|
|
60
|
+
statusText?: string;
|
|
61
|
+
data?: any;
|
|
62
|
+
}
|
|
63
|
+
export interface FetchResult<T = any> {
|
|
64
|
+
data: T | null;
|
|
65
|
+
error: FetchError | null;
|
|
66
|
+
status: number;
|
|
67
|
+
response: Response;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Configure global fetch defaults
|
|
71
|
+
*/
|
|
72
|
+
export declare function configureFetch(config: FetchConfig): void;
|
|
73
|
+
/**
|
|
74
|
+
* FetchBuilder class for method chaining
|
|
75
|
+
*/
|
|
76
|
+
declare class FetchBuilder<T = any> {
|
|
77
|
+
url: string;
|
|
78
|
+
options: FetchOptions;
|
|
79
|
+
constructor(url: string, options?: FetchOptions);
|
|
80
|
+
method(value: string): this;
|
|
81
|
+
body(value: any): this;
|
|
82
|
+
params(value: Record<string, any>): this;
|
|
83
|
+
headers(value: Record<string, string>): this;
|
|
84
|
+
header(key: string, value: string): this;
|
|
85
|
+
timeout(value: number): this;
|
|
86
|
+
credentials(value: RequestCredentials): this;
|
|
87
|
+
log(value: LogLevel): this;
|
|
88
|
+
parseResponse(value: boolean): this;
|
|
89
|
+
onUnauthorized(callback: () => void): this;
|
|
90
|
+
onError(callback: (error: FetchError) => void): this;
|
|
91
|
+
/**
|
|
92
|
+
* Execute the fetch request
|
|
93
|
+
*/
|
|
94
|
+
send(): Promise<FetchResult<T>>;
|
|
95
|
+
/**
|
|
96
|
+
* Alias for send()
|
|
97
|
+
*/
|
|
98
|
+
fetch(): Promise<FetchResult<T>>;
|
|
99
|
+
/**
|
|
100
|
+
* Make the builder thenable (Promise-like) so it can be awaited directly
|
|
101
|
+
* This allows: await jux.fetch('/users') without needing .send()
|
|
102
|
+
*/
|
|
103
|
+
then<TResult1 = FetchResult<T>, TResult2 = never>(onfulfilled?: ((value: FetchResult<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
104
|
+
/**
|
|
105
|
+
* Make the builder catchable for Promise.catch()
|
|
106
|
+
*/
|
|
107
|
+
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<FetchResult<T> | TResult>;
|
|
108
|
+
/**
|
|
109
|
+
* Make the builder finally-able for Promise.finally()
|
|
110
|
+
*/
|
|
111
|
+
finally(onfinally?: (() => void) | null): Promise<FetchResult<T>>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Create a fetch builder
|
|
115
|
+
*/
|
|
116
|
+
export declare function juxFetch<T = any>(url: string, options?: FetchOptions): FetchBuilder<T>;
|
|
117
|
+
/**
|
|
118
|
+
* Convenience methods for common HTTP verbs
|
|
119
|
+
*/
|
|
120
|
+
export declare const fetchHelpers: {
|
|
121
|
+
get: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
|
|
122
|
+
post: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
|
|
123
|
+
put: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
|
|
124
|
+
patch: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
|
|
125
|
+
delete: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Fetch multiple URLs in parallel
|
|
129
|
+
*/
|
|
130
|
+
export declare function fetchAll<T = any>(urls: string[], options?: FetchOptions): Promise<FetchResult<T>[]>;
|
|
131
|
+
/**
|
|
132
|
+
* Get a service URL from window.juxConfig
|
|
133
|
+
*/
|
|
134
|
+
export declare function getServiceUrl(serviceName: string): string | null;
|
|
135
|
+
/**
|
|
136
|
+
* Create a fetch instance preconfigured for a specific service
|
|
137
|
+
*
|
|
138
|
+
* Usage:
|
|
139
|
+
* const api = jux.fetch.serviceClient('database');
|
|
140
|
+
* const { data } = await api.fetch('/users').send();
|
|
141
|
+
*/
|
|
142
|
+
export declare function serviceClient(serviceName: string): {
|
|
143
|
+
fetch: (url: string, options?: any) => FetchBuilder<any>;
|
|
144
|
+
baseUrl: string | null;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Setup fetch from juxconfig
|
|
148
|
+
* Call this in your bootstrap function
|
|
149
|
+
*
|
|
150
|
+
* Usage:
|
|
151
|
+
* export default {
|
|
152
|
+
* bootstrap: [
|
|
153
|
+
* async function initFetch() {
|
|
154
|
+
* await jux.fetch.setupConfig();
|
|
155
|
+
* }
|
|
156
|
+
* ]
|
|
157
|
+
* };
|
|
158
|
+
*/
|
|
159
|
+
export declare function setupConfig(): Promise<{
|
|
160
|
+
services: any;
|
|
161
|
+
getServiceUrl: typeof getServiceUrl;
|
|
162
|
+
} | undefined>;
|
|
163
|
+
export declare const fetchAPI: typeof juxFetch & {
|
|
164
|
+
all: typeof fetchAll;
|
|
165
|
+
get: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
|
|
166
|
+
post: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
|
|
167
|
+
put: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
|
|
168
|
+
patch: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
|
|
169
|
+
delete: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
|
|
170
|
+
config: typeof configureFetch;
|
|
171
|
+
setupConfig: typeof setupConfig;
|
|
172
|
+
getServiceUrl: typeof getServiceUrl;
|
|
173
|
+
serviceClient: typeof serviceClient;
|
|
174
|
+
};
|
|
175
|
+
export {};
|
|
176
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jux Fetch Utility
|
|
3
|
+
*
|
|
4
|
+
* A lightweight fetch wrapper with sensible defaults, error handling, and method chaining.
|
|
5
|
+
* Includes configuration helpers for juxconfig.js integration.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* // Configure once (optional)
|
|
9
|
+
* jux.fetch.config({
|
|
10
|
+
* baseUrl: 'https://api.example.com',
|
|
11
|
+
* credentials: 'include',
|
|
12
|
+
* timeout: 10000,
|
|
13
|
+
* log: 'errors',
|
|
14
|
+
* onUnauthorized: () => window.location.href = '/login'
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Simple GET
|
|
18
|
+
* const { data, error } = await jux.fetch('/users').send();
|
|
19
|
+
*
|
|
20
|
+
* // Method chaining
|
|
21
|
+
* const { data, error } = await jux.fetch('/users')
|
|
22
|
+
* .method('POST')
|
|
23
|
+
* .body({ name: 'John' })
|
|
24
|
+
* .params({ limit: 10 })
|
|
25
|
+
* .timeout(5000)
|
|
26
|
+
* .log(true)
|
|
27
|
+
* .send();
|
|
28
|
+
*
|
|
29
|
+
* // With juxconfig services
|
|
30
|
+
* const { data } = await jux.fetch('/users')
|
|
31
|
+
* .baseUrl(jux.fetch.getServiceUrl('database'))
|
|
32
|
+
* .send();
|
|
33
|
+
*
|
|
34
|
+
* // Service client helper
|
|
35
|
+
* const db = jux.fetch.serviceClient('database');
|
|
36
|
+
* const { data } = await db.fetch('/users').send();
|
|
37
|
+
*/
|
|
38
|
+
// Global configuration
|
|
39
|
+
let globalConfig = {
|
|
40
|
+
credentials: 'same-origin',
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json'
|
|
43
|
+
},
|
|
44
|
+
timeout: 30000,
|
|
45
|
+
log: false
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Configure global fetch defaults
|
|
49
|
+
*/
|
|
50
|
+
export function configureFetch(config) {
|
|
51
|
+
globalConfig = {
|
|
52
|
+
...globalConfig,
|
|
53
|
+
...config,
|
|
54
|
+
headers: {
|
|
55
|
+
...globalConfig.headers,
|
|
56
|
+
...config.headers
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build URL with query parameters
|
|
62
|
+
*/
|
|
63
|
+
function buildUrl(url, params) {
|
|
64
|
+
if (!params || Object.keys(params).length === 0) {
|
|
65
|
+
return url;
|
|
66
|
+
}
|
|
67
|
+
const searchParams = new URLSearchParams();
|
|
68
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
69
|
+
if (value !== undefined && value !== null) {
|
|
70
|
+
searchParams.append(key, String(value));
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
const queryString = searchParams.toString();
|
|
74
|
+
if (!queryString)
|
|
75
|
+
return url;
|
|
76
|
+
return url.includes('?')
|
|
77
|
+
? `${url}&${queryString}`
|
|
78
|
+
: `${url}?${queryString}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Main fetch function
|
|
82
|
+
*/
|
|
83
|
+
async function executeFetch(url, options = {}) {
|
|
84
|
+
const { params, body, timeout = globalConfig.timeout, log = globalConfig.log, onUnauthorized = globalConfig.onUnauthorized, onError = globalConfig.onError, parseResponse = true, headers = {}, ...fetchOptions } = options;
|
|
85
|
+
// Build full URL
|
|
86
|
+
let fullUrl = url;
|
|
87
|
+
// Add base URL if configured and URL is relative
|
|
88
|
+
if (globalConfig.baseUrl && !url.startsWith('http://') && !url.startsWith('https://')) {
|
|
89
|
+
fullUrl = `${globalConfig.baseUrl}${url.startsWith('/') ? url : `/${url}`}`;
|
|
90
|
+
}
|
|
91
|
+
// Add query params
|
|
92
|
+
fullUrl = buildUrl(fullUrl, params);
|
|
93
|
+
// Merge headers
|
|
94
|
+
const mergedHeaders = {
|
|
95
|
+
...globalConfig.headers,
|
|
96
|
+
...headers
|
|
97
|
+
};
|
|
98
|
+
// Prepare request init
|
|
99
|
+
const requestInit = {
|
|
100
|
+
...fetchOptions,
|
|
101
|
+
headers: mergedHeaders,
|
|
102
|
+
credentials: options.credentials ?? globalConfig.credentials
|
|
103
|
+
};
|
|
104
|
+
// Stringify body if it's an object
|
|
105
|
+
if (body !== undefined) {
|
|
106
|
+
if (body instanceof FormData) {
|
|
107
|
+
requestInit.body = body;
|
|
108
|
+
// Remove Content-Type header for FormData (browser sets it with boundary)
|
|
109
|
+
delete requestInit.headers['Content-Type'];
|
|
110
|
+
}
|
|
111
|
+
else if (typeof body === 'object') {
|
|
112
|
+
requestInit.body = JSON.stringify(body);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
requestInit.body = body;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Log request
|
|
119
|
+
if (log === true) {
|
|
120
|
+
console.log(`[JUX Fetch] ${requestInit.method || 'GET'} ${fullUrl}`, {
|
|
121
|
+
headers: requestInit.headers,
|
|
122
|
+
body: requestInit.body,
|
|
123
|
+
params
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Setup timeout
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
const timeoutId = timeout ? setTimeout(() => controller.abort(), timeout) : null;
|
|
129
|
+
if (!requestInit.signal) {
|
|
130
|
+
requestInit.signal = controller.signal;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const response = await fetch(fullUrl, requestInit);
|
|
134
|
+
if (timeoutId)
|
|
135
|
+
clearTimeout(timeoutId);
|
|
136
|
+
// Handle unauthorized
|
|
137
|
+
if (response.status === 401 || response.status === 403) {
|
|
138
|
+
if (onUnauthorized) {
|
|
139
|
+
onUnauthorized();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Parse response
|
|
143
|
+
let data = null;
|
|
144
|
+
let errorData = null;
|
|
145
|
+
if (parseResponse) {
|
|
146
|
+
const contentType = response.headers.get('content-type');
|
|
147
|
+
if (contentType?.includes('application/json')) {
|
|
148
|
+
try {
|
|
149
|
+
const json = await response.json();
|
|
150
|
+
if (response.ok) {
|
|
151
|
+
data = json;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
errorData = json;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
// JSON parse error
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (response.ok) {
|
|
162
|
+
// Non-JSON response, try to get text
|
|
163
|
+
try {
|
|
164
|
+
data = (await response.text());
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
// Ignore text parse errors
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Check if request was successful
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
const error = {
|
|
174
|
+
message: errorData?.message || errorData?.error || response.statusText || 'Request failed',
|
|
175
|
+
status: response.status,
|
|
176
|
+
statusText: response.statusText,
|
|
177
|
+
data: errorData
|
|
178
|
+
};
|
|
179
|
+
// Log error
|
|
180
|
+
if (log === true || log === 'errors') {
|
|
181
|
+
console.error(`[JUX Fetch Error] ${requestInit.method || 'GET'} ${fullUrl}`, error);
|
|
182
|
+
}
|
|
183
|
+
if (onError) {
|
|
184
|
+
onError(error);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
data: null,
|
|
188
|
+
error,
|
|
189
|
+
status: response.status,
|
|
190
|
+
response
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Log success
|
|
194
|
+
if (log === true) {
|
|
195
|
+
console.log(`[JUX Fetch Success] ${requestInit.method || 'GET'} ${fullUrl}`, {
|
|
196
|
+
status: response.status,
|
|
197
|
+
data
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
data,
|
|
202
|
+
error: null,
|
|
203
|
+
status: response.status,
|
|
204
|
+
response
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
if (timeoutId)
|
|
209
|
+
clearTimeout(timeoutId);
|
|
210
|
+
const error = {
|
|
211
|
+
message: err.name === 'AbortError'
|
|
212
|
+
? 'Request timeout'
|
|
213
|
+
: err.message || 'Network error',
|
|
214
|
+
status: 0
|
|
215
|
+
};
|
|
216
|
+
// Log error
|
|
217
|
+
if (log === true || log === 'errors') {
|
|
218
|
+
console.error(`[JUX Fetch Error] ${requestInit.method || 'GET'} ${fullUrl}`, error);
|
|
219
|
+
}
|
|
220
|
+
if (onError) {
|
|
221
|
+
onError(error);
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
data: null,
|
|
225
|
+
error,
|
|
226
|
+
status: 0,
|
|
227
|
+
response: null
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* FetchBuilder class for method chaining
|
|
233
|
+
*/
|
|
234
|
+
class FetchBuilder {
|
|
235
|
+
constructor(url, options = {}) {
|
|
236
|
+
this.options = {};
|
|
237
|
+
this.url = url;
|
|
238
|
+
this.options = options;
|
|
239
|
+
}
|
|
240
|
+
method(value) {
|
|
241
|
+
this.options.method = value;
|
|
242
|
+
return this;
|
|
243
|
+
}
|
|
244
|
+
body(value) {
|
|
245
|
+
this.options.body = value;
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
params(value) {
|
|
249
|
+
this.options.params = value;
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
headers(value) {
|
|
253
|
+
this.options.headers = { ...this.options.headers, ...value };
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
header(key, value) {
|
|
257
|
+
this.options.headers = { ...this.options.headers, [key]: value };
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
timeout(value) {
|
|
261
|
+
this.options.timeout = value;
|
|
262
|
+
return this;
|
|
263
|
+
}
|
|
264
|
+
credentials(value) {
|
|
265
|
+
this.options.credentials = value;
|
|
266
|
+
return this;
|
|
267
|
+
}
|
|
268
|
+
log(value) {
|
|
269
|
+
this.options.log = value;
|
|
270
|
+
return this;
|
|
271
|
+
}
|
|
272
|
+
parseResponse(value) {
|
|
273
|
+
this.options.parseResponse = value;
|
|
274
|
+
return this;
|
|
275
|
+
}
|
|
276
|
+
onUnauthorized(callback) {
|
|
277
|
+
this.options.onUnauthorized = callback;
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
onError(callback) {
|
|
281
|
+
this.options.onError = callback;
|
|
282
|
+
return this;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Execute the fetch request
|
|
286
|
+
*/
|
|
287
|
+
send() {
|
|
288
|
+
return executeFetch(this.url, this.options);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Alias for send()
|
|
292
|
+
*/
|
|
293
|
+
fetch() {
|
|
294
|
+
return this.send();
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Make the builder thenable (Promise-like) so it can be awaited directly
|
|
298
|
+
* This allows: await jux.fetch('/users') without needing .send()
|
|
299
|
+
*/
|
|
300
|
+
then(onfulfilled, onrejected) {
|
|
301
|
+
return this.send().then(onfulfilled, onrejected);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Make the builder catchable for Promise.catch()
|
|
305
|
+
*/
|
|
306
|
+
catch(onrejected) {
|
|
307
|
+
return this.send().catch(onrejected);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Make the builder finally-able for Promise.finally()
|
|
311
|
+
*/
|
|
312
|
+
finally(onfinally) {
|
|
313
|
+
return this.send().finally(onfinally);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Create a fetch builder
|
|
318
|
+
*/
|
|
319
|
+
export function juxFetch(url, options = {}) {
|
|
320
|
+
return new FetchBuilder(url, options);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Convenience methods for common HTTP verbs
|
|
324
|
+
*/
|
|
325
|
+
export const fetchHelpers = {
|
|
326
|
+
get: (url, options) => new FetchBuilder(url, { ...options, method: 'GET' }),
|
|
327
|
+
post: (url, body, options) => new FetchBuilder(url, { ...options, method: 'POST', body }),
|
|
328
|
+
put: (url, body, options) => new FetchBuilder(url, { ...options, method: 'PUT', body }),
|
|
329
|
+
patch: (url, body, options) => new FetchBuilder(url, { ...options, method: 'PATCH', body }),
|
|
330
|
+
delete: (url, options) => new FetchBuilder(url, { ...options, method: 'DELETE' })
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Fetch multiple URLs in parallel
|
|
334
|
+
*/
|
|
335
|
+
export async function fetchAll(urls, options) {
|
|
336
|
+
return Promise.all(urls.map(url => executeFetch(url, options)));
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get a service URL from window.juxConfig
|
|
340
|
+
*/
|
|
341
|
+
export function getServiceUrl(serviceName) {
|
|
342
|
+
if (typeof window === 'undefined')
|
|
343
|
+
return null;
|
|
344
|
+
const juxConfig = window.juxConfig;
|
|
345
|
+
if (!juxConfig?.services)
|
|
346
|
+
return null;
|
|
347
|
+
return juxConfig.services[serviceName] || null;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Create a fetch instance preconfigured for a specific service
|
|
351
|
+
*
|
|
352
|
+
* Usage:
|
|
353
|
+
* const api = jux.fetch.serviceClient('database');
|
|
354
|
+
* const { data } = await api.fetch('/users').send();
|
|
355
|
+
*/
|
|
356
|
+
export function serviceClient(serviceName) {
|
|
357
|
+
const baseUrl = getServiceUrl(serviceName);
|
|
358
|
+
if (!baseUrl) {
|
|
359
|
+
console.warn(`[JUX Fetch] Service '${serviceName}' not found in juxConfig.services`);
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
fetch: (url, options) => {
|
|
363
|
+
return juxFetch(url, {
|
|
364
|
+
...options,
|
|
365
|
+
baseUrl: baseUrl || undefined
|
|
366
|
+
});
|
|
367
|
+
},
|
|
368
|
+
baseUrl
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Setup fetch from juxconfig
|
|
373
|
+
* Call this in your bootstrap function
|
|
374
|
+
*
|
|
375
|
+
* Usage:
|
|
376
|
+
* export default {
|
|
377
|
+
* bootstrap: [
|
|
378
|
+
* async function initFetch() {
|
|
379
|
+
* await jux.fetch.setupConfig();
|
|
380
|
+
* }
|
|
381
|
+
* ]
|
|
382
|
+
* };
|
|
383
|
+
*/
|
|
384
|
+
export async function setupConfig() {
|
|
385
|
+
if (typeof window === 'undefined') {
|
|
386
|
+
console.warn('[JUX Fetch] setupConfig() called outside browser environment');
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const juxConfig = window.juxConfig;
|
|
390
|
+
if (!juxConfig) {
|
|
391
|
+
console.warn('[JUX Fetch] No juxConfig found on window. Make sure your juxconfig.js is loaded.');
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const services = juxConfig.services || {};
|
|
395
|
+
if (Object.keys(services).length === 0) {
|
|
396
|
+
console.log('[JUX Fetch] No services configured in juxConfig');
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
// Configure fetch with common defaults
|
|
400
|
+
const fetchConfig = {
|
|
401
|
+
timeout: juxConfig.fetchTimeout || 30000,
|
|
402
|
+
log: juxConfig.fetchLog || false,
|
|
403
|
+
credentials: 'include'
|
|
404
|
+
};
|
|
405
|
+
// Add service-specific handlers
|
|
406
|
+
if (services.auth) {
|
|
407
|
+
fetchConfig.onUnauthorized = () => {
|
|
408
|
+
console.warn('[JUX Fetch] Unauthorized - consider redirecting to login');
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
configureFetch(fetchConfig);
|
|
412
|
+
// Log configured services
|
|
413
|
+
console.log('[JUX Fetch] Configured with services:', Object.keys(services));
|
|
414
|
+
return {
|
|
415
|
+
services,
|
|
416
|
+
getServiceUrl
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
// Export combined API
|
|
420
|
+
export const fetchAPI = Object.assign(juxFetch, {
|
|
421
|
+
config: configureFetch,
|
|
422
|
+
setupConfig,
|
|
423
|
+
getServiceUrl,
|
|
424
|
+
serviceClient,
|
|
425
|
+
...fetchHelpers,
|
|
426
|
+
all: fetchAll
|
|
427
|
+
});
|