create-aziz-app 3.1.1 → 3.1.3
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 +658 -207
- package/bin/create-aziz-app.js +302 -351
- package/package.json +1 -1
- package/template/README.md +14 -279
- package/template/_framework/api.js +219 -219
- package/template/_framework/boot.js +33 -33
- package/template/_framework/hooks.js +367 -291
- package/template/_framework/next-response.js +128 -128
- package/template/_framework/route-match.js +145 -145
- package/template/_framework/router.js +465 -259
- package/template/_framework/runtime.js +264 -264
- package/template/app/layout.js +3 -5
- package/template/app/page.js +9 -32
- package/template/docs/01-getting-started.md +151 -151
- package/template/docs/02-project-structure.md +109 -109
- package/template/docs/03-pages-and-layouts.md +140 -140
- package/template/docs/04-routing.md +120 -120
- package/template/docs/05-hooks.md +169 -169
- package/template/docs/06-api-routes.md +210 -210
- package/template/docs/07-api-client.md +151 -151
- package/template/docs/08-styling.md +94 -94
- package/template/docs/09-imports-and-modules.md +97 -97
- package/template/docs/10-database-and-models.md +154 -154
- package/template/docs/11-authentication.md +171 -171
- package/template/docs/12-production-and-deployment.md +121 -121
- package/template/docs/13-internals.md +179 -179
- package/template/docs/README.md +67 -67
- package/template/index.html +20 -20
- package/template/package.json +16 -16
- package/template/scripts/dev-server.js +493 -381
- package/template/scripts/lib/api-router.js +525 -525
- package/template/scripts/lib/js-transform.js +213 -141
- package/template/scripts/lib/module-resolver.js +132 -132
|
@@ -1,219 +1,219 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Aziz.js API Client
|
|
3
|
-
// A tiny, dependency-free fetch wrapper for talking to
|
|
4
|
-
// /api/** route handlers (or any REST backend).
|
|
5
|
-
//
|
|
6
|
-
// const users = await api.get('/api/users');
|
|
7
|
-
// const created = await api.post('/api/users', { name: 'A' });
|
|
8
|
-
// await api.put('/api/users?id=1', { name: 'B' });
|
|
9
|
-
// await api.delete('/api/users?id=1');
|
|
10
|
-
//
|
|
11
|
-
// Features:
|
|
12
|
-
// - baseURL + default headers
|
|
13
|
-
// - automatic JSON encode / decode
|
|
14
|
-
// - request timeouts (AbortController)
|
|
15
|
-
// - external AbortSignal support
|
|
16
|
-
// - retries with backoff for 5xx / network errors
|
|
17
|
-
// - typed ApiError with { status, data }
|
|
18
|
-
// - query string helper
|
|
19
|
-
// ============================================================
|
|
20
|
-
|
|
21
|
-
export class ApiError extends Error {
|
|
22
|
-
constructor(message, { status = 0, data = null, url = null } = {}) {
|
|
23
|
-
super(message);
|
|
24
|
-
this.name = 'ApiError';
|
|
25
|
-
this.status = status;
|
|
26
|
-
this.data = data;
|
|
27
|
-
this.url = url;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const defaults = {
|
|
32
|
-
baseURL: '',
|
|
33
|
-
timeout: 15000,
|
|
34
|
-
retries: 0,
|
|
35
|
-
headers: {},
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
function buildURL(path, query) {
|
|
39
|
-
let url = /^https?:\/\//i.test(path)
|
|
40
|
-
? path
|
|
41
|
-
: defaults.baseURL
|
|
42
|
-
? defaults.baseURL.replace(/\/+$/, '') + (path.startsWith('/') ? path : '/' + path)
|
|
43
|
-
: path;
|
|
44
|
-
|
|
45
|
-
if (query && typeof query === 'object') {
|
|
46
|
-
const qs = new URLSearchParams();
|
|
47
|
-
for (const [key, value] of Object.entries(query)) {
|
|
48
|
-
if (value === undefined || value === null) continue;
|
|
49
|
-
if (Array.isArray(value)) value.forEach(v => qs.append(key, v));
|
|
50
|
-
else qs.append(key, value);
|
|
51
|
-
}
|
|
52
|
-
const s = qs.toString();
|
|
53
|
-
if (s) url += (url.includes('?') ? '&' : '?') + s;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return url;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function sleep(ms) {
|
|
60
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function parseResponse(res, raw) {
|
|
64
|
-
if (raw) return res;
|
|
65
|
-
|
|
66
|
-
const contentType = (res.headers.get('content-type') || '').toLowerCase();
|
|
67
|
-
if (res.status === 204 || res.status === 205) return null;
|
|
68
|
-
|
|
69
|
-
if (contentType.includes('application/json')) {
|
|
70
|
-
return res.json().catch(() => null);
|
|
71
|
-
}
|
|
72
|
-
if (contentType.startsWith('text/') || contentType.includes('html') || contentType.includes('xml')) {
|
|
73
|
-
return res.text();
|
|
74
|
-
}
|
|
75
|
-
return res.blob();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function extractMessage(data, status) {
|
|
79
|
-
if (data && typeof data === 'object') {
|
|
80
|
-
const raw = data.error ?? data.message ?? data.detail;
|
|
81
|
-
if (typeof raw === 'string') return raw;
|
|
82
|
-
if (raw && typeof raw === 'object') return raw.message || JSON.stringify(raw);
|
|
83
|
-
}
|
|
84
|
-
if (typeof data === 'string' && data.trim()) return data.trim().slice(0, 200);
|
|
85
|
-
return `Request failed with status ${status}`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function request(path, options = {}) {
|
|
89
|
-
const {
|
|
90
|
-
method = 'GET',
|
|
91
|
-
body,
|
|
92
|
-
headers = {},
|
|
93
|
-
query,
|
|
94
|
-
timeout = defaults.timeout,
|
|
95
|
-
retries = defaults.retries,
|
|
96
|
-
signal,
|
|
97
|
-
raw = false,
|
|
98
|
-
} = options;
|
|
99
|
-
|
|
100
|
-
const url = buildURL(path, query);
|
|
101
|
-
|
|
102
|
-
const finalHeaders = { 'Accept': 'application/json', ...defaults.headers, ...headers };
|
|
103
|
-
let payload = body;
|
|
104
|
-
|
|
105
|
-
const isFormData = typeof FormData !== 'undefined' && body instanceof FormData;
|
|
106
|
-
const isBlob = typeof Blob !== 'undefined' && body instanceof Blob;
|
|
107
|
-
|
|
108
|
-
if (body !== undefined && body !== null && !isFormData && !isBlob && typeof body !== 'string') {
|
|
109
|
-
payload = JSON.stringify(body);
|
|
110
|
-
if (!finalHeaders['Content-Type']) finalHeaders['Content-Type'] = 'application/json';
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let lastError;
|
|
114
|
-
|
|
115
|
-
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
116
|
-
const controller = new AbortController();
|
|
117
|
-
let timedOut = false;
|
|
118
|
-
|
|
119
|
-
const timer = timeout > 0
|
|
120
|
-
? setTimeout(() => { timedOut = true; controller.abort(); }, timeout)
|
|
121
|
-
: null;
|
|
122
|
-
|
|
123
|
-
const onExternalAbort = () => controller.abort();
|
|
124
|
-
if (signal) {
|
|
125
|
-
if (signal.aborted) controller.abort();
|
|
126
|
-
else signal.addEventListener('abort', onExternalAbort, { once: true });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
const res = await fetch(url, {
|
|
131
|
-
method,
|
|
132
|
-
headers: finalHeaders,
|
|
133
|
-
body: payload,
|
|
134
|
-
signal: controller.signal,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const data = await parseResponse(res, raw);
|
|
138
|
-
|
|
139
|
-
if (!res.ok) {
|
|
140
|
-
const err = new ApiError(extractMessage(data, res.status), {
|
|
141
|
-
status: res.status,
|
|
142
|
-
data: raw ? null : data,
|
|
143
|
-
url,
|
|
144
|
-
});
|
|
145
|
-
// Only retry server errors / rate limits
|
|
146
|
-
if (res.status >= 500 || res.status === 429) {
|
|
147
|
-
lastError = err;
|
|
148
|
-
} else {
|
|
149
|
-
throw err;
|
|
150
|
-
}
|
|
151
|
-
} else {
|
|
152
|
-
return data;
|
|
153
|
-
}
|
|
154
|
-
} catch (err) {
|
|
155
|
-
if (err instanceof ApiError && !(err.status >= 500 || err.status === 429)) {
|
|
156
|
-
throw err; // client error — never retry
|
|
157
|
-
}
|
|
158
|
-
if (err.name === 'AbortError') {
|
|
159
|
-
if (signal && signal.aborted) throw err; // caller aborted
|
|
160
|
-
lastError = new ApiError(
|
|
161
|
-
timedOut ? `Request timed out after ${timeout}ms` : 'Request aborted',
|
|
162
|
-
{ status: 0, url }
|
|
163
|
-
);
|
|
164
|
-
} else if (err instanceof ApiError) {
|
|
165
|
-
lastError = err;
|
|
166
|
-
} else {
|
|
167
|
-
lastError = new ApiError(err.message || 'Network error', { status: 0, url });
|
|
168
|
-
}
|
|
169
|
-
} finally {
|
|
170
|
-
if (timer) clearTimeout(timer);
|
|
171
|
-
if (signal) signal.removeEventListener('abort', onExternalAbort);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (attempt < retries) {
|
|
175
|
-
await sleep(200 * Math.pow(2, attempt)); // 200ms, 400ms, 800ms…
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
throw lastError || new ApiError('Request failed', { status: 0, url });
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export const api = {
|
|
183
|
-
ApiError,
|
|
184
|
-
|
|
185
|
-
/** Set a base URL applied to every relative path. */
|
|
186
|
-
setBaseURL(baseURL) { defaults.baseURL = baseURL || ''; return api; },
|
|
187
|
-
|
|
188
|
-
/** Merge default headers (e.g. Authorization). */
|
|
189
|
-
setHeaders(headers) { Object.assign(defaults.headers, headers || {}); return api; },
|
|
190
|
-
|
|
191
|
-
/** Configure timeout / retries / baseURL / headers at once. */
|
|
192
|
-
configure(opts = {}) {
|
|
193
|
-
if ('baseURL' in opts) defaults.baseURL = opts.baseURL || '';
|
|
194
|
-
if ('timeout' in opts) defaults.timeout = opts.timeout;
|
|
195
|
-
if ('retries' in opts) defaults.retries = opts.retries;
|
|
196
|
-
if ('headers' in opts) Object.assign(defaults.headers, opts.headers || {});
|
|
197
|
-
return api;
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
get defaults() { return { ...defaults, headers: { ...defaults.headers } }; },
|
|
201
|
-
|
|
202
|
-
request,
|
|
203
|
-
|
|
204
|
-
get: (path, options) => request(path, { ...options, method: 'GET' }),
|
|
205
|
-
post: (path, body, options) => request(path, { ...options, method: 'POST', body }),
|
|
206
|
-
put: (path, body, options) => request(path, { ...options, method: 'PUT', body }),
|
|
207
|
-
patch: (path, body, options) => request(path, { ...options, method: 'PATCH', body }),
|
|
208
|
-
delete: (path, options) => request(path, { ...options, method: 'DELETE' }),
|
|
209
|
-
del: (path, options) => request(path, { ...options, method: 'DELETE' }),
|
|
210
|
-
head: (path, options) => request(path, { ...options, method: 'HEAD', raw: true }),
|
|
211
|
-
|
|
212
|
-
/** Send multipart/form-data. */
|
|
213
|
-
form: (path, formData, options) => request(path, { ...options, method: 'POST', body: formData }),
|
|
214
|
-
|
|
215
|
-
/** Low-level: return the raw Response instead of parsed data. */
|
|
216
|
-
raw: (path, options) => request(path, { ...options, raw: true }),
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
export default api;
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Aziz.js API Client
|
|
3
|
+
// A tiny, dependency-free fetch wrapper for talking to
|
|
4
|
+
// /api/** route handlers (or any REST backend).
|
|
5
|
+
//
|
|
6
|
+
// const users = await api.get('/api/users');
|
|
7
|
+
// const created = await api.post('/api/users', { name: 'A' });
|
|
8
|
+
// await api.put('/api/users?id=1', { name: 'B' });
|
|
9
|
+
// await api.delete('/api/users?id=1');
|
|
10
|
+
//
|
|
11
|
+
// Features:
|
|
12
|
+
// - baseURL + default headers
|
|
13
|
+
// - automatic JSON encode / decode
|
|
14
|
+
// - request timeouts (AbortController)
|
|
15
|
+
// - external AbortSignal support
|
|
16
|
+
// - retries with backoff for 5xx / network errors
|
|
17
|
+
// - typed ApiError with { status, data }
|
|
18
|
+
// - query string helper
|
|
19
|
+
// ============================================================
|
|
20
|
+
|
|
21
|
+
export class ApiError extends Error {
|
|
22
|
+
constructor(message, { status = 0, data = null, url = null } = {}) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'ApiError';
|
|
25
|
+
this.status = status;
|
|
26
|
+
this.data = data;
|
|
27
|
+
this.url = url;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const defaults = {
|
|
32
|
+
baseURL: '',
|
|
33
|
+
timeout: 15000,
|
|
34
|
+
retries: 0,
|
|
35
|
+
headers: {},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function buildURL(path, query) {
|
|
39
|
+
let url = /^https?:\/\//i.test(path)
|
|
40
|
+
? path
|
|
41
|
+
: defaults.baseURL
|
|
42
|
+
? defaults.baseURL.replace(/\/+$/, '') + (path.startsWith('/') ? path : '/' + path)
|
|
43
|
+
: path;
|
|
44
|
+
|
|
45
|
+
if (query && typeof query === 'object') {
|
|
46
|
+
const qs = new URLSearchParams();
|
|
47
|
+
for (const [key, value] of Object.entries(query)) {
|
|
48
|
+
if (value === undefined || value === null) continue;
|
|
49
|
+
if (Array.isArray(value)) value.forEach(v => qs.append(key, v));
|
|
50
|
+
else qs.append(key, value);
|
|
51
|
+
}
|
|
52
|
+
const s = qs.toString();
|
|
53
|
+
if (s) url += (url.includes('?') ? '&' : '?') + s;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return url;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function sleep(ms) {
|
|
60
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function parseResponse(res, raw) {
|
|
64
|
+
if (raw) return res;
|
|
65
|
+
|
|
66
|
+
const contentType = (res.headers.get('content-type') || '').toLowerCase();
|
|
67
|
+
if (res.status === 204 || res.status === 205) return null;
|
|
68
|
+
|
|
69
|
+
if (contentType.includes('application/json')) {
|
|
70
|
+
return res.json().catch(() => null);
|
|
71
|
+
}
|
|
72
|
+
if (contentType.startsWith('text/') || contentType.includes('html') || contentType.includes('xml')) {
|
|
73
|
+
return res.text();
|
|
74
|
+
}
|
|
75
|
+
return res.blob();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function extractMessage(data, status) {
|
|
79
|
+
if (data && typeof data === 'object') {
|
|
80
|
+
const raw = data.error ?? data.message ?? data.detail;
|
|
81
|
+
if (typeof raw === 'string') return raw;
|
|
82
|
+
if (raw && typeof raw === 'object') return raw.message || JSON.stringify(raw);
|
|
83
|
+
}
|
|
84
|
+
if (typeof data === 'string' && data.trim()) return data.trim().slice(0, 200);
|
|
85
|
+
return `Request failed with status ${status}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function request(path, options = {}) {
|
|
89
|
+
const {
|
|
90
|
+
method = 'GET',
|
|
91
|
+
body,
|
|
92
|
+
headers = {},
|
|
93
|
+
query,
|
|
94
|
+
timeout = defaults.timeout,
|
|
95
|
+
retries = defaults.retries,
|
|
96
|
+
signal,
|
|
97
|
+
raw = false,
|
|
98
|
+
} = options;
|
|
99
|
+
|
|
100
|
+
const url = buildURL(path, query);
|
|
101
|
+
|
|
102
|
+
const finalHeaders = { 'Accept': 'application/json', ...defaults.headers, ...headers };
|
|
103
|
+
let payload = body;
|
|
104
|
+
|
|
105
|
+
const isFormData = typeof FormData !== 'undefined' && body instanceof FormData;
|
|
106
|
+
const isBlob = typeof Blob !== 'undefined' && body instanceof Blob;
|
|
107
|
+
|
|
108
|
+
if (body !== undefined && body !== null && !isFormData && !isBlob && typeof body !== 'string') {
|
|
109
|
+
payload = JSON.stringify(body);
|
|
110
|
+
if (!finalHeaders['Content-Type']) finalHeaders['Content-Type'] = 'application/json';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let lastError;
|
|
114
|
+
|
|
115
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
116
|
+
const controller = new AbortController();
|
|
117
|
+
let timedOut = false;
|
|
118
|
+
|
|
119
|
+
const timer = timeout > 0
|
|
120
|
+
? setTimeout(() => { timedOut = true; controller.abort(); }, timeout)
|
|
121
|
+
: null;
|
|
122
|
+
|
|
123
|
+
const onExternalAbort = () => controller.abort();
|
|
124
|
+
if (signal) {
|
|
125
|
+
if (signal.aborted) controller.abort();
|
|
126
|
+
else signal.addEventListener('abort', onExternalAbort, { once: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const res = await fetch(url, {
|
|
131
|
+
method,
|
|
132
|
+
headers: finalHeaders,
|
|
133
|
+
body: payload,
|
|
134
|
+
signal: controller.signal,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const data = await parseResponse(res, raw);
|
|
138
|
+
|
|
139
|
+
if (!res.ok) {
|
|
140
|
+
const err = new ApiError(extractMessage(data, res.status), {
|
|
141
|
+
status: res.status,
|
|
142
|
+
data: raw ? null : data,
|
|
143
|
+
url,
|
|
144
|
+
});
|
|
145
|
+
// Only retry server errors / rate limits
|
|
146
|
+
if (res.status >= 500 || res.status === 429) {
|
|
147
|
+
lastError = err;
|
|
148
|
+
} else {
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
return data;
|
|
153
|
+
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (err instanceof ApiError && !(err.status >= 500 || err.status === 429)) {
|
|
156
|
+
throw err; // client error — never retry
|
|
157
|
+
}
|
|
158
|
+
if (err.name === 'AbortError') {
|
|
159
|
+
if (signal && signal.aborted) throw err; // caller aborted
|
|
160
|
+
lastError = new ApiError(
|
|
161
|
+
timedOut ? `Request timed out after ${timeout}ms` : 'Request aborted',
|
|
162
|
+
{ status: 0, url }
|
|
163
|
+
);
|
|
164
|
+
} else if (err instanceof ApiError) {
|
|
165
|
+
lastError = err;
|
|
166
|
+
} else {
|
|
167
|
+
lastError = new ApiError(err.message || 'Network error', { status: 0, url });
|
|
168
|
+
}
|
|
169
|
+
} finally {
|
|
170
|
+
if (timer) clearTimeout(timer);
|
|
171
|
+
if (signal) signal.removeEventListener('abort', onExternalAbort);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (attempt < retries) {
|
|
175
|
+
await sleep(200 * Math.pow(2, attempt)); // 200ms, 400ms, 800ms…
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
throw lastError || new ApiError('Request failed', { status: 0, url });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const api = {
|
|
183
|
+
ApiError,
|
|
184
|
+
|
|
185
|
+
/** Set a base URL applied to every relative path. */
|
|
186
|
+
setBaseURL(baseURL) { defaults.baseURL = baseURL || ''; return api; },
|
|
187
|
+
|
|
188
|
+
/** Merge default headers (e.g. Authorization). */
|
|
189
|
+
setHeaders(headers) { Object.assign(defaults.headers, headers || {}); return api; },
|
|
190
|
+
|
|
191
|
+
/** Configure timeout / retries / baseURL / headers at once. */
|
|
192
|
+
configure(opts = {}) {
|
|
193
|
+
if ('baseURL' in opts) defaults.baseURL = opts.baseURL || '';
|
|
194
|
+
if ('timeout' in opts) defaults.timeout = opts.timeout;
|
|
195
|
+
if ('retries' in opts) defaults.retries = opts.retries;
|
|
196
|
+
if ('headers' in opts) Object.assign(defaults.headers, opts.headers || {});
|
|
197
|
+
return api;
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
get defaults() { return { ...defaults, headers: { ...defaults.headers } }; },
|
|
201
|
+
|
|
202
|
+
request,
|
|
203
|
+
|
|
204
|
+
get: (path, options) => request(path, { ...options, method: 'GET' }),
|
|
205
|
+
post: (path, body, options) => request(path, { ...options, method: 'POST', body }),
|
|
206
|
+
put: (path, body, options) => request(path, { ...options, method: 'PUT', body }),
|
|
207
|
+
patch: (path, body, options) => request(path, { ...options, method: 'PATCH', body }),
|
|
208
|
+
delete: (path, options) => request(path, { ...options, method: 'DELETE' }),
|
|
209
|
+
del: (path, options) => request(path, { ...options, method: 'DELETE' }),
|
|
210
|
+
head: (path, options) => request(path, { ...options, method: 'HEAD', raw: true }),
|
|
211
|
+
|
|
212
|
+
/** Send multipart/form-data. */
|
|
213
|
+
form: (path, formData, options) => request(path, { ...options, method: 'POST', body: formData }),
|
|
214
|
+
|
|
215
|
+
/** Low-level: return the raw Response instead of parsed data. */
|
|
216
|
+
raw: (path, options) => request(path, { ...options, raw: true }),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export default api;
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Aziz.js Framework Boot
|
|
3
|
-
// ============================================================
|
|
4
|
-
|
|
5
|
-
import { h, Fragment } from '/_framework/runtime.js';
|
|
6
|
-
import { initHooks } from '/_framework/hooks.js';
|
|
7
|
-
import { router } from '/_framework/router.js';
|
|
8
|
-
import api from '/_framework/api.js';
|
|
9
|
-
|
|
10
|
-
// Make h and Fragment globally available for JSX in pages
|
|
11
|
-
window.h = h;
|
|
12
|
-
window.Fragment = Fragment;
|
|
13
|
-
|
|
14
|
-
// Global API client: api.get('/api/users'), api.post(...), etc.
|
|
15
|
-
window.api = api;
|
|
16
|
-
|
|
17
|
-
async function boot() {
|
|
18
|
-
initHooks();
|
|
19
|
-
await router.init();
|
|
20
|
-
window.__azizReady = true;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
boot().catch(err => {
|
|
24
|
-
console.error('❌ Aziz.js boot failed:', err);
|
|
25
|
-
const root = document.getElementById('root');
|
|
26
|
-
if (root) {
|
|
27
|
-
root.innerHTML = `<div style="padding:40px;font-family:monospace;color:#b00;background:#fff1f0;border:1px solid #e88;border-radius:8px;margin:40px">
|
|
28
|
-
<h2>⚡ Aziz.js Boot Error</h2>
|
|
29
|
-
<pre style="white-space:pre-wrap">${String(err && err.message || err)}</pre>
|
|
30
|
-
<p style="color:#666;font-size:13px">Check the browser console for details.</p>
|
|
31
|
-
</div>`;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Aziz.js Framework Boot
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
import { h, Fragment } from '/_framework/runtime.js';
|
|
6
|
+
import { initHooks } from '/_framework/hooks.js';
|
|
7
|
+
import { router } from '/_framework/router.js';
|
|
8
|
+
import api from '/_framework/api.js';
|
|
9
|
+
|
|
10
|
+
// Make h and Fragment globally available for JSX in pages
|
|
11
|
+
window.h = h;
|
|
12
|
+
window.Fragment = Fragment;
|
|
13
|
+
|
|
14
|
+
// Global API client: api.get('/api/users'), api.post(...), etc.
|
|
15
|
+
window.api = api;
|
|
16
|
+
|
|
17
|
+
async function boot() {
|
|
18
|
+
initHooks();
|
|
19
|
+
await router.init();
|
|
20
|
+
window.__azizReady = true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
boot().catch(err => {
|
|
24
|
+
console.error('❌ Aziz.js boot failed:', err);
|
|
25
|
+
const root = document.getElementById('root');
|
|
26
|
+
if (root) {
|
|
27
|
+
root.innerHTML = `<div style="padding:40px;font-family:monospace;color:#b00;background:#fff1f0;border:1px solid #e88;border-radius:8px;margin:40px">
|
|
28
|
+
<h2>⚡ Aziz.js Boot Error</h2>
|
|
29
|
+
<pre style="white-space:pre-wrap">${String(err && err.message || err)}</pre>
|
|
30
|
+
<p style="color:#666;font-size:13px">Check the browser console for details.</p>
|
|
31
|
+
</div>`;
|
|
32
|
+
}
|
|
33
|
+
});
|