Skip to content

Instantly share code, notes, and snippets.

@leosuncin
Last active June 6, 2020 04:54
Show Gist options
  • Save leosuncin/8cf405461c6878e9557eb35c49dfa640 to your computer and use it in GitHub Desktop.
Save leosuncin/8cf405461c6878e9557eb35c49dfa640 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function assertString(input) {
var isString = typeof input === 'string' || input instanceof String;
if (!isString) {
var invalidType;
if (input === null) {
invalidType = 'null';
} else {
invalidType = _typeof(input);
if (invalidType === 'object' && input.constructor && input.constructor.hasOwnProperty('name')) {
invalidType = input.constructor.name;
} else {
invalidType = "a ".concat(invalidType);
}
}
throw new TypeError("Expected string but received ".concat(invalidType, "."));
}
}
function merge() {
var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var defaults = arguments.length > 1 ? arguments[1] : undefined;
for (var key in defaults) {
if (typeof obj[key] === 'undefined') {
obj[key] = defaults[key];
}
}
return obj;
}
function isEmpty(text) {
return !Boolean(text);
}
function isLength(text, minLength) {
return isEmpty(text) || text.length < minLength;
}
function validateLogin(username, password) {
return !isLength(username, 5) && !isLength(password, 8);
}
const loginMachine = Machine({
id: 'login',
initial: 'fill',
context: {
username: '',
password: '',
retries: 0,
},
states: {
fill: {
type: 'parallel',
states: {
username: {
initial: 'valid',
states: {
valid: {},
invalid: {
initial: 'empty',
states: {
empty: {},
tooShort: {},
incorrect: {},
},
},
},
on: {
SET_USERNAME: [
{
target: '.invalid.empty',
actions: 'setUsername',
cond: 'isUsernameEmpty',
},
{
target: '.invalid.tooShort',
actions: 'setUsername',
cond: 'isUsernameShort',
},
{ target: '.valid', actions: 'setUsername' },
],
},
},
password: {
initial: 'valid',
states: {
valid: {},
invalid: {
initial: 'empty',
states: {
empty: {},
tooShort: {},
incorrect: {},
},
},
},
on: {
SET_PASSWORD: [
{
target: '.invalid.empty',
actions: 'setPassword',
cond: 'isPasswordEmpty',
},
{
target: '.invalid.tooShort',
actions: 'setPassword',
cond: 'isPasswordShort',
},
{ target: '.valid', actions: 'setPassword' },
],
},
},
},
on: {
SUBMIT: [
{
target: 'send',
cond: 'validPayload',
},
],
},
},
send: {
invoke: {
src: 'login',
onDone: 'successful',
onError: [
{ target: 'locked', cond: 'fail2ban' },
{
target: 'fill.username.invalid.incorrect',
actions: 'incrementRetries',
cond: 'isUsernameIncorrect',
},
{
target: 'fill.password.invalid.incorrect',
actions: 'incrementRetries',
cond: 'isPasswordIncorrect',
},
{ target: 'error', actions: 'setError' },
],
},
},
successful: {
type: 'final',
},
error: {
on: {
'': [
{
target: 'locked',
cond: 'fail2ban',
},
{ target: 'fill' },
],
},
},
locked: {
type: 'final',
},
},
}, {
actions: {
setUsername: assign((context, event) => ({
username: event.text,
})),
setPassword: assign((context, event) => ({
password: event.text,
})),
setError: assign((context, event) => ({
errorMessage: event.data.message,
})),
incrementRetries: assign(context => ({
retries: context.retries + 1,
})),
},
guards: {
isUsernameEmpty(context, event) {
return isEmpty(event.text);
},
isUsernameShort(context, event) {
return isLength(event.text, 5);
},
isPasswordEmpty(context, event) {
return isEmpty(event.text);
},
isPasswordShort(context, event) {
return isLength(event.text, 8);
},
validPayload({ username, password }) {
return validateLogin(username, password);
},
fail2ban(context) {
return context.retries >= 3;
},
isUsernameIncorrect(context, event) {
return event.data && /any user/i.test(event.data.message);
},
isPasswordIncorrect(context, event) {
return event.data && /Wrong password/i.test(event.data.message);
},
finish: console.log
},
services: {
login({username, password}) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (username !== 'admin') {
return reject(
new Error(`There isn't any user with username: ${username}`),
);
}
if (password !== 'Pa$$w0rd!') {
return reject(
new Error(`Wrong password for user with username: ${username}`),
);
}
resolve({ username, password });
}, 1e3);
});
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment