melony 0.3.5 → 0.3.7
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 +95 -12
- package/dist/index.js +176 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -17,20 +17,24 @@ declare class Runtime<TState = any, TEvent = any> {
|
|
|
17
17
|
* Process an incoming event through the runtime.
|
|
18
18
|
* All event processing is handled by user-defined event handlers.
|
|
19
19
|
*/
|
|
20
|
-
run(event: TEvent, options?:
|
|
21
|
-
state?: TState;
|
|
22
|
-
runId?: string;
|
|
23
|
-
}): AsyncGenerator<TEvent>;
|
|
20
|
+
run(event: TEvent, options?: RunOptions<TState>): AsyncGenerator<TEvent>;
|
|
24
21
|
/**
|
|
25
22
|
* Run all event handlers that match the given event type.
|
|
26
23
|
*/
|
|
27
24
|
private runEventHandlers;
|
|
28
25
|
/**
|
|
29
|
-
* Internal helper to yield an event with metadata.
|
|
26
|
+
* Internal helper to yield an event with metadata and trigger hooks.
|
|
30
27
|
*/
|
|
31
28
|
private emit;
|
|
32
29
|
}
|
|
33
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Options for executing a Melony run.
|
|
33
|
+
*/
|
|
34
|
+
interface RunOptions<TState = any> {
|
|
35
|
+
state?: TState;
|
|
36
|
+
runId?: string;
|
|
37
|
+
}
|
|
34
38
|
interface RuntimeContext<TState = any, TEvent = any> {
|
|
35
39
|
state: TState;
|
|
36
40
|
runId: string;
|
|
@@ -51,6 +55,7 @@ type EventInterceptor<TState = any, TEvent = any> = (event: TEvent, context: Run
|
|
|
51
55
|
* Can return events to emit or undefined to continue processing.
|
|
52
56
|
*/
|
|
53
57
|
type EventHandler<TState = any, TEvent = any> = (event: TEvent, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void;
|
|
58
|
+
type LifecycleHookResult<TEvent = any> = AsyncGenerator<TEvent, void, unknown> | void;
|
|
54
59
|
/**
|
|
55
60
|
* Configuration for the Melony runtime.
|
|
56
61
|
*/
|
|
@@ -62,10 +67,30 @@ interface Config<TState = any, TEvent = any> {
|
|
|
62
67
|
* Defaults to "type".
|
|
63
68
|
*/
|
|
64
69
|
eventKey?: string;
|
|
70
|
+
/**
|
|
71
|
+
* The initial state for the runtime.
|
|
72
|
+
* Can be an object or a factory function (sync or async).
|
|
73
|
+
*/
|
|
74
|
+
initialState?: TState | (() => TState | Promise<TState>);
|
|
75
|
+
/**
|
|
76
|
+
* Hook called before the runtime starts processing events.
|
|
77
|
+
*/
|
|
78
|
+
onStart?: (context: RuntimeContext<TState, TEvent>, initialEvent: TEvent) => Promise<LifecycleHookResult<TEvent>> | LifecycleHookResult<TEvent>;
|
|
79
|
+
/**
|
|
80
|
+
* Hook called after the runtime has finished processing events (even on failure).
|
|
81
|
+
*/
|
|
82
|
+
onEnd?: (context: RuntimeContext<TState, TEvent>) => Promise<LifecycleHookResult<TEvent>> | LifecycleHookResult<TEvent>;
|
|
83
|
+
/**
|
|
84
|
+
* Hook called for every event emitted by the runtime.
|
|
85
|
+
*/
|
|
86
|
+
onEvent?: (context: RuntimeContext<TState, TEvent>, event: TEvent) => Promise<void> | void;
|
|
65
87
|
}
|
|
66
88
|
|
|
89
|
+
/**
|
|
90
|
+
* The Melony Runtime class.
|
|
91
|
+
* This is the core class that powers the Melony framework.
|
|
92
|
+
*/
|
|
67
93
|
declare const MelonyRuntime: typeof Runtime;
|
|
68
|
-
|
|
69
94
|
/**
|
|
70
95
|
* A Melony plugin is a function that receives the builder and extends it.
|
|
71
96
|
* This allows for modularizing common handlers.
|
|
@@ -83,17 +108,42 @@ declare class MelonyBuilder<TState = any, TEvent = any> {
|
|
|
83
108
|
* Defaults to "type".
|
|
84
109
|
*/
|
|
85
110
|
eventKey(key: string): this;
|
|
111
|
+
/**
|
|
112
|
+
* Configure the initial state for the runtime.
|
|
113
|
+
* Supports a static object or a factory function.
|
|
114
|
+
*/
|
|
115
|
+
initialState(state: TState | (() => TState | Promise<TState>)): this;
|
|
116
|
+
/**
|
|
117
|
+
* Register a hook called before the runtime starts processing events.
|
|
118
|
+
*/
|
|
119
|
+
onStart(hook: (context: RuntimeContext<TState, TEvent>, initialEvent: TEvent) => Promise<LifecycleHookResult<TEvent>> | LifecycleHookResult<TEvent>): this;
|
|
120
|
+
/**
|
|
121
|
+
* Register a hook called after the runtime has finished processing events.
|
|
122
|
+
*/
|
|
123
|
+
onEnd(hook: (context: RuntimeContext<TState, TEvent>) => Promise<LifecycleHookResult<TEvent>> | LifecycleHookResult<TEvent>): this;
|
|
124
|
+
/**
|
|
125
|
+
* Register a hook called for every event emitted by the runtime.
|
|
126
|
+
*/
|
|
127
|
+
onEvent(hook: (context: RuntimeContext<TState, TEvent>, event: TEvent) => Promise<void> | void): this;
|
|
86
128
|
/**
|
|
87
129
|
* Add an event handler for a specific event type. Supports method chaining.
|
|
88
130
|
* The handler receives the narrowed event type based on the eventType string.
|
|
89
131
|
*/
|
|
90
|
-
on
|
|
132
|
+
on<K extends (TEvent extends {
|
|
133
|
+
type: string;
|
|
134
|
+
} ? TEvent["type"] : string) | "*">(eventType: K, handler: (event: K extends "*" ? TEvent : Extract<TEvent, {
|
|
135
|
+
type: K;
|
|
136
|
+
}>, context: RuntimeContext<TState, TEvent>) => AsyncGenerator<TEvent, void, unknown> | void): this;
|
|
91
137
|
/**
|
|
92
138
|
* Register an interceptor that runs before any handlers.
|
|
93
139
|
* Useful for logging, validation, or suspending for approval.
|
|
94
140
|
*/
|
|
95
141
|
intercept(interceptor: EventInterceptor<TState, TEvent>): this;
|
|
96
|
-
intercept
|
|
142
|
+
intercept<K extends (TEvent extends {
|
|
143
|
+
type: string;
|
|
144
|
+
} ? TEvent["type"] : string)>(eventType: K, interceptor: (event: Extract<TEvent, {
|
|
145
|
+
type: K;
|
|
146
|
+
}>, context: RuntimeContext<TState, TEvent>) => Promise<TEvent | void> | TEvent | void): this;
|
|
97
147
|
/**
|
|
98
148
|
* Use a plugin to extend the builder.
|
|
99
149
|
* This is ideal for modularizing common handlers.
|
|
@@ -104,6 +154,10 @@ declare class MelonyBuilder<TState = any, TEvent = any> {
|
|
|
104
154
|
* This is the final method in the fluent chain.
|
|
105
155
|
*/
|
|
106
156
|
build(): Runtime<TState, TEvent>;
|
|
157
|
+
/**
|
|
158
|
+
* Execute the runtime for a specific event.
|
|
159
|
+
*/
|
|
160
|
+
run(event: TEvent, options?: RunOptions<TState>): Promise<AsyncGenerator<TEvent>>;
|
|
107
161
|
/**
|
|
108
162
|
* Execute and stream the response for an event.
|
|
109
163
|
* This is a convenience method that builds the runtime and calls run().
|
|
@@ -116,9 +170,13 @@ declare class MelonyBuilder<TState = any, TEvent = any> {
|
|
|
116
170
|
* Execute the agent and return the data from the last event of a specific type as a JSON response.
|
|
117
171
|
* Ideal for initialization or non-streaming requests where you only need the final UI state.
|
|
118
172
|
*/
|
|
119
|
-
jsonResponse(event: TEvent, options?:
|
|
120
|
-
|
|
121
|
-
|
|
173
|
+
jsonResponse(event: TEvent, options?: RunOptions<TState>): Promise<Response>;
|
|
174
|
+
/**
|
|
175
|
+
* A unified Web-Standard Request Handler.
|
|
176
|
+
* Automatically parses a Request and returns a streaming Response.
|
|
177
|
+
*/
|
|
178
|
+
handle(request: Request, options?: {
|
|
179
|
+
state?: (req: Request) => Promise<TState> | TState;
|
|
122
180
|
}): Promise<Response>;
|
|
123
181
|
/**
|
|
124
182
|
* Get the current configuration (useful for debugging or serialization).
|
|
@@ -131,6 +189,15 @@ declare class MelonyBuilder<TState = any, TEvent = any> {
|
|
|
131
189
|
*/
|
|
132
190
|
declare function melony<TState = any, TEvent = any>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent>;
|
|
133
191
|
|
|
192
|
+
interface CreateJsonResponseDeps<TState, TEvent> {
|
|
193
|
+
run: (event: TEvent, options?: RunOptions<TState>) => AsyncIterable<TEvent>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Run the agent to completion and return all emitted events as a JSON Response.
|
|
197
|
+
* Useful for initialization or non-streaming requests.
|
|
198
|
+
*/
|
|
199
|
+
declare function createJsonResponse<TState, TEvent>(event: TEvent, options: RunOptions<TState> | undefined, deps: CreateJsonResponseDeps<TState, TEvent>): Promise<Response>;
|
|
200
|
+
|
|
134
201
|
/**
|
|
135
202
|
* Convert an async generator of events to an HTTP streaming response
|
|
136
203
|
* Exported for backward compatibility and standalone usage
|
|
@@ -139,4 +206,20 @@ declare function createStreamResponse<TEvent = any>(generator: AsyncGenerator<TE
|
|
|
139
206
|
|
|
140
207
|
declare const generateId: () => string;
|
|
141
208
|
|
|
142
|
-
|
|
209
|
+
interface HandleMelonyRequestOptions<TState> {
|
|
210
|
+
state?: (req: Request) => Promise<TState> | TState;
|
|
211
|
+
}
|
|
212
|
+
interface HandleMelonyRequestDeps<TState, TEvent> {
|
|
213
|
+
eventKey: string;
|
|
214
|
+
initialState?: TState | (() => TState | Promise<TState>);
|
|
215
|
+
streamResponse: (event: TEvent, options?: {
|
|
216
|
+
state?: TState;
|
|
217
|
+
runId?: string;
|
|
218
|
+
}) => Promise<Response>;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Unified Web-Standard Request handler: parses Request and returns a streaming Response.
|
|
222
|
+
*/
|
|
223
|
+
declare function handleMelonyRequest<TState, TEvent>(request: Request, options: HandleMelonyRequestOptions<TState> | undefined, deps: HandleMelonyRequestDeps<TState, TEvent>): Promise<Response>;
|
|
224
|
+
|
|
225
|
+
export { type Config, type CreateJsonResponseDeps, type EventHandler, type EventInterceptor, type HandleMelonyRequestDeps, type HandleMelonyRequestOptions, type LifecycleHookResult, MelonyBuilder, type MelonyPlugin, MelonyRuntime, type RunOptions, Runtime, type RuntimeContext, createJsonResponse, createStreamResponse, generateId, handleMelonyRequest, melony };
|
package/dist/index.js
CHANGED
|
@@ -29,8 +29,18 @@ var Runtime = class {
|
|
|
29
29
|
async *run(event, options) {
|
|
30
30
|
const runId = options?.runId ?? generateId();
|
|
31
31
|
const eventKey = this.config.eventKey || "type";
|
|
32
|
+
let state;
|
|
33
|
+
if (options?.state) {
|
|
34
|
+
state = options.state;
|
|
35
|
+
} else if (typeof this.config.initialState === "function") {
|
|
36
|
+
state = await this.config.initialState();
|
|
37
|
+
} else if (this.config.initialState) {
|
|
38
|
+
state = typeof globalThis.structuredClone === "function" ? globalThis.structuredClone(this.config.initialState) : { ...this.config.initialState };
|
|
39
|
+
} else {
|
|
40
|
+
state = {};
|
|
41
|
+
}
|
|
32
42
|
const context = {
|
|
33
|
-
state
|
|
43
|
+
state,
|
|
34
44
|
runtime: this,
|
|
35
45
|
runId,
|
|
36
46
|
suspend: (event2) => {
|
|
@@ -38,6 +48,14 @@ var Runtime = class {
|
|
|
38
48
|
}
|
|
39
49
|
};
|
|
40
50
|
try {
|
|
51
|
+
if (this.config.onStart) {
|
|
52
|
+
const startEvents = await this.config.onStart(context, event);
|
|
53
|
+
if (startEvents) {
|
|
54
|
+
for await (const lifecycleEvent of startEvents) {
|
|
55
|
+
yield* this.runEventHandlers(lifecycleEvent, context);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
41
59
|
yield* this.runEventHandlers(event, context);
|
|
42
60
|
} catch (error) {
|
|
43
61
|
let eventToEmit;
|
|
@@ -53,7 +71,16 @@ var Runtime = class {
|
|
|
53
71
|
};
|
|
54
72
|
}
|
|
55
73
|
if (eventToEmit) {
|
|
56
|
-
yield* this.
|
|
74
|
+
yield* this.runEventHandlers(eventToEmit, context);
|
|
75
|
+
}
|
|
76
|
+
} finally {
|
|
77
|
+
if (this.config.onEnd) {
|
|
78
|
+
const endEvents = await this.config.onEnd(context);
|
|
79
|
+
if (endEvents) {
|
|
80
|
+
for await (const lifecycleEvent of endEvents) {
|
|
81
|
+
yield* this.runEventHandlers(lifecycleEvent, context);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
57
84
|
}
|
|
58
85
|
}
|
|
59
86
|
}
|
|
@@ -70,7 +97,7 @@ var Runtime = class {
|
|
|
70
97
|
currentEvent = result;
|
|
71
98
|
}
|
|
72
99
|
}
|
|
73
|
-
|
|
100
|
+
let eventType = this.getEventType(currentEvent);
|
|
74
101
|
if (eventType !== "*") {
|
|
75
102
|
const specificInterceptors = this.config.interceptors.get(eventType) || [];
|
|
76
103
|
for (const interceptor of specificInterceptors) {
|
|
@@ -80,11 +107,11 @@ var Runtime = class {
|
|
|
80
107
|
}
|
|
81
108
|
}
|
|
82
109
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
];
|
|
87
|
-
yield* this.emit(currentEvent);
|
|
110
|
+
eventType = this.getEventType(currentEvent);
|
|
111
|
+
const wildcardHandlers = this.config.handlers.get("*") || [];
|
|
112
|
+
const specificHandlers = this.config.handlers.get(eventType) || [];
|
|
113
|
+
const handlers = eventType === "*" ? [...wildcardHandlers] : [...wildcardHandlers, ...specificHandlers];
|
|
114
|
+
yield* this.emit(currentEvent, context);
|
|
88
115
|
for (const handler of handlers) {
|
|
89
116
|
const result = handler(currentEvent, context);
|
|
90
117
|
if (result) {
|
|
@@ -95,15 +122,26 @@ var Runtime = class {
|
|
|
95
122
|
}
|
|
96
123
|
}
|
|
97
124
|
/**
|
|
98
|
-
* Internal helper to yield an event with metadata.
|
|
125
|
+
* Internal helper to yield an event with metadata and trigger hooks.
|
|
99
126
|
*/
|
|
100
|
-
async *emit(event) {
|
|
127
|
+
async *emit(event, context) {
|
|
128
|
+
if (this.config.onEvent) {
|
|
129
|
+
await this.config.onEvent(context, event);
|
|
130
|
+
}
|
|
101
131
|
yield event;
|
|
102
132
|
}
|
|
103
133
|
};
|
|
104
134
|
|
|
105
|
-
// src/
|
|
106
|
-
|
|
135
|
+
// src/utils/create-json-response.ts
|
|
136
|
+
async function createJsonResponse(event, options, deps) {
|
|
137
|
+
const events = [];
|
|
138
|
+
for await (const e of deps.run(event, options)) {
|
|
139
|
+
events.push(e);
|
|
140
|
+
}
|
|
141
|
+
return new Response(JSON.stringify({ events }), {
|
|
142
|
+
headers: { "Content-Type": "application/json" }
|
|
143
|
+
});
|
|
144
|
+
}
|
|
107
145
|
|
|
108
146
|
// src/utils/create-stream-response.ts
|
|
109
147
|
function createStreamResponse(generator) {
|
|
@@ -132,13 +170,87 @@ function createStreamResponse(generator) {
|
|
|
132
170
|
});
|
|
133
171
|
}
|
|
134
172
|
|
|
135
|
-
// src/
|
|
173
|
+
// src/utils/handle-request.ts
|
|
174
|
+
async function handleMelonyRequest(request, options, deps) {
|
|
175
|
+
if (request.method === "OPTIONS") {
|
|
176
|
+
const requested = request.headers.get("access-control-request-headers");
|
|
177
|
+
const defaultAllowHeaders = "Content-Type, x-melony-thread-id, x-melony-run-id, x-melony-session-id, Authorization, Last-Event-ID";
|
|
178
|
+
const origin2 = request.headers.get("origin");
|
|
179
|
+
const allowOrigin = origin2 ?? "*";
|
|
180
|
+
const headers = {
|
|
181
|
+
"Access-Control-Allow-Origin": allowOrigin,
|
|
182
|
+
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
|
183
|
+
"Access-Control-Allow-Headers": requested ?? defaultAllowHeaders
|
|
184
|
+
};
|
|
185
|
+
if (origin2) {
|
|
186
|
+
headers.Vary = "Origin";
|
|
187
|
+
headers["Access-Control-Allow-Credentials"] = "true";
|
|
188
|
+
}
|
|
189
|
+
const pnr2 = request.headers.get("access-control-request-private-network");
|
|
190
|
+
if (pnr2?.toLowerCase() === "true") {
|
|
191
|
+
headers["Access-Control-Allow-Private-Network"] = "true";
|
|
192
|
+
}
|
|
193
|
+
return new Response(null, { status: 204, headers });
|
|
194
|
+
}
|
|
195
|
+
let event;
|
|
196
|
+
try {
|
|
197
|
+
if (request.method === "POST") {
|
|
198
|
+
event = await request.json();
|
|
199
|
+
} else {
|
|
200
|
+
const url = new URL(request.url);
|
|
201
|
+
event = {
|
|
202
|
+
[deps.eventKey]: url.searchParams.get("type") || "http-get",
|
|
203
|
+
data: Object.fromEntries(url.searchParams.entries())
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
} catch {
|
|
207
|
+
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
208
|
+
status: 400,
|
|
209
|
+
headers: {
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
"Access-Control-Allow-Origin": "*"
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const threadId = request.headers.get("x-melony-thread-id") || event.threadId || generateId();
|
|
216
|
+
const runId = request.headers.get("x-melony-run-id") || generateId();
|
|
217
|
+
const sessionId = request.headers.get("x-melony-session-id") || event.sessionId || generateId();
|
|
218
|
+
let state;
|
|
219
|
+
if (options?.state) {
|
|
220
|
+
state = await options.state(request);
|
|
221
|
+
} else if (typeof deps.initialState === "function") {
|
|
222
|
+
state = await deps.initialState();
|
|
223
|
+
} else if (deps.initialState) {
|
|
224
|
+
state = typeof globalThis.structuredClone === "function" ? globalThis.structuredClone(deps.initialState) : { ...deps.initialState };
|
|
225
|
+
} else {
|
|
226
|
+
state = { threadId, runId, sessionId };
|
|
227
|
+
}
|
|
228
|
+
const response = await deps.streamResponse(event, { state, runId });
|
|
229
|
+
const origin = request.headers.get("origin");
|
|
230
|
+
response.headers.set("Access-Control-Allow-Origin", origin ?? "*");
|
|
231
|
+
if (origin) {
|
|
232
|
+
response.headers.set("Vary", "Origin");
|
|
233
|
+
response.headers.set("Access-Control-Allow-Credentials", "true");
|
|
234
|
+
}
|
|
235
|
+
const pnr = request.headers.get("access-control-request-private-network");
|
|
236
|
+
if (pnr?.toLowerCase() === "true") {
|
|
237
|
+
response.headers.set("Access-Control-Allow-Private-Network", "true");
|
|
238
|
+
}
|
|
239
|
+
return response;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/melony.ts
|
|
243
|
+
var MelonyRuntime = Runtime;
|
|
136
244
|
var MelonyBuilder = class {
|
|
137
245
|
constructor(initialConfig) {
|
|
138
246
|
this.config = {
|
|
139
247
|
handlers: initialConfig?.handlers ?? /* @__PURE__ */ new Map(),
|
|
140
248
|
interceptors: initialConfig?.interceptors ?? /* @__PURE__ */ new Map(),
|
|
141
|
-
eventKey: initialConfig?.eventKey ?? "type"
|
|
249
|
+
eventKey: initialConfig?.eventKey ?? "type",
|
|
250
|
+
initialState: initialConfig?.initialState,
|
|
251
|
+
onStart: initialConfig?.onStart,
|
|
252
|
+
onEnd: initialConfig?.onEnd,
|
|
253
|
+
onEvent: initialConfig?.onEvent
|
|
142
254
|
};
|
|
143
255
|
}
|
|
144
256
|
/**
|
|
@@ -149,6 +261,35 @@ var MelonyBuilder = class {
|
|
|
149
261
|
this.config.eventKey = key;
|
|
150
262
|
return this;
|
|
151
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Configure the initial state for the runtime.
|
|
266
|
+
* Supports a static object or a factory function.
|
|
267
|
+
*/
|
|
268
|
+
initialState(state) {
|
|
269
|
+
this.config.initialState = state;
|
|
270
|
+
return this;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Register a hook called before the runtime starts processing events.
|
|
274
|
+
*/
|
|
275
|
+
onStart(hook) {
|
|
276
|
+
this.config.onStart = hook;
|
|
277
|
+
return this;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Register a hook called after the runtime has finished processing events.
|
|
281
|
+
*/
|
|
282
|
+
onEnd(hook) {
|
|
283
|
+
this.config.onEnd = hook;
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Register a hook called for every event emitted by the runtime.
|
|
288
|
+
*/
|
|
289
|
+
onEvent(hook) {
|
|
290
|
+
this.config.onEvent = hook;
|
|
291
|
+
return this;
|
|
292
|
+
}
|
|
152
293
|
/**
|
|
153
294
|
* Add an event handler for a specific event type. Supports method chaining.
|
|
154
295
|
* The handler receives the narrowed event type based on the eventType string.
|
|
@@ -192,6 +333,13 @@ var MelonyBuilder = class {
|
|
|
192
333
|
build() {
|
|
193
334
|
return new Runtime(this.config);
|
|
194
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Execute the runtime for a specific event.
|
|
338
|
+
*/
|
|
339
|
+
async run(event, options) {
|
|
340
|
+
const runtime = this.build();
|
|
341
|
+
return runtime.run(event, options);
|
|
342
|
+
}
|
|
195
343
|
/**
|
|
196
344
|
* Execute and stream the response for an event.
|
|
197
345
|
* This is a convenience method that builds the runtime and calls run().
|
|
@@ -206,13 +354,19 @@ var MelonyBuilder = class {
|
|
|
206
354
|
* Ideal for initialization or non-streaming requests where you only need the final UI state.
|
|
207
355
|
*/
|
|
208
356
|
async jsonResponse(event, options) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
357
|
+
return createJsonResponse(event, options, {
|
|
358
|
+
run: (e, opts) => this.build().run(e, opts)
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* A unified Web-Standard Request Handler.
|
|
363
|
+
* Automatically parses a Request and returns a streaming Response.
|
|
364
|
+
*/
|
|
365
|
+
async handle(request, options) {
|
|
366
|
+
return handleMelonyRequest(request, options, {
|
|
367
|
+
eventKey: this.config.eventKey || "type",
|
|
368
|
+
initialState: this.config.initialState,
|
|
369
|
+
streamResponse: (event, opts) => this.streamResponse(event, opts)
|
|
216
370
|
});
|
|
217
371
|
}
|
|
218
372
|
/**
|
|
@@ -226,6 +380,6 @@ function melony(initialConfig) {
|
|
|
226
380
|
return new MelonyBuilder(initialConfig);
|
|
227
381
|
}
|
|
228
382
|
|
|
229
|
-
export { MelonyBuilder, MelonyRuntime, Runtime, createStreamResponse, generateId, melony };
|
|
383
|
+
export { MelonyBuilder, MelonyRuntime, Runtime, createJsonResponse, createStreamResponse, generateId, handleMelonyRequest, melony };
|
|
230
384
|
//# sourceMappingURL=index.js.map
|
|
231
385
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/generate-id.ts","../src/runtime.ts","../src/melony.ts","../src/utils/create-stream-response.ts","../src/builder.ts"],"names":["event"],"mappings":"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","file":"index.js","sourcesContent":["export const generateId = () => {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(7);\n};\n","import {\n RuntimeContext,\n Config,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent = any> {\n public readonly config: Config<TState, TEvent>;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Helper to get the event type from an event object based on configuration.\n */\n private getEventType(event: TEvent): string {\n const key = this.config.eventKey || \"type\";\n return (event as any)[key] || \"*\";\n }\n\n /**\n * Helper to check if a value is a Melony Event.\n */\n private isEvent(val: any): val is TEvent {\n const key = this.config.eventKey || \"type\";\n return val && typeof val === \"object\" && typeof (val as any)[key] === \"string\";\n }\n\n /**\n * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): AsyncGenerator<TEvent> {\n const runId = options?.runId ?? generateId();\n const eventKey = this.config.eventKey || \"type\";\n\n const context: RuntimeContext<TState, TEvent> = {\n state: (options?.state ?? {}) as TState,\n runtime: this,\n runId,\n suspend: (event?: TEvent) => {\n throw event || { [eventKey]: \"run-suspended\", data: {} };\n },\n };\n\n try {\n // Process the incoming event through handlers\n yield* this.runEventHandlers(event, context);\n } catch (error) {\n let eventToEmit: TEvent | undefined;\n\n if (this.isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n [eventKey]: \"error\",\n data: {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n } as unknown as TEvent;\n }\n\n if (eventToEmit) {\n yield* this.emit(eventToEmit);\n }\n }\n }\n\n\n /**\n * Run all event handlers that match the given event type.\n */\n private async *runEventHandlers(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n let currentEvent = event;\n const eventKey = this.config.eventKey || \"type\";\n\n // 1. Run global interceptors first\n const globalInterceptors = this.config.interceptors.get(\"*\") || [];\n for (const interceptor of globalInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && eventKey in (result as any)) {\n currentEvent = result as TEvent;\n }\n }\n\n // 2. Run specific interceptors for the (possibly new) event type\n // If currentEvent type is \"*\", it's already been handled by the global interceptors\n const eventType = this.getEventType(currentEvent);\n if (eventType !== \"*\") {\n const specificInterceptors = this.config.interceptors.get(eventType) || [];\n for (const interceptor of specificInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && eventKey in (result as any)) {\n currentEvent = result as TEvent;\n }\n }\n }\n\n const handlers = [\n ...(this.config.handlers.get(\"*\") || []),\n ...(this.config.handlers.get(this.getEventType(currentEvent)) || []),\n ];\n\n // First emit the event itself\n yield* this.emit(currentEvent);\n\n for (const handler of handlers) {\n const result = handler(currentEvent, context);\n if (result) {\n for await (const yieldedEvent of result) {\n // Recursively process yielded events through their handlers\n yield* this.runEventHandlers(yieldedEvent, context);\n }\n }\n }\n }\n\n /**\n * Internal helper to yield an event with metadata.\n */\n private async *emit(\n event: TEvent\n ): AsyncGenerator<TEvent> {\n yield event;\n }\n}\n","import { Runtime } from \"./runtime\";\n\nexport const MelonyRuntime = Runtime;","/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse<TEvent = any>(\n generator: AsyncGenerator<TEvent>,\n): Response {\n const encoder = new TextEncoder();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n for await (const message of generator) {\n // Format as SSE: data: {...}\\n\\n\n const chunk = `data: ${JSON.stringify(message)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n","import {\n EventHandler,\n Config,\n RuntimeContext,\n EventInterceptor,\n} from \"./types\";\nimport { Runtime } from \"./runtime\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\n\n/**\n * A Melony plugin is a function that receives the builder and extends it.\n * This allows for modularizing common handlers.\n */\nexport type MelonyPlugin<TState = any, TEvent = any> = (\n builder: MelonyBuilder<TState, TEvent>\n) => void;\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for handlers and plugins with full TypeScript support.\n */\nexport class MelonyBuilder<\n TState = any,\n TEvent = any\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n handlers: initialConfig?.handlers ?? new Map(),\n interceptors: initialConfig?.interceptors ?? new Map(),\n eventKey: initialConfig?.eventKey ?? \"type\",\n };\n }\n\n /**\n * Configure the key in the event object that defines its type.\n * Defaults to \"type\".\n */\n eventKey(key: string): this {\n this.config.eventKey = key;\n return this;\n }\n\n /**\n * Add an event handler for a specific event type. Supports method chaining.\n * The handler receives the narrowed event type based on the eventType string.\n */\n on(\n eventType: string | \"*\",\n handler: (\n event: TEvent,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.handlers.has(eventType)) {\n this.config.handlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.handlers.get(eventType)!.push(handler as EventHandler<TState, TEvent>);\n return this;\n }\n\n /**\n * Register an interceptor that runs before any handlers.\n * Useful for logging, validation, or suspending for approval.\n */\n intercept(interceptor: EventInterceptor<TState, TEvent>): this;\n intercept(\n eventType: string,\n interceptor: (\n event: TEvent,\n context: RuntimeContext<TState, TEvent>\n ) => Promise<TEvent | void> | TEvent | void\n ): this;\n intercept(\n arg1: string | EventInterceptor<TState, TEvent>,\n arg2?: any\n ): this {\n if (typeof arg1 === \"string\") {\n const type = arg1;\n const interceptor = arg2!;\n if (!this.config.interceptors.has(type)) {\n this.config.interceptors.set(type, []);\n }\n this.config.interceptors.get(type)!.push(interceptor as EventInterceptor<TState, TEvent>);\n } else {\n const interceptor = arg1;\n if (!this.config.interceptors.has(\"*\")) {\n this.config.interceptors.set(\"*\", []);\n }\n this.config.interceptors.get(\"*\")!.push(interceptor);\n }\n return this;\n }\n\n /**\n * Use a plugin to extend the builder.\n * This is ideal for modularizing common handlers.\n */\n use(plugin: MelonyPlugin<TState, TEvent>): this {\n plugin(this);\n return this;\n }\n\n /**\n * Build and return the Melony runtime instance.\n * This is the final method in the fluent chain.\n */\n build(): Runtime<TState, TEvent> {\n return new Runtime(this.config);\n }\n\n /**\n * Execute and stream the response for an event.\n * This is a convenience method that builds the runtime and calls run().\n */\n async streamResponse(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event, options);\n return createStreamResponse(generator);\n }\n\n /**\n * Execute the agent and return the data from the last event of a specific type as a JSON response.\n * Ideal for initialization or non-streaming requests where you only need the final UI state.\n */\n async jsonResponse(\n event: TEvent,\n options?: {\n state?: TState;\n runId?: string;\n }\n ): Promise<Response> {\n const events = [];\n const runtime = this.build();\n\n for await (const e of runtime.run(event, options)) {\n events.push(e);\n }\n\n return new Response(JSON.stringify({ events }), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /**\n * Get the current configuration (useful for debugging or serialization).\n */\n getConfig(): Config<TState, TEvent> {\n return { ...this.config };\n }\n}\n\n/**\n * Factory function to create a new Melony builder instance.\n * This is the entry point for the fluent API.\n */\nexport function melony<\n TState = any,\n TEvent = any\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/generate-id.ts","../src/runtime.ts","../src/utils/create-json-response.ts","../src/utils/create-stream-response.ts","../src/utils/handle-request.ts","../src/melony.ts"],"names":["event","origin","pnr"],"mappings":"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","file":"index.js","sourcesContent":["export const generateId = () => {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : Math.random().toString(36).substring(7);\n};\n","import {\n RuntimeContext,\n Config,\n RunOptions,\n} from \"./types\";\nimport { generateId } from \"./utils/generate-id\";\n\n/**\n * The Melony Runtime.\n * Fully unopinionated - processes events through handlers.\n */\nexport class Runtime<TState = any, TEvent = any> {\n public readonly config: Config<TState, TEvent>;\n\n constructor(config: Config<TState, TEvent>) {\n this.config = config;\n }\n\n /**\n * Helper to get the event type from an event object based on configuration.\n */\n private getEventType(event: TEvent): string {\n const key = this.config.eventKey || \"type\";\n return (event as any)[key] || \"*\";\n }\n\n /**\n * Helper to check if a value is a Melony Event.\n */\n private isEvent(val: any): val is TEvent {\n const key = this.config.eventKey || \"type\";\n return val && typeof val === \"object\" && typeof (val as any)[key] === \"string\";\n }\n\n /**\n * Process an incoming event through the runtime.\n * All event processing is handled by user-defined event handlers.\n */\n public async *run(\n event: TEvent,\n options?: RunOptions<TState>\n ): AsyncGenerator<TEvent> {\n const runId = options?.runId ?? generateId();\n const eventKey = this.config.eventKey || \"type\";\n\n // Resolve initial state: options.state > config.initialState > {}\n let state: TState;\n if (options?.state) {\n state = options.state;\n } else if (typeof this.config.initialState === \"function\") {\n state = await (this.config.initialState as any)();\n } else if (this.config.initialState) {\n // Use structuredClone if available, otherwise fallback to simple spread for safety\n state = typeof (globalThis as any).structuredClone === \"function\"\n ? (globalThis as any).structuredClone(this.config.initialState)\n : { ...this.config.initialState };\n } else {\n state = {} as TState;\n }\n\n const context: RuntimeContext<TState, TEvent> = {\n state,\n runtime: this,\n runId,\n suspend: (event?: TEvent) => {\n throw event || { [eventKey]: \"run-suspended\", data: {} };\n },\n };\n\n try {\n // 1. Call onStart hook\n if (this.config.onStart) {\n const startEvents = await this.config.onStart(context, event);\n if (startEvents) {\n for await (const lifecycleEvent of startEvents) {\n yield* this.runEventHandlers(lifecycleEvent, context);\n }\n }\n }\n\n // 2. Process the incoming event through handlers\n yield* this.runEventHandlers(event, context);\n } catch (error) {\n let eventToEmit: TEvent | undefined;\n\n if (this.isEvent(error)) {\n eventToEmit = error as TEvent;\n } else {\n eventToEmit = {\n [eventKey]: \"error\",\n data: {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n },\n } as unknown as TEvent;\n }\n\n if (eventToEmit) {\n yield* this.runEventHandlers(eventToEmit, context);\n }\n } finally {\n // 3. Call onEnd hook\n if (this.config.onEnd) {\n const endEvents = await this.config.onEnd(context);\n if (endEvents) {\n for await (const lifecycleEvent of endEvents) {\n yield* this.runEventHandlers(lifecycleEvent, context);\n }\n }\n }\n }\n }\n\n\n /**\n * Run all event handlers that match the given event type.\n */\n private async *runEventHandlers(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>,\n ): AsyncGenerator<TEvent> {\n let currentEvent = event;\n const eventKey = this.config.eventKey || \"type\";\n\n // 1. Run global interceptors first\n const globalInterceptors = this.config.interceptors.get(\"*\") || [];\n for (const interceptor of globalInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && eventKey in (result as any)) {\n currentEvent = result as TEvent;\n }\n }\n\n // 2. Run specific interceptors for the (possibly new) event type\n // If currentEvent type is \"*\", it's already been handled by the global interceptors\n let eventType = this.getEventType(currentEvent);\n if (eventType !== \"*\") {\n const specificInterceptors = this.config.interceptors.get(eventType) || [];\n for (const interceptor of specificInterceptors) {\n const result = await interceptor(currentEvent, context);\n if (result && typeof result === \"object\" && eventKey in (result as any)) {\n currentEvent = result as TEvent;\n }\n }\n }\n\n eventType = this.getEventType(currentEvent);\n const wildcardHandlers = this.config.handlers.get(\"*\") || [];\n const specificHandlers = this.config.handlers.get(eventType) || [];\n // When type is missing, getEventType is \"*\"; do not register wildcard handlers twice.\n const handlers =\n eventType === \"*\"\n ? [...wildcardHandlers]\n : [...wildcardHandlers, ...specificHandlers];\n\n // First emit the event itself\n yield* this.emit(currentEvent, context);\n\n for (const handler of handlers) {\n const result = handler(currentEvent, context);\n if (result) {\n for await (const yieldedEvent of result) {\n // Recursively process yielded events through their handlers\n yield* this.runEventHandlers(yieldedEvent, context);\n }\n }\n }\n }\n\n /**\n * Internal helper to yield an event with metadata and trigger hooks.\n */\n private async *emit(\n event: TEvent,\n context: RuntimeContext<TState, TEvent>\n ): AsyncGenerator<TEvent> {\n if (this.config.onEvent) {\n await this.config.onEvent(context, event);\n }\n yield event;\n }\n}\n","import type { RunOptions } from \"../types\";\n\nexport interface CreateJsonResponseDeps<TState, TEvent> {\n run: (\n event: TEvent,\n options?: RunOptions<TState>\n ) => AsyncIterable<TEvent>;\n}\n\n/**\n * Run the agent to completion and return all emitted events as a JSON Response.\n * Useful for initialization or non-streaming requests.\n */\nexport async function createJsonResponse<TState, TEvent>(\n event: TEvent,\n options: RunOptions<TState> | undefined,\n deps: CreateJsonResponseDeps<TState, TEvent>\n): Promise<Response> {\n const events: TEvent[] = [];\n for await (const e of deps.run(event, options)) {\n events.push(e);\n }\n\n return new Response(JSON.stringify({ events }), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n","/**\n * Convert an async generator of events to an HTTP streaming response\n * Exported for backward compatibility and standalone usage\n */\nexport function createStreamResponse<TEvent = any>(\n generator: AsyncGenerator<TEvent>,\n): Response {\n const encoder = new TextEncoder();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n for await (const message of generator) {\n // Format as SSE: data: {...}\\n\\n\n const chunk = `data: ${JSON.stringify(message)}\\n\\n`;\n controller.enqueue(encoder.encode(chunk));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n}\n","import { generateId } from \"./generate-id\";\n\nexport interface HandleMelonyRequestOptions<TState> {\n state?: (req: Request) => Promise<TState> | TState;\n}\n\nexport interface HandleMelonyRequestDeps<TState, TEvent> {\n eventKey: string;\n initialState?: TState | (() => TState | Promise<TState>);\n streamResponse: (\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ) => Promise<Response>;\n}\n\n/**\n * Unified Web-Standard Request handler: parses Request and returns a streaming Response.\n */\nexport async function handleMelonyRequest<TState, TEvent>(\n request: Request,\n options: HandleMelonyRequestOptions<TState> | undefined,\n deps: HandleMelonyRequestDeps<TState, TEvent>\n): Promise<Response> {\n if (request.method === \"OPTIONS\") {\n const requested = request.headers.get(\"access-control-request-headers\");\n const defaultAllowHeaders =\n \"Content-Type, x-melony-thread-id, x-melony-run-id, x-melony-session-id, Authorization, Last-Event-ID\";\n const origin = request.headers.get(\"origin\");\n const allowOrigin = origin ?? \"*\";\n const headers: Record<string, string> = {\n \"Access-Control-Allow-Origin\": allowOrigin,\n \"Access-Control-Allow-Methods\": \"POST, GET, OPTIONS\",\n \"Access-Control-Allow-Headers\": requested ?? defaultAllowHeaders,\n };\n if (origin) {\n headers.Vary = \"Origin\";\n headers[\"Access-Control-Allow-Credentials\"] = \"true\";\n }\n const pnr = request.headers.get(\"access-control-request-private-network\");\n if (pnr?.toLowerCase() === \"true\") {\n headers[\"Access-Control-Allow-Private-Network\"] = \"true\";\n }\n return new Response(null, { status: 204, headers });\n }\n\n let event: TEvent;\n try {\n if (request.method === \"POST\") {\n event = await request.json();\n } else {\n const url = new URL(request.url);\n // Avoid defaulting GET to \"run\": browsers, probes, and EventSource use GET; reconnects\n // would re-trigger full runs. Use ?type=run when you intend orchestration via GET.\n event = {\n [deps.eventKey]: url.searchParams.get(\"type\") || \"http-get\",\n data: Object.fromEntries(url.searchParams.entries()),\n } as unknown as TEvent;\n }\n } catch {\n return new Response(JSON.stringify({ error: \"Invalid JSON body\" }), {\n status: 400,\n headers: {\n \"Content-Type\": \"application/json\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n }\n\n const threadId =\n request.headers.get(\"x-melony-thread-id\") ||\n (event as { threadId?: string }).threadId ||\n generateId();\n const runId = request.headers.get(\"x-melony-run-id\") || generateId();\n const sessionId =\n request.headers.get(\"x-melony-session-id\") ||\n (event as { sessionId?: string }).sessionId ||\n generateId();\n\n let state: TState;\n if (options?.state) {\n state = await options.state(request);\n } else if (typeof deps.initialState === \"function\") {\n state = await (deps.initialState as () => TState | Promise<TState>)();\n } else if (deps.initialState) {\n state =\n typeof (globalThis as any).structuredClone === \"function\"\n ? (globalThis as any).structuredClone(deps.initialState)\n : { ...(deps.initialState as object) };\n } else {\n state = { threadId, runId, sessionId } as unknown as TState;\n }\n\n const response = await deps.streamResponse(event, { state, runId });\n const origin = request.headers.get(\"origin\");\n response.headers.set(\"Access-Control-Allow-Origin\", origin ?? \"*\");\n if (origin) {\n response.headers.set(\"Vary\", \"Origin\");\n response.headers.set(\"Access-Control-Allow-Credentials\", \"true\");\n }\n const pnr = request.headers.get(\"access-control-request-private-network\");\n if (pnr?.toLowerCase() === \"true\") {\n response.headers.set(\"Access-Control-Allow-Private-Network\", \"true\");\n }\n return response;\n}\n","import { Runtime } from \"./runtime\";\nimport {\n Config,\n RuntimeContext,\n EventInterceptor,\n RunOptions,\n LifecycleHookResult,\n} from \"./types\";\nimport { createJsonResponse } from \"./utils/create-json-response\";\nimport { createStreamResponse } from \"./utils/create-stream-response\";\nimport { handleMelonyRequest } from \"./utils/handle-request\";\n\n/**\n * The Melony Runtime class.\n * This is the core class that powers the Melony framework.\n */\nexport const MelonyRuntime = Runtime;\n\n/**\n * A Melony plugin is a function that receives the builder and extends it.\n * This allows for modularizing common handlers.\n */\nexport type MelonyPlugin<TState = any, TEvent = any> = (\n builder: MelonyBuilder<TState, TEvent>\n) => void;\n\n/**\n * Fluent builder for creating Melony agents with excellent developer experience.\n * Provides method chaining for handlers and plugins with full TypeScript support.\n */\nexport class MelonyBuilder<\n TState = any,\n TEvent = any\n> {\n private config: Config<TState, TEvent>;\n\n constructor(initialConfig?: Partial<Config<TState, TEvent>>) {\n this.config = {\n handlers: initialConfig?.handlers ?? new Map(),\n interceptors: initialConfig?.interceptors ?? new Map(),\n eventKey: initialConfig?.eventKey ?? \"type\",\n initialState: initialConfig?.initialState,\n onStart: initialConfig?.onStart,\n onEnd: initialConfig?.onEnd,\n onEvent: initialConfig?.onEvent,\n };\n }\n\n /**\n * Configure the key in the event object that defines its type.\n * Defaults to \"type\".\n */\n eventKey(key: string): this {\n this.config.eventKey = key;\n return this;\n }\n\n /**\n * Configure the initial state for the runtime.\n * Supports a static object or a factory function.\n */\n initialState(state: TState | (() => TState | Promise<TState>)): this {\n this.config.initialState = state;\n return this;\n }\n\n /**\n * Register a hook called before the runtime starts processing events.\n */\n onStart(\n hook: (\n context: RuntimeContext<TState, TEvent>,\n initialEvent: TEvent\n ) => Promise<LifecycleHookResult<TEvent>> | LifecycleHookResult<TEvent>\n ): this {\n this.config.onStart = hook;\n return this;\n }\n\n /**\n * Register a hook called after the runtime has finished processing events.\n */\n onEnd(\n hook: (\n context: RuntimeContext<TState, TEvent>\n ) => Promise<LifecycleHookResult<TEvent>> | LifecycleHookResult<TEvent>\n ): this {\n this.config.onEnd = hook;\n return this;\n }\n\n /**\n * Register a hook called for every event emitted by the runtime.\n */\n onEvent(\n hook: (\n context: RuntimeContext<TState, TEvent>,\n event: TEvent\n ) => Promise<void> | void\n ): this {\n this.config.onEvent = hook;\n return this;\n }\n\n /**\n * Add an event handler for a specific event type. Supports method chaining.\n * The handler receives the narrowed event type based on the eventType string.\n */\n on<K extends (TEvent extends { type: string } ? TEvent[\"type\"] : string) | \"*\">(\n eventType: K,\n handler: (\n event: K extends \"*\" ? TEvent : Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => AsyncGenerator<TEvent, void, unknown> | void\n ): this {\n if (!this.config.handlers.has(eventType)) {\n this.config.handlers.set(eventType, []);\n }\n // Cast is safe because runtime only calls this handler for matching event types\n this.config.handlers.get(eventType)!.push(handler as any);\n return this;\n }\n\n /**\n * Register an interceptor that runs before any handlers.\n * Useful for logging, validation, or suspending for approval.\n */\n intercept(interceptor: EventInterceptor<TState, TEvent>): this;\n intercept<K extends (TEvent extends { type: string } ? TEvent[\"type\"] : string)>(\n eventType: K,\n interceptor: (\n event: Extract<TEvent, { type: K }>,\n context: RuntimeContext<TState, TEvent>\n ) => Promise<TEvent | void> | TEvent | void\n ): this;\n intercept(\n arg1: string | EventInterceptor<TState, TEvent>,\n arg2?: any\n ): this {\n if (typeof arg1 === \"string\") {\n const type = arg1;\n const interceptor = arg2!;\n if (!this.config.interceptors.has(type)) {\n this.config.interceptors.set(type, []);\n }\n this.config.interceptors.get(type)!.push(interceptor as any);\n } else {\n const interceptor = arg1;\n if (!this.config.interceptors.has(\"*\")) {\n this.config.interceptors.set(\"*\", []);\n }\n this.config.interceptors.get(\"*\")!.push(interceptor);\n }\n return this;\n }\n\n /**\n * Use a plugin to extend the builder.\n * This is ideal for modularizing common handlers.\n */\n use(plugin: MelonyPlugin<TState, TEvent>): this {\n plugin(this);\n return this;\n }\n\n /**\n * Build and return the Melony runtime instance.\n * This is the final method in the fluent chain.\n */\n build(): Runtime<TState, TEvent> {\n return new Runtime(this.config);\n }\n\n /**\n * Execute the runtime for a specific event.\n */\n async run(\n event: TEvent,\n options?: RunOptions<TState>\n ): Promise<AsyncGenerator<TEvent>> {\n const runtime = this.build();\n return runtime.run(event, options);\n }\n\n /**\n * Execute and stream the response for an event.\n * This is a convenience method that builds the runtime and calls run().\n */\n async streamResponse(\n event: TEvent,\n options?: { state?: TState; runId?: string }\n ): Promise<Response> {\n const runtime = this.build();\n const generator = runtime.run(event, options);\n return createStreamResponse(generator);\n }\n\n /**\n * Execute the agent and return the data from the last event of a specific type as a JSON response.\n * Ideal for initialization or non-streaming requests where you only need the final UI state.\n */\n async jsonResponse(\n event: TEvent,\n options?: RunOptions<TState>\n ): Promise<Response> {\n return createJsonResponse(event, options, {\n run: (e, opts) => this.build().run(e, opts),\n });\n }\n\n /**\n * A unified Web-Standard Request Handler.\n * Automatically parses a Request and returns a streaming Response.\n */\n async handle(\n request: Request,\n options?: { state?: (req: Request) => Promise<TState> | TState }\n ): Promise<Response> {\n return handleMelonyRequest(request, options, {\n eventKey: this.config.eventKey || \"type\",\n initialState: this.config.initialState,\n streamResponse: (event: TEvent, opts) => this.streamResponse(event, opts),\n });\n }\n\n /**\n * Get the current configuration (useful for debugging or serialization).\n */\n getConfig(): Config<TState, TEvent> {\n return { ...this.config };\n }\n}\n\n/**\n * Factory function to create a new Melony builder instance.\n * This is the entry point for the fluent API.\n */\nexport function melony<\n TState = any,\n TEvent = any\n>(initialConfig?: Partial<Config<TState, TEvent>>): MelonyBuilder<TState, TEvent> {\n return new MelonyBuilder<TState, TEvent>(initialConfig);\n}\n"]}
|