@statelyai/inspect
Advanced tools
Comparing version 0.2.0 to 0.2.1
{ | ||
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", | ||
"changelog": "@changesets/cli/changelog", | ||
"changelog": ["@changesets/changelog-github", { "repo": "statelyai/inspect" }], | ||
"commit": false, | ||
@@ -5,0 +5,0 @@ "fixed": [], |
# @statelyai/inspect | ||
## 0.2.1 | ||
### Patch Changes | ||
- [#8](https://github.com/statelyai/inspect/pull/8) [`ea5bab4`](https://github.com/statelyai/inspect/commit/ea5bab45c581cb8bf76af0c610258bf1c4250466) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Safely stringify snapshots from XState events to deal with circular references | ||
- [#9](https://github.com/statelyai/inspect/pull/9) [`12fe68e`](https://github.com/statelyai/inspect/commit/12fe68efd528d63999e157c4711e6b108e650808) Thanks [@mellson](https://github.com/mellson)! - Update to the latest version of XState and move it to peer dependencies. | ||
## 0.2.0 | ||
@@ -4,0 +12,0 @@ |
@@ -96,3 +96,3 @@ import { InspectionEvent, Snapshot, AnyActorRef, AnyEventObject, Observer, Subscribable } from 'xstate'; | ||
} | ||
declare function createInspector<TAdapter extends Adapter>(adapter: TAdapter): Inspector<TAdapter>; | ||
declare function createInspector<TAdapter extends Adapter>(adapter: TAdapter, options?: InspectorOptions): Inspector<TAdapter>; | ||
@@ -99,0 +99,0 @@ interface WebSocketInspectorOptions extends InspectorOptions { |
@@ -52,2 +52,3 @@ "use strict"; | ||
devDependencies: { | ||
"@changesets/changelog-github": "^0.5.0", | ||
"@changesets/cli": "^2.26.2", | ||
@@ -58,6 +59,7 @@ "@types/jsdom": "^21.1.6", | ||
typescript: "^5.1.6", | ||
vitest: "^0.34.6" | ||
vitest: "^0.34.6", | ||
xstate: "^5.5.1" | ||
}, | ||
name: "@statelyai/inspect", | ||
version: "0.2.0", | ||
version: "0.2.1", | ||
description: "Inspection utilities for state, actors, workflows, and state machines.", | ||
@@ -70,5 +72,7 @@ main: "dist/index.js", | ||
"fast-safe-stringify": "^2.1.1", | ||
"isomorphic-ws": "^5.0.0", | ||
xstate: "5.1.0" | ||
"isomorphic-ws": "^5.0.0" | ||
}, | ||
peerDependencies: { | ||
xstate: "^5.5.1" | ||
}, | ||
scripts: { | ||
@@ -78,7 +82,11 @@ build: "tsup src/index.ts --dts", | ||
test: "vitest", | ||
prepublishOnly: "tsup src/index.ts --dts" | ||
prepublishOnly: "tsup src/index.ts --dts", | ||
changeset: "changeset", | ||
release: "changeset publish", | ||
version: "changeset version" | ||
}, | ||
publishConfig: { | ||
access: "public" | ||
} | ||
}, | ||
packageManager: "pnpm@8.11.0" | ||
}; | ||
@@ -97,2 +105,3 @@ | ||
// src/createInspector.ts | ||
var import_fast_safe_stringify = __toESM(require("fast-safe-stringify")); | ||
function getRoot(actorRef) { | ||
@@ -109,3 +118,10 @@ let marker = actorRef; | ||
} | ||
function createInspector(adapter) { | ||
function createInspector(adapter, options) { | ||
function sendAdapter(event) { | ||
if (options?.filter && !options.filter(event)) { | ||
return; | ||
} | ||
const serializedEvent = options?.serialize?.(event) ?? event; | ||
adapter.send(serializedEvent); | ||
} | ||
const inspector = { | ||
@@ -120,3 +136,3 @@ adapter, | ||
const name = definitionObject ? definitionObject.id : sessionId; | ||
adapter.send({ | ||
sendAdapter({ | ||
type: "@xstate.actor", | ||
@@ -134,6 +150,6 @@ name, | ||
}, | ||
event(target, event, info) { | ||
event: (target, event, info) => { | ||
const sessionId = typeof target === "string" ? target : target.sessionId; | ||
const sourceId = !info?.source ? void 0 : typeof info.source === "string" ? info.source : info.source.sessionId; | ||
adapter.send({ | ||
sendAdapter({ | ||
type: "@xstate.event", | ||
@@ -149,5 +165,5 @@ sourceId, | ||
}, | ||
snapshot(actor, snapshot, info) { | ||
snapshot: (actor, snapshot, info) => { | ||
const sessionId = typeof actor === "string" ? actor : actor.sessionId; | ||
adapter.send({ | ||
sendAdapter({ | ||
type: "@xstate.snapshot", | ||
@@ -170,3 +186,3 @@ snapshot: { | ||
const convertedEvent = convertXStateEvent(event); | ||
adapter.send(convertedEvent); | ||
sendAdapter(convertedEvent); | ||
}); | ||
@@ -232,3 +248,3 @@ } | ||
event: inspectionEvent.event, | ||
snapshot: JSON.parse(JSON.stringify(inspectionEvent.snapshot)), | ||
snapshot: JSON.parse((0, import_fast_safe_stringify.default)(inspectionEvent.snapshot)), | ||
sessionId: inspectionEvent.actorRef.sessionId, | ||
@@ -251,3 +267,3 @@ _version: package_default.version, | ||
var import_isomorphic_ws = __toESM(require("isomorphic-ws")); | ||
var import_fast_safe_stringify = __toESM(require("fast-safe-stringify")); | ||
var import_fast_safe_stringify2 = __toESM(require("fast-safe-stringify")); | ||
var import_xstate = require("xstate"); | ||
@@ -262,3 +278,3 @@ var WebSocketAdapter = class { | ||
filter: () => true, | ||
serialize: (event) => JSON.parse((0, import_fast_safe_stringify.default)(event)), | ||
serialize: (event) => JSON.parse((0, import_fast_safe_stringify2.default)(event)), | ||
autoStart: true, | ||
@@ -311,3 +327,3 @@ url: "ws://localhost:8080", | ||
const adapter = new WebSocketAdapter(options); | ||
const inspector = createInspector(adapter); | ||
const inspector = createInspector(adapter, options); | ||
return inspector; | ||
@@ -351,3 +367,3 @@ } | ||
var import_xstate2 = require("xstate"); | ||
var import_fast_safe_stringify2 = __toESM(require("fast-safe-stringify")); | ||
var import_fast_safe_stringify3 = __toESM(require("fast-safe-stringify")); | ||
@@ -383,3 +399,3 @@ // src/useless.ts | ||
filter: () => true, | ||
serialize: (event) => JSON.parse((0, import_fast_safe_stringify2.default)(event)), | ||
serialize: (event) => JSON.parse((0, import_fast_safe_stringify3.default)(event)), | ||
autoStart: true, | ||
@@ -391,3 +407,3 @@ iframe: null, | ||
const adapter = new BrowserAdapter(resolvedOptions); | ||
const inspector = createInspector(adapter); | ||
const inspector = createInspector(adapter, resolvedOptions); | ||
if (resolvedOptions.autoStart) { | ||
@@ -394,0 +410,0 @@ inspector.start(); |
{ | ||
"devDependencies": { | ||
"@changesets/changelog-github": "^0.5.0", | ||
"@changesets/cli": "^2.26.2", | ||
@@ -8,6 +9,7 @@ "@types/jsdom": "^21.1.6", | ||
"typescript": "^5.1.6", | ||
"vitest": "^0.34.6" | ||
"vitest": "^0.34.6", | ||
"xstate": "^5.5.1" | ||
}, | ||
"name": "@statelyai/inspect", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Inspection utilities for state, actors, workflows, and state machines.", | ||
@@ -20,5 +22,11 @@ "main": "dist/index.js", | ||
"fast-safe-stringify": "^2.1.1", | ||
"isomorphic-ws": "^5.0.0", | ||
"xstate": "5.1.0" | ||
"isomorphic-ws": "^5.0.0" | ||
}, | ||
"peerDependencies": { | ||
"xstate": "^5.5.1" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"packageManager": "pnpm@8.11.0", | ||
"scripts": { | ||
@@ -28,7 +36,6 @@ "build": "tsup src/index.ts --dts", | ||
"test": "vitest", | ||
"prepublishOnly": "tsup src/index.ts --dts" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
"changeset": "changeset", | ||
"release": "changeset publish", | ||
"version": "changeset version" | ||
} | ||
} | ||
} |
@@ -62,3 +62,3 @@ import { AnyEventObject, Observer, Subscribable, toObserver } from 'xstate'; | ||
const adapter = new BrowserAdapter(resolvedOptions); | ||
const inspector = createInspector(adapter); | ||
const inspector = createInspector(adapter, resolvedOptions); | ||
@@ -65,0 +65,0 @@ // Start immediately |
import { expect, test } from 'vitest'; | ||
import { createInspector } from './createInspector'; | ||
import { StatelyInspectionEvent, Adapter } from './types'; | ||
import { StatelyInspectionEvent, Adapter, StatelyEventEvent } from './types'; | ||
import { createActor, createMachine } from 'xstate'; | ||
import pkg from '../package.json'; | ||
import { StatelyActorEvent } from '../dist'; | ||
@@ -189,1 +190,102 @@ function simplifyEvent(ev: StatelyInspectionEvent) { | ||
}); | ||
test('options.serialize', async () => { | ||
const events: StatelyInspectionEvent[] = []; | ||
const testAdapter: Adapter = { | ||
send: (event) => { | ||
events.push(event); | ||
}, | ||
start: () => {}, | ||
stop: () => {}, | ||
}; | ||
const inspector = createInspector(testAdapter, { | ||
serialize: (ev) => { | ||
if ('snapshot' in ev) { | ||
return { | ||
...ev, | ||
snapshot: { | ||
context: { user: 'anonymous' }, | ||
} as any, | ||
}; | ||
} else if (ev.type === '@xstate.event') { | ||
return { | ||
...ev, | ||
event: { | ||
...ev.event, | ||
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', () => { | ||
const events: StatelyInspectionEvent[] = []; | ||
const testAdapter: Adapter = { | ||
send: (event) => { | ||
events.push(event); | ||
}, | ||
start: () => {}, | ||
stop: () => {}, | ||
}; | ||
const inspector = createInspector(testAdapter); | ||
const circular = { | ||
get val() { | ||
return circular; | ||
}, | ||
}; | ||
expect(() => { | ||
inspector.inspect.next?.({ | ||
type: '@xstate.snapshot', | ||
snapshot: { context: circular } as any, | ||
actorRef: {} as any, | ||
event: { type: 'any' }, | ||
rootId: '', | ||
}); | ||
}).not.toThrow(); | ||
}); |
@@ -13,2 +13,3 @@ import { | ||
import { idleCallback } from './idleCallback'; | ||
import safeStringify from 'fast-safe-stringify'; | ||
@@ -52,4 +53,15 @@ function getRoot(actorRef: AnyActorRef) { | ||
export function createInspector<TAdapter extends Adapter>( | ||
adapter: TAdapter | ||
adapter: TAdapter, | ||
options?: InspectorOptions | ||
): Inspector<TAdapter> { | ||
function sendAdapter(event: StatelyInspectionEvent): void { | ||
if (options?.filter && !options.filter(event)) { | ||
// Event filtered out | ||
return; | ||
} | ||
const serializedEvent = options?.serialize?.(event) ?? event; | ||
// idleCallback(() => { | ||
adapter.send(serializedEvent); | ||
// }) | ||
} | ||
const inspector: Inspector<TAdapter> = { | ||
@@ -74,3 +86,3 @@ adapter, | ||
adapter.send({ | ||
sendAdapter({ | ||
type: '@xstate.actor', | ||
@@ -88,3 +100,3 @@ name, | ||
}, | ||
event(target, event, info) { | ||
event: (target, event, info) => { | ||
const sessionId = typeof target === 'string' ? target : target.sessionId; | ||
@@ -96,3 +108,3 @@ const sourceId = !info?.source | ||
: info.source.sessionId; | ||
adapter.send({ | ||
sendAdapter({ | ||
type: '@xstate.event', | ||
@@ -108,5 +120,5 @@ sourceId, | ||
}, | ||
snapshot(actor, snapshot, info) { | ||
snapshot: (actor, snapshot, info) => { | ||
const sessionId = typeof actor === 'string' ? actor : actor.sessionId; | ||
adapter.send({ | ||
sendAdapter({ | ||
type: '@xstate.snapshot', | ||
@@ -129,3 +141,3 @@ snapshot: { | ||
const convertedEvent = convertXStateEvent(event); | ||
adapter.send(convertedEvent); | ||
sendAdapter(convertedEvent); | ||
}); | ||
@@ -202,3 +214,3 @@ }, | ||
event: inspectionEvent.event, | ||
snapshot: JSON.parse(JSON.stringify(inspectionEvent.snapshot)), | ||
snapshot: JSON.parse(safeStringify(inspectionEvent.snapshot)), | ||
sessionId: inspectionEvent.actorRef.sessionId, | ||
@@ -205,0 +217,0 @@ _version: pkg.version, |
@@ -76,3 +76,3 @@ import { InspectorOptions, createInspector } from './createInspector'; | ||
const inspector = createInspector(adapter); | ||
const inspector = createInspector(adapter, options); | ||
@@ -79,0 +79,0 @@ return inspector; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
66636
23
1705
8
+ Addedxstate@5.19.0(transitive)
- Removedxstate@5.1.0
- Removedxstate@5.1.0(transitive)