Skip to content

Commit 3561799

Browse files
committed
fix: fix issue with node 16 and 18
1 parent fd81060 commit 3561799

File tree

12 files changed

+326
-22
lines changed

12 files changed

+326
-22
lines changed

bin/cli.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#!/usr/bin/env node
22

3-
// Simple wrapper script that loads the actual bundled code
4-
require('../dist/cli.js');
3+
// Load Node.js 16 polyfills before anything else
4+
import './node16-preload.js';
5+
6+
// Then import the main application
7+
import('../dist/cli.js');

bin/node16-preload.js

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Node.js 16 polyfills for modern web APIs
2+
// This file is loaded before anything else to ensure compatibility with Node.js 16
3+
4+
// Make the file work with ESM
5+
import { createRequire } from 'module';
6+
const require = createRequire(import.meta.url);
7+
8+
// Polyfill for DOMException
9+
if (typeof globalThis.DOMException === 'undefined') {
10+
globalThis.DOMException = class DOMException extends Error {
11+
constructor(message, name) {
12+
super(message);
13+
this.name = name || 'Error';
14+
this.code = 0;
15+
16+
// Common DOMException codes
17+
if (name === 'AbortError') this.code = 20;
18+
if (name === 'InvalidStateError') this.code = 11;
19+
if (name === 'NetworkError') this.code = 19;
20+
if (name === 'NotFoundError') this.code = 8;
21+
if (name === 'NotSupportedError') this.code = 9;
22+
if (name === 'SecurityError') this.code = 18;
23+
if (name === 'SyntaxError') this.code = 12;
24+
if (name === 'TypeMismatchError') this.code = 17;
25+
}
26+
};
27+
}
28+
29+
// Polyfill for ReadableStream
30+
if (typeof globalThis.ReadableStream === 'undefined') {
31+
const { Readable } = require('stream');
32+
33+
globalThis.ReadableStream = class ReadableStream {
34+
constructor(underlyingSource = {}) {
35+
this._readable = new Readable({
36+
read: underlyingSource.pull,
37+
objectMode: true
38+
});
39+
40+
if (underlyingSource.start) {
41+
underlyingSource.start(this);
42+
}
43+
}
44+
45+
getReader() {
46+
return {
47+
read: async () => {
48+
return new Promise((resolve) => {
49+
this._readable.once('data', (chunk) => {
50+
resolve({ value: chunk, done: false });
51+
});
52+
this._readable.once('end', () => {
53+
resolve({ value: undefined, done: true });
54+
});
55+
});
56+
},
57+
releaseLock: () => {}
58+
};
59+
}
60+
};
61+
}
62+
63+
// Polyfill for Blob
64+
if (typeof globalThis.Blob === 'undefined') {
65+
const { Buffer } = require('buffer');
66+
67+
globalThis.Blob = class Blob {
68+
constructor(array, options = {}) {
69+
this.parts = array;
70+
this.type = options.type || '';
71+
72+
// Calculate size
73+
this.size = array.reduce((acc, part) => {
74+
const buf = part instanceof Buffer ? part : Buffer.from(String(part));
75+
return acc + buf.length;
76+
}, 0);
77+
}
78+
79+
// Basic implementation of slice
80+
slice(start, end, contentType) {
81+
// For simplicity, we're not implementing the full logic
82+
return new Blob([], { type: contentType || this.type });
83+
}
84+
85+
// Add other methods as needed
86+
async text() {
87+
const buffers = [];
88+
for (const part of this.parts) {
89+
const buf = part instanceof Buffer ? part : Buffer.from(String(part));
90+
buffers.push(buf);
91+
}
92+
return Buffer.concat(buffers).toString('utf-8');
93+
}
94+
95+
async arrayBuffer() {
96+
const buffers = [];
97+
for (const part of this.parts) {
98+
const buf = part instanceof Buffer ? part : Buffer.from(String(part));
99+
buffers.push(buf);
100+
}
101+
return Buffer.concat(buffers).buffer;
102+
}
103+
};
104+
}
105+
106+
// Add additional web API polyfills that undici might need
107+
if (typeof globalThis.WritableStream === 'undefined') {
108+
const { Writable } = require('stream');
109+
110+
globalThis.WritableStream = class WritableStream {
111+
constructor(underlyingSink = {}) {
112+
this._writable = new Writable({
113+
write: (chunk, encoding, callback) => {
114+
if (underlyingSink.write) {
115+
Promise.resolve(underlyingSink.write(chunk))
116+
.then(() => callback(), callback);
117+
} else {
118+
callback();
119+
}
120+
}
121+
});
122+
123+
if (underlyingSink.start) {
124+
underlyingSink.start(this);
125+
}
126+
}
127+
128+
getWriter() {
129+
return {
130+
write: async (chunk) => {
131+
return new Promise((resolve, reject) => {
132+
this._writable.write(chunk, (err) => {
133+
if (err) reject(err);
134+
else resolve();
135+
});
136+
});
137+
},
138+
close: async () => {
139+
return new Promise((resolve) => {
140+
this._writable.end(() => resolve());
141+
});
142+
},
143+
releaseLock: () => {}
144+
};
145+
}
146+
};
147+
}
148+
149+
// More web polyfills
150+
if (typeof globalThis.FormData === 'undefined') {
151+
globalThis.FormData = class FormData {
152+
constructor() {
153+
this._data = new Map();
154+
}
155+
156+
append(name, value, filename) {
157+
this._data.set(name, { value, filename });
158+
}
159+
160+
delete(name) {
161+
this._data.delete(name);
162+
}
163+
164+
get(name) {
165+
return this._data.get(name)?.value;
166+
}
167+
168+
has(name) {
169+
return this._data.has(name);
170+
}
171+
172+
set(name, value, filename) {
173+
this.append(name, value, filename);
174+
}
175+
};
176+
}
177+
178+
// Export to ensure this file is properly loaded as a module
179+
export default {};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "@watercrawl/mcp",
33
"version": "1.0.0",
4+
"type": "module",
45
"main": "dist/index.js",
56
"bin": {
67
"watercrawl-mcp": "bin/cli.js"

scripts/build.js

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#!/usr/bin/env node
22

3-
const esbuild = require('esbuild');
4-
const path = require('path');
3+
import esbuild from 'esbuild';
4+
import path from 'path';
5+
import { fileURLToPath } from 'url';
56

6-
// Get project root directory
7+
// Get project root directory using ES module approach
8+
const __filename = fileURLToPath(import.meta.url);
9+
const __dirname = path.dirname(__filename);
710
const projectRoot = path.resolve(__dirname, '..');
811

912
async function build() {
@@ -16,7 +19,49 @@ async function build() {
1619
target: 'node16',
1720
outfile: 'dist/cli.js',
1821
external: ['fastmcp', '@watercrawl/nodejs'],
19-
format: 'cjs',
22+
format: 'esm',
23+
banner: {
24+
js: `
25+
// ESM shim for CommonJS modules with dynamic requires
26+
import { createRequire } from 'module';
27+
const require = createRequire(import.meta.url);
28+
29+
// Polyfill for ReadableStream in Node.js 16
30+
if (typeof globalThis.ReadableStream === 'undefined') {
31+
const { Readable } = require('stream');
32+
33+
// Simple polyfill for ReadableStream
34+
globalThis.ReadableStream = class ReadableStream {
35+
constructor(underlyingSource = {}) {
36+
this._readable = new Readable({
37+
read: underlyingSource.pull,
38+
objectMode: true
39+
});
40+
41+
if (underlyingSource.start) {
42+
underlyingSource.start(this);
43+
}
44+
}
45+
46+
getReader() {
47+
return {
48+
read: async () => {
49+
return new Promise((resolve) => {
50+
this._readable.once('data', (chunk) => {
51+
resolve({ value: chunk, done: false });
52+
});
53+
this._readable.once('end', () => {
54+
resolve({ value: undefined, done: true });
55+
});
56+
});
57+
},
58+
releaseLock: () => {}
59+
};
60+
}
61+
};
62+
}
63+
`,
64+
},
2065
});
2166

2267
console.log('CLI build completed successfully');
@@ -29,7 +74,49 @@ async function build() {
2974
target: 'node16',
3075
outfile: 'dist/index.js',
3176
external: ['fastmcp', '@watercrawl/nodejs'],
32-
format: 'cjs',
77+
format: 'esm',
78+
banner: {
79+
js: `
80+
// ESM shim for CommonJS modules with dynamic requires
81+
import { createRequire } from 'module';
82+
const require = createRequire(import.meta.url);
83+
84+
// Polyfill for ReadableStream in Node.js 16
85+
if (typeof globalThis.ReadableStream === 'undefined') {
86+
const { Readable } = require('stream');
87+
88+
// Simple polyfill for ReadableStream
89+
globalThis.ReadableStream = class ReadableStream {
90+
constructor(underlyingSource = {}) {
91+
this._readable = new Readable({
92+
read: underlyingSource.pull,
93+
objectMode: true
94+
});
95+
96+
if (underlyingSource.start) {
97+
underlyingSource.start(this);
98+
}
99+
}
100+
101+
getReader() {
102+
return {
103+
read: async () => {
104+
return new Promise((resolve) => {
105+
this._readable.once('data', (chunk) => {
106+
resolve({ value: chunk, done: false });
107+
});
108+
this._readable.once('end', () => {
109+
resolve({ value: undefined, done: true });
110+
});
111+
});
112+
},
113+
releaseLock: () => {}
114+
};
115+
}
116+
};
117+
}
118+
`,
119+
},
33120
});
34121

35122
console.log('Library build completed successfully');

scripts/node16-polyfills.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Node.js 16 polyfills for modern web APIs
2+
// This file should be required before any other code runs
3+
4+
// Polyfill for ReadableStream
5+
if (typeof globalThis.ReadableStream === 'undefined') {
6+
const { Readable } = require('stream');
7+
8+
globalThis.ReadableStream = class ReadableStream {
9+
constructor(underlyingSource = {}) {
10+
this._readable = new Readable({
11+
read: underlyingSource.pull,
12+
objectMode: true
13+
});
14+
15+
if (underlyingSource.start) {
16+
underlyingSource.start(this);
17+
}
18+
}
19+
20+
getReader() {
21+
return {
22+
read: async () => {
23+
return new Promise((resolve) => {
24+
this._readable.once('data', (chunk) => {
25+
resolve({ value: chunk, done: false });
26+
});
27+
this._readable.once('end', () => {
28+
resolve({ value: undefined, done: true });
29+
});
30+
});
31+
},
32+
releaseLock: () => {}
33+
};
34+
}
35+
};
36+
}
37+
38+
// Other polyfills can be added as needed
39+
40+
// Export to ensure this file is properly loaded as a module
41+
module.exports = {};

src/tools/crawl-manager.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { z } from 'zod';
2-
import { Tool } from 'fastmcp/src/FastMCP';
3-
import { Context, ToolParameters, UserError } from 'fastmcp';
2+
import { Context, ToolParameters, UserError, Tool } from 'fastmcp';
43
import { getClient } from '@utils/client';
54

