diff --git a/package-lock.json b/package-lock.json index 5e32b35..3ea3f29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,9 @@ "version": "0.1.0", "license": "MIT", "devDependencies": { - "rxjs": "^7.8.1", "tsup": "^8.3.5", "typescript": "^5.6.0", "vitest": "^4.1.7" - }, - "peerDependencies": { - "rxjs": "^7.0.0" } }, "node_modules/@emnapi/core": { @@ -2266,16 +2262,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -2426,7 +2412,8 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, - "license": "0BSD" + "license": "0BSD", + "optional": true }, "node_modules/tsup": { "version": "8.5.1", diff --git a/package.json b/package.json index d256b98..8ba4cab 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,7 @@ "test": "vitest run", "prepublishOnly": "npm run build" }, - "peerDependencies": { - "rxjs": "^7.0.0" - }, "devDependencies": { - "rxjs": "^7.8.1", "tsup": "^8.3.5", "typescript": "^5.6.0", "vitest": "^4.1.7" @@ -34,7 +30,6 @@ "keywords": [ "ecs", "entity-component-system", - "rxjs", "observable", "game" ], diff --git a/src/index.ts b/src/index.ts index c6749fa..9bb2d6a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,3 +17,4 @@ export type { RelationshipUpdate, } from "./observable/events"; export type { WorldSnapshot } from "./serialization"; +export type { Observable, Subscription } from "./observable/subject"; diff --git a/src/observable/observe.ts b/src/observable/observe.ts index 6b413d1..f30aa61 100644 --- a/src/observable/observe.ts +++ b/src/observable/observe.ts @@ -1,4 +1,4 @@ -import { Subject } from "rxjs"; +import { Subject } from "./subject"; import type { Query } from "../query"; import type { Entity } from "../entity"; import type { diff --git a/src/observable/subject.ts b/src/observable/subject.ts new file mode 100644 index 0000000..cfd03d6 --- /dev/null +++ b/src/observable/subject.ts @@ -0,0 +1,50 @@ +// ── Internal Observable / Subject ───────────────────── +/** Minimal subscription handle returned by `.subscribe()`. */ +export interface Subscription { + unsubscribe(): void; +} + +/** Minimal observable interface — only supports single-callback subscribe. */ +export interface Observable { + subscribe(observer: (value: T) => void): Subscription; +} + +/** Lightweight multicast subject, replacing the RxJS dependency. */ +export class Subject implements Observable { + private _subs = new Set<(value: T) => void>(); + private _done = false; + + /** Push a value to all current subscribers. No-op after complete. */ + next(value: T): void { + if (this._done) return; + for (const fn of this._subs) { + fn(value); + } + } + + /** Register a subscriber. Returns a handle to unsubscribe. */ + subscribe(observer: (value: T) => void): Subscription { + const fn = observer; + this._subs.add(fn); + return { + unsubscribe: () => { + this._subs.delete(fn); + }, + }; + } + + /** Complete this subject — clears all subscribers and silences future calls. */ + complete(): void { + this._done = true; + this._subs.clear(); + } + + /** Return a read-only Observable facade (hides `next` / `complete`). */ + asObservable(): Observable { + return { + subscribe: (observer: (value: T) => void): Subscription => { + return this.subscribe(observer); + }, + }; + } +} diff --git a/src/world.ts b/src/world.ts index e4f26b6..1653d9b 100644 --- a/src/world.ts +++ b/src/world.ts @@ -6,7 +6,7 @@ import { SparseSet } from "./storage/sparse-set"; import { ObservableLayer } from "./observable/observe"; import type { QueryUpdate, RelationshipUpdate } from "./observable/events"; import type { RelationshipDef } from "./relationship"; -import { Observable } from "rxjs"; +import type { Observable } from "./observable/subject"; import type { WorldEvent } from "./observable/events"; import type { WorldSnapshot } from "./serialization";