Skip to content
Merged
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 .github/workflows/test-and-build.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
name: Test and build when pushing to a branch
on: push
jobs:
build_and_deploy:
test_and_build:
runs-on: ubuntu-latest
env:
NODE_OPTIONS: "--max_old_space_size=4096"
steps:
- uses: actions/checkout@v2
- name: install monorepo dependencies
run: npm ci
- name: lint monorepo
run: npm run lint
- name: build monorepo packages
run: npm run build
- name: test monorepo
Expand Down
6 changes: 3 additions & 3 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import globals from "globals";
import tseslint from "typescript-eslint";


export default [
{ files: ["**/*.{js,mjs,cjs,ts}"] },
{ languageOptions: { globals: globals.browser } },
Expand All @@ -11,5 +10,6 @@ export default [
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
},
}
];
},
];

6,196 changes: 3,074 additions & 3,122 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
"main": "lib/rimless.js",
"module": "lib/rimless.js",
"types": "lib/index.d.ts",
"files": [
"lib"
],
"files": ["lib"],
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint . --ignore-pattern '**/*.min.js'",
"lint": "eslint . --ignore-pattern='lib/*' --ignore-pattern='lib/**' --ignore-pattern '**/*.min.js'",
"test": "vitest run",
"preview": "vite preview",
"storybook": "storybook dev -p 6006",
Expand Down Expand Up @@ -43,6 +41,7 @@
"eslint": "^9.12.0",
"globals": "^15.11.0",
"happy-dom": "^15.7.4",
"prettier": "^3.5.3",
"storybook": "^8.2.9",
"terser": "^5.34.1",
"typescript": "^5.5.3",
Expand Down
2 changes: 1 addition & 1 deletion src/guest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function connect(schema: ISchema = {}, eventHandlers?: EventHandlers): Promise<I
eventData.schema,
eventData.methods,
eventData.connectionID,
event
event,
);

await eventHandlers?.onConnectionSetup?.(remote);
Expand Down
11 changes: 5 additions & 6 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ let NodeWorkerClass: any = null;

if (isNodeEnv()) {
try {
const workerThreads = require('worker_threads');
// eslint-disable-next-line @typescript-eslint/no-require-imports
const workerThreads = require("worker_threads");
NodeWorkerClass = workerThreads.Worker;
} catch {
}
} catch {}
}

