@pulse-js/core 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,172 +1,97 @@
1
1
  <div align="center">
2
-
3
2
  <img width="200" height="200" alt="logo" src="https://raw.githubusercontent.com/ZtaMDev/Pulse/refs/heads/main/pulse.svg" />
4
3
 
5
- # Pulse-JS
4
+ # Pulse-JS v2.0
6
5
 
7
6
  [![npm version](https://img.shields.io/npm/v/@pulse-js/core.svg?color=blue)](https://www.npmjs.com/package/@pulse-js/core)
8
7
 
9
- > A semantic reactivity system for modern applications. Separate reactive data (sources) from business conditions (guards) with a declarative, composable, and observable approach.
8
+ > A semantic reactivity system for modern applications. Separate reactive state (pulse) from business conditions (guards) with a declarative, composable, and proxied approach.
10
9
 
11
10
  Official [Documentation](https://pulse-js.vercel.app)
12
11
 
13
- Pulse differs from traditional signals or state managers by treating `Conditions` as first-class citizens. Instead of embedding complex boolean logic inside components or selectors, you define **Semantic Guards** that can be observed, composed, and debugged independently.
12
+ Pulse differs from traditional signals or state managers by treating `Conditions` as first-class citizens. Instead of embedding complex boolean logic inside components, you define **Semantic Guards** that are observed, composed, and debugged independently.
14
13
 
15
14
  </div>
16
15
 
17
16
  ## Installation
18
17
 
19
- ```bash
20
- npm install @pulse-js/core @pulse-js/tools
21
- ```
22
-
23
- ### or
24
-
25
18
  ```bash
26
19
  bun add @pulse-js/core @pulse-js/tools
27
20
  ```
28
21
 
29
- Pulse works with React via adapters like `@pulse-js/react`.
30
-
31
- ```bash
32
- bun add @pulse-js/react
33
- ```
34
-
35
22
  ## Core Concepts
36
23
 
37
- ### Sources (Refined Data)
24
+ ### Pulse Objects (Universal Reactivity)
38
25
 
39
- Sources are the primitive containers for your application state. They hold values and notify dependents when those values change.
26
+ `pulse()` creates a deep reactive Proxy. Use it for complex objects and arrays. Track property access automatically and mutate state directly.
40
27
 
41
28
  ```typescript
42
- import { source } from "@pulse-js/core";
29
+ import { pulse } from "@pulse-js/core";
30
+
31
+ const user = pulse({
32
+ name: "Alice",
33
+ role: "admin",
34
+ increment() {
35
+ this.stats.clicks++;
36
+ },
37
+ stats: { clicks: 0 },
38
+ });
43
39
 
44
- // Create a source
45
- const user = source({ name: "Alice", id: 1 });
46
- const rawCount = source(0);
40
+ // Mutate directly - it's reactive!
41
+ user.name = "Bob";
42
+ user.increment();
43
+ ```
47
44
 
48
- // Read the value (dependencies are tracked automatically if called inside a Guard)
49
- console.log(user());
45
+ ### Sources (Primitive Records)
50
46
 
51
- // Update the value
52
- user.set({ name: "Bob", id: 1 });
47
+ Sources are primitive containers for your application state. They hold values and notify dependents when those values change.
53
48
 
54
- // Update using a callback
55
- rawCount.update((n) => n + 1);
49
+ ```typescript
50
+ import { source } from "@pulse-js/core";
51
+ const count = source(0);
52
+ count.set(5);
56
53
  ```
57
54
 
58
55
  ### Guards (Semantic Logic)
59
56
 
60
- Guards represent business rules or derivations. A Guard is not just a boolean: it is a **Semantic Guard**—an observable rule with context. They track their own state including `status` (ok, fail, pending) and `reason` (why it failed).
57
+ Guards represent business rules or derivations. They act as high-performance **Selectors** with built-in dependency tracking and rich failure context.
61
58
 
62
59
  ```typescript
63
60
  import { guard } from "@pulse-js/core";
64
61
 
65
- // Synchronous Guard
66
- const isAdmin = guard("is-admin", () => {
62
+ const isAuthorized = guard("auth-check", async () => {
67
63
  const u = user();
68
- if (u.role !== "admin") return false; // Implicitly sets status to 'fail'
69
- return true;
70
- });
71
-
72
- // Guards can be checked explicitly
73
- if (isAdmin.ok()) {
74
- // Grant access
75
- } else {
76
- console.log(isAdmin.reason()); // e.g. "is-admin failed"
77
- }
78
- ```
79
-
80
- ### Computed Values
81
-
82
- You can derive new data from sources or other guards using `compute`. It works like a memoized transformation that automatically re-evaluates when dependencies change.
83
-
84
- ```typescript
85
- import { compute } from "@pulse-js/core";
86
-
87
- const fullName = compute("full-name", [firstName, lastName], (first, last) => {
88
- return `${first} ${last}`;
89
- });
90
- ```
91
-
92
- ### Async Guards & Race Control
93
-
94
- Pulse handles asynchronous logic natively. Guards can return Promises, and their status will automatically transition from `pending` to `ok` or `fail`.
95
-
96
- Pulse implements internal **runId versioning** to automatically cancel stale async evaluations if the underlying sources change multiple times before a promise resolves, preventing race conditions.
97
-
98
- ```typescript
99
- const isServerOnline = guard("check-server", async () => {
100
- const response = await fetch("/health");
101
- if (!response.ok) throw new Error("Server unreachable");
64
+ if (!u) return false;
102
65
  return true;
103
66
  });
104
67
  ```
105
68
 
106
69
  ### Explanable Guards
107
70
 
108
- For complex conditions, you can call `.explain()` to get a structured tree of the current status, failure reason, and the status of all direct dependencies.
71
+ Get a structured tree of the current status, failure reasons, and the status of all direct dependencies.
109
72
 
110
73
  ```ts
111
74
  const explanation = canCheckout.explain();
112
- console.log(explanation);
113
- // { status: 'fail', reason: 'auth failed', dependencies: [...] }
75
+ // { status: 'fail', reason: { code: 'AUTH', message: '...' }, dependencies: [...] }
114
76
  ```
115
77
 
116
- ## Server-Side Rendering (SSR)
117
-
118
- Pulse is designed with SSR in mind. It supports isomorphic rendering where async guards can be evaluated on the server, their state serialized, and then hydrated on the client.
119
-
120
- ### Server Side
121
-
122
- ```typescript
123
- import { evaluate } from "@pulse-js/core";
124
-
125
- // 1. Evaluate critical guards on the server
126
- const hydrationState = await evaluate([isUserAuthenticated, appSettings]);
127
-
128
- // 2. Serialize this state into your HTML
129
- const html = `
130
- <script>window.__PULSE_STATE__ = ${JSON.stringify(hydrationState)}</script>
131
- `;
132
- ```
133
-
134
- ### Client Side (Hydration)
135
-
136
- ```typescript
137
- import { hydrate } from "@pulse-js/core";
138
-
139
- // 1. Hydrate before rendering
140
- hydrate(window.__PULSE_STATE__);
141
- ```
142
-
143
- ### Mental Model
144
-
145
- Compare Pulse primitives:
146
-
147
- | Concept | Can be async | Has state | Observable | Purpose |
148
- | :---------- | :----------: | :-------: | :--------: | :----------------------------------- |
149
- | **Source** | ❌ | ❌ | ✅ | Reactive data (facts). |
150
- | **Guard** | ✅ | ✅ | ✅ | Business rules (conditioned truths). |
151
- | **Compute** | ❌ | ❌ | ✅ | Pure transformations (derivations). |
152
-
153
78
  ## Framework Integrations
154
79
 
155
- Pulse provides official adapters for major frameworks to ensure seamless integration.
80
+ Pulse provides official adapters for all major frameworks.
156
81
 
157
- | Framework | Package | Documentation |
158
- | :--------- | :----------------- | :----------------------------------------------------------- |
159
- | **React** | `@pulse-js/react` | [Read Docs](https://pulse-js.vercel.app/integrations/react) |
160
- | **Vue** | `@pulse-js/vue` | [Read Docs](https://pulse-js.vercel.app/integrations/vue) |
161
- | **Svelte** | `@pulse-js/svelte` | [Read Docs](https://pulse-js.vercel.app/integrations/svelte) |
82
+ | Framework | Package | Status |
83
+ | :----------- | :------------------- | :----- |
84
+ | **Astro** | `@pulse-js/astro` | NEW |
85
+ | **React** | `@pulse-js/react` | Stable |
86
+ | **Vue** | `@pulse-js/vue` | Stable |
87
+ | **Svelte** | `@pulse-js/svelte` | Stable |
88
+ | **TanStack** | `@pulse-js/tanstack` | NEW |
162
89
 
163
90
  ## Developer Tools
164
91
 
165
- Debug your reactive graph with **[Pulse Tools](https://pulse-js.vercel.app/guides/devtools/)**, a powerful framework-agnostic inspector.
166
-
167
- ### Features
92
+ Debug your reactive graph with **[Pulse Tools](https://pulse-js.vercel.app/guides/devtools/)**, a decoupled Agent-Client inspector.
168
93
 
169
- - **Component Tree**: Visualize your entire guard dependency graph.
170
- - **Editable Logic**: Update source values directly from the UI to test logic branches.
171
- - **Time Travel**: (Coming Soon) Replay state changes.
94
+ - **Agent-Client Architecture**: Isolated UI that doesn't restart your app.
95
+ - **Dependency Graph**: Visualize how your guards are connected.
96
+ - **Glassmorphism UI**: A premium, draggable development experience.
172
97
  - **Zero Config**: Works out of the box with `@pulse-js/tools`.
package/dist/index.cjs CHANGED
@@ -21,16 +21,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  PulseRegistry: () => PulseRegistry,
24
+ batch: () => batch,
24
25
  compute: () => compute,
26
+ createSignal: () => createSignal,
27
+ effect: () => effect,
25
28
  evaluate: () => evaluate,
26
29
  getCurrentGuard: () => getCurrentGuard,
27
30
  guard: () => extendedGuard,
28
31
  guardFail: () => guardFail,
29
32
  guardOk: () => guardOk,
30
33
  hydrate: () => hydrate,
34
+ isPulseObject: () => isPulseObject,
35
+ pulse: () => pulse,
36
+ readonly: () => readonly,
31
37
  registerGuardForHydration: () => registerGuardForHydration,
32
38
  runInContext: () => runInContext,
33
- source: () => source
39
+ source: () => source,
40
+ toRaw: () => toRaw
34
41
  });
35
42
  module.exports = __toCommonJS(index_exports);
36
43
 
@@ -316,9 +323,8 @@ function guard(nameOrFn, fn) {
316
323
  if (name) {
317
324
  registerGuardForHydration(name, g);
318
325
  }
319
- PulseRegistry.register(g);
320
326
  evaluate2();
321
- return g;
327
+ return PulseRegistry.register(g);
322
328
  }
323
329
  guard.map = function(source2, mapper, name) {
324
330
  const guardName = name || `map-${source2._name || "source"}`;
@@ -327,69 +333,132 @@ guard.map = function(source2, mapper, name) {
327
333
  return mapper(value);
328
334
  });
329
335
  };
336
+ guard.select = function(pulseObj, selector, name) {
337
+ const guardName = name || `select-${pulseObj._name || "pulse"}`;
338
+ return guard(guardName, () => {
339
+ return selector(pulseObj);
340
+ });
341
+ };
342
+ guard.from = function(getValue, options) {
343
+ const name = options?.name || "from-external";
344
+ return guard(name, () => {
345
+ const result = getValue();
346
+ if (result && typeof result === "object" && ("value" in result || "isLoading" in result || "error" in result)) {
347
+ const wrapped = result;
348
+ if (wrapped.isLoading) {
349
+ return void 0;
350
+ }
351
+ if (wrapped.error) {
352
+ guardFail(wrapped.error?.message || "External error");
353
+ }
354
+ return wrapped.value;
355
+ }
356
+ return result;
357
+ });
358
+ };
330
359
 
331
360
  // src/registry.ts
361
+ function generateUID(name, sourceInfo) {
362
+ if (sourceInfo?.file && sourceInfo?.line) {
363
+ return `${sourceInfo.file}:${sourceInfo.line}:${name}`;
364
+ }
365
+ return `pulse:${name}`;
366
+ }
332
367
  var Registry = class {
333
- units = /* @__PURE__ */ new Map();
368
+ targets = /* @__PURE__ */ new Map();
369
+ proxies = /* @__PURE__ */ new Map();
334
370
  listeners = /* @__PURE__ */ new Set();
335
371
  currentGeneration = 0;
336
372
  cleanupScheduled = false;
373
+ hmrDebounce = null;
374
+ /**
375
+ * Registers a unit and returns a stable Identity Proxy.
376
+ *
377
+ * If a unit with the same UID already exists, it updates the internal
378
+ * target of the existing proxy and returns that same proxy.
379
+ */
380
+ register(unit) {
381
+ const meta = unit;
382
+ const name = meta._name;
383
+ if (!name) return unit;
384
+ const uid = generateUID(name, meta._sourceInfo);
385
+ meta._uid = uid;
386
+ const existingTarget = this.targets.get(uid);
387
+ const existingProxy = this.proxies.get(uid);
388
+ if (existingProxy) {
389
+ if (this.targets.get(uid) !== unit) {
390
+ if (this.currentGeneration === unit._generation) {
391
+ }
392
+ this.targets.set(uid, unit);
393
+ this.notifyListeners(unit, "update");
394
+ }
395
+ return existingProxy;
396
+ }
397
+ this.targets.set(uid, unit);
398
+ const self = this;
399
+ const proxy = new Proxy((() => {
400
+ }), {
401
+ get(_, prop) {
402
+ const target = self.targets.get(uid);
403
+ if (!target) return void 0;
404
+ const value = target[prop];
405
+ return typeof value === "function" ? value.bind(target) : value;
406
+ },
407
+ apply(_, thisArg, args) {
408
+ const target = self.targets.get(uid);
409
+ if (typeof target !== "function") return void 0;
410
+ return Reflect.apply(target, thisArg, args);
411
+ },
412
+ // Ensure type checking and other proxy traps work
413
+ getPrototypeOf(_) {
414
+ return Object.getPrototypeOf(self.targets.get(uid) || {});
415
+ },
416
+ has(_, prop) {
417
+ return Reflect.has(self.targets.get(uid) || {}, prop);
418
+ },
419
+ ownKeys(_) {
420
+ return Reflect.ownKeys(self.targets.get(uid) || {});
421
+ },
422
+ getOwnPropertyDescriptor(_, prop) {
423
+ return Reflect.getOwnPropertyDescriptor(self.targets.get(uid) || {}, prop);
424
+ }
425
+ });
426
+ this.proxies.set(uid, proxy);
427
+ this.notifyListeners(unit, "add");
428
+ return proxy;
429
+ }
337
430
  /**
338
- * Schedules cleanup of units that weren't re-registered (deleted from code).
431
+ * Schedules cleanup of units that weren't re-registered.
339
432
  */
340
433
  scheduleCleanup() {
341
434
  if (this.cleanupScheduled) return;
342
435
  this.cleanupScheduled = true;
343
- setTimeout(() => {
436
+ if (this.hmrDebounce) clearTimeout(this.hmrDebounce);
437
+ this.hmrDebounce = setTimeout(() => {
344
438
  this.cleanupDeadUnits();
345
439
  this.cleanupScheduled = false;
346
- }, 100);
440
+ this.hmrDebounce = null;
441
+ }, 150);
347
442
  }
348
- /**
349
- * Removes units that weren't re-registered in the current generation.
350
- * Uses mark-and-sweep: units that were re-registered have current generation,
351
- * units that weren't are from old generation and should be removed.
352
- */
353
443
  cleanupDeadUnits() {
354
- const toDelete = [];
355
- this.units.forEach((unit, key) => {
356
- const gen = unit._generation;
357
- if (gen !== void 0 && gen < this.currentGeneration) {
358
- toDelete.push(key);
359
- }
360
- });
361
- toDelete.forEach((key) => this.units.delete(key));
362
- if (toDelete.length > 0) {
363
- console.log(`[Pulse] Cleaned up ${toDelete.length} deleted units after HMR`);
364
- }
365
444
  }
366
- /**
367
- * Registers a unit (only if it has an explicit name).
368
- */
369
- register(unit) {
370
- const unitWithMetadata = unit;
371
- const name = unitWithMetadata._name;
372
- if (!name) {
373
- return;
374
- }
375
- const existingUnit = this.units.get(name);
376
- if (existingUnit) {
377
- const existingGen = existingUnit?._generation;
378
- if (existingGen === this.currentGeneration) {
379
- unitWithMetadata._generation = this.currentGeneration;
380
- this.units.set(name, unit);
381
- this.listeners.forEach((l) => l(unit));
382
- return;
383
- }
384
- this.currentGeneration++;
385
- this.scheduleCleanup();
386
- }
387
- unitWithMetadata._generation = this.currentGeneration;
388
- this.units.set(name, unit);
389
- this.listeners.forEach((l) => l(unit));
445
+ notifyListeners(unit, event) {
446
+ this.listeners.forEach((l) => l(unit, event));
447
+ }
448
+ get(nameOrUid) {
449
+ const proxy = this.proxies.get(nameOrUid);
450
+ if (proxy) return proxy;
451
+ const uid = generateUID(nameOrUid);
452
+ return this.proxies.get(uid);
390
453
  }
391
454
  getAll() {
392
- return Array.from(this.units.values());
455
+ return Array.from(this.proxies.values());
456
+ }
457
+ getAllWithMeta() {
458
+ return Array.from(this.proxies.entries()).map(([uid, unit]) => ({
459
+ unit,
460
+ uid
461
+ }));
393
462
  }
394
463
  onRegister(listener) {
395
464
  this.listeners.add(listener);
@@ -398,7 +467,8 @@ var Registry = class {
398
467
  };
399
468
  }
400
469
  reset() {
401
- this.units.clear();
470
+ this.targets.clear();
471
+ this.proxies.clear();
402
472
  this.currentGeneration = 0;
403
473
  }
404
474
  };
@@ -440,8 +510,192 @@ function source(initialValue, options = {}) {
440
510
  return () => subscribers.delete(listener);
441
511
  };
442
512
  s._name = options.name;
443
- PulseRegistry.register(s);
444
- return s;
513
+ return PulseRegistry.register(s);
514
+ }
515
+
516
+ // src/signal.ts
517
+ var batchQueue = null;
518
+ var batchDepth = 0;
519
+ function batch(fn) {
520
+ batchDepth++;
521
+ if (!batchQueue) {
522
+ batchQueue = /* @__PURE__ */ new Set();
523
+ }
524
+ try {
525
+ fn();
526
+ } finally {
527
+ batchDepth--;
528
+ if (batchDepth === 0 && batchQueue) {
529
+ const queue = batchQueue;
530
+ batchQueue = null;
531
+ queue.forEach((notify) => notify());
532
+ }
533
+ }
534
+ }
535
+ function scheduleNotification(notify) {
536
+ if (batchQueue) {
537
+ batchQueue.add(notify);
538
+ } else {
539
+ notify();
540
+ }
541
+ }
542
+ function createSignal(initialValue, equals = (a, b) => a === b) {
543
+ let value = initialValue;
544
+ const subscribers = /* @__PURE__ */ new Set();
545
+ const dependents = /* @__PURE__ */ new Set();
546
+ const notify = () => {
547
+ subscribers.forEach((sub) => sub(value));
548
+ const deps = Array.from(dependents);
549
+ dependents.clear();
550
+ deps.forEach((dep) => dep.notify());
551
+ };
552
+ const signal = {
553
+ get() {
554
+ const activeGuard = getCurrentGuard();
555
+ if (activeGuard) {
556
+ dependents.add(activeGuard);
557
+ activeGuard.addDependency(signal);
558
+ }
559
+ return value;
560
+ },
561
+ peek() {
562
+ return value;
563
+ },
564
+ set(newValue) {
565
+ if (!equals(value, newValue)) {
566
+ value = newValue;
567
+ scheduleNotification(notify);
568
+ }
569
+ },
570
+ update(fn) {
571
+ signal.set(fn(value));
572
+ },
573
+ subscribe(listener) {
574
+ subscribers.add(listener);
575
+ return () => subscribers.delete(listener);
576
+ }
577
+ };
578
+ return signal;
579
+ }
580
+ function effect(fn) {
581
+ let cleanup;
582
+ let disposed = false;
583
+ const run = () => {
584
+ if (disposed) return;
585
+ if (cleanup) cleanup();
586
+ cleanup = fn();
587
+ };
588
+ run();
589
+ return () => {
590
+ disposed = true;
591
+ if (cleanup) cleanup();
592
+ };
593
+ }
594
+
595
+ // src/pulse.ts
596
+ var PULSE_META = /* @__PURE__ */ Symbol("PULSE_META");
597
+ function pulse(target, options = {}) {
598
+ const { name, deep = true } = options;
599
+ const signals = /* @__PURE__ */ new Map();
600
+ const subscribers = /* @__PURE__ */ new Set();
601
+ const dependents = /* @__PURE__ */ new Set();
602
+ const nestedCache = /* @__PURE__ */ new Map();
603
+ const meta = {
604
+ signals,
605
+ subscribers,
606
+ dependents,
607
+ name,
608
+ target
609
+ };
610
+ function getSignal(key) {
611
+ if (!signals.has(key)) {
612
+ const initialValue = target[key];
613
+ signals.set(key, createSignal(initialValue));
614
+ }
615
+ return signals.get(key);
616
+ }
617
+ function notify() {
618
+ subscribers.forEach((sub) => sub(proxy));
619
+ const deps = Array.from(dependents);
620
+ dependents.clear();
621
+ deps.forEach((dep) => dep.notify());
622
+ }
623
+ function trackAccess() {
624
+ const activeGuard = getCurrentGuard();
625
+ if (activeGuard) {
626
+ dependents.add(activeGuard);
627
+ activeGuard.addDependency(proxy);
628
+ }
629
+ }
630
+ const proxy = new Proxy(target, {
631
+ get(obj, prop) {
632
+ if (prop === PULSE_META) return meta;
633
+ if (prop === "$raw") return target;
634
+ if (prop === "$subscribe") {
635
+ return (listener) => {
636
+ subscribers.add(listener);
637
+ return () => subscribers.delete(listener);
638
+ };
639
+ }
640
+ if (prop === "$snapshot") {
641
+ return () => ({ ...target });
642
+ }
643
+ const value = obj[prop];
644
+ if (typeof value === "function") {
645
+ return value.bind(proxy);
646
+ }
647
+ trackAccess();
648
+ const signal = getSignal(prop);
649
+ const currentValue = signal.get();
650
+ if (deep && currentValue !== null && typeof currentValue === "object" && !isPulseObject(currentValue)) {
651
+ if (!nestedCache.has(prop)) {
652
+ nestedCache.set(prop, pulse(currentValue, { deep, name: name ? `${name}.${String(prop)}` : void 0 }));
653
+ }
654
+ return nestedCache.get(prop);
655
+ }
656
+ return currentValue;
657
+ },
658
+ set(obj, prop, value) {
659
+ const oldValue = obj[prop];
660
+ if (oldValue === value) return true;
661
+ obj[prop] = value;
662
+ getSignal(prop).set(value);
663
+ notify();
664
+ return true;
665
+ },
666
+ has(obj, prop) {
667
+ if (prop === PULSE_META) return true;
668
+ trackAccess();
669
+ return Reflect.has(obj, prop);
670
+ },
671
+ ownKeys(obj) {
672
+ trackAccess();
673
+ return Reflect.ownKeys(obj);
674
+ }
675
+ });
676
+ return PulseRegistry.register(proxy);
677
+ }
678
+ function isPulseObject(value) {
679
+ return value !== null && typeof value === "object" && PULSE_META in value;
680
+ }
681
+ function toRaw(pulseObj) {
682
+ return pulseObj.$raw;
683
+ }
684
+ function readonly(pulseObj) {
685
+ return new Proxy(pulseObj, {
686
+ set() {
687
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
688
+ console.warn("[Pulse] Attempted to mutate a readonly pulse object");
689
+ }
690
+ return false;
691
+ },
692
+ deleteProperty() {
693
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
694
+ console.warn("[Pulse] Attempted to delete from a readonly pulse object");
695
+ }
696
+ return false;
697
+ }
698
+ });
445
699
  }
446
700
 
447
701
  // src/compute.ts
@@ -510,14 +764,21 @@ var extendedGuard = Object.assign(guard, guardExtensions);
510
764
  // Annotate the CommonJS export names for ESM import in node:
511
765
  0 && (module.exports = {
512
766
  PulseRegistry,
767
+ batch,
513
768
  compute,
769
+ createSignal,
770
+ effect,
514
771
  evaluate,
515
772
  getCurrentGuard,
516
773
  guard,
517
774
  guardFail,
518
775
  guardOk,
519
776
  hydrate,
777
+ isPulseObject,
778
+ pulse,
779
+ readonly,
520
780
  registerGuardForHydration,
521
781
  runInContext,
522
- source
782
+ source,
783
+ toRaw
523
784
  });