@pulse-js/core 0.1.0 → 0.1.1

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/dist/index.d.cts DELETED
@@ -1,414 +0,0 @@
1
- /**
2
- * Represents an object that can be notified of changes.
3
- * Primarily implemented by Guards to trigger re-evaluation.
4
- */
5
- interface Trackable {
6
- /** Triggered when a dependency (Source or another Guard) changes. */
7
- notify(): void;
8
- }
9
- /**
10
- * Subscriber callback for manual source subscriptions.
11
- */
12
- type Subscriber<T> = (value: T) => void;
13
- /**
14
- * Internal interface for Guard nodes within the dependency graph.
15
- */
16
- interface GuardNode extends Trackable {
17
- /**
18
- * Registers a dependency for this guard.
19
- * Internal use only.
20
- */
21
- addDependency(trackable: Trackable): void;
22
- }
23
- /**
24
- * Executes a function within the context of a specific Guard.
25
- * Any Pulse primitives read during this execution will register the guard as a dependent.
26
- *
27
- * @internal
28
- * @param guard The guard node to set as active.
29
- * @param fn The function to execute.
30
- * @returns The result of the function.
31
- */
32
- declare function runInContext<T>(guard: GuardNode, fn: () => T): T;
33
- /**
34
- * Retrieves the guard currently being evaluated, if any.
35
- * Used by Sources and Guards to perform automatic dependency registration.
36
- *
37
- * @internal
38
- */
39
- declare function getCurrentGuard(): GuardNode | null;
40
-
41
- /**
42
- * Status of a Pulse Guard evaluation.
43
- * - 'pending': Async evaluation is in progress.
44
- * - 'ok': Evaluation completed successfully (return value was not `false`).
45
- * - 'fail': Evaluation encountered an error or return value was `false`.
46
- */
47
- type GuardStatus = 'ok' | 'fail' | 'pending';
48
- /**
49
- * The internal state of a Pulse Guard.
50
- */
51
- interface GuardState<T> {
52
- /** Current status of the guard. */
53
- status: GuardStatus;
54
- /** The value returned by the evaluator (only if status is 'ok'). */
55
- value?: T;
56
- /** The message explaining why the guard failed (only if status is 'fail'). */
57
- reason?: string;
58
- }
59
- /**
60
- * A Pulse Guard is a reactive semantic condition.
61
- * It encapsulates a condition (sync or async) and manages its lifecycle,
62
- * dependencies, and error states.
63
- *
64
- * @template T The type of the value returned by the evaluator.
65
- */
66
- interface Guard<T = boolean> {
67
- /**
68
- * Returns the current value of the guard if its status is 'ok'.
69
- * If status is 'fail' or 'pending', returns `undefined`.
70
- *
71
- * When called within another Guard's evaluator, it establishes a reactive dependency.
72
- *
73
- * @returns The successful value or undefined.
74
- */
75
- (): T | undefined;
76
- /**
77
- * Returns `true` if the guard successfully evaluated and is ready for use.
78
- * Establishes a reactive dependency.
79
- */
80
- ok(): boolean;
81
- /**
82
- * Returns `true` if the guard failed its condition or encountered an error.
83
- * Establishes a reactive dependency.
84
- */
85
- fail(): boolean;
86
- /**
87
- * Returns `true` if the guard is currently performing an asynchronous evaluation.
88
- * Establishes a reactive dependency.
89
- */
90
- pending(): boolean;
91
- /**
92
- * Returns the failure reason message if the guard is in the 'fail' state.
93
- * Useful for displaying semantic error messages in the UI.
94
- *
95
- * @returns The error message or undefined.
96
- */
97
- reason(): string | undefined;
98
- /**
99
- * Returns a snapshot of the full internal state of the guard.
100
- * Useful for adapters (like React) to synchronize with the guard.
101
- *
102
- * @returns {GuardState<T>}
103
- */
104
- state(): GuardState<T>;
105
- /**
106
- * Manually subscribes to changes in the guard's state.
107
- *
108
- * @param listener - A callback that receives the new GuardState.
109
- * @returns An unsubscription function.
110
- */
111
- subscribe(listener: Subscriber<GuardState<T>>): () => void;
112
- /**
113
- * Manually forces a re-evaluation of the guard.
114
- * Typically used internally by Pulse or for debugging.
115
- * @internal
116
- */
117
- _evaluate(): void;
118
- }
119
- /**
120
- * Creates a new Pulse Guard.
121
- *
122
- * Guards represent semantic conditions or asynchronous data dependencies.
123
- * They automatically track any Sources or other Guards used during their evaluation.
124
- *
125
- * @template T - The type of value returned by the evaluator (defaults to boolean).
126
- * @param nameOrFn - Either a unique string name (required for SSR) or the evaluator function.
127
- * @param fn - The evaluator function if a name was provided as the first argument.
128
- * @returns A reactive Pulse Guard.
129
- *
130
- * @example
131
- * ```ts
132
- * // 1. Synchronous boolean guard
133
- * const canEnter = guard(() => age() >= 18);
134
- *
135
- * // 2. Asynchronous data guard with a name
136
- * const profile = guard('user-profile', async () => {
137
- * const data = await fetchUser(userId());
138
- * return data.json();
139
- * });
140
- * ```
141
- */
142
- declare function guard<T = boolean>(nameOrFn?: string | (() => T | Promise<T>), fn?: () => T | Promise<T>): Guard<T>;
143
-
144
- /**
145
- * Creates a composite guard that is 'ok' only if ALL provided guards are 'ok'.
146
- * If any guard fails, this guard also fails and adopts the reason of the FIRST failing guard.
147
- *
148
- * @param nameOrGuards Optional name for the guard or the array of guards.
149
- * @param maybeGuards The array of guards (if name was provided).
150
- *
151
- * @example
152
- * ```ts
153
- * const canPost = guard.all('can-post', [isLoggedIn, hasPostPermission, emailVerified]);
154
- *
155
- * // If isLoggedIn fails with reason "Unauthorized",
156
- * // canPost.reason() will also be "Unauthorized".
157
- * ```
158
- */
159
- declare function guardAll(nameOrGuards: string | Guard<any>[], maybeGuards?: Guard<any>[]): Guard<boolean>;
160
- /**
161
- * Creates a composite guard that is 'ok' if AT LEAST ONE provided guard is 'ok'.
162
- * If all guards fail, this guard fails and concatenates their reasons.
163
- *
164
- * @param nameOrGuards Optional name for the guard or the array of guards.
165
- * @param maybeGuards The array of guards (if name was provided).
166
- *
167
- * @example
168
- * ```ts
169
- * const isStaff = guard.any('is-staff', [isAdmin, isEditor, isModerator]);
170
- * ```
171
- */
172
- declare function guardAny(nameOrGuards: string | Guard<any>[], maybeGuards?: Guard<any>[]): Guard<boolean>;
173
- /**
174
- * Negates a Pulse Guard, Source, or boolean-returning function.
175
- *
176
- * @param nameOrTarget Optional name or the target to negate.
177
- * @param maybeTarget The target to negate (if name was provided).
178
- *
179
- * @example
180
- * ```ts
181
- * const isGuest = guard.not('is-guest', isLoggedIn);
182
- * ```
183
- */
184
- declare function guardNot(nameOrTarget: string | Guard<any> | (() => any), maybeTarget?: Guard<any> | (() => any)): Guard<boolean>;
185
- /**
186
- * Utility to transform reactive dependencies into a new derived value.
187
- *
188
- * Works like a memoized computation that automatically re-evaluates when
189
- * any of its dependencies change.
190
- *
191
- * @template T - The type of input values.
192
- * @template R - The type of the computed result.
193
- * @param name - A unique name for the computation (required for SSR).
194
- * @param dependencies - An array of sources or guards to observe.
195
- * @param processor - A function that derives the new value.
196
- * @returns A Pulse Guard holding the computed result.
197
- *
198
- * @example
199
- * ```ts
200
- * const fullName = guard.compute('full-name', [firstName, lastName], (f, l) => `${f} ${l}`);
201
- * ```
202
- */
203
- declare function guardCompute<T, R>(name: string, dependencies: any[], processor: (...args: any[]) => R): Guard<R>;
204
-
205
- /**
206
- * Options for configuring a Pulse Source.
207
- *
208
- * @template T - The type of value stored in the source.
209
- */
210
- interface SourceOptions<T> {
211
- /**
212
- * A descriptive name for the source.
213
- * Required for SSR hydration and highly recommended for debugging in DevTools.
214
- */
215
- name?: string;
216
- /**
217
- * Custom equality function to determine if a value has changed.
218
- * By default, Pulse uses strict equality (`===`).
219
- *
220
- * @param a - The current value.
221
- * @param b - The new value.
222
- * @returns `true` if the values are considered equal, `false` otherwise.
223
- *
224
- * @example
225
- * ```ts
226
- * const list = source([1], {
227
- * equals: (a, b) => a.length === b.length
228
- * });
229
- * ```
230
- */
231
- equals?: (a: T, b: T) => boolean;
232
- }
233
- /**
234
- * A Pulse Source is a reactive container for a value.
235
- * It tracks which Guards read its value and notifies them when it changes.
236
- *
237
- * @template T The type of the value held by the source.
238
- */
239
- interface Source<T> {
240
- /**
241
- * Returns the current value of the source.
242
- * If called within a Guard evaluation, it automatically registers that Guard as a dependent.
243
- *
244
- * @example
245
- * ```ts
246
- * const count = source(0);
247
- * console.log(count()); // 0
248
- * ```
249
- */
250
- (): T;
251
- /**
252
- * Updates the source with a new value.
253
- * If the value is different (based on strict equality or `options.equals`),
254
- * all dependent Guards and subscribers will be notified.
255
- *
256
- * @param value The new value to set.
257
- *
258
- * @example
259
- * ```ts
260
- * const count = source(0);
261
- * count.set(1); // Triggers re-evaluation of dependents
262
- * ```
263
- *
264
- * @error
265
- * Common error: Mutating an object property without setting a new object reference.
266
- * Pulse uses reference equality by default. If you mutate a property, Pulse won't know it changed.
267
- * Solution: Always provide a new object or implement a custom `equals`.
268
- */
269
- set(value: T): void;
270
- /**
271
- * Updates the source value using a transformer function based on the current value.
272
- * Useful for increments or toggles.
273
- *
274
- * @param updater A function that receives the current value and returns the new value.
275
- *
276
- * @example
277
- * ```ts
278
- * const count = source(0);
279
- * count.update(n => n + 1);
280
- * ```
281
- */
282
- update(updater: (current: T) => T): void;
283
- /**
284
- * Manually subscribes to changes in the source value.
285
- *
286
- * @param listener A callback that receives the new value.
287
- * @returns An unsubscription function.
288
- *
289
- * @note Most users should use `guard()` or `usePulse()` instead of manual subscriptions.
290
- */
291
- subscribe(listener: Subscriber<T>): () => void;
292
- }
293
- /**
294
- * Creates a new Pulse Source.
295
- *
296
- * Sources are the fundamental building blocks of state in Pulse. They hold a value
297
- * and track which Guards depend on them.
298
- *
299
- * @template T - The type of value to store.
300
- * @param initialValue - The initial state.
301
- * @param options - Configuration options (name, equality).
302
- * @returns A reactive Pulse Source.
303
- *
304
- * @example
305
- * ```ts
306
- * const user = source({ name: 'Alice' }, { name: 'user_state' });
307
- *
308
- * // Read value (auto-tracks if inside a guard)
309
- * console.log(user());
310
- *
311
- * // Update value
312
- * user.set({ name: 'Bob' });
313
- * ```
314
- */
315
- declare function source<T>(initialValue: T, options?: SourceOptions<T>): Source<T>;
316
-
317
- /**
318
- * Serialized state of guards for transfer from server to client.
319
- */
320
- interface HydrationState {
321
- /** Map of guard names to their semantic states. */
322
- [key: string]: GuardState<any>;
323
- }
324
- /**
325
- * Registers a guard to be automatically hydrated when the client starts.
326
- * Guards with a 'name' are automatically registered upon creation.
327
- *
328
- * @internal
329
- */
330
- declare function registerGuardForHydration(name: string, guard: Guard<any>): void;
331
- /**
332
- * Evaluates a list of Pulse Guards and returns a serializable snapshot of their states.
333
- * This is meant to be used on the server (SSR).
334
- * It waits for any 'pending' guards to resolve before taking the snapshot.
335
- *
336
- * @param guards Array of guards to evaluate.
337
- * @returns A promise resolving to the hydration state.
338
- *
339
- * @example
340
- * ```ts
341
- * // Server side
342
- * const state = await evaluate([isLoggedIn, userData]);
343
- * const html = renderToString(<App />);
344
- * res.send(`
345
- * <script>window.__PULSE_STATE__ = ${JSON.stringify(state)}</script>
346
- * <div id="root">${html}</div>
347
- * `);
348
- * ```
349
- */
350
- declare function evaluate(guards: Guard<any>[]): Promise<HydrationState>;
351
- /**
352
- * Hydrates client-side guards with the state captured on the server.
353
- * This should be called early in the client lifecycle, before rendering.
354
- *
355
- * @param state The hydration state received from the server.
356
- *
357
- * @example
358
- * ```ts
359
- * // Client side
360
- * import { hydrate } from '@pulse/core';
361
- * hydrate(window.__PULSE_STATE__);
362
- * ```
363
- */
364
- declare function hydrate(state: HydrationState): void;
365
-
366
- type PulseUnit = Source<any> | Guard<any>;
367
- /**
368
- * Root Registry for Pulse.
369
- *
370
- * It tracks all registered Units (Sources and Guards) globally, providing
371
- * the data source for DevTools and HMR stability.
372
- */
373
- declare class Registry {
374
- private units;
375
- private listeners;
376
- /**
377
- * Registers a new unit (Source or Guard).
378
- * Uses the unit's name as a key to prevent duplicates during HMR.
379
- */
380
- register(unit: PulseUnit): void;
381
- /**
382
- * Retrieves all registered units.
383
- */
384
- getAll(): PulseUnit[];
385
- /**
386
- * Subscribes to new unit registrations.
387
- *
388
- * @param listener - Callback receiving the newly registered unit.
389
- * @returns Unsubscribe function.
390
- */
391
- onRegister(listener: (unit: PulseUnit) => void): () => void;
392
- }
393
- declare const PulseRegistry: Registry;
394
-
395
- /**
396
- * Pulse Guard with integrated Composition Helpers.
397
- *
398
- * This is the primary entry point for creating reactive conditions.
399
- * It includes static methods like `.all()`, `.any()`, and `.not()`.
400
- *
401
- * @example
402
- * ```ts
403
- * const isReady = guard(() => true);
404
- * const allReady = guard.all([isReady, isLoaded]);
405
- * ```
406
- */
407
- declare const extendedGuard: typeof guard & {
408
- all: typeof guardAll;
409
- any: typeof guardAny;
410
- not: typeof guardNot;
411
- compute: typeof guardCompute;
412
- };
413
-
414
- export { type Guard, type GuardNode, type GuardState, type GuardStatus, type HydrationState, PulseRegistry, type PulseUnit, type Source, type SourceOptions, type Subscriber, type Trackable, evaluate, getCurrentGuard, extendedGuard as guard, hydrate, registerGuardForHydration, runInContext, source };