name: dev description: Develop and maintain the PWAFire PWA utilities library. Use when working on pwafire package, adding PWA APIs, fixing modules, writing tests, or contributing to the PWAFire codebase.
PWAFire Development
When to Apply
Use this skill when working on:
packages/pwafire/source code- PWA API modules (badging, clipboard, notifications, etc.)
- Tests, console app, or build configuration
- Any PWAFire contribution or maintenance
Core Principles
- No code comments - code is self-documenting
- Catch-and-return pattern - all PWA functions follow this
- Never throw errors - catch and return them
- Consistent response format:
{ ok: boolean, message: string, ...data? } - Minimal abstractions - KISS, DRY, YAGNI
Sync vs Async (IMPORTANT)
Use sync when the underlying browser API is synchronous:
- Property reads:
navigator.onLine,document.visibilityState,matchMedia().matches - Sync APIs:
new BroadcastChannel(),postMessage(),close() - Examples:
connectivity,visibility,displayMode,broadcast
Use async when the API returns a Promise or requires user interaction:
navigator.clipboard.*,navigator.share(),requestFullscreen(), file pickers, etc.- Rule: Match the underlying browser API. Sync → sync. Promise-returning → async.
Error Handling (Required Pattern)
Every PWA module function must use this structure (async when API is async):
export const apiName = async (...args) => {
try {
if (!featureAvailable) return { ok: false, message: "API not supported" };
const result = await someAPI(...args);
return { ok: true, message: "Success", ...data };
} catch (error) {
return {
ok: false,
message: error instanceof Error ? error.message : "Failed"
};
}
};
For sync APIs, omit async and await. Feature detection → { ok: false, message: "API not supported" }
- Success →
{ ok: true, message: "...", ...optionalData } - Error messages:
"Failed to {action}"or"{API} API not supported"
Naming Conventions
| Kind | Style | Examples |
|---|---|---|
| Functions/variables | camelCase | webShare, copyText |
| Files/directories | kebab-case | lazy-load, idle-detection |
| Constants | SCREAMING_SNAKE_CASE | MAX_RETRY_ATTEMPTS |
| Types | PascalCase | ResponseType, ConfigOptions |
- Check API names match main API:
check.webShare()forwebShare() - Verb-noun pattern:
screenSharenotscreenSharingControls
Experimental Browser APIs
The 7 ESLint any warnings are expected. Do not fix by defining custom interfaces.
Affected modules: barcode, contacts, content-indexing, files, idle-detection, screen.
Use unknown and as any for experimental APIs without TypeScript definitions.
Anti-Patterns
Do NOT:
- Add code comments
- Add try/catch in user-facing examples (built-in)
- Throw errors to consumers
- Hardcode test or feature lists (use dynamic generation)
- Define custom interfaces for browser APIs
- Use inconsistent naming between main and check APIs
Do:
- Handle all errors internally
- Use dynamic generation for tests and features
- Keep main and check API names aligned
Before Committing
cd packages/pwafire
npm run lint # 0 errors (7 warnings OK)
npm run build # CJS, ESM, DTS generated
npm test # All tests pass
Commit and PR Title Format
<type>(<scope>) - <description>
PR titles use the same format as commit messages.
Examples: feat(notifications) - add support for notification actions, fix(lazy-load) - prevent CSS injection
Project Structure
packages/pwafire/src/
├── pwa/ # One module per feature (e.g. badging/, clipboard/)
├── check/ # Feature detection utilities
├── index.ts # Main entry
└── types.d.ts # Minimal type definitions
- One primary export per file
- Named exports preferred
- Never commit
lib/(build output)
Detailed Docs
For full guidelines, see project docs:
Agents (style guides): docs/agents/
code-style.md- Formatting, type safetynaming-conventions.md- Naming rulesfile-organization.md- Module structurecommit-style.md- Commit and PR formattesting-style.md- Test patternsconsole.md- Console app
APIs: docs/apis/ - Unique API docs (passkey, broadcast, system)
system.md- Sync APIs (connectivity, visibility, displayMode)