# Hooks, plugins, and timeline reference

Extend lifecycle, install plugins with grants, and control time projections while distinguishing their authorities.

A hook changes the lifecycle flow; a plugin groups setup, permissions, and cleanup; timeline keeps a projection journal. Each mechanism has an owner and a way to end its activity.

<span id="interceptar-una-fase"></span>

<span class="section-anchor" id="section-1"></span>

## Intercepting a phase

```js
import { wu, createGuardHook } from 'wu-framework';

const removeGuard = wu.hooks.use('beforeMount', createGuardHook(context => {
  return context.appName !== 'disabled-app';
}), { name: 'availability' });
// Al retirar esta extensión:
removeGuard();
```

Available phases are before/after Init, Load, Mount, Update, Unmount, and Destroy. Higher priority runs first. Omitting `next()` cancels the chain; `failOpen: true` allows continuation after middleware failure. A UI guard does not replace role controls or core grants.

<span id="conceder-autoridad-a-un-plugin"></span>

<span class="section-anchor" id="section-2"></span>

## Granting authority to a plugin

Plugin permissions are `mount`, `events`, `store`, `apps`, `config`, and `unsafe`. A plugin requests these names, and the host grants `options.grants` during installation. Do not reuse `store.read` or `rpc.call` as plugin grants: those belong to application contracts.

Await `pluginSystem.use` or `pluginSystem.ready` before depending on setup. Installation from an asynchronous factory also participates in this startup. A plugin executes host code; its reduced API does not remove privileges captured in closures.

<span id="grabar-antes-de-escribir"></span>

<span class="section-anchor" id="section-3"></span>

## Recording before writing

```js
await wu.timelineReady();
wu.timeline.record({ maxEntries: 500 });
wu.store.set('demo.count', 1);
wu.store.set('demo.count', 2);
await wu.timeline.seek(0, { apps: false, props: false });
await wu.timeline.live();
wu.timeline.stop();
```

The `wu.timeline` facade retains chainable methods for synchronous controls. The real object returned by `timelineReady` has different return values; use the facade in this reference's examples. Seek rematerializes store, props, and composition according to options; it does not rewind networks, timers, or infrastructure.

<span class="section-anchor" id="section-4"></span>

## wu.hooks.use

Installs lifecycle middleware with priority and individual cleanup.

`wu.hooks.use(phase, middleware, options?): () => void`

- **Parameters:** Valid phase, middleware(context,next); options: name, priority, failOpen.
- **Returns:** Unsubscribe function; the TypeScript declaration says void.
- **Errors:** Unknown phase or invalid callback throws; omitting next cancels the chain.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** stop() removes only that middleware.

```js
const stop = wu.hooks.use('beforeMount', async (context, next) => {
  console.log(context.appName);
  await next();
}, { name: 'mount-log', priority: 10 });
```

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-5"></span>

## wu.hooks.useMultiple

Installs the same middleware in several phases.

`wu.hooks.useMultiple(phases, middleware, options?): () => void`

- **Parameters:** Phase array; use a stable name to identify each derived registration.
- **Returns:** Combined cleanup.
- **Errors:** Every phase must exist; registration is not atomic if a later phase fails.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** stop() removes the created installations.

```js
const stop = wu.hooks.useMultiple(['beforeMount', 'beforeUnmount'], async (ctx, next) => {
  await next();
}, { name: 'trace' });
```

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-6"></span>

## wu.hooks.remove

Removes middleware identified by phase and name.

`wu.hooks.remove(phase, name): void`

- **Parameters:** phase and registration name.
- **Returns:** void; absence does not throw.
- **Errors:** Duplicate names make removal ambiguous; prefer individual cleanup.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no new resources.

```js
wu.hooks.remove('beforeMount', 'mount-log');
```

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-7"></span>

## wu.hooks.getHooks

Queries installed middleware metadata.

`wu.hooks.getHooks(phase?): object | object[]`

- **Parameters:** Optional phase.
- **Returns:** Without a phase: metadata map; with a phase: registration array.
- **Errors:** With a phase, returns internal registrations; do not mutate them as a configuration API.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no new resources.

```js
console.log(wu.hooks.getHooks());
```

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-8"></span>

## wu.hooks.getStats

Queries hook distribution and execution records.

`wu.hooks.getStats(): object`

- **Parameters:** No arguments.
- **Returns:** Metrics object.
- **Errors:** The execution log has limited capacity.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no new resources.

```js
console.log(wu.hooks.getStats());
```

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-9"></span>

## wu.hooks.cleanup

Removes middleware from one or every phase.

`wu.hooks.cleanup(phase?): void`

- **Parameters:** Optional phase; omitting it also empties the execution log.
- **Returns:** void.
- **Errors:** Does not itself cancel a callback already running.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Releases registrations; resources created by callbacks need their own cleanup.

```js
wu.hooks.cleanup('beforeMount');
```

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-10"></span>

## createSimpleHook

Converts a callback into middleware that continues the chain.

`createSimpleHook(fn): Function`

- **Parameters:** fn(context) may be asynchronous.
- **Returns:** async(context,next) middleware.
- **Errors:** Callback errors follow the factory and chain policy.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Install with hooks.use and retain that registration's cleanup.

```js
import { createSimpleHook } from 'wu-framework';
const middleware = createSimpleHook(ctx => console.log(ctx.appName));
```

Awaits the callback, then invokes next.

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-11"></span>

## createConditionalHook

Executes a callback if the condition is true, then continues.

`createConditionalHook(condition, fn): Function`

- **Parameters:** condition(context) and fn(context).
- **Returns:** async(context,next) middleware.
- **Errors:** Callback errors follow the factory and chain policy.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Install with hooks.use and retain that registration's cleanup.

```js
import { createConditionalHook } from 'wu-framework';
const middleware = createConditionalHook(ctx => ctx.appName === 'catalog', ctx => console.log(ctx));
```

The condition is not a cancellation guard: a false condition continues the chain.

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-12"></span>

## createGuardHook

Continues the chain only when the guard allows it.

`createGuardHook(shouldContinue): Function`

- **Parameters:** shouldContinue(context), synchronous or promise.
- **Returns:** async(context,next) middleware.
- **Errors:** Callback errors follow the factory and chain policy.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Install with hooks.use and retain that registration's cleanup.

```js
import { createGuardHook } from 'wu-framework';
const middleware = createGuardHook(ctx => ctx.appName !== 'disabled-app');
```

If it returns false, it does not call next; it does not replace grants or server authorization.

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-13"></span>

## createTransformHook

Transforms the context received by the next middleware.

`createTransformHook(transformer): Function`

- **Parameters:** transformer(context) returns context data.
- **Returns:** async(context,next) middleware.
- **Errors:** Callback errors follow the factory and chain policy.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Install with hooks.use and retain that registration's cleanup.

```js
import { createTransformHook } from 'wu-framework';
const middleware = createTransformHook(ctx => ({ ...ctx, traceLabel: 'catalog' }));
```

This does not configure the core beyond fields consumed by that lifecycle.

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-14"></span>

## createTimedHook

Limits how long middleware waits for a callback.

`createTimedHook(fn, timeout?: number): Function`

- **Parameters:** fn(context); default timeout 5000 ms.
- **Returns:** async(context,next) middleware.
- **Errors:** Callback errors follow the factory and chain policy.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Install with hooks.use and retain that registration's cleanup.

```js
import { createTimedHook } from 'wu-framework';
const middleware = createTimedHook(async ctx => console.log(ctx.appName), 1000);
```

A failure or timeout is logged and the chain continues; original work is not automatically aborted.

Reference: `src/core/wu-hooks.js`.

<span class="section-anchor" id="section-15"></span>

## createPlugin

Builds a plugin with a name, requested permissions, and callbacks.

`createPlugin(config): WuPlugin`

- **Parameters:** config with name; optional install/uninstall and hooks.
- **Returns:** Plugin object; creating does not install.
- **Errors:** Invalid name/config may throw.
- **Permissions:** The plugin requests permissions; the host grants them when calling use.
- **Cleanup:** Install with pluginSystem.use and remove with uninstall.

```js
import { createPlugin } from 'wu-framework';
const plugin = createPlugin({ name: 'catalog-observer', permissions: ['events'], install(api) { console.log(api.version); } });
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-16"></span>

## wu.pluginSystem.use

Installs a plugin and awaits setup before considering it available.

`wu.pluginSystem.use(pluginOrFactory, options?): Promise<boolean>`

- **Parameters:** Plugin or async factory; options.grants and compatibility configure authority.
- **Returns:** true when installed; rejects validation/setup failures.
- **Errors:** Required permissions without grants, duplicates, and install errors may reject.
- **Permissions:** Plugin permissions: mount, events, store, apps, config, unsafe; distinct from app capabilities.
- **Cleanup:** await uninstall(name) revokes its API and runs cleanup.

```js
await wu.pluginSystem.use({
  name: 'catalog-observer', permissions: ['events'],
  install(api) { console.log(api.version); },
}, { grants: ['events'] });
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-17"></span>

## wu.pluginSystem.ready

Awaits pending installations and exposes their failures to bootstrap.

`wu.pluginSystem.ready(): Promise<boolean>`

- **Parameters:** No arguments.
- **Returns:** true on successful completion.
- **Errors:** Rejects the first pending error and includes pendingPluginErrors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Does not uninstall successful plugins.

```js
await wu.pluginSystem.ready();
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-18"></span>

## wu.pluginSystem.uninstall

Removes a plugin and its associated authority.

`wu.pluginSystem.uninstall(name): Promise<boolean>`

- **Parameters:** Exact plugin name.
- **Returns:** Uninstallation boolean.
- **Errors:** Uninstall may fail; inspect the error and diagnostics.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Invokes the uninstall hook and releases plugin-owned hooks/listeners.

```js
await wu.pluginSystem.uninstall('catalog-observer');
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-19"></span>

## wu.pluginSystem.getPlugin

Queries an installed plugin's definition.

`wu.pluginSystem.getPlugin(name): WuPlugin | undefined`

- **Parameters:** Exact name.
- **Returns:** Plugin or undefined.
- **Errors:** Does not exist until installation completes.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no new resources.

```js
console.log(wu.pluginSystem.getPlugin('catalog-observer')?.name);
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-20"></span>

## wu.pluginSystem.getStats

Lists plugins, granted permissions, and active hooks.

`wu.pluginSystem.getStats(): object`

- **Parameters:** No arguments.
- **Returns:** Object with totalPlugins, plugins, and hooks.
- **Errors:** Does not verify plugin external effects.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no new resources.

```js
console.log(wu.pluginSystem.getStats());
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-21"></span>

## wu.pluginSystem.cleanup

Uninstalls every plugin in the system.

`wu.pluginSystem.cleanup(): Promise<void>`

- **Parameters:** No arguments.
- **Returns:** Promise resolving when uninstallation traversal finishes.
- **Errors:** Failures follow the uninstall contract.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Affects all plugins; belongs to host teardown.

```js
await wu.pluginSystem.cleanup();
```

Reference: `src/core/wu-plugin.js`.

<span class="section-anchor" id="section-22"></span>

## wu.timelineReady

Loads the recorder before the first writes you want to capture.

`wu.timelineReady(): Promise<unknown>`

- **Parameters:** No arguments.
- **Returns:** Actual recorder instance; not the chainable facade.
- **Errors:** Rejects chunk download/import errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** wu.timeline.stop() removes observers; clear resets the journal.

```js
await wu.timelineReady();
wu.timeline.record();
```

Reference: `src/index.js`.

<span class="section-anchor" id="section-23"></span>

## wu.timeline.record

Starts the journal from current state and apps.

`wu.timeline.record(options?: { snapshotEvery?: number; maxEntries?: number }): WuTimelineFacade`

- **Parameters:** Optional snapshot frequency and entry limit.
- **Returns:** WuTimelineFacade
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** stop() removes taps.

```js
await wu.timelineReady();
wu.timeline.record({ snapshotEvery: 25, maxEntries: 500 });
```

The facade returns itself; the actual recorder returns status. Without timelineReady, deferred loading may miss initial writes.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-24"></span>

## wu.timeline.stop

Stops capture while retaining the journal for inspection.

`wu.timeline.stop(): WuTimelineFacade`

- **Parameters:** No arguments.
- **Returns:** WuTimelineFacade
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Removes store and bus taps.

```js
wu.timeline.stop();
```

Does not stop timers, requests, or processes created by applications.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-25"></span>

## wu.timeline.clear

Empties the journal and takes the current situation as the new baseline.