export function isNodeWorker(target: any): target is NodeWorker {
Expand All @@ -139,15 +139,15 @@ export function isWorkerLike(target: any): target is WorkerLike {
export function addEventListener(target: Window | WorkerLike | HTMLIFrameElement, event: string, handler: any) {
if (isNodeWorker(target)) {
target.on(event, handler);
} else if ('addEventListener' in target) {
} else if ("addEventListener" in target) {
target.addEventListener(event, handler);
}
}

export function removeEventListener(target: Window | WorkerLike | HTMLIFrameElement, event: string, handler: any) {
if (isNodeWorker(target)) {
target.off(event, handler);
} else if ('removeEventListener' in target) {
} else if ("removeEventListener" in target) {
target.removeEventListener(event, handler);
}
}
Expand All @@ -160,4 +160,3 @@ export function removeEventListener(target: Window | WorkerLike | HTMLIFrameElem
export function getEventData(event: any): any {
return event.data || event;
}

26 changes: 18 additions & 8 deletions src/host.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { extractMethods, generateId, getOriginFromURL, isNodeEnv, addEventListener, removeEventListener, isNodeWorker, NodeWorker, getEventData } from "./helpers";
import {
extractMethods,
generateId,
getOriginFromURL,
isNodeEnv,
addEventListener,
removeEventListener,
isNodeWorker,
NodeWorker,
getEventData,
} from "./helpers";
import { registerLocalMethods, registerRemoteMethods } from "./rpc";
import { actions, events, IConnection, IConnections, ISchema } from "./types";

const connections: IConnections = {};

function isValidTarget(guest: HTMLIFrameElement | Worker | NodeWorker, event: any) {
// If it's a worker, we don't need to validate origin
if (isNodeWorker(guest) || (typeof Worker !== 'undefined' && guest instanceof Worker)) {
if (isNodeWorker(guest) || (typeof Worker !== "undefined" && guest instanceof Worker)) {
return true;
}

Expand All @@ -20,7 +30,7 @@ function isValidTarget(guest: HTMLIFrameElement | Worker | NodeWorker, event: an

return (hasProperOrigin && hasProperSource) || !childURL;
} catch (e) {
console.warn('Error checking iframe target:', e);
console.warn("Error checking iframe target:", e);
return false;
}
}
Expand All @@ -36,17 +46,17 @@ function isValidTarget(guest: HTMLIFrameElement | Worker | NodeWorker, event: an
function connect(guest: HTMLIFrameElement | Worker | NodeWorker, schema: ISchema = {}): Promise<IConnection> {
if (!guest) throw new Error("a target is required");

const guestIsWorker = isNodeWorker(guest) || ((guest as Worker).onerror !== undefined && (guest as Worker).onmessage !== undefined);
const guestIsWorker =
isNodeWorker(guest) || ((guest as Worker).onerror !== undefined && (guest as Worker).onmessage !== undefined);
const listeners = guestIsWorker || isNodeEnv() ? guest : window;

return new Promise((resolve) => {
const connectionID = generateId();

// on handshake request
function handleHandshake(event: any) {

if (!guestIsWorker && !isNodeEnv() && !isValidTarget(guest, event)) return;

const eventData = getEventData(event);
if (eventData?.action !== actions.HANDSHAKE_REQUEST) return;

Expand All @@ -56,7 +66,7 @@ function connect(guest: HTMLIFrameElement | Worker | NodeWorker, schema: ISchema
schema,
localMethods,
connectionID,
guestIsWorker || isNodeEnv() ? (guest as Worker) : undefined
guestIsWorker || isNodeEnv() ? (guest as Worker) : undefined,
);

// register remote methods
Expand All @@ -65,7 +75,7 @@ function connect(guest: HTMLIFrameElement | Worker | NodeWorker, schema: ISchema
eventData.methods,
connectionID,
event,
guestIsWorker || isNodeEnv() ? (guest as Worker) : undefined
guestIsWorker || isNodeEnv() ? (guest as Worker) : undefined,
);

const payload = {
Expand Down
17 changes: 13 additions & 4 deletions src/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { generateId, get, isNodeEnv, isWorker, set, addEventListener, removeEventListener, getEventData } from "./helpers";
import {
generateId,
get,
isNodeEnv,
isWorker,
set,
addEventListener,
removeEventListener,
getEventData,
} from "./helpers";
import { actions, events, IRPCRequestPayload, IRPCResolvePayload, ISchema } from "./types";

/**
Expand All @@ -14,7 +23,7 @@ export function registerLocalMethods(
schema: ISchema = {},
methods: any[] = [],
_connectionID: string,
guest?: Worker
guest?: Worker,
): any {
const listeners: any[] = [];
methods.forEach((methodName) => {
Expand Down Expand Up @@ -81,7 +90,7 @@ export function createRPC(
_connectionID: string,
event: any,
listeners: Array<() => void> = [],
guest?: Worker
guest?: Worker,
) {
return (...args: any) => {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -140,7 +149,7 @@ export function registerRemoteMethods(
methods: any[] = [],
_connectionID: string,
event: any,
guest?: Worker
guest?: Worker,
) {
const remote = { ...schema };
const listeners: Array<() => void> = [];
Expand Down
16 changes: 8 additions & 8 deletions tests/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,25 @@ describe("environment detection", () => {
});

it("returns true in worker environment", () => {
// @ts-ignore
// @ts-expect-error - mocking worker env
global.window = undefined;
// @ts-ignore
// @ts-expect-error - mocking worker env
global.self = {};
expect(isWorker()).toBe(true);
});

it("returns false in browser environment", () => {
// @ts-ignore
// @ts-expect-error - mocking browser env
global.window = {};
// @ts-ignore
// @ts-expect-error - mocking browser env
global.self = {};
expect(isWorker()).toBe(false);
});

it("returns false when self is undefined", () => {
// @ts-ignore
// @ts-expect-error - mocking node env
global.window = undefined;
// @ts-ignore
// @ts-expect-error - mocking node env
global.self = undefined;
expect(isWorker()).toBe(false);
});
Expand All @@ -102,13 +102,13 @@ describe("environment detection", () => {
});

it("returns true in Node.js environment", () => {
// @ts-ignore
// @ts-expect-error - mocking node env
global.window = undefined;
expect(isNodeEnv()).toBe(true);
});

it("returns false in browser environment", () => {
// @ts-ignore
// @ts-expect-error - mocking browser env
global.window = {};
expect(isNodeEnv()).toBe(false);
});
Expand Down