voodoojs 0.4.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.
Files changed (54) hide show
  1. package/README.md +77 -0
  2. package/dist/chunk-234ZLC6W.js +401 -0
  3. package/dist/chunk-4HQEOXTK.js +10271 -0
  4. package/dist/chunk-5777LJVW.js +64 -0
  5. package/dist/chunk-5CKGDARU.js +1845 -0
  6. package/dist/chunk-A2UOVQBP.js +82 -0
  7. package/dist/chunk-E27NRARW.js +16 -0
  8. package/dist/chunk-JZIYRIY6.js +1196 -0
  9. package/dist/chunk-NNU6WOOU.js +641 -0
  10. package/dist/chunk-PQZEVFVZ.js +448 -0
  11. package/dist/chunk-RJUNPXQF.js +946 -0
  12. package/dist/chunk-U76IRJKH.js +72 -0
  13. package/dist/essential.cjs +13889 -0
  14. package/dist/essential.d.cts +24 -0
  15. package/dist/essential.d.ts +24 -0
  16. package/dist/essential.js +51 -0
  17. package/dist/gpu.cjs +2008 -0
  18. package/dist/gpu.d.cts +68 -0
  19. package/dist/gpu.d.ts +68 -0
  20. package/dist/gpu.js +273 -0
  21. package/dist/http.cjs +467 -0
  22. package/dist/http.d.cts +148 -0
  23. package/dist/http.d.ts +148 -0
  24. package/dist/http.js +7 -0
  25. package/dist/index-CaLD-0oh.d.cts +608 -0
  26. package/dist/index-CaLD-0oh.d.ts +608 -0
  27. package/dist/index-DTllqUtj.d.cts +261 -0
  28. package/dist/index-DTllqUtj.d.ts +261 -0
  29. package/dist/index.cjs +23063 -0
  30. package/dist/index.d.cts +1603 -0
  31. package/dist/index.d.ts +1603 -0
  32. package/dist/index.js +6924 -0
  33. package/dist/query-CKJ4oSpG.d.cts +1595 -0
  34. package/dist/query-DQFRmu3u.d.ts +1595 -0
  35. package/dist/reactivity.cjs +676 -0
  36. package/dist/reactivity.d.cts +188 -0
  37. package/dist/reactivity.d.ts +188 -0
  38. package/dist/reactivity.js +4 -0
  39. package/dist/socket.cjs +2685 -0
  40. package/dist/socket.d.cts +167 -0
  41. package/dist/socket.d.ts +167 -0
  42. package/dist/socket.js +238 -0
  43. package/dist/style-XEUAGGJK.js +5 -0
  44. package/dist/utils.cjs +397 -0
  45. package/dist/utils.d.cts +111 -0
  46. package/dist/utils.d.ts +111 -0
  47. package/dist/utils.js +4 -0
  48. package/dist/voodoo.core.js +8213 -0
  49. package/dist/voodoo.core.min.js +146 -0
  50. package/dist/voodoo.full.js +21193 -0
  51. package/dist/voodoo.full.min.js +1784 -0
  52. package/dist/voodoo.js +14185 -0
  53. package/dist/voodoo.min.js +420 -0
  54. package/package.json +127 -0