`wu.timeline.clear(): WuTimelineFacade`

- **Parameters:** No arguments.
- **Returns:** WuTimelineFacade
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Does not replace stop if you want to stop recording.

```js
wu.timeline.clear();
```

Does not delete business state or reverse external effects.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-26"></span>

## wu.timeline.seek

Materializes a journal position in its projections.

`wu.timeline.seek(position: number, options?: { store?: boolean; apps?: boolean; props?: boolean }): Promise<WuTimelineStatus>`

- **Parameters:** Index 0..length; selects store/apps/props.
- **Returns:** Promise<WuTimelineStatus>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Return to live to recover the final position.

```js
const status = await wu.timeline.seek(0, { store: true, apps: false, props: false });
```

Does not reverse HTTP, timers, or infrastructure. Writes made in the past do not create a new branch.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-27"></span>

## wu.timeline.live

Materializes the end of the journal.

`wu.timeline.live(): Promise<WuTimelineStatus>`

- **Parameters:** No arguments.
- **Returns:** Promise<WuTimelineStatus>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Retains the recorder until stop.

```js
await wu.timeline.live();
```

Returning to live discards unrecorded changes made at the historical position.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-28"></span>

## wu.timeline.stepBack

Moves back one journal position.

`wu.timeline.stepBack(): Promise<WuTimelineStatus>`

- **Parameters:** No arguments.
- **Returns:** Promise<WuTimelineStatus>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** stop releases capture when the session ends.

```js
await wu.timeline.stepBack();
```

Limited to the recorder's reproducible projections.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-29"></span>

## wu.timeline.stepForward

Moves forward one journal position.

`wu.timeline.stepForward(): Promise<WuTimelineStatus>`

- **Parameters:** No arguments.
- **Returns:** Promise<WuTimelineStatus>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** stop releases capture when the session ends.

```js
await wu.timeline.stepForward();
```

Does not replay an action's external effects.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-30"></span>

## wu.timeline.export

Serializes entries, snapshots, and the app baseline.

`wu.timeline.export(): Promise<WuTimelineExport>`

- **Parameters:** No arguments.
- **Returns:** Promise<WuTimelineExport>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** The host decides where to save/export the object.

```js
const journal = await wu.timeline.export();
```

May contain application state; not an automatic durable audit.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-31"></span>

## wu.timeline.import

Loads a serialized journal for inspection.

`wu.timeline.import(journal: WuTimelineExport): Promise<WuTimelineStatus>`

- **Parameters:** Compatible export object.
- **Returns:** Promise<WuTimelineStatus>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Affects the recorder; explicitly choose the subsequent projection.

```js
await wu.timeline.import(journal);
```

Validate state provenance; importing does not execute a remote sandbox.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-32"></span>

## wu.timeline.ingest

Merges entries using journal order and a shared empty baseline.

`wu.timeline.ingest(entries: WuTimelineEntry[]): Promise<WuTimelineStatus>`

- **Parameters:** Entries with Lamport clock and site identity.
- **Returns:** Promise<WuTimelineStatus>
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Does not open or authenticate transport.

```js
await wu.timeline.ingest(remoteEntries);
```

Merging does not itself materialize all UI state; it requires a shared baseline and projection rules.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-33"></span>

## wu.timeline.entries

Reads entries retained by the recorder.

`wu.timeline.entries(): WuTimelineEntry[]`

- **Parameters:** No arguments.
- **Returns:** WuTimelineEntry[]
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no resources.

```js
console.table(wu.timeline.entries());
```

The array is shallow-copied; do not use it to mutate the recorder.

Reference: `src/core/wu-timeline.js`.

<span class="section-anchor" id="section-34"></span>

## wu.timeline.status

Queries capture, position, clocks, and used capacity.

`wu.timeline.status(): WuTimelineStatus`

- **Parameters:** No arguments.
- **Returns:** WuTimelineStatus
- **Errors:** The asynchronous family may reject chunk, format, or materialization errors.
- **Permissions:** Host; the scoped facade does not expose global administration.
- **Cleanup:** Installs no resources.

```js
console.log(wu.timeline.status());
```

loaded indicates whether the chunk is available; it does not guarantee recording is active.

Reference: `src/core/wu-timeline.js`.