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

@statelyai/inspect

Package Overview
Dependencies
Maintainers
3
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.0.3 to 0.0.4

21

dist/index.d.ts

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

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

@@ -21,3 +21,4 @@ interface StatelyBaseInspectionEvent {

}, 'type'> & {
snapshot: any;
name: string;
snapshot: InspectedSnapshot;
definition: string | undefined;

@@ -34,3 +35,3 @@ parentId: string | undefined;

status: Snapshot<unknown>['status'];
context: any;
context?: any;
}

@@ -42,7 +43,9 @@ interface Inspector<TAdapter extends Adapter> {

*/
snapshot: (actor: AnyActorRef | string, snapshot: InspectedSnapshot) => void;
snapshot: (actor: AnyActorRef | string, snapshot: InspectedSnapshot, info?: {
event?: AnyEventObject;
}) => void;
/**
* Sends an event inspection event. This represents the event that was sent to the actor.
*/
event: (targetActor: AnyActorRef | string, event: AnyEventObject | string, { source, }: {
event: (targetActor: AnyActorRef | string, event: AnyEventObject | string, info?: {
source?: string;

@@ -53,3 +56,3 @@ }) => void;

*/
actor: (actor: AnyActorRef | string, snapshot: any, info?: {
actor: (actor: AnyActorRef | string, snapshot?: InspectedSnapshot, info?: {
definition?: string;

@@ -76,2 +79,3 @@ parentId?: string;

* })
* ```
*/

@@ -83,2 +87,3 @@ inspect: Observer<InspectionEvent>;

filter?: (event: StatelyInspectionEvent) => boolean;
serialize?: (event: StatelyInspectionEvent) => StatelyInspectionEvent;
}

@@ -115,2 +120,6 @@ declare function createInspector<TAdapter extends Adapter>(adapter: TAdapter): Inspector<TAdapter>;

}
/**
* Creates a browser-based inspector that sends events to a remote inspector window.
* The remote inspector opens an inspector window at the specified URL by default.
*/
declare function createBrowserInspector(options?: BrowserInspectorOptions): Inspector<BrowserAdapter>;

@@ -117,0 +126,0 @@ interface BrowserReceiverOptions {

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

var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {

@@ -31,2 +34,197 @@ for (var name in all)

// node_modules/.pnpm/registry.npmjs.org+fast-safe-stringify@2.1.1/node_modules/fast-safe-stringify/index.js
var require_fast_safe_stringify = __commonJS({
"node_modules/.pnpm/registry.npmjs.org+fast-safe-stringify@2.1.1/node_modules/fast-safe-stringify/index.js"(exports, module2) {
"use strict";
module2.exports = stringify;
stringify.default = stringify;
stringify.stable = deterministicStringify;
stringify.stableStringify = deterministicStringify;
var LIMIT_REPLACE_NODE = "[...]";
var CIRCULAR_REPLACE_NODE = "[Circular]";
var arr = [];
var replacerStack = [];
function defaultOptions() {
return {
depthLimit: Number.MAX_SAFE_INTEGER,
edgesLimit: Number.MAX_SAFE_INTEGER
};
}
function stringify(obj, replacer, spacer, options) {
if (typeof options === "undefined") {
options = defaultOptions();
}
decirc(obj, "", 0, [], void 0, 0, options);
var res;
try {
if (replacerStack.length === 0) {
res = JSON.stringify(obj, replacer, spacer);
} else {
res = JSON.stringify(obj, replaceGetterValues(replacer), spacer);
}
} catch (_) {
return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]");
} finally {
while (arr.length !== 0) {
var part = arr.pop();
if (part.length === 4) {
Object.defineProperty(part[0], part[1], part[3]);
} else {
part[0][part[1]] = part[2];
}
}
}
return res;
}
function setReplace(replace, val, k, parent) {
var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k);
if (propertyDescriptor.get !== void 0) {
if (propertyDescriptor.configurable) {
Object.defineProperty(parent, k, { value: replace });
arr.push([parent, k, val, propertyDescriptor]);
} else {
replacerStack.push([val, k, replace]);
}
} else {
parent[k] = replace;
arr.push([parent, k, val]);
}
}
function decirc(val, k, edgeIndex, stack, parent, depth, options) {
depth += 1;
var i;
if (typeof val === "object" && val !== null) {
for (i = 0; i < stack.length; i++) {
if (stack[i] === val) {
setReplace(CIRCULAR_REPLACE_NODE, val, k, parent);
return;
}
}
if (typeof options.depthLimit !== "undefined" && depth > options.depthLimit) {
setReplace(LIMIT_REPLACE_NODE, val, k, parent);
return;
}
if (typeof options.edgesLimit !== "undefined" && edgeIndex + 1 > options.edgesLimit) {
setReplace(LIMIT_REPLACE_NODE, val, k, parent);
return;
}
stack.push(val);
if (Array.isArray(val)) {
for (i = 0; i < val.length; i++) {
decirc(val[i], i, i, stack, val, depth, options);
}
} else {
var keys = Object.keys(val);
for (i = 0; i < keys.length; i++) {
var key = keys[i];
decirc(val[key], key, i, stack, val, depth, options);
}
}
stack.pop();
}
}
function compareFunction(a, b) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
function deterministicStringify(obj, replacer, spacer, options) {
if (typeof options === "undefined") {
options = defaultOptions();
}
var tmp = deterministicDecirc(obj, "", 0, [], void 0, 0, options) || obj;
var res;
try {
if (replacerStack.length === 0) {
res = JSON.stringify(tmp, replacer, spacer);
} else {
res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer);
}
} catch (_) {
return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]");
} finally {
while (arr.length !== 0) {
var part = arr.pop();
if (part.length === 4) {
Object.defineProperty(part[0], part[1], part[3]);
} else {
part[0][part[1]] = part[2];
}
}
}
return res;
}
function deterministicDecirc(val, k, edgeIndex, stack, parent, depth, options) {
depth += 1;
var i;
if (typeof val === "object" && val !== null) {
for (i = 0; i < stack.length; i++) {
if (stack[i] === val) {
setReplace(CIRCULAR_REPLACE_NODE, val, k, parent);
return;
}
}
try {
if (typeof val.toJSON === "function") {
return;
}
} catch (_) {
return;
}
if (typeof options.depthLimit !== "undefined" && depth > options.depthLimit) {
setReplace(LIMIT_REPLACE_NODE, val, k, parent);
return;
}
if (typeof options.edgesLimit !== "undefined" && edgeIndex + 1 > options.edgesLimit) {
setReplace(LIMIT_REPLACE_NODE, val, k, parent);
return;
}
stack.push(val);
if (Array.isArray(val)) {
for (i = 0; i < val.length; i++) {
deterministicDecirc(val[i], i, i, stack, val, depth, options);
}
} else {
var tmp = {};
var keys = Object.keys(val).sort(compareFunction);
for (i = 0; i < keys.length; i++) {
var key = keys[i];
deterministicDecirc(val[key], key, i, stack, val, depth, options);
tmp[key] = val[key];
}
if (typeof parent !== "undefined") {
arr.push([parent, k, val]);
parent[k] = tmp;
} else {
return tmp;
}
}
stack.pop();
}
}
function replaceGetterValues(replacer) {
replacer = typeof replacer !== "undefined" ? replacer : function(k, v) {
return v;
};
return function(key, val) {
if (replacerStack.length > 0) {
for (var i = 0; i < replacerStack.length; i++) {
var part = replacerStack[i];
if (part[1] === key && part[0] === val) {
val = part[2];
replacerStack.splice(i, 1);
break;
}
}
}
return replacer.call(this, key, val);
};
}
}
});
// src/index.ts

@@ -61,3 +259,3 @@ var src_exports = {};

name: "@statelyai/inspect",
version: "0.0.3",
version: "0.0.4",
description: "Inspection utilities for state, actors, workflows, and state machines.",

@@ -69,4 +267,5 @@ main: "dist/index.js",

dependencies: {
"fast-safe-stringify": "^2.1.1",
"isomorphic-ws": "^5.0.0",
xstate: "5.0.0-beta.44"
xstate: "5.0.0-beta.53"
},

@@ -102,4 +301,6 @@ scripts: {

const parentId = info?.parentId ?? typeof actorRef === "string" ? void 0 : actorRef._parent?.sessionId;
const name = definitionObject ? definitionObject.id : sessionId;
adapter.send({
type: "@xstate.actor",
name,
sessionId,

@@ -112,10 +313,10 @@ createdAt: Date.now().toString(),

definition,
snapshot
snapshot: snapshot ?? { status: "active" }
});
},
event(target, event, { source }) {
event(target, event, extra) {
const sessionId = typeof target === "string" ? target : target.sessionId;
adapter.send({
type: "@xstate.event",
sourceId: source,
sourceId: extra?.source,
sessionId,

@@ -129,3 +330,3 @@ event: toEventObject(event),

},
snapshot(actor, snapshot) {
snapshot(actor, snapshot, extra) {
const sessionId = typeof actor === "string" ? actor : actor.sessionId;

@@ -135,3 +336,3 @@ adapter.send({

snapshot,
event: null,
event: extra?.event ?? null,
sessionId,

@@ -167,3 +368,5 @@ id: null,

}) : void 0;
const name = definitionObject ? definitionObject.id : actorRef.sessionId;
return {
name,
type: "@xstate.actor",

@@ -272,2 +475,3 @@ definition: definitionString,

// src/BrowserAdapter.ts
var import_fast_safe_stringify = __toESM(require_fast_safe_stringify());
var BrowserAdapter = class {

@@ -282,2 +486,3 @@ status = "disconnected";

filter: () => true,
serialize: (event) => JSON.parse((0, import_fast_safe_stringify.default)(event)),
...options

@@ -299,3 +504,4 @@ };

this.deferredEvents.forEach((event2) => {
this.targetWindow?.postMessage(event2, "*");
const serializedEvent = this.options.serialize(event2);
this.targetWindow?.postMessage(serializedEvent, "*");
});

@@ -314,3 +520,4 @@ }

if (this.status === "connected") {
this.targetWindow?.postMessage(event, "*");
const serializedEvent = this.options.serialize(event);
this.targetWindow?.postMessage(serializedEvent, "*");
}

@@ -317,0 +524,0 @@ this.deferredEvents.push(event);

@@ -11,3 +11,3 @@ {

"name": "@statelyai/inspect",
"version": "0.0.3",
"version": "0.0.4",
"description": "Inspection utilities for state, actors, workflows, and state machines.",

@@ -19,4 +19,5 @@ "main": "dist/index.js",

"dependencies": {
"fast-safe-stringify": "^2.1.1",
"isomorphic-ws": "^5.0.0",
"xstate": "5.0.0-beta.44"
"xstate": "5.0.0-beta.53"
},

@@ -23,0 +24,0 @@ "scripts": {

@@ -6,2 +6,3 @@ # Stately.ai Inspect

## Features
- Visualize state machines

@@ -24,3 +25,3 @@ - Visualize sequence diagrams

const actor = createActor(machine, {
inspect: inspector.inspect
inspect: inspector.inspect,
});

@@ -40,11 +41,25 @@

inspector.actor('someActor', {/* initial state */});
inspector.actor('someActor', {
status: 'active',
context: {
/* any context data */
},
});
inspector.actor('anotherActor', {/* initial state */});
inspector.actor('anotherActor');
inspector.event('someActor', { type: 'hello' }, {
target: 'anotherActor'
inspector.event(
'someActor',
{ type: 'hello' },
{
target: 'anotherActor',
}
);
inspector.snapshot('anotherActor', {
status: 'active',
context: {
/* any context data */
},
});
inspector.snapshot('anotherActor', {/* updated state */});
```
import { expect, test } from 'vitest';
import { createActor, createMachine } from 'xstate';
import { createBrowserInspector } from './browser';
import { createBrowserInspector } from './';
import { StatelyActorEvent } from './types';

@@ -5,0 +5,0 @@ import { JSDOM } from 'jsdom';

@@ -33,2 +33,6 @@ import { AnyEventObject, Observer, Subscribable, toObserver } from 'xstate';

/**
* Creates a browser-based inspector that sends events to a remote inspector window.
* The remote inspector opens an inspector window at the specified URL by default.
*/
export function createBrowserInspector(

@@ -35,0 +39,0 @@ options?: BrowserInspectorOptions

import { Adapter, StatelyInspectionEvent } from './types';
import { BrowserInspectorOptions, isEventObject } from './browser';
import safeStringify from 'fast-safe-stringify';

@@ -14,2 +15,3 @@ export class BrowserAdapter implements Adapter {

filter: () => true,
serialize: (event) => JSON.parse(safeStringify(event)),
...options,

@@ -35,3 +37,4 @@ };

this.deferredEvents.forEach((event) => {
this.targetWindow?.postMessage(event, '*');
const serializedEvent = this.options.serialize(event);
this.targetWindow?.postMessage(serializedEvent, '*');
});

@@ -51,3 +54,4 @@ }

if (this.status === 'connected') {
this.targetWindow?.postMessage(event, '*');
const serializedEvent = this.options.serialize(event);
this.targetWindow?.postMessage(serializedEvent, '*');
}

@@ -54,0 +58,0 @@ this.deferredEvents.push(event);

@@ -15,3 +15,3 @@ import { expect, test } from 'vitest';

sessionId: ev.sessionId,
snapshot: (ev.snapshot as any).value,
snapshot: 'value' in ev.snapshot ? ev.snapshot.value : ev.snapshot,
};

@@ -106,2 +106,70 @@ }

test('Manually inspected events', () => {
const events: StatelyInspectionEvent[] = [];
const testAdapter: Adapter = {
send: (event) => {
events.push(event);
},
start: () => {},
stop: () => {},
};
const inspector = createInspector(testAdapter);
inspector.actor('test');
inspector.actor('another', { status: 'active', context: 10 });
inspector.event('test', 'stringEvent');
inspector.event('another', { type: 'objectEvent' }, { source: 'test' });
inspector.snapshot('test', { status: 'active', context: 20 });
inspector.snapshot(
'another',
{ status: 'done', context: { foo: 'bar' } },
{ event: { type: 'objectEvent' } }
);
expect(events.map(simplifyEvent)).toMatchInlineSnapshot(`
[
{
"sessionId": "test",
"type": "@xstate.actor",
},
{
"sessionId": "another",
"type": "@xstate.actor",
},
{
"event": {
"type": "stringEvent",
},
"sessionId": "test",
"type": "@xstate.event",
},
{
"event": {
"type": "objectEvent",
},
"sessionId": "another",
"type": "@xstate.event",
},
{
"sessionId": "test",
"snapshot": {
"context": 20,
"status": "active",
},
"type": "@xstate.snapshot",
},
{
"sessionId": "another",
"snapshot": {
"context": {
"foo": "bar",
},
"status": "done",
},
"type": "@xstate.snapshot",
},
]
`);
});
test('Inspected event includes version', () => {

@@ -108,0 +176,0 @@ const events: StatelyInspectionEvent[] = [];

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

filter?: (event: StatelyInspectionEvent) => boolean;
serialize?: (event: StatelyInspectionEvent) => StatelyInspectionEvent;
}

@@ -39,2 +40,3 @@

filter: () => true,
serialize: (event) => event,
};

@@ -64,5 +66,7 @@

: actorRef._parent?.sessionId;
const name = definitionObject ? definitionObject.id : sessionId;
adapter.send({
type: '@xstate.actor',
name,
sessionId,

@@ -75,10 +79,10 @@ createdAt: Date.now().toString(),

definition,
snapshot,
snapshot: snapshot ?? { status: 'active' },
} satisfies StatelyActorEvent);
},
event(target, event, { source }) {
event(target, event, extra) {
const sessionId = typeof target === 'string' ? target : target.sessionId;
adapter.send({
type: '@xstate.event',
sourceId: source,
sourceId: extra?.source,
sessionId,

@@ -92,3 +96,3 @@ event: toEventObject(event),

},
snapshot(actor, snapshot) {
snapshot(actor, snapshot, extra) {
const sessionId = typeof actor === 'string' ? actor : actor.sessionId;

@@ -98,3 +102,3 @@ adapter.send({

snapshot: snapshot as unknown as Snapshot<unknown>,
event: null as any,
event: extra?.event ?? (null as any),
sessionId,

@@ -137,4 +141,6 @@ id: null as any,

: undefined;
const name = definitionObject ? definitionObject.id : actorRef.sessionId;
return {
name,
type: '@xstate.actor',

@@ -141,0 +147,0 @@ definition: definitionString,

@@ -36,3 +36,4 @@ import {

> & {
snapshot: any; // JSON snapshot
name: string;
snapshot: InspectedSnapshot; // JSON snapshot
definition: string | undefined; // JSON-stringified definition or URL

@@ -55,3 +56,3 @@ parentId: string | undefined;

status: Snapshot<unknown>['status'];
context: any;
context?: any;
}

@@ -64,3 +65,7 @@

*/
snapshot: (actor: AnyActorRef | string, snapshot: InspectedSnapshot) => void;
snapshot: (
actor: AnyActorRef | string,
snapshot: InspectedSnapshot,
info?: { event?: AnyEventObject }
) => void;
/**

@@ -72,5 +77,3 @@ * Sends an event inspection event. This represents the event that was sent to the actor.

event: AnyEventObject | string,
{
source,
}: {
info?: {
source?: string;

@@ -108,4 +111,5 @@ }

* })
* ```
*/
inspect: Observer<InspectionEvent>;
}
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