@yoltra/devtools-ui 0.2.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.es.md +224 -0
- package/README.md +224 -0
- package/dist/devtools-ui.cjs.js +7 -0
- package/dist/devtools-ui.cjs.js.map +1 -0
- package/dist/devtools-ui.esm.js +847 -0
- package/dist/devtools-ui.esm.js.map +1 -0
- package/dist/types/context/HubContext.d.ts +23 -0
- package/dist/types/context/HubProvider.d.ts +34 -0
- package/dist/types/hooks/snapshotRetry.d.ts +46 -0
- package/dist/types/hooks/timeTravelNav.d.ts +52 -0
- package/dist/types/hooks/useEventEmitter.d.ts +44 -0
- package/dist/types/hooks/useEventLog.d.ts +52 -0
- package/dist/types/hooks/useEventReplay.d.ts +36 -0
- package/dist/types/hooks/useHubConnection.d.ts +29 -0
- package/dist/types/hooks/useStoreMetrics.d.ts +56 -0
- package/dist/types/hooks/useStoreRegistry.d.ts +33 -0
- package/dist/types/hooks/useStoreState.d.ts +51 -0
- package/dist/types/hooks/useStoreSubscriptions.d.ts +45 -0
- package/dist/types/hooks/useTimeTravel.d.ts +67 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/transport/loopback.d.ts +30 -0
- package/dist/types/types.d.ts +138 -0
- package/dist/types/utils/apply-patch.d.ts +30 -0
- package/package.json +73 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { RegisteredStore } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks connected stores from `STORE_REGISTRY` hub broadcasts.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* The hook listens for three message types:
|
|
7
|
+
* - `STORE_REGISTRY` -- replaces the full store list (sent on initial connect).
|
|
8
|
+
* - `STORE_CONNECTED` -- adds or updates a single store entry.
|
|
9
|
+
* - `STORE_DISCONNECTED` -- marks a store as `"disconnected"`.
|
|
10
|
+
*
|
|
11
|
+
* The returned array is referentially stable unless the underlying data changes.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { useStoreRegistry } from "@yoltra/devtools-ui";
|
|
16
|
+
*
|
|
17
|
+
* function StoreList() {
|
|
18
|
+
* const stores = useStoreRegistry();
|
|
19
|
+
* return (
|
|
20
|
+
* <ul>
|
|
21
|
+
* {stores.map((s) => (
|
|
22
|
+
* <li key={s.id}>{s.name} ({s.status})</li>
|
|
23
|
+
* ))}
|
|
24
|
+
* </ul>
|
|
25
|
+
* );
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @returns The current list of registered stores (see {@link RegisteredStore}).
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
export declare function useStoreRegistry(): RegisteredStore[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook that provides a live, incrementally-patched view of a store's state.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* On activation, the hook requests a full `STATE_SNAPSHOT` from the hub.
|
|
6
|
+
* While waiting, any `STORE_EVENT` patches that arrive are buffered and
|
|
7
|
+
* replayed once the snapshot lands. After that, each committed patch is
|
|
8
|
+
* applied via {@link applyPatches} so the UI always reflects the latest
|
|
9
|
+
* store state without requiring full snapshots.
|
|
10
|
+
*
|
|
11
|
+
* @module @yoltra/devtools-ui
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Lazily fetches a store's full state and keeps it up-to-date via patches.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* The state is initially `null` until a `STATE_SNAPSHOT` is received.
|
|
18
|
+
* After that, incoming `STORE_EVENT` patches are applied incrementally
|
|
19
|
+
* using {@link applyPatches}. Patches that arrive before the snapshot are
|
|
20
|
+
* buffered and replayed in version order once the snapshot is available.
|
|
21
|
+
*
|
|
22
|
+
* Call `refresh()` to discard the current state and re-fetch from scratch.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { useStoreState } from "@yoltra/devtools-ui";
|
|
27
|
+
*
|
|
28
|
+
* function StateInspector({ storeId }: { storeId: string }) {
|
|
29
|
+
* const { state, version, loading, refresh } = useStoreState(storeId);
|
|
30
|
+
* if (loading) return <p>Loading...</p>;
|
|
31
|
+
* return (
|
|
32
|
+
* <div>
|
|
33
|
+
* <p>Version: {version}</p>
|
|
34
|
+
* <pre>{JSON.stringify(state, null, 2)}</pre>
|
|
35
|
+
* <button onClick={refresh}>Refresh</button>
|
|
36
|
+
* </div>
|
|
37
|
+
* );
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @param storeId - The store ID to track state for, or `null` to disable.
|
|
42
|
+
* @returns An object with `state`, `version`, `loading`, and `refresh`.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export declare function useStoreState(storeId: string | null): {
|
|
47
|
+
state: unknown;
|
|
48
|
+
version: number;
|
|
49
|
+
loading: boolean;
|
|
50
|
+
refresh: () => void;
|
|
51
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { StoreSubscriptions } from '@yoltra/devtools-protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Subscription data payload with protocol envelope fields stripped.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
type SubscriptionData = Omit<StoreSubscriptions, "type" | "timestamp" | "sourceId" | "sourceRole" | "storeId">;
|
|
8
|
+
/**
|
|
9
|
+
* Fetches and caches subscription/consumer info for a store.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* On mount (or when `storeId` changes) the hook sends a
|
|
13
|
+
* `REQUEST_SUBSCRIPTIONS` message and sets `loading` to `true`. When the
|
|
14
|
+
* matching `STORE_SUBSCRIPTIONS` response arrives the data is cached and
|
|
15
|
+
* `loading` flips to `false`.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { useStoreSubscriptions } from "@yoltra/devtools-ui";
|
|
20
|
+
*
|
|
21
|
+
* function SubscriptionPanel({ storeId }: { storeId: string }) {
|
|
22
|
+
* const { data, loading, refresh } = useStoreSubscriptions(storeId);
|
|
23
|
+
* if (loading || !data) return <p>Loading...</p>;
|
|
24
|
+
* return (
|
|
25
|
+
* <div>
|
|
26
|
+
* <p>Atomic: {data.atomic.length}</p>
|
|
27
|
+
* <p>Event: {data.event.length}</p>
|
|
28
|
+
* <button onClick={refresh}>Refresh</button>
|
|
29
|
+
* </div>
|
|
30
|
+
* );
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @param storeId - The store ID to query, or `null` to disable.
|
|
35
|
+
* @returns An object with `data` ({@link SubscriptionData} or `null`),
|
|
36
|
+
* `loading`, and `refresh`.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export declare function useStoreSubscriptions(storeId: string | null): {
|
|
41
|
+
data: SubscriptionData | null;
|
|
42
|
+
loading: boolean;
|
|
43
|
+
refresh: () => void;
|
|
44
|
+
};
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { EventLogEntry } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Provides time-travel navigation through the event log.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* The hook tracks whether the user is actively time-traveling via
|
|
7
|
+
* `isTimeTraveling`. While traveling, `currentIndex` indicates the position
|
|
8
|
+
* within the `entries` array. The `stepBack` / `stepForward` helpers move
|
|
9
|
+
* one entry at a time, while `jumpTo` allows arbitrary positioning. Calling
|
|
10
|
+
* `resume()` exits time-travel mode, jumps to the latest entry, and resets
|
|
11
|
+
* the index to `-1`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { useEventLog, useTimeTravel } from "@yoltra/devtools-ui";
|
|
16
|
+
*
|
|
17
|
+
* function TimeTravelControls({ storeId }: { storeId: string }) {
|
|
18
|
+
* const { entries } = useEventLog(storeId);
|
|
19
|
+
* const { currentIndex, isTimeTraveling, stepBack, stepForward, resume } =
|
|
20
|
+
* useTimeTravel(storeId, entries);
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <div>
|
|
24
|
+
* <button onClick={stepBack} disabled={currentIndex <= 0}>Back</button>
|
|
25
|
+
* <button onClick={stepForward}>Forward</button>
|
|
26
|
+
* {isTimeTraveling && <button onClick={resume}>Resume Live</button>}
|
|
27
|
+
* <span>Index: {currentIndex} / {entries.length - 1}</span>
|
|
28
|
+
* </div>
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @param storeId - The store ID to time-travel, or `null` to disable.
|
|
34
|
+
* @param entries - The event log entries (typically from {@link useEventLog}).
|
|
35
|
+
* @returns An object with `currentIndex`, `isTimeTraveling`, `jumpTo`,
|
|
36
|
+
* `stepBack`, `stepForward`, and `resume`.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export declare function useTimeTravel(storeId: string | null, entries: EventLogEntry[],
|
|
41
|
+
/**
|
|
42
|
+
* Whether the selected store advertised the `replay` capability. Time-travel
|
|
43
|
+
* commands are gated on it (DEV-4): the agent/core enforce it too, but the UI
|
|
44
|
+
* should not send commands that will be dropped. Defaults to `true`.
|
|
45
|
+
*/
|
|
46
|
+
canReplay?: boolean): {
|
|
47
|
+
currentIndex: number;
|
|
48
|
+
isTimeTraveling: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* The store state reconstructed at the currently-viewed position (the
|
|
51
|
+
* scrubbed index while traveling, otherwise the latest entry). `null` until
|
|
52
|
+
* the baseline snapshot has been captured. Lets consumers render a live
|
|
53
|
+
* preview of the state at any point in history.
|
|
54
|
+
*/
|
|
55
|
+
previewState: unknown;
|
|
56
|
+
/**
|
|
57
|
+
* The event count the timeline is measured against: frozen at travel-start
|
|
58
|
+
* so a live-emitting store cannot shift the scrubber, or `null` when live
|
|
59
|
+
* (use `entries.length`). Consumers should size the slider/label off
|
|
60
|
+
* `frameCount ?? entries.length`.
|
|
61
|
+
*/
|
|
62
|
+
frameCount: number | null;
|
|
63
|
+
jumpTo: (index: number) => void;
|
|
64
|
+
stepBack: () => void;
|
|
65
|
+
stepForward: () => void;
|
|
66
|
+
resume: () => void;
|
|
67
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @yoltra/devtools-ui
|
|
3
|
+
*
|
|
4
|
+
* Shared React hooks and business logic for Yoltra DevTools UIs.
|
|
5
|
+
* Used by both `@yoltra/devtools-storeview` (React DOM) and `@yoltra/devtools-cli` (Ink).
|
|
6
|
+
* This package contains no UI components — only logic.
|
|
7
|
+
*/
|
|
8
|
+
export { HubContext } from './context/HubContext';
|
|
9
|
+
export { HubProvider } from './context/HubProvider';
|
|
10
|
+
export { useEventEmitter } from './hooks/useEventEmitter';
|
|
11
|
+
export { useEventLog } from './hooks/useEventLog';
|
|
12
|
+
export { useEventReplay } from './hooks/useEventReplay';
|
|
13
|
+
export { useHubConnection } from './hooks/useHubConnection';
|
|
14
|
+
export { useStoreMetrics } from './hooks/useStoreMetrics';
|
|
15
|
+
export { useStoreRegistry } from './hooks/useStoreRegistry';
|
|
16
|
+
export { useStoreState } from './hooks/useStoreState';
|
|
17
|
+
export { useStoreSubscriptions } from './hooks/useStoreSubscriptions';
|
|
18
|
+
export { useTimeTravel } from './hooks/useTimeTravel';
|
|
19
|
+
export { applyPatches } from './utils/apply-patch';
|
|
20
|
+
export { createLoopbackHub } from './transport/loopback';
|
|
21
|
+
export type { LoopbackHub } from './transport/loopback';
|
|
22
|
+
export type { EventLogEntry, HubConnectionConfig, HubConnectionStatus, HubContextValue, RegisteredStore, } from './types';
|
|
23
|
+
export type { UseEventLogOptions } from './hooks/useEventLog';
|
|
24
|
+
export type { UseStoreMetricsOptions } from './hooks/useStoreMetrics';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DevtoolsSocketFactory } from '@yoltra/devtools-protocol';
|
|
2
|
+
/**
|
|
3
|
+
* A loopback hub instance. Wire the agent and the panel to the *same* instance.
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export interface LoopbackHub {
|
|
8
|
+
/** Inject into the browser agent: `withDevtools(store, { socketFactory })`. */
|
|
9
|
+
agentSocketFactory: DevtoolsSocketFactory;
|
|
10
|
+
/** Pass to the DevTools UI as `config.WebSocket` (e.g. `<DevtoolsApp>`). */
|
|
11
|
+
WebSocket: {
|
|
12
|
+
new (url: string): WebSocket;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates a self-contained in-memory DevTools hub plus the two client transports
|
|
17
|
+
* that connect to it — a `socketFactory` for the store agent and a
|
|
18
|
+
* `WebSocket`-compatible class for the panel UI. No ports, no server, no
|
|
19
|
+
* extension: everything runs in the current process.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const hub = createLoopbackHub();
|
|
24
|
+
* withDevtools(store, { port: 0, socketFactory: hub.agentSocketFactory });
|
|
25
|
+
* // <DevtoolsApp config={{ port: 0, WebSocket: hub.WebSocket }} />
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export declare function createLoopbackHub(): LoopbackHub;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { DevtoolsMessage, StoreCapabilities, StoreEvent } from '@yoltra/devtools-protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Connection configuration for the DevTools hub.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Pass this to {@link HubProvider} to control how the extension connects to
|
|
7
|
+
* the hub server. The only required field is `port`; all other fields have
|
|
8
|
+
* sensible defaults.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const config: HubConnectionConfig = {
|
|
13
|
+
* port: 8900,
|
|
14
|
+
* extensionName: "My Panel",
|
|
15
|
+
* autoReconnect: true,
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* <HubProvider config={config}>
|
|
19
|
+
* <App />
|
|
20
|
+
* </HubProvider>
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export interface HubConnectionConfig {
|
|
26
|
+
/** Hub server host. @defaultValue `"localhost"` */
|
|
27
|
+
host?: string;
|
|
28
|
+
/** Hub server port. */
|
|
29
|
+
port: number;
|
|
30
|
+
/** Display name for this extension instance. */
|
|
31
|
+
extensionName?: string;
|
|
32
|
+
/** Auto-reconnect on disconnect. @defaultValue `true` */
|
|
33
|
+
autoReconnect?: boolean;
|
|
34
|
+
/** Maximum reconnect attempts. @defaultValue `Infinity` */
|
|
35
|
+
maxReconnectAttempts?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Custom WebSocket constructor for Node.js environments.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* In Node.js 18, the global `WebSocket` is not available. Pass the `WebSocket`
|
|
41
|
+
* class from the `ws` package to enable connectivity:
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* import WebSocket from "ws";
|
|
45
|
+
* config.WebSocket = WebSocket as any;
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* In browsers or Node.js 21+, this is not needed — the native `WebSocket` is
|
|
49
|
+
* used automatically.
|
|
50
|
+
*/
|
|
51
|
+
WebSocket?: {
|
|
52
|
+
new (url: string): WebSocket;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Connection status for the hub WebSocket.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* - `"disconnected"` -- no active connection.
|
|
60
|
+
* - `"connecting"` -- WebSocket handshake in progress.
|
|
61
|
+
* - `"connected"` -- handshake complete, messages can be sent and received.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export type HubConnectionStatus = "disconnected" | "connecting" | "connected";
|
|
66
|
+
/**
|
|
67
|
+
* Registered store entry tracked by the store registry.
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* Populated automatically by the {@link useStoreRegistry} hook in response to
|
|
71
|
+
* `STORE_REGISTRY`, `STORE_CONNECTED`, and `STORE_DISCONNECTED` hub messages.
|
|
72
|
+
*
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export interface RegisteredStore {
|
|
76
|
+
/** Unique store identifier assigned by the hub. */
|
|
77
|
+
id: string;
|
|
78
|
+
/** Human-readable store name. */
|
|
79
|
+
name: string;
|
|
80
|
+
/** Current connectivity status of the store. */
|
|
81
|
+
status: "connected" | "connecting" | "disconnected";
|
|
82
|
+
/** Capabilities advertised by the store during handshake. */
|
|
83
|
+
capabilities: StoreCapabilities;
|
|
84
|
+
/** ISO-8601 timestamp of when the store first connected. */
|
|
85
|
+
connectedAt: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A logged event entry in the event log.
|
|
89
|
+
*
|
|
90
|
+
* @remarks
|
|
91
|
+
* Each entry captures a single `STORE_EVENT` message received from the hub,
|
|
92
|
+
* including the event descriptor, resulting patches, and the snapshot version
|
|
93
|
+
* after the event was applied. The {@link useEventLog} hook collects these
|
|
94
|
+
* entries in chronological order.
|
|
95
|
+
*
|
|
96
|
+
* @public
|
|
97
|
+
*/
|
|
98
|
+
export interface EventLogEntry {
|
|
99
|
+
/** The event descriptor (channel, type, payload). */
|
|
100
|
+
event: StoreEvent["event"];
|
|
101
|
+
/** Identifier of the store that emitted the event. */
|
|
102
|
+
storeId: string;
|
|
103
|
+
/** JSON Patch operations produced by the event. */
|
|
104
|
+
patches: StoreEvent["patches"];
|
|
105
|
+
/** Store snapshot version after this event was applied. */
|
|
106
|
+
snapshotVersion: number;
|
|
107
|
+
/** Whether the event was committed to the store. */
|
|
108
|
+
committed: boolean;
|
|
109
|
+
/** ISO-8601 timestamp of the event. */
|
|
110
|
+
timestamp: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Hub connection context value provided to consumers.
|
|
114
|
+
*
|
|
115
|
+
* @remarks
|
|
116
|
+
* This is the shape of the value exposed by {@link HubContext} and consumed
|
|
117
|
+
* via {@link useHubConnection}. It contains methods for sending messages,
|
|
118
|
+
* subscribing to incoming messages, and controlling the connection lifecycle.
|
|
119
|
+
*
|
|
120
|
+
* @public
|
|
121
|
+
*/
|
|
122
|
+
export interface HubContextValue {
|
|
123
|
+
/** Current connection status. */
|
|
124
|
+
status: HubConnectionStatus;
|
|
125
|
+
/** Send a protocol message to the hub. */
|
|
126
|
+
send: (message: DevtoolsMessage) => void;
|
|
127
|
+
/**
|
|
128
|
+
* Subscribe to incoming hub messages.
|
|
129
|
+
*
|
|
130
|
+
* @param handler - Callback invoked for every incoming message.
|
|
131
|
+
* @returns An unsubscribe function.
|
|
132
|
+
*/
|
|
133
|
+
subscribe: (handler: (message: DevtoolsMessage) => void) => () => void;
|
|
134
|
+
/** Manually disconnect from the hub and cancel auto-reconnect. */
|
|
135
|
+
disconnect: () => void;
|
|
136
|
+
/** Reset reconnect attempts and establish a fresh connection. */
|
|
137
|
+
reconnect: () => void;
|
|
138
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { JsonPatch } from '@yoltra/devtools-protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Apply an array of RFC 6902 JSON Patch operations to a value.
|
|
4
|
+
* Returns a new object -- does not mutate the input.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Only the `add`, `remove`, and `replace` operations are implemented because
|
|
8
|
+
* the v1 devtools protocol does not emit `move`, `copy`, or `test` patches.
|
|
9
|
+
* Each operation is applied sequentially in array order. Path segments are
|
|
10
|
+
* resolved according to RFC 6901 (JSON Pointer), including `~0` / `~1`
|
|
11
|
+
* escape handling.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { applyPatches } from "@yoltra/devtools-ui";
|
|
16
|
+
*
|
|
17
|
+
* const next = applyPatches(
|
|
18
|
+
* { counter: { value: 0 } },
|
|
19
|
+
* [{ op: "replace", path: "/counter/value", value: 1 }],
|
|
20
|
+
* );
|
|
21
|
+
* // next => { counter: { value: 1 } }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param target - The value to patch.
|
|
25
|
+
* @param patches - RFC 6902 operations.
|
|
26
|
+
* @returns A new patched value.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyPatches<T = unknown>(target: T, patches: JsonPatch[]): T;
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yoltra/devtools-ui",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Shared React hooks and business logic for Yoltra DevTools UIs",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Manu Ramirez <@pixerael>",
|
|
8
|
+
"email": "manu@yoltra.dev"
|
|
9
|
+
},
|
|
10
|
+
"maintainers": [],
|
|
11
|
+
"homepage": "https://yoltra.dev",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"yoltra",
|
|
14
|
+
"devtools",
|
|
15
|
+
"ui",
|
|
16
|
+
"hooks"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/yoltra/yoltra.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/yoltra/yoltra/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "dist/devtools-ui.cjs.js",
|
|
27
|
+
"module": "dist/devtools-ui.esm.js",
|
|
28
|
+
"types": "dist/types/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/types/index.d.ts",
|
|
32
|
+
"import": "./dist/devtools-ui.esm.js",
|
|
33
|
+
"require": "./dist/devtools-ui.cjs.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"sideEffects": false,
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": "^18 || ^19"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@yoltra/devtools-protocol": "0.2.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"react": "19.1.1",
|
|
48
|
+
"@types/react": "^19.1.8",
|
|
49
|
+
"typedoc": "^0.28.13",
|
|
50
|
+
"typedoc-plugin-markdown": "4.9.0",
|
|
51
|
+
"typedoc-plugin-localization": "3.0.6",
|
|
52
|
+
"typescript": "5.9.3",
|
|
53
|
+
"vite": "^7.1.11",
|
|
54
|
+
"vite-plugin-dts": "^4.5.4",
|
|
55
|
+
"vite-plugin-banner": "0.8.1",
|
|
56
|
+
"vitest": "3.2.4"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.18"
|
|
60
|
+
},
|
|
61
|
+
"publishConfig": {
|
|
62
|
+
"access": "public"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "vite build",
|
|
66
|
+
"test": "vitest --watch=false",
|
|
67
|
+
"lint": "node ../../tools/repo-tools/bin/repo-eslint.cjs --report-unused-disable-directives --max-warnings 0",
|
|
68
|
+
"typecheck": "tsc --noEmit",
|
|
69
|
+
"docs": "rushx docs:js && rushx docs:md",
|
|
70
|
+
"docs:md": "pnpm typedoc --options ./typedoc.json",
|
|
71
|
+
"docs:js": "pnpm typedoc --options ./typedoc.json --json ./.typedoc/devtools-ui-en.json"
|
|
72
|
+
}
|
|
73
|
+
}
|