Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

colyseus-events

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

colyseus-events - npm Package Compare versions

Comparing version 2.1.1 to 3.0.0

dist/de-dupe-wrapper.d.ts

15

dist/core-visitors.d.ts
import { Container, Events, Traverse, Visitor } from './types';
export declare const schemaKeys: readonly string[];
import { CallbacksCleanup } from './destructors';
export declare const handleSchema: Readonly<{
/**
* keys that exist on any schema object - are not data fields
*/
schemaKeys: readonly string[];
visit: (traverse: Traverse, state: Container, events: Events, namespace: string) => boolean;
cache: CallbacksCleanup;
visit(traverse: Traverse, state: Container, events: Events, namespace: string): boolean;
}>;
export declare const handleArraySchema: Readonly<{
visit: (traverse: Traverse, state: Container, events: Events, namespace: string) => boolean;
cache: CallbacksCleanup;
visit(traverse: Traverse, state: Container, events: Events, namespace: string): boolean;
}>;
export declare const handleMapSchema: Readonly<{
visit: (traverse: Traverse, state: Container, events: Events, namespace: string) => boolean;
cache: CallbacksCleanup;
visit(traverse: Traverse, state: Container, events: Events, namespace: string): boolean;
}>;
export declare const coreVisitors: ReadonlyArray<Visitor>;
//# sourceMappingURL=core-visitors.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.coreVisitors = exports.handleMapSchema = exports.handleArraySchema = exports.handleSchema = exports.schemaKeys = void 0;
exports.coreVisitors = exports.handleMapSchema = exports.handleArraySchema = exports.handleSchema = void 0;
const types_1 = require("./types");
const schema_1 = require("@colyseus/schema");
// all objects in this module are frozen, to narrow API surface
exports.schemaKeys = Object.freeze(Object.keys(new (class extends schema_1.Schema {
})()).concat(['onChange', 'onRemove']));
const destructors_1 = require("./destructors");
exports.handleSchema = Object.freeze({
/**
* keys that exist on any schema object - are not data fields
*/
schemaKeys: exports.schemaKeys,
visit: (traverse, state, events, namespace) => {
cache: new destructors_1.CallbacksCleanup(),
visit(traverse, state, events, namespace) {
if (!(state instanceof schema_1.Schema)) {
return false;
}
state.onChange = (changes) => {
for (const { field, value } of changes) {
const fieldNamespace = `${namespace}/${field}`;
// @ts-ignore: access _definition to get fields list
const fieldsList = Object.values(state._definition.fieldsByIndex);
const destructors = this.cache.resetDestructors(state);
for (const field of fieldsList) {
const fieldNamespace = `${namespace}/${field}`;
const d = state.listen(field, (value, previousValue) => {
if (value === previousValue)
return;
events.emit(fieldNamespace, (0, types_1.Replace)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
}
};
for (const field in state) {
if (!exports.schemaKeys.includes(field) && Object.prototype.hasOwnProperty.call(state, field)) {
const fieldNamespace = `${namespace}/${field}`;
const value = state[field];
traverse(value, events, fieldNamespace);
}
});
destructors.add(d);
}
this.cache.recheckCallbacks(state);
return true;

@@ -36,24 +31,30 @@ },

exports.handleArraySchema = Object.freeze({
visit: (traverse, state, events, namespace) => {
cache: new destructors_1.CallbacksCleanup(),
visit(traverse, state, events, namespace) {
if (!(state instanceof schema_1.ArraySchema)) {
return false;
}
state.onAdd = (value, field) => {
const knownKeys = new Set(); // for ignoring first and last onChange
const destructors = this.cache.resetDestructors(state);
destructors.add(state.onAdd((value, field) => {
const fieldNamespace = `${namespace}/${field}`;
events.emit(namespace, (0, types_1.Add)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
};
state.onChange = (value, field) => {
}));
destructors.add(state.onChange((value, field) => {
if (knownKeys.has(field)) {
const fieldNamespace = `${namespace}/${field}`;
events.emit(fieldNamespace, (0, types_1.Replace)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
}
else {
knownKeys.add(field);
}
}));
destructors.add(state.onRemove((_, field) => {
knownKeys.delete(field);
const fieldNamespace = `${namespace}/${field}`;
events.emit(fieldNamespace, (0, types_1.Replace)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
};
state.onRemove = (_, field) => {
const fieldNamespace = `${namespace}/${field}`;
events.emit(namespace, (0, types_1.Remove)(fieldNamespace));
};
for (const [field, value] of state.entries()) {
const fieldNamespace = `${namespace}/${field}`;
traverse(value, events, fieldNamespace);
}
}));
this.cache.recheckCallbacks(state);
return true;

@@ -63,24 +64,32 @@ },

exports.handleMapSchema = Object.freeze({
visit: (traverse, state, events, namespace) => {
cache: new destructors_1.CallbacksCleanup(),
visit(traverse, state, events, namespace) {
// Check if it is going to handle the state object, and return `false` if not.
if (!(state instanceof schema_1.MapSchema)) {
return false;
}
state.onAdd = (value, field) => {
const knownKeys = new Set(); // for ignoring first and last onChange
const destructors = this.cache.resetDestructors(state);
// Hook on new elements and register destructors
destructors.add(state.onAdd((value, field) => {
const fieldNamespace = `${namespace}/${field}`; // path to the new element
events.emit(namespace, (0, types_1.Add)(fieldNamespace, value)); // emit the add event
traverse(value, events, fieldNamespace); // call the traverse function on the new value
}));
destructors.add(state.onChange((value, field) => {
if (knownKeys.has(field)) {
const fieldNamespace = `${namespace}/${field}`;
events.emit(fieldNamespace, (0, types_1.Replace)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
}
else {
knownKeys.add(field);
}
}));
destructors.add(state.onRemove((_, field) => {
knownKeys.delete(field);
const fieldNamespace = `${namespace}/${field}`;
events.emit(namespace, (0, types_1.Add)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
};
state.onChange = (value, field) => {
const fieldNamespace = `${namespace}/${field}`;
events.emit(fieldNamespace, (0, types_1.Replace)(fieldNamespace, value));
traverse(value, events, fieldNamespace);
};
state.onRemove = (_, field) => {
const fieldNamespace = `${namespace}/${field}`;
events.emit(namespace, (0, types_1.Remove)(fieldNamespace));
};
for (const [field, value] of state.entries()) {
const fieldNamespace = `${namespace}/${field}`;
traverse(value, events, fieldNamespace);
}
}));
this.cache.recheckCallbacks(state);
return true;

@@ -87,0 +96,0 @@ },

export * from './types';
export * from './wire-events';
export * from './core-visitors';
export { CallbacksCleanup } from './destructors';
//# sourceMappingURL=index.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CallbacksCleanup = void 0;
const tslib_1 = require("tslib");

@@ -7,2 +8,4 @@ tslib_1.__exportStar(require("./types"), exports);

tslib_1.__exportStar(require("./core-visitors"), exports);
var destructors_1 = require("./destructors");
Object.defineProperty(exports, "CallbacksCleanup", { enumerable: true, get: function () { return destructors_1.CallbacksCleanup; } });
//# sourceMappingURL=index.js.map

@@ -24,6 +24,7 @@ import { ArraySchema, CollectionSchema, MapSchema, Schema, SetSchema } from '@colyseus/schema';

export declare type Event = Add | Remove | Replace;
export declare function equalEvents(a: Event, b: Event): boolean;
export declare function Add(path: string, value: Colyseus): Add;
export declare function Replace(path: string, value: Colyseus): Replace;
export declare function Remove(path: string): Remove;
export declare type Traverse<T extends Events = Events> = (state: Colyseus, events: T, jsonPath: string) => T;
export declare type Traverse<T extends Events = Events> = (state: Colyseus, events: T, jsonPath: string) => unknown;
/**

@@ -30,0 +31,0 @@ * logic to wire events for a single entity type

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Remove = exports.Replace = exports.Add = exports.isPrimitive = void 0;
exports.Remove = exports.Replace = exports.Add = exports.equalEvents = exports.isPrimitive = void 0;
function isPrimitive(val) {

@@ -8,2 +8,12 @@ return typeof val !== 'object' || !val;

exports.isPrimitive = isPrimitive;
function equalEvents(a, b) {
if (a === b)
return true;
if (a.op !== b.op || a.path !== b.path)
return false;
if (a.op === 'remove')
return true; // 'remove' events have no 'value'
return a.value === b.value;
}
exports.equalEvents = equalEvents;
function Add(path, value) {

@@ -10,0 +20,0 @@ return { op: 'add', path, value };

@@ -15,3 +15,6 @@ import { Colyseus, Events, Visitor } from './types';

*/
export declare function customWireEvents(visitors: Iterable<Visitor>): <T extends Events<string>>(state: Colyseus, events: T, namespace?: string) => T;
export declare function customWireEvents(visitors: Iterable<Visitor>): <T extends Events<string>>(root: Colyseus, userEvents: T, rootNamespace?: string) => {
events: T;
clearCache: () => void;
};
/**

@@ -25,3 +28,6 @@ * make every change in Colyseus state trigger an event in the EventEmitter using the provided namespace.

*/
export declare const wireEvents: <T extends Events<string>>(state: Colyseus, events: T, namespace?: string) => T;
export declare const wireEvents: <T extends Events<string>>(root: Colyseus, userEvents: T, rootNamespace?: string) => {
events: T;
clearCache: () => void;
};
//# sourceMappingURL=wire-events.d.ts.map

@@ -5,2 +5,4 @@ "use strict";

const types_1 = require("./types");
const de_dupe_wrapper_1 = require("./de-dupe-wrapper");
const weak_set_1 = require("./weak-set");
const core_visitors_1 = require("./core-visitors");

@@ -13,12 +15,22 @@ /**

function customWireEvents(visitors) {
return function recursive(state, events, namespace = '') {
if ((0, types_1.isPrimitive)(state)) {
return events;
}
for (const ch of visitors) {
if (ch.visit(recursive, state, events, namespace)) {
return function wireEvents(root, userEvents, rootNamespace = '') {
const wiredContainers = new weak_set_1.SymbolWeakSet();
function recursive(state, events, namespace) {
if ((0, types_1.isPrimitive)(state)) {
return events;
}
if (wiredContainers.has(state)) {
return events;
}
wiredContainers.add(state);
for (const ch of visitors) {
if (ch.visit(recursive, state, events, namespace)) {
return events;
}
}
return events;
}
return events;
const dedupedEvents = new de_dupe_wrapper_1.DeDupeEmitter(userEvents);
recursive(root, dedupedEvents, rootNamespace);
return { events: userEvents, clearCache: dedupedEvents.clearCache };
};

@@ -25,0 +37,0 @@ }

{
"name": "colyseus-events",
"version": "2.1.1",
"version": "3.0.0",
"description": "generate notification events from colyseus state",

@@ -32,6 +32,6 @@ "repository": "git@github.com:starwards/colyseus-events.git",

"peerDependencies": {
"@colyseus/schema": "1.x"
"@colyseus/schema": "2.x"
},
"devDependencies": {
"@colyseus/schema": "^1.0.41",
"@colyseus/schema": "^2.0.27",
"@types/tape": "^4.13.2",

@@ -38,0 +38,0 @@ "@typescript-eslint/eslint-plugin": "^5.29.0",

@@ -7,3 +7,3 @@ # colyseus-events

const room: Room<GameState> = await client.joinOrCreate("game");
const events = wireEvents(room.state, new EventEmitter());
const { events } = wireEvents(room.state, new EventEmitter());
// `events` will emit json-patch events whenever the room state changes

@@ -14,3 +14,3 @@ ```

Due to breaking API changes in Colyseus, this version only supports Colyseus 0.14 and above (@colyseus/schema >= 1.0.2)
Due to breaking API changes in Colyseus, this version only supports Colyseus 0.15 and above (@colyseus/schema 2.x)

@@ -30,3 +30,3 @@ ## Pending support

const room: Room<GameState> = await client.joinOrCreate("game");
const events = wireEvents(room.state, new EventEmitter());
const { events } = wireEvents(room.state, new EventEmitter());
// `events` will emit json-patch events whenever the room state changes

@@ -45,3 +45,3 @@ ```

const room: Room<GameState> = await client.joinOrCreate("game");
const events = wireEvents(room.state, new EventEmitter());
const { events } = wireEvents(room.state, new EventEmitter());
// `events` will emit json-patch events whenever the room state changes

@@ -58,7 +58,8 @@ ```

2. Call the traverse function for each child member of the state.
3. Hook on the state's [`.onChange`](https://docs.colyseus.io/colyseus/state/schema/#onchange-changes-datachange) and possibly [`.onAdd`](https://docs.colyseus.io/colyseus/state/schema/#onadd-instance-key) and [`.onRemove`](https://docs.colyseus.io/colyseus/state/schema/#onremove-instance-key), or perhaspse the [`.listen`](https://docs.colyseus.io/colyseus/state/schema/#listenprop-callback) mechanism.
3. Hook on the state's [Client-side Callbacks](https://docs.colyseus.io/state/schema-callbacks/#state-sync-client-side-callbacks). Make sure to only hook once per state object. This may become trickey with Proxies, and 'stickey' callbacks.
4. For every new value in each child member of the state, call the traverse function and emit the events using the event emitter.
Examples can be found in [core-visitors.ts](src/core-visitors.ts). Here is the visitor that handles `MapSchema`:
Examples can be found in [core-visitors.ts](src/core-visitors.ts). Here is a brief of the visitor that handles `MapSchema`:
```typescript
{
visit: (traverse: Traverse, state: Container, events: Events, namespace: string) => {

@@ -78,7 +79,2 @@ // Check if it is going to handle the state object, and return `false` if not.

// Call the traverse function for each child member of the state.
for (const [field, value] of state.entries()) {
const fieldNamespace = `${namespace}/${field}`;
traverse(value as Colyseus, events, fieldNamespace);
}
// finally return true. this will break the visitors fallback chain and complete the wiring for this object.

@@ -89,2 +85,3 @@ return true;

```
In addition to the code above, there ais also code to handle duplicate events and keeping only one registration per state object.
## Examples

@@ -91,0 +88,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc