chore(root): streamline agent guidance and skills

This commit is contained in:
Rahim
2026-07-14 15:49:05 -07:00
parent a9a09a7e52
commit b66b1ebf23
190 changed files with 1560 additions and 18335 deletions
+302
View File
@@ -0,0 +1,302 @@
# Code Examples Pattern
How to write effective code examples across documentation — site pages, READMEs, and JSDoc.
## Core Principles
1. **Self-contained** — include all imports
2. **Copy-paste ready** — works immediately
3. **TypeScript-first** — show types, leverage inference
4. **Minimal** — only what's needed to demonstrate the concept
5. **Real** — use realistic values, not `foo`/`bar`
## Self-Contained Examples
```tsx
// ❌ Missing imports — won't work when copied
function App() {
return (
<Player.Container>
<Video src="video.mp4" />
<PlayButton />
</Player.Container>
);
}
// ✅ Complete — copy, paste, run
import { createPlayer, PlayButton } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';
const Player = createPlayer({ features: videoFeatures });
function App() {
return (
<Player.Provider>
<Player.Container>
<Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" />
<PlayButton />
</Player.Container>
</Player.Provider>
);
}
```
## TypeScript Best Practices
### Show Type Inference
```ts
// ✅ Let inference work — cleaner
const store = createStore<HTMLMediaElement>()(volumeSlice);
// ❌ Redundant annotation
const store: Store<HTMLMediaElement, VolumeState> = createStore<HTMLMediaElement>()(volumeSlice);
```
### Annotate When Helpful
```ts
// ✅ Annotation clarifies complex return
import type { InferSliceState } from '@videojs/store';
type VolumeState = InferSliceState<typeof volumeSlice>;
// { volume: number; muted: boolean; setVolume: ...; toggleMuted: ... }
```
### Show Type Imports
```ts
// ✅ Separate type imports
import { createStore, defineSlice } from '@videojs/store';
import type { InferStoreState } from '@videojs/store';
```
## Framework-Specific Code
Site pages use `<FrameworkCase>` and `<StyleCase>` to show code per framework. Never use generic `<Tabs>` for framework switching.
**React:**
```tsx
import { createPlayer, PlayButton } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';
const Player = createPlayer({ features: videoFeatures });
export default function BasicUsage() {
return (
<Player.Provider>
<Player.Container className="player">
<Video
src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4"
autoPlay
muted
playsInline
/>
<PlayButton
render={(props, state) => (
<button {...props}>{state.paused ? 'Play' : 'Pause'}</button>
)}
/>
</Player.Container>
</Player.Provider>
);
}
```
**HTML:**
```html
<video-player class="player">
<video
src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4"
autoplay
muted
playsinline
></video>
<media-play-button>
<span class="show-when-paused">Play</span>
<span class="show-when-playing">Pause</span>
</media-play-button>
</video-player>
```
## Progressive Examples
Start simple, add complexity in later sections:
```markdown
## Basic Usage
const volumeSlice = defineSlice<HTMLMediaElement>()({
state: () => ({ volume: 1 }),
attach: ({ target, set, signal }) => {
const sync = () => set({ volume: target.volume });
target.addEventListener('volumechange', sync, { signal });
},
});
## With Actions
const volumeSlice = defineSlice<HTMLMediaElement>()({
state: ({ target }) => ({
volume: 1,
setVolume(value: number) {
target().volume = Math.max(0, Math.min(1, value));
},
}),
attach: ({ target, set, signal }) => {
const sync = () => set({ volume: target.volume });
sync();
target.addEventListener('volumechange', sync, { signal });
},
});
## Combining Slices
const mediaSlice = combine(volumeSlice, playbackSlice);
const store = createStore<HTMLMediaElement>()(mediaSlice);
```
## Do/Don't Contrasts
Use `// ❌ Don't` / `// ✅ Do` pairs. Always explain *why* the wrong way is wrong:
```ts
// ❌ Don't — creates new Set on every render
const trackedRef = useRef(new Set<string>());
// ✅ Do — initializer only runs once
const [tracked] = useState(() => new Set<string>());
```
```ts
// ❌ Don't — redundant type annotation
const value = someFunction() as SomeType;
// ✅ Do — let inference work
const value = someFunction();
```
## Show Output
Include expected output as comments when the result isn't obvious:
```ts
import type { InferSliceState } from '@videojs/store';
type VolumeState = InferSliceState<typeof volumeSlice>;
// { volume: number; setVolume: (value: number) => void }
const store = createStore<HTMLMediaElement>()(volumeSlice);
store.attach(videoElement);
const { volume } = store;
// volume: 1
```
## Error Examples
Show what errors look like and how to handle them:
```ts
import { isStoreError } from '@videojs/store';
try {
await store.play();
} catch (error) {
if (isStoreError(error)) {
switch (error.code) {
case 'NO_TARGET':
// No media element attached
break;
case 'DESTROYED':
// Store was destroyed
break;
}
}
}
```
## Filename Headers
Show which file code belongs to when multiple files are involved:
````markdown
```tsx title="App.tsx"
import { createPlayer, PlayButton } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';
import './App.css';
const Player = createPlayer({ features: videoFeatures });
export default function App() {
return (
<Player.Provider>
<Player.Container className="player">
<Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" />
<PlayButton />
</Player.Container>
</Player.Provider>
);
}
```
```css title="App.css"
.player {
--player-accent-color: #3b82f6;
}
```
````
## Realistic Values
```ts
// ❌ Meaningless
const slice = defineSlice<Foo>()({
state: () => ({ bar: 'baz' }),
});
// ✅ Realistic
const volumeSlice = defineSlice<HTMLMediaElement>()({
state: () => ({ volume: 1, muted: false }),
attach: ({ target, set, signal }) => {
const sync = () => set({ volume: target.volume, muted: target.muted });
sync();
target.addEventListener('volumechange', sync, { signal });
},
});
```
## Console Examples
For installation and CLI:
```bash
# Install the package
npm install @videojs/store
# Or with other package managers
pnpm add @videojs/store
```
## Demo Files (Site Pages)
Live demos in reference pages use the `<Demo>` component with `?raw` imports for source code display. Follow the neighboring generated-reference demo patterns.
```mdx
import BasicUsageDemo from "@/components/docs/demos/play-button/react/css/BasicUsage";
import basicUsageTsx from "@/components/docs/demos/play-button/react/css/BasicUsage.tsx?raw";
import basicUsageCss from "@/components/docs/demos/play-button/react/css/BasicUsage.css?raw";
<FrameworkCase frameworks={["react"]}>
<StyleCase styles={["css"]}>
<Demo files={[
{ title: "App.tsx", code: basicUsageTsx, lang: "tsx" },
{ title: "App.css", code: basicUsageCss, lang: "css" },
]}>
<BasicUsageDemo client:idle />
</Demo>
</StyleCase>
</FrameworkCase>
```
+274
View File
@@ -0,0 +1,274 @@
# Error Documentation Pattern
Document store errors consistently across Video.js packages.
---
## Error Code Reference Table
Always document errors in this format:
| Code | Meaning | Recovery |
| ------------ | ------------------------------------------- | ---------------------------------------------- |
| `ABORTED` | Request aborted via signal | Expected during cleanup — no action needed |
| `CANCELLED` | Cancelled by another request's `cancel: []` | Check request coordination |
| `SUPERSEDED` | Same-key request replaced this one | Expected during rapid input — no action needed |
| `REJECTED` | Guard returned falsy | Check preconditions, show user feedback |
| `TIMEOUT` | Guard timed out | Increase timeout or check target readiness |
| `NO_TARGET` | No target attached | Call `attach()` before making requests |
| `DETACHED` | Target was detached | Re-attach or abort operation |
| `DESTROYED` | Store was destroyed | Create new store instance |
---
## Expected vs Unexpected Errors
Document which errors are "normal" vs programming errors:
| Code | Expected? | Notes |
| ------------ | --------- | --------------------------------------------- |
| `SUPERSEDED` | Often | Rapid user input (scrubbing, repeated clicks) |
| `ABORTED` | Often | Component unmount, navigation |
| `CANCELLED` | Sometimes | Intentional coordination between requests |
| `REJECTED` | Sometimes | Guard logic blocking execution |
| `TIMEOUT` | Rarely | Slow media load, network issues |
| `NO_TARGET` | Never | Programming error — attach before use |
| `DETACHED` | Rarely | Lifecycle timing issue |
| `DESTROYED` | Never | Programming error — don't use after destroy |
---
## Error Handling Patterns
### Global Handler (store config)
```ts
const store = createStore({
features: [playbackFeature, volumeFeature],
onError: ({ error, request }) => {
if (request) {
console.error(`${request.name} failed:`, error.code);
}
// Report to analytics, show toast, etc.
},
});
```
### Local Handler (try/catch)
```ts
import { isStoreError } from '@videojs/store';
try {
await store.request.play();
} catch (error) {
if (isStoreError(error)) {
switch (error.code) {
case 'SUPERSEDED':
// Another request took over — expected, ignore
break;
case 'REJECTED':
// Guard blocked execution — show feedback
showMessage('Cannot play right now');
break;
case 'TIMEOUT':
// Took too long — retry or show error
showMessage('Media not ready');
break;
default:
console.error(`[${error.code}]`, error.message);
}
} else {
throw error; // Re-throw unknown errors
}
}
```
### Type Guard Pattern
Always show the type guard:
```ts
import { isStoreError } from '@videojs/store';
function handleError(error: unknown) {
if (isStoreError(error)) {
// error is StoreError — has .code, .message
return { code: error.code, message: error.message };
}
throw error;
}
```
---
## Troubleshooting Section Format
### Structure
1. Error code/message as heading
2. **Cause:** One sentence
3. **Solution:** Code example
### Examples
#### NO_TARGET
**Cause:** Request made before `attach()` was called.
**Solution:**
```ts
// ❌ Wrong
const store = createStore({ features: [playbackFeature] });
await store.request.play(); // Error: NO_TARGET
// ✅ Correct
const store = createStore({ features: [playbackFeature] });
store.attach(videoElement);
await store.request.play();
```
#### SUPERSEDED
**Cause:** Another request with the same key started before this one finished.
**Solution:** This is usually expected behavior. If you need the result, check before making a new request:
```ts
// If you need to know the final state
const result = await store.request.play();
// Result may be from a later request if superseded
// If you want to prevent supersession, use unique keys
request: {
trackEvent: {
key: () => Symbol(), // Each call gets unique key
handler: (data) => analytics.log(data),
},
}
```
#### REJECTED
**Cause:** A guard returned a falsy value.
**Solution:** Check what condition the guard expects:
```ts
// Guard that checks readyState
const canPlay: Guard<HTMLMediaElement> = ({ target }) => {
return target.readyState >= HTMLMediaElement.HAVE_ENOUGH_DATA;
};
// If rejected, media isn't ready — wait for canplay event
player.on('canplay', () => {
// Now safe to request play
store.request.play();
});
```
#### TIMEOUT
**Cause:** A guard didn't resolve within the timeout period.
**Solution:** Increase the timeout or ensure the target is ready:
```ts
import { timeout } from '@videojs/store';
request: {
play: {
// Increase timeout for slow connections
guard: timeout(canMediaPlay, 10000), // 10 seconds
handler: async (_, { target }) => {
await target.play();
},
},
}
```
#### ABORTED
**Cause:** The abort signal was triggered (usually from component unmount).
**Solution:** This is expected behavior. Ensure cleanup runs:
```ts
// React
useEffect(() => {
const controller = new AbortController();
store.request.play(null, { signal: controller.signal });
return () => controller.abort(); // Cleans up on unmount
}, []);
```
---
## API Reference Format
When documenting error-related APIs:
### isStoreError
Type guard for store errors.
```ts
import { isStoreError } from '@videojs/store';
if (isStoreError(error)) {
console.log(error.code); // 'ABORTED' | 'CANCELLED' | ...
}
```
#### Parameters
| Parameter | Type | Description |
| --------- | --------- | ---------------- |
| `error` | `unknown` | Any caught error |
#### Returns
`error is StoreError` — Type predicate
### StoreError
Error thrown by store operations.
#### Properties
| Property | Type | Description |
| --------- | ---------------- | -------------------------- |
| `code` | `StoreErrorCode` | Error classification |
| `message` | `string` | Human-readable description |
#### StoreErrorCode
```ts
type StoreErrorCode =
| 'ABORTED'
| 'CANCELLED'
| 'DESTROYED'
| 'DETACHED'
| 'NO_TARGET'
| 'REJECTED'
| 'SUPERSEDED'
| 'TIMEOUT';
```
---
## Checklist
When documenting errors:
- [ ] Error code table with all codes
- [ ] Expected vs unexpected classification
- [ ] Global handler example (onError)
- [ ] Local handler example (try/catch)
- [ ] Type guard usage shown
- [ ] Troubleshooting section for common errors
- [ ] Each troubleshooting entry has: Cause + Solution
- [ ] Code examples are self-contained