refactor: keep only sockjs and uws transports

Remove faye and ws transports as agreed with maintainer.
DISABLE_SOCKJS=1 now resolves to uws instead of faye.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dupontbertrand
2026-03-18 08:48:31 +01:00
parent 81515c3d99
commit b700e0aa53
5 changed files with 5 additions and 160 deletions

View File

@@ -5,8 +5,6 @@ Package.describe({
});
Npm.depends({
"faye-websocket": "0.11.4",
"ws": "8.18.1",
"uWebSockets.js": "git+https://github.com/unetworking/uWebSockets.js#v20.58.0",
"permessage-deflate2": "0.1.8",
sockjs: "0.3.24",
@@ -55,8 +53,6 @@ Package.onUse(function (api) {
api.addFiles("transports/raw_connection.js", "server");
api.addFiles("transports/sockjs.js", "server");
api.addFiles("transports/faye.js", "server");
api.addFiles("transports/ws.js", "server");
api.addFiles("transports/uws.js", "server");
api.addFiles("transports/index.js", "server");
api.addFiles("stream_server.js", "server");

View File

@@ -1,62 +0,0 @@
import { EventEmitter } from 'events';
import { RawWebSocketConnection } from './raw_connection.js';
/**
* faye-websocket transport — raw WebSocket via faye-websocket library.
* No SockJS, no polling transports, no /sockjs/info endpoint.
*/
export function createFayeTransport() {
return {
name: 'faye',
setup(httpServer, pathPrefix, options) {
var emitter = new EventEmitter();
var FayeWebSocket = Npm.require('faye-websocket');
RoutePolicy.declare(pathPrefix + '/websocket/', 'network');
// Reject plain HTTP requests to /websocket with a clear error message
// (same behavior as SockJS). Without this, they'd fall through to the
// app and return the main HTML page.
WebApp.rawConnectHandlers.use(function (req, res, next) {
var pathname = new URL(req.url, 'http://localhost').pathname;
if (pathname === pathPrefix + '/websocket' ||
pathname === pathPrefix + '/websocket/') {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Not a valid websocket request');
} else {
next();
}
});
// We must take over existing 'upgrade' listeners (similar to what SockJS
// does via overshadowListeners) so that our handler runs first for the
// /websocket path, and other handlers (HMR, etc.) get the rest.
var oldUpgradeListeners = httpServer.listeners('upgrade').slice(0);
httpServer.removeAllListeners('upgrade');
httpServer.on('upgrade', function (req, rawSocket, head) {
var pathname = new URL(req.url, 'http://localhost').pathname;
if (FayeWebSocket.isWebSocket(req) &&
(pathname === pathPrefix + '/websocket' ||
pathname === pathPrefix + '/websocket/')) {
var wsOptions = { extensions: options.websocketExtensions() };
var ws = new FayeWebSocket(req, rawSocket, head, null, wsOptions);
var meteorSocket = new RawWebSocketConnection(ws, req, rawSocket,
// faye-websocket wraps message data in an event object
(event) => event.data
);
emitter.emit('connection', meteorSocket);
} else {
// Pass to other upgrade handlers (HMR, etc.)
for (var i = 0; i < oldUpgradeListeners.length; i++) {
oldUpgradeListeners[i].call(httpServer, req, rawSocket, head);
}
}
});
return emitter;
}
};
}

View File

@@ -1,12 +1,8 @@
import { createSockJSTransport } from './sockjs.js';
import { createFayeTransport } from './faye.js';
import { createWsTransport } from './ws.js';
import { createUwsTransport } from './uws.js';
const TRANSPORTS = {
sockjs: createSockJSTransport,
faye: createFayeTransport,
ws: createWsTransport,
uws: createUwsTransport,
};
@@ -16,7 +12,7 @@ const VALID_NAMES = Object.keys(TRANSPORTS);
* Resolve which transport to use. Priority:
* 1. Meteor.settings.packages['ddp-server'].transport
* 2. DDP_TRANSPORT env var
* 3. DISABLE_SOCKJS=1 → 'faye' (backward compat)
* 3. DISABLE_SOCKJS=1 → 'uws' (backward compat)
* 4. default: 'sockjs'
*
* Also sets __meteor_runtime_config__.DDP_TRANSPORT so the client
@@ -51,9 +47,9 @@ function resolveTransportName() {
return process.env.DDP_TRANSPORT;
}
// 3. Backward compat: DISABLE_SOCKJS=1 → faye
// 3. Backward compat: DISABLE_SOCKJS=1 → uws
if (process.env.DISABLE_SOCKJS) {
return 'faye';
return 'uws';
}
// 4. Default

View File

@@ -5,8 +5,8 @@ import { EventEmitter } from 'events';
* interface as a SockJS connection, as expected by _onConnection
* and livedata_server.js.
*
* Used by the faye and ws transports. The uws transport implements
* its own socket interface directly.
* Used by non-SockJS transports that provide a standard WebSocket
* object. The uws transport implements its own socket interface directly.
*/
export class RawWebSocketConnection extends EventEmitter {
constructor(ws, req, rawSocket, messageAdapter) {

View File

@@ -1,85 +0,0 @@
import { EventEmitter } from 'events';
import zlib from 'node:zlib';
import { RawWebSocketConnection } from './raw_connection.js';
/**
* ws transport — raw WebSocket via the `ws` npm package.
* No SockJS, no polling transports, no /sockjs/info endpoint.
*/
export function createWsTransport() {
return {
name: 'ws',
setup(httpServer, pathPrefix, options) {
var emitter = new EventEmitter();
var WebSocket = Npm.require('ws');
// Determine compression config from websocketExtensions().
// If extensions are configured, enable perMessageDeflate.
var extensions = options.websocketExtensions();
var perMessageDeflate = extensions.length > 0
? {
zlibDeflateOptions: {
level: zlib.constants.Z_BEST_SPEED,
memLevel: zlib.constants.Z_MIN_MEMLEVEL,
windowBits: zlib.constants.Z_MIN_WINDOWBITS
},
threshold: 1024
}
: false;
// Create a ws server in noServer mode — we handle upgrade manually so
// that non-/websocket upgrades (HMR, etc.) reach their own handlers.
var wss = new WebSocket.Server({
noServer: true,
perMessageDeflate: perMessageDeflate
});
RoutePolicy.declare(pathPrefix + '/websocket/', 'network');
// Reject plain HTTP requests to /websocket with a clear error message
WebApp.rawConnectHandlers.use(function (req, res, next) {
var pathname = new URL(req.url, 'http://localhost').pathname;
if (pathname === pathPrefix + '/websocket' ||
pathname === pathPrefix + '/websocket/') {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Not a valid websocket request');
} else {
next();
}
});
// Take over existing 'upgrade' listeners so our handler runs first
// for the /websocket path, and other handlers (HMR, etc.) get the rest.
var oldUpgradeListeners = httpServer.listeners('upgrade').slice(0);
httpServer.removeAllListeners('upgrade');
httpServer.on('upgrade', function (req, rawSocket, head) {
var pathname = new URL(req.url, 'http://localhost').pathname;
if (req.headers.upgrade &&
req.headers.upgrade.toLowerCase() === 'websocket' &&
(pathname === pathPrefix + '/websocket' ||
pathname === pathPrefix + '/websocket/')) {
wss.handleUpgrade(req, rawSocket, head, function (ws) {
var meteorSocket = new RawWebSocketConnection(ws, req, rawSocket,
// ws passes data directly (no event wrapper like faye)
(data, isBinary) => {
if (isBinary) return null;
return typeof data === 'string' ? data : data.toString();
}
);
emitter.emit('connection', meteorSocket);
});
} else {
// Pass to other upgrade handlers (HMR, etc.)
for (var i = 0; i < oldUpgradeListeners.length; i++) {
oldUpgradeListeners[i].call(httpServer, req, rawSocket, head);
}
}
});
return emitter;
}
};
}