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

@statelyai/inspect

Package Overview
Dependencies
Maintainers
0
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@statelyai/inspect - npm Package Compare versions

Comparing version 0.3.1 to 0.4.0

.changeset/neat-beans-wave.md

17

dist/index.d.ts

@@ -1,2 +0,2 @@

import { InspectionEvent, Snapshot, AnyActorRef, AnyEventObject, Observer, Subscribable } from 'xstate';
import { InspectionEvent, Snapshot, AnyActorRef, AnyEventObject, Observer, MachineContext, Subscribable } from 'xstate';

@@ -95,2 +95,17 @@ interface StatelyBaseInspectionEvent {

autoStart?: boolean;
/**
* The maximum number of deferred events to hold in memory until the inspector is active.
* If the number of deferred events exceeds this number, the oldest events will be dropped.
*
* @default 200
*/
maxDeferredEvents?: number;
/**
* Sanitizes events sent to actors. Only the sanitized event will be sent to the inspector.
*/
sanitizeEvent?: (event: AnyEventObject) => AnyEventObject;
/**
* Sanitizes actor snapshot context. Only the sanitized context will be sent to the inspector.
*/
sanitizeContext?: (context: MachineContext) => MachineContext;
}

@@ -97,0 +112,0 @@ declare function createInspector<TAdapter extends Adapter>(adapter: TAdapter, options?: InspectorOptions): Inspector<TAdapter>;

49

dist/index.js

@@ -59,13 +59,13 @@ "use strict";

"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.1",
"@types/jsdom": "^21.1.6",
"@changesets/cli": "^2.27.7",
"@types/jsdom": "^21.1.7",
"@types/uuid": "^9.0.8",
jsdom: "^23.2.0",
tsup: "^8.0.2",
typescript: "^5.3.3",
vitest: "^1.3.1",
xstate: "^5.9.1"
tsup: "^8.1.0",
typescript: "^5.5.3",
vitest: "^1.6.0",
xstate: "^5.14.0"
},
name: "@statelyai/inspect",
version: "0.3.1",
version: "0.4.0",
description: "Inspection utilities for state, actors, workflows, and state machines.",

@@ -129,10 +129,29 @@ main: "dist/index.js",

serialize: (event) => event,
autoStart: true
autoStart: true,
maxDeferredEvents: 200,
sanitizeEvent: (event) => event,
sanitizeContext: (context) => context
};
function createInspector(adapter, options) {
function sendAdapter(event) {
if (options?.filter && !options.filter(event)) {
function sendAdapter(inspectionEvent) {
if (options?.filter && !options.filter(inspectionEvent)) {
return;
}
const serializedEvent = options?.serialize?.(event) ?? event;
const sanitizedEvent = options?.sanitizeContext || options?.sanitizeEvent ? inspectionEvent : {
...inspectionEvent
};
if (options?.sanitizeContext && (sanitizedEvent.type === "@xstate.actor" || sanitizedEvent.type === "@xstate.snapshot")) {
sanitizedEvent.snapshot = {
...sanitizedEvent.snapshot,
// @ts-ignore
context: options.sanitizeContext(
// @ts-ignore
sanitizedEvent.snapshot.context
)
};
}
if (options?.sanitizeEvent && (sanitizedEvent.type === "@xstate.event" || sanitizedEvent.type === "@xstate.snapshot")) {
sanitizedEvent.event = options.sanitizeEvent(sanitizedEvent.event);
}
const serializedEvent = options?.serialize?.(sanitizedEvent) ?? sanitizedEvent;
adapter.send(serializedEvent);

@@ -306,2 +325,3 @@ }

const resolvedOptions = {
...defaultInspectorOptions,
url: "https://stately.ai/inspect",

@@ -402,2 +422,5 @@ filter: () => true,

this.deferredEvents.push(event);
if (this.deferredEvents.length > this.options.maxDeferredEvents) {
this.deferredEvents.shift();
}
}

@@ -462,2 +485,3 @@ };

this.options = {
...defaultInspectorOptions,
filter: () => true,

@@ -509,2 +533,5 @@ serialize: (inspectionEvent) => JSON.parse((0, import_safe_stable_stringify2.default)(inspectionEvent)),

this.deferredEvents.push(inspectionEvent);
if (this.deferredEvents.length > this.options.maxDeferredEvents) {
this.deferredEvents.shift();
}
}

@@ -511,0 +538,0 @@ }

{
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.1",
"@types/jsdom": "^21.1.6",
"@changesets/cli": "^2.27.7",
"@types/jsdom": "^21.1.7",
"@types/uuid": "^9.0.8",
"jsdom": "^23.2.0",
"tsup": "^8.0.2",
"typescript": "^5.3.3",
"vitest": "^1.3.1",
"xstate": "^5.9.1"
"tsup": "^8.1.0",
"typescript": "^5.5.3",
"vitest": "^1.6.0",
"xstate": "^5.14.0"
},
"name": "@statelyai/inspect",
"version": "0.3.1",
"version": "0.4.0",
"description": "Inspection utilities for state, actors, workflows, and state machines.",

@@ -31,6 +31,2 @@ "main": "dist/index.js",

},
"publishConfig": {
"access": "public"
},
"packageManager": "pnpm@8.11.0",
"scripts": {

@@ -40,2 +36,3 @@ "build": "tsup src/index.ts --dts",

"test": "vitest",
"prepublishOnly": "tsup src/index.ts --dts",
"changeset": "changeset",

@@ -45,3 +42,7 @@ "release": "changeset publish",

"dev": "yarn build && ./scripts/dev.sh"
}
}
},
"publishConfig": {
"access": "public"
},
"packageManager": "pnpm@8.11.0"
}
import safeStringify from 'fast-safe-stringify';
import { AnyEventObject, Observer, Subscribable, toObserver } from 'xstate';
import { InspectorOptions, createInspector } from './createInspector';
import {
InspectorOptions,
createInspector,
defaultInspectorOptions,
} from './createInspector';
import { Adapter, Inspector, StatelyInspectionEvent } from './types';

