@portel/photon 1.23.1 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -0
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +262 -18
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/beam.bundle.js +58287 -56177
- package/dist/beam.bundle.js.map +4 -4
- package/dist/capability-negotiator.d.ts +9 -0
- package/dist/capability-negotiator.d.ts.map +1 -1
- package/dist/capability-negotiator.js +14 -0
- package/dist/capability-negotiator.js.map +1 -1
- package/dist/cli/commands/claim.d.ts +17 -0
- package/dist/cli/commands/claim.d.ts.map +1 -0
- package/dist/cli/commands/claim.js +124 -0
- package/dist/cli/commands/claim.js.map +1 -0
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +2 -0
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/daemon/claims.d.ts +108 -0
- package/dist/daemon/claims.d.ts.map +1 -0
- package/dist/daemon/claims.js +245 -0
- package/dist/daemon/claims.js.map +1 -0
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +15 -29
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/cron.d.ts +36 -0
- package/dist/daemon/cron.d.ts.map +1 -0
- package/dist/daemon/cron.js +216 -0
- package/dist/daemon/cron.js.map +1 -0
- package/dist/daemon/schedule-loader.d.ts +76 -0
- package/dist/daemon/schedule-loader.d.ts.map +1 -0
- package/dist/daemon/schedule-loader.js +124 -0
- package/dist/daemon/schedule-loader.js.map +1 -0
- package/dist/daemon/server.js +76 -226
- package/dist/daemon/server.js.map +1 -1
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +68 -3
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/loader.d.ts +22 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +162 -7
- package/dist/loader.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +17 -0
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +50 -1
- package/dist/server.js.map +1 -1
- package/dist/shared/memory-sqlite.d.ts +37 -0
- package/dist/shared/memory-sqlite.d.ts.map +1 -0
- package/dist/shared/memory-sqlite.js +143 -0
- package/dist/shared/memory-sqlite.js.map +1 -0
- package/package.json +2 -2
- package/templates/cloudflare/worker.ts.template +44 -73
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portel/photon",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "You focus on the business logic. We'll enable the rest. Build MCP servers and CLI tools in a single TypeScript file.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"@modelcontextprotocol/ext-apps": "^1.0.1",
|
|
114
114
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
115
115
|
"@portel/cli": "^1.1.0",
|
|
116
|
-
"@portel/photon-core": "^2.
|
|
116
|
+
"@portel/photon-core": "^2.25.0",
|
|
117
117
|
"boxen": "^8.0.1",
|
|
118
118
|
"chalk": "^5.4.1",
|
|
119
119
|
"chart.js": "^4.5.1",
|
|
@@ -11,13 +11,6 @@ interface Env {
|
|
|
11
11
|
[key: string]: string | undefined;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
type SSESession = {
|
|
15
|
-
writer: WritableStreamDefaultWriter<Uint8Array>;
|
|
16
|
-
encoder: TextEncoder;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const sessions = new Map<string, SSESession>();
|
|
20
|
-
|
|
21
14
|
// Tool definitions extracted at build time
|
|
22
15
|
// @ts-ignore - Will be replaced during build
|
|
23
16
|
const TOOL_DEFINITIONS: any[] = __TOOL_DEFINITIONS__;
|
|
@@ -100,66 +93,34 @@ async function handleMCPRequest(request: any, env: Env): Promise<any> {
|
|
|
100
93
|
}
|
|
101
94
|
|
|
102
95
|
// SSE stream handler
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
clearInterval(interval);
|
|
121
|
-
}
|
|
122
|
-
}, 30000);
|
|
123
|
-
|
|
124
|
-
// Cleanup on close
|
|
125
|
-
request.signal.addEventListener('abort', () => {
|
|
126
|
-
clearInterval(interval);
|
|
127
|
-
sessions.delete(sessionId);
|
|
128
|
-
writer.close().catch(() => {});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
return new Response(readable, {
|
|
132
|
-
headers: {
|
|
133
|
-
'Content-Type': 'text/event-stream',
|
|
134
|
-
'Cache-Control': 'no-cache',
|
|
135
|
-
'Connection': 'keep-alive',
|
|
136
|
-
'Access-Control-Allow-Origin': '*',
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Message handler for SSE
|
|
142
|
-
async function handleMessage(request: Request, env: Env): Promise<Response> {
|
|
143
|
-
const url = new URL(request.url);
|
|
144
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
145
|
-
|
|
146
|
-
if (!sessionId || !sessions.has(sessionId)) {
|
|
147
|
-
return new Response('Invalid session', { status: 400 });
|
|
96
|
+
/**
|
|
97
|
+
* Stateless MCP Streamable HTTP handler.
|
|
98
|
+
*
|
|
99
|
+
* Each POST /mcp is a complete JSON-RPC exchange: body in, result out, no
|
|
100
|
+
* session state carried across requests. This matches the MCP Streamable
|
|
101
|
+
* HTTP spec's single-endpoint pattern and stays within the Cloudflare
|
|
102
|
+
* Workers free tier (no Durable Objects needed for session storage).
|
|
103
|
+
*/
|
|
104
|
+
async function handleStreamableMCP(request: Request, env: Env): Promise<Response> {
|
|
105
|
+
let body: unknown;
|
|
106
|
+
try {
|
|
107
|
+
body = await request.json();
|
|
108
|
+
} catch (error: any) {
|
|
109
|
+
return Response.json(
|
|
110
|
+
{ jsonrpc: '2.0', id: null, error: { code: -32700, message: `Parse error: ${error?.message ?? String(error)}` } },
|
|
111
|
+
{ status: 400, headers: CORS_HEADERS }
|
|
112
|
+
);
|
|
148
113
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const body = await request.json();
|
|
152
|
-
const response = await handleMCPRequest(body, env);
|
|
153
|
-
|
|
154
|
-
// Send response via SSE
|
|
155
|
-
const data = `event: message\ndata: ${JSON.stringify(response)}\n\n`;
|
|
156
|
-
await session.writer.write(session.encoder.encode(data));
|
|
157
|
-
|
|
158
|
-
return new Response('OK', {
|
|
159
|
-
headers: { 'Access-Control-Allow-Origin': '*' },
|
|
160
|
-
});
|
|
114
|
+
const result = await handleMCPRequest(body, env);
|
|
115
|
+
return Response.json(result, { headers: CORS_HEADERS });
|
|
161
116
|
}
|
|
162
117
|
|
|
118
|
+
const CORS_HEADERS = {
|
|
119
|
+
'Access-Control-Allow-Origin': '*',
|
|
120
|
+
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
|
121
|
+
'Access-Control-Allow-Headers': 'Content-Type, Mcp-Session-Id',
|
|
122
|
+
};
|
|
123
|
+
|
|
163
124
|
// Playground HTML
|
|
164
125
|
function getPlaygroundHTML(): string {
|
|
165
126
|
return `<!DOCTYPE html>
|
|
@@ -324,25 +285,35 @@ export default {
|
|
|
324
285
|
if (url.pathname === '/' && request.method === 'GET') {
|
|
325
286
|
return Response.json({
|
|
326
287
|
name: PHOTON_NAME,
|
|
327
|
-
transport: '
|
|
288
|
+
transport: 'streamable-http',
|
|
328
289
|
runtime: 'cloudflare-workers',
|
|
329
290
|
endpoints: {
|
|
330
|
-
|
|
331
|
-
messages: '/mcp/messages',
|
|
291
|
+
mcp: '/mcp',
|
|
332
292
|
...(DEV_MODE ? { playground: '/playground' } : {}),
|
|
333
293
|
},
|
|
334
294
|
tools: TOOL_DEFINITIONS.length,
|
|
335
295
|
});
|
|
336
296
|
}
|
|
337
297
|
|
|
338
|
-
//
|
|
298
|
+
// MCP Streamable HTTP: one endpoint, stateless per request.
|
|
299
|
+
if (url.pathname === '/mcp' && request.method === 'POST') {
|
|
300
|
+
return handleStreamableMCP(request, env);
|
|
301
|
+
}
|
|
339
302
|
if (url.pathname === '/mcp' && request.method === 'GET') {
|
|
340
|
-
|
|
303
|
+
// Spec-compliant no-op: clients that open an SSE stream for server
|
|
304
|
+
// notifications get a valid empty stream. We do not push anything
|
|
305
|
+
// server-initiated from a stateless Worker.
|
|
306
|
+
return new Response(': streamable-http\n\n', {
|
|
307
|
+
headers: {
|
|
308
|
+
'Content-Type': 'text/event-stream',
|
|
309
|
+
'Cache-Control': 'no-cache',
|
|
310
|
+
...CORS_HEADERS,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
341
313
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return handleMessage(request, env);
|
|
314
|
+
if (url.pathname === '/mcp' && request.method === 'DELETE') {
|
|
315
|
+
// Session termination: stateless, nothing to clean up.
|
|
316
|
+
return new Response(null, { status: 204, headers: CORS_HEADERS });
|
|
346
317
|
}
|
|
347
318
|
|
|
348
319
|
// Dev-only endpoints
|