vendor: 4,132 bytes, lines 1-88
1import { m as mapOneOrManyArgs, _ as __read, i as isArrayLike, b as mergeMap, c as innerFrom, O as Observable, d as isFunction, o as operate, e as createOperatorSubscriber, f as __values, h as arrRemove, E as EMPTY, n as noop, j as map, p as pipe, k as filter, l as defer, v as validateApiPerspective, q as atom } from './lMIEOdbu.js'; 2import { stegaEncodeSourceMap } from './Bz19uxUR.js'; 3import '#entry'; 4 5var nodeEventEmitterMethods = ['addListener', 'removeListener']; 6var eventTargetMethods = ['addEventListener', 'removeEventListener']; 7var jqueryMethods = ['on', 'off']; 8function fromEvent(target, eventName, options, resultSelector) { 9 if (isFunction(options)) { 10 resultSelector = options; 11 options = undefined; 12 } 13 if (resultSelector) { 14 return fromEvent(target, eventName, options).pipe(mapOneOrManyArgs(resultSelector)); 15 } 16 var _a = __read(isEventTarget(target) 17 ? eventTargetMethods.map(function (methodName) { return function (handler) { return target[methodName](eventName, handler, options); }; }) 18 : 19 isNodeStyleEventEmitter(target) 20 ? nodeEventEmitterMethods.map(toCommonHandlerRegistry(target, eventName)) 21 : isJQueryStyleEventEmitter(target) 22 ? jqueryMethods.map(toCommonHandlerRegistry(target, eventName)) 23 : [], 2), add = _a[0], remove = _a[1]; 24 if (!add) { 25 if (isArrayLike(target)) { 26 return mergeMap(function (subTarget) { return fromEvent(subTarget, eventName, options); })(innerFrom(target)); 27 } 28 } 29 if (!add) { 30 throw new TypeError('Invalid event target'); 31 } 32 return new Observable(function (subscriber) { 33 var handler = function () { 34 var args = []; 35 for (var _i = 0; _i < arguments.length; _i++) { 36 args[_i] = arguments[_i]; 37 } 38 return subscriber.next(1 < args.length ? args : args[0]); 39 }; 40 add(handler); 41 return function () { return remove(handler); }; 42 }); 43} 44function toCommonHandlerRegistry(target, eventName) { 45 return function (methodName) { return function (handler) { return target[methodName](eventName, handler); }; }; 46} 47function isNodeStyleEventEmitter(target) { 48 return isFunction(target.addListener) && isFunction(target.removeListener); 49} 50function isJQueryStyleEventEmitter(target) { 51 return isFunction(target.on) && isFunction(target.off); 52} 53function isEventTarget(target) { 54 return isFunction(target.addEventListener) && isFunction(target.removeEventListener); 55} 56 57function bufferCount(bufferSize, startBufferEvery) { 58 if (startBufferEvery === void 0) { startBufferEvery = null; } 59 startBufferEvery = startBufferEvery !== null && startBufferEvery !== void 0 ? startBufferEvery : bufferSize; 60 return operate(function (source, subscriber) { 61 var buffers = []; 62 var count = 0; 63 source.subscribe(createOperatorSubscriber(subscriber, function (value) { 64 var e_1, _a, e_2, _b; 65 var toEmit = null; 66 if (count++ % startBufferEvery === 0) { 67 buffers.push([]); 68 } 69 try { 70 for (var buffers_1 = __values(buffers), buffers_1_1 = buffers_1.next(); !buffers_1_1.done; buffers_1_1 = buffers_1.next()) { 71 var buffer = buffers_1_1.value; 72 buffer.push(value); 73 if (bufferSize <= buffer.length) { 74 toEmit = toEmit !== null && toEmit !== void 0 ? toEmit : []; 75 toEmit.push(buffer); 76 } 77 } 78 } 79 catch (e_1_1) { e_1 = { error: e_1_1 }; } 80 finally { 81 try { 82 if (buffers_1_1 && !buffers_1_1.done && (_a = buffers_1.return)) _a.call(buffers_1); 83 } 84 finally { if (e_1) throw e_1.error; } 85 } 86 if (toEmit) { 87 try { 88 for (var toEmit_1 = __values(toEmit), toEmit_1_1 = toEmit_1.next(); !toEmit_1_1.done; toEmit_1_1 = toEmit_1.next()) {
89 var buffer = toEmit_1_1.value; 90 arrRemove(buffers, buffer); 91 subscriber.next(buffer); 92 } 93 } 94 catch (e_2_1) { e_2 = { error: e_2_1 }; } 95 finally { 96 try { 97 if (toEmit_1_1 && !toEmit_1_1.done && (_b = toEmit_1.return)) _b.call(toEmit_1); 98 } 99 finally { if (e_2) throw e_2.error; } 100 } 101 } 102 }, function () { 103 var e_3, _a; 104 try { 105 for (var buffers_2 = __values(buffers), buffers_2_1 = buffers_2.next(); !buffers_2_1.done; buffers_2_1 = buffers_2.next()) { 106 var buffer = buffers_2_1.value; 107 subscriber.next(buffer); 108 } 109 } 110 catch (e_3_1) { e_3 = { error: e_3_1 }; } 111 finally { 112 try { 113 if (buffers_2_1 && !buffers_2_1.done && (_a = buffers_2.return)) _a.call(buffers_2); 114 } 115 finally { if (e_3) throw e_3.error; } 116 } 117 subscriber.complete(); 118 }, undefined, function () { 119 buffers = null; 120 })); 121 }); 122} 123 124function concatMap(project, resultSelector) { 125 return isFunction(resultSelector) ? mergeMap(project, resultSelector, 1) : mergeMap(project, 1); 126} 127 128function take(count) { 129 return count <= 0 130 ? 131 function () { return EMPTY; } 132 : operate(function (source, subscriber) { 133 var seen = 0; 134 source.subscribe(createOperatorSubscriber(subscriber, function (value) { 135 if (++seen <= count) { 136 subscriber.next(value); 137 if (count <= seen) { 138 subscriber.complete(); 139 } 140 } 141 })); 142 }); 143} 144 145function takeUntil(notifier) { 146 return operate(function (source, subscriber) { 147 innerFrom(notifier).subscribe(createOperatorSubscriber(subscriber, function () { return subscriber.complete(); }, noop)); 148 !subscriber.closed && source.subscribe(subscriber); 149 }); 150} 151 152const byteToHex = []; 153for (let i = 0; i < 256; ++i) { 154 byteToHex.push((i + 0x100).toString(16).slice(1)); 155} 156function unsafeStringify(arr, offset = 0) { 157 return (byteToHex[arr[offset + 0]] + 158 byteToHex[arr[offset + 1]] + 159 byteToHex[arr[offset + 2]] + 160 byteToHex[arr[offset + 3]] + 161 '-' + 162 byteToHex[arr[offset + 4]] + 163 byteToHex[arr[offset + 5]] + 164 '-' + 165 byteToHex[arr[offset + 6]] + 166 byteToHex[arr[offset + 7]] + 167 '-' + 168 byteToHex[arr[offset + 8]] + 169 byteToHex[arr[offset + 9]] + 170 '-' + 171 byteToHex[arr[offset + 10]] + 172 byteToHex[arr[offset + 11]] + 173 byteToHex[arr[offset + 12]] + 174 byteToHex[arr[offset + 13]] + 175 byteToHex[arr[offset + 14]] + 176 byteToHex[arr[offset + 15]]).toLowerCase(); 177} 178 179let getRandomValues; 180const rnds8 = new Uint8Array(16); 181function rng() { 182 if (!getRandomValues) { 183 if (typeof crypto === 'undefined' || !crypto.getRandomValues) { 184 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); 185 } 186 getRandomValues = crypto.getRandomValues.bind(crypto); 187 } 188 return getRandomValues(rnds8); 189} 190 191const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); 192const native = { randomUUID }; 193 194function _v4(options, buf, offset) { 195 options = options || {}; 196 const rnds = options.random ?? options.rng?.() ?? rng(); 197 if (rnds.length < 16) { 198 throw new Error('Random bytes length must be >= 16'); 199 } 200 rnds[6] = (rnds[6] & 0x0f) | 0x40; 201 rnds[8] = (rnds[8] & 0x3f) | 0x80; 202 return unsafeStringify(rnds); 203} 204function v4(options, buf, offset) { 205 if (native.randomUUID && true && !options) { 206 return native.randomUUID(); 207 } 208 return _v4(options); 209} 210 211// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis 212function getGlobal() { 213 if (typeof globalThis !== 'undefined') { 214 return globalThis; 215 } 216 if (typeof self !== 'undefined') { 217 return self; 218 } 219 if (typeof window !== 'undefined') { 220 return window; 221 } 222 if (typeof global !== 'undefined') { 223 return global; 224 } 225} 226function getDevTools() { 227 const w = getGlobal(); 228 if (w.__xstate__) { 229 return w.__xstate__; 230 } 231 return undefined; 232} 233const devToolsAdapter = service => { 234 if (typeof window === 'undefined') { 235 return; 236 } 237 const devTools = getDevTools(); 238 if (devTools) { 239 devTools.register(service); 240 } 241}; 242 243class Mailbox { 244 constructor(_process) { 245 this._process = _process; 246 this._active = false;
vendor: 4,357 bytes, lines 247-420
247 this._current = null; 248 this._last = null; 249 } 250 start() { 251 this._active = true; 252 this.flush(); 253 } 254 clear() { 255 // we can't set _current to null because we might be currently processing 256 // and enqueue following clear shouldn't start processing the enqueued item immediately 257 if (this._current) { 258 this._current.next = null; 259 this._last = this._current; 260 } 261 } 262 enqueue(event) { 263 const enqueued = { 264 value: event, 265 next: null 266 }; 267 if (this._current) { 268 this._last.next = enqueued; 269 this._last = enqueued; 270 return; 271 } 272 this._current = enqueued; 273 this._last = enqueued; 274 if (this._active) { 275 this.flush(); 276 } 277 } 278 flush() { 279 while (this._current) { 280 // atm the given _process is responsible for implementing proper try/catch handling 281 // we assume here that this won't throw in a way that can affect this mailbox 282 const consumed = this._current; 283 this._process(consumed.value); 284 this._current = consumed.next; 285 } 286 this._last = null; 287 } 288} 289 290const STATE_DELIMITER = '.'; 291const TARGETLESS_KEY = ''; 292const NULL_EVENT = ''; 293const STATE_IDENTIFIER$1 = '#'; 294const WILDCARD = '*'; 295const XSTATE_INIT = 'xstate.init'; 296const XSTATE_ERROR = 'xstate.error'; 297const XSTATE_STOP = 'xstate.stop'; 298 299/** 300 * Returns an event that represents an implicit event that is sent after the 301 * specified `delay`. 302 * 303 * @param delayRef The delay in milliseconds 304 * @param id The state node ID where this event is handled 305 */ 306function createAfterEvent(delayRef, id) { 307 return { 308 type: `xstate.after.${delayRef}.${id}` 309 }; 310} 311 312/** 313 * Returns an event that represents that a final state node has been reached in 314 * the parent state node. 315 * 316 * @param id The final state node's parent state node `id` 317 * @param output The data to pass into the event 318 */ 319function createDoneStateEvent(id, output) { 320 return { 321 type: `xstate.done.state.${id}`, 322 output 323 }; 324} 325 326/** 327 * Returns an event that represents that an invoked service has terminated. 328 * 329 * An invoked service is terminated when it has reached a top-level final state 330 * node, but not when it is canceled. 331 * 332 * @param invokeId The invoked service ID 333 * @param output The data to pass into the event 334 */ 335function createDoneActorEvent(invokeId, output) { 336 return { 337 type: `xstate.done.actor.${invokeId}`, 338 output, 339 actorId: invokeId 340 }; 341} 342function createErrorActorEvent(id, error) { 343 return { 344 type: `xstate.error.actor.${id}`, 345 error, 346 actorId: id 347 }; 348} 349function createInitEvent(input) { 350 return { 351 type: XSTATE_INIT, 352 input 353 }; 354} 355 356/** 357 * This function makes sure that unhandled errors are thrown in a separate 358 * macrotask. It allows those errors to be detected by global error handlers and 359 * reported to bug tracking services without interrupting our own stack of 360 * execution. 361 * 362 * @param err Error to be thrown 363 */ 364function reportUnhandledError(err) { 365 setTimeout(() => { 366 throw err; 367 }); 368} 369 370const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')(); 371 372function matchesState(parentStateId, childStateId) { 373 const parentStateValue = toStateValue(parentStateId); 374 const childStateValue = toStateValue(childStateId); 375 if (typeof childStateValue === 'string') { 376 if (typeof parentStateValue === 'string') { 377 return childStateValue === parentStateValue; 378 } 379 380 // Parent more specific than child 381 return false; 382 } 383 if (typeof parentStateValue === 'string') { 384 return parentStateValue in childStateValue; 385 } 386 return Object.keys(parentStateValue).every(key => { 387 if (!(key in childStateValue)) { 388 return false; 389 } 390 return matchesState(parentStateValue[key], childStateValue[key]); 391 }); 392} 393function toStatePath(stateId) { 394 if (isArray(stateId)) { 395 return stateId; 396 } 397 const result = []; 398 let segment = ''; 399 for (let i = 0; i < stateId.length; i++) { 400 const char = stateId.charCodeAt(i); 401 switch (char) { 402 // \ 403 case 92: 404 // consume the next character 405 segment += stateId[i + 1]; 406 // and skip over it 407 i++; 408 continue; 409 // . 410 case 46: 411 result.push(segment); 412 segment = ''; 413 continue; 414 } 415 segment += stateId[i]; 416 } 417 result.push(segment); 418 return result; 419} 420function toStateValue(stateValue) {
vendor: 5,811 bytes, lines 421-619
421 if (isMachineSnapshot(stateValue)) { 422 return stateValue.value; 423 } 424 if (typeof stateValue !== 'string') { 425 return stateValue; 426 } 427 const statePath = toStatePath(stateValue); 428 return pathToStateValue(statePath); 429} 430function pathToStateValue(statePath) { 431 if (statePath.length === 1) { 432 return statePath[0]; 433 } 434 const value = {}; 435 let marker = value; 436 for (let i = 0; i < statePath.length - 1; i++) { 437 if (i === statePath.length - 2) { 438 marker[statePath[i]] = statePath[i + 1]; 439 } else { 440 const previous = marker; 441 marker = {}; 442 previous[statePath[i]] = marker; 443 } 444 } 445 return value; 446} 447function mapValues(collection, iteratee) { 448 const result = {}; 449 const collectionKeys = Object.keys(collection); 450 for (let i = 0; i < collectionKeys.length; i++) { 451 const key = collectionKeys[i]; 452 result[key] = iteratee(collection[key], key, collection, i); 453 } 454 return result; 455} 456function toArrayStrict(value) { 457 if (isArray(value)) { 458 return value; 459 } 460 return [value]; 461} 462function toArray(value) { 463 if (value === undefined) { 464 return []; 465 } 466 return toArrayStrict(value); 467} 468function resolveOutput(mapper, context, event, self) { 469 if (typeof mapper === 'function') { 470 return mapper({ 471 context, 472 event, 473 self 474 }); 475 } 476 return mapper; 477} 478function isArray(value) { 479 return Array.isArray(value); 480} 481function isErrorActorEvent(event) { 482 return event.type.startsWith('xstate.error.actor'); 483} 484function toTransitionConfigArray(configLike) { 485 return toArrayStrict(configLike).map(transitionLike => { 486 if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') { 487 return { 488 target: transitionLike 489 }; 490 } 491 return transitionLike; 492 }); 493} 494function normalizeTarget(target) { 495 if (target === undefined || target === TARGETLESS_KEY) { 496 return undefined; 497 } 498 return toArray(target); 499} 500function toObserver(nextHandler, errorHandler, completionHandler) { 501 const isObserver = typeof nextHandler === 'object'; 502 const self = isObserver ? nextHandler : undefined; 503 return { 504 next: (isObserver ? nextHandler.next : nextHandler)?.bind(self), 505 error: (isObserver ? nextHandler.error : errorHandler)?.bind(self), 506 complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self) 507 }; 508} 509function createInvokeId(stateNodeId, index) { 510 return `${index}.${stateNodeId}`; 511} 512function resolveReferencedActor(machine, src) { 513 const match = src.match(/^xstate\.invoke\.(\d+)\.(.*)/); 514 if (!match) { 515 return machine.implementations.actors[src]; 516 } 517 const [, indexStr, nodeId] = match; 518 const node = machine.getStateNodeById(nodeId); 519 const invokeConfig = node.config.invoke; 520 return (Array.isArray(invokeConfig) ? invokeConfig[indexStr] : invokeConfig).src; 521} 522 523/** 524 * Checks if an event type matches an event descriptor, supporting wildcards. 525 * Event descriptors can be: 526 * 527 * - Exact matches: "event.type" 528 * - Wildcard: "*" 529 * - Partial matches: "event.*" 530 * 531 * @param eventType - The actual event type string 532 * @param descriptor - The event descriptor to match against 533 * @returns True if the event type matches the descriptor 534 */ 535function matchesEventDescriptor(eventType, descriptor) { 536 if (descriptor === eventType) { 537 return true; 538 } 539 if (descriptor === WILDCARD) { 540 return true; 541 } 542 if (!descriptor.endsWith('.*')) { 543 return false; 544 } 545 const partialEventTokens = descriptor.split('.'); 546 const eventTokens = eventType.split('.'); 547 for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) { 548 const partialEventToken = partialEventTokens[tokenIndex]; 549 const eventToken = eventTokens[tokenIndex]; 550 if (partialEventToken === '*') { 551 const isLastToken = tokenIndex === partialEventTokens.length - 1; 552 return isLastToken; 553 } 554 if (partialEventToken !== eventToken) { 555 return false; 556 } 557 } 558 return true; 559} 560 561function createScheduledEventId(actorRef, id) { 562 return `${actorRef.sessionId}.${id}`; 563} 564let idCounter = 0; 565function createSystem(rootActor, options) { 566 const children = new Map(); 567 const keyedActors = new Map(); 568 const reverseKeyedActors = new WeakMap(); 569 const inspectionObservers = new Set(); 570 const timerMap = {}; 571 const { 572 clock, 573 logger 574 } = options; 575 const scheduler = { 576 schedule: (source, target, event, delay, id = Math.random().toString(36).slice(2)) => { 577 const scheduledEvent = { 578 source, 579 target, 580 event, 581 delay, 582 id, 583 startedAt: Date.now() 584 }; 585 const scheduledEventId = createScheduledEventId(source, id); 586 system._snapshot._scheduledEvents[scheduledEventId] = scheduledEvent; 587 const timeout = clock.setTimeout(() => { 588 delete timerMap[scheduledEventId]; 589 delete system._snapshot._scheduledEvents[scheduledEventId]; 590 system._relay(source, target, event); 591 }, delay); 592 timerMap[scheduledEventId] = timeout; 593 }, 594 cancel: (source, id) => { 595 const scheduledEventId = createScheduledEventId(source, id); 596 const timeout = timerMap[scheduledEventId]; 597 delete timerMap[scheduledEventId]; 598 delete system._snapshot._scheduledEvents[scheduledEventId]; 599 if (timeout !== undefined) { 600 clock.clearTimeout(timeout); 601 } 602 }, 603 cancelAll: actorRef => { 604 for (const scheduledEventId in system._snapshot._scheduledEvents) { 605 const scheduledEvent = system._snapshot._scheduledEvents[scheduledEventId]; 606 if (scheduledEvent.source === actorRef) { 607 scheduler.cancel(actorRef, scheduledEvent.id); 608 } 609 } 610 } 611 }; 612 const sendInspectionEvent = event => { 613 if (!inspectionObservers.size) { 614 return; 615 } 616 const resolvedInspectionEvent = { 617 ...event, 618 rootId: rootActor.sessionId 619 };
vendor: 8,496 bytes, lines 620-897
620 inspectionObservers.forEach(observer => observer.next?.(resolvedInspectionEvent)); 621 }; 622 const system = { 623 _snapshot: { 624 _scheduledEvents: (options?.snapshot && options.snapshot.scheduler) ?? {} 625 }, 626 _bookId: () => `x:${idCounter++}`, 627 _register: (sessionId, actorRef) => { 628 children.set(sessionId, actorRef); 629 return sessionId; 630 }, 631 _unregister: actorRef => { 632 children.delete(actorRef.sessionId); 633 const systemId = reverseKeyedActors.get(actorRef); 634 if (systemId !== undefined) { 635 keyedActors.delete(systemId); 636 reverseKeyedActors.delete(actorRef); 637 } 638 }, 639 get: systemId => { 640 return keyedActors.get(systemId); 641 }, 642 getAll: () => { 643 return Object.fromEntries(keyedActors.entries()); 644 }, 645 _set: (systemId, actorRef) => { 646 const existing = keyedActors.get(systemId); 647 if (existing && existing !== actorRef) { 648 throw new Error(`Actor with system ID '${systemId}' already exists.`); 649 } 650 keyedActors.set(systemId, actorRef); 651 reverseKeyedActors.set(actorRef, systemId); 652 }, 653 inspect: observerOrFn => { 654 const observer = toObserver(observerOrFn); 655 inspectionObservers.add(observer); 656 return { 657 unsubscribe() { 658 inspectionObservers.delete(observer); 659 } 660 }; 661 }, 662 _sendInspectionEvent: sendInspectionEvent, 663 _relay: (source, target, event) => { 664 system._sendInspectionEvent({ 665 type: '@xstate.event', 666 sourceRef: source, 667 actorRef: target, 668 event 669 }); 670 target._send(event); 671 }, 672 scheduler, 673 getSnapshot: () => { 674 return { 675 _scheduledEvents: { 676 ...system._snapshot._scheduledEvents 677 } 678 }; 679 }, 680 start: () => { 681 const scheduledEvents = system._snapshot._scheduledEvents; 682 system._snapshot._scheduledEvents = {}; 683 for (const scheduledId in scheduledEvents) { 684 const { 685 source, 686 target, 687 event, 688 delay, 689 id 690 } = scheduledEvents[scheduledId]; 691 scheduler.schedule(source, target, event, delay, id); 692 } 693 }, 694 _clock: clock, 695 _logger: logger 696 }; 697 return system; 698} 699 700// those are needed to make JSDoc `@link` work properly 701 702let executingCustomAction = false; 703const $$ACTOR_TYPE = 1; 704 705// those values are currently used by @xstate/react directly so it's important to keep the assigned values in sync 706let ProcessingStatus = /*#__PURE__*/function (ProcessingStatus) { 707 ProcessingStatus[ProcessingStatus["NotStarted"] = 0] = "NotStarted"; 708 ProcessingStatus[ProcessingStatus["Running"] = 1] = "Running"; 709 ProcessingStatus[ProcessingStatus["Stopped"] = 2] = "Stopped"; 710 return ProcessingStatus; 711}({}); 712const defaultOptions = { 713 clock: { 714 setTimeout: (fn, ms) => { 715 return setTimeout(fn, ms); 716 }, 717 clearTimeout: id => { 718 return clearTimeout(id); 719 } 720 }, 721 logger: console.log.bind(console), 722 devTools: false 723}; 724 725/** 726 * An Actor is a running process that can receive events, send events and change 727 * its behavior based on the events it receives, which can cause effects outside 728 * of the actor. When you run a state machine, it becomes an actor. 729 */ 730class Actor { 731 /** 732 * Creates a new actor instance for the given logic with the provided options, 733 * if any. 734 * 735 * @param logic The logic to create an actor from 736 * @param options Actor options 737 */ 738 constructor(logic, options) { 739 this.logic = logic; 740 /** The current internal state of the actor. */ 741 this._snapshot = void 0; 742 /** 743 * The clock that is responsible for setting and clearing timeouts, such as 744 * delayed events and transitions. 745 */ 746 this.clock = void 0; 747 this.options = void 0; 748 /** The unique identifier for this actor relative to its parent. */ 749 this.id = void 0; 750 this.mailbox = new Mailbox(this._process.bind(this)); 751 this.observers = new Set(); 752 this.eventListeners = new Map(); 753 this.logger = void 0; 754 /** @internal */ 755 this._processingStatus = ProcessingStatus.NotStarted; 756 // Actor Ref 757 this._parent = void 0; 758 /** @internal */ 759 this._syncSnapshot = void 0; 760 this.ref = void 0; 761 // TODO: add typings for system 762 this._actorScope = void 0; 763 this.systemId = void 0; 764 /** The globally unique process ID for this invocation. */ 765 this.sessionId = void 0; 766 /** The system to which this actor belongs. */ 767 this.system = void 0; 768 this._doneEvent = void 0; 769 this.src = void 0; 770 // array of functions to defer 771 this._deferred = []; 772 const resolvedOptions = { 773 ...defaultOptions, 774 ...options 775 }; 776 const { 777 clock, 778 logger, 779 parent, 780 syncSnapshot, 781 id, 782 systemId, 783 inspect 784 } = resolvedOptions; 785 this.system = parent ? parent.system : createSystem(this, { 786 clock, 787 logger 788 }); 789 if (inspect && !parent) { 790 // Always inspect at the system-level 791 this.system.inspect(toObserver(inspect)); 792 } 793 this.sessionId = this.system._bookId(); 794 this.id = id ?? this.sessionId; 795 this.logger = options?.logger ?? this.system._logger; 796 this.clock = options?.clock ?? this.system._clock; 797 this._parent = parent; 798 this._syncSnapshot = syncSnapshot; 799 this.options = resolvedOptions; 800 this.src = resolvedOptions.src ?? logic; 801 this.ref = this; 802 this._actorScope = { 803 self: this, 804 id: this.id, 805 sessionId: this.sessionId, 806 logger: this.logger, 807 defer: fn => { 808 this._deferred.push(fn); 809 }, 810 system: this.system, 811 stopChild: child => { 812 if (child._parent !== this) { 813 throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`); 814 } 815 child._stop(); 816 }, 817 emit: emittedEvent => { 818 const listeners = this.eventListeners.get(emittedEvent.type); 819 const wildcardListener = this.eventListeners.get('*'); 820 if (!listeners && !wildcardListener) { 821 return; 822 } 823 const allListeners = [...(listeners ? listeners.values() : []), ...(wildcardListener ? wildcardListener.values() : [])]; 824 for (const handler of allListeners) { 825 try { 826 handler(emittedEvent); 827 } catch (err) { 828 reportUnhandledError(err); 829 } 830 } 831 }, 832 actionExecutor: action => { 833 const exec = () => { 834 this._actorScope.system._sendInspectionEvent({ 835 type: '@xstate.action', 836 actorRef: this, 837 action: { 838 type: action.type, 839 params: action.params 840 } 841 }); 842 if (!action.exec) { 843 return; 844 } 845 const saveExecutingCustomAction = executingCustomAction; 846 try { 847 executingCustomAction = true; 848 action.exec(action.info, action.params); 849 } finally { 850 executingCustomAction = saveExecutingCustomAction; 851 } 852 }; 853 if (this._processingStatus === ProcessingStatus.Running) { 854 exec(); 855 } else { 856 this._deferred.push(exec); 857 } 858 } 859 }; 860 861 // Ensure that the send method is bound to this Actor instance 862 // if destructured 863 this.send = this.send.bind(this); 864 this.system._sendInspectionEvent({ 865 type: '@xstate.actor', 866 actorRef: this 867 }); 868 if (systemId) { 869 this.systemId = systemId; 870 this.system._set(systemId, this); 871 } 872 this._initState(options?.snapshot ?? options?.state); 873 if (systemId && this._snapshot.status !== 'active') { 874 this.system._unregister(this); 875 } 876 } 877 _initState(persistedState) { 878 try { 879 this._snapshot = persistedState ? this.logic.restoreSnapshot ? this.logic.restoreSnapshot(persistedState, this._actorScope) : persistedState : this.logic.getInitialSnapshot(this._actorScope, this.options?.input); 880 } catch (err) { 881 // if we get here then it means that we assign a value to this._snapshot that is not of the correct type 882 // we can't get the true `TSnapshot & { status: 'error'; }`, it's impossible 883 // so right now this is a lie of sorts 884 this._snapshot = { 885 status: 'error', 886 output: undefined, 887 error: err 888 }; 889 } 890 } 891 update(snapshot, event) { 892 // Update state 893 this._snapshot = snapshot; 894 895 // Execute deferred effects 896 let deferredFn; 897 while (deferredFn = this._deferred.shift()) {
vendor: 5,064 bytes, lines 898-1069
898 try { 899 deferredFn(); 900 } catch (err) { 901 // this error can only be caught when executing *initial* actions 902 // it's the only time when we call actions provided by the user through those deferreds 903 // when the actor is already running we always execute them synchronously while transitioning 904 // no "builtin deferred" should actually throw an error since they are either safe 905 // or the control flow is passed through the mailbox and errors should be caught by the `_process` used by the mailbox 906 this._deferred.length = 0; 907 this._snapshot = { 908 ...snapshot, 909 status: 'error', 910 error: err 911 }; 912 } 913 } 914 switch (this._snapshot.status) { 915 case 'active': 916 for (const observer of this.observers) { 917 try { 918 observer.next?.(snapshot); 919 } catch (err) { 920 reportUnhandledError(err); 921 } 922 } 923 break; 924 case 'done': 925 // next observers are meant to be notified about done snapshots 926 // this can be seen as something that is different from how observable work 927 // but with observables `complete` callback is called without any arguments 928 // it's more ergonomic for XState to treat a done snapshot as a "next" value 929 // and the completion event as something that is separate, 930 // something that merely follows emitting that done snapshot 931 for (const observer of this.observers) { 932 try { 933 observer.next?.(snapshot); 934 } catch (err) { 935 reportUnhandledError(err); 936 } 937 } 938 this._stopProcedure(); 939 this._complete(); 940 this._doneEvent = createDoneActorEvent(this.id, this._snapshot.output); 941 if (this._parent) { 942 this.system._relay(this, this._parent, this._doneEvent); 943 } 944 break; 945 case 'error': 946 this._error(this._snapshot.error); 947 break; 948 } 949 this.system._sendInspectionEvent({ 950 type: '@xstate.snapshot', 951 actorRef: this, 952 event, 953 snapshot 954 }); 955 } 956 957 /** 958 * Subscribe an observer to an actorâs snapshot values. 959 * 960 * @remarks 961 * The observer will receive the actorâs snapshot value when it is emitted. 962 * The observer can be: 963 * 964 * - A plain function that receives the latest snapshot, or 965 * - An observer object whose `.next(snapshot)` method receives the latest 966 * snapshot 967 * 968 * @example 969 * 970 * ```ts 971 * // Observer as a plain function 972 * const subscription = actor.subscribe((snapshot) => { 973 * console.log(snapshot); 974 * }); 975 * ``` 976 * 977 * @example 978 * 979 * ```ts 980 * // Observer as an object 981 * const subscription = actor.subscribe({ 982 * next(snapshot) { 983 * console.log(snapshot); 984 * }, 985 * error(err) { 986 * // ... 987 * }, 988 * complete() { 989 * // ... 990 * } 991 * }); 992 * ``` 993 * 994 * The return value of `actor.subscribe(observer)` is a subscription object 995 * that has an `.unsubscribe()` method. You can call 996 * `subscription.unsubscribe()` to unsubscribe the observer: 997 * 998 * @example 999 * 1000 * ```ts 1001 * const subscription = actor.subscribe((snapshot) => { 1002 * // ... 1003 * }); 1004 * 1005 * // Unsubscribe the observer 1006 * subscription.unsubscribe(); 1007 * ``` 1008 * 1009 * When the actor is stopped, all of its observers will automatically be 1010 * unsubscribed. 1011 * 1012 * @param observer - Either a plain function that receives the latest 1013 * snapshot, or an observer object whose `.next(snapshot)` method receives 1014 * the latest snapshot 1015 */ 1016 1017 subscribe(nextListenerOrObserver, errorListener, completeListener) { 1018 const observer = toObserver(nextListenerOrObserver, errorListener, completeListener); 1019 if (this._processingStatus !== ProcessingStatus.Stopped) { 1020 this.observers.add(observer); 1021 } else { 1022 switch (this._snapshot.status) { 1023 case 'done': 1024 try { 1025 observer.complete?.(); 1026 } catch (err) { 1027 reportUnhandledError(err); 1028 } 1029 break; 1030 case 'error': 1031 { 1032 const err = this._snapshot.error; 1033 if (!observer.error) { 1034 reportUnhandledError(err); 1035 } else { 1036 try { 1037 observer.error(err); 1038 } catch (err) { 1039 reportUnhandledError(err); 1040 } 1041 } 1042 break; 1043 } 1044 } 1045 } 1046 return { 1047 unsubscribe: () => { 1048 this.observers.delete(observer); 1049 } 1050 }; 1051 } 1052 on(type, handler) { 1053 let listeners = this.eventListeners.get(type); 1054 if (!listeners) { 1055 listeners = new Set(); 1056 this.eventListeners.set(type, listeners); 1057 } 1058 const wrappedHandler = handler.bind(undefined); 1059 listeners.add(wrappedHandler); 1060 return { 1061 unsubscribe: () => { 1062 listeners.delete(wrappedHandler); 1063 } 1064 }; 1065 } 1066 1067 /** Starts the Actor from the initial state */ 1068 start() { 1069 if (this._processingStatus === ProcessingStatus.Running) {
vendor: 4,508 bytes, lines 1070-1235
1070 // Do not restart the service if it is already started 1071 return this; 1072 } 1073 if (this._syncSnapshot) { 1074 this.subscribe({ 1075 next: snapshot => { 1076 if (snapshot.status === 'active') { 1077 this.system._relay(this, this._parent, { 1078 type: `xstate.snapshot.${this.id}`, 1079 snapshot 1080 }); 1081 } 1082 }, 1083 error: () => {} 1084 }); 1085 } 1086 this.system._register(this.sessionId, this); 1087 if (this.systemId) { 1088 this.system._set(this.systemId, this); 1089 } 1090 this._processingStatus = ProcessingStatus.Running; 1091 1092 // TODO: this isn't correct when rehydrating 1093 const initEvent = createInitEvent(this.options.input); 1094 this.system._sendInspectionEvent({ 1095 type: '@xstate.event', 1096 sourceRef: this._parent, 1097 actorRef: this, 1098 event: initEvent 1099 }); 1100 const status = this._snapshot.status; 1101 switch (status) { 1102 case 'done': 1103 // a state machine can be "done" upon initialization (it could reach a final state using initial microsteps) 1104 // we still need to complete observers, flush deferreds etc 1105 this.update(this._snapshot, initEvent); 1106 // TODO: rethink cleanup of observers, mailbox, etc 1107 return this; 1108 case 'error': 1109 this._error(this._snapshot.error); 1110 return this; 1111 } 1112 if (!this._parent) { 1113 this.system.start(); 1114 } 1115 if (this.logic.start) { 1116 try { 1117 this.logic.start(this._snapshot, this._actorScope); 1118 } catch (err) { 1119 this._snapshot = { 1120 ...this._snapshot, 1121 status: 'error', 1122 error: err 1123 }; 1124 this._error(err); 1125 return this; 1126 } 1127 } 1128 1129 // TODO: this notifies all subscribers but usually this is redundant 1130 // there is no real change happening here 1131 // we need to rethink if this needs to be refactored 1132 this.update(this._snapshot, initEvent); 1133 if (this.options.devTools) { 1134 this.attachDevTools(); 1135 } 1136 this.mailbox.start(); 1137 return this; 1138 } 1139 _process(event) { 1140 let nextState; 1141 let caughtError; 1142 try { 1143 nextState = this.logic.transition(this._snapshot, event, this._actorScope); 1144 } catch (err) { 1145 // we wrap it in a box so we can rethrow it later even if falsy value gets caught here 1146 caughtError = { 1147 err 1148 }; 1149 } 1150 if (caughtError) { 1151 const { 1152 err 1153 } = caughtError; 1154 this._snapshot = { 1155 ...this._snapshot, 1156 status: 'error', 1157 error: err 1158 }; 1159 this._error(err); 1160 return; 1161 } 1162 this.update(nextState, event); 1163 if (event.type === XSTATE_STOP) { 1164 this._stopProcedure(); 1165 this._complete(); 1166 } 1167 } 1168 _stop() { 1169 if (this._processingStatus === ProcessingStatus.Stopped) { 1170 return this; 1171 } 1172 this.mailbox.clear(); 1173 if (this._processingStatus === ProcessingStatus.NotStarted) { 1174 this._processingStatus = ProcessingStatus.Stopped; 1175 return this; 1176 } 1177 this.mailbox.enqueue({ 1178 type: XSTATE_STOP 1179 }); 1180 return this; 1181 } 1182 1183 /** Stops the Actor and unsubscribe all listeners. */ 1184 stop() { 1185 if (this._parent) { 1186 throw new Error('A non-root actor cannot be stopped directly.'); 1187 } 1188 return this._stop(); 1189 } 1190 _complete() { 1191 for (const observer of this.observers) { 1192 try { 1193 observer.complete?.(); 1194 } catch (err) { 1195 reportUnhandledError(err); 1196 } 1197 } 1198 this.observers.clear(); 1199 this.eventListeners.clear(); 1200 } 1201 _reportError(err) { 1202 if (!this.observers.size) { 1203 if (!this._parent) { 1204 reportUnhandledError(err); 1205 } 1206 this.eventListeners.clear(); 1207 return; 1208 } 1209 let reportError = false; 1210 for (const observer of this.observers) { 1211 const errorListener = observer.error; 1212 reportError ||= !errorListener; 1213 try { 1214 errorListener?.(err); 1215 } catch (err2) { 1216 reportUnhandledError(err2); 1217 } 1218 } 1219 this.observers.clear(); 1220 this.eventListeners.clear(); 1221 if (reportError) { 1222 reportUnhandledError(err); 1223 } 1224 } 1225 _error(err) { 1226 this._stopProcedure(); 1227 this._reportError(err); 1228 if (this._parent) { 1229 this.system._relay(this, this._parent, createErrorActorEvent(this.id, err)); 1230 } 1231 } 1232 // TODO: atm children don't belong entirely to the actor so 1233 // in a way - it's not even super aware of them 1234 // so we can't stop them from here but we really should! 1235 // right now, they are being stopped within the machine's transition
vendor: 16,204 bytes, lines 1236-1772
1236 // but that could throw and leave us with "orphaned" active actors 1237 _stopProcedure() { 1238 if (this._processingStatus !== ProcessingStatus.Running) { 1239 // Actor already stopped; do nothing 1240 return this; 1241 } 1242 1243 // Cancel all delayed events 1244 this.system.scheduler.cancelAll(this); 1245 1246 // TODO: mailbox.reset 1247 this.mailbox.clear(); 1248 // TODO: after `stop` we must prepare ourselves for receiving events again 1249 // events sent *after* stop signal must be queued 1250 // it seems like this should be the common behavior for all of our consumers 1251 // so perhaps this should be unified somehow for all of them 1252 this.mailbox = new Mailbox(this._process.bind(this)); 1253 this._processingStatus = ProcessingStatus.Stopped; 1254 this.system._unregister(this); 1255 return this; 1256 } 1257 1258 /** @internal */ 1259 _send(event) { 1260 if (this._processingStatus === ProcessingStatus.Stopped) { 1261 return; 1262 } 1263 this.mailbox.enqueue(event); 1264 } 1265 1266 /** 1267 * Sends an event to the running Actor to trigger a transition. 1268 * 1269 * @param event The event to send 1270 */ 1271 send(event) { 1272 this.system._relay(undefined, this, event); 1273 } 1274 attachDevTools() { 1275 const { 1276 devTools 1277 } = this.options; 1278 if (devTools) { 1279 const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter; 1280 resolvedDevToolsAdapter(this); 1281 } 1282 } 1283 toJSON() { 1284 return { 1285 xstate$$type: $$ACTOR_TYPE, 1286 id: this.id 1287 }; 1288 } 1289 1290 /** 1291 * Obtain the internal state of the actor, which can be persisted. 1292 * 1293 * @remarks 1294 * The internal state can be persisted from any actor, not only machines. 1295 * 1296 * Note that the persisted state is not the same as the snapshot from 1297 * {@link Actor.getSnapshot}. Persisted state represents the internal state of 1298 * the actor, while snapshots represent the actor's last emitted value. 1299 * 1300 * Can be restored with {@link ActorOptions.state} 1301 * @see https://stately.ai/docs/persistence 1302 */ 1303 1304 getPersistedSnapshot(options) { 1305 return this.logic.getPersistedSnapshot(this._snapshot, options); 1306 } 1307 [symbolObservable]() { 1308 return this; 1309 } 1310 1311 /** 1312 * Read an actorâs snapshot synchronously. 1313 * 1314 * @remarks 1315 * The snapshot represent an actor's last emitted value. 1316 * 1317 * When an actor receives an event, its internal state may change. An actor 1318 * may emit a snapshot when a state transition occurs. 1319 * 1320 * Note that some actors, such as callback actors generated with 1321 * `fromCallback`, will not emit snapshots. 1322 * @see {@link Actor.subscribe} to subscribe to an actorâs snapshot values. 1323 * @see {@link Actor.getPersistedSnapshot} to persist the internal state of an actor (which is more than just a snapshot). 1324 */ 1325 getSnapshot() { 1326 return this._snapshot; 1327 } 1328} 1329/** 1330 * Creates a new actor instance for the given actor logic with the provided 1331 * options, if any. 1332 * 1333 * @remarks 1334 * When you create an actor from actor logic via `createActor(logic)`, you 1335 * implicitly create an actor system where the created actor is the root actor. 1336 * Any actors spawned from this root actor and its descendants are part of that 1337 * actor system. 1338 * @example 1339 * 1340 * ```ts 1341 * import { createActor } from 'xstate'; 1342 * import { someActorLogic } from './someActorLogic.ts'; 1343 * 1344 * // Creating the actor, which implicitly creates an actor system with itself as the root actor 1345 * const actor = createActor(someActorLogic); 1346 * 1347 * actor.subscribe((snapshot) => { 1348 * console.log(snapshot); 1349 * }); 1350 * 1351 * // Actors must be started by calling `actor.start()`, which will also start the actor system. 1352 * actor.start(); 1353 * 1354 * // Actors can receive events 1355 * actor.send({ type: 'someEvent' }); 1356 * 1357 * // You can stop root actors by calling `actor.stop()`, which will also stop the actor system and all actors in that system. 1358 * actor.stop(); 1359 * ``` 1360 * 1361 * @param logic - The actor logic to create an actor from. For a state machine 1362 * actor logic creator, see {@link createMachine}. Other actor logic creators 1363 * include {@link fromCallback}, {@link fromEventObservable}, 1364 * {@link fromObservable}, {@link fromPromise}, and {@link fromTransition}. 1365 * @param options - Actor options 1366 */ 1367function createActor(logic, ...[options]) { 1368 return new Actor(logic, options); 1369} 1370 1371/** 1372 * @deprecated Use `Actor` instead. 1373 * @alias 1374 */ 1375 1376function resolveCancel(_, snapshot, actionArgs, actionParams, { 1377 sendId 1378}) { 1379 const resolvedSendId = typeof sendId === 'function' ? sendId(actionArgs, actionParams) : sendId; 1380 return [snapshot, { 1381 sendId: resolvedSendId 1382 }, undefined]; 1383} 1384function executeCancel(actorScope, params) { 1385 actorScope.defer(() => { 1386 actorScope.system.scheduler.cancel(actorScope.self, params.sendId); 1387 }); 1388} 1389/** 1390 * Cancels a delayed `sendTo(...)` action that is waiting to be executed. The 1391 * canceled `sendTo(...)` action will not send its event or execute, unless the 1392 * `delay` has already elapsed before `cancel(...)` is called. 1393 * 1394 * @example 1395 * 1396 * ```ts 1397 * import { createMachine, sendTo, cancel } from 'xstate'; 1398 * 1399 * const machine = createMachine({ 1400 * // ... 1401 * on: { 1402 * sendEvent: { 1403 * actions: sendTo( 1404 * 'some-actor', 1405 * { type: 'someEvent' }, 1406 * { 1407 * id: 'some-id', 1408 * delay: 1000 1409 * } 1410 * ) 1411 * }, 1412 * cancelEvent: { 1413 * actions: cancel('some-id') 1414 * } 1415 * } 1416 * }); 1417 * ``` 1418 * 1419 * @param sendId The `id` of the `sendTo(...)` action to cancel. 1420 */ 1421function cancel(sendId) { 1422 function cancel(_args, _params) { 1423 } 1424 cancel.type = 'xstate.cancel'; 1425 cancel.sendId = sendId; 1426 cancel.resolve = resolveCancel; 1427 cancel.execute = executeCancel; 1428 return cancel; 1429} 1430 1431function resolveSpawn(actorScope, snapshot, actionArgs, _actionParams, { 1432 id, 1433 systemId, 1434 src, 1435 input, 1436 syncSnapshot 1437}) { 1438 const logic = typeof src === 'string' ? resolveReferencedActor(snapshot.machine, src) : src; 1439 const resolvedId = typeof id === 'function' ? id(actionArgs) : id; 1440 let actorRef; 1441 let resolvedInput = undefined; 1442 if (logic) { 1443 resolvedInput = typeof input === 'function' ? input({ 1444 context: snapshot.context, 1445 event: actionArgs.event, 1446 self: actorScope.self 1447 }) : input; 1448 actorRef = createActor(logic, { 1449 id: resolvedId, 1450 src, 1451 parent: actorScope.self, 1452 syncSnapshot, 1453 systemId, 1454 input: resolvedInput 1455 }); 1456 } 1457 return [cloneMachineSnapshot(snapshot, { 1458 children: { 1459 ...snapshot.children, 1460 [resolvedId]: actorRef 1461 } 1462 }), { 1463 id, 1464 systemId, 1465 actorRef, 1466 src, 1467 input: resolvedInput 1468 }, undefined]; 1469} 1470function executeSpawn(actorScope, { 1471 actorRef 1472}) { 1473 if (!actorRef) { 1474 return; 1475 } 1476 actorScope.defer(() => { 1477 if (actorRef._processingStatus === ProcessingStatus.Stopped) { 1478 return; 1479 } 1480 actorRef.start(); 1481 }); 1482} 1483function spawnChild(...[src, { 1484 id, 1485 systemId, 1486 input, 1487 syncSnapshot = false 1488} = {}]) { 1489 function spawnChild(_args, _params) { 1490 } 1491 spawnChild.type = 'xstate.spawnChild'; 1492 spawnChild.id = id; 1493 spawnChild.systemId = systemId; 1494 spawnChild.src = src; 1495 spawnChild.input = input; 1496 spawnChild.syncSnapshot = syncSnapshot; 1497 spawnChild.resolve = resolveSpawn; 1498 spawnChild.execute = executeSpawn; 1499 return spawnChild; 1500} 1501 1502function resolveStop(_, snapshot, args, actionParams, { 1503 actorRef 1504}) { 1505 const actorRefOrString = typeof actorRef === 'function' ? actorRef(args, actionParams) : actorRef; 1506 const resolvedActorRef = typeof actorRefOrString === 'string' ? snapshot.children[actorRefOrString] : actorRefOrString; 1507 let children = snapshot.children; 1508 if (resolvedActorRef) { 1509 children = { 1510 ...children 1511 }; 1512 delete children[resolvedActorRef.id]; 1513 } 1514 return [cloneMachineSnapshot(snapshot, { 1515 children 1516 }), resolvedActorRef, undefined]; 1517} 1518function unregisterRecursively(actorScope, actorRef) { 1519 // unregister children first (depth-first) 1520 const snapshot = actorRef.getSnapshot(); 1521 if (snapshot && 'children' in snapshot) { 1522 for (const child of Object.values(snapshot.children)) { 1523 unregisterRecursively(actorScope, child); 1524 } 1525 } 1526 actorScope.system._unregister(actorRef); 1527} 1528function executeStop(actorScope, actorRef) { 1529 if (!actorRef) { 1530 return; 1531 } 1532 1533 // we need to eagerly unregister it here so a new actor with the same systemId can be registered immediately 1534 // since we defer actual stopping of the actor but we don't defer actor creations (and we can't do that) 1535 // this could throw on `systemId` collision, for example, when dealing with reentering transitions 1536 // we also need to recursively unregister all nested children's systemIds 1537 unregisterRecursively(actorScope, actorRef); 1538 1539 // this allows us to prevent an actor from being started if it gets stopped within the same macrostep 1540 // this can happen, for example, when the invoking state is being exited immediately by an always transition 1541 if (actorRef._processingStatus !== ProcessingStatus.Running) { 1542 actorScope.stopChild(actorRef); 1543 return; 1544 } 1545 // stopping a child enqueues a stop event in the child actor's mailbox 1546 // we need for all of the already enqueued events to be processed before we stop the child 1547 // the parent itself might want to send some events to a child (for example from exit actions on the invoking state) 1548 // and we don't want to ignore those events 1549 actorScope.defer(() => { 1550 actorScope.stopChild(actorRef); 1551 }); 1552} 1553/** 1554 * Stops a child actor. 1555 * 1556 * @param actorRef The actor to stop. 1557 */ 1558function stopChild(actorRef) { 1559 function stop(_args, _params) { 1560 } 1561 stop.type = 'xstate.stopChild'; 1562 stop.actorRef = actorRef; 1563 stop.resolve = resolveStop; 1564 stop.execute = executeStop; 1565 return stop; 1566} 1567 1568// TODO: throw on cycles (depth check should be enough) 1569function evaluateGuard(guard, context, event, snapshot) { 1570 const { 1571 machine 1572 } = snapshot; 1573 const isInline = typeof guard === 'function'; 1574 const resolved = isInline ? guard : machine.implementations.guards[typeof guard === 'string' ? guard : guard.type]; 1575 if (!isInline && !resolved) { 1576 throw new Error(`Guard '${typeof guard === 'string' ? guard : guard.type}' is not implemented.'.`); 1577 } 1578 if (typeof resolved !== 'function') { 1579 return evaluateGuard(resolved, context, event, snapshot); 1580 } 1581 const guardArgs = { 1582 context, 1583 event 1584 }; 1585 const guardParams = isInline || typeof guard === 'string' ? undefined : 'params' in guard ? typeof guard.params === 'function' ? guard.params({ 1586 context, 1587 event 1588 }) : guard.params : undefined; 1589 if (!('check' in resolved)) { 1590 // the existing type of `.guards` assumes non-nullable `TExpressionGuard` 1591 // inline guards expect `TExpressionGuard` to be set to `undefined` 1592 // it's fine to cast this here, our logic makes sure that we call those 2 "variants" correctly 1593 return resolved(guardArgs, guardParams); 1594 } 1595 const builtinGuard = resolved; 1596 return builtinGuard.check(snapshot, guardArgs, resolved // this holds all params 1597 ); 1598} 1599 1600function isAtomicStateNode(stateNode) { 1601 return stateNode.type === 'atomic' || stateNode.type === 'final'; 1602} 1603function getChildren(stateNode) { 1604 return Object.values(stateNode.states).filter(sn => sn.type !== 'history'); 1605} 1606function getProperAncestors(stateNode, toStateNode) { 1607 const ancestors = []; 1608 if (toStateNode === stateNode) { 1609 return ancestors; 1610 } 1611 1612 // add all ancestors 1613 let m = stateNode.parent; 1614 while (m && m !== toStateNode) { 1615 ancestors.push(m); 1616 m = m.parent; 1617 } 1618 return ancestors; 1619} 1620function getAllStateNodes(stateNodes) { 1621 const nodeSet = new Set(stateNodes); 1622 const adjList = getAdjList(nodeSet); 1623 1624 // add descendants 1625 for (const s of nodeSet) { 1626 // if previously active, add existing child nodes 1627 if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) { 1628 getInitialStateNodesWithTheirAncestors(s).forEach(sn => nodeSet.add(sn)); 1629 } else { 1630 if (s.type === 'parallel') { 1631 for (const child of getChildren(s)) { 1632 if (child.type === 'history') { 1633 continue; 1634 } 1635 if (!nodeSet.has(child)) { 1636 const initialStates = getInitialStateNodesWithTheirAncestors(child); 1637 for (const initialStateNode of initialStates) { 1638 nodeSet.add(initialStateNode); 1639 } 1640 } 1641 } 1642 } 1643 } 1644 } 1645 1646 // add all ancestors 1647 for (const s of nodeSet) { 1648 let m = s.parent; 1649 while (m) { 1650 nodeSet.add(m); 1651 m = m.parent; 1652 } 1653 } 1654 return nodeSet; 1655} 1656function getValueFromAdj(baseNode, adjList) { 1657 const childStateNodes = adjList.get(baseNode); 1658 if (!childStateNodes) { 1659 return {}; // todo: fix? 1660 } 1661 if (baseNode.type === 'compound') { 1662 const childStateNode = childStateNodes[0]; 1663 if (childStateNode) { 1664 if (isAtomicStateNode(childStateNode)) { 1665 return childStateNode.key; 1666 } 1667 } else { 1668 return {}; 1669 } 1670 } 1671 const stateValue = {}; 1672 for (const childStateNode of childStateNodes) { 1673 stateValue[childStateNode.key] = getValueFromAdj(childStateNode, adjList); 1674 } 1675 return stateValue; 1676} 1677function getAdjList(stateNodes) { 1678 const adjList = new Map(); 1679 for (const s of stateNodes) { 1680 if (!adjList.has(s)) { 1681 adjList.set(s, []); 1682 } 1683 if (s.parent) { 1684 if (!adjList.has(s.parent)) { 1685 adjList.set(s.parent, []); 1686 } 1687 adjList.get(s.parent).push(s); 1688 } 1689 } 1690 return adjList; 1691} 1692function getStateValue(rootNode, stateNodes) { 1693 const config = getAllStateNodes(stateNodes); 1694 return getValueFromAdj(rootNode, getAdjList(config)); 1695} 1696function isInFinalState(stateNodeSet, stateNode) { 1697 if (stateNode.type === 'compound') { 1698 return getChildren(stateNode).some(s => s.type === 'final' && stateNodeSet.has(s)); 1699 } 1700 if (stateNode.type === 'parallel') { 1701 return getChildren(stateNode).every(sn => isInFinalState(stateNodeSet, sn)); 1702 } 1703 return stateNode.type === 'final'; 1704} 1705const isStateId = str => str[0] === STATE_IDENTIFIER$1; 1706function getCandidates(stateNode, receivedEventType) { 1707 const candidates = stateNode.transitions.get(receivedEventType) || [...stateNode.transitions.keys()].filter(eventDescriptor => matchesEventDescriptor(receivedEventType, eventDescriptor)).sort((a, b) => b.length - a.length).flatMap(key => stateNode.transitions.get(key)); 1708 return candidates; 1709} 1710 1711/** All delayed transitions from the config. */ 1712function getDelayedTransitions(stateNode) { 1713 const afterConfig = stateNode.config.after; 1714 if (!afterConfig) { 1715 return []; 1716 } 1717 const mutateEntryExit = delay => { 1718 const afterEvent = createAfterEvent(delay, stateNode.id); 1719 const eventType = afterEvent.type; 1720 stateNode.entry.push(raise(afterEvent, { 1721 id: eventType, 1722 delay 1723 })); 1724 stateNode.exit.push(cancel(eventType)); 1725 return eventType; 1726 }; 1727 const delayedTransitions = Object.keys(afterConfig).flatMap(delay => { 1728 const configTransition = afterConfig[delay]; 1729 const resolvedTransition = typeof configTransition === 'string' ? { 1730 target: configTransition 1731 } : configTransition; 1732 const resolvedDelay = Number.isNaN(+delay) ? delay : +delay; 1733 const eventType = mutateEntryExit(resolvedDelay); 1734 return toArray(resolvedTransition).map(transition => ({ 1735 ...transition, 1736 event: eventType, 1737 delay: resolvedDelay 1738 })); 1739 }); 1740 return delayedTransitions.map(delayedTransition => { 1741 const { 1742 delay 1743 } = delayedTransition; 1744 return { 1745 ...formatTransition(stateNode, delayedTransition.event, delayedTransition), 1746 delay 1747 }; 1748 }); 1749} 1750function formatTransition(stateNode, descriptor, transitionConfig) { 1751 const normalizedTarget = normalizeTarget(transitionConfig.target); 1752 const reenter = transitionConfig.reenter ?? false; 1753 const target = resolveTarget(stateNode, normalizedTarget); 1754 const transition = { 1755 ...transitionConfig, 1756 actions: toArray(transitionConfig.actions), 1757 guard: transitionConfig.guard, 1758 target, 1759 source: stateNode, 1760 reenter, 1761 eventType: descriptor, 1762 toJSON: () => ({ 1763 ...transition, 1764 source: `#${stateNode.id}`, 1765 target: target ? target.map(t => `#${t.id}`) : undefined 1766 }) 1767 }; 1768 return transition; 1769} 1770function formatTransitions(stateNode) { 1771 const transitions = new Map(); 1772 if (stateNode.config.on) {
1773 for (const descriptor of Object.keys(stateNode.config.on)) { 1774 if (descriptor === NULL_EVENT) { 1775 throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.'); 1776 } 1777 const transitionsConfig = stateNode.config.on[descriptor]; 1778 transitions.set(descriptor, toTransitionConfigArray(transitionsConfig).map(t => formatTransition(stateNode, descriptor, t))); 1779 } 1780 } 1781 if (stateNode.config.onDone) { 1782 const descriptor = `xstate.done.state.${stateNode.id}`; 1783 transitions.set(descriptor, toTransitionConfigArray(stateNode.config.onDone).map(t => formatTransition(stateNode, descriptor, t))); 1784 } 1785 for (const invokeDef of stateNode.invoke) { 1786 if (invokeDef.onDone) { 1787 const descriptor = `xstate.done.actor.${invokeDef.id}`; 1788 transitions.set(descriptor, toTransitionConfigArray(invokeDef.onDone).map(t => formatTransition(stateNode, descriptor, t))); 1789 } 1790 if (invokeDef.onError) { 1791 const descriptor = `xstate.error.actor.${invokeDef.id}`; 1792 transitions.set(descriptor, toTransitionConfigArray(invokeDef.onError).map(t => formatTransition(stateNode, descriptor, t))); 1793 } 1794 if (invokeDef.onSnapshot) { 1795 const descriptor = `xstate.snapshot.${invokeDef.id}`; 1796 transitions.set(descriptor, toTransitionConfigArray(invokeDef.onSnapshot).map(t => formatTransition(stateNode, descriptor, t))); 1797 } 1798 } 1799 for (const delayedTransition of stateNode.after) { 1800 let existing = transitions.get(delayedTransition.eventType); 1801 if (!existing) { 1802 existing = []; 1803 transitions.set(delayedTransition.eventType, existing); 1804 } 1805 existing.push(delayedTransition); 1806 } 1807 return transitions; 1808} 1809 1810/** 1811 * Collects route transitions from all descendants with explicit IDs. Called 1812 * once on the root node to avoid O(N²) repeated traversals. 1813 */ 1814function formatRouteTransitions(rootStateNode) { 1815 const routeTransitions = []; 1816 const collectRoutes = states => { 1817 Object.values(states).forEach(sn => { 1818 if (sn.config.route && sn.config.id) { 1819 const routeId = sn.config.id; 1820 const userGuard = sn.config.route.guard; 1821 const routeGuard = (args, params) => { 1822 if (args.event.to !== `#${routeId}`) { 1823 return false; 1824 } 1825 if (!userGuard) { 1826 return true; 1827 } 1828 if (typeof userGuard === 'function') { 1829 return userGuard(args, params); 1830 } 1831 return true; 1832 }; 1833 const transition = { 1834 ...sn.config.route, 1835 guard: routeGuard, 1836 target: `#${routeId}` 1837 }; 1838 routeTransitions.push(formatTransition(rootStateNode, 'xstate.route', transition)); 1839 } 1840 if (sn.states) { 1841 collectRoutes(sn.states); 1842 } 1843 }); 1844 }; 1845 collectRoutes(rootStateNode.states); 1846 if (routeTransitions.length > 0) { 1847 rootStateNode.transitions.set('xstate.route', routeTransitions); 1848 } 1849} 1850function formatInitialTransition(stateNode, _target) { 1851 const resolvedTarget = typeof _target === 'string' ? stateNode.states[_target] : _target ? stateNode.states[_target.target] : undefined; 1852 if (!resolvedTarget && _target) { 1853 throw new Error( 1854 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-base-to-string 1855 `Initial state node "${_target}" not found on parent state node #${stateNode.id}`); 1856 } 1857 const transition = { 1858 source: stateNode, 1859 actions: !_target || typeof _target === 'string' ? [] : toArray(_target.actions), 1860 eventType: null, 1861 reenter: false, 1862 target: resolvedTarget ? [resolvedTarget] : [], 1863 toJSON: () => ({ 1864 ...transition, 1865 source: `#${stateNode.id}`, 1866 target: resolvedTarget ? [`#${resolvedTarget.id}`] : [] 1867 }) 1868 }; 1869 return transition; 1870} 1871function resolveTarget(stateNode, targets) { 1872 if (targets === undefined) { 1873 // an undefined target signals that the state node should not transition from that state when receiving that event 1874 return undefined; 1875 } 1876 return targets.map(target => { 1877 if (typeof target !== 'string') { 1878 return target; 1879 } 1880 if (isStateId(target)) { 1881 return stateNode.machine.getStateNodeById(target); 1882 } 1883 const isInternalTarget = target[0] === STATE_DELIMITER; 1884 // If internal target is defined on machine, 1885 // do not include machine key on target 1886 if (isInternalTarget && !stateNode.parent) { 1887 return getStateNodeByPath(stateNode, target.slice(1)); 1888 } 1889 const resolvedTarget = isInternalTarget ? stateNode.key + target : target; 1890 if (stateNode.parent) {
vendor: 11,635 bytes, lines 1891-2239
1891 try { 1892 const targetStateNode = getStateNodeByPath(stateNode.parent, resolvedTarget); 1893 return targetStateNode; 1894 } catch (err) { 1895 throw new Error(`Invalid transition definition for state node '${stateNode.id}':\n${err.message}`); 1896 } 1897 } else { 1898 throw new Error(`Invalid target: "${target}" is not a valid target from the root node. Did you mean ".${target}"?`); 1899 } 1900 }); 1901} 1902function resolveHistoryDefaultTransition(stateNode) { 1903 const normalizedTarget = normalizeTarget(stateNode.config.target); 1904 if (!normalizedTarget) { 1905 return stateNode.parent.initial; 1906 } 1907 return { 1908 target: normalizedTarget.map(t => typeof t === 'string' ? getStateNodeByPath(stateNode.parent, t) : t) 1909 }; 1910} 1911function isHistoryNode(stateNode) { 1912 return stateNode.type === 'history'; 1913} 1914function getInitialStateNodesWithTheirAncestors(stateNode) { 1915 const states = getInitialStateNodes(stateNode); 1916 for (const initialState of states) { 1917 for (const ancestor of getProperAncestors(initialState, stateNode)) { 1918 states.add(ancestor); 1919 } 1920 } 1921 return states; 1922} 1923function getInitialStateNodes(stateNode) { 1924 const set = new Set(); 1925 function iter(descStateNode) { 1926 if (set.has(descStateNode)) { 1927 return; 1928 } 1929 set.add(descStateNode); 1930 if (descStateNode.type === 'compound') { 1931 iter(descStateNode.initial.target[0]); 1932 } else if (descStateNode.type === 'parallel') { 1933 for (const child of getChildren(descStateNode)) { 1934 iter(child); 1935 } 1936 } 1937 } 1938 iter(stateNode); 1939 return set; 1940} 1941/** Returns the child state node from its relative `stateKey`, or throws. */ 1942function getStateNode(stateNode, stateKey) { 1943 if (isStateId(stateKey)) { 1944 return stateNode.machine.getStateNodeById(stateKey); 1945 } 1946 if (!stateNode.states) { 1947 throw new Error(`Unable to retrieve child state '${stateKey}' from '${stateNode.id}'; no child states exist.`); 1948 } 1949 const result = stateNode.states[stateKey]; 1950 if (!result) { 1951 throw new Error(`Child state '${stateKey}' does not exist on '${stateNode.id}'`); 1952 } 1953 return result; 1954} 1955 1956/** 1957 * Returns the relative state node from the given `statePath`, or throws. 1958 * 1959 * @param statePath The string or string array relative path to the state node. 1960 */ 1961function getStateNodeByPath(stateNode, statePath) { 1962 if (typeof statePath === 'string' && isStateId(statePath)) { 1963 try { 1964 return stateNode.machine.getStateNodeById(statePath); 1965 } catch { 1966 // try individual paths 1967 // throw e; 1968 } 1969 } 1970 const arrayStatePath = toStatePath(statePath).slice(); 1971 let currentStateNode = stateNode; 1972 while (arrayStatePath.length) { 1973 const key = arrayStatePath.shift(); 1974 if (!key.length) { 1975 break; 1976 } 1977 currentStateNode = getStateNode(currentStateNode, key); 1978 } 1979 return currentStateNode; 1980} 1981 1982/** 1983 * Returns the state nodes represented by the current state value. 1984 * 1985 * @param stateValue The state value or State instance 1986 */ 1987function getStateNodes(stateNode, stateValue) { 1988 if (typeof stateValue === 'string') { 1989 const childStateNode = stateNode.states[stateValue]; 1990 if (!childStateNode) { 1991 throw new Error(`State '${stateValue}' does not exist on '${stateNode.id}'`); 1992 } 1993 return [stateNode, childStateNode]; 1994 } 1995 const childStateKeys = Object.keys(stateValue); 1996 const childStateNodes = childStateKeys.map(subStateKey => getStateNode(stateNode, subStateKey)).filter(Boolean); 1997 return [stateNode.machine.root, stateNode].concat(childStateNodes, childStateKeys.reduce((allSubStateNodes, subStateKey) => { 1998 const subStateNode = getStateNode(stateNode, subStateKey); 1999 if (!subStateNode) { 2000 return allSubStateNodes; 2001 } 2002 const subStateNodes = getStateNodes(subStateNode, stateValue[subStateKey]); 2003 return allSubStateNodes.concat(subStateNodes); 2004 }, [])); 2005} 2006function transitionAtomicNode(stateNode, stateValue, snapshot, event) { 2007 const childStateNode = getStateNode(stateNode, stateValue); 2008 const next = childStateNode.next(snapshot, event); 2009 if (!next || !next.length) { 2010 return stateNode.next(snapshot, event); 2011 } 2012 return next; 2013} 2014function transitionCompoundNode(stateNode, stateValue, snapshot, event) { 2015 const subStateKeys = Object.keys(stateValue); 2016 const childStateNode = getStateNode(stateNode, subStateKeys[0]); 2017 const next = transitionNode(childStateNode, stateValue[subStateKeys[0]], snapshot, event); 2018 if (!next || !next.length) { 2019 return stateNode.next(snapshot, event); 2020 } 2021 return next; 2022} 2023function transitionParallelNode(stateNode, stateValue, snapshot, event) { 2024 const allInnerTransitions = []; 2025 for (const subStateKey of Object.keys(stateValue)) { 2026 const subStateValue = stateValue[subStateKey]; 2027 if (!subStateValue) { 2028 continue; 2029 } 2030 const subStateNode = getStateNode(stateNode, subStateKey); 2031 const innerTransitions = transitionNode(subStateNode, subStateValue, snapshot, event); 2032 if (innerTransitions) { 2033 allInnerTransitions.push(...innerTransitions); 2034 } 2035 } 2036 if (!allInnerTransitions.length) { 2037 return stateNode.next(snapshot, event); 2038 } 2039 return allInnerTransitions; 2040} 2041function transitionNode(stateNode, stateValue, snapshot, event) { 2042 // leaf node 2043 if (typeof stateValue === 'string') { 2044 return transitionAtomicNode(stateNode, stateValue, snapshot, event); 2045 } 2046 2047 // compound node 2048 if (Object.keys(stateValue).length === 1) { 2049 return transitionCompoundNode(stateNode, stateValue, snapshot, event); 2050 } 2051 2052 // parallel node 2053 return transitionParallelNode(stateNode, stateValue, snapshot, event); 2054} 2055function getHistoryNodes(stateNode) { 2056 return Object.keys(stateNode.states).map(key => stateNode.states[key]).filter(sn => sn.type === 'history'); 2057} 2058function isDescendant(childStateNode, parentStateNode) { 2059 let marker = childStateNode; 2060 while (marker.parent && marker.parent !== parentStateNode) { 2061 marker = marker.parent; 2062 } 2063 return marker.parent === parentStateNode; 2064} 2065function hasIntersection(s1, s2) { 2066 const set1 = new Set(s1); 2067 const set2 = new Set(s2); 2068 for (const item of set1) { 2069 if (set2.has(item)) { 2070 return true; 2071 } 2072 } 2073 for (const item of set2) { 2074 if (set1.has(item)) { 2075 return true; 2076 } 2077 } 2078 return false; 2079} 2080function removeConflictingTransitions(enabledTransitions, stateNodeSet, historyValue) { 2081 const filteredTransitions = new Set(); 2082 for (const t1 of enabledTransitions) { 2083 let t1Preempted = false; 2084 const transitionsToRemove = new Set(); 2085 for (const t2 of filteredTransitions) { 2086 if (hasIntersection(computeExitSet([t1], stateNodeSet, historyValue), computeExitSet([t2], stateNodeSet, historyValue))) { 2087 if (isDescendant(t1.source, t2.source)) { 2088 transitionsToRemove.add(t2); 2089 } else { 2090 t1Preempted = true; 2091 break; 2092 } 2093 } 2094 } 2095 if (!t1Preempted) { 2096 for (const t3 of transitionsToRemove) { 2097 filteredTransitions.delete(t3); 2098 } 2099 filteredTransitions.add(t1); 2100 } 2101 } 2102 return Array.from(filteredTransitions); 2103} 2104function findLeastCommonAncestor(stateNodes) { 2105 const [head, ...tail] = stateNodes; 2106 for (const ancestor of getProperAncestors(head, undefined)) { 2107 if (tail.every(sn => isDescendant(sn, ancestor))) { 2108 return ancestor; 2109 } 2110 } 2111} 2112function getEffectiveTargetStates(transition, historyValue) { 2113 if (!transition.target) { 2114 return []; 2115 } 2116 const targets = new Set(); 2117 for (const targetNode of transition.target) { 2118 if (isHistoryNode(targetNode)) { 2119 if (historyValue[targetNode.id]) { 2120 for (const node of historyValue[targetNode.id]) { 2121 targets.add(node); 2122 } 2123 } else { 2124 for (const node of getEffectiveTargetStates(resolveHistoryDefaultTransition(targetNode), historyValue)) { 2125 targets.add(node); 2126 } 2127 } 2128 } else { 2129 targets.add(targetNode); 2130 } 2131 } 2132 return [...targets]; 2133} 2134function getTransitionDomain(transition, historyValue) { 2135 const targetStates = getEffectiveTargetStates(transition, historyValue); 2136 if (!targetStates) { 2137 return; 2138 } 2139 if (!transition.reenter && targetStates.every(target => target === transition.source || isDescendant(target, transition.source))) { 2140 return transition.source; 2141 } 2142 const lca = findLeastCommonAncestor(targetStates.concat(transition.source)); 2143 if (lca) { 2144 return lca; 2145 } 2146 2147 // at this point we know that it's a root transition since LCA couldn't be found 2148 if (transition.reenter) { 2149 return; 2150 } 2151 return transition.source.machine.root; 2152} 2153function computeExitSet(transitions, stateNodeSet, historyValue) { 2154 const statesToExit = new Set(); 2155 for (const t of transitions) { 2156 if (t.target?.length) { 2157 const domain = getTransitionDomain(t, historyValue); 2158 if (t.reenter && t.source === domain) { 2159 statesToExit.add(domain); 2160 } 2161 for (const stateNode of stateNodeSet) { 2162 if (isDescendant(stateNode, domain)) { 2163 statesToExit.add(stateNode); 2164 } 2165 } 2166 } 2167 } 2168 return [...statesToExit]; 2169} 2170function areStateNodeCollectionsEqual(prevStateNodes, nextStateNodeSet) { 2171 if (prevStateNodes.length !== nextStateNodeSet.size) { 2172 return false; 2173 } 2174 for (const node of prevStateNodes) { 2175 if (!nextStateNodeSet.has(node)) { 2176 return false; 2177 } 2178 } 2179 return true; 2180} 2181function initialMicrostep(root, preInitialState, actorScope, initEvent, internalQueue) { 2182 return microstep([{ 2183 target: [...getInitialStateNodes(root)], 2184 source: root, 2185 reenter: true, 2186 actions: [], 2187 eventType: null, 2188 toJSON: null 2189 }], preInitialState, actorScope, initEvent, true, internalQueue); 2190} 2191 2192/** https://www.w3.org/TR/scxml/#microstepProcedure */ 2193function microstep(transitions, currentSnapshot, actorScope, event, isInitial, internalQueue) { 2194 const actions = []; 2195 if (!transitions.length) { 2196 return [currentSnapshot, actions]; 2197 } 2198 const originalExecutor = actorScope.actionExecutor; 2199 actorScope.actionExecutor = action => { 2200 actions.push(action); 2201 originalExecutor(action); 2202 }; 2203 try { 2204 const mutStateNodeSet = new Set(currentSnapshot._nodes); 2205 let historyValue = currentSnapshot.historyValue; 2206 const filteredTransitions = removeConflictingTransitions(transitions, mutStateNodeSet, historyValue); 2207 let nextState = currentSnapshot; 2208 2209 // Exit states 2210 if (!isInitial) { 2211 [nextState, historyValue] = exitStates(nextState, event, actorScope, filteredTransitions, mutStateNodeSet, historyValue, internalQueue, actorScope.actionExecutor); 2212 } 2213 2214 // Execute transition content 2215 nextState = resolveActionsAndContext(nextState, event, actorScope, filteredTransitions.flatMap(t => t.actions), internalQueue, undefined); 2216 2217 // Enter states 2218 nextState = enterStates(nextState, event, actorScope, filteredTransitions, mutStateNodeSet, internalQueue, historyValue, isInitial); 2219 const nextStateNodes = [...mutStateNodeSet]; 2220 if (nextState.status === 'done') { 2221 nextState = resolveActionsAndContext(nextState, event, actorScope, nextStateNodes.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue, undefined); 2222 } 2223 2224 // eslint-disable-next-line no-useless-catch 2225 try { 2226 if (historyValue === currentSnapshot.historyValue && areStateNodeCollectionsEqual(currentSnapshot._nodes, mutStateNodeSet)) { 2227 return [nextState, actions]; 2228 } 2229 return [cloneMachineSnapshot(nextState, { 2230 _nodes: nextStateNodes, 2231 historyValue 2232 }), actions]; 2233 } catch (e) { 2234 // TODO: Refactor this once proper error handling is implemented. 2235 // See https://github.com/statelyai/rfcs/pull/4 2236 throw e; 2237 } 2238 } finally { 2239 actorScope.actionExecutor = originalExecutor
vendor: 7,491 bytes, lines 2239-2397
2239; 2240 } 2241} 2242function getMachineOutput(snapshot, event, actorScope, rootNode, rootCompletionNode) { 2243 if (rootNode.output === undefined) { 2244 return; 2245 } 2246 const doneStateEvent = createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output !== undefined && rootCompletionNode.parent ? resolveOutput(rootCompletionNode.output, snapshot.context, event, actorScope.self) : undefined); 2247 return resolveOutput(rootNode.output, snapshot.context, doneStateEvent, actorScope.self); 2248} 2249function enterStates(currentSnapshot, event, actorScope, filteredTransitions, mutStateNodeSet, internalQueue, historyValue, isInitial) { 2250 let nextSnapshot = currentSnapshot; 2251 const statesToEnter = new Set(); 2252 // those are states that were directly targeted or indirectly targeted by the explicit target 2253 // in other words, those are states for which initial actions should be executed 2254 // when we target `#deep_child` initial actions of its ancestors shouldn't be executed 2255 const statesForDefaultEntry = new Set(); 2256 computeEntrySet(filteredTransitions, historyValue, statesForDefaultEntry, statesToEnter); 2257 2258 // In the initial state, the root state node is "entered". 2259 if (isInitial) { 2260 statesForDefaultEntry.add(currentSnapshot.machine.root); 2261 } 2262 const completedNodes = new Set(); 2263 for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) { 2264 mutStateNodeSet.add(stateNodeToEnter); 2265 const actions = []; 2266 2267 // Add entry actions 2268 actions.push(...stateNodeToEnter.entry); 2269 for (const invokeDef of stateNodeToEnter.invoke) { 2270 actions.push(spawnChild(invokeDef.src, { 2271 ...invokeDef, 2272 syncSnapshot: !!invokeDef.onSnapshot 2273 })); 2274 } 2275 if (statesForDefaultEntry.has(stateNodeToEnter)) { 2276 const initialActions = stateNodeToEnter.initial.actions; 2277 actions.push(...initialActions); 2278 } 2279 nextSnapshot = resolveActionsAndContext(nextSnapshot, event, actorScope, actions, internalQueue, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id)); 2280 if (stateNodeToEnter.type === 'final') { 2281 const parent = stateNodeToEnter.parent; 2282 let ancestorMarker = parent?.type === 'parallel' ? parent : parent?.parent; 2283 let rootCompletionNode = ancestorMarker || stateNodeToEnter; 2284 if (parent?.type === 'compound') { 2285 internalQueue.push(createDoneStateEvent(parent.id, stateNodeToEnter.output !== undefined ? resolveOutput(stateNodeToEnter.output, nextSnapshot.context, event, actorScope.self) : undefined)); 2286 } 2287 while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutStateNodeSet, ancestorMarker)) { 2288 completedNodes.add(ancestorMarker); 2289 internalQueue.push(createDoneStateEvent(ancestorMarker.id)); 2290 rootCompletionNode = ancestorMarker; 2291 ancestorMarker = ancestorMarker.parent; 2292 } 2293 if (ancestorMarker) { 2294 continue; 2295 } 2296 nextSnapshot = cloneMachineSnapshot(nextSnapshot, { 2297 status: 'done', 2298 output: getMachineOutput(nextSnapshot, event, actorScope, nextSnapshot.machine.root, rootCompletionNode) 2299 }); 2300 } 2301 } 2302 return nextSnapshot; 2303} 2304function computeEntrySet(transitions, historyValue, statesForDefaultEntry, statesToEnter) { 2305 for (const t of transitions) { 2306 const domain = getTransitionDomain(t, historyValue); 2307 for (const s of t.target || []) { 2308 if (!isHistoryNode(s) && ( 2309 // if the target is different than the source then it will *definitely* be entered 2310 t.source !== s || 2311 // we know that the domain can't lie within the source 2312 // if it's different than the source then it's outside of it and it means that the target has to be entered as well 2313 t.source !== domain || 2314 // reentering transitions always enter the target, even if it's the source itself 2315 t.reenter)) { 2316 statesToEnter.add(s); 2317 statesForDefaultEntry.add(s); 2318 } 2319 addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter); 2320 } 2321 const targetStates = getEffectiveTargetStates(t, historyValue); 2322 for (const s of targetStates) { 2323 const ancestors = getProperAncestors(s, domain); 2324 if (domain?.type === 'parallel') { 2325 ancestors.push(domain); 2326 } 2327 addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, ancestors, !t.source.parent && t.reenter ? undefined : domain); 2328 } 2329 } 2330} 2331function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEntry, statesToEnter) { 2332 if (isHistoryNode(stateNode)) { 2333 if (historyValue[stateNode.id]) { 2334 const historyStateNodes = historyValue[stateNode.id]; 2335 for (const s of historyStateNodes) { 2336 statesToEnter.add(s); 2337 addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter); 2338 } 2339 for (const s of historyStateNodes) { 2340 addProperAncestorStatesToEnter(s, stateNode.parent, statesToEnter, historyValue, statesForDefaultEntry); 2341 } 2342 } else { 2343 const historyDefaultTransition = resolveHistoryDefaultTransition(stateNode); 2344 for (const s of historyDefaultTransition.target) { 2345 statesToEnter.add(s); 2346 if (historyDefaultTransition === stateNode.parent?.initial) { 2347 statesForDefaultEntry.add(stateNode.parent); 2348 } 2349 addDescendantStatesToEnter(s, historyValue, statesForDefaultEntry, statesToEnter); 2350 } 2351 for (const s of historyDefaultTransition.target) { 2352 addProperAncestorStatesToEnter(s, stateNode.parent, statesToEnter, historyValue, statesForDefaultEntry); 2353 } 2354 } 2355 } else { 2356 if (stateNode.type === 'compound') { 2357 const [initialState] = stateNode.initial.target; 2358 if (!isHistoryNode(initialState)) { 2359 statesToEnter.add(initialState); 2360 statesForDefaultEntry.add(initialState); 2361 } 2362 addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter); 2363 addProperAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry); 2364 } else { 2365 if (stateNode.type === 'parallel') { 2366 for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) { 2367 if (![...statesToEnter].some(s => isDescendant(s, child))) { 2368 if (!isHistoryNode(child)) { 2369 statesToEnter.add(child); 2370 statesForDefaultEntry.add(child); 2371 } 2372 addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter); 2373 } 2374 } 2375 } 2376 } 2377 } 2378} 2379function addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, ancestors, reentrancyDomain) { 2380 for (const anc of ancestors) { 2381 if (!reentrancyDomain || isDescendant(anc, reentrancyDomain)) { 2382 statesToEnter.add(anc); 2383 } 2384 if (anc.type === 'parallel') { 2385 for (const child of getChildren(anc).filter(sn => !isHistoryNode(sn))) { 2386 if (![...statesToEnter].some(s => isDescendant(s, child))) { 2387 statesToEnter.add(child); 2388 addDescendantStatesToEnter(child, historyValue, statesForDefaultEntry, statesToEnter); 2389 } 2390 } 2391 } 2392 } 2393} 2394function addProperAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, historyValue, statesForDefaultEntry) { 2395 addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, getProperAncestors(stateNode, toStateNode)); 2396} 2397function exitStates(currentSnapshot, event, actorScope, transitions, mutStateNodeSet, historyValue, internalQueue
vendor: 12,354 bytes, lines 2397-2763
2397, _actionExecutor) { 2398 let nextSnapshot = currentSnapshot; 2399 const statesToExit = computeExitSet(transitions, mutStateNodeSet, historyValue); 2400 statesToExit.sort((a, b) => b.order - a.order); 2401 let changedHistory; 2402 2403 // From SCXML algorithm: https://www.w3.org/TR/scxml/#exitStates 2404 for (const exitStateNode of statesToExit) { 2405 for (const historyNode of getHistoryNodes(exitStateNode)) { 2406 let predicate; 2407 if (historyNode.history === 'deep') { 2408 predicate = sn => isAtomicStateNode(sn) && isDescendant(sn, exitStateNode); 2409 } else { 2410 predicate = sn => { 2411 return sn.parent === exitStateNode; 2412 }; 2413 } 2414 changedHistory ??= { 2415 ...historyValue 2416 }; 2417 changedHistory[historyNode.id] = Array.from(mutStateNodeSet).filter(predicate); 2418 } 2419 } 2420 for (const s of statesToExit) { 2421 nextSnapshot = resolveActionsAndContext(nextSnapshot, event, actorScope, [...s.exit, ...s.invoke.map(def => stopChild(def.id))], internalQueue, undefined); 2422 mutStateNodeSet.delete(s); 2423 } 2424 return [nextSnapshot, changedHistory || historyValue]; 2425} 2426function getAction(machine, actionType) { 2427 return machine.implementations.actions[actionType]; 2428} 2429function resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope, actions, extra, retries) { 2430 const { 2431 machine 2432 } = currentSnapshot; 2433 let intermediateSnapshot = currentSnapshot; 2434 for (const action of actions) { 2435 const isInline = typeof action === 'function'; 2436 const resolvedAction = isInline ? action : 2437 // the existing type of `.actions` assumes non-nullable `TExpressionAction` 2438 // it's fine to cast this here to get a common type and lack of errors in the rest of the code 2439 // our logic below makes sure that we call those 2 "variants" correctly 2440 2441 getAction(machine, typeof action === 'string' ? action : action.type); 2442 const actionArgs = { 2443 context: intermediateSnapshot.context, 2444 event, 2445 self: actorScope.self, 2446 system: actorScope.system 2447 }; 2448 const actionParams = isInline || typeof action === 'string' ? undefined : 'params' in action ? typeof action.params === 'function' ? action.params({ 2449 context: intermediateSnapshot.context, 2450 event 2451 }) : action.params : undefined; 2452 if (!resolvedAction || !('resolve' in resolvedAction)) { 2453 actorScope.actionExecutor({ 2454 type: typeof action === 'string' ? action : typeof action === 'object' ? action.type : action.name || '(anonymous)', 2455 info: actionArgs, 2456 params: actionParams, 2457 exec: resolvedAction 2458 }); 2459 continue; 2460 } 2461 const builtinAction = resolvedAction; 2462 const [nextState, params, actions] = builtinAction.resolve(actorScope, intermediateSnapshot, actionArgs, actionParams, resolvedAction, 2463 // this holds all params 2464 extra); 2465 intermediateSnapshot = nextState; 2466 if ('retryResolve' in builtinAction) { 2467 retries?.push([builtinAction, params]); 2468 } 2469 if ('execute' in builtinAction) { 2470 actorScope.actionExecutor({ 2471 type: builtinAction.type, 2472 info: actionArgs, 2473 params, 2474 exec: builtinAction.execute.bind(null, actorScope, params) 2475 }); 2476 } 2477 if (actions) { 2478 intermediateSnapshot = resolveAndExecuteActionsWithContext(intermediateSnapshot, event, actorScope, actions, extra, retries); 2479 } 2480 } 2481 return intermediateSnapshot; 2482} 2483function resolveActionsAndContext(currentSnapshot, event, actorScope, actions, internalQueue, deferredActorIds) { 2484 const retries = deferredActorIds ? [] : undefined; 2485 const nextState = resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope, actions, { 2486 internalQueue, 2487 deferredActorIds 2488 }, retries); 2489 retries?.forEach(([builtinAction, params]) => { 2490 builtinAction.retryResolve(actorScope, nextState, params); 2491 }); 2492 return nextState; 2493} 2494function macrostep(snapshot, event, actorScope, internalQueue) { 2495 let nextSnapshot = snapshot; 2496 const microsteps = []; 2497 function addMicrostep(step, event, transitions) { 2498 actorScope.system._sendInspectionEvent({ 2499 type: '@xstate.microstep', 2500 actorRef: actorScope.self, 2501 event, 2502 snapshot: step[0], 2503 _transitions: transitions 2504 }); 2505 microsteps.push(step); 2506 } 2507 2508 // Handle stop event 2509 if (event.type === XSTATE_STOP) { 2510 nextSnapshot = cloneMachineSnapshot(stopChildren(nextSnapshot, event, actorScope), { 2511 status: 'stopped' 2512 }); 2513 addMicrostep([nextSnapshot, []], event, []); 2514 return { 2515 snapshot: nextSnapshot, 2516 microsteps 2517 }; 2518 } 2519 let nextEvent = event; 2520 2521 // Assume the state is at rest (no raised events) 2522 // Determine the next state based on the next microstep 2523 if (nextEvent.type !== XSTATE_INIT) { 2524 const currentEvent = nextEvent; 2525 const isErr = isErrorActorEvent(currentEvent); 2526 const transitions = selectTransitions(currentEvent, nextSnapshot); 2527 if (isErr && !transitions.length) { 2528 // TODO: we should likely only allow transitions selected by very explicit descriptors 2529 // `*` shouldn't be matched, likely `xstate.error.*` shouldn't be either 2530 // similarly `xstate.error.actor.*` and `xstate.error.actor.todo.*` have to be considered too 2531 nextSnapshot = cloneMachineSnapshot(snapshot, { 2532 status: 'error', 2533 error: currentEvent.error 2534 }); 2535 addMicrostep([nextSnapshot, []], currentEvent, []); 2536 return { 2537 snapshot: nextSnapshot, 2538 microsteps 2539 }; 2540 } 2541 const step = microstep(transitions, snapshot, actorScope, nextEvent, false, 2542 // isInitial 2543 internalQueue); 2544 nextSnapshot = step[0]; 2545 addMicrostep(step, currentEvent, transitions); 2546 } 2547 let shouldSelectEventlessTransitions = true; 2548 while (nextSnapshot.status === 'active') { 2549 let enabledTransitions = shouldSelectEventlessTransitions ? selectEventlessTransitions(nextSnapshot, nextEvent) : []; 2550 2551 // eventless transitions should always be selected after selecting *regular* transitions 2552 // by assigning `undefined` to `previousState` we ensure that `shouldSelectEventlessTransitions` gets always computed to true in such a case 2553 const previousState = enabledTransitions.length ? nextSnapshot : undefined; 2554 if (!enabledTransitions.length) { 2555 if (!internalQueue.length) { 2556 break; 2557 } 2558 nextEvent = internalQueue.shift(); 2559 enabledTransitions = selectTransitions(nextEvent, nextSnapshot); 2560 } 2561 const step = microstep(enabledTransitions, nextSnapshot, actorScope, nextEvent, false, internalQueue); 2562 nextSnapshot = step[0]; 2563 shouldSelectEventlessTransitions = nextSnapshot !== previousState; 2564 addMicrostep(step, nextEvent, enabledTransitions); 2565 } 2566 if (nextSnapshot.status !== 'active') { 2567 stopChildren(nextSnapshot, nextEvent, actorScope); 2568 } 2569 return { 2570 snapshot: nextSnapshot, 2571 microsteps 2572 }; 2573} 2574function stopChildren(nextState, event, actorScope) { 2575 return resolveActionsAndContext(nextState, event, actorScope, Object.values(nextState.children).map(child => stopChild(child)), [], undefined); 2576} 2577function selectTransitions(event, nextState) { 2578 return nextState.machine.getTransitionData(nextState, event); 2579} 2580function selectEventlessTransitions(nextState, event) { 2581 const enabledTransitionSet = new Set(); 2582 const atomicStates = nextState._nodes.filter(isAtomicStateNode); 2583 for (const stateNode of atomicStates) { 2584 loop: for (const s of [stateNode].concat(getProperAncestors(stateNode, undefined))) { 2585 if (!s.always) { 2586 continue; 2587 } 2588 for (const transition of s.always) { 2589 if (transition.guard === undefined || evaluateGuard(transition.guard, nextState.context, event, nextState)) { 2590 enabledTransitionSet.add(transition); 2591 break loop; 2592 } 2593 } 2594 } 2595 } 2596 return removeConflictingTransitions(Array.from(enabledTransitionSet), new Set(nextState._nodes), nextState.historyValue); 2597} 2598 2599/** 2600 * Resolves a partial state value with its full representation in the state 2601 * node's machine. 2602 * 2603 * @param stateValue The partial state value to resolve. 2604 */ 2605function resolveStateValue(rootNode, stateValue) { 2606 const allStateNodes = getAllStateNodes(getStateNodes(rootNode, stateValue)); 2607 return getStateValue(rootNode, [...allStateNodes]); 2608} 2609 2610function isMachineSnapshot(value) { 2611 return !!value && typeof value === 'object' && 'machine' in value && 'value' in value; 2612} 2613const machineSnapshotMatches = function matches(testValue) { 2614 return matchesState(testValue, this.value); 2615}; 2616const machineSnapshotHasTag = function hasTag(tag) { 2617 return this.tags.has(tag); 2618}; 2619const machineSnapshotCan = function can(event) { 2620 const transitionData = this.machine.getTransitionData(this, event); 2621 return !!transitionData?.length && 2622 // Check that at least one transition is not forbidden 2623 transitionData.some(t => t.target !== undefined || t.actions.length); 2624}; 2625const machineSnapshotToJSON = function toJSON() { 2626 const { 2627 _nodes: nodes, 2628 tags, 2629 machine, 2630 getMeta, 2631 toJSON, 2632 can, 2633 hasTag, 2634 matches, 2635 ...jsonValues 2636 } = this; 2637 return { 2638 ...jsonValues, 2639 tags: Array.from(tags) 2640 }; 2641}; 2642const machineSnapshotGetMeta = function getMeta() { 2643 return this._nodes.reduce((acc, stateNode) => { 2644 if (stateNode.meta !== undefined) { 2645 acc[stateNode.id] = stateNode.meta; 2646 } 2647 return acc; 2648 }, {}); 2649}; 2650function createMachineSnapshot(config, machine) { 2651 return { 2652 status: config.status, 2653 output: config.output, 2654 error: config.error, 2655 machine, 2656 context: config.context, 2657 _nodes: config._nodes, 2658 value: getStateValue(machine.root, config._nodes), 2659 tags: new Set(config._nodes.flatMap(sn => sn.tags)), 2660 children: config.children, 2661 historyValue: config.historyValue || {}, 2662 matches: machineSnapshotMatches, 2663 hasTag: machineSnapshotHasTag, 2664 can: machineSnapshotCan, 2665 getMeta: machineSnapshotGetMeta, 2666 toJSON: machineSnapshotToJSON 2667 }; 2668} 2669function cloneMachineSnapshot(snapshot, config = {}) { 2670 return createMachineSnapshot({ 2671 ...snapshot, 2672 ...config 2673 }, snapshot.machine); 2674} 2675function serializeHistoryValue(historyValue) { 2676 if (typeof historyValue !== 'object' || historyValue === null) { 2677 return {}; 2678 } 2679 const result = {}; 2680 for (const key in historyValue) { 2681 const value = historyValue[key]; 2682 if (Array.isArray(value)) { 2683 result[key] = value.map(item => ({ 2684 id: item.id 2685 })); 2686 } 2687 } 2688 return result; 2689} 2690function getPersistedSnapshot(snapshot, options) { 2691 const { 2692 _nodes: nodes, 2693 tags, 2694 machine, 2695 children, 2696 context, 2697 can, 2698 hasTag, 2699 matches, 2700 getMeta, 2701 toJSON, 2702 ...jsonValues 2703 } = snapshot; 2704 const childrenJson = {}; 2705 for (const id in children) { 2706 const child = children[id]; 2707 childrenJson[id] = { 2708 snapshot: child.getPersistedSnapshot(options), 2709 src: child.src, 2710 systemId: child.systemId, 2711 syncSnapshot: child._syncSnapshot 2712 }; 2713 } 2714 const persisted = { 2715 ...jsonValues, 2716 context: persistContext(context), 2717 children: childrenJson, 2718 historyValue: serializeHistoryValue(jsonValues.historyValue) 2719 }; 2720 return persisted; 2721} 2722function persistContext(contextPart) { 2723 let copy; 2724 for (const key in contextPart) { 2725 const value = contextPart[key]; 2726 if (value && typeof value === 'object') { 2727 if ('sessionId' in value && 'send' in value && 'ref' in value) { 2728 copy ??= Array.isArray(contextPart) ? contextPart.slice() : { 2729 ...contextPart 2730 }; 2731 copy[key] = { 2732 xstate$$type: $$ACTOR_TYPE, 2733 id: value.id 2734 }; 2735 } else { 2736 const result = persistContext(value); 2737 if (result !== value) { 2738 copy ??= Array.isArray(contextPart) ? contextPart.slice() : { 2739 ...contextPart 2740 }; 2741 copy[key] = result; 2742 } 2743 } 2744 } 2745 } 2746 return copy ?? contextPart; 2747} 2748 2749function resolveRaise(_, snapshot, args, actionParams, { 2750 event: eventOrExpr, 2751 id, 2752 delay 2753}, { 2754 internalQueue 2755}) { 2756 const delaysMap = snapshot.machine.implementations.delays; 2757 if (typeof eventOrExpr === 'string') { 2758 throw new Error( 2759 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions 2760 `Only event objects may be used with raise; use raise({ type: "${eventOrExpr}" }) instead`); 2761 } 2762 const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args, actionParams) : eventOrExpr; 2763 let resolvedDelay;
2764 if (typeof delay === 'string') { 2765 const configDelay = delaysMap && delaysMap[delay]; 2766 resolvedDelay = typeof configDelay === 'function' ? configDelay(args, actionParams) : configDelay; 2767 } else { 2768 resolvedDelay = typeof delay === 'function' ? delay(args, actionParams) : delay; 2769 } 2770 if (typeof resolvedDelay !== 'number') { 2771 internalQueue.push(resolvedEvent); 2772 } 2773 return [snapshot, { 2774 event: resolvedEvent, 2775 id, 2776 delay: resolvedDelay 2777 }, undefined]; 2778} 2779function executeRaise(actorScope, params) { 2780 const { 2781 event, 2782 delay, 2783 id 2784 } = params; 2785 if (typeof delay === 'number') { 2786 actorScope.defer(() => { 2787 const self = actorScope.self; 2788 actorScope.system.scheduler.schedule(self, self, event, delay, id); 2789 }); 2790 return; 2791 } 2792} 2793/** 2794 * Raises an event. This places the event in the internal event queue, so that 2795 * the event is immediately consumed by the machine in the current step. 2796 * 2797 * @param eventType The event to raise. 2798 */ 2799function raise(eventOrExpr, options) { 2800 function raise(_args, _params) { 2801 } 2802 raise.type = 'xstate.raise'; 2803 raise.event = eventOrExpr; 2804 raise.id = options?.id; 2805 raise.delay = options?.delay; 2806 raise.resolve = resolveRaise; 2807 raise.execute = executeRaise; 2808 return raise; 2809} 2810 2811const XSTATE_OBSERVABLE_ERROR = 'xstate.observable.error'; 2812const XSTATE_OBSERVABLE_COMPLETE = 'xstate.observable.complete'; 2813 2814/** 2815 * Creates event observable logic that listens to an observable that delivers 2816 * event objects. 2817 * 2818 * Event observable actor logic is described by an observable stream of 2819 * {@link https://stately.ai/docs/transitions#event-objects | event objects}. 2820 * Actors created from event observable logic (âevent observable actorsâ) can: 2821 * 2822 * - Implicitly send events to its parent actor 2823 * - Emit snapshots of its emitted event objects 2824 * 2825 * Sending events to event observable actors will have no effect. 2826 * 2827 * @example 2828 * 2829 * ```ts 2830 * import { 2831 * fromEventObservable, 2832 * Subscribable, 2833 * EventObject, 2834 * createMachine, 2835 * createActor 2836 * } from 'xstate'; 2837 * import { fromEvent } from 'rxjs'; 2838 * 2839 * const mouseClickLogic = fromEventObservable( 2840 * () => fromEvent(document.body, 'click') as Subscribable<EventObject> 2841 * ); 2842 * 2843 * const canvasMachine = createMachine({ 2844 * invoke: { 2845 * // Will send mouse `click` events to the canvas actor 2846 * src: mouseClickLogic 2847 * } 2848 * }); 2849 * 2850 * const canvasActor = createActor(canvasMachine); 2851 * canvasActor.start(); 2852 * ``` 2853 * 2854 * @param lazyObservable A function that creates an observable that delivers 2855 * event objects. It receives one argument, an object with the following 2856 * properties: 2857 * 2858 * - `input` - Data that was provided to the event observable actor 2859 * - `self` - The parent actor 2860 * - `system` - The actor system to which the event observable actor belongs. 2861 * 2862 * It should return a {@link Subscribable}, which is compatible with an RxJS 2863 * Observable, although RxJS is not required to create them. 2864 */ 2865function fromEventObservable(lazyObservable) { 2866 // TODO: event types 2867 const logic = { 2868 config: lazyObservable, 2869 transition: (state, event) => { 2870 if (state.status !== 'active') { 2871 return state; 2872 } 2873 switch (event.type) { 2874 case XSTATE_OBSERVABLE_ERROR: 2875 return { 2876 ...state, 2877 status: 'error', 2878 error: event.data, 2879 input: undefined, 2880 _subscription: undefined 2881 }; 2882 case XSTATE_OBSERVABLE_COMPLETE: 2883 return { 2884 ...state, 2885 status: 'done', 2886 input: undefined, 2887 _subscription: undefined 2888 }; 2889 case XSTATE_STOP: 2890 state._subscription.unsubscribe(); 2891 return { 2892 ...state, 2893 status: 'stopped', 2894 input: undefined, 2895 _subscription: undefined 2896 }; 2897 default: 2898 return state; 2899 } 2900 }, 2901 getInitialSnapshot: (_, input) => { 2902 return { 2903 status: 'active', 2904 output: undefined, 2905 error: undefined, 2906 context: undefined, 2907 input, 2908 _subscription: undefined 2909 }; 2910 }, 2911 start: (state, { 2912 self, 2913 system, 2914 emit 2915 }) => { 2916 if (state.status === 'done') {
2917 // Do not restart a completed observable 2918 return; 2919 } 2920 state._subscription = lazyObservable({ 2921 input: state.input, 2922 system, 2923 self, 2924 emit 2925 }).subscribe({ 2926 next: value => { 2927 if (self._parent) { 2928 system._relay(self, self._parent, value); 2929 } 2930 }, 2931 error: err => { 2932 system._relay(self, self, { 2933 type: XSTATE_OBSERVABLE_ERROR, 2934 data: err 2935 }); 2936 }, 2937 complete: () => { 2938 system._relay(self, self, { 2939 type: XSTATE_OBSERVABLE_COMPLETE 2940 }); 2941 } 2942 }); 2943 }, 2944 getPersistedSnapshot: ({ 2945 _subscription, 2946 ...snapshot 2947 }) => snapshot, 2948 restoreSnapshot: snapshot => ({ 2949 ...snapshot, 2950 _subscription: undefined 2951 }) 2952 }; 2953 return logic; 2954} 2955 2956function createSpawner(actorScope, { 2957 machine, 2958 context 2959}, event, spawnedChildren) { 2960 const spawn = (src, options) => { 2961 if (typeof src === 'string') { 2962 const logic = resolveReferencedActor(machine, src); 2963 if (!logic) { 2964 throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`); 2965 } 2966 const actorRef = createActor(logic, { 2967 id: options?.id, 2968 parent: actorScope.self, 2969 syncSnapshot: options?.syncSnapshot, 2970 input: typeof options?.input === 'function' ? options.input({ 2971 context, 2972 event, 2973 self: actorScope.self 2974 }) : options?.input, 2975 src, 2976 systemId: options?.systemId 2977 }); 2978 spawnedChildren[actorRef.id] = actorRef; 2979 return actorRef; 2980 } else { 2981 const actorRef = createActor(src, { 2982 id: options?.id, 2983 parent: actorScope.self, 2984 syncSnapshot: options?.syncSnapshot, 2985 input: options?.input, 2986 src, 2987 systemId: options?.systemId 2988 }); 2989 return actorRef; 2990 } 2991 }; 2992 return (src, options) => { 2993 const actorRef = spawn(src, options); // TODO: fix types 2994 spawnedChildren[actorRef.id] = actorRef; 2995 actorScope.defer(() => { 2996 if (actorRef._processingStatus === ProcessingStatus.Stopped) { 2997 return; 2998 } 2999 actorRef.start(); 3000 }); 3001 return actorRef; 3002 }; 3003} 3004 3005function resolveAssign(actorScope, snapshot, actionArgs, actionParams, { 3006 assignment 3007}) { 3008 if (!snapshot.context) { 3009 throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.'); 3010 } 3011 const spawnedChildren = {}; 3012 const assignArgs = { 3013 context: snapshot.context, 3014 event: actionArgs.event, 3015 spawn: createSpawner(actorScope, snapshot, actionArgs.event, spawnedChildren), 3016 self: actorScope.self, 3017 system: actorScope.system 3018 }; 3019 let partialUpdate = {}; 3020 if (typeof assignment === 'function') { 3021 partialUpdate = assignment(assignArgs, actionParams); 3022 } else { 3023 for (const key of Object.keys(assignment)) { 3024 const propAssignment = assignment[key]; 3025 partialUpdate[key] = typeof propAssignment === 'function' ? propAssignment(assignArgs, actionParams) : propAssignment; 3026 } 3027 } 3028 const updatedContext = Object.assign({}, snapshot.context, partialUpdate); 3029 return [cloneMachineSnapshot(snapshot, { 3030 context: updatedContext, 3031 children: Object.keys(spawnedChildren).length ? { 3032 ...snapshot.children, 3033 ...spawnedChildren 3034 } : snapshot.children 3035 }), undefined, undefined]; 3036} 3037/** 3038 * Updates the current context of the machine. 3039 * 3040 * @example 3041 * 3042 * ```ts 3043 * import { createMachine, assign } from 'xstate'; 3044 * 3045 * const countMachine = createMachine({ 3046 * context: { 3047 * count: 0, 3048 * message: '' 3049 * }, 3050 * on: { 3051 * inc: { 3052 * actions: assign({ 3053 * count: ({ context }) => context.count + 1 3054 * }) 3055 * }, 3056 * updateMessage: { 3057 * actions: assign(({ context, event }) => { 3058 * return { 3059 * message: event.message.trim() 3060 * }; 3061 * }) 3062 * } 3063 * } 3064 * }); 3065 * ``` 3066 * 3067 * @param assignment An object that represents the partial context to update, or 3068 * a function that returns an object that represents the partial context to 3069 * update. 3070 */ 3071function assign(assignment) { 3072 function assign(_args, _params) { 3073 } 3074 assign.type = 'xstate.assign'; 3075 assign.assignment = assignment; 3076 assign.resolve = resolveAssign; 3077 return assign; 3078} 3079 3080const cache = new WeakMap(); 3081function memo(object, key, fn) { 3082 let memoizedData = cache.get(object); 3083 if (!memoizedData) { 3084 memoizedData = { 3085 [key]: fn() 3086 }; 3087 cache.set(object, memoizedData); 3088 } else if (!(key in memoizedData)) { 3089 memoizedData[key] = fn(); 3090 } 3091 return memoizedData[key]; 3092} 3093 3094const EMPTY_OBJECT = {}; 3095const toSerializableAction = action => { 3096 if (typeof action === 'string') { 3097 return { 3098 type: action 3099 }; 3100 } 3101 if (typeof action === 'function') { 3102 if ('resolve' in action) { 3103 return { 3104 type: action.type 3105 }; 3106 } 3107 return { 3108 type: action.name 3109 }; 3110 } 3111 return action; 3112}; 3113class StateNode { 3114 constructor(/** The raw config used to create the machine. */ 3115 config, options) { 3116 this.config = config; 3117 /** 3118 * The relative key of the state node, which represents its location in the 3119 * overall state value. 3120 */ 3121 this.key = void 0; 3122 /** The unique ID of the state node. */ 3123 this.id = void 0; 3124 /** 3125 * The type of this state node: 3126 * 3127 * - `'atomic'` - no child state nodes 3128 * - `'compound'` - nested child state nodes (XOR) 3129 * - `'parallel'` - orthogonal nested child state nodes (AND) 3130 * - `'history'` - history state node 3131 * - `'final'` - final state node 3132 */ 3133 this.type = void 0; 3134 /** The string path from the root machine node to this node. */ 3135 this.path = void 0; 3136 /** The child state nodes. */ 3137 this.states = void 0; 3138 /** 3139 * The type of history on this state node. Can be: 3140 * 3141 * - `'shallow'` - recalls only top-level historical state value 3142 * - `'deep'` - recalls historical state value at all levels 3143 */ 3144 this.history = void 0; 3145 /** The action(s) to be executed upon entering the state node. */ 3146 this.entry = void 0; 3147 /** The action(s) to be executed upon exiting the state node. */ 3148 this.exit = void 0; 3149 /** The parent state node. */ 3150 this.parent = void 0; 3151 /** The root machine node. */ 3152 this.machine = void 0; 3153 /** 3154 * The meta data associated with this state node, which will be returned in 3155 * State instances. 3156 */ 3157 this.meta = void 0; 3158 /** 3159 * The output data sent with the "xstate.done.state._id_" event if this is a 3160 * final state node. 3161 */ 3162 this.output = void 0; 3163 /** 3164 * The order this state node appears. Corresponds to the implicit document 3165 * order. 3166 */ 3167 this.order = -1; 3168 this.description = void 0; 3169 this.tags = []; 3170 this.transitions = void 0; 3171 this.always = void 0; 3172 this.parent = options._parent; 3173 this.key = options._key; 3174 this.machine = options._machine; 3175 this.path = this.parent ? this.parent.path.concat(this.key) : []; 3176 this.id = this.config.id || [this.machine.id, ...this.path].join(STATE_DELIMITER); 3177 this.type = this.config.type || (this.config.states && Object.keys(this.config.states).length ? 'compound' : this.config.history ? 'history' : 'atomic'); 3178 this.description = this.config.description; 3179 this.order = this.machine.idMap.size; 3180 this.machine.idMap.set(this.id, this); 3181 this.states = this.config.states ? mapValues(this.config.states, (stateConfig, key) => { 3182 const stateNode = new StateNode(stateConfig, { 3183 _parent: this, 3184 _key: key, 3185 _machine: this.machine 3186 }); 3187 return stateNode; 3188 }) : EMPTY_OBJECT;
vendor: 4,103 bytes, lines 3189-3318
3189 if (this.type === 'compound' && !this.config.initial) { 3190 throw new Error(`No initial state specified for compound state node "#${this.id}". Try adding { initial: "${Object.keys(this.states)[0]}" } to the state config.`); 3191 } 3192 3193 // History config 3194 this.history = this.config.history === true ? 'shallow' : this.config.history || false; 3195 this.entry = toArray(this.config.entry).slice(); 3196 this.exit = toArray(this.config.exit).slice(); 3197 this.meta = this.config.meta; 3198 this.output = this.type === 'final' || !this.parent ? this.config.output : undefined; 3199 this.tags = toArray(config.tags).slice(); 3200 } 3201 3202 /** @internal */ 3203 _initialize() { 3204 this.transitions = formatTransitions(this); 3205 if (this.config.always) { 3206 this.always = toTransitionConfigArray(this.config.always).map(t => formatTransition(this, NULL_EVENT, t)); 3207 } 3208 Object.keys(this.states).forEach(key => { 3209 this.states[key]._initialize(); 3210 }); 3211 } 3212 3213 /** The well-structured state node definition. */ 3214 get definition() { 3215 return { 3216 id: this.id, 3217 key: this.key, 3218 version: this.machine.version, 3219 type: this.type, 3220 initial: this.initial ? { 3221 target: this.initial.target, 3222 source: this, 3223 actions: this.initial.actions.map(toSerializableAction), 3224 eventType: null, 3225 reenter: false, 3226 toJSON: () => ({ 3227 target: this.initial.target.map(t => `#${t.id}`), 3228 source: `#${this.id}`, 3229 actions: this.initial.actions.map(toSerializableAction), 3230 eventType: null 3231 }) 3232 } : undefined, 3233 history: this.history, 3234 states: mapValues(this.states, state => { 3235 return state.definition; 3236 }), 3237 on: this.on, 3238 transitions: [...this.transitions.values()].flat().map(t => ({ 3239 ...t, 3240 actions: t.actions.map(toSerializableAction) 3241 })), 3242 entry: this.entry.map(toSerializableAction), 3243 exit: this.exit.map(toSerializableAction), 3244 meta: this.meta, 3245 order: this.order || -1, 3246 output: this.output, 3247 invoke: this.invoke, 3248 description: this.description, 3249 tags: this.tags 3250 }; 3251 } 3252 3253 /** @internal */ 3254 toJSON() { 3255 return this.definition; 3256 } 3257 3258 /** The logic invoked as actors by this state node. */ 3259 get invoke() { 3260 return memo(this, 'invoke', () => toArray(this.config.invoke).map((invokeConfig, i) => { 3261 const { 3262 src, 3263 systemId 3264 } = invokeConfig; 3265 const resolvedId = invokeConfig.id ?? createInvokeId(this.id, i); 3266 const sourceName = typeof src === 'string' ? src : `xstate.invoke.${createInvokeId(this.id, i)}`; 3267 return { 3268 ...invokeConfig, 3269 src: sourceName, 3270 id: resolvedId, 3271 systemId: systemId, 3272 toJSON() { 3273 const { 3274 onDone, 3275 onError, 3276 ...invokeDefValues 3277 } = invokeConfig; 3278 return { 3279 ...invokeDefValues, 3280 type: 'xstate.invoke', 3281 src: sourceName, 3282 id: resolvedId 3283 }; 3284 } 3285 }; 3286 })); 3287 } 3288 3289 /** The mapping of events to transitions. */ 3290 get on() { 3291 return memo(this, 'on', () => { 3292 const transitions = this.transitions; 3293 return [...transitions].flatMap(([descriptor, t]) => t.map(t => [descriptor, t])).reduce((map, [descriptor, transition]) => { 3294 map[descriptor] = map[descriptor] || []; 3295 map[descriptor].push(transition); 3296 return map; 3297 }, {}); 3298 }); 3299 } 3300 get after() { 3301 return memo(this, 'delayedTransitions', () => getDelayedTransitions(this)); 3302 } 3303 get initial() { 3304 return memo(this, 'initial', () => formatInitialTransition(this, this.config.initial)); 3305 } 3306 3307 /** @internal */ 3308 next(snapshot, event) { 3309 const eventType = event.type; 3310 const actions = []; 3311 let selectedTransition; 3312 const candidates = memo(this, `candidates-${eventType}`, () => getCandidates(this, eventType)); 3313 for (const candidate of candidates) { 3314 const { 3315 guard 3316 } = candidate; 3317 const resolvedContext = snapshot.context; 3318 let guardPassed = false;
vendor: 6,121 bytes, lines 3319-3518
3319 try { 3320 guardPassed = !guard || evaluateGuard(guard, resolvedContext, event, snapshot); 3321 } catch (err) { 3322 const guardType = typeof guard === 'string' ? guard : typeof guard === 'object' ? guard.type : undefined; 3323 throw new Error(`Unable to evaluate guard ${guardType ? `'${guardType}' ` : ''}in transition for event '${eventType}' in state node '${this.id}':\n${err.message}`); 3324 } 3325 if (guardPassed) { 3326 actions.push(...candidate.actions); 3327 selectedTransition = candidate; 3328 break; 3329 } 3330 } 3331 return selectedTransition ? [selectedTransition] : undefined; 3332 } 3333 3334 /** All the event types accepted by this state node and its descendants. */ 3335 get events() { 3336 return memo(this, 'events', () => { 3337 const { 3338 states 3339 } = this; 3340 const events = new Set(this.ownEvents); 3341 if (states) { 3342 for (const stateId of Object.keys(states)) { 3343 const state = states[stateId]; 3344 if (state.states) { 3345 for (const event of state.events) { 3346 events.add(`${event}`); 3347 } 3348 } 3349 } 3350 } 3351 return Array.from(events); 3352 }); 3353 } 3354 3355 /** 3356 * All the events that have transitions directly from this state node. 3357 * 3358 * Excludes any inert events. 3359 */ 3360 get ownEvents() { 3361 const keys = Object.keys(Object.fromEntries(this.transitions)); 3362 const events = new Set(keys.filter(descriptor => { 3363 return this.transitions.get(descriptor).some(transition => !(!transition.target && !transition.actions.length && !transition.reenter)); 3364 })); 3365 return Array.from(events); 3366 } 3367} 3368 3369const STATE_IDENTIFIER = '#'; 3370class StateMachine { 3371 constructor(/** The raw config used to create the machine. */ 3372 config, implementations) { 3373 this.config = config; 3374 /** The machine's own version. */ 3375 this.version = void 0; 3376 this.schemas = void 0; 3377 this.implementations = void 0; 3378 /** @internal */ 3379 this.__xstatenode = true; 3380 /** @internal */ 3381 this.idMap = new Map(); 3382 this.root = void 0; 3383 this.id = void 0; 3384 this.states = void 0; 3385 this.events = void 0; 3386 this.id = config.id || '(machine)'; 3387 this.implementations = { 3388 actors: implementations?.actors ?? {}, 3389 actions: implementations?.actions ?? {}, 3390 delays: implementations?.delays ?? {}, 3391 guards: implementations?.guards ?? {} 3392 }; 3393 this.version = this.config.version; 3394 this.schemas = this.config.schemas; 3395 this.transition = this.transition.bind(this); 3396 this.getInitialSnapshot = this.getInitialSnapshot.bind(this); 3397 this.getPersistedSnapshot = this.getPersistedSnapshot.bind(this); 3398 this.restoreSnapshot = this.restoreSnapshot.bind(this); 3399 this.start = this.start.bind(this); 3400 this.root = new StateNode(config, { 3401 _key: this.id, 3402 _machine: this 3403 }); 3404 this.root._initialize(); 3405 formatRouteTransitions(this.root); 3406 this.states = this.root.states; // TODO: remove! 3407 this.events = this.root.events; 3408 } 3409 3410 /** 3411 * Clones this state machine with the provided implementations. 3412 * 3413 * @param implementations Options (`actions`, `guards`, `actors`, `delays`) to 3414 * recursively merge with the existing options. 3415 * @returns A new `StateMachine` instance with the provided implementations. 3416 */ 3417 provide(implementations) { 3418 const { 3419 actions, 3420 guards, 3421 actors, 3422 delays 3423 } = this.implementations; 3424 return new StateMachine(this.config, { 3425 actions: { 3426 ...actions, 3427 ...implementations.actions 3428 }, 3429 guards: { 3430 ...guards, 3431 ...implementations.guards 3432 }, 3433 actors: { 3434 ...actors, 3435 ...implementations.actors 3436 }, 3437 delays: { 3438 ...delays, 3439 ...implementations.delays 3440 } 3441 }); 3442 } 3443 resolveState(config) { 3444 const resolvedStateValue = resolveStateValue(this.root, config.value); 3445 const nodeSet = getAllStateNodes(getStateNodes(this.root, resolvedStateValue)); 3446 return createMachineSnapshot({ 3447 _nodes: [...nodeSet], 3448 context: config.context || {}, 3449 children: {}, 3450 status: isInFinalState(nodeSet, this.root) ? 'done' : config.status || 'active', 3451 output: config.output, 3452 error: config.error, 3453 historyValue: config.historyValue 3454 }, this); 3455 } 3456 3457 /** 3458 * Determines the next snapshot given the current `snapshot` and received 3459 * `event`. Calculates a full macrostep from all microsteps. 3460 * 3461 * @param snapshot The current snapshot 3462 * @param event The received event 3463 */ 3464 transition(snapshot, event, actorScope) { 3465 return macrostep(snapshot, event, actorScope, []).snapshot; 3466 } 3467 3468 /** 3469 * Determines the next state given the current `state` and `event`. Calculates 3470 * a microstep. 3471 * 3472 * @param state The current state 3473 * @param event The received event 3474 */ 3475 microstep(snapshot, event, actorScope) { 3476 return macrostep(snapshot, event, actorScope, []).microsteps.map(([s]) => s); 3477 } 3478 getTransitionData(snapshot, event) { 3479 return transitionNode(this.root, snapshot.value, snapshot, event) || []; 3480 } 3481 3482 /** 3483 * The initial state _before_ evaluating any microsteps. This "pre-initial" 3484 * state is provided to initial actions executed in the initial state. 3485 * 3486 * @internal 3487 */ 3488 _getPreInitialState(actorScope, initEvent, internalQueue) { 3489 const { 3490 context 3491 } = this.config; 3492 const preInitial = createMachineSnapshot({ 3493 context: typeof context !== 'function' && context ? context : {}, 3494 _nodes: [this.root], 3495 children: {}, 3496 status: 'active' 3497 }, this); 3498 if (typeof context === 'function') { 3499 const assignment = ({ 3500 spawn, 3501 event, 3502 self 3503 }) => context({ 3504 spawn, 3505 input: event.input, 3506 self 3507 }); 3508 return resolveActionsAndContext(preInitial, initEvent, actorScope, [assign(assignment)], internalQueue, undefined); 3509 } 3510 return preInitial; 3511 } 3512 3513 /** 3514 * Returns the initial `State` instance, with reference to `self` as an 3515 * `ActorRef`. 3516 */ 3517 getInitialSnapshot(actorScope, input) { 3518 const initEvent = createInitEvent(input);
3518 // TODO: fix; 3519 const internalQueue = []; 3520 const preInitialState = this._getPreInitialState(actorScope, initEvent, internalQueue); 3521 const [nextState] = initialMicrostep(this.root, preInitialState, actorScope, initEvent, internalQueue); 3522 const { 3523 snapshot: macroState 3524 } = macrostep(nextState, initEvent, actorScope, internalQueue); 3525 return macroState; 3526 } 3527 start(snapshot) { 3528 Object.values(snapshot.children).forEach(child => { 3529 if (child.getSnapshot().status === 'active') { 3530 child.start(); 3531 } 3532 }); 3533 } 3534 getStateNodeById(stateId) { 3535 const fullPath = toStatePath(stateId); 3536 const relativePath = fullPath.slice(1); 3537 const resolvedStateId = isStateId(fullPath[0]) ? fullPath[0].slice(STATE_IDENTIFIER.length) : fullPath[0]; 3538 const stateNode = this.idMap.get(resolvedStateId); 3539 if (!stateNode) { 3540 throw new Error(`Child state node '#${resolvedStateId}' does not exist on machine '${this.id}'`); 3541 } 3542 return getStateNodeByPath(stateNode, relativePath); 3543 } 3544 get definition() { 3545 return this.root.definition; 3546 } 3547 toJSON() { 3548 return this.definition; 3549 } 3550 getPersistedSnapshot(snapshot, options) { 3551 return getPersistedSnapshot(snapshot, options); 3552 } 3553 restoreSnapshot(snapshot, _actorScope) { 3554 const children = {}; 3555 const snapshotChildren = snapshot.children; 3556 Object.keys(snapshotChildren).forEach(actorId => { 3557 const actorData = snapshotChildren[actorId]; 3558 const childState = actorData.snapshot; 3559 const src = actorData.src; 3560 const logic = typeof src === 'string' ? resolveReferencedActor(this, src) : src; 3561 if (!logic) { 3562 return; 3563 } 3564 const actorRef = createActor(logic, { 3565 id: actorId, 3566 parent: _actorScope.self, 3567 syncSnapshot: actorData.syncSnapshot, 3568 snapshot: childState, 3569 src, 3570 systemId: actorData.systemId 3571 }); 3572 children[actorId] = actorRef; 3573 }); 3574 function resolveHistoryReferencedState(root, referenced) { 3575 if (referenced instanceof StateNode) { 3576 return referenced; 3577 } 3578 try { 3579 return root.machine.getStateNodeById(referenced.id); 3580 } catch { 3581 } 3582 } 3583 function reviveHistoryValue(root, historyValue) { 3584 if (!historyValue || typeof historyValue !== 'object') { 3585 return {}; 3586 } 3587 const revived = {}; 3588 for (const key in historyValue) { 3589 const arr = historyValue[key]; 3590 for (const item of arr) { 3591 const resolved = resolveHistoryReferencedState(root, item); 3592 if (!resolved) { 3593 continue; 3594 } 3595 revived[key] ??= []; 3596 revived[key].push(resolved); 3597 } 3598 } 3599 return revived; 3600 } 3601 const revivedHistoryValue = reviveHistoryValue(this.root, snapshot.historyValue); 3602 const restoredSnapshot = createMachineSnapshot({ 3603 ...snapshot, 3604 children, 3605 _nodes: Array.from(getAllStateNodes(getStateNodes(this.root, snapshot.value))), 3606 historyValue: revivedHistoryValue 3607 }, this); 3608 const seen = new Set(); 3609 function reviveContext(contextPart, children) { 3610 if (seen.has(contextPart)) { 3611 return; 3612 } 3613 seen.add(contextPart); 3614 for (const key in contextPart) { 3615 const value = contextPart[key]; 3616 if (value && typeof value === 'object') { 3617 if ('xstate$$type' in value && value.xstate$$type === $$ACTOR_TYPE) { 3618 contextPart[key] = children[value.id]; 3619 continue; 3620 } 3621 reviveContext(value, children); 3622 } 3623 } 3624 } 3625 reviveContext(restoredSnapshot.context, children); 3626 return restoredSnapshot; 3627 } 3628} 3629 3630function resolveEmit(_, snapshot, args, actionParams, { 3631 event: eventOrExpr 3632}) { 3633 const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args, actionParams) : eventOrExpr; 3634 return [snapshot, { 3635 event: resolvedEvent 3636 }, undefined]; 3637} 3638function executeEmit(actorScope, { 3639 event 3640}) { 3641 actorScope.defer(() => actorScope.emit(event)); 3642} 3643/** 3644 * Emits an event to event handlers registered on the actor via `actor.on(event, 3645 * handler)`. 3646 * 3647 * @example 3648 * 3649 * ```ts 3650 * import { emit } from 'xstate'; 3651 * 3652 * const machine = createMachine({ 3653 * // ... 3654 * on: { 3655 * something: { 3656 * actions: emit({ 3657 * type: 'emitted', 3658 * some: 'data' 3659 * }) 3660 * } 3661 * } 3662 * // ... 3663 * }); 3664 * 3665 * const actor = createActor(machine).start(); 3666 * 3667 * actor.on('emitted', (event) => { 3668 * console.log(event); 3669 * }); 3670 * 3671 * actor.send({ type: 'something' }); 3672 * // logs: 3673 * // { 3674 * // type: 'emitted', 3675 * // some: 'data' 3676 * // } 3677 * ``` 3678 */ 3679function emit(/** The event to emit, or an expression that returns an event to emit. */ 3680eventOrExpr) { 3681 function emit(_args, _params) { 3682 } 3683 emit.type = 'xstate.emit'; 3684 emit.event = eventOrExpr; 3685 emit.resolve = resolveEmit; 3686 emit.execute = executeEmit; 3687 return emit; 3688} 3689 3690// this is needed to make JSDoc `@link` work properly 3691 3692/** 3693 * @remarks 3694 * `T | unknown` reduces to `unknown` and that can be problematic when it comes 3695 * to contextual typing. It especially is a problem when the union has a 3696 * function member, like here: 3697 * 3698 * ```ts 3699 * declare function test( 3700 * cbOrVal: ((arg: number) => unknown) | unknown 3701 * ): void; 3702 * test((arg) => {}); // oops, implicit any 3703 * ``` 3704 * 3705 * This type can be used to avoid this problem. This union represents the same 3706 * value space as `unknown`. 3707 */ 3708 3709// https://github.com/microsoft/TypeScript/issues/23182#issuecomment-379091887 3710 3711// @TODO: we can't use native `NoInfer` as we need those: 3712// https://github.com/microsoft/TypeScript/pull/61092 3713// https://github.com/microsoft/TypeScript/pull/61077 3714// but even with those fixes native NoInfer still doesn't work - further issues have to be reproduced and fixed 3715 3716/** @deprecated Use the built-in `NoInfer` type instead */ 3717 3718/** The full definition of an event, with a string `type`. */ 3719 3720/** 3721 * The string or object representing the state value relative to the parent 3722 * state node. 3723 * 3724 * @remarks 3725 * - For a child atomic state node, this is a string, e.g., `"pending"`. 3726 * - For complex state nodes, this is an object, e.g., `{ success: 3727 * "someChildState" }`. 3728 */ 3729 3730/** @deprecated Use `AnyMachineSnapshot` instead */ 3731 3732// TODO: possibly refactor this somehow, use even a simpler type, and maybe even make `machine.options` private or something 3733/** @ignore */ 3734 3735let SpecialTargets = /*#__PURE__*/function (SpecialTargets) { 3736 SpecialTargets["Parent"] = "#_parent"; 3737 SpecialTargets["Internal"] = "#_internal"; 3738 return SpecialTargets; 3739}({}); 3740 3741/** @deprecated Use `AnyActor` instead. */ 3742 3743// Based on RxJS types 3744 3745// TODO: in v6, this should only accept AnyActorLogic, like ActorRefFromLogic 3746 3747/** @deprecated Use `Actor<T>` instead. */ 3748 3749/** 3750 * Represents logic which can be used by an actor. 3751 * 3752 * @template TSnapshot - The type of the snapshot. 3753 * @template TEvent - The type of the event object. 3754 * @template TInput - The type of the input. 3755 * @template TSystem - The type of the actor system. 3756 */ 3757 3758/** @deprecated */ 3759 3760// TODO: cover all that can be actually returned 3761 3762function resolveSendTo(actorScope, snapshot, args, actionParams, { 3763 to, 3764 event: eventOrExpr, 3765 id, 3766 delay 3767}, extra) { 3768 const delaysMap = snapshot.machine.implementations.delays; 3769 if (typeof eventOrExpr === 'string') { 3770 throw new Error( 3771 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions 3772 `Only event objects may be used with sendTo; use sendTo({ type: "${eventOrExpr}" }) instead`); 3773 } 3774 const resolvedEvent = typeof eventOrExpr === 'function' ? eventOrExpr(args, actionParams) : eventOrExpr; 3775 let resolvedDelay;
vendor: 4,614 bytes, lines 3776-3898
3776 if (typeof delay === 'string') { 3777 const configDelay = delaysMap && delaysMap[delay]; 3778 resolvedDelay = typeof configDelay === 'function' ? configDelay(args, actionParams) : configDelay; 3779 } else { 3780 resolvedDelay = typeof delay === 'function' ? delay(args, actionParams) : delay; 3781 } 3782 const resolvedTarget = typeof to === 'function' ? to(args, actionParams) : to; 3783 let targetActorRef; 3784 if (typeof resolvedTarget === 'string') { 3785 // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison 3786 if (resolvedTarget === SpecialTargets.Parent) { 3787 targetActorRef = actorScope.self._parent; 3788 } 3789 // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison 3790 else if (resolvedTarget === SpecialTargets.Internal) { 3791 targetActorRef = actorScope.self; 3792 } else if (resolvedTarget.startsWith('#_')) { 3793 // SCXML compatibility: https://www.w3.org/TR/scxml/#SCXMLEventProcessor 3794 // #_invokeid. If the target is the special term '#_invokeid', where invokeid is the invokeid of an SCXML session that the sending session has created by <invoke>, the Processor must add the event to the external queue of that session. 3795 targetActorRef = snapshot.children[resolvedTarget.slice(2)]; 3796 } else { 3797 targetActorRef = extra.deferredActorIds?.includes(resolvedTarget) ? resolvedTarget : snapshot.children[resolvedTarget]; 3798 } 3799 if (!targetActorRef) { 3800 throw new Error(`Unable to send event to actor '${resolvedTarget}' from machine '${snapshot.machine.id}'.`); 3801 } 3802 } else { 3803 targetActorRef = resolvedTarget || actorScope.self; 3804 } 3805 return [snapshot, { 3806 to: targetActorRef, 3807 targetId: typeof resolvedTarget === 'string' ? resolvedTarget : undefined, 3808 event: resolvedEvent, 3809 id, 3810 delay: resolvedDelay 3811 }, undefined]; 3812} 3813function retryResolveSendTo(_, snapshot, params) { 3814 if (typeof params.to === 'string') { 3815 params.to = snapshot.children[params.to]; 3816 } 3817} 3818function executeSendTo(actorScope, params) { 3819 // this forms an outgoing events queue 3820 // thanks to that the recipient actors are able to read the *updated* snapshot value of the sender 3821 actorScope.defer(() => { 3822 const { 3823 to, 3824 event, 3825 delay, 3826 id 3827 } = params; 3828 if (typeof delay === 'number') { 3829 actorScope.system.scheduler.schedule(actorScope.self, to, event, delay, id); 3830 return; 3831 } 3832 actorScope.system._relay(actorScope.self, 3833 // at this point, in a deferred task, it should already be mutated by retryResolveSendTo 3834 // if it initially started as a string 3835 to, event.type === XSTATE_ERROR ? createErrorActorEvent(actorScope.self.id, event.data) : event); 3836 }); 3837} 3838/** 3839 * Sends an event to an actor. 3840 * 3841 * @param actor The `ActorRef` to send the event to. 3842 * @param event The event to send, or an expression that evaluates to the event 3843 * to send 3844 * @param options Send action options 3845 * 3846 * - `id` - The unique send event identifier (used with `cancel()`). 3847 * - `delay` - The number of milliseconds to delay the sending of the event. 3848 */ 3849function sendTo(to, eventOrExpr, options) { 3850 function sendTo(_args, _params) { 3851 } 3852 sendTo.type = 'xstate.sendTo'; 3853 sendTo.to = to; 3854 sendTo.event = eventOrExpr; 3855 sendTo.id = options?.id; 3856 sendTo.delay = options?.delay; 3857 sendTo.resolve = resolveSendTo; 3858 sendTo.retryResolve = retryResolveSendTo; 3859 sendTo.execute = executeSendTo; 3860 return sendTo; 3861} 3862 3863/** 3864 * Sends an event to this machine's parent. 3865 * 3866 * @param event The event to send to the parent machine. 3867 * @param options Options to pass into the send event. 3868 */ 3869function sendParent(event, options) { 3870 return sendTo(SpecialTargets.Parent, event, options); 3871} 3872 3873function resolveEnqueueActions(actorScope, snapshot, args, actionParams, { 3874 collect 3875}) { 3876 const actions = []; 3877 const enqueue = function enqueue(action) { 3878 actions.push(action); 3879 }; 3880 enqueue.assign = (...args) => { 3881 actions.push(assign(...args)); 3882 }; 3883 enqueue.cancel = (...args) => { 3884 actions.push(cancel(...args)); 3885 }; 3886 enqueue.raise = (...args) => { 3887 // for some reason it fails to infer `TDelay` from `...args` here and picks its default (`never`) 3888 // then it fails to typecheck that because `...args` use `string` in place of `TDelay` 3889 actions.push(raise(...args)); 3890 }; 3891 enqueue.sendTo = (...args) => { 3892 // for some reason it fails to infer `TDelay` from `...args` here and picks its default (`never`) 3893 // then it fails to typecheck that because `...args` use `string` in place of `TDelay 3894 actions.push(sendTo(...args)); 3895 }; 3896 enqueue.sendParent = (...args) => { 3897 actions.push(sendParent(...args)); 3898 };
3899 enqueue.spawnChild = (...args) => { 3900 actions.push(spawnChild(...args)); 3901 }; 3902 enqueue.stopChild = (...args) => { 3903 actions.push(stopChild(...args)); 3904 }; 3905 enqueue.emit = (...args) => { 3906 actions.push(emit(...args)); 3907 }; 3908 collect({ 3909 context: args.context, 3910 event: args.event, 3911 enqueue, 3912 check: guard => evaluateGuard(guard, snapshot.context, args.event, snapshot), 3913 self: actorScope.self, 3914 system: actorScope.system 3915 }, actionParams); 3916 return [snapshot, undefined, actions]; 3917} 3918/** 3919 * Creates an action object that will execute actions that are queued by the 3920 * `enqueue(action)` function. 3921 * 3922 * @example 3923 * 3924 * ```ts 3925 * import { createMachine, enqueueActions } from 'xstate'; 3926 * 3927 * const machine = createMachine({ 3928 * entry: enqueueActions(({ enqueue, check }) => { 3929 * enqueue.assign({ count: 0 }); 3930 * 3931 * if (check('someGuard')) { 3932 * enqueue.assign({ count: 1 }); 3933 * } 3934 * 3935 * enqueue('someAction'); 3936 * }) 3937 * }); 3938 * ``` 3939 */ 3940function enqueueActions(collect) { 3941 function enqueueActions(_args, _params) { 3942 } 3943 enqueueActions.type = 'xstate.enqueueActions'; 3944 enqueueActions.collect = collect; 3945 enqueueActions.resolve = resolveEnqueueActions; 3946 return enqueueActions; 3947} 3948 3949function resolveLog(_, snapshot, actionArgs, actionParams, { 3950 value, 3951 label 3952}) { 3953 return [snapshot, { 3954 value: typeof value === 'function' ? value(actionArgs, actionParams) : value, 3955 label 3956 }, undefined]; 3957} 3958function executeLog({ 3959 logger 3960}, { 3961 value, 3962 label 3963}) { 3964 if (label) { 3965 logger(label, value); 3966 } else { 3967 logger(value); 3968 } 3969} 3970/** 3971 * @param expr The expression function to evaluate which will be logged. Takes 3972 * in 2 arguments: 3973 * 3974 * - `ctx` - the current state context 3975 * - `event` - the event that caused this action to be executed. 3976 * 3977 * @param label The label to give to the logged expression. 3978 */ 3979function log(value = ({ 3980 context, 3981 event 3982}) => ({ 3983 context, 3984 event 3985}), label) { 3986 function log(_args, _params) { 3987 } 3988 log.type = 'xstate.log'; 3989 log.value = value; 3990 log.label = label; 3991 log.resolve = resolveLog; 3992 log.execute = executeLog; 3993 return log; 3994} 3995 3996/** 3997 * Asserts that the given event object is of the specified type or types. Throws 3998 * an error if the event object is not of the specified types. 3999 * 4000 * @example 4001 * 4002 * ```ts 4003 * // ... 4004 * entry: ({ event }) => { 4005 * assertEvent(event, 'doNothing'); 4006 * // event is { type: 'doNothing' } 4007 * }, 4008 * // ... 4009 * exit: ({ event }) => { 4010 * assertEvent(event, 'greet'); 4011 * // event is { type: 'greet'; message: string } 4012 * 4013 * assertEvent(event, ['greet', 'notify']); 4014 * // event is { type: 'greet'; message: string } 4015 * // or { type: 'notify'; message: string; level: 'info' | 'error' } 4016 * }, 4017 * ``` 4018 */ 4019function assertEvent(event, type) { 4020 const types = toArray(type); 4021 const matches = types.some(descriptor => matchesEventDescriptor(event.type, descriptor)); 4022 if (!matches) { 4023 const typesText = types.length === 1 ? `type matching "${types[0]}"` : `one of types matching "${types.join('", "')}"`; 4024 throw new Error(`Expected event ${JSON.stringify(event)} to have ${typesText}`); 4025 } 4026} 4027 4028/** 4029 * Creates a state machine (statechart) with the given configuration. 4030 * 4031 * The state machine represents the pure logic of a state machine actor. 4032 * 4033 * @example 4034 * 4035 * ```ts 4036 * import { createMachine } from 'xstate'; 4037 * 4038 * const lightMachine = createMachine({ 4039 * id: 'light', 4040 * initial: 'green', 4041 * states: { 4042 * green: { 4043 * on: { 4044 * TIMER: { target: 'yellow' } 4045 * } 4046 * }, 4047 * yellow: { 4048 * on: { 4049 * TIMER: { target: 'red' } 4050 * } 4051 * }, 4052 * red: { 4053 * on: { 4054 * TIMER: { target: 'green' } 4055 * } 4056 * } 4057 * } 4058 * }); 4059 * 4060 * const lightActor = createActor(lightMachine); 4061 * lightActor.start(); 4062 * 4063 * lightActor.send({ type: 'TIMER' }); 4064 * ``` 4065 * 4066 * @param config The state machine configuration. 4067 * @param options DEPRECATED: use `setup({ ... })` or `machine.provide({ ... })` 4068 * to provide machine implementations instead. 4069 */ 4070function createMachine(config, implementations) { 4071 return new StateMachine(config, implementations); 4072} 4073 4074// at the moment we allow extra actors - ones that are not specified by `children` 4075// this could be reconsidered in the future 4076 4077// used to keep only StateSchema relevant keys 4078// this helps with type serialization as it makes the inferred type much shorter when dealing with huge configs 4079 4080function setup({ 4081 schemas, 4082 actors, 4083 actions, 4084 guards, 4085 delays 4086}) { 4087 return { 4088 assign, 4089 sendTo, 4090 raise, 4091 log, 4092 cancel, 4093 stopChild, 4094 enqueueActions, 4095 emit, 4096 spawnChild, 4097 createStateConfig: config => config, 4098 createAction: fn => fn, 4099 createMachine: config => createMachine({ 4100 ...config, 4101 schemas 4102 }, {
4103 actors, 4104 actions, 4105 guards, 4106 delays 4107 }), 4108 extend: extended => setup({ 4109 schemas, 4110 actors, 4111 actions: { 4112 ...actions, 4113 ...extended.actions 4114 }, 4115 guards: { 4116 ...guards, 4117 ...extended.guards 4118 }, 4119 delays: { 4120 ...delays, 4121 ...extended.delays 4122 } 4123 }) 4124 }; 4125} 4126 4127const listenInputFromContext = (config) => ({ 4128 context 4129}) => { 4130 const { count, include, exclude, responseType = "message.received" } = config; 4131 return { 4132 count, 4133 domain: context.domain, 4134 from: context.connectTo, 4135 include: include ? Array.isArray(include) ? include : [include] : [], 4136 exclude: exclude ? Array.isArray(exclude) ? exclude : [exclude] : [], 4137 responseType, 4138 target: context.target, 4139 to: context.name 4140 }; 4141}, listenFilter = (input) => (event) => { 4142 const { data } = event; 4143 return (input.include.length ? input.include.includes(data.type) : true) && (input.exclude.length ? !input.exclude.includes(data.type) : true) && data.domain === input.domain && data.from === input.from && data.to === input.to && (!input.target || event.source === input.target); 4144}, eventToMessage = (type) => (event) => ({ 4145 type, 4146 message: event 4147}), messageEvents$ = defer( 4148 () => fromEvent(window, "message") 4149), createListenLogic = (compatMap) => fromEventObservable(({ input }) => messageEvents$.pipe( 4150 compatMap ? map(compatMap) : pipe(), 4151 filter(listenFilter(input)), 4152 map(eventToMessage(input.responseType)), 4153 input.count ? pipe( 4154 bufferCount(input.count), 4155 concatMap((arr) => arr), 4156 take(input.count) 4157 ) : pipe() 4158)), DOMAIN = "sanity/comlink", RESPONSE_TIMEOUT_DEFAULT = 3e3, FETCH_TIMEOUT_DEFAULT = 1e4, MSG_RESPONSE = "comlink/response", MSG_HEARTBEAT = "comlink/heartbeat", MSG_DISCONNECT = "comlink/disconnect", MSG_HANDSHAKE_SYN = "comlink/handshake/syn", MSG_HANDSHAKE_SYN_ACK = "comlink/handshake/syn-ack", MSG_HANDSHAKE_ACK = "comlink/handshake/ack", throwOnEvent = (message) => (source) => source.pipe( 4159 take(1), 4160 map(() => { 4161 throw new Error(message); 4162 }) 4163), createRequestMachine = () => setup({ 4164 actors: { 4165 listen: fromEventObservable( 4166 ({ 4167 input 4168 }) => { 4169 const abortSignal$ = input.signal ? fromEvent(input.signal, "abort").pipe( 4170 throwOnEvent(`Request ${input.requestId} aborted`) 4171 ) : EMPTY, messageFilter = (event) => event.data?.type === MSG_RESPONSE && event.data?.responseTo === input.requestId && !!event.source && input.sources.has(event.source); 4172 return fromEvent(window, "message").pipe( 4173 filter(messageFilter), 4174 take(input.sources.size), 4175 takeUntil(abortSignal$) 4176 ); 4177 } 4178 ) 4179 }, 4180 actions: { 4181 "send message": ({ context }, params) => { 4182 const { sources, targetOrigin } = context, { message } = params; 4183 sources.forEach((source) => { 4184 source.postMessage(message, { targetOrigin }); 4185 }); 4186 }, 4187 "on success": sendTo( 4188 ({ context }) => context.parentRef, 4189 ({ context, self }) => (context.response && context.resolvable?.resolve(context.response), { 4190 type: "request.success", 4191 requestId: self.id, 4192 response: context.response, 4193 responseTo: context.responseTo 4194 }) 4195 ), 4196 "on fail": sendTo( 4197 ({ context }) => context.parentRef, 4198 ({ context, self }) => (context.suppressWarnings || console.warn( 4199 `[@sanity/comlink] Received no response to message '${context.type}' on client '${context.from}' (ID: '${context.id}').` 4200 ), context.resolvable?.reject(new Error("No response received")), { type: "request.failed", requestId: self.id }) 4201 ), 4202 "on abort": sendTo( 4203 ({ context }) => context.parentRef, 4204 ({ context, self }) => (context.resolvable?.reject(new Error("Request aborted")), { type: "request.aborted", requestId: self.id }) 4205 ) 4206 }, 4207 guards: { 4208 expectsResponse: ({ context }) => context.expectResponse 4209 }, 4210 delays: { 4211 initialTimeout: 0, 4212 responseTimeout: ({ context }) => context.responseTimeout ?? RESPONSE_TIMEOUT_DEFAULT 4213 } 4214}).createMachine({ 4215 /** @xstate-layout N4IgpgJg5mDOIC5QAoC2BDAxgCwJYDswBKAOlwgBswBiAD1gBd0GwT0AzFgJ2QNwdzoKAFVyowAewCuDItTRY8hUuSoBtAAwBdRKAAOE2P1wT8ukLUQBGAEwBWEgBYAnK+eOAzB7sB2DzY8rABoQAE9rDQc3V0cNTw8fAA4NHwBfVJCFHAJiElgwfAgCKGpNHSQQAyMBU3NLBDsrDxI7DTaAjQA2OOcNDxDwhHsNJx9Ou0TOq2cJxP9HdMyMbOU8gqL8ErUrcv1DY1qK+sbm1vaPLp6+gcRnGydo9wDGycWQLKVc9AB3dGNN6jiWCwdAwMrmKoHMxHRCJRKOEiJHwuZKBZwXKzBMKIGyYkhtAkXOweTqOHw2RJvD45Ug-P4CAH0JgsNicMA8LhwAz4fKicTSWTyZafWm-f5QcEVSE1aGgepwhFIlF9aYYrGDC4+JzEppjGzOUkeGbpDIgfASCBwczU5QQ-YyuqIAC0nRuCBd+IJXu9KSpwppZEoYDt1RMsosiEcNjdVjiJEeGisiSTHkcVgWpptuXyhWKIahjqGzi1BqRJINnVcdkcbuTLS9VYC8ISfsUAbp4vzDphCHJIyjBvJNlxNmRNexQ3sJGH43GPj8jWJrZWuXYfyoEC7YcLsbrgRsjkcvkmdgNbopVhIPhVfnsh8ClMz-tWsCkmEwcHgUvt257u8v+6Hse4xnhOdZnImVidPqCRNB4JqpEAA */ 4216 context: ({ input }) => ({ 4217 channelId: input.channelId, 4218 data: input.data, 4219 domain: input.domain, 4220 expectResponse: input.expectResponse ?? false, 4221 from: input.from, 4222 id: `msg-${v4()}`, 4223 parentRef: input.parentRef, 4224 resolvable: input.resolvable, 4225 response: null, 4226 responseTimeout: input.responseTimeout, 4227 responseTo: input.responseTo, 4228 signal: input.signal,
4229 sources: input.sources instanceof Set ? input.sources : /* @__PURE__ */ new Set([input.sources]), 4230 suppressWarnings: input.suppressWarnings, 4231 targetOrigin: input.targetOrigin, 4232 to: input.to, 4233 type: input.type 4234 }), 4235 initial: "idle", 4236 on: { 4237 abort: ".aborted" 4238 }, 4239 states: { 4240 idle: { 4241 after: { 4242 initialTimeout: [ 4243 { 4244 target: "sending" 4245 } 4246 ] 4247 } 4248 }, 4249 sending: { 4250 entry: { 4251 type: "send message", 4252 params: ({ context }) => { 4253 const { channelId, data, domain, from, id, responseTo, to, type } = context; 4254 return { message: { 4255 channelId, 4256 data, 4257 domain, 4258 from, 4259 id, 4260 to, 4261 type, 4262 responseTo 4263 } }; 4264 } 4265 }, 4266 always: [ 4267 { 4268 guard: "expectsResponse", 4269 target: "awaiting" 4270 }, 4271 "success" 4272 ] 4273 }, 4274 awaiting: { 4275 invoke: { 4276 id: "listen for response", 4277 src: "listen", 4278 input: ({ context }) => ({ 4279 requestId: context.id, 4280 sources: context.sources, 4281 signal: context.signal 4282 }), 4283 onError: "aborted" 4284 }, 4285 after: { 4286 responseTimeout: "failed" 4287 }, 4288 on: { 4289 message: { 4290 actions: assign({ 4291 response: ({ event }) => event.data.data, 4292 responseTo: ({ event }) => event.data.responseTo 4293 }), 4294 target: "success" 4295 } 4296 } 4297 }, 4298 failed: { 4299 type: "final", 4300 entry: "on fail" 4301 }, 4302 success: { 4303 type: "final", 4304 entry: "on success" 4305 }, 4306 aborted: { 4307 type: "final", 4308 entry: "on abort" 4309 } 4310 }, 4311 output: ({ context, self }) => ({ 4312 requestId: self.id, 4313 response: context.response, 4314 responseTo: context.responseTo 4315 }) 4316}); 4317function createPromiseWithResolvers() { 4318 if (typeof Promise.withResolvers == "function") 4319 return Promise.withResolvers(); 4320 let resolve, reject; 4321 return { promise: new Promise((res, rej) => { 4322 resolve = res, reject = rej; 4323 }), resolve, reject }; 4324} 4325const createNodeMachine = () => setup({ 4326 actors: { 4327 requestMachine: createRequestMachine(), 4328 listen: createListenLogic() 4329 }, 4330 actions: { 4331 "buffer handshake": assign({ 4332 handshakeBuffer: ({ event, context }) => (assertEvent(event, "message.received"), [...context.handshakeBuffer, event]) 4333 }), 4334 "buffer message": enqueueActions(({ enqueue }) => { 4335 enqueue.assign({ 4336 buffer: ({ event, context }) => (assertEvent(event, "post"), [ 4337 ...context.buffer, 4338 { 4339 data: event.data, 4340 resolvable: event.resolvable, 4341 options: event.options 4342 } 4343 ]) 4344 }), enqueue.emit(({ event }) => (assertEvent(event, "post"), { 4345 type: "buffer.added", 4346 message: event.data 4347 })); 4348 }), 4349 "create request": assign({ 4350 requests: ({ context, event, self, spawn }) => { 4351 assertEvent(event, "request"); 4352 const requests = (Array.isArray(event.data) ? event.data : [event.data]).map((request) => { 4353 const id = `req-${v4()}`; 4354 return spawn("requestMachine", { 4355 id, 4356 input: { 4357 channelId: context.channelId, 4358 data: request.data, 4359 domain: context.domain, 4360 expectResponse: request.expectResponse, 4361 from: context.name, 4362 parentRef: self, 4363 resolvable: request.resolvable, 4364 responseTimeout: request.options?.responseTimeout, 4365 responseTo: request.responseTo, 4366 signal: request.options?.signal, 4367 sources: context.target, 4368 suppressWarnings: request.options?.suppressWarnings, 4369 targetOrigin: context.targetOrigin, 4370 to: context.connectTo, 4371 type: request.type 4372 } 4373 }); 4374 }); 4375 return [...context.requests, ...requests]; 4376 } 4377 }), 4378 "emit heartbeat": emit(() => ({ 4379 type: "heartbeat" 4380 })), 4381 "emit received message": enqueueActions(({ enqueue }) => { 4382 enqueue.emit(({ event }) => (assertEvent(event, "message.received"), { 4383 type: "message", 4384 message: event.message.data 4385 })); 4386 }), 4387 "emit status": emit((_, params) => ({ 4388 type: "status", 4389 status: params.status 4390 })), 4391 "post message": raise(({ event }) => (assertEvent(event, "post"), { 4392 type: "request", 4393 data: { 4394 data: event.data.data, 4395 expectResponse: !!event.resolvable, 4396 type: event.data.type, 4397 resolvable: event.resolvable, 4398 options: event.options 4399 } 4400 })), 4401 "process pending handshakes": enqueueActions(({ context, enqueue }) => { 4402 context.handshakeBuffer.forEach((event) => enqueue.raise(event)), enqueue.assign({ 4403 handshakeBuffer: [] 4404 }); 4405 }), 4406 "remove request": enqueueActions(({ context, enqueue, event }) => { 4407 assertEvent(event, ["request.success", "request.failed", "request.aborted"]), stopChild(event.requestId), enqueue.assign({ requests: context.requests.filter(({ id }) => id !== event.requestId) }); 4408 }), 4409 "send response": raise(({ event }) => (assertEvent(event, ["message.received", "heartbeat.received"]), { 4410 type: "request", 4411 data: { 4412 type: MSG_RESPONSE, 4413 responseTo: event.message.data.id, 4414 data: void 0 4415 } 4416 })), 4417 "send handshake syn ack": raise({ 4418 type: "request", 4419 data: { type: MSG_HANDSHAKE_SYN_ACK } 4420 }), 4421 "send pending messages": enqueueActions(({ enqueue }) => { 4422 enqueue.raise(({ context }) => ({ 4423 type: "request", 4424 data: context.buffer.map(({ data, resolvable, options }) => ({ 4425 data: data.data, 4426 type: data.type, 4427 expectResponse: !!resolvable, 4428 resolvable, 4429 options 4430 })) 4431 })), enqueue.emit(({ context }) => ({ 4432 type: "buffer.flushed", 4433 messages: context.buffer.map(({ data }) => data) 4434 })), enqueue.assign({ 4435 buffer: [] 4436 }); 4437 }), 4438 "set connection config": assign({ 4439 channelId: ({ event }) => (assertEvent(event, "handshake.syn"), event.message.data.channelId), 4440 target: ({ event }) => (assertEvent(event, "handshake.syn"), event.message.source || void 0), 4441 targetOrigin: ({ event }) => (assertEvent(event, "handshake.syn"), event.message.origin) 4442 }) 4443 }, 4444 guards: { 4445 hasSource: ({ context }) => context.target !== null 4446 } 4447}).createMachine({
4448 /** @xstate-layout N4IgpgJg5mDOIC5QDsD2EwGIBOYCOArnAC4B0sBAxpXLANoAMAuoqAA6qwCWxXqyrEAA9EAVgYAWUgEYJDUQA4JAZmUSJC0coDsAGhABPRNIYLSErdOkBOAGzbx227YUBfV-rQYc+IrDIAZgCGXAA2kIwsSCAc3Lz8giIIoiakqgBMDKbp2tYS0srp+kYI0ununuhgpFwQ4ZgQ-NVcyABuqADW1V7NdWAILe2UQfHIkZGCsTx8AtFJ6aKipAzWOtrpC7Z5BUWGiNoK6aS26RLW2tLaqkqqFSA9NX2YALa0QTCkuDRcrRHMk5xpgk5ogJLZSNZIVDoVCFLZiohbIVSLkXLZRHZDgxbHcHrV6rFiBNolNRolEVJbCsdGUzsoyhiEcllOC1DowelVmVrOUPPcqqQABZBZAQWDCjotKANJo1NqdboC4Wi8VBSXIKADeXDUbjf4kwFkkEILbg8RZMHKOzWKzKJkHJa086Xa4qZS4pUisUSqU+QgkYnsQ0zcnJaRLDbpZwKNQSBYspm2MEyC5KTnaDSSd18h7K71q32EwMxYPA0BJFLKY5yZxIrKSURM0RnFHSBTrQqQ9babQejBCr2q9XSiBcWCUfjIMCUIn6oNxEPGtTWFFR0RUy7iGzt+3Ip0XURXVZKPvVCfIKczyB+vyzqLzoGzcuIG0MGTyCztjRtjaJjbHVMNAUTdu1PUhz0vYhryLOcSwXMthBfK0ZGsLQGBZekCi0Jso1IdI23WG04zOE4wIg6coIgBox3Imdi1JRdnxNOxSHNSQkWtW0mTjMxMQ7fDzgcbNKn7WjKJeN4Pi+MAfj+e84MfUMFHbZZwxOHZNDyO09gQOQjmAhZJCM9IMjIycKOvQUwCCbBiAAI2sshpNkiB6NLJ9EIQBQbWOdJlMhYCUjbJkchXGsFmsJQMVsWl3BzKp4GiHoAXgjykgAWmkZZ6xy3LZF2EobCy6xsQWJQ42kE4FjA-EwBSxTjSRUhDgqkzgO2BxdykU4AvXFQ-KjMC8yHKV6qNJi6WOdcypcZsXGxe0JG0XySKjM5lKsMyLwsiAxsYzylDfONznUEqrmi+1ThkHqXDONbULi1wgA */ 4449 id: "node", 4450 context: ({ input }) => ({ 4451 buffer: [], 4452 channelId: null, 4453 connectTo: input.connectTo, 4454 domain: input.domain ?? DOMAIN, 4455 handshakeBuffer: [], 4456 name: input.name, 4457 requests: [], 4458 target: void 0, 4459 targetOrigin: null 4460 }), 4461 // Always listen for handshake syn messages. The channel could have 4462 // disconnected without being able to notify the node, and so need to 4463 // re-establish the connection. 4464 invoke: { 4465 id: "listen for handshake syn", 4466 src: "listen", 4467 input: listenInputFromContext({ 4468 include: MSG_HANDSHAKE_SYN, 4469 responseType: "handshake.syn" 4470 }) 4471 }, 4472 on: { 4473 "request.success": { 4474 actions: "remove request" 4475 }, 4476 "request.failed": { 4477 actions: "remove request" 4478 }, 4479 "request.aborted": { 4480 actions: "remove request" 4481 }, 4482 "handshake.syn": { 4483 actions: "set connection config", 4484 target: ".handshaking" 4485 } 4486 }, 4487 initial: "idle", 4488 states: { 4489 idle: { 4490 entry: [{ type: "emit status", params: { status: "idle" } }], 4491 on: { 4492 post: { 4493 actions: "buffer message" 4494 } 4495 } 4496 }, 4497 handshaking: { 4498 guard: "hasSource", 4499 entry: ["send handshake syn ack", { type: "emit status", params: { status: "handshaking" } }], 4500 invoke: [ 4501 { 4502 id: "listen for handshake ack", 4503 src: "listen", 4504 input: listenInputFromContext({ 4505 include: MSG_HANDSHAKE_ACK, 4506 count: 1, 4507 // Override the default `message.received` responseType to prevent 4508 // buffering the ack message. We transition to the connected state 4509 // using onDone instead of listening to this event using `on` 4510 responseType: "handshake.complete" 4511 }), 4512 onDone: "connected" 4513 }, 4514 { 4515 id: "listen for disconnect", 4516 src: "listen", 4517 input: listenInputFromContext({ 4518 include: MSG_DISCONNECT, 4519 count: 1, 4520 responseType: "disconnect" 4521 }) 4522 }, 4523 { 4524 id: "listen for messages", 4525 src: "listen", 4526 input: listenInputFromContext({ 4527 exclude: [ 4528 MSG_DISCONNECT, 4529 MSG_HANDSHAKE_SYN, 4530 MSG_HANDSHAKE_ACK, 4531 MSG_HEARTBEAT, 4532 MSG_RESPONSE 4533 ] 4534 }) 4535 } 4536 ], 4537 on: { 4538 request: { 4539 actions: "create request" 4540 }, 4541 post: { 4542 actions: "buffer message" 4543 }, 4544 "message.received": { 4545 actions: "buffer handshake" 4546 }, 4547 disconnect: { 4548 target: "idle" 4549 } 4550 } 4551 }, 4552 connected: { 4553 entry: [ 4554 "process pending handshakes", 4555 "send pending messages", 4556 { type: "emit status", params: { status: "connected" } } 4557 ], 4558 invoke: [ 4559 { 4560 id: "listen for messages", 4561 src: "listen", 4562 input: listenInputFromContext({ 4563 exclude: [ 4564 MSG_DISCONNECT, 4565 MSG_HANDSHAKE_SYN, 4566 MSG_HANDSHAKE_ACK, 4567 MSG_HEARTBEAT, 4568 MSG_RESPONSE 4569 ] 4570 }) 4571 }, 4572 { 4573 id: "listen for heartbeat", 4574 src: "listen", 4575 input: listenInputFromContext({ 4576 include: MSG_HEARTBEAT, 4577 responseType: "heartbeat.received" 4578 }) 4579 }, 4580 { 4581 id: "listen for disconnect", 4582 src: "listen", 4583 input: listenInputFromContext({ 4584 include: MSG_DISCONNECT, 4585 count: 1, 4586 responseType: "disconnect" 4587 }) 4588 } 4589 ], 4590 on: { 4591 request: { 4592 actions: "create request" 4593 }, 4594 post: { 4595 actions: "post message" 4596 }, 4597 disconnect: { 4598 target: "idle" 4599 }, 4600 "message.received": { 4601 actions: ["send response", "emit received message"] 4602 }, 4603 "heartbeat.received": { 4604 actions: ["send response", "emit heartbeat"] 4605 } 4606 } 4607 } 4608 } 4609}), createNode = (input, machine = createNodeMachine()) => { 4610 const actor = createActor(machine, { 4611 input 4612 }), eventHandlers = /* @__PURE__ */ new Map(), unhandledMessages = /* @__PURE__ */ new Map(), on = (type, handler, options) => {
4613 const handlers = eventHandlers.get(type) || /* @__PURE__ */ new Set(); 4614 eventHandlers.has(type) || eventHandlers.set(type, handlers), handlers.add(handler); 4615 const unhandledMessagesForType = unhandledMessages.get(type); 4616 if (unhandledMessagesForType) { 4617 const replayCount = options?.replay ?? 1; 4618 Array.from(unhandledMessagesForType).slice(-replayCount).forEach(({ data }) => handler(data)), unhandledMessages.delete(type); 4619 } 4620 return () => { 4621 handlers.delete(handler); 4622 }; 4623 }; 4624 let cachedStatus; 4625 const onStatus = (handler, filter2) => { 4626 const subscription = actor.on( 4627 "status", 4628 (event) => { 4629 cachedStatus = event.status, !(filter2 && event.status !== filter2) && handler(event.status); 4630 } 4631 ); 4632 return cachedStatus && handler(cachedStatus), () => subscription.unsubscribe(); 4633 }, post = (type, data) => { 4634 const _data = { type, data }; 4635 actor.send({ type: "post", data: _data }); 4636 }, fetch = (type, data, options) => { 4637 const { responseTimeout = FETCH_TIMEOUT_DEFAULT, signal, suppressWarnings } = options || {}, resolvable = createPromiseWithResolvers(), _data = { type, data }; 4638 return actor.send({ 4639 type: "post", 4640 data: _data, 4641 resolvable, 4642 options: { responseTimeout, signal, suppressWarnings } 4643 }), resolvable.promise; 4644 }; 4645 actor.on("message", ({ message }) => { 4646 const handlers = eventHandlers.get(message.type); 4647 if (handlers) { 4648 handlers.forEach((handler) => handler(message.data)); 4649 return; 4650 } 4651 const unhandledMessagesForType = unhandledMessages.get(message.type); 4652 unhandledMessagesForType ? unhandledMessagesForType.add(message) : unhandledMessages.set(message.type, /* @__PURE__ */ new Set([message])); 4653 }); 4654 const stop = () => { 4655 actor.stop(); 4656 }; 4657 return { 4658 actor, 4659 fetch, 4660 machine, 4661 on, 4662 onStatus, 4663 post, 4664 start: () => (actor.start(), stop), 4665 stop 4666 }; 4667}; 4668 4669const channelsToComlinkMap = { 4670 "handshake/syn": MSG_HANDSHAKE_SYN, 4671 "handshake/syn-ack": MSG_HANDSHAKE_SYN_ACK, 4672 "handshake/ack": MSG_HANDSHAKE_ACK, 4673 "channel/response": MSG_RESPONSE, 4674 "channel/heartbeat": MSG_HEARTBEAT, 4675 "channel/disconnect": MSG_DISCONNECT, 4676 "overlay/focus": "visual-editing/focus", 4677 "overlay/navigate": "visual-editing/navigate", 4678 "overlay/toggle": "visual-editing/toggle", 4679 "presentation/toggleOverlay": "presentation/toggle-overlay" 4680}, comlinkToChannelsMap = { 4681 [MSG_HANDSHAKE_SYN]: "handshake/syn", 4682 [MSG_HANDSHAKE_SYN_ACK]: "handshake/syn-ack", 4683 [MSG_HANDSHAKE_ACK]: "handshake/ack", 4684 [MSG_RESPONSE]: "channel/response", 4685 [MSG_HEARTBEAT]: "channel/heartbeat", 4686 [MSG_DISCONNECT]: "channel/disconnect", 4687 "visual-editing/focus": "overlay/focus", 4688 "visual-editing/navigate": "overlay/navigate", 4689 "visual-editing/toggle": "overlay/toggle", 4690 "presentation/toggle-overlay": "presentation/toggleOverlay" 4691}, convertToComlinkEvent = (event) => { 4692 const { data } = event; 4693 return data && typeof data == "object" && "domain" in data && "type" in data && "from" in data && "to" in data && (data.domain === "sanity/channels" && (data.domain = DOMAIN), data.to === "overlays" && (data.to = "visual-editing"), data.from === "overlays" && (data.from = "visual-editing"), data.channelId = data.connectionId, delete data.connectionId, data.type = channelsToComlinkMap[data.type] ?? data.type), event; 4694}, convertToChannelsMessage = (comlinkMessage) => { 4695 const { channelId, ...rest } = comlinkMessage, message = { ...rest, connectionId: channelId }; 4696 return message.domain === DOMAIN && (message.domain = "sanity/channels"), message.to === "visual-editing" && (message.to = "overlays"), message.from === "visual-editing" && (message.from = "overlays"), message.type = comlinkToChannelsMap[message.type] ?? message.type, message.type === "channel/response" && message.responseTo && !message.data && (message.data = { responseTo: message.responseTo }), (message.type === "handshake/syn" || message.type === "handshake/syn-ack" || message.type === "handshake/ack") && (message.data = { id: message.connectionId }), message; 4697}, sendAsChannelsMessage = ({ context }, params) => { 4698 const { sources, targetOrigin } = context, message = convertToChannelsMessage(params.message);
4699 sources.forEach((source) => { 4700 source.postMessage(message, { targetOrigin }); 4701 }); 4702}, createCompatibilityActors = () => ({ 4703 listen: createListenLogic(convertToComlinkEvent), 4704 requestMachine: createRequestMachine().provide({ 4705 actions: { 4706 "send message": sendAsChannelsMessage 4707 } 4708 }) 4709}); 4710 4711const LISTEN_HEARTBEAT_INTERVAL = 1e4; 4712function enableLiveMode(options) { 4713 const { client, setFetcher, onConnect, onDisconnect, onPerspective } = options; 4714 if (!client) 4715 throw new Error( 4716 `Expected \`client\` to be an instance of SanityClient: ${JSON.stringify(client)}` 4717 ); 4718 const { projectId, dataset, perspective } = client.config(), $perspective = atom( 4719 perspective && perspective !== "raw" ? perspective : "drafts" 4720 ), $connected = atom(false), cache = /* @__PURE__ */ new Map(), comlink = createNode( 4721 { 4722 name: "loaders", 4723 connectTo: "presentation" 4724 }, 4725 createNodeMachine().provide({ 4726 actors: createCompatibilityActors() 4727 }) 4728 ); 4729 comlink.onStatus(() => { 4730 $connected.set(true); 4731 }, "connected"), comlink.on("loader/perspective", (data) => { 4732 if (data.projectId === projectId && data.dataset === dataset) { 4733 validateApiPerspective(data.perspective); 4734 const nextPerspective = data.perspective === "raw" ? "drafts" : data.perspective; 4735 $perspective.set(nextPerspective), onPerspective?.(nextPerspective), updateLiveQueries(); 4736 } 4737 }), comlink.on("loader/query-change", (data) => { 4738 if (data.projectId === projectId && data.dataset === dataset) { 4739 const { perspective: perspective2, query, params } = data; 4740 data.result !== void 0 && data.resultSourceMap !== void 0 && client.config().stega.enabled ? cache.set(JSON.stringify({ perspective: perspective2, query, params }), { 4741 ...data, 4742 result: stegaEncodeSourceMap( 4743 data.result, 4744 data.resultSourceMap, 4745 client.config().stega 4746 ) 4747 }) : cache.set(JSON.stringify({ perspective: perspective2, query, params }), data), updateLiveQueries(); 4748 } 4749 }); 4750 let unsetFetcher; 4751 const unlistenConnection = $connected.listen((connected) => { 4752 connected ? (unsetFetcher = setFetcher({ 4753 hydrate: (query, params, initial) => { 4754 const perspective2 = initial?.perspective || $perspective.get(), key = JSON.stringify({ 4755 perspective: perspective2, 4756 query, 4757 params 4758 }), snapshot = cache.get(key); 4759 return snapshot?.result !== void 0 && snapshot?.resultSourceMap !== void 0 ? { 4760 loading: false, 4761 error: void 0, 4762 data: snapshot.result, 4763 sourceMap: snapshot.resultSourceMap, 4764 perspective: perspective2 4765 } : { 4766 loading: $connected.value === true && initial?.data === void 0 || initial?.sourceMap === void 0, 4767 error: void 0, 4768 data: initial?.data, 4769 sourceMap: initial?.sourceMap, 4770 perspective: initial?.perspective || "published" 4771 }; 4772 }, 4773 fetch: (query, params, $fetch, controller) => { 4774 try { 4775 const removeLiveQuery = addLiveQuery(query, params, $fetch); 4776 if (controller.signal.addEventListener( 4777 "abort", 4778 () => { 4779 removeLiveQuery(), updateLiveQueries(); 4780 }, 4781 { 4782 once: !0 4783 } 4784 ), updateLiveQueries(), $fetch.setKey("error", void 0), controller.signal.aborted) return; 4785 } catch (error) { 4786 $fetch.setKey("error", error), $fetch.setKey("loading", false); 4787 } 4788 } 4789 }), onConnect?.()) : (unsetFetcher?.(), onDisconnect?.()); 4790 }), liveQueries = /* @__PURE__ */ new Set(), addLiveQuery = (query, params, $fetch) => { 4791 const liveQuery = { query, params, $fetch }; 4792 liveQueries.add(liveQuery), emitQueryListen(); 4793 const interval = setInterval(() => emitQueryListen(true), LISTEN_HEARTBEAT_INTERVAL); 4794 return () => { 4795 clearInterval(interval), liveQueries.delete(liveQuery), emitQueryListen(); 4796 }; 4797 }, emitQueryListen = (skipSetLoading) => { 4798 if (!comlink) 4799 throw new Error("No connection"); 4800 const perspective2 = $perspective.get(); 4801 for (const { query, params, $fetch } of liveQueries) 4802 comlink.post("loader/query-listen", { 4803 projectId, 4804 dataset, 4805 perspective: perspective2, 4806 query, 4807 params, 4808 heartbeat: LISTEN_HEARTBEAT_INTERVAL 4809 }), !skipSetLoading && $connected.value === true && $fetch.setKey("loading", true), $fetch.setKey("perspective", perspective2); 4810 }; 4811 function updateLiveQueries() { 4812 const perspective2 = $perspective.get(), documentsOnPage = []; 4813 for (const { query, params, $fetch } of liveQueries) {
4814 const key = JSON.stringify({ perspective: perspective2, query, params }), value = cache.get(key); 4815 value && ($fetch.set({ 4816 data: value.result, 4817 error: void 0, 4818 loading: false, 4819 perspective: perspective2, 4820 sourceMap: value.resultSourceMap 4821 }), documentsOnPage.push(...value.resultSourceMap?.documents ?? [])); 4822 } 4823 comlink.post("loader/documents", { 4824 projectId, 4825 dataset, 4826 perspective: perspective2, 4827 documents: documentsOnPage 4828 }); 4829 } 4830 const stop = comlink.start(); 4831 return () => { 4832 unsetFetcher?.(), unlistenConnection(), stop(), $connected.set(false); 4833 }; 4834} 4835 4836export { enableLiveMode };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.