@intent-framework/core 0.1.0-alpha.8 → 0.1.0-alpha.9
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.ts +1 -1
- package/dist/index.js +113 -40
- package/dist/resource.d.ts +5 -3
- package/dist/screen.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type { AskNode, AnyAskNode, AskKind, AskBuilder } from "./ask.js";
|
|
|
7
7
|
export type { ActNode, ActCondition, ActStatus, FeedbackConfig, ActBuilder, NavigationService, ActionExecutionContext, DefaultScreenServices } from "./act.js";
|
|
8
8
|
export type { FlowNode, FlowStep, FlowBuilder } from "./flow.js";
|
|
9
9
|
export type { SurfaceNode, SurfaceBuilder } from "./surface.js";
|
|
10
|
-
export type { ResourceNode, ResourceConfig, ResourceCacheOptions, ResourceLoadContext, ResourceStatus, AnyResourceNode } from "./resource.js";
|
|
10
|
+
export type { ResourceNode, ResourceConfig, ResourceCacheOptions, ResourceLoadContext, ResourceStatus, ResourceKey, AnyResourceNode } from "./resource.js";
|
|
11
11
|
export { ResourceRef, createResourceNode } from "./resource.js";
|
|
12
12
|
export { createScreenRuntime } from "./runtime.js";
|
|
13
13
|
export type { ScreenRuntime } from "./runtime.js";
|
package/dist/index.js
CHANGED
|
@@ -40,13 +40,26 @@ function signal(initial) {
|
|
|
40
40
|
function createResourceNode(id, name, loader, autoLoad = true, cache) {
|
|
41
41
|
const statusSignal = signal(0);
|
|
42
42
|
const staleSignal = signal(0);
|
|
43
|
+
const hasKey = typeof cache?.key === "function";
|
|
44
|
+
const DEFAULT_KEY = "";
|
|
45
|
+
function createEntry() {
|
|
46
|
+
return {
|
|
47
|
+
value: void 0,
|
|
48
|
+
status: "idle",
|
|
49
|
+
error: void 0,
|
|
50
|
+
stale: false,
|
|
51
|
+
staleTimer: null,
|
|
52
|
+
inFlightPromise: null
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const entries = /* @__PURE__ */ new Map();
|
|
56
|
+
let _activeKey = DEFAULT_KEY;
|
|
57
|
+
if (!hasKey) entries.set(DEFAULT_KEY, createEntry());
|
|
43
58
|
let currentStatus = "idle";
|
|
44
59
|
let currentValue = void 0;
|
|
45
60
|
let currentError = void 0;
|
|
46
61
|
let currentStale = false;
|
|
47
62
|
let lastContext = void 0;
|
|
48
|
-
let _staleTimer = null;
|
|
49
|
-
let _inFlightPromise = null;
|
|
50
63
|
const notify = () => statusSignal.set(statusSignal.get() + 1);
|
|
51
64
|
const staleNotify = () => staleSignal.set(staleSignal.get() + 1);
|
|
52
65
|
const shouldDeduplicate = cache ? cache.deduplicate !== false : false;
|
|
@@ -54,6 +67,69 @@ function createResourceNode(id, name, loader, autoLoad = true, cache) {
|
|
|
54
67
|
let _pending;
|
|
55
68
|
let _failed;
|
|
56
69
|
let _stale;
|
|
70
|
+
function getActiveEntry() {
|
|
71
|
+
let entry = entries.get(_activeKey);
|
|
72
|
+
if (!entry) {
|
|
73
|
+
entry = createEntry();
|
|
74
|
+
entries.set(_activeKey, entry);
|
|
75
|
+
}
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
function syncFromEntry(entry) {
|
|
79
|
+
currentStatus = entry.status;
|
|
80
|
+
currentValue = entry.value;
|
|
81
|
+
currentError = entry.error;
|
|
82
|
+
if (currentStale !== entry.stale) {
|
|
83
|
+
currentStale = entry.stale;
|
|
84
|
+
staleNotify();
|
|
85
|
+
}
|
|
86
|
+
notify();
|
|
87
|
+
}
|
|
88
|
+
function syncFromActiveEntry() {
|
|
89
|
+
syncFromEntry(getActiveEntry());
|
|
90
|
+
}
|
|
91
|
+
function encodeResourceKey(key) {
|
|
92
|
+
if (Array.isArray(key)) return ["array", key.map(encodeResourceKey)];
|
|
93
|
+
if (key === null) return ["null"];
|
|
94
|
+
if (key === void 0) return ["undefined"];
|
|
95
|
+
if (typeof key === "string") return ["string", key];
|
|
96
|
+
if (typeof key === "boolean") return ["boolean", key];
|
|
97
|
+
if (typeof key === "number") {
|
|
98
|
+
if (Number.isNaN(key)) return ["number", "NaN"];
|
|
99
|
+
if (key === Infinity) return ["number", "Infinity"];
|
|
100
|
+
if (key === -Infinity) return ["number", "-Infinity"];
|
|
101
|
+
if (Object.is(key, -0)) return ["number", "-0"];
|
|
102
|
+
return ["number", key];
|
|
103
|
+
}
|
|
104
|
+
const exhaustive = key;
|
|
105
|
+
return exhaustive;
|
|
106
|
+
}
|
|
107
|
+
function normalizeKey(key) {
|
|
108
|
+
return JSON.stringify(encodeResourceKey(key));
|
|
109
|
+
}
|
|
110
|
+
function resolveKey(ctx) {
|
|
111
|
+
if (!hasKey) return DEFAULT_KEY;
|
|
112
|
+
const context = ctx ?? lastContext ?? {};
|
|
113
|
+
return normalizeKey(cache.key(context));
|
|
114
|
+
}
|
|
115
|
+
function _clearEntryStaleTimer(entry) {
|
|
116
|
+
if (entry.staleTimer != null) {
|
|
117
|
+
clearTimeout(entry.staleTimer);
|
|
118
|
+
entry.staleTimer = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function _startEntryStaleTimer(entry) {
|
|
122
|
+
_clearEntryStaleTimer(entry);
|
|
123
|
+
if (cache?.staleTime != null && isFinite(cache.staleTime)) entry.staleTimer = setTimeout(() => {
|
|
124
|
+
if (!entry.stale) {
|
|
125
|
+
entry.stale = true;
|
|
126
|
+
if (entry === getActiveEntry()) {
|
|
127
|
+
currentStale = true;
|
|
128
|
+
staleNotify();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}, cache.staleTime);
|
|
132
|
+
}
|
|
57
133
|
function getReady() {
|
|
58
134
|
if (!_ready) _ready = createCondition(() => currentStatus === "ready", (notify$1) => statusSignal.subscribe(() => notify$1()));
|
|
59
135
|
return _ready;
|
|
@@ -70,62 +146,59 @@ function createResourceNode(id, name, loader, autoLoad = true, cache) {
|
|
|
70
146
|
if (!_stale) _stale = createCondition(() => currentStale, (notify$1) => staleSignal.subscribe(() => notify$1()));
|
|
71
147
|
return _stale;
|
|
72
148
|
}
|
|
73
|
-
function _clearStaleTimer() {
|
|
74
|
-
if (_staleTimer != null) {
|
|
75
|
-
clearTimeout(_staleTimer);
|
|
76
|
-
_staleTimer = null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function _startStaleTimer() {
|
|
80
|
-
_clearStaleTimer();
|
|
81
|
-
if (cache?.staleTime != null && isFinite(cache.staleTime)) _staleTimer = setTimeout(() => {
|
|
82
|
-
if (!currentStale) {
|
|
83
|
-
currentStale = true;
|
|
84
|
-
staleNotify();
|
|
85
|
-
}
|
|
86
|
-
}, cache.staleTime);
|
|
87
|
-
}
|
|
88
149
|
function executeLoad(context) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
150
|
+
const key = resolveKey(context);
|
|
151
|
+
_activeKey = key;
|
|
152
|
+
let entry = entries.get(key);
|
|
153
|
+
if (!entry) {
|
|
154
|
+
entry = createEntry();
|
|
155
|
+
entries.set(key, entry);
|
|
156
|
+
}
|
|
157
|
+
if (shouldDeduplicate && entry.inFlightPromise) return entry.inFlightPromise;
|
|
96
158
|
if (context !== void 0) lastContext = context;
|
|
97
159
|
const loadContext = context ?? lastContext ?? {};
|
|
160
|
+
entry.stale = false;
|
|
161
|
+
entry.status = "pending";
|
|
162
|
+
entry.value = void 0;
|
|
163
|
+
entry.error = void 0;
|
|
164
|
+
syncFromActiveEntry();
|
|
98
165
|
const promise = (async () => {
|
|
99
166
|
try {
|
|
100
167
|
const result = await Promise.resolve(loader(loadContext));
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
168
|
+
entry.value = result;
|
|
169
|
+
entry.status = "ready";
|
|
170
|
+
entry.stale = false;
|
|
171
|
+
if (entry === getActiveEntry()) syncFromEntry(entry);
|
|
105
172
|
staleNotify();
|
|
106
|
-
|
|
173
|
+
_startEntryStaleTimer(entry);
|
|
107
174
|
} catch (e) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
175
|
+
entry.error = e;
|
|
176
|
+
entry.status = "failed";
|
|
177
|
+
entry.stale = false;
|
|
178
|
+
if (entry === getActiveEntry()) syncFromEntry(entry);
|
|
112
179
|
staleNotify();
|
|
113
180
|
} finally {
|
|
114
|
-
|
|
181
|
+
entry.inFlightPromise = null;
|
|
115
182
|
}
|
|
116
183
|
})();
|
|
117
|
-
|
|
184
|
+
entry.inFlightPromise = promise;
|
|
118
185
|
return promise;
|
|
119
186
|
}
|
|
120
187
|
function invalidate() {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
188
|
+
const entry = getActiveEntry();
|
|
189
|
+
if (!entry.stale) {
|
|
190
|
+
entry.stale = true;
|
|
191
|
+
if (entry === getActiveEntry()) {
|
|
192
|
+
currentStale = true;
|
|
193
|
+
staleNotify();
|
|
194
|
+
}
|
|
124
195
|
}
|
|
125
196
|
}
|
|
126
197
|
function dispose() {
|
|
127
|
-
|
|
128
|
-
|
|
198
|
+
for (const entry of entries.values()) {
|
|
199
|
+
_clearEntryStaleTimer(entry);
|
|
200
|
+
entry.inFlightPromise = null;
|
|
201
|
+
}
|
|
129
202
|
}
|
|
130
203
|
const node = {
|
|
131
204
|
id,
|
package/dist/resource.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Condition } from "./signal.js";
|
|
2
2
|
import type { ActionExecutionContext, DefaultScreenServices } from "./act.js";
|
|
3
3
|
export type ResourceStatus = "idle" | "pending" | "ready" | "failed";
|
|
4
|
+
export type ResourceKey = string | number | boolean | null | undefined | ResourceKey[];
|
|
4
5
|
export type ResourceLoadContext<TServices extends object = DefaultScreenServices> = ActionExecutionContext<TServices>;
|
|
5
6
|
type ResourceLoader<TValue, TServices extends object> = (() => TValue | Promise<TValue>) | ((context: ResourceLoadContext<TServices>) => TValue | Promise<TValue>);
|
|
6
7
|
export type ResourceNode<TValue, TServices extends object = DefaultScreenServices> = {
|
|
@@ -21,7 +22,8 @@ export type ResourceNode<TValue, TServices extends object = DefaultScreenService
|
|
|
21
22
|
dispose: () => void;
|
|
22
23
|
};
|
|
23
24
|
export type AnyResourceNode = ResourceNode<unknown, any>;
|
|
24
|
-
export type ResourceCacheOptions = {
|
|
25
|
+
export type ResourceCacheOptions<TServices extends object = DefaultScreenServices> = {
|
|
26
|
+
key?: (context: ResourceLoadContext<TServices>) => ResourceKey;
|
|
25
27
|
staleTime?: number;
|
|
26
28
|
deduplicate?: boolean;
|
|
27
29
|
};
|
|
@@ -30,11 +32,11 @@ export type ResourceConfig<TValue = unknown, TServices extends object = DefaultS
|
|
|
30
32
|
name: string;
|
|
31
33
|
autoLoad: boolean;
|
|
32
34
|
loader: ResourceLoader<TValue, TServices>;
|
|
33
|
-
cache?: ResourceCacheOptions
|
|
35
|
+
cache?: ResourceCacheOptions<TServices>;
|
|
34
36
|
ref?: ResourceRef<TValue, TServices>;
|
|
35
37
|
};
|
|
36
38
|
export declare function createResourceConfig<TValue, TServices extends object = DefaultScreenServices>(id: string, name: string, loader: ResourceLoader<TValue, TServices>, autoLoad?: boolean): ResourceConfig<TValue, TServices>;
|
|
37
|
-
export declare function createResourceNode<TValue, TServices extends object = DefaultScreenServices>(id: string, name: string, loader: ResourceLoader<TValue, TServices>, autoLoad?: boolean, cache?: ResourceCacheOptions): ResourceNode<TValue, TServices>;
|
|
39
|
+
export declare function createResourceNode<TValue, TServices extends object = DefaultScreenServices>(id: string, name: string, loader: ResourceLoader<TValue, TServices>, autoLoad?: boolean, cache?: ResourceCacheOptions<TServices>): ResourceNode<TValue, TServices>;
|
|
38
40
|
export declare class ResourceRef<TValue, TServices extends object = DefaultScreenServices> {
|
|
39
41
|
readonly id: string;
|
|
40
42
|
readonly name: string;
|
package/dist/screen.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ export type ScreenBuilder<TServices extends object = DefaultScreenServices> = {
|
|
|
31
31
|
resource: <T>(name: string, config: {
|
|
32
32
|
load: (() => Promise<T>) | ((context: ResourceLoadContext<TServices>) => Promise<T>);
|
|
33
33
|
autoLoad?: boolean;
|
|
34
|
-
cache?: ResourceCacheOptions
|
|
34
|
+
cache?: ResourceCacheOptions<TServices>;
|
|
35
35
|
}) => ResourceRef<T, TServices>;
|
|
36
36
|
};
|
|
37
37
|
export type ScreenDefinition<TServices extends object = DefaultScreenServices> = {
|