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,2685 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * Voodoo.js v0.4.6
7
+ * JavaScript feels like magic.
8
+ * (c) 2026 Voodoo.js contributors. MIT License.
9
+ */
10
+ var __defProp = Object.defineProperty;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
+
14
+ // src/runtime/registry.ts
15
+ var config = {
16
+ prefix: "v-"};
17
+ var directives = /* @__PURE__ */ new Map();
18
+ var PRIORITY = {
19
+ DATA: 70,
20
+ DEFAULT: 0,
21
+ TRANSITION: -20
22
+ };
23
+ function defineDirective(name, setup, options = {}) {
24
+ directives.set(name, {
25
+ name,
26
+ setup,
27
+ priority: options.priority ?? PRIORITY.DEFAULT,
28
+ terminal: options.terminal ?? false
29
+ });
30
+ }
31
+ function warnOnce(key, message) {
32
+ return;
33
+ }
34
+
35
+ // src/reactivity/index.ts
36
+ var resolvedPromise = /* @__PURE__ */ Promise.resolve();
37
+ var queue = [];
38
+ var postQueue = [];
39
+ var isFlushing = false;
40
+ var isFlushPending = false;
41
+ var RECURSION_LIMIT = 100;
42
+ function queueJob(job) {
43
+ if (job.queued) return;
44
+ job.queued = true;
45
+ queue.push(job);
46
+ queueFlush();
47
+ }
48
+ function queueFlush() {
49
+ if (isFlushing || isFlushPending) return;
50
+ isFlushPending = true;
51
+ resolvedPromise.then(flushJobs);
52
+ }
53
+ function flushJobs() {
54
+ isFlushPending = false;
55
+ isFlushing = true;
56
+ const counts = /* @__PURE__ */ new Map();
57
+ try {
58
+ for (let i = 0; i < queue.length; i++) {
59
+ const job = queue[i];
60
+ if (!job.active) continue;
61
+ const count = (counts.get(job) || 0) + 1;
62
+ counts.set(job, count);
63
+ if (count > RECURSION_LIMIT) {
64
+ warn2(
65
+ "Infinite update loop detected. A reactive effect keeps triggering itself without ever settling. Check whether some expression writes to state that it also reads."
66
+ );
67
+ continue;
68
+ }
69
+ try {
70
+ job.run();
71
+ } catch (err) {
72
+ handleError(err, "effect");
73
+ }
74
+ }
75
+ } finally {
76
+ for (const job of queue) job.queued = false;
77
+ queue = [];
78
+ isFlushing = false;
79
+ const posts = postQueue;
80
+ postQueue = [];
81
+ for (const cb of posts) {
82
+ try {
83
+ cb();
84
+ } catch (err) {
85
+ handleError(err, "post-flush");
86
+ }
87
+ }
88
+ if (queue.length || postQueue.length) {
89
+ resolvedPromise.then(flushJobs);
90
+ isFlushPending = true;
91
+ }
92
+ }
93
+ }
94
+ function handleError(err, context) {
95
+ console.error(`[Voodoo] error in ${context}:`, err);
96
+ }
97
+ function warn2(msg, ...args) {
98
+ console.warn(`[Voodoo] ${msg}`, ...args);
99
+ }
100
+ var activeEffect;
101
+ var shouldTrack = true;
102
+ var trackStack = [];
103
+ function pauseTracking() {
104
+ trackStack.push(shouldTrack);
105
+ shouldTrack = false;
106
+ }
107
+ function resetTracking() {
108
+ shouldTrack = trackStack.pop() ?? true;
109
+ }
110
+ var ITERATE_KEY = /* @__PURE__ */ Symbol("voodoo:iterate");
111
+ var targetMap = /* @__PURE__ */ new WeakMap();
112
+ function track(target2, key) {
113
+ if (!shouldTrack || !activeEffect) return;
114
+ let depsMap = targetMap.get(target2);
115
+ if (!depsMap) targetMap.set(target2, depsMap = /* @__PURE__ */ new Map());
116
+ let dep = depsMap.get(key);
117
+ if (!dep) depsMap.set(key, dep = /* @__PURE__ */ new Set());
118
+ if (!dep.has(activeEffect)) {
119
+ dep.add(activeEffect);
120
+ activeEffect.deps.push(dep);
121
+ }
122
+ }
123
+ function trigger(target2, type, key, _newValue) {
124
+ const depsMap = targetMap.get(target2);
125
+ if (!depsMap) return;
126
+ const effects = /* @__PURE__ */ new Set();
127
+ const add = (dep) => {
128
+ if (!dep) return;
129
+ for (const e of dep) if (e !== activeEffect || type === "clear" /* CLEAR */) effects.add(e);
130
+ };
131
+ if (type === "clear" /* CLEAR */) {
132
+ depsMap.forEach(add);
133
+ } else {
134
+ if (key !== void 0) add(depsMap.get(key));
135
+ const isArr = Array.isArray(target2);
136
+ if (type === "add" /* ADD */) {
137
+ if (!isArr) add(depsMap.get(ITERATE_KEY));
138
+ else if (isIntegerKey(key)) add(depsMap.get("length"));
139
+ } else if (type === "delete" /* DELETE */) {
140
+ if (!isArr) add(depsMap.get(ITERATE_KEY));
141
+ } else if (isArr && key === "length") {
142
+ const newLen = Number(_newValue);
143
+ depsMap.forEach((dep, k) => {
144
+ if (k === "length" || typeof k !== "symbol" && Number(k) >= newLen) add(dep);
145
+ });
146
+ }
147
+ }
148
+ for (const e of effects) {
149
+ if (e.scheduler) e.scheduler();
150
+ else queueJob(e);
151
+ }
152
+ }
153
+ function isIntegerKey(key) {
154
+ return typeof key === "string" && key !== "NaN" && key[0] !== "-" && String(parseInt(key, 10)) === key;
155
+ }
156
+ var RAW = /* @__PURE__ */ Symbol("voodoo:raw");
157
+ var IS_REACTIVE = /* @__PURE__ */ Symbol("voodoo:isReactive");
158
+ var SKIP = /* @__PURE__ */ Symbol("voodoo:skip");
159
+ var reactiveMap = /* @__PURE__ */ new WeakMap();
160
+ var arrayInstrumentations = /* @__PURE__ */ (() => {
161
+ const inst = {};
162
+ for (const key of ["includes", "indexOf", "lastIndexOf"]) {
163
+ inst[key] = function(...args) {
164
+ const arr = toRaw(this);
165
+ for (let i = 0; i < arr.length; i++) track(arr, String(i));
166
+ const res = arr[key].apply(arr, args);
167
+ if (res === -1 || res === false) {
168
+ return arr[key].apply(arr, args.map(toRaw));
169
+ }
170
+ return res;
171
+ };
172
+ }
173
+ for (const key of ["push", "pop", "shift", "unshift", "splice"]) {
174
+ inst[key] = function(...args) {
175
+ pauseTracking();
176
+ try {
177
+ return toRaw(this)[key].apply(this, args);
178
+ } finally {
179
+ resetTracking();
180
+ }
181
+ };
182
+ }
183
+ return inst;
184
+ })();
185
+ function isObject(val) {
186
+ return val !== null && typeof val === "object";
187
+ }
188
+ var NON_REACTIVE = /* @__PURE__ */ new Set([
189
+ "Date",
190
+ "RegExp",
191
+ "Promise",
192
+ "Error",
193
+ "File",
194
+ "FileList",
195
+ "Blob",
196
+ "FormData",
197
+ "URL",
198
+ "URLSearchParams",
199
+ "ArrayBuffer",
200
+ "DataView"
201
+ ]);
202
+ function canObserve(value) {
203
+ if (!isObject(value)) return false;
204
+ if (value[SKIP]) return false;
205
+ if (Object.isFrozen(value)) return false;
206
+ if (typeof Node !== "undefined" && value instanceof Node) return false;
207
+ const tag = Object.prototype.toString.call(value).slice(8, -1);
208
+ if (NON_REACTIVE.has(tag)) return false;
209
+ return tag === "Object" || tag === "Array" || tag === "Map" || tag === "Set";
210
+ }
211
+ function toRaw(observed) {
212
+ const raw = observed && observed[RAW];
213
+ return raw ? toRaw(raw) : observed;
214
+ }
215
+ function isReactive(value) {
216
+ return !!(value && value[IS_REACTIVE]);
217
+ }
218
+ function reactive(target2) {
219
+ if (!isObject(target2)) return target2;
220
+ if (isReactive(target2)) return target2;
221
+ if (!canObserve(target2)) return target2;
222
+ const existing = reactiveMap.get(target2);
223
+ if (existing) return existing;
224
+ const isMapOrSet = target2 instanceof Map || target2 instanceof Set;
225
+ const proxy = new Proxy(
226
+ target2,
227
+ isMapOrSet ? collectionHandlers : baseHandlers
228
+ );
229
+ reactiveMap.set(target2, proxy);
230
+ return proxy;
231
+ }
232
+ var baseHandlers = {
233
+ get(target2, key, receiver) {
234
+ if (key === RAW) return target2;
235
+ if (key === IS_REACTIVE) return true;
236
+ const isArr = Array.isArray(target2);
237
+ if (isArr && Object.prototype.hasOwnProperty.call(arrayInstrumentations, key)) {
238
+ return Reflect.get(arrayInstrumentations, key, receiver);
239
+ }
240
+ const res = Reflect.get(target2, key, receiver);
241
+ if (typeof key === "symbol") return res;
242
+ track(target2, key);
243
+ if (isRef(res)) return isArr && isIntegerKey(key) ? res : res.value;
244
+ if (isObject(res)) return reactive(res);
245
+ return res;
246
+ },
247
+ set(target2, key, value, receiver) {
248
+ const oldValue = target2[key];
249
+ value = toRaw(value);
250
+ if (!Array.isArray(target2) && isRef(oldValue) && !isRef(value)) {
251
+ oldValue.value = value;
252
+ return true;
253
+ }
254
+ const hadKey = Array.isArray(target2) && isIntegerKey(key) ? Number(key) < target2.length : Object.prototype.hasOwnProperty.call(target2, key);
255
+ const result = Reflect.set(target2, key, value, receiver);
256
+ if (target2 === toRaw(receiver)) {
257
+ if (!hadKey) trigger(target2, "add" /* ADD */, key, value);
258
+ else if (hasChanged(value, oldValue)) trigger(target2, "set" /* SET */, key, value);
259
+ }
260
+ return result;
261
+ },
262
+ deleteProperty(target2, key) {
263
+ const hadKey = Object.prototype.hasOwnProperty.call(target2, key);
264
+ const result = Reflect.deleteProperty(target2, key);
265
+ if (result && hadKey) trigger(target2, "delete" /* DELETE */, key);
266
+ return result;
267
+ },
268
+ has(target2, key) {
269
+ const result = Reflect.has(target2, key);
270
+ if (typeof key !== "symbol") track(target2, key);
271
+ return result;
272
+ },
273
+ ownKeys(target2) {
274
+ track(target2, Array.isArray(target2) ? "length" : ITERATE_KEY);
275
+ return Reflect.ownKeys(target2);
276
+ }
277
+ };
278
+ var collectionHandlers = {
279
+ get(target2, key, receiver) {
280
+ if (key === RAW) return target2;
281
+ if (key === IS_REACTIVE) return true;
282
+ const raw = target2;
283
+ if (key === "size") {
284
+ track(raw, ITERATE_KEY);
285
+ return Reflect.get(raw, "size", raw);
286
+ }
287
+ const methods = {
288
+ get(k) {
289
+ track(raw, k);
290
+ const v = raw.get(k);
291
+ return isObject(v) ? reactive(v) : v;
292
+ },
293
+ has(k) {
294
+ track(raw, k);
295
+ return raw.has(k);
296
+ },
297
+ add(v) {
298
+ v = toRaw(v);
299
+ const had = raw.has(v);
300
+ raw.add(v);
301
+ if (!had) trigger(raw, "add" /* ADD */, v, v);
302
+ return receiver;
303
+ },
304
+ set(k, v) {
305
+ const had = raw.has(k);
306
+ const old = raw.get(k);
307
+ raw.set(k, toRaw(v));
308
+ if (!had) trigger(raw, "add" /* ADD */, k, v);
309
+ else if (hasChanged(v, old)) trigger(raw, "set" /* SET */, k, v);
310
+ return receiver;
311
+ },
312
+ delete(k) {
313
+ const had = raw.has(k);
314
+ const res2 = raw.delete(k);
315
+ if (had) trigger(raw, "delete" /* DELETE */, k);
316
+ return res2;
317
+ },
318
+ clear() {
319
+ const had = raw.size !== 0;
320
+ const res2 = raw.clear();
321
+ if (had) trigger(raw, "clear" /* CLEAR */);
322
+ return res2;
323
+ },
324
+ forEach(cb, thisArg) {
325
+ track(raw, ITERATE_KEY);
326
+ return raw.forEach((v, k) => {
327
+ cb.call(thisArg, isObject(v) ? reactive(v) : v, isObject(k) ? reactive(k) : k, receiver);
328
+ });
329
+ }
330
+ };
331
+ if (key in methods) return methods[key];
332
+ if (key === Symbol.iterator || key === "keys" || key === "values" || key === "entries") {
333
+ track(raw, ITERATE_KEY);
334
+ const method = raw[key];
335
+ return typeof method === "function" ? method.bind(raw) : method;
336
+ }
337
+ const res = Reflect.get(raw, key, raw);
338
+ return typeof res === "function" ? res.bind(raw) : res;
339
+ }
340
+ };
341
+ function hasChanged(value, oldValue) {
342
+ return !Object.is(value, oldValue);
343
+ }
344
+ function isRef(r) {
345
+ return !!(r && r.__v_isRef === true);
346
+ }
347
+
348
+ // src/parser/interpreter.ts
349
+ var SafeObject = /* @__PURE__ */ Object.freeze({
350
+ keys: Object.keys,
351
+ values: Object.values,
352
+ entries: Object.entries,
353
+ fromEntries: Object.fromEntries,
354
+ assign: Object.assign,
355
+ is: Object.is,
356
+ hasOwn: Object.hasOwn ?? ((o, k) => Object.prototype.hasOwnProperty.call(o, k))
357
+ });
358
+ var DELIBERATELY_WITHHELD = /* @__PURE__ */ new Set([
359
+ "eval",
360
+ "Function",
361
+ "window",
362
+ "globalThis",
363
+ "self",
364
+ "top",
365
+ "parent",
366
+ "document",
367
+ "fetch",
368
+ "XMLHttpRequest",
369
+ "importScripts",
370
+ "require",
371
+ "process",
372
+ "Reflect",
373
+ "Proxy",
374
+ "WebAssembly",
375
+ "localStorage",
376
+ "sessionStorage",
377
+ "indexedDB",
378
+ "navigator",
379
+ "location",
380
+ "history",
381
+ "crypto",
382
+ "Worker",
383
+ "SharedWorker",
384
+ "ServiceWorker"
385
+ ]);
386
+ var allowedGlobals = {
387
+ Math,
388
+ JSON,
389
+ Date,
390
+ Number,
391
+ String,
392
+ Boolean,
393
+ Array,
394
+ Object: SafeObject,
395
+ Intl,
396
+ RegExp,
397
+ Promise,
398
+ parseInt,
399
+ parseFloat,
400
+ isNaN,
401
+ isFinite,
402
+ encodeURIComponent,
403
+ decodeURIComponent,
404
+ console
405
+ };
406
+ var VoodooRuntimeError = class extends Error {
407
+ constructor(message, expression) {
408
+ super(expression ? `${message}
409
+
410
+ Expression: ${expression}` : message);
411
+ __publicField(this, "expression", expression);
412
+ this.name = "VoodooRuntimeError";
413
+ }
414
+ };
415
+ var SPREAD = /* @__PURE__ */ Symbol("spread");
416
+ var BLOCKED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
417
+ function chaveBloqueada(key) {
418
+ return typeof key === "string" && BLOCKED_KEYS.has(key);
419
+ }
420
+ function checkKey(key, expression) {
421
+ if (chaveBloqueada(key)) {
422
+ throw new VoodooRuntimeError(
423
+ `Access blocked to "${String(key)}": template expressions cannot reach the prototype chain. Expose a method in state instead.`,
424
+ expression
425
+ );
426
+ }
427
+ return key;
428
+ }
429
+ function evaluate(node, scope) {
430
+ switch (node.t) {
431
+ case "lit":
432
+ return node.v;
433
+ case "tpl": {
434
+ let out = node.quasis[0] ?? "";
435
+ for (let i = 0; i < node.exprs.length; i++) {
436
+ out += stringify(evaluate(node.exprs[i], scope));
437
+ out += node.quasis[i + 1] ?? "";
438
+ }
439
+ return out;
440
+ }
441
+ case "id": {
442
+ checkKey(node.n);
443
+ const owner = scope.lookup(node.n);
444
+ if (owner) return owner[node.n];
445
+ if (node.n in allowedGlobals) return allowedGlobals[node.n];
446
+ return void 0;
447
+ }
448
+ case "member": {
449
+ const obj = evaluate(node.o, scope);
450
+ if (obj == null) {
451
+ if (node.opt) return void 0;
452
+ throw new VoodooRuntimeError(
453
+ `Could not read "${describeKey(node, scope)}" from ${obj === null ? "null" : "undefined"}`
454
+ );
455
+ }
456
+ const key = checkKey(
457
+ node.computed ? evaluate(node.p, scope) : node.p.v
458
+ );
459
+ return obj[key];
460
+ }
461
+ case "call": {
462
+ let thisArg;
463
+ let fn;
464
+ if (node.callee.t === "member") {
465
+ const obj = evaluate(node.callee.o, scope);
466
+ if (obj == null) {
467
+ if (node.callee.opt || node.opt) return void 0;
468
+ throw new VoodooRuntimeError(
469
+ `Could not call "${describeKey(node.callee, scope)}" from ${obj === null ? "null" : "undefined"}`
470
+ );
471
+ }
472
+ const key = checkKey(
473
+ node.callee.computed ? evaluate(node.callee.p, scope) : node.callee.p.v
474
+ );
475
+ thisArg = obj;
476
+ fn = obj[key];
477
+ } else if (node.callee.t === "id") {
478
+ checkKey(node.callee.n);
479
+ const owner = scope.lookup(node.callee.n);
480
+ if (owner) {
481
+ thisArg = owner;
482
+ fn = owner[node.callee.n];
483
+ } else {
484
+ fn = allowedGlobals[node.callee.n];
485
+ }
486
+ } else {
487
+ fn = evaluate(node.callee, scope);
488
+ }
489
+ if (fn == null && node.opt) return void 0;
490
+ if (typeof fn !== "function") {
491
+ const name = node.callee.t === "id" ? node.callee.n : describeKey(node.callee, scope);
492
+ if (node.callee.t === "id" && !scope.lookup(name) && !(name in allowedGlobals)) {
493
+ if (DELIBERATELY_WITHHELD.has(name)) {
494
+ throw new VoodooRuntimeError(
495
+ `"${name}" is blocked. Expressions run in a sandbox without access to it.`
496
+ );
497
+ }
498
+ throw new VoodooRuntimeError(
499
+ `"${name}" was not found. Expressions cannot reach window: expose it with V.config.globals.${name} = ..., or put it in scope with V.data({ ${name} }).`
500
+ );
501
+ }
502
+ throw new VoodooRuntimeError(`"${name}" is not a function`);
503
+ }
504
+ return fn.apply(thisArg, evalArgs(node.args, scope));
505
+ }
506
+ case "unary": {
507
+ if (node.op === "...") return { [SPREAD]: evaluate(node.a, scope) };
508
+ if (node.op === "typeof") {
509
+ if (node.a.t === "id") {
510
+ if (chaveBloqueada(node.a.n)) return "undefined";
511
+ const owner = scope.lookup(node.a.n);
512
+ const value = owner ? owner[node.a.n] : allowedGlobals[node.a.n];
513
+ return typeof value;
514
+ }
515
+ return typeof evaluate(node.a, scope);
516
+ }
517
+ const v = evaluate(node.a, scope);
518
+ switch (node.op) {
519
+ case "!":
520
+ return !v;
521
+ case "-":
522
+ return -v;
523
+ case "+":
524
+ return +v;
525
+ case "void":
526
+ return void 0;
527
+ }
528
+ throw new VoodooRuntimeError(`Unsupported unary operator: ${node.op}`);
529
+ }
530
+ case "update": {
531
+ const old = Number(evaluate(node.a, scope));
532
+ const updated = node.op === "++" ? old + 1 : old - 1;
533
+ assign(node.a, updated, scope);
534
+ return node.prefix ? updated : old;
535
+ }
536
+ case "bin": {
537
+ const l = evaluate(node.l, scope);
538
+ const r = evaluate(node.r, scope);
539
+ switch (node.op) {
540
+ case "+":
541
+ return l + r;
542
+ case "-":
543
+ return l - r;
544
+ case "*":
545
+ return l * r;
546
+ case "/":
547
+ return l / r;
548
+ case "%":
549
+ return l % r;
550
+ case "**":
551
+ return l ** r;
552
+ case "==":
553
+ return l == r;
554
+ case "!=":
555
+ return l != r;
556
+ case "===":
557
+ return l === r;
558
+ case "!==":
559
+ return l !== r;
560
+ case "<":
561
+ return l < r;
562
+ case ">":
563
+ return l > r;
564
+ case "<=":
565
+ return l <= r;
566
+ case ">=":
567
+ return l >= r;
568
+ case "in":
569
+ return l in r;
570
+ case "instanceof":
571
+ return l instanceof r;
572
+ }
573
+ throw new VoodooRuntimeError(`Unsupported operator: ${node.op}`);
574
+ }
575
+ case "logic": {
576
+ const l = evaluate(node.l, scope);
577
+ if (node.op === "&&") return l ? evaluate(node.r, scope) : l;
578
+ if (node.op === "||") return l ? l : evaluate(node.r, scope);
579
+ return l ?? evaluate(node.r, scope);
580
+ }
581
+ case "cond":
582
+ return evaluate(node.test, scope) ? evaluate(node.cons, scope) : evaluate(node.alt, scope);
583
+ case "assign": {
584
+ let value;
585
+ if (node.op === "=") {
586
+ value = evaluate(node.value, scope);
587
+ } else if (node.op === "&&=" || node.op === "||=" || node.op === "??=") {
588
+ const current = evaluate(node.target, scope);
589
+ const shouldAssign = node.op === "&&=" ? !!current : node.op === "||=" ? !current : current == null;
590
+ if (!shouldAssign) return current;
591
+ value = evaluate(node.value, scope);
592
+ } else {
593
+ const current = evaluate(node.target, scope);
594
+ const operand = evaluate(node.value, scope);
595
+ switch (node.op) {
596
+ case "+=":
597
+ value = current + operand;
598
+ break;
599
+ case "-=":
600
+ value = current - operand;
601
+ break;
602
+ case "*=":
603
+ value = current * operand;
604
+ break;
605
+ case "/=":
606
+ value = current / operand;
607
+ break;
608
+ case "%=":
609
+ value = current % operand;
610
+ break;
611
+ case "**=":
612
+ value = current ** operand;
613
+ break;
614
+ default:
615
+ throw new VoodooRuntimeError(`Unsupported assignment: ${node.op}`);
616
+ }
617
+ }
618
+ assign(node.target, value, scope);
619
+ return value;
620
+ }
621
+ case "if": {
622
+ if (evaluate(node.test, scope)) return evaluate(node.cons, scope);
623
+ return node.alt ? evaluate(node.alt, scope) : void 0;
624
+ }
625
+ case "method": {
626
+ const methodParams = node.params;
627
+ const methodBody = node.body;
628
+ return function(...args) {
629
+ const vars = {};
630
+ for (let i = 0; i < methodParams.length; i++) vars[methodParams[i]] = args[i];
631
+ const owner = this;
632
+ const base = owner !== null && typeof owner === "object" ? scope.child(owner) : scope;
633
+ return evaluate(methodBody, base.child(vars));
634
+ };
635
+ }
636
+ case "arrow": {
637
+ const params = node.params;
638
+ const body = node.body;
639
+ return (...args) => {
640
+ const vars = {};
641
+ for (let i = 0; i < params.length; i++) vars[params[i]] = args[i];
642
+ return evaluate(body, scope.child(vars));
643
+ };
644
+ }
645
+ case "obj": {
646
+ const out = {};
647
+ for (const prop of node.props) {
648
+ if (prop.spread) {
649
+ Object.assign(out, evaluate(prop.spread, scope));
650
+ } else {
651
+ const key = checkKey(
652
+ prop.key !== null ? prop.key : String(evaluate(prop.keyExpr, scope))
653
+ );
654
+ if (prop.getter) {
655
+ const compute = evaluate(prop.value, scope);
656
+ Object.defineProperty(out, key, {
657
+ enumerable: true,
658
+ configurable: true,
659
+ get() {
660
+ return compute.call(this);
661
+ }
662
+ });
663
+ continue;
664
+ }
665
+ out[key] = evaluate(prop.value, scope);
666
+ }
667
+ }
668
+ return out;
669
+ }
670
+ case "arr": {
671
+ const out = [];
672
+ for (const el of node.els) {
673
+ if (el && typeof el === "object" && "spread" in el) {
674
+ out.push(...evaluate(el.spread, scope));
675
+ } else {
676
+ out.push(evaluate(el, scope));
677
+ }
678
+ }
679
+ return out;
680
+ }
681
+ case "seq": {
682
+ let last;
683
+ for (const stmt of node.body) last = evaluate(stmt, scope);
684
+ return last;
685
+ }
686
+ }
687
+ throw new VoodooRuntimeError(`Unknown node: ${node.t}`);
688
+ }
689
+ function evalArgs(args, scope) {
690
+ const out = [];
691
+ for (const arg of args) {
692
+ const value = evaluate(arg, scope);
693
+ if (value && typeof value === "object" && SPREAD in value) {
694
+ out.push(...value[SPREAD]);
695
+ } else {
696
+ out.push(value);
697
+ }
698
+ }
699
+ return out;
700
+ }
701
+ function assign(target2, value, scope) {
702
+ if (target2.t === "id") {
703
+ checkKey(target2.n);
704
+ scope.set(target2.n, value);
705
+ return;
706
+ }
707
+ if (target2.t === "member") {
708
+ const obj = evaluate(target2.o, scope);
709
+ if (obj == null) {
710
+ throw new VoodooRuntimeError("Could not write to null or undefined");
711
+ }
712
+ const key = checkKey(
713
+ target2.computed ? evaluate(target2.p, scope) : target2.p.v
714
+ );
715
+ obj[key] = value;
716
+ return;
717
+ }
718
+ throw new VoodooRuntimeError("Invalid assignment target");
719
+ }
720
+ function describeKey(node, scope) {
721
+ if (node.t === "member") {
722
+ return node.computed ? String(evaluate(node.p, scope)) : String(node.p.v);
723
+ }
724
+ if (node.t === "id") return node.n;
725
+ return "value";
726
+ }
727
+ function stringify(value) {
728
+ if (value == null) return "";
729
+ if (typeof value === "string") return value;
730
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
731
+ if (value instanceof Date) return value.toLocaleString();
732
+ if (typeof value === "object") {
733
+ try {
734
+ return JSON.stringify(value);
735
+ } catch {
736
+ return String(value);
737
+ }
738
+ }
739
+ return String(value);
740
+ }
741
+
742
+ // src/parser/lexer.ts
743
+ var VoodooSyntaxError = class extends Error {
744
+ constructor(message, source, position) {
745
+ const pointer = `${source}
746
+ ${" ".repeat(Math.max(0, position))}^`;
747
+ super(`${message}
748
+
749
+ ${pointer}`);
750
+ __publicField(this, "source", source);
751
+ __publicField(this, "position", position);
752
+ this.name = "VoodooSyntaxError";
753
+ }
754
+ };
755
+ var PUNCTUATORS = [
756
+ ">>>=",
757
+ "===",
758
+ "!==",
759
+ "**=",
760
+ "...",
761
+ "<<=",
762
+ ">>=",
763
+ "&&=",
764
+ "||=",
765
+ "??=",
766
+ "?.",
767
+ "=>",
768
+ "==",
769
+ "!=",
770
+ "<=",
771
+ ">=",
772
+ "&&",
773
+ "||",
774
+ "??",
775
+ "**",
776
+ "++",
777
+ "--",
778
+ "+=",
779
+ "-=",
780
+ "*=",
781
+ "/=",
782
+ "%=",
783
+ "+",
784
+ "-",
785
+ "*",
786
+ "/",
787
+ "%",
788
+ "!",
789
+ "<",
790
+ ">",
791
+ "=",
792
+ "(",
793
+ ")",
794
+ "[",
795
+ "]",
796
+ "{",
797
+ "}",
798
+ ",",
799
+ ".",
800
+ "?",
801
+ ":",
802
+ ";"
803
+ ];
804
+ var IDENT_START = /[A-Za-z_$À-￿]/;
805
+ var IDENT_PART = /[A-Za-z0-9_$À-￿]/;
806
+ function isIdentStart(ch) {
807
+ return IDENT_START.test(ch);
808
+ }
809
+ function isIdentPart(ch) {
810
+ return IDENT_PART.test(ch);
811
+ }
812
+ function isDigit(ch) {
813
+ return ch >= "0" && ch <= "9";
814
+ }
815
+ var ESCAPES = {
816
+ n: "\n",
817
+ t: " ",
818
+ r: "\r",
819
+ b: "\b",
820
+ f: "\f",
821
+ v: "\v",
822
+ "0": "\0"
823
+ };
824
+ function tokenize(source) {
825
+ const tokens = [];
826
+ let i = 0;
827
+ const len = source.length;
828
+ while (i < len) {
829
+ const ch = source[i];
830
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v") {
831
+ i++;
832
+ continue;
833
+ }
834
+ if (ch === "/" && source[i + 1] === "/") {
835
+ while (i < len && source[i] !== "\n") i++;
836
+ continue;
837
+ }
838
+ if (ch === "/" && source[i + 1] === "*") {
839
+ const end = source.indexOf("*/", i + 2);
840
+ if (end === -1) throw new VoodooSyntaxError("Unclosed block comment", source, i);
841
+ i = end + 2;
842
+ continue;
843
+ }
844
+ const start = i;
845
+ if (isDigit(ch) || ch === "." && isDigit(source[i + 1])) {
846
+ let raw = "";
847
+ if (ch === "0" && (source[i + 1] === "x" || source[i + 1] === "X")) {
848
+ raw = "0x";
849
+ i += 2;
850
+ while (i < len && /[0-9a-fA-F_]/.test(source[i])) raw += source[i++];
851
+ } else if (ch === "0" && (source[i + 1] === "b" || source[i + 1] === "B")) {
852
+ raw = "0b";
853
+ i += 2;
854
+ while (i < len && /[01_]/.test(source[i])) raw += source[i++];
855
+ } else {
856
+ while (i < len && /[0-9_]/.test(source[i])) raw += source[i++];
857
+ if (source[i] === ".") {
858
+ raw += source[i++];
859
+ while (i < len && /[0-9_]/.test(source[i])) raw += source[i++];
860
+ }
861
+ if (source[i] === "e" || source[i] === "E") {
862
+ raw += source[i++];
863
+ if (source[i] === "+" || source[i] === "-") raw += source[i++];
864
+ while (i < len && isDigit(source[i])) raw += source[i++];
865
+ }
866
+ }
867
+ const parsed = Number(raw.replace(/_/g, ""));
868
+ if (Number.isNaN(parsed)) throw new VoodooSyntaxError("Invalid number", source, start);
869
+ tokens.push({ type: "num", value: raw, parsed, start, end: i });
870
+ continue;
871
+ }
872
+ if (ch === '"' || ch === "'") {
873
+ i++;
874
+ let out = "";
875
+ while (i < len && source[i] !== ch) {
876
+ if (source[i] === "\\") {
877
+ i++;
878
+ const esc = source[i];
879
+ if (esc === "u") {
880
+ if (source[i + 1] === "{") {
881
+ const close = source.indexOf("}", i);
882
+ if (close === -1)
883
+ throw new VoodooSyntaxError("Unclosed Unicode escape", source, start);
884
+ const digits = source.slice(i + 2, close);
885
+ if (!/^[0-9a-fA-F]+$/.test(digits) || parseInt(digits, 16) > 1114111)
886
+ throw new VoodooSyntaxError(
887
+ `Invalid Unicode escape "\\u{${digits}}"`,
888
+ source,
889
+ i - 1
890
+ );
891
+ out += String.fromCodePoint(parseInt(digits, 16));
892
+ i = close + 1;
893
+ } else {
894
+ const digits = source.slice(i + 1, i + 5);
895
+ if (!/^[0-9a-fA-F]{4}$/.test(digits))
896
+ throw new VoodooSyntaxError(
897
+ "Invalid Unicode escape: \\u needs 4 hexadecimal digits",
898
+ source,
899
+ i - 1
900
+ );
901
+ out += String.fromCharCode(parseInt(digits, 16));
902
+ i += 5;
903
+ }
904
+ } else if (esc === "x") {
905
+ const digits = source.slice(i + 1, i + 3);
906
+ if (!/^[0-9a-fA-F]{2}$/.test(digits))
907
+ throw new VoodooSyntaxError(
908
+ "Invalid hexadecimal escape: \\x needs 2 hexadecimal digits",
909
+ source,
910
+ i - 1
911
+ );
912
+ out += String.fromCharCode(parseInt(digits, 16));
913
+ i += 3;
914
+ } else {
915
+ out += ESCAPES[esc] ?? esc;
916
+ i++;
917
+ }
918
+ } else {
919
+ out += source[i++];
920
+ }
921
+ }
922
+ if (i >= len) throw new VoodooSyntaxError("Unclosed string", source, start);
923
+ i++;
924
+ tokens.push({ type: "str", value: out, parsed: out, start, end: i });
925
+ continue;
926
+ }
927
+ if (ch === "`") {
928
+ i++;
929
+ const quasis = [];
930
+ const exprs = [];
931
+ let current = "";
932
+ while (i < len && source[i] !== "`") {
933
+ if (source[i] === "\\") {
934
+ const esc = source[i + 1];
935
+ current += ESCAPES[esc] ?? esc;
936
+ i += 2;
937
+ continue;
938
+ }
939
+ if (source[i] === "$" && source[i + 1] === "{") {
940
+ quasis.push(current);
941
+ current = "";
942
+ i += 2;
943
+ let depth = 1;
944
+ let expr = "";
945
+ while (i < len) {
946
+ const c = source[i];
947
+ if (c === "{") depth++;
948
+ else if (c === "}") {
949
+ depth--;
950
+ if (depth === 0) break;
951
+ } else if (c === '"' || c === "'" || c === "`") {
952
+ const quote = c;
953
+ expr += source[i++];
954
+ while (i < len && source[i] !== quote) {
955
+ if (source[i] === "\\") expr += source[i++];
956
+ expr += source[i++];
957
+ }
958
+ }
959
+ expr += source[i++];
960
+ }
961
+ if (depth !== 0)
962
+ throw new VoodooSyntaxError("Unclosed template interpolation", source, start);
963
+ i++;
964
+ exprs.push(expr);
965
+ continue;
966
+ }
967
+ current += source[i++];
968
+ }
969
+ if (i >= len) throw new VoodooSyntaxError("Unclosed template literal", source, start);
970
+ i++;
971
+ quasis.push(current);
972
+ tokens.push({
973
+ type: "tpl",
974
+ value: source.slice(start, i),
975
+ tpl: { quasis, exprs },
976
+ start,
977
+ end: i
978
+ });
979
+ continue;
980
+ }
981
+ if (isIdentStart(ch)) {
982
+ let name = "";
983
+ while (i < len && isIdentPart(source[i])) name += source[i++];
984
+ tokens.push({ type: "ident", value: name, start, end: i });
985
+ continue;
986
+ }
987
+ let matched;
988
+ for (const p of PUNCTUATORS) {
989
+ if (source.startsWith(p, i)) {
990
+ if (p === "?." && isDigit(source[i + 2])) continue;
991
+ matched = p;
992
+ break;
993
+ }
994
+ }
995
+ if (matched) {
996
+ i += matched.length;
997
+ tokens.push({ type: "punct", value: matched, start, end: i });
998
+ continue;
999
+ }
1000
+ throw new VoodooSyntaxError(`Unexpected character "${ch}"`, source, i);
1001
+ }
1002
+ tokens.push({ type: "eof", value: "", start: len, end: len });
1003
+ return tokens;
1004
+ }
1005
+
1006
+ // src/parser/parser.ts
1007
+ var BINARY_PRECEDENCE = {
1008
+ "??": 1,
1009
+ "||": 2,
1010
+ "&&": 3,
1011
+ "==": 6,
1012
+ "!=": 6,
1013
+ "===": 6,
1014
+ "!==": 6,
1015
+ "<": 7,
1016
+ ">": 7,
1017
+ "<=": 7,
1018
+ ">=": 7,
1019
+ in: 7,
1020
+ instanceof: 7,
1021
+ "+": 9,
1022
+ "-": 9,
1023
+ "*": 10,
1024
+ "/": 10,
1025
+ "%": 10,
1026
+ "**": 11
1027
+ };
1028
+ var ASSIGN_OPS = /* @__PURE__ */ new Set(["=", "+=", "-=", "*=", "/=", "%=", "**=", "&&=", "||=", "??="]);
1029
+ var UNARY_OPS = /* @__PURE__ */ new Set(["!", "-", "+", "typeof", "void"]);
1030
+ var LITERALS = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(null), {
1031
+ true: true,
1032
+ false: false,
1033
+ null: null,
1034
+ undefined: void 0
1035
+ });
1036
+ var MAX_DEPTH = 1200;
1037
+ var MAX_TEMPLATE_DEPTH = 32;
1038
+ var templateDepth = 0;
1039
+ var Parser = class {
1040
+ constructor(tokens, source) {
1041
+ __publicField(this, "tokens", tokens);
1042
+ __publicField(this, "source", source);
1043
+ __publicField(this, "pos", 0);
1044
+ __publicField(this, "depth", 0);
1045
+ }
1046
+ peek(offset = 0) {
1047
+ return this.tokens[Math.min(this.pos + offset, this.tokens.length - 1)];
1048
+ }
1049
+ next() {
1050
+ return this.tokens[this.pos++];
1051
+ }
1052
+ isPunct(value, offset = 0) {
1053
+ const t = this.peek(offset);
1054
+ return t.type === "punct" && t.value === value;
1055
+ }
1056
+ isIdent(value, offset = 0) {
1057
+ const t = this.peek(offset);
1058
+ return t.type === "ident" && t.value === value;
1059
+ }
1060
+ expect(value) {
1061
+ if (!this.isPunct(value)) {
1062
+ const t = this.peek();
1063
+ throw new VoodooSyntaxError(
1064
+ `Expected "${value}" but found "${t.value || "end of expression"}"`,
1065
+ this.source,
1066
+ t.start
1067
+ );
1068
+ }
1069
+ return this.next();
1070
+ }
1071
+ /** Entry point: one or more expressions separated by `;` or `,` at the top. */
1072
+ parseProgram() {
1073
+ const body = [];
1074
+ while (this.peek().type !== "eof") {
1075
+ body.push(this.parseStatement());
1076
+ while (this.isPunct(";") || this.isPunct(",")) this.next();
1077
+ }
1078
+ if (body.length === 0) return { t: "lit", v: void 0 };
1079
+ if (body.length === 1) return body[0];
1080
+ return { t: "seq", body };
1081
+ }
1082
+ /**
1083
+ * Parses the body of an arrow function.
1084
+ *
1085
+ * A `{` right after `=>` opens a block, as in JavaScript, and the block's
1086
+ * last value is what the arrow returns. Without this, the common
1087
+ * `(() => { count = 42 })()` failed to parse, because `{` was read as the
1088
+ * start of an object literal and `=` inside it made no sense.
1089
+ *
1090
+ * To return an object literal, wrap it in parentheses exactly as JavaScript
1091
+ * requires: `() => ({ a: 1 })`.
1092
+ */
1093
+ parseArrowBody() {
1094
+ if (!this.isPunct("{")) return this.parseAssignment();
1095
+ this.next();
1096
+ const body = [];
1097
+ while (!this.isPunct("}") && this.peek().type !== "eof") {
1098
+ body.push(this.parseStatement());
1099
+ while (this.isPunct(";") || this.isPunct(",")) this.next();
1100
+ }
1101
+ this.expect("}");
1102
+ if (body.length === 0) return { t: "lit", v: void 0 };
1103
+ if (body.length === 1) return body[0];
1104
+ return { t: "seq", body };
1105
+ }
1106
+ /**
1107
+ * One statement. Only `if` needs its own form; everything else in this
1108
+ * language is an expression.
1109
+ */
1110
+ parseStatement() {
1111
+ if (this.peek().type === "ident" && this.peek().value === "if" && this.isPunct("(", 1)) {
1112
+ this.next();
1113
+ this.expect("(");
1114
+ const test = this.parseExpression();
1115
+ this.expect(")");
1116
+ const cons = this.parseBlockOrStatement();
1117
+ let alt = null;
1118
+ if (this.peek().type === "ident" && this.peek().value === "else") {
1119
+ this.next();
1120
+ alt = this.parseBlockOrStatement();
1121
+ }
1122
+ return { t: "if", test, cons, alt };
1123
+ }
1124
+ return this.parseExpression();
1125
+ }
1126
+ /** The body of an `if` or `else`, with or without braces. */
1127
+ parseBlockOrStatement() {
1128
+ if (!this.isPunct("{")) return this.parseStatement();
1129
+ this.next();
1130
+ const body = [];
1131
+ while (!this.isPunct("}") && this.peek().type !== "eof") {
1132
+ body.push(this.parseStatement());
1133
+ while (this.isPunct(";") || this.isPunct(",")) this.next();
1134
+ }
1135
+ this.expect("}");
1136
+ if (body.length === 0) return { t: "lit", v: void 0 };
1137
+ if (body.length === 1) return body[0];
1138
+ return { t: "seq", body };
1139
+ }
1140
+ parseExpression() {
1141
+ return this.parseAssignment();
1142
+ }
1143
+ /** Raises recursion level and rejects expression when exceeding limit. */
1144
+ enterLevel() {
1145
+ if (++this.depth > MAX_DEPTH) {
1146
+ const t = this.peek();
1147
+ throw new VoodooSyntaxError(
1148
+ `Expression too deeply nested (limit of ${MAX_DEPTH} levels)`,
1149
+ this.source,
1150
+ t.start
1151
+ );
1152
+ }
1153
+ }
1154
+ parseAssignment() {
1155
+ this.enterLevel();
1156
+ const node = this.parseAssignmentInternal();
1157
+ this.depth--;
1158
+ return node;
1159
+ }
1160
+ parseAssignmentInternal() {
1161
+ if (this.peek().type === "ident" && this.isPunct("=>", 1)) {
1162
+ const param = this.next().value;
1163
+ this.next();
1164
+ return { t: "arrow", params: [param], body: this.parseArrowBody() };
1165
+ }
1166
+ if (this.isPunct("(")) {
1167
+ const arrow = this.tryParseParenArrow();
1168
+ if (arrow) return arrow;
1169
+ }
1170
+ const left = this.parseConditional();
1171
+ const t = this.peek();
1172
+ if (t.type === "punct" && ASSIGN_OPS.has(t.value)) {
1173
+ if (left.t !== "id" && left.t !== "member") {
1174
+ throw new VoodooSyntaxError("Invalid assignment target", this.source, t.start);
1175
+ }
1176
+ this.next();
1177
+ const value = this.parseAssignment();
1178
+ return { t: "assign", op: t.value, target: left, value };
1179
+ }
1180
+ return left;
1181
+ }
1182
+ /**
1183
+ * Tries to read `( params ) =>`. If what comes after the closing parenthesis
1184
+ * is not `=>`, returns to original position and lets normal parsing continue.
1185
+ */
1186
+ tryParseParenArrow() {
1187
+ const start = this.pos;
1188
+ let depth = 0;
1189
+ let i = this.pos;
1190
+ for (; i < this.tokens.length; i++) {
1191
+ const t = this.tokens[i];
1192
+ if (t.type === "punct" && t.value === "(") depth++;
1193
+ else if (t.type === "punct" && t.value === ")") {
1194
+ depth--;
1195
+ if (depth === 0) break;
1196
+ } else if (t.type === "eof") break;
1197
+ }
1198
+ const after = this.tokens[i + 1];
1199
+ if (!after || after.type !== "punct" || after.value !== "=>") return null;
1200
+ this.next();
1201
+ const params = [];
1202
+ while (!this.isPunct(")")) {
1203
+ const t = this.next();
1204
+ if (t.type !== "ident") {
1205
+ this.pos = start;
1206
+ return null;
1207
+ }
1208
+ params.push(t.value);
1209
+ if (this.isPunct(",")) this.next();
1210
+ }
1211
+ this.expect(")");
1212
+ this.expect("=>");
1213
+ return { t: "arrow", params, body: this.parseArrowBody() };
1214
+ }
1215
+ parseConditional() {
1216
+ const test = this.parseBinary(0);
1217
+ if (this.isPunct("?")) {
1218
+ this.next();
1219
+ const cons = this.parseAssignment();
1220
+ this.expect(":");
1221
+ const alt = this.parseAssignment();
1222
+ return { t: "cond", test, cons, alt };
1223
+ }
1224
+ return test;
1225
+ }
1226
+ parseBinary(minPrec) {
1227
+ this.enterLevel();
1228
+ const node = this.parseBinaryInternal(minPrec);
1229
+ this.depth--;
1230
+ return node;
1231
+ }
1232
+ parseBinaryInternal(minPrec) {
1233
+ let left = this.parseUnary();
1234
+ for (; ; ) {
1235
+ const t = this.peek();
1236
+ const op = t.value;
1237
+ const isOperator = t.type === "punct" && op in BINARY_PRECEDENCE || t.type === "ident" && (op === "in" || op === "instanceof");
1238
+ if (!isOperator) break;
1239
+ const prec = BINARY_PRECEDENCE[op];
1240
+ if (prec === void 0 || prec <= minPrec) break;
1241
+ this.next();
1242
+ const right = this.parseBinary(op === "**" ? prec - 1 : prec);
1243
+ const kind = op === "&&" || op === "||" || op === "??" ? "logic" : "bin";
1244
+ left = { t: kind, op, l: left, r: right };
1245
+ }
1246
+ return left;
1247
+ }
1248
+ parseUnary() {
1249
+ this.enterLevel();
1250
+ const node = this.parseUnaryInternal();
1251
+ this.depth--;
1252
+ return node;
1253
+ }
1254
+ parseUnaryInternal() {
1255
+ const t = this.peek();
1256
+ if ((t.type === "punct" || t.type === "ident") && UNARY_OPS.has(t.value)) {
1257
+ this.next();
1258
+ return { t: "unary", op: t.value, a: this.parseUnary() };
1259
+ }
1260
+ if (t.type === "punct" && (t.value === "++" || t.value === "--")) {
1261
+ this.next();
1262
+ const arg = this.parseUnary();
1263
+ return { t: "update", op: t.value, a: arg, prefix: true };
1264
+ }
1265
+ let expr = this.parseCallMember();
1266
+ const post = this.peek();
1267
+ if (post.type === "punct" && (post.value === "++" || post.value === "--")) {
1268
+ this.next();
1269
+ expr = { t: "update", op: post.value, a: expr, prefix: false };
1270
+ }
1271
+ return expr;
1272
+ }
1273
+ parseCallMember() {
1274
+ let expr = this.parsePrimary();
1275
+ for (; ; ) {
1276
+ if (this.isPunct(".")) {
1277
+ this.next();
1278
+ const prop = this.next();
1279
+ if (prop.type !== "ident") {
1280
+ throw new VoodooSyntaxError("Invalid property name", this.source, prop.start);
1281
+ }
1282
+ expr = { t: "member", o: expr, p: { t: "lit", v: prop.value }, computed: false, opt: false };
1283
+ } else if (this.isPunct("?.")) {
1284
+ this.next();
1285
+ if (this.isPunct("(")) {
1286
+ expr = { t: "call", callee: expr, args: this.parseArguments(), opt: true };
1287
+ } else if (this.isPunct("[")) {
1288
+ this.next();
1289
+ const p = this.parseExpression();
1290
+ this.expect("]");
1291
+ expr = { t: "member", o: expr, p, computed: true, opt: true };
1292
+ } else {
1293
+ const prop = this.next();
1294
+ if (prop.type !== "ident") {
1295
+ throw new VoodooSyntaxError("Invalid property name", this.source, prop.start);
1296
+ }
1297
+ expr = {
1298
+ t: "member",
1299
+ o: expr,
1300
+ p: { t: "lit", v: prop.value },
1301
+ computed: false,
1302
+ opt: true
1303
+ };
1304
+ }
1305
+ } else if (this.isPunct("[")) {
1306
+ this.next();
1307
+ const p = this.parseExpression();
1308
+ this.expect("]");
1309
+ expr = { t: "member", o: expr, p, computed: true, opt: false };
1310
+ } else if (this.isPunct("(")) {
1311
+ expr = { t: "call", callee: expr, args: this.parseArguments(), opt: false };
1312
+ } else {
1313
+ return expr;
1314
+ }
1315
+ }
1316
+ }
1317
+ parseArguments() {
1318
+ this.expect("(");
1319
+ const args = [];
1320
+ while (!this.isPunct(")")) {
1321
+ if (this.isPunct("...")) {
1322
+ this.next();
1323
+ args.push({ t: "unary", op: "...", a: this.parseAssignment() });
1324
+ } else {
1325
+ args.push(this.parseAssignment());
1326
+ }
1327
+ if (this.isPunct(",")) this.next();
1328
+ else break;
1329
+ }
1330
+ this.expect(")");
1331
+ return args;
1332
+ }
1333
+ parsePrimary() {
1334
+ const t = this.peek();
1335
+ if (t.type === "ident" && t.value === "function") {
1336
+ this.next();
1337
+ if (this.peek().type === "ident") this.next();
1338
+ this.expect("(");
1339
+ const params = [];
1340
+ while (!this.isPunct(")")) {
1341
+ const param = this.next();
1342
+ if (param.type !== "ident") {
1343
+ throw new VoodooSyntaxError("Expected a parameter name", this.source, param.start);
1344
+ }
1345
+ params.push(param.value);
1346
+ if (this.isPunct(",")) this.next();
1347
+ }
1348
+ this.expect(")");
1349
+ return { t: "arrow", params, body: this.parseArrowBody() };
1350
+ }
1351
+ if (t.type === "num" || t.type === "str") {
1352
+ this.next();
1353
+ return { t: "lit", v: t.parsed };
1354
+ }
1355
+ if (t.type === "tpl") {
1356
+ this.next();
1357
+ const part = t.tpl;
1358
+ if (templateDepth >= MAX_TEMPLATE_DEPTH) {
1359
+ throw new VoodooSyntaxError(
1360
+ `Template literal too deeply nested (limit of ${MAX_TEMPLATE_DEPTH} levels)`,
1361
+ this.source,
1362
+ t.start
1363
+ );
1364
+ }
1365
+ templateDepth++;
1366
+ try {
1367
+ return {
1368
+ t: "tpl",
1369
+ quasis: part.quasis,
1370
+ exprs: part.exprs.map((src) => parse(src))
1371
+ };
1372
+ } finally {
1373
+ templateDepth--;
1374
+ }
1375
+ }
1376
+ if (t.type === "ident") {
1377
+ if (t.value in LITERALS) {
1378
+ this.next();
1379
+ return { t: "lit", v: LITERALS[t.value] };
1380
+ }
1381
+ this.next();
1382
+ return { t: "id", n: t.value };
1383
+ }
1384
+ if (t.type === "punct") {
1385
+ if (t.value === "(") {
1386
+ this.next();
1387
+ const expr = this.parseExpression();
1388
+ this.expect(")");
1389
+ return expr;
1390
+ }
1391
+ if (t.value === "[") return this.parseArrayLiteral();
1392
+ if (t.value === "{") return this.parseObjectLiteral();
1393
+ }
1394
+ throw new VoodooSyntaxError(
1395
+ `Unexpected token "${t.value || "end of expression"}"`,
1396
+ this.source,
1397
+ t.start
1398
+ );
1399
+ }
1400
+ parseArrayLiteral() {
1401
+ this.expect("[");
1402
+ const els = [];
1403
+ while (!this.isPunct("]")) {
1404
+ if (this.isPunct("...")) {
1405
+ this.next();
1406
+ els.push({ spread: this.parseAssignment() });
1407
+ } else {
1408
+ els.push(this.parseAssignment());
1409
+ }
1410
+ if (this.isPunct(",")) this.next();
1411
+ else break;
1412
+ }
1413
+ this.expect("]");
1414
+ return { t: "arr", els };
1415
+ }
1416
+ parseObjectLiteral() {
1417
+ this.expect("{");
1418
+ const props = [];
1419
+ while (!this.isPunct("}")) {
1420
+ if (this.isPunct("...")) {
1421
+ this.next();
1422
+ props.push({ key: null, spread: this.parseAssignment() });
1423
+ } else if (this.isPunct("[")) {
1424
+ this.next();
1425
+ const keyExpr = this.parseAssignment();
1426
+ this.expect("]");
1427
+ this.expect(":");
1428
+ props.push({ key: null, keyExpr, value: this.parseAssignment() });
1429
+ } else {
1430
+ if (this.peek().type === "ident" && this.peek().value === "get" && this.peek(1).type === "ident" && this.isPunct("(", 2)) {
1431
+ this.next();
1432
+ const nameToken = this.next();
1433
+ this.expect("(");
1434
+ this.expect(")");
1435
+ props.push({
1436
+ key: String(nameToken.value),
1437
+ getter: true,
1438
+ value: { t: "method", params: [], body: this.parseArrowBody() }
1439
+ });
1440
+ if (this.isPunct(",")) this.next();
1441
+ continue;
1442
+ }
1443
+ const keyToken = this.next();
1444
+ if (keyToken.type !== "ident" && keyToken.type !== "str" && keyToken.type !== "num") {
1445
+ throw new VoodooSyntaxError("Invalid object key", this.source, keyToken.start);
1446
+ }
1447
+ const key = String(keyToken.parsed ?? keyToken.value);
1448
+ if (this.isPunct(":")) {
1449
+ this.next();
1450
+ props.push({ key, value: this.parseAssignment() });
1451
+ } else if (this.isPunct("(")) {
1452
+ this.next();
1453
+ const params = [];
1454
+ while (!this.isPunct(")")) {
1455
+ const param = this.next();
1456
+ if (param.type !== "ident") {
1457
+ throw new VoodooSyntaxError("Expected a parameter name", this.source, param.start);
1458
+ }
1459
+ params.push(param.value);
1460
+ if (this.isPunct(",")) this.next();
1461
+ }
1462
+ this.expect(")");
1463
+ props.push({ key, value: { t: "method", params, body: this.parseArrowBody() } });
1464
+ } else {
1465
+ props.push({ key, value: { t: "id", n: key } });
1466
+ }
1467
+ }
1468
+ if (this.isPunct(",")) this.next();
1469
+ else break;
1470
+ }
1471
+ this.expect("}");
1472
+ return { t: "obj", props };
1473
+ }
1474
+ };
1475
+ var cache = /* @__PURE__ */ new Map();
1476
+ var MAX_CACHE = 2e3;
1477
+ function parse(source) {
1478
+ const cached = cache.get(source);
1479
+ if (cached) return cached;
1480
+ const node = new Parser(tokenize(source), source).parseProgram();
1481
+ if (cache.size >= MAX_CACHE) evictOldest();
1482
+ cache.set(source, node);
1483
+ return node;
1484
+ }
1485
+ function evictOldest() {
1486
+ const alvo = Math.floor(MAX_CACHE / 2);
1487
+ let removidos = 0;
1488
+ for (const chave of cache.keys()) {
1489
+ cache.delete(chave);
1490
+ if (++removidos >= alvo) break;
1491
+ }
1492
+ }
1493
+ var attributeCache = /* @__PURE__ */ new WeakMap();
1494
+ function readAttr(el, name) {
1495
+ const cached = attributeCache.get(el)?.get(name);
1496
+ if (cached !== void 0) return cached;
1497
+ return el.getAttribute(name);
1498
+ }
1499
+ function evaluateIn(expression, scope, context, el) {
1500
+ if (!expression) return void 0;
1501
+ try {
1502
+ return evaluate(parse(expression), scope);
1503
+ } catch (err) {
1504
+ handleError(err, context ? `${context} ("${expression}")` : `expression "${expression}"`);
1505
+ return void 0;
1506
+ }
1507
+ }
1508
+
1509
+ // src/utils/index.ts
1510
+ function parseDuration(value, fallback = 0) {
1511
+ if (value == null || value === "") return fallback;
1512
+ if (typeof value === "number") return value;
1513
+ const match = /^\s*([\d.]+)\s*(ms|s|m|h)?\s*$/i.exec(String(value));
1514
+ if (!match) return fallback;
1515
+ const amount = parseFloat(match[1]);
1516
+ switch ((match[2] || "ms").toLowerCase()) {
1517
+ case "s":
1518
+ return amount * 1e3;
1519
+ case "m":
1520
+ return amount * 6e4;
1521
+ case "h":
1522
+ return amount * 36e5;
1523
+ default:
1524
+ return amount;
1525
+ }
1526
+ }
1527
+
1528
+ // src/devtools/bus.ts
1529
+ var listeners = /* @__PURE__ */ new Map();
1530
+ var devtoolsBus = {
1531
+ /** Publishes an event. With no listeners, the call is practically free. */
1532
+ emit(type, data) {
1533
+ const set = listeners.get(type);
1534
+ if (!set || set.size === 0) return;
1535
+ for (const listener of [...set]) {
1536
+ try {
1537
+ listener(data);
1538
+ } catch (err) {
1539
+ console.error("[Voodoo] error in devtools listener:", err);
1540
+ }
1541
+ }
1542
+ },
1543
+ /** Subscribes to an event type. Returns the function that unsubscribes. */
1544
+ on(type, callback) {
1545
+ let set = listeners.get(type);
1546
+ if (!set) listeners.set(type, set = /* @__PURE__ */ new Set());
1547
+ set.add(callback);
1548
+ return () => {
1549
+ set?.delete(callback);
1550
+ };
1551
+ },
1552
+ /** Cancels a specific subscription. */
1553
+ off(type, callback) {
1554
+ listeners.get(type)?.delete(callback);
1555
+ },
1556
+ /** Removes all listeners of a type or all listeners. */
1557
+ clear(type) {
1558
+ if (type) listeners.delete(type);
1559
+ else listeners.clear();
1560
+ },
1561
+ /** Number of listeners registered for a type. */
1562
+ count(type) {
1563
+ return listeners.get(type)?.size ?? 0;
1564
+ }
1565
+ };
1566
+
1567
+ // src/socket/protocol.ts
1568
+ var ENGINE = {
1569
+ OPEN: "0",
1570
+ CLOSE: "1",
1571
+ PING: "2",
1572
+ PONG: "3",
1573
+ MESSAGE: "4",
1574
+ UPGRADE: "5",
1575
+ NOOP: "6"
1576
+ };
1577
+ var SIO = {
1578
+ CONNECT: 0,
1579
+ DISCONNECT: 1,
1580
+ EVENT: 2,
1581
+ ACK: 3,
1582
+ CONNECT_ERROR: 4,
1583
+ BINARY_EVENT: 5,
1584
+ BINARY_ACK: 6
1585
+ };
1586
+ function parseJson(text) {
1587
+ if (!text) return void 0;
1588
+ try {
1589
+ return JSON.parse(text);
1590
+ } catch {
1591
+ return void 0;
1592
+ }
1593
+ }
1594
+ function decodeSocketIo(body) {
1595
+ if (!body) return null;
1596
+ const type = Number(body[0]);
1597
+ if (!Number.isInteger(type) || type < 0 || type > 6) return null;
1598
+ let i = 1;
1599
+ let namespace = "/";
1600
+ if (body[i] === "/") {
1601
+ const comma = body.indexOf(",", i);
1602
+ if (comma === -1) {
1603
+ return { type, namespace: body.slice(i) };
1604
+ }
1605
+ namespace = body.slice(i, comma);
1606
+ i = comma + 1;
1607
+ }
1608
+ let ack;
1609
+ const ackStart = i;
1610
+ while (i < body.length && body.charCodeAt(i) >= 48 && body.charCodeAt(i) <= 57) i++;
1611
+ if (i > ackStart) ack = Number(body.slice(ackStart, i));
1612
+ const rest = body.slice(i);
1613
+ return { type, namespace, ack, data: parseJson(rest) };
1614
+ }
1615
+ function decodeEngine(raw) {
1616
+ if (typeof raw !== "string" || !raw) return { kind: "unknown", raw: String(raw ?? "") };
1617
+ const code = raw[0];
1618
+ const body = raw.slice(1);
1619
+ switch (code) {
1620
+ case ENGINE.OPEN: {
1621
+ const data = parseJson(body);
1622
+ return {
1623
+ kind: "open",
1624
+ handshake: {
1625
+ sid: data?.sid ?? "",
1626
+ // Server values take precedence. The defaults here are from Engine.IO
1627
+ // v4 and only come into play if the handshake is incomplete.
1628
+ pingInterval: Number(data?.pingInterval) || 25e3,
1629
+ pingTimeout: Number(data?.pingTimeout) || 2e4,
1630
+ upgrades: data?.upgrades,
1631
+ maxPayload: data?.maxPayload
1632
+ }
1633
+ };
1634
+ }
1635
+ case ENGINE.CLOSE:
1636
+ return { kind: "close" };
1637
+ case ENGINE.PING:
1638
+ return { kind: "ping" };
1639
+ case ENGINE.PONG:
1640
+ return { kind: "pong" };
1641
+ case ENGINE.MESSAGE: {
1642
+ const packet = decodeSocketIo(body);
1643
+ return packet ? { kind: "message", packet } : { kind: "unknown", raw };
1644
+ }
1645
+ case ENGINE.NOOP:
1646
+ return { kind: "noop" };
1647
+ default:
1648
+ return { kind: "unknown", raw };
1649
+ }
1650
+ }
1651
+ function encodeSocketIo(packet) {
1652
+ let out = ENGINE.MESSAGE + String(packet.type);
1653
+ if (packet.namespace && packet.namespace !== "/") out += `${packet.namespace},`;
1654
+ if (packet.ack !== void 0) out += String(packet.ack);
1655
+ if (packet.data !== void 0) out += JSON.stringify(packet.data);
1656
+ return out;
1657
+ }
1658
+ function engineURL(base, path = "/socket.io/") {
1659
+ const pathname = `/${path.replace(/^\/+|\/+$/g, "")}/`;
1660
+ const query = "EIO=4&transport=websocket";
1661
+ try {
1662
+ const u = new URL(base);
1663
+ u.pathname = pathname;
1664
+ u.search = query;
1665
+ return u.toString();
1666
+ } catch {
1667
+ return `${base.replace(/\/+$/, "")}${pathname}?${query}`;
1668
+ }
1669
+ }
1670
+
1671
+ // src/socket/index.ts
1672
+ var defaults = {
1673
+ baseURL: "",
1674
+ transport: "ws",
1675
+ reconnect: true,
1676
+ reconnectDelay: 500,
1677
+ reconnectMaxDelay: 3e4,
1678
+ reconnectMaxAttempts: Infinity,
1679
+ jitter: 0.3,
1680
+ heartbeat: 25e3,
1681
+ heartbeatTimeout: 1e4,
1682
+ pingPayload: "ping",
1683
+ pongPayload: "pong",
1684
+ queueLimit: 64,
1685
+ json: true,
1686
+ path: "/socket.io/",
1687
+ namespace: "/",
1688
+ auth: null,
1689
+ WebSocket: null,
1690
+ manual: false,
1691
+ joinEvent: "join",
1692
+ leaveEvent: "leave",
1693
+ presenceEvent: "room:members",
1694
+ memberJoinEvent: "room:joined",
1695
+ memberLeaveEvent: "room:left",
1696
+ roomBuffer: 50
1697
+ };
1698
+ var incomingInterceptors = [];
1699
+ var outgoingInterceptors = [];
1700
+ function use(list, fn) {
1701
+ list.push(fn);
1702
+ return () => {
1703
+ const i = list.indexOf(fn);
1704
+ if (i > -1) list.splice(i, 1);
1705
+ };
1706
+ }
1707
+ function apply(list, message) {
1708
+ let current = message;
1709
+ for (const fn of list) {
1710
+ if (!current) return null;
1711
+ const result = fn(current);
1712
+ if (result === null) return null;
1713
+ if (result) current = result;
1714
+ }
1715
+ return current;
1716
+ }
1717
+ var openConnections = /* @__PURE__ */ new Set();
1718
+ function sameMember(a, b) {
1719
+ if (a === b) return true;
1720
+ const ida = a && typeof a === "object" ? a.id : a;
1721
+ const idb = b && typeof b === "object" ? b.id : b;
1722
+ return ida !== void 0 && ida === idb;
1723
+ }
1724
+ function resolveSocketURL(url, baseURL = defaults.baseURL) {
1725
+ let address = url || "/";
1726
+ if (baseURL && !/^(wss?|https?):\/\//i.test(address) && !address.startsWith("//")) {
1727
+ address = `${baseURL.replace(/\/$/, "")}/${address.replace(/^\//, "")}`;
1728
+ }
1729
+ if (/^wss?:\/\//i.test(address)) return address;
1730
+ if (/^https?:\/\//i.test(address)) return address.replace(/^http/i, "ws");
1731
+ if (typeof location === "undefined" || !location.host) return address;
1732
+ const protocol = location.protocol === "https:" ? "wss:" : "ws:";
1733
+ return `${protocol}//${location.host}${address.startsWith("/") ? address : `/${address}`}`;
1734
+ }
1735
+ function constructor(options) {
1736
+ const chosen = options.WebSocket ?? defaults.WebSocket ?? globalThis.WebSocket;
1737
+ return typeof chosen === "function" ? chosen : null;
1738
+ }
1739
+ function socketSupported() {
1740
+ return constructor({}) !== null;
1741
+ }
1742
+ function createSocket(url, options = {}) {
1743
+ const opts = { ...defaults, ...options };
1744
+ const Impl = constructor(options);
1745
+ const base = resolveSocketURL(url, opts.baseURL);
1746
+ const socketIo = opts.transport === "socket.io";
1747
+ const address = socketIo ? engineURL(base, opts.path) : base;
1748
+ const state = reactive({
1749
+ state: "closed",
1750
+ connected: false,
1751
+ attempts: 0,
1752
+ queued: 0,
1753
+ error: null
1754
+ });
1755
+ const listeners2 = /* @__PURE__ */ new Map();
1756
+ const queue2 = [];
1757
+ const acks = /* @__PURE__ */ new Map();
1758
+ const rooms = /* @__PURE__ */ new Map();
1759
+ let ws = null;
1760
+ let nextAck = 1;
1761
+ let closedPurposefully = false;
1762
+ let handshake = null;
1763
+ let openedAt = 0;
1764
+ let reconnectTimer = null;
1765
+ let heartbeatTimer = null;
1766
+ let watchdogTimer = null;
1767
+ function on(event, listener) {
1768
+ let set = listeners2.get(event);
1769
+ if (!set) listeners2.set(event, set = /* @__PURE__ */ new Set());
1770
+ set.add(listener);
1771
+ return () => {
1772
+ set?.delete(listener);
1773
+ };
1774
+ }
1775
+ function once(event, listener) {
1776
+ const cancel = on(event, (data, ack) => {
1777
+ cancel();
1778
+ listener(data, ack);
1779
+ });
1780
+ return cancel;
1781
+ }
1782
+ function off(event, listener) {
1783
+ if (!event) {
1784
+ listeners2.clear();
1785
+ return;
1786
+ }
1787
+ if (!listener) {
1788
+ listeners2.delete(event);
1789
+ return;
1790
+ }
1791
+ listeners2.get(event)?.delete(listener);
1792
+ }
1793
+ function deliver(event, data, ack) {
1794
+ for (const name of event === "message" ? [event] : [event, "message"]) {
1795
+ const set = listeners2.get(name);
1796
+ if (!set) continue;
1797
+ for (const listener of [...set]) {
1798
+ try {
1799
+ listener(data, ack);
1800
+ } catch (err) {
1801
+ console.error("[Voodoo] error in socket listener:", err);
1802
+ }
1803
+ }
1804
+ }
1805
+ }
1806
+ function changeState(newState) {
1807
+ if (state.state === newState) return;
1808
+ state.state = newState;
1809
+ state.connected = newState === "open";
1810
+ deliver(`state:${newState}`, newState);
1811
+ }
1812
+ function registerError(message) {
1813
+ state.error = message;
1814
+ deliver("error", message);
1815
+ devtoolsBus.emit("network", {
1816
+ method: "WS",
1817
+ url: address,
1818
+ ok: false,
1819
+ error: message,
1820
+ source: "socket"
1821
+ });
1822
+ }
1823
+ function stopTimers() {
1824
+ if (reconnectTimer !== null) {
1825
+ clearTimeout(reconnectTimer);
1826
+ reconnectTimer = null;
1827
+ }
1828
+ if (heartbeatTimer !== null) {
1829
+ clearInterval(heartbeatTimer);
1830
+ heartbeatTimer = null;
1831
+ }
1832
+ if (watchdogTimer !== null) {
1833
+ clearTimeout(watchdogTimer);
1834
+ watchdogTimer = null;
1835
+ }
1836
+ }
1837
+ function armWatchdog(ms) {
1838
+ if (watchdogTimer !== null) clearTimeout(watchdogTimer);
1839
+ watchdogTimer = null;
1840
+ if (!ms || ms <= 0) return;
1841
+ watchdogTimer = setTimeout(() => {
1842
+ watchdogTimer = null;
1843
+ registerError("connection unresponsive");
1844
+ tearDown();
1845
+ }, ms);
1846
+ }
1847
+ function silenceWindow() {
1848
+ if (socketIo) {
1849
+ const h = handshake;
1850
+ return h ? h.pingInterval + h.pingTimeout : 0;
1851
+ }
1852
+ return opts.heartbeat > 0 ? opts.heartbeat + opts.heartbeatTimeout : 0;
1853
+ }
1854
+ function markAlive() {
1855
+ armWatchdog(silenceWindow());
1856
+ }
1857
+ function startHeartbeat() {
1858
+ if (socketIo || opts.heartbeat <= 0) return;
1859
+ if (heartbeatTimer !== null) clearInterval(heartbeatTimer);
1860
+ heartbeatTimer = setInterval(() => {
1861
+ if (opts.pingPayload == null) return;
1862
+ sendText(opts.pingPayload);
1863
+ }, opts.heartbeat);
1864
+ }
1865
+ function attemptDelay(n) {
1866
+ const raw = opts.reconnectDelay * 2 ** Math.max(0, n - 1);
1867
+ const cap = Math.min(raw, opts.reconnectMaxDelay);
1868
+ const deviation = cap * Math.min(Math.max(opts.jitter, 0), 1);
1869
+ return Math.max(0, Math.round(cap - deviation + Math.random() * deviation * 2));
1870
+ }
1871
+ function scheduleReconnect() {
1872
+ if (closedPurposefully || !opts.reconnect) {
1873
+ changeState("closed");
1874
+ return;
1875
+ }
1876
+ if (state.attempts >= opts.reconnectMaxAttempts) {
1877
+ registerError(`reconnection gave up after ${state.attempts} attempts`);
1878
+ changeState("closed");
1879
+ return;
1880
+ }
1881
+ state.attempts += 1;
1882
+ changeState("reconnecting");
1883
+ const delay = attemptDelay(state.attempts);
1884
+ deliver("reconnecting", { attempt: state.attempts, delay });
1885
+ if (reconnectTimer !== null) clearTimeout(reconnectTimer);
1886
+ reconnectTimer = setTimeout(() => {
1887
+ reconnectTimer = null;
1888
+ if (closedPurposefully) return;
1889
+ connect();
1890
+ }, delay);
1891
+ }
1892
+ function enqueue(text) {
1893
+ if (opts.queueLimit <= 0) return;
1894
+ if (queue2.length >= opts.queueLimit) {
1895
+ queue2.shift();
1896
+ }
1897
+ queue2.push(text);
1898
+ state.queued = queue2.length;
1899
+ }
1900
+ function drainQueue() {
1901
+ if (!queue2.length) return;
1902
+ const pending = queue2.splice(0, queue2.length);
1903
+ state.queued = 0;
1904
+ for (const text of pending) sendText(text);
1905
+ }
1906
+ function sendText(text) {
1907
+ if (ws && ws.readyState === 1 && (!socketIo || state.connected)) {
1908
+ try {
1909
+ ws.send(text);
1910
+ return true;
1911
+ } catch (err) {
1912
+ registerError(err?.message ?? "send failed");
1913
+ return false;
1914
+ }
1915
+ }
1916
+ enqueue(text);
1917
+ return false;
1918
+ }
1919
+ function emit(event, data, ack) {
1920
+ const message = apply(outgoingInterceptors, { event, data, url: address });
1921
+ if (!message) return false;
1922
+ devtoolsBus.emit("event", {
1923
+ type: `socket:${message.event}`,
1924
+ detail: message.data,
1925
+ source: "socket:out"
1926
+ });
1927
+ if (socketIo) {
1928
+ let num;
1929
+ if (ack) {
1930
+ num = nextAck++;
1931
+ acks.set(num, ack);
1932
+ }
1933
+ const args = message.data === void 0 ? [message.event] : [message.event, message.data];
1934
+ return sendText(
1935
+ encodeSocketIo({
1936
+ type: SIO.EVENT,
1937
+ namespace: opts.namespace,
1938
+ ack: num,
1939
+ data: args
1940
+ })
1941
+ );
1942
+ }
1943
+ return sendText(
1944
+ opts.json ? JSON.stringify({ event: message.event, data: message.data }) : String(message.data ?? message.event)
1945
+ );
1946
+ }
1947
+ function send(data) {
1948
+ const message = apply(outgoingInterceptors, { event: "message", data, url: address });
1949
+ if (!message) return false;
1950
+ const payload = message.data;
1951
+ const text = typeof payload === "string" ? payload : JSON.stringify(payload);
1952
+ if (socketIo) {
1953
+ return sendText(
1954
+ encodeSocketIo({
1955
+ type: SIO.EVENT,
1956
+ namespace: opts.namespace,
1957
+ data: ["message", payload]
1958
+ })
1959
+ );
1960
+ }
1961
+ return sendText(text);
1962
+ }
1963
+ function receive(event, data, raw, ack) {
1964
+ const message = apply(incomingInterceptors, {
1965
+ event,
1966
+ data,
1967
+ url: address,
1968
+ raw
1969
+ });
1970
+ if (!message) return;
1971
+ devtoolsBus.emit("event", {
1972
+ type: `socket:${message.event}`,
1973
+ detail: message.data,
1974
+ source: "socket:in"
1975
+ });
1976
+ routePresence(message.event, message.data);
1977
+ routeRoom(message.event, message.data, ack);
1978
+ deliver(message.event, message.data, ack);
1979
+ }
1980
+ function roomName(data) {
1981
+ if (!data || typeof data !== "object" || Array.isArray(data)) return null;
1982
+ const obj = data;
1983
+ const name = obj.room ?? obj.sala;
1984
+ return typeof name === "string" && name ? name : null;
1985
+ }
1986
+ function roomPayload(data) {
1987
+ const obj = data;
1988
+ if ("data" in obj) return obj.data;
1989
+ if ("dados" in obj) return obj.dados;
1990
+ return obj;
1991
+ }
1992
+ function deliverInRoom(room, event, data, ack) {
1993
+ for (const name of event === "message" ? [event] : [event, "message"]) {
1994
+ const set = room.listeners.get(name);
1995
+ if (!set) continue;
1996
+ for (const listener of [...set]) {
1997
+ try {
1998
+ listener(data, ack);
1999
+ } catch (err) {
2000
+ console.error("[Voodoo] error in room listener:", err);
2001
+ }
2002
+ }
2003
+ }
2004
+ }
2005
+ function routeRoom(event, data, ack) {
2006
+ const name = roomName(data);
2007
+ if (!name) return;
2008
+ const room = rooms.get(name);
2009
+ if (!room) return;
2010
+ if (event === opts.presenceEvent || event === opts.memberJoinEvent || event === opts.memberLeaveEvent) {
2011
+ return;
2012
+ }
2013
+ const payload = roomPayload(data);
2014
+ room.state.messages.push(payload);
2015
+ if (room.state.messages.length > room.buffer) {
2016
+ room.state.messages.splice(0, room.state.messages.length - room.buffer);
2017
+ }
2018
+ deliverInRoom(room, event, payload, ack);
2019
+ }
2020
+ function routePresence(event, data) {
2021
+ const name = roomName(data);
2022
+ if (!name) return;
2023
+ const room = rooms.get(name);
2024
+ if (!room) return;
2025
+ const obj = data;
2026
+ if (event === opts.presenceEvent) {
2027
+ const list = obj.members ?? obj.membros;
2028
+ if (Array.isArray(list)) room.state.members = [...list];
2029
+ return;
2030
+ }
2031
+ const member = obj.member ?? obj.membro ?? obj.id;
2032
+ if (member === void 0) return;
2033
+ if (event === opts.memberJoinEvent) {
2034
+ if (!room.state.members.some((m) => sameMember(m, member))) {
2035
+ room.state.members.push(member);
2036
+ }
2037
+ deliverInRoom(room, "entrou", member);
2038
+ return;
2039
+ }
2040
+ if (event === opts.memberLeaveEvent) {
2041
+ const i = room.state.members.findIndex((m) => sameMember(m, member));
2042
+ if (i > -1) room.state.members.splice(i, 1);
2043
+ deliverInRoom(room, "saiu", member);
2044
+ }
2045
+ }
2046
+ function requestJoin(room, name) {
2047
+ room.state.state = "joining";
2048
+ emit(opts.joinEvent, { room: name, private: room.private });
2049
+ }
2050
+ function rejoinRooms() {
2051
+ for (const [name, room] of rooms) {
2052
+ if (room.state.state === "left") continue;
2053
+ requestJoin(room, name);
2054
+ }
2055
+ }
2056
+ function join(name, config2 = {}) {
2057
+ const existing = rooms.get(name);
2058
+ if (existing && existing.state.state !== "left") return existing.public;
2059
+ const isPrivate = config2.privada ?? config2.private ?? false;
2060
+ const roomState = reactive({
2061
+ state: "joining",
2062
+ members: [],
2063
+ messages: []
2064
+ });
2065
+ const roomListeners = /* @__PURE__ */ new Map();
2066
+ const sendInRoom = (event, data, target2) => emit(event, target2 ? { room: name, to: target2, data } : { room: name, data });
2067
+ const public_ = {
2068
+ get name() {
2069
+ return name;
2070
+ },
2071
+ get private() {
2072
+ return isPrivate;
2073
+ },
2074
+ get privada() {
2075
+ return isPrivate;
2076
+ },
2077
+ get state() {
2078
+ return roomState.state;
2079
+ },
2080
+ get estado() {
2081
+ return roomState.state;
2082
+ },
2083
+ get members() {
2084
+ return roomState.members;
2085
+ },
2086
+ get membros() {
2087
+ return roomState.members;
2088
+ },
2089
+ get messages() {
2090
+ return roomState.messages;
2091
+ },
2092
+ get mensagens() {
2093
+ return roomState.messages;
2094
+ },
2095
+ on(event, listener) {
2096
+ let set = roomListeners.get(event);
2097
+ if (!set) roomListeners.set(event, set = /* @__PURE__ */ new Set());
2098
+ set.add(listener);
2099
+ return () => {
2100
+ set?.delete(listener);
2101
+ };
2102
+ },
2103
+ off(event, listener) {
2104
+ if (!event) roomListeners.clear();
2105
+ else if (!listener) roomListeners.delete(event);
2106
+ else roomListeners.get(event)?.delete(listener);
2107
+ },
2108
+ emit: (event, data) => sendInRoom(event, data),
2109
+ enviar: (event, data) => sendInRoom(event, data),
2110
+ to: (target2) => ({
2111
+ emit: (event, data) => sendInRoom(event, data, target2)
2112
+ }),
2113
+ leave: () => leave(name),
2114
+ sair: () => leave(name)
2115
+ };
2116
+ const internal = {
2117
+ public: public_,
2118
+ state: roomState,
2119
+ listeners: roomListeners,
2120
+ private: isPrivate,
2121
+ buffer: config2.buffer ?? opts.roomBuffer
2122
+ };
2123
+ rooms.set(name, internal);
2124
+ requestJoin(internal, name);
2125
+ if (state.connected) roomState.state = "joined";
2126
+ return public_;
2127
+ }
2128
+ function leave(name) {
2129
+ const room = rooms.get(name);
2130
+ if (!room) return;
2131
+ rooms.delete(name);
2132
+ room.state.state = "left";
2133
+ room.listeners.clear();
2134
+ room.state.members = [];
2135
+ if (state.connected) emit(opts.leaveEvent, { room: name });
2136
+ }
2137
+ function to(target2) {
2138
+ return {
2139
+ emit: (event, data) => emit(event, { to: target2, data })
2140
+ };
2141
+ }
2142
+ function receiveNative(raw) {
2143
+ if (typeof raw !== "string") {
2144
+ receive("message", raw);
2145
+ return;
2146
+ }
2147
+ if (opts.pongPayload != null && raw === opts.pongPayload) return;
2148
+ let payload = raw;
2149
+ if (opts.json) {
2150
+ const start = raw.trimStart()[0];
2151
+ if (start === "{" || start === "[") {
2152
+ try {
2153
+ payload = JSON.parse(raw);
2154
+ } catch {
2155
+ }
2156
+ }
2157
+ }
2158
+ if (payload && typeof payload === "object" && !Array.isArray(payload)) {
2159
+ const obj = payload;
2160
+ const name = obj.event ?? obj.type;
2161
+ if (typeof name === "string" && name) {
2162
+ receive(name, "data" in obj ? obj.data : obj, raw);
2163
+ return;
2164
+ }
2165
+ }
2166
+ receive("message", payload, raw);
2167
+ }
2168
+ function receiveSocketIo(raw) {
2169
+ const packet = decodeEngine(raw);
2170
+ switch (packet.kind) {
2171
+ case "open":
2172
+ handshake = packet.handshake;
2173
+ sendHandshakeConnect();
2174
+ markAlive();
2175
+ return;
2176
+ case "ping":
2177
+ ws?.send(ENGINE.PONG);
2178
+ markAlive();
2179
+ return;
2180
+ case "pong":
2181
+ case "noop":
2182
+ markAlive();
2183
+ return;
2184
+ case "close":
2185
+ tearDown();
2186
+ return;
2187
+ case "message":
2188
+ break;
2189
+ default:
2190
+ markAlive();
2191
+ return;
2192
+ }
2193
+ const { packet: socketPacket } = packet;
2194
+ switch (socketPacket.type) {
2195
+ case SIO.CONNECT:
2196
+ confirmOpen();
2197
+ return;
2198
+ case SIO.CONNECT_ERROR: {
2199
+ const data = socketPacket.data;
2200
+ registerError(data?.message ?? "connection refused by server");
2201
+ tearDown();
2202
+ return;
2203
+ }
2204
+ case SIO.DISCONNECT:
2205
+ tearDown();
2206
+ return;
2207
+ case SIO.ACK: {
2208
+ const response = Array.isArray(socketPacket.data) ? socketPacket.data[0] : socketPacket.data;
2209
+ if (socketPacket.ack !== void 0) {
2210
+ const callback = acks.get(socketPacket.ack);
2211
+ acks.delete(socketPacket.ack);
2212
+ callback?.(response);
2213
+ }
2214
+ return;
2215
+ }
2216
+ case SIO.EVENT: {
2217
+ const args = Array.isArray(socketPacket.data) ? socketPacket.data : [];
2218
+ const name = typeof args[0] === "string" ? args[0] : "message";
2219
+ const payload = args.length > 2 ? args.slice(1) : args[1];
2220
+ let responder;
2221
+ if (socketPacket.ack !== void 0) {
2222
+ const num = socketPacket.ack;
2223
+ responder = (response) => {
2224
+ sendText(
2225
+ encodeSocketIo({
2226
+ type: SIO.ACK,
2227
+ namespace: opts.namespace,
2228
+ ack: num,
2229
+ data: [response]
2230
+ })
2231
+ );
2232
+ };
2233
+ }
2234
+ receive(name, payload, typeof raw === "string" ? raw : void 0, responder);
2235
+ return;
2236
+ }
2237
+ default:
2238
+ warnOnce(
2239
+ `socket-packet:${address}`,
2240
+ `Socket.IO packet type ${socketPacket.type} ignored: binary attachments are not implemented in this client.`
2241
+ );
2242
+ }
2243
+ }
2244
+ function sendHandshakeConnect() {
2245
+ ws?.send(
2246
+ encodeSocketIo({
2247
+ type: SIO.CONNECT,
2248
+ namespace: opts.namespace,
2249
+ data: options.auth ?? defaults.auth ?? void 0
2250
+ })
2251
+ );
2252
+ }
2253
+ function confirmOpen() {
2254
+ state.attempts = 0;
2255
+ state.error = null;
2256
+ openedAt = Date.now();
2257
+ changeState("open");
2258
+ startHeartbeat();
2259
+ markAlive();
2260
+ rejoinRooms();
2261
+ drainQueue();
2262
+ for (const room of rooms.values()) {
2263
+ if (room.state.state === "joining") room.state.state = "joined";
2264
+ }
2265
+ deliver("open", { url: address });
2266
+ devtoolsBus.emit("network", {
2267
+ method: "WS",
2268
+ url: address,
2269
+ status: 101,
2270
+ ok: true,
2271
+ source: "socket"
2272
+ });
2273
+ }
2274
+ function releaseWs() {
2275
+ const prev = ws;
2276
+ if (prev) {
2277
+ prev.onopen = null;
2278
+ prev.onclose = null;
2279
+ prev.onerror = null;
2280
+ prev.onmessage = null;
2281
+ }
2282
+ ws = null;
2283
+ return prev;
2284
+ }
2285
+ function tearDown() {
2286
+ const prev = releaseWs();
2287
+ handshake = null;
2288
+ if (heartbeatTimer !== null) {
2289
+ clearInterval(heartbeatTimer);
2290
+ heartbeatTimer = null;
2291
+ }
2292
+ if (watchdogTimer !== null) {
2293
+ clearTimeout(watchdogTimer);
2294
+ watchdogTimer = null;
2295
+ }
2296
+ state.connected = false;
2297
+ try {
2298
+ prev?.close();
2299
+ } catch {
2300
+ }
2301
+ deliver("close", { url: address });
2302
+ scheduleReconnect();
2303
+ }
2304
+ function connect() {
2305
+ if (!Impl) return;
2306
+ if (ws) return;
2307
+ changeState(state.attempts > 0 ? "reconnecting" : "connecting");
2308
+ let newWs;
2309
+ try {
2310
+ newWs = new Impl(address, opts.protocols);
2311
+ } catch (err) {
2312
+ registerError(err?.message ?? "failed to open connection");
2313
+ scheduleReconnect();
2314
+ return;
2315
+ }
2316
+ ws = newWs;
2317
+ newWs.onopen = () => {
2318
+ if (ws !== newWs) return;
2319
+ if (socketIo) markAlive();
2320
+ else confirmOpen();
2321
+ };
2322
+ newWs.onmessage = (event) => {
2323
+ if (ws !== newWs) return;
2324
+ markAlive();
2325
+ if (socketIo) receiveSocketIo(event?.data);
2326
+ else receiveNative(event?.data);
2327
+ };
2328
+ newWs.onerror = () => {
2329
+ if (ws !== newWs) return;
2330
+ registerError("connection failed");
2331
+ };
2332
+ newWs.onclose = (event) => {
2333
+ if (ws !== newWs) return;
2334
+ releaseWs();
2335
+ handshake = null;
2336
+ if (heartbeatTimer !== null) {
2337
+ clearInterval(heartbeatTimer);
2338
+ heartbeatTimer = null;
2339
+ }
2340
+ if (watchdogTimer !== null) {
2341
+ clearTimeout(watchdogTimer);
2342
+ watchdogTimer = null;
2343
+ }
2344
+ state.connected = false;
2345
+ const detail = event;
2346
+ deliver("close", { url: address, code: detail?.code, reason: detail?.reason });
2347
+ devtoolsBus.emit("network", {
2348
+ method: "WS",
2349
+ url: address,
2350
+ status: detail?.code,
2351
+ ok: true,
2352
+ duration: openedAt ? Date.now() - openedAt : void 0,
2353
+ source: "socket"
2354
+ });
2355
+ scheduleReconnect();
2356
+ };
2357
+ }
2358
+ function openConnection() {
2359
+ closedPurposefully = false;
2360
+ if (!Impl) return;
2361
+ openConnections.add(instance);
2362
+ if (ws || reconnectTimer !== null) return;
2363
+ connect();
2364
+ }
2365
+ function closeConnection(code, reason) {
2366
+ closedPurposefully = true;
2367
+ stopTimers();
2368
+ changeState("closing");
2369
+ const prev = releaseWs();
2370
+ handshake = null;
2371
+ acks.clear();
2372
+ queue2.length = 0;
2373
+ state.queued = 0;
2374
+ state.attempts = 0;
2375
+ for (const [name, room] of rooms) {
2376
+ room.state.state = "left";
2377
+ room.listeners.clear();
2378
+ room.state.members = [];
2379
+ rooms.delete(name);
2380
+ }
2381
+ try {
2382
+ prev?.close(code, reason);
2383
+ } catch {
2384
+ }
2385
+ openConnections.delete(instance);
2386
+ changeState("closed");
2387
+ deliver("close", { url: address, code, reason });
2388
+ }
2389
+ const instance = {
2390
+ get url() {
2391
+ return address;
2392
+ },
2393
+ get state() {
2394
+ return state.state;
2395
+ },
2396
+ get connected() {
2397
+ return state.connected;
2398
+ },
2399
+ get attempts() {
2400
+ return state.attempts;
2401
+ },
2402
+ get queued() {
2403
+ return state.queued;
2404
+ },
2405
+ get error() {
2406
+ return state.error;
2407
+ },
2408
+ get raw() {
2409
+ return ws;
2410
+ },
2411
+ get rooms() {
2412
+ return [...rooms.values()].map((r) => r.public);
2413
+ },
2414
+ on,
2415
+ once,
2416
+ off,
2417
+ emit,
2418
+ send,
2419
+ open: openConnection,
2420
+ close: closeConnection,
2421
+ join,
2422
+ leave,
2423
+ to
2424
+ };
2425
+ if (!Impl) {
2426
+ state.error = "WebSocket unavailable in this environment";
2427
+ return instance;
2428
+ }
2429
+ if (!opts.manual) openConnection();
2430
+ else openConnections.add(instance);
2431
+ return instance;
2432
+ }
2433
+ var factory = ((url, options = {}) => createSocket(url, options));
2434
+ Object.assign(factory, {
2435
+ defaults,
2436
+ interceptors: {
2437
+ incoming: { use: (fn) => use(incomingInterceptors, fn) },
2438
+ outgoing: { use: (fn) => use(outgoingInterceptors, fn) }
2439
+ },
2440
+ close() {
2441
+ for (const s of [...openConnections]) s.close();
2442
+ },
2443
+ supported: socketSupported,
2444
+ setWebSocket(impl) {
2445
+ defaults.WebSocket = impl;
2446
+ }
2447
+ });
2448
+ Object.defineProperty(factory, "open", {
2449
+ get: () => [...openConnections],
2450
+ enumerable: true
2451
+ });
2452
+ var socket = factory;
2453
+
2454
+ // src/directives/socket.ts
2455
+ function aliasLegacy(view, pairs) {
2456
+ for (const [old, canonical] of pairs) {
2457
+ Object.defineProperty(view, old, {
2458
+ enumerable: false,
2459
+ configurable: true,
2460
+ get() {
2461
+ return view[canonical];
2462
+ },
2463
+ set(value) {
2464
+ view[canonical] = value;
2465
+ }
2466
+ });
2467
+ }
2468
+ }
2469
+ function attr(el, name) {
2470
+ return readAttr(el, `${config.prefix}${name}`);
2471
+ }
2472
+ var connections = /* @__PURE__ */ new WeakMap();
2473
+ function closest(el, map) {
2474
+ let current = el;
2475
+ while (current) {
2476
+ const found = map.get(current);
2477
+ if (found) return found;
2478
+ current = current.parentElement;
2479
+ }
2480
+ return null;
2481
+ }
2482
+ function resolveText(expression, scope, context) {
2483
+ const text = expression.trim();
2484
+ if (!text) return "";
2485
+ if (/^[A-Za-z_$][\w$]*$/.test(text)) {
2486
+ const value2 = scope.has(text) ? scope.get(text) : void 0;
2487
+ return typeof value2 === "string" && value2 ? value2 : text;
2488
+ }
2489
+ if (/^(wss?|https?):\/\//i.test(text) || /^[\w:.\-/]+$/.test(text)) return text;
2490
+ const value = evaluateIn(text, scope, context);
2491
+ return typeof value === "string" && value ? value : text;
2492
+ }
2493
+ function dispatch(el, type, detail) {
2494
+ el.dispatchEvent(new CustomEvent(type, { detail, bubbles: true }));
2495
+ }
2496
+ defineDirective(
2497
+ "socket",
2498
+ ({ el, scope, expression, modifiers, cleanup, effect: effect2 }) => {
2499
+ const name = attr(el, "socket-as") || "$socket";
2500
+ if (!socketSupported()) {
2501
+ el.setAttribute("data-socket", "unsupported");
2502
+ scope.set(
2503
+ name,
2504
+ reactive({
2505
+ connected: false,
2506
+ state: "closed",
2507
+ error: "WebSocket unavailable in this environment",
2508
+ attempts: 0,
2509
+ messages: [],
2510
+ send: () => false,
2511
+ open: () => void 0,
2512
+ close: () => void 0,
2513
+ socket: null
2514
+ })
2515
+ );
2516
+ dispatch(el, "voodoo:socket-unsupported", { url: expression });
2517
+ return;
2518
+ }
2519
+ const limit = Number(attr(el, "socket-buffer") ?? 50);
2520
+ const transport = attr(el, "socket-transport") || "ws";
2521
+ const reconnect = !modifiers["no-reconnect"] && modifiers.reconnect !== "false" && attr(el, "socket-reconnect") !== "false";
2522
+ const options = {
2523
+ transport: transport === "socket.io" ? "socket.io" : "ws",
2524
+ manual: !!modifiers.manual,
2525
+ reconnect
2526
+ };
2527
+ if (modifiers.json) options.json = modifiers.json !== "false";
2528
+ const path = attr(el, "socket-path");
2529
+ if (path) options.path = path;
2530
+ const heartbeat = attr(el, "socket-heartbeat");
2531
+ if (heartbeat !== null) options.heartbeat = parseDuration(heartbeat, 25e3);
2532
+ const s = createSocket(resolveText(expression, scope, "v-socket") || "/", options);
2533
+ connections.set(el, s);
2534
+ el.setAttribute("data-socket", "ready");
2535
+ function send(event, ...rest) {
2536
+ if (typeof event !== "string") return s.send(event);
2537
+ return rest.length ? s.emit(event, rest[0]) : s.emit(event);
2538
+ }
2539
+ const view = reactive({
2540
+ connected: s.connected,
2541
+ state: s.state,
2542
+ error: s.error,
2543
+ attempts: s.attempts,
2544
+ messages: [],
2545
+ send,
2546
+ open: () => s.open(),
2547
+ close: () => s.close(),
2548
+ socket: s
2549
+ });
2550
+ aliasLegacy(view, [
2551
+ ["conectado", "connected"],
2552
+ ["estado", "state"],
2553
+ ["mensagens", "messages"],
2554
+ ["erro", "error"],
2555
+ ["tentativas", "attempts"],
2556
+ ["enviar", "send"],
2557
+ ["abrir", "open"],
2558
+ ["fechar", "close"]
2559
+ ]);
2560
+ scope.set(name, view);
2561
+ effect2(() => {
2562
+ view.connected = s.connected;
2563
+ view.state = s.state;
2564
+ view.error = s.error;
2565
+ view.attempts = s.attempts;
2566
+ });
2567
+ const unsubscribe = [
2568
+ s.on("message", (data) => {
2569
+ view.messages.push(data);
2570
+ if (view.messages.length > limit) {
2571
+ view.messages.splice(0, view.messages.length - limit);
2572
+ }
2573
+ }),
2574
+ s.on("open", () => dispatch(el, "voodoo:socket-open", { url: s.url })),
2575
+ s.on("close", (d) => dispatch(el, "voodoo:socket-close", d)),
2576
+ s.on("error", (d) => dispatch(el, "voodoo:socket-error", d))
2577
+ ];
2578
+ cleanup(() => {
2579
+ for (const stop of unsubscribe) stop();
2580
+ s.off();
2581
+ s.close();
2582
+ connections.delete(el);
2583
+ });
2584
+ },
2585
+ { priority: PRIORITY.DATA }
2586
+ );
2587
+ defineDirective(
2588
+ "room",
2589
+ ({ el, scope, expression, modifiers, cleanup, effect: effect2 }) => {
2590
+ const s = closest(el, connections);
2591
+ if (!s) return;
2592
+ const roomName = resolveText(expression, scope, "v-room");
2593
+ if (!roomName) return;
2594
+ const room = s.join(roomName, {
2595
+ private: !!modifiers.private || !!modifiers.privada,
2596
+ buffer: Number(attr(el, "room-buffer") ?? 50)
2597
+ });
2598
+ const view = reactive({
2599
+ name: roomName,
2600
+ private: room.private,
2601
+ state: room.state,
2602
+ members: room.members,
2603
+ messages: room.messages,
2604
+ /** Sends to the room. With `to`, only to that recipient. */
2605
+ send: (event, data, to) => to ? room.to(to).emit(event, data) : room.emit(event, data),
2606
+ leave: () => room.leave(),
2607
+ room
2608
+ });
2609
+ aliasLegacy(view, [
2610
+ ["membros", "members"],
2611
+ ["mensagens", "messages"],
2612
+ ["estado", "state"],
2613
+ ["nome", "name"],
2614
+ ["privada", "private"],
2615
+ ["enviar", "send"],
2616
+ ["sair", "leave"]
2617
+ ]);
2618
+ scope.set(attr(el, "room-as") || "$room", view);
2619
+ effect2(() => {
2620
+ view.state = room.state;
2621
+ view.members = room.members;
2622
+ view.messages = room.messages;
2623
+ });
2624
+ const unsubscribe = [
2625
+ room.on("joined", (m) => dispatch(el, "voodoo:room-join", m)),
2626
+ room.on("left", (m) => dispatch(el, "voodoo:room-leave", m))
2627
+ ];
2628
+ cleanup(() => {
2629
+ for (const stop of unsubscribe) stop();
2630
+ room.off();
2631
+ room.leave();
2632
+ });
2633
+ },
2634
+ // After `v-socket`, so the connection exists when the room asks to join.
2635
+ { priority: PRIORITY.DATA - 1 }
2636
+ );
2637
+ defineDirective("on-socket", ({ el, scope, arg, expression, cleanup }) => {
2638
+ if (!arg) return;
2639
+ const target2 = closest(el, connections);
2640
+ if (!target2) return;
2641
+ const unsubscribe = target2.on(arg, (data, ack) => {
2642
+ const local = scope.child({ $event: data, $ack: ack, $el: el });
2643
+ const value = evaluateIn(expression, local, `v-on-socket:${arg}`);
2644
+ if (typeof value === "function") value.call(scope.data, data);
2645
+ });
2646
+ cleanup(unsubscribe);
2647
+ });
2648
+ for (const nome of [
2649
+ "socket-transport",
2650
+ "socket-as",
2651
+ "socket-buffer",
2652
+ "socket-path",
2653
+ "socket-heartbeat",
2654
+ "socket-reconnect",
2655
+ "room-as",
2656
+ "room-buffer"
2657
+ ]) {
2658
+ defineDirective(nome, () => void 0, { priority: PRIORITY.TRANSITION });
2659
+ }
2660
+
2661
+ // src/socket/plugin.ts
2662
+ var voodooSocket = {
2663
+ name: "socket",
2664
+ install(V) {
2665
+ if (!V.socket) V.socket = socket;
2666
+ }
2667
+ };
2668
+ var target = globalThis.V;
2669
+ if (target && typeof target === "object" && !target.socket) target.socket = socket;
2670
+ var plugin_default = voodooSocket;
2671
+
2672
+ exports.ENGINE = ENGINE;
2673
+ exports.SIO = SIO;
2674
+ exports.createSocket = createSocket;
2675
+ exports.decodeEngine = decodeEngine;
2676
+ exports.decodeSocketIo = decodeSocketIo;
2677
+ exports.default = plugin_default;
2678
+ exports.encodeSocketIo = encodeSocketIo;
2679
+ exports.engineURL = engineURL;
2680
+ exports.resolveSocketURL = resolveSocketURL;
2681
+ exports.socket = socket;
2682
+ exports.socketSupported = socketSupported;
2683
+ exports.voodooSocket = voodooSocket;
2684
+ //# sourceMappingURL=socket.cjs.map
2685
+ //# sourceMappingURL=socket.cjs.map