@aotui/mobile-ai-native 0.1.0-alpha.0 → 0.1.0-alpha.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/GUIDE.md +79 -109
- package/LICENSE +201 -0
- package/README.md +106 -40
- package/dist/core/action/createActionRuntime.d.ts +6 -6
- package/dist/core/action/createActionRuntime.js +71 -18
- package/dist/core/action/defineAction.d.ts +4 -5
- package/dist/core/action/defineViewTypeTool.d.ts +5 -0
- package/dist/core/action/defineViewTypeTool.js +3 -0
- package/dist/core/effect/types.d.ts +21 -1
- package/dist/core/snapshot/createSnapshotBundle.d.ts +7 -4
- package/dist/core/snapshot/createSnapshotBundle.js +110 -3
- package/dist/core/snapshot/createSnapshotRegistry.d.ts +4 -0
- package/dist/core/snapshot/createSnapshotRegistry.js +52 -0
- package/dist/core/trace/createTraceStore.d.ts +2 -0
- package/dist/core/trace/createTraceStore.js +38 -0
- package/dist/core/trace/types.d.ts +21 -0
- package/dist/core/trace/types.js +1 -0
- package/dist/core/types.d.ts +61 -10
- package/dist/demo/inbox/InboxGUI.js +5 -3
- package/dist/demo/inbox/InboxTUI.d.ts +3 -1
- package/dist/demo/inbox/InboxTUI.js +73 -7
- package/dist/demo/inbox/actions.d.ts +2 -2
- package/dist/demo/inbox/actions.js +15 -4
- package/dist/demo/inbox/createInboxApp.d.ts +2 -5
- package/dist/demo/inbox/createInboxApp.js +4 -4
- package/dist/demo/inbox/effects.d.ts +3 -5
- package/dist/demo/inbox/effects.js +5 -0
- package/dist/demo/inbox/state.d.ts +3 -0
- package/dist/demo/inbox/state.js +16 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +12 -2
- package/dist/projection/gui/AppProvider.d.ts +8 -12
- package/dist/projection/gui/AppProvider.js +77 -2
- package/dist/projection/gui/hooks.d.ts +2 -5
- package/dist/projection/gui/hooks.js +3 -12
- package/dist/projection/react/AppRuntimeProvider.d.ts +10 -0
- package/dist/projection/react/AppRuntimeProvider.js +15 -0
- package/dist/projection/react/createReactAppRuntime.d.ts +35 -0
- package/dist/projection/react/createReactAppRuntime.js +80 -0
- package/dist/projection/react/hooks.d.ts +8 -0
- package/dist/projection/react/hooks.js +18 -0
- package/dist/projection/tui/View.d.ts +8 -0
- package/dist/projection/tui/View.js +5 -0
- package/dist/projection/tui/createSnapshotAssembler.d.ts +2 -0
- package/dist/projection/tui/createSnapshotAssembler.js +14 -0
- package/dist/projection/tui/renderSnapshotDocument.d.ts +2 -0
- package/dist/projection/tui/renderSnapshotDocument.js +3 -0
- package/dist/projection/tui/renderTUI.d.ts +1 -1
- package/dist/projection/tui/renderTUI.js +13 -4
- package/dist/projection/tui/renderViewFragment.d.ts +10 -0
- package/dist/projection/tui/renderViewFragment.js +15 -0
- package/dist/tool/createToolBridge.d.ts +4 -9
- package/dist/tool/createToolBridge.js +55 -11
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +8 -9
|
@@ -6,10 +6,10 @@ declare const inboxMessageSchema: z.ZodObject<{
|
|
|
6
6
|
opened: z.ZodBoolean;
|
|
7
7
|
}, z.core.$strip>;
|
|
8
8
|
export declare function createInboxActions(): {
|
|
9
|
-
openMessage: import("
|
|
9
|
+
openMessage: import("../..").ViewTypeToolActionDefinition<InboxState, InboxEvent, {
|
|
10
10
|
message: z.infer<typeof inboxMessageSchema>;
|
|
11
11
|
}>;
|
|
12
|
-
searchMessages: import("
|
|
12
|
+
searchMessages: import("../..").ViewTypeToolActionDefinition<InboxState, InboxEvent, {
|
|
13
13
|
query: string;
|
|
14
14
|
}>;
|
|
15
15
|
};
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { defineViewTypeTool } from "../../core/action/defineViewTypeTool";
|
|
3
|
+
import { isInboxSearchActive, isInboxSearchRelevant } from "./state";
|
|
3
4
|
const inboxMessageSchema = z.object({
|
|
4
5
|
id: z.string(),
|
|
5
6
|
subject: z.string(),
|
|
6
7
|
opened: z.boolean(),
|
|
7
8
|
});
|
|
8
9
|
export function createInboxActions() {
|
|
9
|
-
const openMessage =
|
|
10
|
+
const openMessage = defineViewTypeTool({
|
|
10
11
|
name: "openMessage",
|
|
11
12
|
description: "Open a message from the inbox.",
|
|
12
13
|
schema: z.object({
|
|
13
14
|
message: inboxMessageSchema,
|
|
14
15
|
}),
|
|
16
|
+
viewType: "Inbox",
|
|
17
|
+
meta: {
|
|
18
|
+
supportsRefs: true,
|
|
19
|
+
},
|
|
15
20
|
visibility(state) {
|
|
16
21
|
return state.shell.currentTab === "inbox";
|
|
17
22
|
},
|
|
@@ -23,18 +28,22 @@ export function createInboxActions() {
|
|
|
23
28
|
});
|
|
24
29
|
return {
|
|
25
30
|
success: true,
|
|
31
|
+
mutated: true,
|
|
32
|
+
message: `Opened message ${input.message.subject}`,
|
|
26
33
|
data: { openedMessageId: input.message.id },
|
|
27
34
|
};
|
|
28
35
|
},
|
|
29
36
|
});
|
|
30
|
-
const searchMessages =
|
|
37
|
+
const searchMessages = defineViewTypeTool({
|
|
31
38
|
name: "searchMessages",
|
|
32
39
|
description: "Search inbox messages.",
|
|
33
40
|
schema: z.object({
|
|
34
41
|
query: z.string().min(1),
|
|
35
42
|
}),
|
|
43
|
+
viewType: "Inbox",
|
|
36
44
|
visibility(state) {
|
|
37
|
-
return state.shell.currentTab === "inbox"
|
|
45
|
+
return (state.shell.currentTab === "inbox" &&
|
|
46
|
+
(isInboxSearchRelevant(state) || isInboxSearchActive(state)));
|
|
38
47
|
},
|
|
39
48
|
async handler(ctx, input) {
|
|
40
49
|
ctx.emit({ type: "SearchStarted", query: input.query });
|
|
@@ -42,9 +51,11 @@ export function createInboxActions() {
|
|
|
42
51
|
type: "TraceUpdated",
|
|
43
52
|
summary: `Started search for ${input.query}`,
|
|
44
53
|
});
|
|
54
|
+
ctx.trace.update(`Started search for ${input.query}`);
|
|
45
55
|
await ctx.runEffect("searchMessages", input);
|
|
46
56
|
return {
|
|
47
57
|
success: true,
|
|
58
|
+
mutated: true,
|
|
48
59
|
message: `Started search for ${input.query}`,
|
|
49
60
|
};
|
|
50
61
|
},
|
|
@@ -4,11 +4,8 @@ export declare function createInboxApp(config: {
|
|
|
4
4
|
}): {
|
|
5
5
|
store: import("../../core/types").Store<import("./state").InboxState, import("./state").InboxEvent>;
|
|
6
6
|
bridge: {
|
|
7
|
-
listTools():
|
|
8
|
-
|
|
9
|
-
description: string;
|
|
10
|
-
}[];
|
|
11
|
-
getSnapshotBundle(): import("../../core/types").SnapshotBundle;
|
|
7
|
+
listTools(): import("../..").ToolDefinition[];
|
|
8
|
+
getSnapshotBundle(): import("../..").SnapshotBundle;
|
|
12
9
|
executeTool(name: string, input: Record<string, unknown>, snapshotId: string): Promise<import("../../core/types").ActionResult>;
|
|
13
10
|
};
|
|
14
11
|
gui: {
|
|
@@ -3,14 +3,13 @@ import { jsx as _jsx } from "preact/jsx-runtime";
|
|
|
3
3
|
import renderToString from "preact-render-to-string";
|
|
4
4
|
import { createActionRuntime } from "../../core/action/createActionRuntime";
|
|
5
5
|
import { createStore } from "../../core/state/createStore";
|
|
6
|
-
import { renderTUI } from "../../projection/tui/renderTUI";
|
|
7
6
|
import { AppProvider } from "../../projection/gui/AppProvider";
|
|
8
7
|
import { createToolBridge } from "../../tool/createToolBridge";
|
|
9
8
|
import { createInboxActions } from "./actions";
|
|
10
9
|
import { createInboxEffects } from "./effects";
|
|
11
10
|
import { InboxGUI } from "./InboxGUI";
|
|
12
|
-
import {
|
|
13
|
-
import { createInitialInboxState, reduceInboxState, } from "./state";
|
|
11
|
+
import { createInboxSnapshotBundle, } from "./InboxTUI";
|
|
12
|
+
import { createInitialInboxState, getInboxRelevantViewTypes, reduceInboxState, } from "./state";
|
|
14
13
|
export function createInboxApp(config) {
|
|
15
14
|
const store = createStore({
|
|
16
15
|
initialState: createInitialInboxState(config.initialMessages),
|
|
@@ -21,11 +20,12 @@ export function createInboxApp(config) {
|
|
|
21
20
|
store,
|
|
22
21
|
actions: [actions.openMessage, actions.searchMessages],
|
|
23
22
|
effects: createInboxEffects(config.initialMessages),
|
|
23
|
+
getRelevantViewTypes: () => getInboxRelevantViewTypes(store.getState()),
|
|
24
24
|
});
|
|
25
25
|
const bridge = createToolBridge({
|
|
26
26
|
actionRuntime,
|
|
27
27
|
renderCurrentSnapshot() {
|
|
28
|
-
return
|
|
28
|
+
return createInboxSnapshotBundle(store.getState(), actionRuntime.listVisibleTools());
|
|
29
29
|
},
|
|
30
30
|
});
|
|
31
31
|
function renderGUI() {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { InboxEvent, InboxMessage, InboxState } from "./state";
|
|
2
|
+
import type { EffectContext, EffectResult } from "../../core/effect/types";
|
|
2
3
|
export declare function createInboxEffects(allMessages: InboxMessage[]): {
|
|
3
|
-
searchMessages(ctx: {
|
|
4
|
-
getState(): InboxState;
|
|
5
|
-
emit(event: InboxEvent): void;
|
|
6
|
-
}, input: {
|
|
4
|
+
searchMessages(ctx: EffectContext<InboxState, InboxEvent>, input: {
|
|
7
5
|
query: string;
|
|
8
|
-
}): Promise<
|
|
6
|
+
}): Promise<EffectResult>;
|
|
9
7
|
};
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
export function createInboxEffects(allMessages) {
|
|
2
2
|
return {
|
|
3
3
|
async searchMessages(ctx, input) {
|
|
4
|
+
ctx.trace.update(`Searching ${input.query}`);
|
|
4
5
|
const items = allMessages.filter((item) => item.subject.toLowerCase().includes(input.query.toLowerCase()));
|
|
5
6
|
ctx.emit({
|
|
6
7
|
type: "SearchSucceeded",
|
|
7
8
|
query: input.query,
|
|
8
9
|
items,
|
|
9
10
|
});
|
|
11
|
+
ctx.trace.update(`Found ${items.length} matching messages`);
|
|
12
|
+
return {
|
|
13
|
+
success: true,
|
|
14
|
+
};
|
|
10
15
|
},
|
|
11
16
|
};
|
|
12
17
|
}
|
|
@@ -31,3 +31,6 @@ export type InboxEvent = {
|
|
|
31
31
|
};
|
|
32
32
|
export declare function createInitialInboxState(messages: InboxMessage[]): InboxState;
|
|
33
33
|
export declare function reduceInboxState(state: InboxState, event: InboxEvent): InboxState;
|
|
34
|
+
export declare function isInboxSearchRelevant(state: InboxState): boolean;
|
|
35
|
+
export declare function isInboxSearchActive(state: InboxState): boolean;
|
|
36
|
+
export declare function getInboxRelevantViewTypes(state: InboxState): string[];
|
package/dist/demo/inbox/state.js
CHANGED
|
@@ -54,3 +54,19 @@ export function reduceInboxState(state, event) {
|
|
|
54
54
|
return state;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
export function isInboxSearchRelevant(state) {
|
|
58
|
+
return state.inbox.items.length > 1;
|
|
59
|
+
}
|
|
60
|
+
export function isInboxSearchActive(state) {
|
|
61
|
+
return state.inbox.isLoading || state.inbox.query.trim().length > 0;
|
|
62
|
+
}
|
|
63
|
+
export function getInboxRelevantViewTypes(state) {
|
|
64
|
+
const viewTypes = ["Root", "Inbox"];
|
|
65
|
+
if (isInboxSearchActive(state)) {
|
|
66
|
+
viewTypes.push("InboxSearch");
|
|
67
|
+
}
|
|
68
|
+
if (state.inbox.openedMessageId) {
|
|
69
|
+
viewTypes.push("MessageDetail");
|
|
70
|
+
}
|
|
71
|
+
return viewTypes;
|
|
72
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
import { createSnapshotBundle } from "./core/snapshot/createSnapshotBundle";
|
|
2
|
+
import { VERSION } from "./version";
|
|
3
|
+
export { VERSION };
|
|
2
4
|
export { createStore } from "./core/state/createStore";
|
|
3
|
-
export { createSnapshotBundle }
|
|
5
|
+
export { createSnapshotBundle };
|
|
6
|
+
export type { RefIndexEntry, MountedViewDescriptor, SnapshotBundle, TraceState, ToolDefinition, StaticViewCatalogEntry, SnapshotAssemblerInput, ViewFragment, } from "./core/types";
|
|
7
|
+
export type { EffectContext, EffectFailure, EffectHandler, EffectMap, EffectResult, EffectSuccess, EffectTrace, } from "./core/effect/types";
|
|
8
|
+
export type { ActionContext, ActionDefinition, } from "./core/action/defineAction";
|
|
9
|
+
export type { ViewTypeToolActionDefinition, } from "./core/action/defineViewTypeTool";
|
|
4
10
|
export { defineAction } from "./core/action/defineAction";
|
|
11
|
+
export { defineViewTypeTool } from "./core/action/defineViewTypeTool";
|
|
5
12
|
export { createActionRuntime } from "./core/action/createActionRuntime";
|
|
6
13
|
export { createToolBridge } from "./tool/createToolBridge";
|
|
7
14
|
export { useDataRef } from "./ref/useDataRef";
|
|
8
15
|
export { useArrayRef } from "./ref/useArrayRef";
|
|
16
|
+
export { View } from "./projection/tui/View";
|
|
17
|
+
export { createSnapshotAssembler } from "./projection/tui/createSnapshotAssembler";
|
|
9
18
|
export { renderTUI } from "./projection/tui/renderTUI";
|
|
19
|
+
export { createReactAppRuntime } from "./projection/react/createReactAppRuntime";
|
|
20
|
+
export type { ReactAppDefinition, ReactAppRuntime, RuntimeTrace, } from "./projection/react/createReactAppRuntime";
|
|
21
|
+
export { AppRuntimeProvider } from "./projection/react/AppRuntimeProvider";
|
|
22
|
+
export { useAppRuntime, useRuntimeActions, useRuntimeState, useRuntimeTrace } from "./projection/react/hooks";
|
|
23
|
+
export { AppProvider } from "./projection/gui/AppProvider";
|
|
24
|
+
export { useAppState, useActions } from "./projection/gui/hooks";
|
|
10
25
|
export { createInboxApp } from "./demo/inbox/createInboxApp";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import { createSnapshotBundle } from "./core/snapshot/createSnapshotBundle";
|
|
2
|
+
import { VERSION } from "./version";
|
|
3
|
+
export { VERSION };
|
|
2
4
|
export { createStore } from "./core/state/createStore";
|
|
3
|
-
export { createSnapshotBundle }
|
|
5
|
+
export { createSnapshotBundle };
|
|
4
6
|
export { defineAction } from "./core/action/defineAction";
|
|
7
|
+
export { defineViewTypeTool } from "./core/action/defineViewTypeTool";
|
|
5
8
|
export { createActionRuntime } from "./core/action/createActionRuntime";
|
|
6
9
|
export { createToolBridge } from "./tool/createToolBridge";
|
|
7
10
|
export { useDataRef } from "./ref/useDataRef";
|
|
8
11
|
export { useArrayRef } from "./ref/useArrayRef";
|
|
12
|
+
export { View } from "./projection/tui/View";
|
|
13
|
+
export { createSnapshotAssembler } from "./projection/tui/createSnapshotAssembler";
|
|
9
14
|
export { renderTUI } from "./projection/tui/renderTUI";
|
|
15
|
+
export { createReactAppRuntime } from "./projection/react/createReactAppRuntime";
|
|
16
|
+
export { AppRuntimeProvider } from "./projection/react/AppRuntimeProvider";
|
|
17
|
+
export { useAppRuntime, useRuntimeActions, useRuntimeState, useRuntimeTrace } from "./projection/react/hooks";
|
|
18
|
+
export { AppProvider } from "./projection/gui/AppProvider";
|
|
19
|
+
export { useAppState, useActions } from "./projection/gui/hooks";
|
|
10
20
|
export { createInboxApp } from "./demo/inbox/createInboxApp";
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import type { ComponentChildren } from "preact";
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
2
|
+
import type { ActionResult, Store, ToolDefinition } from "../../core/types";
|
|
3
|
+
type LegacyAppContextValue = {
|
|
4
|
+
store: Store<unknown, unknown>;
|
|
6
5
|
actionRuntime: {
|
|
7
|
-
executeAction(name: string, input: Record<string, unknown>): Promise<
|
|
8
|
-
listVisibleTools():
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
}>;
|
|
6
|
+
executeAction(name: string, input: Record<string, unknown>): Promise<ActionResult>;
|
|
7
|
+
listVisibleTools(): ToolDefinition[];
|
|
12
8
|
};
|
|
13
9
|
};
|
|
14
10
|
export declare function AppProvider(props: {
|
|
15
|
-
store:
|
|
16
|
-
actionRuntime:
|
|
11
|
+
store: LegacyAppContextValue["store"];
|
|
12
|
+
actionRuntime: LegacyAppContextValue["actionRuntime"];
|
|
17
13
|
children: ComponentChildren;
|
|
18
14
|
}): import("preact").JSX.Element;
|
|
19
|
-
export declare function useAppContext():
|
|
15
|
+
export declare function useAppContext(): LegacyAppContextValue;
|
|
20
16
|
export {};
|
|
@@ -1,10 +1,85 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource preact */
|
|
3
3
|
import { createContext } from "preact";
|
|
4
|
-
import { useContext } from "preact/hooks";
|
|
4
|
+
import { useContext, useMemo } from "preact/hooks";
|
|
5
|
+
import { AppRuntimeProvider } from "../react/AppRuntimeProvider";
|
|
5
6
|
const AppContext = createContext(null);
|
|
7
|
+
function createCompatibilityRuntime(value) {
|
|
8
|
+
let nextTraceId = 1;
|
|
9
|
+
return {
|
|
10
|
+
store: value.store,
|
|
11
|
+
actionRuntime: value.actionRuntime,
|
|
12
|
+
traceStore: {
|
|
13
|
+
getState() {
|
|
14
|
+
return {
|
|
15
|
+
entries: [],
|
|
16
|
+
recent: null,
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
subscribe() {
|
|
20
|
+
return () => { };
|
|
21
|
+
},
|
|
22
|
+
record(entry) {
|
|
23
|
+
return {
|
|
24
|
+
id: `compat_trace_${nextTraceId++}`,
|
|
25
|
+
actionName: entry.actionName,
|
|
26
|
+
status: entry.status,
|
|
27
|
+
summary: entry.summary,
|
|
28
|
+
recordedAt: Date.now(),
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
trace: {
|
|
33
|
+
getState() {
|
|
34
|
+
return {
|
|
35
|
+
entries: [],
|
|
36
|
+
recent: null,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
getEntries() {
|
|
40
|
+
return [];
|
|
41
|
+
},
|
|
42
|
+
getRecent() {
|
|
43
|
+
return undefined;
|
|
44
|
+
},
|
|
45
|
+
subscribe() {
|
|
46
|
+
return () => { };
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
snapshotRegistry: {
|
|
50
|
+
create(snapshot) {
|
|
51
|
+
return snapshot;
|
|
52
|
+
},
|
|
53
|
+
lookup() {
|
|
54
|
+
return undefined;
|
|
55
|
+
},
|
|
56
|
+
markStale() { },
|
|
57
|
+
},
|
|
58
|
+
toolBridge: {
|
|
59
|
+
listTools() {
|
|
60
|
+
return value.actionRuntime.listVisibleTools();
|
|
61
|
+
},
|
|
62
|
+
getSnapshotBundle() {
|
|
63
|
+
throw new Error("Snapshot rendering is not available through AppProvider");
|
|
64
|
+
},
|
|
65
|
+
executeTool(_name, _input, _snapshotId) {
|
|
66
|
+
return Promise.reject(new Error("Snapshot-scoped tool execution is not available through AppProvider"));
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
actions: {
|
|
70
|
+
callAction(name, input) {
|
|
71
|
+
return value.actionRuntime.executeAction(name, input);
|
|
72
|
+
},
|
|
73
|
+
getVisibleTools() {
|
|
74
|
+
return value.actionRuntime.listVisibleTools();
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
6
79
|
export function AppProvider(props) {
|
|
7
|
-
|
|
80
|
+
const value = useMemo(() => ({ store: props.store, actionRuntime: props.actionRuntime }), [props.store, props.actionRuntime]);
|
|
81
|
+
const runtime = useMemo(() => createCompatibilityRuntime(value), [value]);
|
|
82
|
+
return (_jsx(AppContext.Provider, { value: value, children: _jsx(AppRuntimeProvider, { runtime: runtime, children: props.children }) }));
|
|
8
83
|
}
|
|
9
84
|
export function useAppContext() {
|
|
10
85
|
const context = useContext(AppContext);
|
|
@@ -2,9 +2,6 @@ export declare function useAppState<State>(): {
|
|
|
2
2
|
state: State;
|
|
3
3
|
};
|
|
4
4
|
export declare function useActions(): {
|
|
5
|
-
callAction(name: string, input: Record<string, unknown>): Promise<
|
|
6
|
-
getVisibleTools():
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
}[];
|
|
5
|
+
callAction(name: string, input: Record<string, unknown>): Promise<import("../../core/types").ActionResult>;
|
|
6
|
+
getVisibleTools(): import("../..").ToolDefinition[];
|
|
10
7
|
};
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useRuntimeActions, useRuntimeState } from "../react/hooks";
|
|
2
2
|
export function useAppState() {
|
|
3
|
-
const { store } = useAppContext();
|
|
4
3
|
return {
|
|
5
|
-
state:
|
|
4
|
+
state: useRuntimeState((state) => state),
|
|
6
5
|
};
|
|
7
6
|
}
|
|
8
7
|
export function useActions() {
|
|
9
|
-
|
|
10
|
-
return {
|
|
11
|
-
callAction(name, input) {
|
|
12
|
-
return actionRuntime.executeAction(name, input);
|
|
13
|
-
},
|
|
14
|
-
getVisibleTools() {
|
|
15
|
-
return actionRuntime.listVisibleTools();
|
|
16
|
-
},
|
|
17
|
-
};
|
|
8
|
+
return useRuntimeActions();
|
|
18
9
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ComponentChildren } from "preact";
|
|
2
|
+
import type { ReactAppRuntime, RuntimeTrace } from "./createReactAppRuntime";
|
|
3
|
+
export type AppRuntime<State = unknown, Event = unknown> = ReactAppRuntime<State, Event> & {
|
|
4
|
+
trace: RuntimeTrace;
|
|
5
|
+
};
|
|
6
|
+
export declare function AppRuntimeProvider(props: {
|
|
7
|
+
runtime: AppRuntime;
|
|
8
|
+
children: ComponentChildren;
|
|
9
|
+
}): import("preact").JSX.Element;
|
|
10
|
+
export declare function useAppRuntimeContext(): AppRuntime<unknown, unknown>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
import { createContext } from "preact";
|
|
4
|
+
import { useContext } from "preact/hooks";
|
|
5
|
+
const AppRuntimeContext = createContext(null);
|
|
6
|
+
export function AppRuntimeProvider(props) {
|
|
7
|
+
return (_jsx(AppRuntimeContext.Provider, { value: props.runtime, children: props.children }));
|
|
8
|
+
}
|
|
9
|
+
export function useAppRuntimeContext() {
|
|
10
|
+
const runtime = useContext(AppRuntimeContext);
|
|
11
|
+
if (!runtime) {
|
|
12
|
+
throw new Error("AppRuntimeProvider is missing from the component tree");
|
|
13
|
+
}
|
|
14
|
+
return runtime;
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createActionRuntime } from "../../core/action/createActionRuntime";
|
|
2
|
+
import type { ActionDefinition } from "../../core/action/defineAction";
|
|
3
|
+
import type { EffectMap } from "../../core/effect/types";
|
|
4
|
+
import type { ActionResult, SnapshotBundle, SnapshotRegistry, StateReducer, Store, ToolDefinition, TraceRecord, TraceState, TraceStore } from "../../core/types";
|
|
5
|
+
import { createToolBridge } from "../../tool/createToolBridge";
|
|
6
|
+
export type ReactAppDefinition<State, Event> = {
|
|
7
|
+
initialState: State;
|
|
8
|
+
reduce: StateReducer<State, Event>;
|
|
9
|
+
actions: Array<ActionDefinition<State, Event, any>>;
|
|
10
|
+
effects?: EffectMap<State, Event>;
|
|
11
|
+
getRelevantViewTypes?: (state: State) => readonly string[];
|
|
12
|
+
renderCurrentSnapshot?: (context: {
|
|
13
|
+
state: State;
|
|
14
|
+
visibleTools: readonly ToolDefinition[];
|
|
15
|
+
}) => SnapshotBundle;
|
|
16
|
+
};
|
|
17
|
+
export type ReactAppRuntime<State, Event> = {
|
|
18
|
+
store: Store<State, Event>;
|
|
19
|
+
actionRuntime: ReturnType<typeof createActionRuntime<State, Event>>;
|
|
20
|
+
traceStore: TraceStore;
|
|
21
|
+
trace: RuntimeTrace;
|
|
22
|
+
snapshotRegistry: SnapshotRegistry;
|
|
23
|
+
toolBridge: ReturnType<typeof createToolBridge>;
|
|
24
|
+
actions: {
|
|
25
|
+
callAction(name: string, input: Record<string, unknown>): Promise<ActionResult>;
|
|
26
|
+
getVisibleTools(): ToolDefinition[];
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export type RuntimeTrace = {
|
|
30
|
+
getState(): TraceState;
|
|
31
|
+
getEntries(): TraceRecord[];
|
|
32
|
+
getRecent(): TraceRecord | undefined;
|
|
33
|
+
subscribe(listener: () => void): () => void;
|
|
34
|
+
};
|
|
35
|
+
export declare function createReactAppRuntime<State, Event>(app: ReactAppDefinition<State, Event>): ReactAppRuntime<State, Event>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { createActionRuntime } from "../../core/action/createActionRuntime";
|
|
2
|
+
import { createSnapshotRegistry } from "../../core/snapshot/createSnapshotRegistry";
|
|
3
|
+
import { createStore } from "../../core/state/createStore";
|
|
4
|
+
import { createTraceStore } from "../../core/trace/createTraceStore";
|
|
5
|
+
import { createSnapshotAssembler } from "../tui/createSnapshotAssembler";
|
|
6
|
+
import { renderViewFragment } from "../tui/renderViewFragment";
|
|
7
|
+
import { createToolBridge } from "../../tool/createToolBridge";
|
|
8
|
+
export function createReactAppRuntime(app) {
|
|
9
|
+
const store = createStore({
|
|
10
|
+
initialState: app.initialState,
|
|
11
|
+
reduce: app.reduce,
|
|
12
|
+
});
|
|
13
|
+
const traceStore = createTraceStore();
|
|
14
|
+
const getRelevantViewTypes = app.getRelevantViewTypes;
|
|
15
|
+
const actionRuntime = createActionRuntime({
|
|
16
|
+
store,
|
|
17
|
+
actions: app.actions,
|
|
18
|
+
traceStore,
|
|
19
|
+
effects: app.effects,
|
|
20
|
+
getRelevantViewTypes: getRelevantViewTypes
|
|
21
|
+
? () => getRelevantViewTypes(store.getState())
|
|
22
|
+
: undefined,
|
|
23
|
+
});
|
|
24
|
+
const snapshotRegistry = createSnapshotRegistry({ maxEntries: 2 });
|
|
25
|
+
const renderCurrentSnapshot = app.renderCurrentSnapshot ??
|
|
26
|
+
(() => createSnapshotAssembler({
|
|
27
|
+
rootView: renderViewFragment({
|
|
28
|
+
id: "root",
|
|
29
|
+
type: "Root",
|
|
30
|
+
name: "Navigation",
|
|
31
|
+
children: "No custom snapshot renderer configured.",
|
|
32
|
+
}),
|
|
33
|
+
mountedViews: [],
|
|
34
|
+
refIndex: {},
|
|
35
|
+
visibleTools: actionRuntime.listVisibleTools(),
|
|
36
|
+
}));
|
|
37
|
+
const toolBridge = createToolBridge({
|
|
38
|
+
actionRuntime,
|
|
39
|
+
snapshotRegistry,
|
|
40
|
+
renderCurrentSnapshot() {
|
|
41
|
+
return renderCurrentSnapshot({
|
|
42
|
+
state: store.getState(),
|
|
43
|
+
visibleTools: actionRuntime.listVisibleTools(),
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
store,
|
|
49
|
+
actionRuntime,
|
|
50
|
+
traceStore,
|
|
51
|
+
trace: {
|
|
52
|
+
getState() {
|
|
53
|
+
return traceStore.getState();
|
|
54
|
+
},
|
|
55
|
+
getEntries() {
|
|
56
|
+
return traceStore.getState().entries;
|
|
57
|
+
},
|
|
58
|
+
getRecent() {
|
|
59
|
+
return traceStore.getState().recent ?? undefined;
|
|
60
|
+
},
|
|
61
|
+
subscribe(listener) {
|
|
62
|
+
return traceStore.subscribe(listener);
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
snapshotRegistry,
|
|
66
|
+
toolBridge,
|
|
67
|
+
actions: {
|
|
68
|
+
async callAction(name, input) {
|
|
69
|
+
const result = await actionRuntime.executeAction(name, input);
|
|
70
|
+
if (result.mutated) {
|
|
71
|
+
snapshotRegistry.markAllStale?.();
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
},
|
|
75
|
+
getVisibleTools() {
|
|
76
|
+
return actionRuntime.listVisibleTools();
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TraceState } from "../../core/types";
|
|
2
|
+
export declare function useAppRuntime(): import("./AppRuntimeProvider").AppRuntime<unknown, unknown>;
|
|
3
|
+
export declare function useRuntimeState<State, Selected>(selector: (state: State) => Selected): Selected;
|
|
4
|
+
export declare function useRuntimeActions(): {
|
|
5
|
+
callAction(name: string, input: Record<string, unknown>): Promise<import("../../core/types").ActionResult>;
|
|
6
|
+
getVisibleTools(): import("../..").ToolDefinition[];
|
|
7
|
+
};
|
|
8
|
+
export declare function useRuntimeTrace<Selected>(selector: (trace: TraceState) => Selected): Selected;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "preact/compat";
|
|
2
|
+
import { useAppRuntimeContext } from "./AppRuntimeProvider";
|
|
3
|
+
export function useAppRuntime() {
|
|
4
|
+
return useAppRuntimeContext();
|
|
5
|
+
}
|
|
6
|
+
export function useRuntimeState(selector) {
|
|
7
|
+
const runtime = useAppRuntimeContext();
|
|
8
|
+
const getSnapshot = () => selector(runtime.store.getState());
|
|
9
|
+
return useSyncExternalStore(runtime.store.subscribe, getSnapshot);
|
|
10
|
+
}
|
|
11
|
+
export function useRuntimeActions() {
|
|
12
|
+
return useAppRuntimeContext().actions;
|
|
13
|
+
}
|
|
14
|
+
export function useRuntimeTrace(selector) {
|
|
15
|
+
const runtime = useAppRuntimeContext();
|
|
16
|
+
const getSnapshot = () => selector(runtime.traceStore.getState());
|
|
17
|
+
return useSyncExternalStore(runtime.traceStore.subscribe, getSnapshot);
|
|
18
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ComponentChildren, JSX } from "preact";
|
|
2
|
+
export type ViewProps = {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly type: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly children?: ComponentChildren;
|
|
7
|
+
} & JSX.HTMLAttributes<HTMLElement>;
|
|
8
|
+
export declare function View(props: ViewProps): JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createSnapshotBundle } from "../../core/snapshot/createSnapshotBundle";
|
|
2
|
+
import { renderSnapshotDocument } from "./renderSnapshotDocument";
|
|
3
|
+
export function createSnapshotAssembler(input) {
|
|
4
|
+
const views = [input.rootView, ...input.mountedViews];
|
|
5
|
+
const markup = renderSnapshotDocument(views);
|
|
6
|
+
const bundleInput = {
|
|
7
|
+
markup,
|
|
8
|
+
views,
|
|
9
|
+
refIndex: input.refIndex,
|
|
10
|
+
visibleTools: input.visibleTools,
|
|
11
|
+
...(input.tui === undefined ? {} : { tui: input.tui }),
|
|
12
|
+
};
|
|
13
|
+
return createSnapshotBundle(bundleInput);
|
|
14
|
+
}
|
|
@@ -3,4 +3,4 @@ import type { ComponentChild } from "preact";
|
|
|
3
3
|
import type { ToolDefinition } from "../../core/types";
|
|
4
4
|
export declare function renderTUI(node: ComponentChild, options: {
|
|
5
5
|
visibleTools: ToolDefinition[];
|
|
6
|
-
}): import("
|
|
6
|
+
}): import("../..").SnapshotBundle;
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
2
|
import renderToString from "preact-render-to-string";
|
|
3
3
|
import { createRefCollector } from "../../core/ref/ref-index";
|
|
4
|
-
import { createSnapshotBundle } from "../../core/snapshot/createSnapshotBundle";
|
|
5
4
|
import { RefProvider } from "../../ref/RefContext";
|
|
5
|
+
import { renderViewFragment } from "./renderViewFragment";
|
|
6
|
+
import { createSnapshotAssembler } from "./createSnapshotAssembler";
|
|
6
7
|
export function renderTUI(node, options) {
|
|
7
8
|
const collector = createRefCollector();
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const renderedNode = _jsx(RefProvider, { registry: collector, children: node });
|
|
10
|
+
const markup = renderToString(renderedNode);
|
|
11
|
+
const rootView = renderViewFragment({
|
|
12
|
+
id: "root",
|
|
13
|
+
type: "Root",
|
|
14
|
+
name: "Root",
|
|
15
|
+
markup,
|
|
16
|
+
});
|
|
17
|
+
return createSnapshotAssembler({
|
|
18
|
+
rootView,
|
|
19
|
+
mountedViews: [],
|
|
11
20
|
refIndex: collector.snapshot(),
|
|
12
21
|
visibleTools: options.visibleTools,
|
|
13
22
|
});
|