Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion engine/sdks/typescript/runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
"@rivetkit/virtual-websocket": "workspace:*",
"@rivetkit/engine-runner-protocol": "workspace:*",
"uuid": "^12.0.0",
"pino": "^9.9.5",
"pino": "^9.9.5"
},
"optionalDependencies": {
"ws": "^8.18.3"
},
"devDependencies": {
Expand Down
28 changes: 23 additions & 5 deletions engine/sdks/typescript/runner/src/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,32 @@ export async function importWebSocket(): Promise<typeof WebSocket> {
webSocketPromise = (async () => {
let _WebSocket: typeof WebSocket;

if (typeof WebSocket !== "undefined") {
// Native
_WebSocket = WebSocket as unknown as typeof WebSocket;
// Check for native WebSocket in multiple ways to handle different runtimes
// Some runtimes expose WebSocket on globalThis but not as a global variable
const nativeWebSocket =
typeof WebSocket !== "undefined"
? WebSocket
: typeof globalThis !== "undefined" && globalThis.WebSocket
? globalThis.WebSocket
: undefined;

if (nativeWebSocket) {
// Native WebSocket (browsers, Deno, Node 22+, edge runtimes like Convex/Cloudflare)
_WebSocket = nativeWebSocket as unknown as typeof WebSocket;
logger()?.debug({ msg: "using native websocket" });
} else {
// Node.js package
// Node.js package - only for older Node.js without native WebSocket
try {
const ws = await import("ws");
// Use new Function to completely hide the import from bundlers.
// Bundlers like esbuild statically analyze imports and include
// dependencies even with variable indirection. This technique
// prevents any bundler from seeing the "ws" string.
// Edge runtimes should hit the native WebSocket branch above.
const dynamicImport = new Function(
"moduleName",
"return import(moduleName)",
) as (moduleName: string) => Promise<any>;
const ws = await dynamicImport("ws");
_WebSocket = ws.default as unknown as typeof WebSocket;
logger()?.debug({ msg: "using websocket from npm" });
} catch {
Expand Down
6 changes: 6 additions & 0 deletions examples/convex/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions examples/convex/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions examples/convex/convex.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions examples/convex/convex/_generated/api.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions examples/convex/convex/_generated/api.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions examples/convex/convex/_generated/dataModel.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading