christoph-fricke / xsystem Goto Github PK
View Code? Open in Web Editor NEWBuilding Blocks for XState-based Actor Systems.
Home Page: https://npmjs.com/package/xsystem
License: MIT License
Building Blocks for XState-based Actor Systems.
Home Page: https://npmjs.com/package/xsystem
License: MIT License
The fromActor
service creator should be used to connect a machine to an actor that accepts subscribe events, i.e. a publisher.
The current implementation of fromActor
creates some type errors when the helper function is actually used. Some thinks to keep in mind:
These have an influence on the type definitions for the machine and actor.
Furthermore, it might be a good idea to send a state update of the actor as an event back to the machine.
I am starting to explore an implementation of a registry for XState-based actor systems. This is still very much in the exploration phase and will evolve once we start to gather feedback in the XState community.
Related work:
Features / Use-Cases that should be supported by an implementation (uncertainty is marked with ???):
ActorRef
itselfActorRef
in the registryActorRef
from the registry for a given IDBehavior
and StateMachine
definitions directly with the registry as their parent
I ran into this error while compiling for Angular Nativescript:
ERROR in �[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m87�[0m - �[91merror�[0m�[90m TS1110: �[0mType expected.
Angular Version: 10.1.2
Nativescript Version: 8.0.8
xsystem version: 0.4.0
xstate version: 4.26.0
Here's the detailed log:
Preparing project...
File change detected. Starting incremental webpack compilation...
webpack is watching the files…
Hash: 593690d783b1d5f15c6c
Version: webpack 4.44.1
Time: 23585ms
Built at: 26/01/2022 10:29:51 am
Asset Size Chunks Chunk Names
assets/image/samplelogo.jpg 46.2 KiB [emitted]
assets/login/google/btn_google_signin_dark_disabled_web.png 2.25 KiB [emitted]
assets/login/google/btn_google_signin_dark_focus_web.png 4.09 KiB [emitted]
assets/login/google/btn_google_signin_dark_normal_web.png 3.89 KiB [emitted]
assets/login/google/btn_google_signin_dark_pressed_web.png 4.14 KiB [emitted]
assets/login/google/btn_google_signin_light_disabled_web.png 2.25 KiB [emitted]
assets/login/google/btn_google_signin_light_focus_web.png 4.23 KiB [emitted]
assets/login/google/btn_google_signin_light_normal_web.png 4 KiB [emitted]
assets/login/google/btn_google_signin_light_pressed_web.png 4.04 KiB [emitted]
bundle.js 15 KiB bundle [emitted] bundle
fonts/fa-brands-400.ttf 131 KiB [emitted]
fonts/fa-regular-400.ttf 39.1 KiB [emitted]
fonts/fa-solid-900.ttf 204 KiB [emitted]
package.json 133 bytes [emitted]
runtime.js 77.1 KiB runtime [emitted] runtime
tns-java-classes.js 0 bytes [emitted]
vendor.js 6.11 MiB vendor [emitted] vendor
Entrypoint bundle = runtime.js vendor.js bundle.js
[./app.css] 3.68 KiB {bundle} [built]
[./main.ts] 1.13 KiB {bundle} [built]
[/package.json] external "/package.json" 42 bytes {bundle} [optional] [built]
+ 335 hidden modules
ERROR in �[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m87�[0m - �[91merror�[0m�[90m TS1110: �[0mType expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~~~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m96�[0m - �[91merror�[0m�[90m TS1005: �[0m'}' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~~~~~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m101�[0m - �[91merror�[0m�[90m TS1128: �[0mDeclaration or statement expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m103�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m115�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m122�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~~~~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m132�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m133�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m141�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m152�[0m - �[91merror�[0m�[90m TS1109: �[0mExpression expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m158�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m159�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m167�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m179�[0m - �[91merror�[0m�[90m TS1005: �[0m';' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m2�[0m:�[93m205�[0m - �[91merror�[0m�[90m TS1005: �[0m'(' expected.
�[7m2�[0m export declare type Wildcard<S extends string, Separator extends string> = (S extends ${infer Start}${Separator}${infer Rest}
? ${Start}${Separator}*
| ${Start}${Separator}${Wildcard<Rest, Separator>}
: never) | "*";
�[7m �[0m �[91m ~�[0m
�[96mnode_modules/xsystem/dist/subscriptions/wildcard.d.ts�[0m:�[93m5�[0m:�[93m1�[0m - �[91merror�[0m�[90m TS1160: �[0mUnterminated template literal.
�[7m5�[0m
�[7m �[0m �[91m�[0m
Webpack compilation complete. Watching for file changes.
Webpack build done!
Updating runtime package.json with configuration values...
Project successfully prepared (android)
Attached compressed package.json file
package.json.zip
fromMachine
is used to convert a state machine to a behavior so it can be used with higher-order-behavior defined by this library.
However, it is currently not possible to pass a machine that is created with createMachine
or model.createMachine
to fromMachine
. TypeScript produces some type errors that I don't fully understand yet.
Relevant source: https://github.com/christoph-fricke/xsystem/blob/main/src/utils/from_machine.ts
Test that should not produce errors if TS comment is removed: https://github.com/christoph-fricke/xsystem/blob/main/src/utils/from_machine.test.ts
Currently, this repository waits for statelyai/xstate#2560 to be merged. When it is finally merged, all behaviors that are marked with TODO
should add their stop behavior.
The relevant behaviors are:
fromMachine
event-bus
withSubscriptions
withPubSub
(? should it empty its subscribers on stop ?)Elixir's and Akka actor system follows a "let it crash" mentality and use supervisors to create actors trees, which are partly restarted if an actor in the tree crashes12. XState is currently not really concerned with proper error handling and it is handled rather inconsistently, although errors in the system are inevitable. There have been a few discussions on the Discord3 and in the RFCs4, which can inspire a solution.
We might try to tackle the problem in XSystem first, before forces changes in XState, since XSystem is smaller and easier to change. A solution probably requires our own spawning implementation and potential extensions to the Behavior
and ActorRef
interface.
An initial thought is to wrap any behavior transition in a spawn
function in a try/catch
block and "restart" the behavior in case the catch
block is reached.
I am open for ideas and suggestions regarding this topic. 😄
https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html ↩
https://doc.akka.io/docs/akka/current/typed/fault-tolerance.html ↩
https://discord.com/channels/795785288994652170/877478623202906132/895041466538266704 ↩
https://github.com/statelyai/rfcs/blob/0001-errors/text/0001-errors.md ↩
The idea of withPubSub
is to extend a given behavior with the ability to publish event. Most importantly, the type for published events should be different from the type for received event, because an actor does not have to only publish events it can receive.
The current generics make it rather awkward to type the publishable events. As soon as the generic P
gets defined, a user has to also provide types for the other generics. When defaults are used for the remainder, the wrapped behavior does not correctly infer its types from the given behavior.
To avoid this, a user currently has to type the published events like this: withPubSub((pub: Publish<Event>) => behavior)
.
Ideally, this should work: withPubSub<Event>((pub) => behavior)
and should correctly infer the receive-able events and state from behavior
.
I tried this, but it does not work as the resulting behavior will be typed as Behavior<any, any>
:
export function withPubSub<P extends EventObject>(
getBehavior: (publish: Publish<P>) => Behavior<any>
): ReturnType<typeof getBehavior> extends Behavior<infer E, infer S>
? WithPubSub<P, Behavior<E, S>>
: never {
const subscribers = createSubscriberStructure<P>();
const behavior = getBehavior(createPublishFunction(subscribers));
return {
...behavior,
transition: (state, event, ctx) => {
if (handleSubscribeEvent(subscribers, event)) return state;
return behavior.transition(state, event, ctx);
},
};
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.