65
interface CrawlManagerArgs {

src/tools/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { Tool } from 'fastmcp/src/FastMCP';
21
import { ScrapeTool } from './scrape';
3-
import { ToolParameters } from 'fastmcp';
2+
import { Tool, ToolParameters } from 'fastmcp';
43
import { SearchTool } from './search';
54
import { SitemapTool } from './sitemap';
65
import { CrawlManagerTool } from './crawl-manager';

src/tools/monitor.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { z } from 'zod';
2-
import { Tool } from 'fastmcp/src/FastMCP';
3-
import { Context, ToolParameters, UserError } from 'fastmcp';
2+
import { Context, ToolParameters, UserError, Tool } from 'fastmcp';
43
import { getClient } from '@utils/client';
5-
import { CrawlRequest } from '@utils/types';
4+
import type { CrawlRequest } from '@watercrawl/nodejs/dist/types';
65

76
interface MonitorArgs {
87
type: 'crawl' | 'search';

src/tools/scrape.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { z } from 'zod';
2-
import { Tool } from 'fastmcp/src/FastMCP';
3-
import { Context, ToolParameters, UserError } from 'fastmcp';
2+
import { Context, ToolParameters, UserError, Tool } from 'fastmcp';
43
import { getClient } from '@utils/client';
54
import type { PageOptions } from '@watercrawl/nodejs/dist/types';
65

0 commit comments

Comments
 (0)