@xstate/inspect
Version:
XState inspection utilities
126 lines (121 loc) • 4.62 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var _tslib = require('./_virtual/_tslib.js');
var xstate = require('xstate');
var inspectMachine = require('./inspectMachine.js');
var utils = require('./utils.js');
var services = new Set();
var serviceMap = new Map();
var serviceListeners = new Set();
function createDevTools() {
globalThis.__xstate__ = {
services: services,
register: function (service) {
services.add(service);
serviceMap.set(service.sessionId, service);
serviceListeners.forEach(function (listener) { return listener(service); });
service.onStop(function () {
services.delete(service);
serviceMap.delete(service.sessionId);
});
},
onRegister: function (listener) {
serviceListeners.add(listener);
services.forEach(function (service) { return listener(service); });
return {
unsubscribe: function () {
serviceListeners.delete(listener);
}
};
}
};
}
function inspect(options) {
var server = options.server;
createDevTools();
var inspectService = xstate.interpret(inspectMachine.createInspectMachine(globalThis.__xstate__, options)).start();
var client = xstate.toActorRef({
id: '@@xstate/ws-client',
send: function (event) {
server.clients.forEach(function (wsClient) {
if (wsClient.readyState === wsClient.OPEN) {
wsClient.send(JSON.stringify(event));
}
});
},
subscribe: function () {
return { unsubscribe: function () { return void 0; } };
},
getSnapshot: function () { return undefined; }
});
server.on('connection', function connection(wsClient) {
wsClient.on('message', function incoming(data, isBinary) {
if (isBinary) {
return;
}
var jsonMessage = JSON.parse(data.toString());
inspectService.send(_tslib.__assign(_tslib.__assign({}, jsonMessage), { client: client }));
});
});
globalThis.__xstate__.onRegister(function (service) {
inspectService.send({
type: 'service.register',
machine: JSON.stringify(service.machine),
state: JSON.stringify(service.state || service.initialState),
id: service.id,
sessionId: service.sessionId
});
inspectService.send({
type: 'service.event',
event: utils.stringify((service.state || service.initialState)._event),
sessionId: service.sessionId
});
// monkey-patch service.send so that we know when an event was sent
// to a service *before* it is processed, since other events might occur
// while the sent one is being processed, which throws the order off
var originalSend = service.send.bind(service);
service.send = function inspectSend(event, payload) {
inspectService.send({
type: 'service.event',
event: utils.stringify(xstate.toSCXMLEvent(xstate.toEventObject(event, payload))),
sessionId: service.sessionId
});
return originalSend(event, payload);
};
service.subscribe(function (state) {
inspectService.send({
type: 'service.state',
state: utils.stringify(state),
sessionId: service.sessionId
});
});
service.onStop(function () {
inspectService.send({
type: 'service.stop',
sessionId: service.sessionId
});
});
});
var inspector = xstate.toActorRef({
id: '@@xstate/inspector',
send: function (event) {
inspectService.send(event);
},
subscribe: function () {
return {
unsubscribe: function () { return void 0; }
};
},
disconnect: function () {
server.close();
inspectService.stop();
},
getSnapshot: function () { return undefined; }
});
server.on('close', function () {
inspectService.stop();
server.clients.forEach(function (client) { return client.terminate(); });
});
return inspector;
}
exports.inspect = inspect;