@@ -0,0 +1,448 @@
1
+ import { warnOnce } from './chunk-A2UOVQBP.js';
2
+ import { parseDuration } from './chunk-234ZLC6W.js';
3
+ import { __publicField } from './chunk-E27NRARW.js';
4
+
5
+ /**
6
+ * Voodoo.js v0.4.6
7
+ * JavaScript feels like magic.
8
+ * (c) 2026 Voodoo.js contributors. MIT License.
9
+ */
10
+
11
+ // src/http/index.ts
12
+ var HttpError = class extends Error {
13
+ constructor(message, response, config, cause) {
14
+ super(message);
15
+ __publicField(this, "response", response);
16
+ __publicField(this, "config", config);
17
+ __publicField(this, "cause", cause);
18
+ this.name = "HttpError";
19
+ }
20
+ get status() {
21
+ return this.response?.status ?? 0;
22
+ }
23
+ /** `true` when error is network, timeout, or cancellation. */
24
+ get isNetworkError() {
25
+ return !this.response;
26
+ }
27
+ };
28
+ var defaults = {
29
+ baseURL: "",
30
+ headers: { Accept: "application/json, text/html, */*" },
31
+ timeout: 3e4,
32
+ retry: 0,
33
+ retryDelay: 500,
34
+ credentials: "same-origin",
35
+ csrfMeta: "csrf-token",
36
+ csrfHeader: "X-CSRF-TOKEN"
37
+ };
38
+ var requestInterceptors = [];
39
+ var responseInterceptors = [];
40
+ var errorInterceptors = [];
41
+ var responseCache = /* @__PURE__ */ new Map();
42
+ function cacheKey(config) {
43
+ return `${config.method ?? "GET"} ${buildURL(config)}`;
44
+ }
45
+ function clearCache(pattern) {
46
+ if (!pattern) {
47
+ responseCache.clear();
48
+ return;
49
+ }
50
+ const test = typeof pattern === "string" ? (k) => k.includes(pattern) : (k) => pattern.test(k);
51
+ for (const key of [...responseCache.keys()]) if (test(key)) responseCache.delete(key);
52
+ }
53
+ var OFFLINE_KEY = "voodoo:offline-queue";
54
+ function readQueue() {
55
+ try {
56
+ return JSON.parse(localStorage.getItem(OFFLINE_KEY) || "[]");
57
+ } catch {
58
+ return [];
59
+ }
60
+ }
61
+ function writeQueue(list) {
62
+ try {
63
+ localStorage.setItem(OFFLINE_KEY, JSON.stringify(list));
64
+ } catch {
65
+ }
66
+ }
67
+ function enqueueOffline(config) {
68
+ if (typeof localStorage === "undefined") return;
69
+ const list = readQueue();
70
+ list.push({
71
+ url: buildURL(config),
72
+ method: config.method ?? "POST",
73
+ body: config.body,
74
+ headers: config.headers ?? {},
75
+ at: Date.now()
76
+ });
77
+ writeQueue(list);
78
+ }
79
+ async function flushOfflineQueue() {
80
+ if (typeof localStorage === "undefined") return 0;
81
+ const list = readQueue();
82
+ if (!list.length) return 0;
83
+ writeQueue([]);
84
+ let sent = 0;
85
+ for (let index = 0; index < list.length; index++) {
86
+ const item = list[index];
87
+ try {
88
+ await request({
89
+ url: item.url,
90
+ method: item.method,
91
+ body: item.body,
92
+ headers: item.headers,
93
+ offlineQueue: false
94
+ });
95
+ sent++;
96
+ } catch {
97
+ const newItems = readQueue();
98
+ writeQueue([...list.slice(index), ...newItems]);
99
+ break;
100
+ }
101
+ }
102
+ return sent;
103
+ }
104
+ if (typeof window !== "undefined") {
105
+ window.addEventListener("online", () => {
106
+ void flushOfflineQueue();
107
+ });
108
+ }
109
+ function buildURL(config) {
110
+ let url = config.url;
111
+ const base = defaults.baseURL;
112
+ if (base && !/^https?:\/\//i.test(url) && !url.startsWith("//")) {
113
+ url = `${base.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
114
+ }
115
+ if (config.params) {
116
+ const search = new URLSearchParams();
117
+ for (const [key, value] of Object.entries(config.params)) {
118
+ if (value == null || value === "") continue;
119
+ search.append(key, String(value));
120
+ }
121
+ const query = search.toString();
122
+ if (query) url += (url.includes("?") ? "&" : "?") + query;
123
+ }
124
+ return url;
125
+ }
126
+ function csrfToken() {
127
+ if (typeof document === "undefined") return null;
128
+ const meta = document.querySelector(`meta[name="${defaults.csrfMeta}"]`);
129
+ return meta?.getAttribute("content") ?? null;
130
+ }
131
+ function prepareBody(body, headers) {
132
+ if (body == null) return void 0;
133
+ if (typeof FormData !== "undefined" && body instanceof FormData || typeof Blob !== "undefined" && body instanceof Blob || typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams || typeof ArrayBuffer !== "undefined" && body instanceof ArrayBuffer || typeof body === "string") {
134
+ return body;
135
+ }
136
+ if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
137
+ return JSON.stringify(body);
138
+ }
139
+ async function parseResponse(response, type) {
140
+ if (response.status === 204 || response.status === 205) return null;
141
+ const contentType = response.headers.get("content-type") || "";
142
+ switch (type) {
143
+ case "json":
144
+ return response.json();
145
+ case "text":
146
+ return response.text();
147
+ case "blob":
148
+ return response.blob();
149
+ case "arrayBuffer":
150
+ return response.arrayBuffer();
151
+ case "formData":
152
+ return response.formData();
153
+ default:
154
+ if (contentType.includes("application/json") || contentType.includes("+json")) {
155
+ const text = await response.text();
156
+ return text ? JSON.parse(text) : null;
157
+ }
158
+ return response.text();
159
+ }
160
+ }
161
+ var METODOS_SEGUROS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
162
+ function temChaveDeIdempotencia(headers) {
163
+ for (const [name, value] of Object.entries(headers)) {
164
+ if (name.toLowerCase() === "idempotency-key" && String(value).trim() !== "") return true;
165
+ }
166
+ return false;
167
+ }
168
+ function podeRepetir(method, config, headers, url) {
169
+ if (METODOS_SEGUROS.has(method)) return true;
170
+ if (config.retryUnsafe === true) return true;
171
+ if (temChaveDeIdempotencia(headers)) return true;
172
+ if ((config.retry ?? 0) > 0) {
173
+ warnOnce(
174
+ `http:retry-unsafe:${method} ${url}`,
175
+ `retry ignored on ${method} ${url}: retrying a method that changes state may apply the same operation twice if the response is lost in transit. Allow with retryUnsafe: true or send an Idempotency-Key header.`
176
+ );
177
+ }
178
+ return false;
179
+ }
180
+ async function request(input) {
181
+ let config = {
182
+ method: "GET",
183
+ timeout: defaults.timeout,
184
+ retry: defaults.retry,
185
+ retryDelay: defaults.retryDelay,
186
+ credentials: defaults.credentials,
187
+ responseType: "auto",
188
+ ...input,
189
+ headers: { ...defaults.headers, ...input.headers }
190
+ };
191
+ for (const interceptor of requestInterceptors) {
192
+ config = await interceptor(config);
193
+ }
194
+ const method = (config.method ?? "GET").toUpperCase();
195
+ if (config.cache && method === "GET") {
196
+ const entry = responseCache.get(cacheKey(config));
197
+ if (entry && entry.expires > Date.now()) return entry.value;
198
+ }
199
+ if (config.offlineQueue && typeof navigator !== "undefined" && navigator.onLine === false && method !== "GET") {
200
+ enqueueOffline(config);
201
+ return {
202
+ data: null,
203
+ status: 0,
204
+ statusText: "offline-queued",
205
+ headers: new Headers(),
206
+ ok: true,
207
+ raw: new Response(null, { status: 202 }),
208
+ config
209
+ };
210
+ }
211
+ const headers = { ...config.headers };
212
+ if (method !== "GET" && method !== "HEAD") {
213
+ const token = csrfToken();
214
+ if (token && !headers[defaults.csrfHeader]) headers[defaults.csrfHeader] = token;
215
+ }
216
+ headers["X-Requested-With"] || (headers["X-Requested-With"] = "XMLHttpRequest");
217
+ const body = prepareBody(config.body, headers);
218
+ const url = buildURL(config);
219
+ const attempts = podeRepetir(method, config, headers, url) ? (config.retry ?? 0) + 1 : 1;
220
+ let lastError;
221
+ for (let attempt = 0; attempt < attempts; attempt++) {
222
+ const controller = new AbortController();
223
+ const externo = config.signal;
224
+ let repassarAborto = null;
225
+ if (externo) {
226
+ if (externo.aborted) {
227
+ controller.abort(externo.reason);
228
+ } else {
229
+ repassarAborto = () => controller.abort(externo.reason);
230
+ externo.addEventListener("abort", repassarAborto, { once: true });
231
+ }
232
+ }
233
+ const soltarSinal = () => {
234
+ if (repassarAborto && externo) externo.removeEventListener("abort", repassarAborto);
235
+ repassarAborto = null;
236
+ };
237
+ const timeoutId = config.timeout && config.timeout > 0 ? setTimeout(() => controller.abort(new DOMException("timeout", "TimeoutError")), config.timeout) : null;
238
+ try {
239
+ const response = await fetch(url, {
240
+ method,
241
+ headers,
242
+ body: method === "GET" || method === "HEAD" ? void 0 : body,
243
+ credentials: config.credentials,
244
+ signal: controller.signal
245
+ });
246
+ if (timeoutId) clearTimeout(timeoutId);
247
+ soltarSinal();
248
+ const data = await parseResponse(response, config.responseType);
249
+ let result = {
250
+ data,
251
+ status: response.status,
252
+ statusText: response.statusText,
253
+ headers: response.headers,
254
+ ok: response.ok,
255
+ raw: response,
256
+ config
257
+ };
258
+ if (!response.ok) {
259
+ if (response.status >= 500 && attempt < attempts - 1) {
260
+ await wait((config.retryDelay ?? 500) * 2 ** attempt);
261
+ continue;
262
+ }
263
+ const error2 = new HttpError(
264
+ `Request failed with status ${response.status}`,
265
+ result,
266
+ config
267
+ );
268
+ for (const interceptor of errorInterceptors) interceptor(error2);
269
+ throw error2;
270
+ }
271
+ for (const interceptor of responseInterceptors) {
272
+ result = await interceptor(result);
273
+ }
274
+ if (config.cache && method === "GET") {
275
+ responseCache.set(cacheKey(config), {
276
+ expires: Date.now() + config.cache,
277
+ value: result
278
+ });
279
+ }
280
+ return result;
281
+ } catch (err) {
282
+ if (timeoutId) clearTimeout(timeoutId);
283
+ soltarSinal();
284
+ if (err instanceof HttpError) throw err;
285
+ lastError = err;
286
+ const aborted = err?.name === "AbortError" && config.signal?.aborted;
287
+ if (aborted) break;
288
+ if (attempt < attempts - 1) {
289
+ await wait((config.retryDelay ?? 500) * 2 ** attempt);
290
+ continue;
291
+ }
292
+ }
293
+ }
294
+ const message = lastError?.name === "TimeoutError" ? `Timeout after ${config.timeout}ms` : `Network failure accessing ${url}`;
295
+ const error = new HttpError(message, void 0, config, lastError);
296
+ for (const interceptor of errorInterceptors) interceptor(error);
297
+ throw error;
298
+ }
299
+ function wait(ms) {
300
+ return new Promise((resolve) => setTimeout(resolve, ms));
301
+ }
302
+ async function shortcut(config) {
303
+ const response = await request(config);
304
+ return response.data;
305
+ }
306
+ var http = {
307
+ defaults,
308
+ get(url, options = {}) {
309
+ return shortcut({ ...options, url, method: "GET" });
310
+ },
311
+ post(url, body, options = {}) {
312
+ return shortcut({ ...options, url, method: "POST", body });
313
+ },
314
+ put(url, body, options = {}) {
315
+ return shortcut({ ...options, url, method: "PUT", body });
316
+ },
317
+ patch(url, body, options = {}) {
318
+ return shortcut({ ...options, url, method: "PATCH", body });
319
+ },
320
+ delete(url, options = {}) {
321
+ return shortcut({ ...options, url, method: "DELETE" });
322
+ },
323
+ head(url, options = {}) {
324
+ return shortcut({ ...options, url, method: "HEAD" });
325
+ },
326
+ /** Full request with status and headers. */
327
+ request,
328
+ /** Upload files with real progress using XMLHttpRequest. */
329
+ upload(url, data, options = {}) {
330
+ return new Promise((resolve, reject) => {
331
+ const xhr = new XMLHttpRequest();
332
+ const finalUrl = buildURL({ url });
333
+ xhr.open(options.method ?? "POST", finalUrl);
334
+ for (const [key, value] of Object.entries({ ...defaults.headers, ...options.headers })) {
335
+ if (key.toLowerCase() === "content-type") continue;
336
+ xhr.setRequestHeader(key, value);
337
+ }
338
+ const token = csrfToken();
339
+ if (token) xhr.setRequestHeader(defaults.csrfHeader, token);
340
+ xhr.upload.addEventListener("progress", (event) => {
341
+ if (!event.lengthComputable) return;
342
+ options.onProgress?.(
343
+ Math.round(event.loaded / event.total * 100),
344
+ event.loaded,
345
+ event.total
346
+ );
347
+ });
348
+ xhr.addEventListener("load", () => {
349
+ const contentType = xhr.getResponseHeader("content-type") || "";
350
+ let data2 = xhr.responseText;
351
+ if (contentType.includes("json")) {
352
+ try {
353
+ data2 = JSON.parse(xhr.responseText);
354
+ } catch {
355
+ }
356
+ }
357
+ if (xhr.status >= 200 && xhr.status < 300) resolve(data2);
358
+ else reject(new HttpError(`Upload failed with status ${xhr.status}`));
359
+ });
360
+ xhr.addEventListener("error", () => reject(new HttpError("Network failure during upload")));
361
+ xhr.addEventListener("abort", () => reject(new HttpError("Upload canceled")));
362
+ options.signal?.addEventListener("abort", () => xhr.abort());
363
+ xhr.send(data);
364
+ });
365
+ },
366
+ /** Server-Sent Events with automatic reconnection by the browser. */
367
+ sse(url, handlers = {}) {
368
+ const source = new EventSource(buildURL({ url }));
369
+ source.addEventListener("message", (event) => {
370
+ let data = event.data;
371
+ try {
372
+ data = JSON.parse(event.data);
373
+ } catch {
374
+ }
375
+ handlers.message?.(data, event);
376
+ });
377
+ if (handlers.error) source.addEventListener("error", handlers.error);
378
+ return source;
379
+ },
380
+ /** Read a streaming response line by line (NDJSON). */
381
+ async stream(url, onLine, options = {}) {
382
+ const response = await fetch(buildURL({ url, params: options.params }), {
383
+ headers: { ...defaults.headers, ...options.headers },
384
+ signal: options.signal
385
+ });
386
+ if (!response.body) return;
387
+ const reader = response.body.getReader();
388
+ const decoder = new TextDecoder();
389
+ let buffer = "";
390
+ for (; ; ) {
391
+ const { done, value } = await reader.read();
392
+ if (done) break;
393
+ buffer += decoder.decode(value, { stream: true });
394
+ const lines = buffer.split("\n");
395
+ buffer = lines.pop() ?? "";
396
+ for (const line of lines) if (line.trim()) onLine(line);
397
+ }
398
+ if (buffer.trim()) onLine(buffer);
399
+ },
400
+ interceptors: {
401
+ request: {
402
+ use(fn) {
403
+ requestInterceptors.push(fn);
404
+ return () => {
405
+ const i = requestInterceptors.indexOf(fn);
406
+ if (i > -1) requestInterceptors.splice(i, 1);
407
+ };
408
+ }
409
+ },
410
+ response: {
411
+ use(fn) {
412
+ responseInterceptors.push(fn);
413
+ return () => {
414
+ const i = responseInterceptors.indexOf(fn);
415
+ if (i > -1) responseInterceptors.splice(i, 1);
416
+ };
417
+ }
418
+ },
419
+ error: {
420
+ use(fn) {
421
+ errorInterceptors.push(fn);
422
+ return () => {
423
+ const i = errorInterceptors.indexOf(fn);
424
+ if (i > -1) errorInterceptors.splice(i, 1);
425
+ };
426
+ }
427
+ }
428
+ },
429
+ /** Set headers sent on every request. */
430
+ setHeader(name, value) {
431
+ if (value === null) delete defaults.headers[name];
432
+ else defaults.headers[name] = value;
433
+ },
434
+ /** Shortcut for token-based authentication. */
435
+ setToken(token, scheme = "Bearer") {
436
+ this.setHeader("Authorization", token ? `${scheme} ${token}` : null);
437
+ },
438
+ setBaseURL(url) {
439
+ defaults.baseURL = url;
440
+ },
441
+ clearCache,
442
+ flushOfflineQueue,
443
+ parseDuration
444
+ };
445
+
446
+ export { HttpError, clearCache, flushOfflineQueue, http, request };
447
+ //# sourceMappingURL=chunk-PQZEVFVZ.js.map
448
+ //# sourceMappingURL=chunk-PQZEVFVZ.js.map