@@ -57,2 +61,3 @@ import { UselessAdapter } from './useless';

const resolvedOptions = {
...defaultInspectorOptions,
url: 'https://stately.ai/inspect',

@@ -193,3 +198,8 @@ filter: () => true,

this.deferredEvents.push(event);
// Remove the oldest event if we've reached the max deferred events
if (this.deferredEvents.length > this.options.maxDeferredEvents) {
this.deferredEvents.shift();
}
}
}

@@ -263,2 +263,65 @@ import { expect, test } from 'vitest';

test('Sanitization options', async () => {
const events: StatelyInspectionEvent[] = [];
const testAdapter: Adapter = {
send: (event) => {
events.push(event);
},
start: () => {},
stop: () => {},
};
const inspector = createInspector(testAdapter, {
sanitizeContext: (ctx) => ({
...ctx,
user: 'anonymous',
}),
sanitizeEvent: (ev) => {
if ('user' in ev) {
return { ...ev, user: 'anonymous' };
} else {
return ev;
}
},
});
inspector.actor('test', { context: { user: 'David' } });
expect((events[0] as StatelyActorEvent).snapshot.context).toEqual({
user: 'anonymous',
});
inspector.snapshot('test', { context: { user: 'David' } });
expect((events[1] as StatelyActorEvent).snapshot.context).toEqual({
user: 'anonymous',
});
inspector.event('test', { type: 'updateUser', user: 'David' });
expect((events[2] as StatelyEventEvent).event).toEqual({
type: 'updateUser',
user: 'anonymous',
});
inspector.inspect.next?.({
type: '@xstate.event',
actorRef: {} as any,
event: {
type: 'setUser',
user: 'Another',
},
rootId: '',
sourceRef: undefined,
});
await new Promise<void>((res) => {
setTimeout(res, 10);
});
expect((events[3] as StatelyEventEvent).event).toEqual({
type: 'setUser',
user: 'anonymous',
});
});
test('it safely stringifies objects with circular dependencies', () => {

@@ -265,0 +328,0 @@ const events: StatelyInspectionEvent[] = [];

@@ -10,3 +10,9 @@ import {

import { Inspector } from './types';
import { AnyActorRef, InspectionEvent, Snapshot } from 'xstate';
import {
AnyActorRef,
AnyEventObject,
InspectionEvent,
MachineContext,
Snapshot,
} from 'xstate';
import pkg from '../package.json';

@@ -44,2 +50,19 @@ import { idleCallback } from './idleCallback';

autoStart?: boolean;
/**
* The maximum number of deferred events to hold in memory until the inspector is active.
* If the number of deferred events exceeds this number, the oldest events will be dropped.
*
* @default 200
*/
maxDeferredEvents?: number;
/**
* Sanitizes events sent to actors. Only the sanitized event will be sent to the inspector.
*/
sanitizeEvent?: (event: AnyEventObject) => AnyEventObject;
/**
* Sanitizes actor snapshot context. Only the sanitized context will be sent to the inspector.
*/
sanitizeContext?: (context: MachineContext) => MachineContext;
}

@@ -51,2 +74,5 @@

autoStart: true,
maxDeferredEvents: 200,
sanitizeEvent: (event) => event,
sanitizeContext: (context) => context,
};

@@ -58,11 +84,38 @@

): Inspector<TAdapter> {
function sendAdapter(event: StatelyInspectionEvent): void {
if (options?.filter && !options.filter(event)) {
function sendAdapter(inspectionEvent: StatelyInspectionEvent): void {
if (options?.filter && !options.filter(inspectionEvent)) {
// Event filtered out
return;
}
const serializedEvent = options?.serialize?.(event) ?? event;
// idleCallback(() => {
const sanitizedEvent: typeof inspectionEvent =
options?.sanitizeContext || options?.sanitizeEvent
? inspectionEvent
: {
...inspectionEvent,
};
if (
options?.sanitizeContext &&
(sanitizedEvent.type === '@xstate.actor' ||
sanitizedEvent.type === '@xstate.snapshot')
) {
sanitizedEvent.snapshot = {
...sanitizedEvent.snapshot,
// @ts-ignore
context: options.sanitizeContext(
// @ts-ignore
sanitizedEvent.snapshot.context
),
};
}
if (
options?.sanitizeEvent &&
(sanitizedEvent.type === '@xstate.event' ||
sanitizedEvent.type === '@xstate.snapshot')
) {
sanitizedEvent.event = options.sanitizeEvent(sanitizedEvent.event);
}
const serializedEvent =
options?.serialize?.(sanitizedEvent) ?? sanitizedEvent;
adapter.send(serializedEvent);
// })
}

@@ -69,0 +122,0 @@ const inspector: Inspector<TAdapter> = {

@@ -23,2 +23,3 @@ import {

this.options = {
...defaultInspectorOptions,
filter: () => true,

@@ -78,2 +79,6 @@ serialize: (inspectionEvent) =>

this.deferredEvents.push(inspectionEvent);
if (this.deferredEvents.length > this.options.maxDeferredEvents) {
this.deferredEvents.shift();
}
}

@@ -80,0 +85,0 @@ }

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