Initial commit
This commit is contained in:
323
commands/audition.md
Normal file
323
commands/audition.md
Normal file
@@ -0,0 +1,323 @@
|
||||
---
|
||||
description: Get expert guidance on testing XState v5 actors with xstate-audition
|
||||
argument-hint: '[what-to-test]'
|
||||
---
|
||||
|
||||
# XState Audition Testing Guidance
|
||||
|
||||
Provide expert guidance on testing XState v5 actors using the xstate-audition library for comprehensive state machine and actor testing.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
/audition [optional: what you need to test]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
|
||||
- `what-to-test` (optional): Describe what you're trying to test or paste test code you need help with
|
||||
|
||||
## Instructions
|
||||
|
||||
When this command is invoked:
|
||||
|
||||
1. **Load the xstate-audition skill** from `skills/xstate-audition/SKILL.md`
|
||||
|
||||
2. **If the user provided context**, analyze their needs and:
|
||||
- Identify which xstate-audition functions apply to their testing scenario
|
||||
- Provide specific test examples using xstate-audition APIs
|
||||
- Explain the testing pattern and timing considerations
|
||||
- Show best practices for the specific test case
|
||||
- Reference the appropriate documentation from `references/`:
|
||||
- Core Functions for API documentation
|
||||
- Options & Types for configuration details
|
||||
- Testing Patterns for advanced examples
|
||||
|
||||
3. **If no context was provided**, offer to help by:
|
||||
- Asking what they're trying to test or what actor behavior needs verification
|
||||
- Listing common test scenarios:
|
||||
- Testing state transitions
|
||||
- Testing promise actors and async operations
|
||||
- Testing event emissions and actor communication
|
||||
- Testing hierarchical actors and spawning
|
||||
- Testing with timeouts and error handling
|
||||
- Integration testing of actor systems
|
||||
- Offering to show examples of specific patterns
|
||||
|
||||
4. **Always emphasize xstate-audition best practices**:
|
||||
- Use currying for repeated patterns to reduce boilerplate
|
||||
- Set external input BEFORE awaiting (avoid race conditions)
|
||||
- Use `waitFor*()` for multi-stage tests (keeps actor alive)
|
||||
- Provide explicit type arguments (especially for `runUntilSpawn`)
|
||||
- Use appropriate timeouts (less than test framework timeout)
|
||||
- Test state transitions explicitly with `runUntilTransition()`
|
||||
- Use `runUntilSnapshot()` for complex conditions
|
||||
|
||||
5. **Explain the core testing pattern**:
|
||||
1. Create an Actor using `createActor(logic)`
|
||||
2. Create a Promise using a condition function (e.g., `runUntilDone(actor)`)
|
||||
3. If the actor needs external input, perform that operation BEFORE awaiting
|
||||
4. Await the Promise
|
||||
5. Make assertions about the result
|
||||
|
||||
6. **Clarify `runUntil*()` vs `waitFor*()`**:
|
||||
- `runUntil*()` - Starts actor, waits for condition, then STOPS the actor
|
||||
- `waitFor*()` - Starts actor, waits for condition, but KEEPS the actor running
|
||||
|
||||
## Example Interactions
|
||||
|
||||
**With context - testing a promise actor:**
|
||||
|
||||
```text
|
||||
User: /audition How do I test this promise actor?
|
||||
const fetchLogic = fromPromise(async ({ input }) => {
|
||||
const res = await fetch(input.url);
|
||||
return res.json();
|
||||
});
|
||||
|
||||
Agent: Here's how to test your promise actor with xstate-audition:
|
||||
|
||||
\`\`\`typescript
|
||||
import { createActor, fromPromise } from 'xstate';
|
||||
import { runUntilDone } from 'xstate-audition';
|
||||
import { describe, it } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
|
||||
const fetchLogic = fromPromise<any, { url: string }>(
|
||||
async ({ input }) => {
|
||||
const res = await fetch(input.url);
|
||||
return res.json();
|
||||
}
|
||||
);
|
||||
|
||||
describe('fetchLogic', () => {
|
||||
it('should complete with fetched data', async () => {
|
||||
const actor = createActor(fetchLogic, {
|
||||
input: { url: 'https://api.example.com/data' }
|
||||
});
|
||||
|
||||
const result = await runUntilDone(actor);
|
||||
|
||||
assert.ok(result);
|
||||
assert.equal(typeof result, 'object');
|
||||
});
|
||||
|
||||
it('should handle errors', async () => {
|
||||
const actor = createActor(fetchLogic, {
|
||||
input: { url: 'https://invalid.url' }
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
runUntilDone(actor),
|
||||
(err: Error) => {
|
||||
assert.ok(err.message.includes('fetch'));
|
||||
return true;
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
Key patterns:
|
||||
- `runUntilDone()` waits for the promise actor to complete
|
||||
- Pass input via actor options
|
||||
- Use `assert.rejects()` to test error cases
|
||||
- The actor automatically starts when you await the promise
|
||||
```
|
||||
|
||||
**With context - testing state transitions:**
|
||||
|
||||
```text
|
||||
User: /audition I need to test that my machine transitions from idle to loading when FETCH is sent
|
||||
|
||||
Agent: Use `runUntilTransition()` to test explicit state changes:
|
||||
|
||||
\`\`\`typescript
|
||||
import { createActor } from 'xstate';
|
||||
import { runUntilTransition } from 'xstate-audition';
|
||||
import { describe, it, beforeEach } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
|
||||
describe('fetchMachine transitions', () => {
|
||||
let actor: Actor<typeof fetchMachine>;
|
||||
let runFromIdle: CurryTransitionP2<typeof actor>;
|
||||
|
||||
beforeEach(() => {
|
||||
actor = createActor(fetchMachine);
|
||||
// Curry with actor and fromState for reusability
|
||||
runFromIdle = runUntilTransition(actor, 'fetchMachine.idle');
|
||||
});
|
||||
|
||||
it('should transition from idle to loading', async () => {
|
||||
// Setup the promise FIRST
|
||||
const promise = runFromIdle('fetchMachine.loading');
|
||||
|
||||
// THEN send the event that triggers the transition
|
||||
actor.send({ type: 'FETCH' });
|
||||
|
||||
// Finally await the result
|
||||
await promise;
|
||||
});
|
||||
|
||||
it('should transition through loading to success', async () => {
|
||||
actor.send({ type: 'FETCH' });
|
||||
await runFromIdle('fetchMachine.success');
|
||||
});
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
Important timing note:
|
||||
1. Create the promise BEFORE sending the event
|
||||
2. Send the event that triggers the transition
|
||||
3. Then await the promise
|
||||
|
||||
This pattern avoids race conditions. The curried form (`runFromIdle`) reduces boilerplate!
|
||||
```
|
||||
|
||||
**With context - testing event emissions:**
|
||||
|
||||
```text
|
||||
User: /audition How do I test that my machine emits events?
|
||||
|
||||
Agent: Use `runUntilEmitted()` to test event emissions:
|
||||
|
||||
\`\`\`typescript
|
||||
import { createActor, setup, emit } from 'xstate';
|
||||
import { runUntilEmitted } from 'xstate-audition';
|
||||
import { describe, it } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
|
||||
const notifierMachine = setup({
|
||||
types: {
|
||||
emitted: {} as
|
||||
| { type: 'READY'; message: string }
|
||||
| { type: 'ERROR'; error: Error },
|
||||
},
|
||||
}).createMachine({
|
||||
initial: 'initializing',
|
||||
states: {
|
||||
initializing: {
|
||||
entry: emit({ type: 'READY', message: 'System initialized' }),
|
||||
on: {
|
||||
START: 'running',
|
||||
},
|
||||
},
|
||||
running: {},
|
||||
},
|
||||
});
|
||||
|
||||
describe('notifierMachine emissions', () => {
|
||||
it('should emit READY on initialization', async () => {
|
||||
const actor = createActor(notifierMachine);
|
||||
|
||||
// Wait for READY event
|
||||
const [readyEvent] = await runUntilEmitted(actor, ['READY']);
|
||||
|
||||
assert.equal(readyEvent.type, 'READY');
|
||||
assert.equal(readyEvent.message, 'System initialized');
|
||||
});
|
||||
|
||||
it('should emit multiple events', async () => {
|
||||
const actor = createActor(notifierMachine);
|
||||
|
||||
// Wait for any of these events
|
||||
const events = await runUntilEmitted(actor, ['READY', 'ERROR']);
|
||||
|
||||
assert.ok(events.length > 0);
|
||||
assert.equal(events[0].type, 'READY');
|
||||
});
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
The function returns an array of emitted events. Test the ones you care about!
|
||||
```
|
||||
|
||||
**With context - testing hierarchical actors:**
|
||||
|
||||
```text
|
||||
User: /audition How do I test parent/child actor communication?
|
||||
|
||||
Agent: Use `waitForSpawn()` to test hierarchical actors:
|
||||
|
||||
\`\`\`typescript
|
||||
import { createActor } from 'xstate';
|
||||
import { waitForSpawn, waitForSnapshot } from 'xstate-audition';
|
||||
import { describe, it } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
|
||||
describe('parent-child communication', () => {
|
||||
it('should spawn child and communicate', async () => {
|
||||
const parent = createActor(parentMachine);
|
||||
|
||||
// Wait for child to spawn (parent stays running)
|
||||
const child = await waitForSpawn<typeof childLogic>(
|
||||
parent,
|
||||
'childActor'
|
||||
);
|
||||
|
||||
assert.ok(child);
|
||||
assert.equal(child.id, 'childActor');
|
||||
|
||||
// Send event to child
|
||||
child.send({ type: 'CHILD_EVENT' });
|
||||
|
||||
// Wait for parent to react to child's output
|
||||
const parentSnapshot = await waitForSnapshot(
|
||||
parent,
|
||||
(snapshot) => snapshot.matches('parentReacted')
|
||||
);
|
||||
|
||||
assert.ok(parentSnapshot.matches('parentReacted'));
|
||||
});
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
Key points:
|
||||
- Use `waitForSpawn()` not `runUntilSpawn()` to keep parent running
|
||||
- Provide type argument `<typeof childLogic>` for proper typing
|
||||
- Parent stays alive so you can continue testing interactions
|
||||
```
|
||||
|
||||
**Without context:**
|
||||
|
||||
```text
|
||||
User: /audition
|
||||
|
||||
Agent: I can help you test XState v5 actors with xstate-audition! What do you need to test?
|
||||
|
||||
Common testing scenarios:
|
||||
- **State transitions** - Test explicit state changes with `runUntilTransition()`
|
||||
- **Promise actors** - Test async operations with `runUntilDone()`
|
||||
- **Event emissions** - Test emitted events with `runUntilEmitted()`
|
||||
- **Actor spawning** - Test child actors with `runUntilSpawn()` / `waitForSpawn()`
|
||||
- **Complex conditions** - Test multiple conditions with `runUntilSnapshot()`
|
||||
- **Event communication** - Test inter-actor events with `runUntilEventReceived()`
|
||||
- **Timeout handling** - Test with custom timeouts using `*With()` functions
|
||||
- **Integration tests** - Test complete actor systems with `waitFor*()` functions
|
||||
|
||||
You can also:
|
||||
- Paste your existing test code for review
|
||||
- Ask about specific xstate-audition functions
|
||||
- Request help debugging timeout issues
|
||||
- Learn about currying patterns for cleaner tests
|
||||
|
||||
Core testing pattern:
|
||||
1. Create actor with `createActor(logic)`
|
||||
2. Create promise with condition (e.g., `runUntilDone(actor)`)
|
||||
3. If actor needs input, send events BEFORE awaiting
|
||||
4. Await the promise
|
||||
5. Make assertions
|
||||
|
||||
Key distinction:
|
||||
- `runUntil*()` - stops actor after condition
|
||||
- `waitFor*()` - keeps actor running
|
||||
|
||||
What would you like to test?
|
||||
```
|
||||
|
||||
## Related Files
|
||||
|
||||
- [XState Audition Skill](../skills/xstate-audition/SKILL.md)
|
||||
- [Core Functions Reference](../skills/xstate-audition/references/core-functions.md)
|
||||
- [Options & Types Reference](../skills/xstate-audition/references/options-types.md)
|
||||
- [Testing Patterns Reference](../skills/xstate-audition/references/testing-patterns.md)
|
||||
336
commands/xstate.md
Normal file
336
commands/xstate.md
Normal file
@@ -0,0 +1,336 @@
|
||||
---
|
||||
description: Get expert guidance on XState v5 state machines and actor model implementation
|
||||
argument-hint: '[what-you-need]'
|
||||
---
|
||||
|
||||
# XState v5 Expert Guidance
|
||||
|
||||
Provide expert guidance on implementing XState v5 state machines, actors, and statecharts with TypeScript best practices for backend applications.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
/xstate [optional: what you need help with]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
|
||||
- `what-you-need` (optional): Describe what you're trying to implement or paste code you need help with
|
||||
|
||||
## Instructions
|
||||
|
||||
When this command is invoked:
|
||||
|
||||
1. **Load the xstate-v5 skill** from `skills/xstate-v5/SKILL.md`
|
||||
|
||||
2. **If the user provided context**, analyze their needs and:
|
||||
- Identify which XState patterns or APIs apply to their situation
|
||||
- Provide specific code examples using XState v5 APIs
|
||||
- Show TypeScript integration when relevant
|
||||
- Explain best practices and common pitfalls
|
||||
- Reference the appropriate documentation from `references/`:
|
||||
- Core API Reference for function documentation
|
||||
- Actors Reference for actor model guidance
|
||||
- Common Patterns for production-ready examples
|
||||
- TypeScript Integration for typing help
|
||||
- Testing Strategies for test guidance
|
||||
|
||||
3. **If no context was provided**, offer to help by:
|
||||
- Asking what they're trying to implement or what problem they're solving
|
||||
- Listing common scenarios:
|
||||
- Creating state machines with `createMachine` and `setup`
|
||||
- Managing actor lifecycle and communication
|
||||
- Implementing loading states, authentication flows, or wizards
|
||||
- Adding TypeScript types to machines
|
||||
- Testing with xstate-audition
|
||||
- Performance optimization
|
||||
- Offering to show examples of specific patterns
|
||||
|
||||
4. **Always emphasize XState v5 best practices**:
|
||||
- Always use `setup()` for better type inference and reusable logic
|
||||
- Name all actions and guards (avoid inline functions)
|
||||
- Use context for data, states for behavior
|
||||
- Keep machines focused - one machine per logical unit
|
||||
- Leverage TypeScript for compile-time safety
|
||||
- Don't mutate context directly - always use `assign`
|
||||
- Don't use side effects in guards - guards should be pure
|
||||
- Use Promise actors for asynchronous operations
|
||||
|
||||
5. **Focus on backend use cases**:
|
||||
- This plugin is tailored for Node.js/Deno/Bun backend applications
|
||||
- Emphasize server-side patterns: database transactions, API orchestration, rate limiting
|
||||
- Reference backend-specific patterns from the Common Patterns reference
|
||||
|
||||
## Example Interactions
|
||||
|
||||
**With context - creating a machine:**
|
||||
|
||||
```text
|
||||
User: /xstate I need to implement a loading state pattern with retry logic
|
||||
|
||||
Agent: Here's an XState v5 loading pattern with retry logic:
|
||||
|
||||
\`\`\`typescript
|
||||
import { setup, assign, fromPromise } from 'xstate';
|
||||
|
||||
const fetchMachine = setup({
|
||||
types: {
|
||||
context: {} as {
|
||||
data: string | null;
|
||||
error: Error | null;
|
||||
retryCount: number;
|
||||
},
|
||||
events: {} as
|
||||
| { type: 'FETCH' }
|
||||
| { type: 'RETRY' }
|
||||
| { type: 'RESET' },
|
||||
},
|
||||
actors: {
|
||||
fetchData: fromPromise<string, void>(async () => {
|
||||
const response = await fetch('https://api.example.com/data');
|
||||
return response.text();
|
||||
}),
|
||||
},
|
||||
actions: {
|
||||
assignData: assign({
|
||||
data: ({ event }) => (event as any).output,
|
||||
error: null,
|
||||
}),
|
||||
assignError: assign({
|
||||
error: ({ event }) => (event as any).error,
|
||||
}),
|
||||
incrementRetry: assign({
|
||||
retryCount: ({ context }) => context.retryCount + 1,
|
||||
}),
|
||||
resetRetry: assign({
|
||||
retryCount: 0,
|
||||
}),
|
||||
},
|
||||
guards: {
|
||||
canRetry: ({ context }) => context.retryCount < 3,
|
||||
},
|
||||
}).createMachine({
|
||||
id: 'fetch',
|
||||
initial: 'idle',
|
||||
context: {
|
||||
data: null,
|
||||
error: null,
|
||||
retryCount: 0,
|
||||
},
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
FETCH: 'loading',
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
invoke: {
|
||||
src: 'fetchData',
|
||||
onDone: {
|
||||
target: 'success',
|
||||
actions: ['assignData', 'resetRetry'],
|
||||
},
|
||||
onError: {
|
||||
target: 'failure',
|
||||
actions: 'assignError',
|
||||
},
|
||||
},
|
||||
},
|
||||
success: {
|
||||
on: {
|
||||
RESET: 'idle',
|
||||
},
|
||||
},
|
||||
failure: {
|
||||
on: {
|
||||
RETRY: {
|
||||
target: 'loading',
|
||||
guard: 'canRetry',
|
||||
actions: 'incrementRetry',
|
||||
},
|
||||
RESET: 'idle',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
Key XState v5 patterns used:
|
||||
- `setup()` for type-safe configuration and reusable logic
|
||||
- Named actions and guards for clarity
|
||||
- Promise actors with `fromPromise` for async operations
|
||||
- Context for data management (data, error, retryCount)
|
||||
- Guards for conditional transitions (retry limit)
|
||||
- `assign` for immutable context updates
|
||||
|
||||
This pattern is common for backend API calls. See [references/patterns.md] for more examples.
|
||||
```
|
||||
|
||||
**With context - TypeScript help:**
|
||||
|
||||
```text
|
||||
User: /xstate How do I add strong typing to my machine?
|
||||
|
||||
Agent: Use the `setup()` pattern for strong typing in XState v5:
|
||||
|
||||
\`\`\`typescript
|
||||
import { setup, assign } from 'xstate';
|
||||
|
||||
// Define your types
|
||||
interface UserContext {
|
||||
userId: string | null;
|
||||
userData: User | null;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
type UserEvents =
|
||||
| { type: 'LOGIN'; userId: string }
|
||||
| { type: 'LOGOUT' }
|
||||
| { type: 'FETCH_USER' };
|
||||
|
||||
// Use setup for type inference
|
||||
const userMachine = setup({
|
||||
types: {
|
||||
context: {} as UserContext,
|
||||
events: {} as UserEvents,
|
||||
},
|
||||
actions: {
|
||||
setUserId: assign({
|
||||
userId: ({ event }) => {
|
||||
// TypeScript knows event can be LOGIN
|
||||
if (event.type === 'LOGIN') {
|
||||
return event.userId;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
clearUser: assign({
|
||||
userId: null,
|
||||
userData: null,
|
||||
}),
|
||||
},
|
||||
}).createMachine({
|
||||
id: 'user',
|
||||
initial: 'loggedOut',
|
||||
context: {
|
||||
userId: null,
|
||||
userData: null,
|
||||
error: null,
|
||||
},
|
||||
states: {
|
||||
loggedOut: {
|
||||
on: {
|
||||
LOGIN: {
|
||||
target: 'loggedIn',
|
||||
actions: 'setUserId',
|
||||
},
|
||||
},
|
||||
},
|
||||
loggedIn: {
|
||||
on: {
|
||||
LOGOUT: {
|
||||
target: 'loggedOut',
|
||||
actions: 'clearUser',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
\`\`\`
|
||||
|
||||
Key TypeScript patterns:
|
||||
- Define context and event types explicitly
|
||||
- Use `{} as Type` syntax in `types` config
|
||||
- TypeScript infers types throughout the machine
|
||||
- Event types are narrowed in action implementations
|
||||
- No `any` types needed
|
||||
|
||||
See [references/typescript.md] for advanced patterns including generic machine factories.
|
||||
```
|
||||
|
||||
**With context - debugging:**
|
||||
|
||||
```text
|
||||
User: /xstate Why is my context not updating?
|
||||
const machine = createMachine({
|
||||
context: { count: 0 },
|
||||
on: {
|
||||
INC: { actions: (ctx) => ctx.context.count++ }
|
||||
}
|
||||
});
|
||||
|
||||
Agent: The issue is that you're mutating context directly, which XState doesn't detect. Always use `assign` for context updates:
|
||||
|
||||
\`\`\`typescript
|
||||
// ❌ WRONG - mutating context directly
|
||||
on: {
|
||||
INC: { actions: (ctx) => ctx.context.count++ }
|
||||
}
|
||||
|
||||
// ✅ CORRECT - use assign for immutable updates
|
||||
import { assign } from 'xstate';
|
||||
|
||||
on: {
|
||||
INC: {
|
||||
actions: assign({
|
||||
count: ({ context }) => context.count + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
This is a common mistake! XState requires immutable context updates to:
|
||||
1. Maintain predictable state transitions
|
||||
2. Enable time-travel debugging
|
||||
3. Support snapshot serialization
|
||||
4. Ensure proper actor communication
|
||||
|
||||
Other common mistakes to avoid:
|
||||
- Don't use side effects in guards (guards should be pure)
|
||||
- Don't overuse nested states (flatten when possible)
|
||||
- Don't use `setInterval` in machines (use delays instead)
|
||||
|
||||
Want to see more best practices?
|
||||
```
|
||||
|
||||
**Without context:**
|
||||
|
||||
```text
|
||||
User: /xstate
|
||||
|
||||
Agent: I can help you with XState v5! What are you trying to implement?
|
||||
|
||||
Common use cases:
|
||||
- **State machines** - Model application logic with explicit states and transitions
|
||||
- **Actor systems** - Manage concurrent actors and communication
|
||||
- **Loading patterns** - Implement fetch/retry/timeout logic
|
||||
- **Authentication flows** - Handle login/logout/session management
|
||||
- **Wizards & forms** - Multi-step forms with validation
|
||||
- **Backend workflows** - Database transactions, message queue processing, rate limiting
|
||||
- **TypeScript integration** - Add strong typing to your machines
|
||||
- **Testing** - Test actors with xstate-audition
|
||||
|
||||
You can also:
|
||||
- Paste your existing state machine code for review
|
||||
- Ask about specific XState v5 APIs
|
||||
- Request examples of common patterns
|
||||
- Get help debugging issues
|
||||
|
||||
I have access to comprehensive documentation:
|
||||
- Core API reference (setup, createMachine, actors, actions, guards)
|
||||
- Actor model guide (all actor types, spawning, communication)
|
||||
- Common patterns (loading, auth, forms, pagination, etc.)
|
||||
- TypeScript integration patterns
|
||||
- Testing strategies with xstate-audition
|
||||
|
||||
What would you like to work on?
|
||||
```
|
||||
|
||||
## Related Files
|
||||
|
||||
- [XState v5 Skill](../skills/xstate-v5/SKILL.md)
|
||||
- [Core API Reference](../skills/xstate-v5/references/core-api.md)
|
||||
- [Actors Reference](../skills/xstate-v5/references/actors.md)
|
||||
- [Common Patterns](../skills/xstate-v5/references/patterns.md)
|
||||
- [TypeScript Integration](../skills/xstate-v5/references/typescript.md)
|
||||
- [Testing Strategies](../skills/xstate-v5/references/testing.md)
|
||||
Reference in New Issue
Block a user