juxscript 1.0.132 → 1.1.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.
- package/README.md +1 -32
- package/bin/cli.js +4 -2
- package/index.d.ts +200 -0
- package/index.js +96 -22
- package/juxconfig.example.js +58 -63
- package/lib/components/alert.ts +200 -0
- package/lib/components/app.ts +247 -0
- package/lib/components/badge.ts +101 -0
- package/lib/components/base/BaseComponent.ts +421 -0
- package/lib/components/base/FormInput.ts +227 -0
- package/lib/components/button.ts +178 -0
- package/lib/components/card.ts +173 -0
- package/lib/components/chart.ts +231 -0
- package/lib/components/checkbox.ts +242 -0
- package/lib/components/code.ts +123 -0
- package/lib/components/container.ts +140 -0
- package/lib/components/data.ts +135 -0
- package/lib/components/datepicker.ts +234 -0
- package/lib/components/dialog.ts +172 -0
- package/lib/components/divider.ts +100 -0
- package/lib/components/dropdown.ts +186 -0
- package/lib/components/element.ts +267 -0
- package/lib/components/fileupload.ts +309 -0
- package/lib/components/grid.ts +291 -0
- package/lib/components/guard.ts +92 -0
- package/lib/components/heading.ts +96 -0
- package/lib/components/helpers.ts +41 -0
- package/lib/components/hero.ts +224 -0
- package/lib/components/icon.ts +178 -0
- package/lib/components/icons.ts +464 -0
- package/lib/components/include.ts +410 -0
- package/lib/components/input.ts +457 -0
- package/lib/components/list.ts +419 -0
- package/lib/components/loading.ts +100 -0
- package/lib/components/menu.ts +275 -0
- package/lib/components/modal.ts +284 -0
- package/lib/components/nav.ts +257 -0
- package/lib/components/paragraph.ts +97 -0
- package/lib/components/progress.ts +159 -0
- package/lib/components/radio.ts +278 -0
- package/lib/components/req.ts +303 -0
- package/lib/components/script.ts +41 -0
- package/lib/components/select.ts +252 -0
- package/lib/components/sidebar.ts +275 -0
- package/lib/components/style.ts +41 -0
- package/lib/components/switch.ts +246 -0
- package/lib/components/table.ts +1249 -0
- package/lib/components/tabs.ts +250 -0
- package/lib/components/theme-toggle.ts +293 -0
- package/lib/components/tooltip.ts +144 -0
- package/lib/components/view.ts +190 -0
- package/lib/components/write.ts +272 -0
- package/lib/globals.d.ts +19 -5
- package/lib/layouts/default.css +260 -0
- package/lib/layouts/figma.css +334 -0
- package/lib/reactivity/state.ts +78 -0
- package/lib/utils/{fetch.js → fetch.ts} +206 -81
- package/machinery/ast.js +347 -0
- package/machinery/build.js +466 -0
- package/machinery/compiler3.js +6 -66
- package/machinery/config.js +6 -93
- package/machinery/doc-generator.js +136 -0
- package/machinery/imports.js +155 -0
- package/machinery/server.js +166 -0
- package/machinery/ts-shim.js +46 -0
- package/machinery/watcher.js +162 -50
- package/package.json +9 -30
- package/create/index.jux +0 -77
- package/create/layout.jux +0 -18
- package/create/style.css +0 -57
- package/create/themes/assets/jux.svg +0 -34
- package/create/themes/base.css +0 -197
- package/create/themes/base2.css +0 -54
- package/create/themes/layouts/base.jux +0 -16
- package/create/themes/layouts/base_marketing.jux +0 -0
- package/create/themes/layouts/base_saas.jux +0 -0
- package/lib/componentsv2/base/BaseEngine.d.ts +0 -112
- package/lib/componentsv2/base/BaseEngine.js +0 -279
- package/lib/componentsv2/base/BaseSkin.d.ts +0 -74
- package/lib/componentsv2/base/BaseSkin.js +0 -130
- package/lib/componentsv2/base/Neighborhood.d.ts +0 -22
- package/lib/componentsv2/base/Neighborhood.js +0 -56
- package/lib/componentsv2/base/OptionsContract.d.ts +0 -20
- package/lib/componentsv2/base/OptionsContract.js +0 -107
- package/lib/componentsv2/base/State.d.ts +0 -18
- package/lib/componentsv2/base/State.js +0 -68
- package/lib/componentsv2/element/Element.d.ts +0 -30
- package/lib/componentsv2/element/Element.js +0 -50
- package/lib/componentsv2/element/ElementEngine.d.ts +0 -59
- package/lib/componentsv2/element/ElementEngine.js +0 -118
- package/lib/componentsv2/element/ElementSkin.d.ts +0 -10
- package/lib/componentsv2/element/ElementSkin.js +0 -56
- package/lib/componentsv2/element/structure.css +0 -261
- package/lib/componentsv2/grid/Grid.d.ts +0 -13
- package/lib/componentsv2/grid/Grid.js +0 -27
- package/lib/componentsv2/grid/GridEngine.d.ts +0 -77
- package/lib/componentsv2/grid/GridEngine.js +0 -153
- package/lib/componentsv2/grid/GridSkin.d.ts +0 -11
- package/lib/componentsv2/grid/GridSkin.js +0 -84
- package/lib/componentsv2/grid/structure.css +0 -27
- package/lib/componentsv2/input/Input.d.ts +0 -6
- package/lib/componentsv2/input/Input.js +0 -21
- package/lib/componentsv2/input/InputEngine.d.ts +0 -70
- package/lib/componentsv2/input/InputEngine.js +0 -143
- package/lib/componentsv2/input/InputSkin.d.ts +0 -11
- package/lib/componentsv2/input/InputSkin.js +0 -89
- package/lib/componentsv2/input/structure.css +0 -47
- package/lib/componentsv2/list/List.d.ts +0 -49
- package/lib/componentsv2/list/List.js +0 -105
- package/lib/componentsv2/list/ListEngine.d.ts +0 -121
- package/lib/componentsv2/list/ListEngine.js +0 -322
- package/lib/componentsv2/list/ListSkin.d.ts +0 -20
- package/lib/componentsv2/list/ListSkin.js +0 -345
- package/lib/componentsv2/list/structure.css +0 -359
- package/lib/componentsv2/plugins/ClientSQLitePlugin.d.ts +0 -21
- package/lib/componentsv2/plugins/ClientSQLitePlugin.js +0 -130
- package/lib/componentsv2/plugins/IndexedDBPlugin.d.ts +0 -18
- package/lib/componentsv2/plugins/IndexedDBPlugin.js +0 -75
- package/lib/componentsv2/plugins/LocalStoragePlugin.d.ts +0 -20
- package/lib/componentsv2/plugins/LocalStoragePlugin.js +0 -65
- package/lib/componentsv2/plugins/ServerSQLitePlugin.d.ts +0 -25
- package/lib/componentsv2/plugins/ServerSQLitePlugin.js +0 -70
- package/lib/componentsv2/stubs/ComponentComposition.ts.stub +0 -32
- package/lib/componentsv2/stubs/ComponentEngine.ts.stub +0 -36
- package/lib/componentsv2/stubs/ComponentSkin.ts.stub +0 -35
- package/lib/componentsv2/stubs/ComponentStructure.css.d.ts.stub +0 -2
- package/lib/componentsv2/stubs/ComponentStructure.css.stub +0 -13
- package/lib/utils/fetch.d.ts +0 -176
- package/machinery/serve.js +0 -255
- package/types/css.d.ts +0 -10
- /package/{create/themes/layouts/base_blog.jux → machinery/bundleAssets.js} +0 -0
- /package/{create/themes/layouts/base_docs.jux → machinery/bundleJux.js} +0 -0
- /package/{create/themes/layouts/base_login.jux → machinery/bundleVendors.js} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Jux Fetch Utility
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* A lightweight fetch wrapper with sensible defaults, error handling, and method chaining.
|
|
5
5
|
* Includes configuration helpers for juxconfig.js integration.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Usage:
|
|
8
8
|
* // Configure once (optional)
|
|
9
9
|
* jux.fetch.config({
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* log: 'errors',
|
|
14
14
|
* onUnauthorized: () => window.location.href = '/login'
|
|
15
15
|
* });
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* // Simple GET
|
|
18
18
|
* const { data, error } = await jux.fetch('/users').send();
|
|
19
|
-
*
|
|
19
|
+
*
|
|
20
20
|
* // Method chaining
|
|
21
21
|
* const { data, error } = await jux.fetch('/users')
|
|
22
22
|
* .method('POST')
|
|
@@ -25,18 +25,55 @@
|
|
|
25
25
|
* .timeout(5000)
|
|
26
26
|
* .log(true)
|
|
27
27
|
* .send();
|
|
28
|
-
*
|
|
28
|
+
*
|
|
29
29
|
* // With juxconfig services
|
|
30
30
|
* const { data } = await jux.fetch('/users')
|
|
31
31
|
* .baseUrl(jux.fetch.getServiceUrl('database'))
|
|
32
32
|
* .send();
|
|
33
|
-
*
|
|
33
|
+
*
|
|
34
34
|
* // Service client helper
|
|
35
35
|
* const db = jux.fetch.serviceClient('database');
|
|
36
36
|
* const { data } = await db.fetch('/users').send();
|
|
37
37
|
*/
|
|
38
|
+
|
|
39
|
+
export type LogLevel = boolean | 'errors';
|
|
40
|
+
|
|
41
|
+
export interface FetchConfig {
|
|
42
|
+
baseUrl?: string;
|
|
43
|
+
credentials?: RequestCredentials;
|
|
44
|
+
headers?: Record<string, string>;
|
|
45
|
+
timeout?: number;
|
|
46
|
+
log?: LogLevel;
|
|
47
|
+
onUnauthorized?: () => void;
|
|
48
|
+
onError?: (error: FetchError) => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface FetchOptions extends Omit<RequestInit, 'body'> {
|
|
52
|
+
params?: Record<string, any>;
|
|
53
|
+
body?: any;
|
|
54
|
+
timeout?: number;
|
|
55
|
+
log?: LogLevel;
|
|
56
|
+
onUnauthorized?: () => void;
|
|
57
|
+
onError?: (error: FetchError) => void;
|
|
58
|
+
parseResponse?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface FetchError {
|
|
62
|
+
message: string;
|
|
63
|
+
status?: number;
|
|
64
|
+
statusText?: string;
|
|
65
|
+
data?: any;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface FetchResult<T = any> {
|
|
69
|
+
data: T | null;
|
|
70
|
+
error: FetchError | null;
|
|
71
|
+
status: number;
|
|
72
|
+
response: Response;
|
|
73
|
+
}
|
|
74
|
+
|
|
38
75
|
// Global configuration
|
|
39
|
-
let globalConfig = {
|
|
76
|
+
let globalConfig: FetchConfig = {
|
|
40
77
|
credentials: 'same-origin',
|
|
41
78
|
headers: {
|
|
42
79
|
'Content-Type': 'application/json'
|
|
@@ -44,10 +81,11 @@ let globalConfig = {
|
|
|
44
81
|
timeout: 30000,
|
|
45
82
|
log: false
|
|
46
83
|
};
|
|
84
|
+
|
|
47
85
|
/**
|
|
48
86
|
* Configure global fetch defaults
|
|
49
87
|
*/
|
|
50
|
-
export function configureFetch(config) {
|
|
88
|
+
export function configureFetch(config: FetchConfig): void {
|
|
51
89
|
globalConfig = {
|
|
52
90
|
...globalConfig,
|
|
53
91
|
...config,
|
|
@@ -57,64 +95,86 @@ export function configureFetch(config) {
|
|
|
57
95
|
}
|
|
58
96
|
};
|
|
59
97
|
}
|
|
98
|
+
|
|
60
99
|
/**
|
|
61
100
|
* Build URL with query parameters
|
|
62
101
|
*/
|
|
63
|
-
function buildUrl(url, params) {
|
|
102
|
+
function buildUrl(url: string, params?: Record<string, any>): string {
|
|
64
103
|
if (!params || Object.keys(params).length === 0) {
|
|
65
104
|
return url;
|
|
66
105
|
}
|
|
106
|
+
|
|
67
107
|
const searchParams = new URLSearchParams();
|
|
68
108
|
Object.entries(params).forEach(([key, value]) => {
|
|
69
109
|
if (value !== undefined && value !== null) {
|
|
70
110
|
searchParams.append(key, String(value));
|
|
71
111
|
}
|
|
72
112
|
});
|
|
113
|
+
|
|
73
114
|
const queryString = searchParams.toString();
|
|
74
|
-
if (!queryString)
|
|
75
|
-
|
|
115
|
+
if (!queryString) return url;
|
|
116
|
+
|
|
76
117
|
return url.includes('?')
|
|
77
118
|
? `${url}&${queryString}`
|
|
78
119
|
: `${url}?${queryString}`;
|
|
79
120
|
}
|
|
121
|
+
|
|
80
122
|
/**
|
|
81
123
|
* Main fetch function
|
|
82
124
|
*/
|
|
83
|
-
async function executeFetch
|
|
84
|
-
|
|
125
|
+
async function executeFetch<T = any>(
|
|
126
|
+
url: string,
|
|
127
|
+
options: FetchOptions = {}
|
|
128
|
+
): Promise<FetchResult<T>> {
|
|
129
|
+
const {
|
|
130
|
+
params,
|
|
131
|
+
body,
|
|
132
|
+
timeout = globalConfig.timeout,
|
|
133
|
+
log = globalConfig.log,
|
|
134
|
+
onUnauthorized = globalConfig.onUnauthorized,
|
|
135
|
+
onError = globalConfig.onError,
|
|
136
|
+
parseResponse = true,
|
|
137
|
+
headers = {},
|
|
138
|
+
...fetchOptions
|
|
139
|
+
} = options;
|
|
140
|
+
|
|
85
141
|
// Build full URL
|
|
86
142
|
let fullUrl = url;
|
|
143
|
+
|
|
87
144
|
// Add base URL if configured and URL is relative
|
|
88
145
|
if (globalConfig.baseUrl && !url.startsWith('http://') && !url.startsWith('https://')) {
|
|
89
146
|
fullUrl = `${globalConfig.baseUrl}${url.startsWith('/') ? url : `/${url}`}`;
|
|
90
147
|
}
|
|
148
|
+
|
|
91
149
|
// Add query params
|
|
92
150
|
fullUrl = buildUrl(fullUrl, params);
|
|
151
|
+
|
|
93
152
|
// Merge headers
|
|
94
153
|
const mergedHeaders = {
|
|
95
154
|
...globalConfig.headers,
|
|
96
155
|
...headers
|
|
97
156
|
};
|
|
157
|
+
|
|
98
158
|
// Prepare request init
|
|
99
|
-
const requestInit = {
|
|
159
|
+
const requestInit: RequestInit = {
|
|
100
160
|
...fetchOptions,
|
|
101
161
|
headers: mergedHeaders,
|
|
102
162
|
credentials: options.credentials ?? globalConfig.credentials
|
|
103
163
|
};
|
|
164
|
+
|
|
104
165
|
// Stringify body if it's an object
|
|
105
166
|
if (body !== undefined) {
|
|
106
167
|
if (body instanceof FormData) {
|
|
107
168
|
requestInit.body = body;
|
|
108
169
|
// Remove Content-Type header for FormData (browser sets it with boundary)
|
|
109
|
-
delete requestInit.headers['Content-Type'];
|
|
110
|
-
}
|
|
111
|
-
else if (typeof body === 'object') {
|
|
170
|
+
delete (requestInit.headers as Record<string, string>)['Content-Type'];
|
|
171
|
+
} else if (typeof body === 'object') {
|
|
112
172
|
requestInit.body = JSON.stringify(body);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
173
|
+
} else {
|
|
115
174
|
requestInit.body = body;
|
|
116
175
|
}
|
|
117
176
|
}
|
|
177
|
+
|
|
118
178
|
// Log request
|
|
119
179
|
if (log === true) {
|
|
120
180
|
console.log(`[JUX Fetch] ${requestInit.method || 'GET'} ${fullUrl}`, {
|
|
@@ -123,66 +183,73 @@ async function executeFetch(url, options = {}) {
|
|
|
123
183
|
params
|
|
124
184
|
});
|
|
125
185
|
}
|
|
186
|
+
|
|
126
187
|
// Setup timeout
|
|
127
188
|
const controller = new AbortController();
|
|
128
189
|
const timeoutId = timeout ? setTimeout(() => controller.abort(), timeout) : null;
|
|
190
|
+
|
|
129
191
|
if (!requestInit.signal) {
|
|
130
192
|
requestInit.signal = controller.signal;
|
|
131
193
|
}
|
|
194
|
+
|
|
132
195
|
try {
|
|
133
196
|
const response = await fetch(fullUrl, requestInit);
|
|
134
|
-
|
|
135
|
-
|
|
197
|
+
|
|
198
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
199
|
+
|
|
136
200
|
// Handle unauthorized
|
|
137
201
|
if (response.status === 401 || response.status === 403) {
|
|
138
202
|
if (onUnauthorized) {
|
|
139
203
|
onUnauthorized();
|
|
140
204
|
}
|
|
141
205
|
}
|
|
206
|
+
|
|
142
207
|
// Parse response
|
|
143
|
-
let data = null;
|
|
144
|
-
let errorData = null;
|
|
208
|
+
let data: T | null = null;
|
|
209
|
+
let errorData: any = null;
|
|
210
|
+
|
|
145
211
|
if (parseResponse) {
|
|
146
212
|
const contentType = response.headers.get('content-type');
|
|
213
|
+
|
|
147
214
|
if (contentType?.includes('application/json')) {
|
|
148
215
|
try {
|
|
149
216
|
const json = await response.json();
|
|
150
217
|
if (response.ok) {
|
|
151
218
|
data = json;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
219
|
+
} else {
|
|
154
220
|
errorData = json;
|
|
155
221
|
}
|
|
156
|
-
}
|
|
157
|
-
catch (e) {
|
|
222
|
+
} catch (e) {
|
|
158
223
|
// JSON parse error
|
|
159
224
|
}
|
|
160
|
-
}
|
|
161
|
-
else if (response.ok) {
|
|
225
|
+
} else if (response.ok) {
|
|
162
226
|
// Non-JSON response, try to get text
|
|
163
227
|
try {
|
|
164
|
-
data = (await response.text());
|
|
165
|
-
}
|
|
166
|
-
catch (e) {
|
|
228
|
+
data = (await response.text()) as any;
|
|
229
|
+
} catch (e) {
|
|
167
230
|
// Ignore text parse errors
|
|
168
231
|
}
|
|
169
232
|
}
|
|
170
233
|
}
|
|
234
|
+
|
|
171
235
|
// Check if request was successful
|
|
172
236
|
if (!response.ok) {
|
|
173
|
-
const error = {
|
|
237
|
+
const error: FetchError = {
|
|
174
238
|
message: errorData?.message || errorData?.error || response.statusText || 'Request failed',
|
|
175
239
|
status: response.status,
|
|
176
240
|
statusText: response.statusText,
|
|
177
241
|
data: errorData
|
|
178
242
|
};
|
|
243
|
+
|
|
179
244
|
// Log error
|
|
180
245
|
if (log === true || log === 'errors') {
|
|
181
246
|
console.error(`[JUX Fetch Error] ${requestInit.method || 'GET'} ${fullUrl}`, error);
|
|
182
247
|
}
|
|
248
|
+
|
|
183
249
|
if (onError) {
|
|
184
250
|
onError(error);
|
|
185
251
|
}
|
|
252
|
+
|
|
186
253
|
return {
|
|
187
254
|
data: null,
|
|
188
255
|
error,
|
|
@@ -190,6 +257,7 @@ async function executeFetch(url, options = {}) {
|
|
|
190
257
|
response
|
|
191
258
|
};
|
|
192
259
|
}
|
|
260
|
+
|
|
193
261
|
// Log success
|
|
194
262
|
if (log === true) {
|
|
195
263
|
console.log(`[JUX Fetch Success] ${requestInit.method || 'GET'} ${fullUrl}`, {
|
|
@@ -197,169 +265,216 @@ async function executeFetch(url, options = {}) {
|
|
|
197
265
|
data
|
|
198
266
|
});
|
|
199
267
|
}
|
|
268
|
+
|
|
200
269
|
return {
|
|
201
270
|
data,
|
|
202
271
|
error: null,
|
|
203
272
|
status: response.status,
|
|
204
273
|
response
|
|
205
274
|
};
|
|
206
|
-
|
|
207
|
-
catch (err) {
|
|
208
|
-
if (timeoutId)
|
|
209
|
-
|
|
210
|
-
const error = {
|
|
275
|
+
|
|
276
|
+
} catch (err: any) {
|
|
277
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
278
|
+
|
|
279
|
+
const error: FetchError = {
|
|
211
280
|
message: err.name === 'AbortError'
|
|
212
281
|
? 'Request timeout'
|
|
213
282
|
: err.message || 'Network error',
|
|
214
283
|
status: 0
|
|
215
284
|
};
|
|
285
|
+
|
|
216
286
|
// Log error
|
|
217
287
|
if (log === true || log === 'errors') {
|
|
218
288
|
console.error(`[JUX Fetch Error] ${requestInit.method || 'GET'} ${fullUrl}`, error);
|
|
219
289
|
}
|
|
290
|
+
|
|
220
291
|
if (onError) {
|
|
221
292
|
onError(error);
|
|
222
293
|
}
|
|
294
|
+
|
|
223
295
|
return {
|
|
224
296
|
data: null,
|
|
225
297
|
error,
|
|
226
298
|
status: 0,
|
|
227
|
-
response: null
|
|
299
|
+
response: null as any
|
|
228
300
|
};
|
|
229
301
|
}
|
|
230
302
|
}
|
|
303
|
+
|
|
231
304
|
/**
|
|
232
305
|
* FetchBuilder class for method chaining
|
|
233
306
|
*/
|
|
234
|
-
class FetchBuilder {
|
|
235
|
-
|
|
236
|
-
|
|
307
|
+
class FetchBuilder<T = any> {
|
|
308
|
+
public url: string;
|
|
309
|
+
public options: FetchOptions = {};
|
|
310
|
+
|
|
311
|
+
constructor(url: string, options: FetchOptions = {}) {
|
|
237
312
|
this.url = url;
|
|
238
313
|
this.options = options;
|
|
239
314
|
}
|
|
240
|
-
|
|
315
|
+
|
|
316
|
+
method(value: string): this {
|
|
241
317
|
this.options.method = value;
|
|
242
318
|
return this;
|
|
243
319
|
}
|
|
244
|
-
|
|
320
|
+
|
|
321
|
+
body(value: any): this {
|
|
245
322
|
this.options.body = value;
|
|
246
323
|
return this;
|
|
247
324
|
}
|
|
248
|
-
|
|
325
|
+
|
|
326
|
+
params(value: Record<string, any>): this {
|
|
249
327
|
this.options.params = value;
|
|
250
328
|
return this;
|
|
251
329
|
}
|
|
252
|
-
|
|
330
|
+
|
|
331
|
+
headers(value: Record<string, string>): this {
|
|
253
332
|
this.options.headers = { ...this.options.headers, ...value };
|
|
254
333
|
return this;
|
|
255
334
|
}
|
|
256
|
-
|
|
335
|
+
|
|
336
|
+
header(key: string, value: string): this {
|
|
257
337
|
this.options.headers = { ...this.options.headers, [key]: value };
|
|
258
338
|
return this;
|
|
259
339
|
}
|
|
260
|
-
|
|
340
|
+
|
|
341
|
+
timeout(value: number): this {
|
|
261
342
|
this.options.timeout = value;
|
|
262
343
|
return this;
|
|
263
344
|
}
|
|
264
|
-
|
|
345
|
+
|
|
346
|
+
credentials(value: RequestCredentials): this {
|
|
265
347
|
this.options.credentials = value;
|
|
266
348
|
return this;
|
|
267
349
|
}
|
|
268
|
-
|
|
350
|
+
|
|
351
|
+
log(value: LogLevel): this {
|
|
269
352
|
this.options.log = value;
|
|
270
353
|
return this;
|
|
271
354
|
}
|
|
272
|
-
|
|
355
|
+
|
|
356
|
+
parseResponse(value: boolean): this {
|
|
273
357
|
this.options.parseResponse = value;
|
|
274
358
|
return this;
|
|
275
359
|
}
|
|
276
|
-
|
|
360
|
+
|
|
361
|
+
onUnauthorized(callback: () => void): this {
|
|
277
362
|
this.options.onUnauthorized = callback;
|
|
278
363
|
return this;
|
|
279
364
|
}
|
|
280
|
-
|
|
365
|
+
|
|
366
|
+
onError(callback: (error: FetchError) => void): this {
|
|
281
367
|
this.options.onError = callback;
|
|
282
368
|
return this;
|
|
283
369
|
}
|
|
370
|
+
|
|
284
371
|
/**
|
|
285
372
|
* Execute the fetch request
|
|
286
373
|
*/
|
|
287
|
-
send() {
|
|
288
|
-
return executeFetch(this.url, this.options);
|
|
374
|
+
send(): Promise<FetchResult<T>> {
|
|
375
|
+
return executeFetch<T>(this.url, this.options);
|
|
289
376
|
}
|
|
377
|
+
|
|
290
378
|
/**
|
|
291
379
|
* Alias for send()
|
|
292
380
|
*/
|
|
293
|
-
fetch() {
|
|
381
|
+
fetch(): Promise<FetchResult<T>> {
|
|
294
382
|
return this.send();
|
|
295
383
|
}
|
|
384
|
+
|
|
296
385
|
/**
|
|
297
386
|
* Make the builder thenable (Promise-like) so it can be awaited directly
|
|
298
387
|
* This allows: await jux.fetch('/users') without needing .send()
|
|
299
388
|
*/
|
|
300
|
-
then
|
|
389
|
+
then<TResult1 = FetchResult<T>, TResult2 = never>(
|
|
390
|
+
onfulfilled?: ((value: FetchResult<T>) => TResult1 | PromiseLike<TResult1>) | null,
|
|
391
|
+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
|
392
|
+
): Promise<TResult1 | TResult2> {
|
|
301
393
|
return this.send().then(onfulfilled, onrejected);
|
|
302
394
|
}
|
|
395
|
+
|
|
303
396
|
/**
|
|
304
397
|
* Make the builder catchable for Promise.catch()
|
|
305
398
|
*/
|
|
306
|
-
catch(
|
|
399
|
+
catch<TResult = never>(
|
|
400
|
+
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
|
401
|
+
): Promise<FetchResult<T> | TResult> {
|
|
307
402
|
return this.send().catch(onrejected);
|
|
308
403
|
}
|
|
404
|
+
|
|
309
405
|
/**
|
|
310
406
|
* Make the builder finally-able for Promise.finally()
|
|
311
407
|
*/
|
|
312
|
-
finally(onfinally) {
|
|
408
|
+
finally(onfinally?: (() => void) | null): Promise<FetchResult<T>> {
|
|
313
409
|
return this.send().finally(onfinally);
|
|
314
410
|
}
|
|
315
411
|
}
|
|
412
|
+
|
|
316
413
|
/**
|
|
317
414
|
* Create a fetch builder
|
|
318
415
|
*/
|
|
319
|
-
export function juxFetch(url, options = {}) {
|
|
320
|
-
return new FetchBuilder(url, options);
|
|
416
|
+
export function juxFetch<T = any>(url: string, options: FetchOptions = {}): FetchBuilder<T> {
|
|
417
|
+
return new FetchBuilder<T>(url, options);
|
|
321
418
|
}
|
|
419
|
+
|
|
322
420
|
/**
|
|
323
421
|
* Convenience methods for common HTTP verbs
|
|
324
422
|
*/
|
|
325
423
|
export const fetchHelpers = {
|
|
326
|
-
get:
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
424
|
+
get: <T = any>(url: string, options?: Omit<FetchOptions, 'method'>) =>
|
|
425
|
+
new FetchBuilder<T>(url, { ...options, method: 'GET' }),
|
|
426
|
+
|
|
427
|
+
post: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, 'method' | 'body'>) =>
|
|
428
|
+
new FetchBuilder<T>(url, { ...options, method: 'POST', body }),
|
|
429
|
+
|
|
430
|
+
put: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, 'method' | 'body'>) =>
|
|
431
|
+
new FetchBuilder<T>(url, { ...options, method: 'PUT', body }),
|
|
432
|
+
|
|
433
|
+
patch: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, 'method' | 'body'>) =>
|
|
434
|
+
new FetchBuilder<T>(url, { ...options, method: 'PATCH', body }),
|
|
435
|
+
|
|
436
|
+
delete: <T = any>(url: string, options?: Omit<FetchOptions, 'method'>) =>
|
|
437
|
+
new FetchBuilder<T>(url, { ...options, method: 'DELETE' })
|
|
331
438
|
};
|
|
439
|
+
|
|
332
440
|
/**
|
|
333
441
|
* Fetch multiple URLs in parallel
|
|
334
442
|
*/
|
|
335
|
-
export async function fetchAll
|
|
336
|
-
|
|
443
|
+
export async function fetchAll<T = any>(
|
|
444
|
+
urls: string[],
|
|
445
|
+
options?: FetchOptions
|
|
446
|
+
): Promise<FetchResult<T>[]> {
|
|
447
|
+
return Promise.all(urls.map(url => executeFetch<T>(url, options)));
|
|
337
448
|
}
|
|
449
|
+
|
|
338
450
|
/**
|
|
339
451
|
* Get a service URL from window.juxConfig
|
|
340
452
|
*/
|
|
341
|
-
export function getServiceUrl(serviceName) {
|
|
342
|
-
if (typeof window === 'undefined')
|
|
343
|
-
|
|
344
|
-
const juxConfig = window.juxConfig;
|
|
345
|
-
if (!juxConfig?.services)
|
|
346
|
-
|
|
453
|
+
export function getServiceUrl(serviceName: string): string | null {
|
|
454
|
+
if (typeof window === 'undefined') return null;
|
|
455
|
+
|
|
456
|
+
const juxConfig = (window as any).juxConfig;
|
|
457
|
+
if (!juxConfig?.services) return null;
|
|
458
|
+
|
|
347
459
|
return juxConfig.services[serviceName] || null;
|
|
348
460
|
}
|
|
461
|
+
|
|
349
462
|
/**
|
|
350
463
|
* Create a fetch instance preconfigured for a specific service
|
|
351
|
-
*
|
|
464
|
+
*
|
|
352
465
|
* Usage:
|
|
353
466
|
* const api = jux.fetch.serviceClient('database');
|
|
354
467
|
* const { data } = await api.fetch('/users').send();
|
|
355
468
|
*/
|
|
356
|
-
export function serviceClient(serviceName) {
|
|
469
|
+
export function serviceClient(serviceName: string) {
|
|
357
470
|
const baseUrl = getServiceUrl(serviceName);
|
|
471
|
+
|
|
358
472
|
if (!baseUrl) {
|
|
359
473
|
console.warn(`[JUX Fetch] Service '${serviceName}' not found in juxConfig.services`);
|
|
360
474
|
}
|
|
475
|
+
|
|
361
476
|
return {
|
|
362
|
-
fetch: (url, options) => {
|
|
477
|
+
fetch: (url: string, options?: any) => {
|
|
363
478
|
return juxFetch(url, {
|
|
364
479
|
...options,
|
|
365
480
|
baseUrl: baseUrl || undefined
|
|
@@ -368,10 +483,11 @@ export function serviceClient(serviceName) {
|
|
|
368
483
|
baseUrl
|
|
369
484
|
};
|
|
370
485
|
}
|
|
486
|
+
|
|
371
487
|
/**
|
|
372
488
|
* Setup fetch from juxconfig
|
|
373
489
|
* Call this in your bootstrap function
|
|
374
|
-
*
|
|
490
|
+
*
|
|
375
491
|
* Usage:
|
|
376
492
|
* export default {
|
|
377
493
|
* bootstrap: [
|
|
@@ -386,36 +502,46 @@ export async function setupConfig() {
|
|
|
386
502
|
console.warn('[JUX Fetch] setupConfig() called outside browser environment');
|
|
387
503
|
return;
|
|
388
504
|
}
|
|
389
|
-
|
|
505
|
+
|
|
506
|
+
const juxConfig = (window as any).juxConfig;
|
|
507
|
+
|
|
390
508
|
if (!juxConfig) {
|
|
391
509
|
console.warn('[JUX Fetch] No juxConfig found on window. Make sure your juxconfig.js is loaded.');
|
|
392
510
|
return;
|
|
393
511
|
}
|
|
512
|
+
|
|
394
513
|
const services = juxConfig.services || {};
|
|
514
|
+
|
|
395
515
|
if (Object.keys(services).length === 0) {
|
|
396
516
|
console.log('[JUX Fetch] No services configured in juxConfig');
|
|
397
517
|
return;
|
|
398
518
|
}
|
|
519
|
+
|
|
399
520
|
// Configure fetch with common defaults
|
|
400
|
-
const fetchConfig = {
|
|
521
|
+
const fetchConfig: FetchConfig = {
|
|
401
522
|
timeout: juxConfig.fetchTimeout || 30000,
|
|
402
523
|
log: juxConfig.fetchLog || false,
|
|
403
524
|
credentials: 'include'
|
|
404
525
|
};
|
|
526
|
+
|
|
405
527
|
// Add service-specific handlers
|
|
406
528
|
if (services.auth) {
|
|
407
529
|
fetchConfig.onUnauthorized = () => {
|
|
408
530
|
console.warn('[JUX Fetch] Unauthorized - consider redirecting to login');
|
|
409
531
|
};
|
|
410
532
|
}
|
|
533
|
+
|
|
411
534
|
configureFetch(fetchConfig);
|
|
535
|
+
|
|
412
536
|
// Log configured services
|
|
413
537
|
console.log('[JUX Fetch] Configured with services:', Object.keys(services));
|
|
538
|
+
|
|
414
539
|
return {
|
|
415
540
|
services,
|
|
416
541
|
getServiceUrl
|
|
417
542
|
};
|
|
418
543
|
}
|
|
544
|
+
|
|
419
545
|
// Export combined API
|
|
420
546
|
export const fetchAPI = Object.assign(juxFetch, {
|
|
421
547
|
config: configureFetch,
|
|
@@ -425,4 +551,3 @@ export const fetchAPI = Object.assign(juxFetch, {
|
|
|
425
551
|
...fetchHelpers,
|
|
426
552
|
all: fetchAll
|
|
427
553
|
});
|
|
428
|
-
//# sourceMappingURL=fetch.js.map
|