tidewave 0.2.4 → 0.3.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 CHANGED
@@ -56,6 +56,70 @@ tidewave({
56
56
  });
57
57
  ```
58
58
 
59
+ ### HTTP MCP via Next.js Integration
60
+
61
+ Tidewave provides seamless integration with Next.js through a handler function.
62
+ Add the handler to your API routes **and** `middleware.ts`:
63
+
64
+ > [!WARNING] Note that the below helper functions will only work on development
65
+ > mode `NODE_ENV === 'development'` if the validation fails, an Error will be
66
+ > thrown
67
+
68
+ **Pages Router** - Create `pages/api/tidewave/[...all].ts`:
69
+
70
+ ```typescript
71
+ import { tidewaveHandler } from 'tidewave/next-js';
72
+
73
+ export default await tidewaveHandler();
74
+
75
+ // Next.js specific config
76
+ export const config = {
77
+ runtime: 'nodejs',
78
+ api: {
79
+ bodyParser: false, // tidewave already parses the body internally
80
+ },
81
+ };
82
+ ```
83
+
84
+ This exposes MCP endpoints at `/api/tidewave/mcp` and `/api/tidewave/shell`.
85
+
86
+ Then create `middleware.ts` with:
87
+
88
+ ```typescript
89
+ import { tidewaveMiddleware } from 'tidewave/next-js';
90
+
91
+ export const middleware = tidewaveMiddleware();
92
+
93
+ export const config = {
94
+ matcher: '/tidewave/(.*)',
95
+ };
96
+ ```
97
+
98
+ In case you already have an existing `middleware.ts`:
99
+
100
+ ```typescript
101
+ import { tidewaveMiddleware } from 'tidewave/next-js';
102
+
103
+ const withTidewave = tidewaveMiddleware();
104
+
105
+ export function middleware(req: NextRequest): Promise<NextResponse> {
106
+ // This will return a unchanged NextResponse.next()
107
+ // if path doesn't match with `/tidewave`
108
+ // if does match it will rewrite to `/api/tidewave` instead
109
+ withTidewave(req, (req: NextRequest) => {
110
+ // your own logic
111
+ return NextResponse.json({ message: 'hello, world!' });
112
+ });
113
+ }
114
+
115
+ export const config = {
116
+ matcher: [
117
+ '/tidewave/(.*)', // tidewave specific matcher
118
+ '/your/route/', // your specific matcher
119
+ ],
120
+ };
121
+ ```
122
+
59
123
  ### CLI Usage
60
124
 
61
125
  Tidewave also provides the MCP features over a CLI tool. Use it directly via
package/dist/cli/index.js CHANGED
@@ -11055,13 +11055,36 @@ async function extractSymbol(request, options = {}) {
11055
11055
  };
11056
11056
  }
11057
11057
  }
11058
+ // src/evaluation/eval_worker.ts
11059
+ process.on("message", async ({ code, args }) => {
11060
+ if (!process.send) {
11061
+ console.error("[Tidewave] Unable to establish communication channel with code-executor.");
11062
+ process.exit(1);
11063
+ }
11064
+ try {
11065
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
11066
+ const fn = new AsyncFunction(code);
11067
+ const result = await fn(...args);
11068
+ process.send({
11069
+ type: "result",
11070
+ success: true,
11071
+ data: (result || null) && result
11072
+ });
11073
+ } catch (error) {
11074
+ process.send({
11075
+ type: "result",
11076
+ success: false,
11077
+ data: new String(error)
11078
+ });
11079
+ }
11080
+ process.exit(0);
11081
+ });
11082
+
11058
11083
  // src/evaluation/code_executor.ts
11059
11084
  import { fork } from "child_process";
11060
- import { join } from "path";
11061
- var __dirname = "/Users/zoedsoupe/dev/dashbit/tidewave_javascript/src/evaluation";
11062
11085
  async function executeIsolated(request) {
11063
11086
  return new Promise((resolve) => {
11064
- const workerPath = join(__dirname, "eval_worker.ts");
11087
+ const workerPath = __require.resolve("./eval_worker");
11065
11088
  const child = fork(workerPath, { silent: true });
11066
11089
  const evaluation = {
11067
11090
  success: false,
@@ -14033,7 +14056,7 @@ var EMPTY_COMPLETION_RESULT = {
14033
14056
 
14034
14057
  // package.json
14035
14058
  var name = "tidewave";
14036
- var version = "0.2.3";
14059
+ var version = "0.3.0";
14037
14060
 
14038
14061
  // src/mcp.ts
14039
14062
  var {
package/dist/core.d.ts CHANGED
@@ -69,3 +69,9 @@ export declare function isResolveError(result: ResolveResult | InternalResolveRe
69
69
  export declare function isExtractError(result: ExtractResult): result is ExtractError;
70
70
  export declare function resolveError(specifier: ModuleRequest['specifier'], source: ModuleRequest['source']): ResolveError;
71
71
  export declare function createExtractError(code: ExtractError['error']['code'], message: string, details?: unknown): ExtractError;
72
+ export interface TidewaveConfig {
73
+ port?: number;
74
+ host?: string;
75
+ allowRemoteAccess?: boolean;
76
+ allowedOrigins?: string[];
77
+ }
@@ -27,13 +27,36 @@ var __export = (target, all) => {
27
27
  };
28
28
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
29
29
 
30
+ // src/evaluation/eval_worker.ts
31
+ process.on("message", async ({ code, args }) => {
32
+ if (!process.send) {
33
+ console.error("[Tidewave] Unable to establish communication channel with code-executor.");
34
+ process.exit(1);
35
+ }
36
+ try {
37
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
38
+ const fn = new AsyncFunction(code);
39
+ const result = await fn(...args);
40
+ process.send({
41
+ type: "result",
42
+ success: true,
43
+ data: (result || null) && result
44
+ });
45
+ } catch (error) {
46
+ process.send({
47
+ type: "result",
48
+ success: false,
49
+ data: new String(error)
50
+ });
51
+ }
52
+ process.exit(0);
53
+ });
54
+
30
55
  // src/evaluation/code_executor.ts
31
56
  import { fork } from "child_process";
32
- import { join } from "path";
33
- var __dirname = "/Users/zoedsoupe/dev/dashbit/tidewave_javascript/src/evaluation";
34
57
  async function executeIsolated(request) {
35
58
  return new Promise((resolve) => {
36
- const workerPath = join(__dirname, "eval_worker.ts");
59
+ const workerPath = __require.resolve("./eval_worker");
37
60
  const child = fork(workerPath, { silent: true });
38
61
  const evaluation = {
39
62
  success: false,
@@ -1,3 +1,32 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
29
+
1
30
  // src/evaluation/eval_worker.ts
2
31
  process.on("message", async ({ code, args }) => {
3
32
  if (!process.send) {
@@ -1,17 +1,14 @@
1
1
  import type { ServerResponse } from 'http';
2
2
  import type { IncomingMessage, NextFunction, Server } from 'connect';
3
+ import type { TidewaveConfig } from '../core';
3
4
  export interface Request extends IncomingMessage {
4
5
  body?: Record<string, unknown>;
5
6
  }
6
7
  export type Response = ServerResponse<IncomingMessage>;
7
8
  export type NextFn = NextFunction;
8
9
  export declare const ENDPOINT: "/tidewave";
9
- export interface TidewaveConfig {
10
- allowRemoteAccess?: boolean;
11
- allowedOrigins?: string[];
12
- port?: number;
13
- host?: string;
14
- }
10
+ export type Handler = (req: Request, res: Response, next: NextFn) => Promise<void>;
11
+ export declare const HANDLERS: Record<string, Handler>;
15
12
  export declare function configureServer(server?: Server, config?: TidewaveConfig): Server;
16
13
  export declare function serve(server: Server, config?: TidewaveConfig): void;
17
14
  export declare function checkSecurity(config: TidewaveConfig): (req: Request, res: Response, next: NextFn) => void;
@@ -6194,7 +6194,7 @@ var require_ajv = __commonJS((exports, module) => {
6194
6194
  function noop() {}
6195
6195
  });
6196
6196
 
6197
- // node_modules/connect/node_modules/debug/node_modules/ms/index.js
6197
+ // node_modules/connect/node_modules/ms/index.js
6198
6198
  var require_ms = __commonJS((exports, module) => {
6199
6199
  var s = 1000;
6200
6200
  var m = s * 60;
@@ -30078,13 +30078,36 @@ async function extractSymbol(request, options = {}) {
30078
30078
  };
30079
30079
  }
30080
30080
  }
30081
+ // src/evaluation/eval_worker.ts
30082
+ process.on("message", async ({ code, args }) => {
30083
+ if (!process.send) {
30084
+ console.error("[Tidewave] Unable to establish communication channel with code-executor.");
30085
+ process.exit(1);
30086
+ }
30087
+ try {
30088
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
30089
+ const fn = new AsyncFunction(code);
30090
+ const result = await fn(...args);
30091
+ process.send({
30092
+ type: "result",
30093
+ success: true,
30094
+ data: (result || null) && result
30095
+ });
30096
+ } catch (error) {
30097
+ process.send({
30098
+ type: "result",
30099
+ success: false,
30100
+ data: new String(error)
30101
+ });
30102
+ }
30103
+ process.exit(0);
30104
+ });
30105
+
30081
30106
  // src/evaluation/code_executor.ts
30082
30107
  import { fork } from "child_process";
30083
- import { join } from "path";
30084
- var __dirname = "/Users/zoedsoupe/dev/dashbit/tidewave_javascript/src/evaluation";
30085
30108
  async function executeIsolated(request) {
30086
30109
  return new Promise((resolve) => {
30087
- const workerPath = join(__dirname, "eval_worker.ts");
30110
+ const workerPath = __require.resolve("./eval_worker");
30088
30111
  const child = fork(workerPath, { silent: true });
30089
30112
  const evaluation = {
30090
30113
  success: false,
@@ -33056,7 +33079,7 @@ var EMPTY_COMPLETION_RESULT = {
33056
33079
 
33057
33080
  // package.json
33058
33081
  var name = "tidewave";
33059
- var version = "0.2.3";
33082
+ var version = "0.3.0";
33060
33083
 
33061
33084
  // src/mcp.ts
33062
33085
  var {
@@ -33172,9 +33195,21 @@ async function serveMcp(transport) {
33172
33195
  }
33173
33196
 
33174
33197
  // src/http/security.ts
33198
+ function fetchRemoteIp(req) {
33199
+ const remote = req.socket.remoteAddress;
33200
+ if (remote)
33201
+ return remote;
33202
+ const ip = req.headers["x-real-ip"] && req.headers["x-forwarded-for"] || null;
33203
+ if (Array.isArray(ip)) {
33204
+ return ip.join();
33205
+ }
33206
+ return ip;
33207
+ }
33175
33208
  function checkRemoteIp(req, res, config) {
33176
- const { remoteAddress } = req.socket;
33177
- if (isLocalIp(remoteAddress))
33209
+ const ip = fetchRemoteIp(req);
33210
+ if (!ip)
33211
+ return false;
33212
+ if (isLocalIp(ip))
33178
33213
  return true;
33179
33214
  if (config.allowRemoteAccess)
33180
33215
  return true;
@@ -33730,7 +33765,6 @@ async function handleMcp(req, res, next) {
33730
33765
  methodNotAllowed(res);
33731
33766
  return;
33732
33767
  }
33733
- console.debug(`[Tidewave] Received ${req.method} message`);
33734
33768
  const transport = new StreamableHTTPServerTransport({
33735
33769
  sessionIdGenerator: undefined,
33736
33770
  enableJsonResponse: true
@@ -33888,12 +33922,17 @@ var DEFAULT_OPTIONS = {
33888
33922
  port: 5001,
33889
33923
  host: "localhost"
33890
33924
  };
33925
+ var HANDLERS = {
33926
+ mcp: handleMcp,
33927
+ shell: handleShell
33928
+ };
33891
33929
  function configureServer(server = import_connect.default(), config = DEFAULT_OPTIONS) {
33892
33930
  const securityChecker = checkSecurity(config);
33893
33931
  server.use(`${ENDPOINT}`, securityChecker);
33894
33932
  server.use(`${ENDPOINT}`, import_body_parser.default.json());
33895
- server.use(`${ENDPOINT}/mcp`, handleMcp);
33896
- server.use(`${ENDPOINT}/shell`, handleShell);
33933
+ for (const [path4, handler] of Object.entries(HANDLERS)) {
33934
+ server.use(ENDPOINT + "/" + path4, handler);
33935
+ }
33897
33936
  return server;
33898
33937
  }
33899
33938
  function serve(server, config = DEFAULT_OPTIONS) {
@@ -33919,5 +33958,6 @@ export {
33919
33958
  methodNotAllowed,
33920
33959
  configureServer,
33921
33960
  checkSecurity,
33961
+ HANDLERS,
33922
33962
  ENDPOINT
33923
33963
  };
@@ -1,4 +1,5 @@
1
- import type { Request, Response, TidewaveConfig } from './index';
1
+ import type { TidewaveConfig } from '../core';
2
+ import type { Request, Response } from './index';
2
3
  export declare function checkRemoteIp(req: Request, res: Response, config: TidewaveConfig): boolean;
3
4
  export declare function isLocalIp(ip?: string): boolean;
4
5
  export declare function checkOrigin(req: Request, res: Response, config: TidewaveConfig): boolean;
@@ -28,9 +28,21 @@ var __export = (target, all) => {
28
28
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
29
29
 
30
30
  // src/http/security.ts
31
+ function fetchRemoteIp(req) {
32
+ const remote = req.socket.remoteAddress;
33
+ if (remote)
34
+ return remote;
35
+ const ip = req.headers["x-real-ip"] && req.headers["x-forwarded-for"] || null;
36
+ if (Array.isArray(ip)) {
37
+ return ip.join();
38
+ }
39
+ return ip;
40
+ }
31
41
  function checkRemoteIp(req, res, config) {
32
- const { remoteAddress } = req.socket;
33
- if (isLocalIp(remoteAddress))
42
+ const ip = fetchRemoteIp(req);
43
+ if (!ip)
44
+ return false;
45
+ if (isLocalIp(ip))
34
46
  return true;
35
47
  if (config.allowRemoteAccess)
36
48
  return true;
package/dist/index.js CHANGED
@@ -821,13 +821,36 @@ async function extractSymbol(request, options = {}) {
821
821
  };
822
822
  }
823
823
  }
824
+ // src/evaluation/eval_worker.ts
825
+ process.on("message", async ({ code, args }) => {
826
+ if (!process.send) {
827
+ console.error("[Tidewave] Unable to establish communication channel with code-executor.");
828
+ process.exit(1);
829
+ }
830
+ try {
831
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
832
+ const fn = new AsyncFunction(code);
833
+ const result = await fn(...args);
834
+ process.send({
835
+ type: "result",
836
+ success: true,
837
+ data: (result || null) && result
838
+ });
839
+ } catch (error) {
840
+ process.send({
841
+ type: "result",
842
+ success: false,
843
+ data: new String(error)
844
+ });
845
+ }
846
+ process.exit(0);
847
+ });
848
+
824
849
  // src/evaluation/code_executor.ts
825
850
  import { fork } from "child_process";
826
- import { join } from "path";
827
- var __dirname = "/Users/zoedsoupe/dev/dashbit/tidewave_javascript/src/evaluation";
828
851
  async function executeIsolated(request) {
829
852
  return new Promise((resolve) => {
830
- const workerPath = join(__dirname, "eval_worker.ts");
853
+ const workerPath = __require.resolve("./eval_worker");
831
854
  const child = fork(workerPath, { silent: true });
832
855
  const evaluation = {
833
856
  success: false,
package/dist/mcp.js CHANGED
@@ -11054,13 +11054,36 @@ async function extractSymbol(request, options = {}) {
11054
11054
  };
11055
11055
  }
11056
11056
  }
11057
+ // src/evaluation/eval_worker.ts
11058
+ process.on("message", async ({ code, args }) => {
11059
+ if (!process.send) {
11060
+ console.error("[Tidewave] Unable to establish communication channel with code-executor.");
11061
+ process.exit(1);
11062
+ }
11063
+ try {
11064
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
11065
+ const fn = new AsyncFunction(code);
11066
+ const result = await fn(...args);
11067
+ process.send({
11068
+ type: "result",
11069
+ success: true,
11070
+ data: (result || null) && result
11071
+ });
11072
+ } catch (error) {
11073
+ process.send({
11074
+ type: "result",
11075
+ success: false,
11076
+ data: new String(error)
11077
+ });
11078
+ }
11079
+ process.exit(0);
11080
+ });
11081
+
11057
11082
  // src/evaluation/code_executor.ts
11058
11083
  import { fork } from "child_process";
11059
- import { join } from "path";
11060
- var __dirname = "/Users/zoedsoupe/dev/dashbit/tidewave_javascript/src/evaluation";
11061
11084
  async function executeIsolated(request) {
11062
11085
  return new Promise((resolve) => {
11063
- const workerPath = join(__dirname, "eval_worker.ts");
11086
+ const workerPath = __require.resolve("./eval_worker");
11064
11087
  const child = fork(workerPath, { silent: true });
11065
11088
  const evaluation = {
11066
11089
  success: false,
@@ -14032,7 +14055,7 @@ var EMPTY_COMPLETION_RESULT = {
14032
14055
 
14033
14056
  // package.json
14034
14057
  var name = "tidewave";
14035
- var version = "0.2.3";
14058
+ var version = "0.3.0";
14036
14059
 
14037
14060
  // src/mcp.ts
14038
14061
  var {
@@ -0,0 +1,15 @@
1
+ import type { NextApiRequest, NextApiResponse } from 'next';
2
+ import { NextResponse, type NextRequest } from 'next/server';
3
+ import { type Request, type Response } from './http';
4
+ import type { TidewaveConfig } from './core';
5
+ type NextJsHandler = (_req: NextApiRequest, _res: NextApiResponse) => Promise<void>;
6
+ type NextJsMiddleware = (_req: NextRequest) => Promise<NextResponse>;
7
+ type NextHandler = () => ValueOrPromise<unknown>;
8
+ export type FunctionLike = (...args: any[]) => unknown;
9
+ export type Nextable<H extends FunctionLike> = (...args: [...Parameters<H>, NextHandler]) => ValueOrPromise<any>;
10
+ export type ValueOrPromise<T> = T | Promise<T>;
11
+ export type RequestHandler<Req extends Request, Res extends Response> = (req: Req, res: Res) => ValueOrPromise<void>;
12
+ export declare function tidewaveHandler(config?: TidewaveConfig): Promise<NextJsHandler>;
13
+ export declare function tidewaveMiddleware(): NextJsMiddleware;
14
+ export declare function isTidewaveRoute(pathname: string): boolean;
15
+ export {};