Skip to content

Commit 7e47c57

Browse files
committed
add custom code
1 parent 155613f commit 7e47c57

File tree

2 files changed

+172
-1
lines changed

2 files changed

+172
-1
lines changed

src/client.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { Browser, BrowserCreateSessionResponse } from './resources/browser';
3232
import { readEnv } from './internal/utils/env';
3333
import { formatRequestDetails, loggerFor } from './internal/utils/log';
3434
import { isEmptyObj } from './internal/utils/values';
35+
import { KernelApp, appRegistry, browsers as appBrowsers } from './core/app-framework';
3536

3637
export interface ClientOptions {
3738
/**
@@ -480,7 +481,7 @@ export class Kernel {
480481

481482
const isReadableBody =
482483
((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) ||
483-
(typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
484+
(typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body));
484485

485486
const fetchOptions: RequestInit = {
486487
signal: controller.signal as any,
@@ -680,6 +681,14 @@ export class Kernel {
680681
}
681682
}
682683

684+
public app(name: string): KernelApp {
685+
return new KernelApp(name);
686+
}
687+
688+
public static exportRegistry(entrypointRelpath: string): string {
689+
return appRegistry.exportJSON(entrypointRelpath);
690+
}
691+
683692
static Kernel = this;
684693
static DEFAULT_TIMEOUT = 60000; // 1 minute
685694

@@ -701,9 +710,11 @@ export class Kernel {
701710

702711
apps: API.Apps = new API.Apps(this);
703712
browser: API.Browser = new API.Browser(this);
713+
appFrameworkBrowsers = appBrowsers;
704714
}
705715
Kernel.Apps = Apps;
706716
Kernel.Browser = Browser;
717+
Kernel.exportRegistry = (entrypointRelpath: string) => appRegistry.exportJSON(entrypointRelpath);
707718
export declare namespace Kernel {
708719
export type RequestOptions = Opts.RequestOptions;
709720

src/core/app-framework.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Type definitions for browser
2+
export interface Browser {
3+
cdp_ws_url: string;
4+
}
5+
6+
// Context definition
7+
export interface KernelContext {
8+
invocationId: string;
9+
}
10+
11+
// Action definition
12+
export interface KernelAction {
13+
name: string;
14+
handler: (context: KernelContext, input: any) => Promise<any>;
15+
}
16+
17+
export interface KernelJson {
18+
entrypoint: string;
19+
apps: KernelAppJson[];
20+
}
21+
22+
export interface KernelAppJson {
23+
name: string;
24+
actions: KernelActionJson[];
25+
}
26+
27+
export interface KernelActionJson {
28+
name: string;
29+
}
30+
31+
// App definition
32+
export class KernelApp {
33+
name: string;
34+
actions: Map<string, KernelAction> = new Map();
35+
36+
constructor(name: string) {
37+
this.name = name;
38+
// Register this app in the global registry
39+
appRegistry.registerApp(this);
40+
}
41+
42+
/**
43+
* Define an action
44+
*/
45+
action<T, R>(
46+
nameOrHandler:
47+
| string
48+
| ((input: T) => Promise<R>)
49+
| ((context: KernelContext, input: T) => Promise<R>),
50+
handler?: ((input: T) => Promise<R>) | ((context: KernelContext, input: T) => Promise<R>),
51+
) {
52+
let actionName: string;
53+
let actionHandler: (context: KernelContext, input: T) => Promise<R>;
54+
55+
if (typeof nameOrHandler === 'string' && handler) {
56+
// Case: app.action("name", handler)
57+
actionName = nameOrHandler;
58+
59+
// Create a handler that accepts context and input, adapting if needed
60+
if (handler.length === 1) {
61+
// Original handler only takes input, so we adapt it to the new signature
62+
const singleArgHandler = handler as (input: T) => Promise<R>;
63+
actionHandler = async (context: KernelContext, input: T) => singleArgHandler(input);
64+
} else {
65+
// Handler takes both context and input
66+
actionHandler = handler as (context: KernelContext, input: T) => Promise<R>;
67+
}
68+
} else if (typeof nameOrHandler === 'function') {
69+
// Case: app.action(handler)
70+
actionName = nameOrHandler.name || 'default';
71+
72+
// Create a handler that accepts context and input, adapting if needed
73+
if (nameOrHandler.length === 1) {
74+
// Original handler only takes input, so we adapt it to the new signature
75+
const singleArgHandler = nameOrHandler as (input: T) => Promise<R>;
76+
actionHandler = async (context: KernelContext, input: T) => singleArgHandler(input);
77+
} else {
78+
// Handler takes both context and input
79+
actionHandler = nameOrHandler as (context: KernelContext, input: T) => Promise<R>;
80+
}
81+
} else {
82+
throw new Error('Invalid action definition');
83+
}
84+
85+
// Register the action
86+
this.actions.set(actionName, {
87+
name: actionName,
88+
handler: actionHandler,
89+
});
90+
91+
return actionHandler;
92+
}
93+
94+
/**
95+
* Get all actions for this app
96+
*/
97+
getActions(): KernelAction[] {
98+
return Array.from(this.actions.values());
99+
}
100+
101+
/**
102+
* Get an action by name
103+
*/
104+
getAction(name: string): KernelAction | undefined {
105+
return this.actions.get(name);
106+
}
107+
108+
/**
109+
* Export app information without handlers
110+
*/
111+
toJSON(): KernelAppJson {
112+
return {
113+
name: this.name,
114+
actions: this.getActions().map((action) => ({
115+
name: action.name,
116+
})),
117+
};
118+
}
119+
}
120+
121+
// Registry for storing all Kernel apps
122+
class KernelAppRegistry {
123+
private apps: Map<string, KernelApp> = new Map();
124+
125+
registerApp(app: KernelApp): void {
126+
this.apps.set(app.name, app);
127+
}
128+
129+
getApps(): KernelApp[] {
130+
return Array.from(this.apps.values());
131+
}
132+
133+
getAppByName(name: string): KernelApp | undefined {
134+
return this.apps.get(name);
135+
}
136+
137+
/**
138+
* Export the registry as JSON
139+
*/
140+
exportJSON(entrypointRelpath: string): string {
141+
const apps = this.getApps().map((app) => app.toJSON());
142+
return JSON.stringify({ apps, entrypoint: entrypointRelpath } as KernelJson, null, 2);
143+
}
144+
}
145+
146+
// Create a singleton registry for apps
147+
export const appRegistry = new KernelAppRegistry();
148+
149+
// Browser management module
150+
export const browsers = {
151+
/**
152+
* Create a new browser instance
153+
*/
154+
create: async ({ invocationId }: { invocationId: string }): Promise<Browser> => {
155+
return {
156+
cdp_ws_url:
157+
'wss://floral-morning-3s0r8t7x.iad-prod-apiukp-0.onkernel.app:9222/devtools/browser/4dc1cbf6-be0e-4612-bba3-8e399d9638c7',
158+
};
159+
},
160+
};

0 commit comments

Comments
 (0)