@girardmedia/bootspring 3.3.2 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/assets/agents/accessibility-auditor.md +39 -0
  2. package/assets/agents/api-designer.md +40 -0
  3. package/assets/agents/auth-implementer.md +64 -0
  4. package/assets/agents/bug-hunter.md +42 -0
  5. package/assets/agents/bundle-analyzer.md +40 -0
  6. package/assets/agents/cache-optimizer.md +55 -0
  7. package/assets/agents/changelog-writer.md +55 -0
  8. package/assets/agents/ci-cd-builder.md +40 -0
  9. package/assets/agents/code-explainer.md +39 -0
  10. package/assets/agents/code-reviewer.md +39 -0
  11. package/assets/agents/cost-optimizer.md +57 -0
  12. package/assets/agents/cron-scheduler.md +51 -0
  13. package/assets/agents/data-seeder.md +56 -0
  14. package/assets/agents/database-architect.md +40 -0
  15. package/assets/agents/dependency-updater.md +40 -0
  16. package/assets/agents/deploy-checker.md +40 -0
  17. package/assets/agents/docker-optimizer.md +40 -0
  18. package/assets/agents/documentation-writer.md +40 -0
  19. package/assets/agents/email-builder.md +55 -0
  20. package/assets/agents/env-setup.md +40 -0
  21. package/assets/agents/error-handler.md +40 -0
  22. package/assets/agents/eslint-fixer.md +46 -0
  23. package/assets/agents/feature-flagger.md +69 -0
  24. package/assets/agents/git-detective.md +39 -0
  25. package/assets/agents/graphql-builder.md +60 -0
  26. package/assets/agents/incident-responder.md +59 -0
  27. package/assets/agents/log-analyzer.md +39 -0
  28. package/assets/agents/migration-planner.md +41 -0
  29. package/assets/agents/monorepo-navigator.md +39 -0
  30. package/assets/agents/nextjs-expert.md +57 -0
  31. package/assets/agents/notification-builder.md +56 -0
  32. package/assets/agents/onboarding-guide.md +39 -0
  33. package/assets/agents/performance-profiler.md +40 -0
  34. package/assets/agents/prisma-expert.md +57 -0
  35. package/assets/agents/rate-limiter.md +58 -0
  36. package/assets/agents/react-expert.md +58 -0
  37. package/assets/agents/refactorer.md +42 -0
  38. package/assets/agents/regex-builder.md +46 -0
  39. package/assets/agents/release-manager.md +40 -0
  40. package/assets/agents/s3-manager.md +58 -0
  41. package/assets/agents/schema-validator.md +40 -0
  42. package/assets/agents/search-builder.md +62 -0
  43. package/assets/agents/security-auditor.md +39 -0
  44. package/assets/agents/sitemap-generator.md +53 -0
  45. package/assets/agents/stripe-integrator.md +59 -0
  46. package/assets/agents/tailwind-expert.md +55 -0
  47. package/assets/agents/tech-debt-tracker.md +39 -0
  48. package/assets/agents/test-writer.md +42 -0
  49. package/assets/agents/type-fixer.md +45 -0
  50. package/assets/agents/webhook-builder.md +54 -0
  51. package/assets/rules/cpp.md +53 -0
  52. package/assets/rules/css.md +52 -0
  53. package/assets/rules/go.md +50 -0
  54. package/assets/rules/html.md +52 -0
  55. package/assets/rules/java.md +51 -0
  56. package/assets/rules/kotlin.md +50 -0
  57. package/assets/rules/php.md +51 -0
  58. package/assets/rules/python.md +51 -0
  59. package/assets/rules/ruby.md +51 -0
  60. package/assets/rules/rust.md +49 -0
  61. package/assets/rules/shell.md +52 -0
  62. package/assets/rules/sql.md +49 -0
  63. package/assets/rules/swift.md +50 -0
  64. package/assets/rules/typescript.md +52 -0
  65. package/assets/rules/yaml-json.md +51 -0
  66. package/assets/skills/accessibility.md +210 -0
  67. package/assets/skills/agent-patterns.md +387 -0
  68. package/assets/skills/ai-integration.md +263 -0
  69. package/assets/skills/animation-patterns.md +224 -0
  70. package/assets/skills/api-design.md +218 -0
  71. package/assets/skills/api-gateway.md +341 -0
  72. package/assets/skills/api-versioning.md +226 -0
  73. package/assets/skills/astro-patterns.md +233 -0
  74. package/assets/skills/auth-patterns.md +248 -0
  75. package/assets/skills/aws-patterns.md +171 -0
  76. package/assets/skills/background-jobs.md +162 -0
  77. package/assets/skills/browser-extensions.md +309 -0
  78. package/assets/skills/caching-patterns.md +253 -0
  79. package/assets/skills/ci-cd.md +251 -0
  80. package/assets/skills/cli-development.md +296 -0
  81. package/assets/skills/code-review.md +185 -0
  82. package/assets/skills/cron-patterns.md +327 -0
  83. package/assets/skills/data-fetching.md +231 -0
  84. package/assets/skills/database-migrations.md +346 -0
  85. package/assets/skills/database-patterns.md +219 -0
  86. package/assets/skills/debugging.md +281 -0
  87. package/assets/skills/design-system.md +289 -0
  88. package/assets/skills/django-patterns.md +182 -0
  89. package/assets/skills/docker-patterns.md +235 -0
  90. package/assets/skills/e2e-testing.md +287 -0
  91. package/assets/skills/edge-computing.md +268 -0
  92. package/assets/skills/electron-patterns.md +266 -0
  93. package/assets/skills/email-templates.md +206 -0
  94. package/assets/skills/error-handling.md +265 -0
  95. package/assets/skills/event-driven.md +232 -0
  96. package/assets/skills/express-patterns.md +239 -0
  97. package/assets/skills/fastapi-patterns.md +198 -0
  98. package/assets/skills/feature-flags.md +212 -0
  99. package/assets/skills/figma-to-code.md +298 -0
  100. package/assets/skills/file-upload.md +228 -0
  101. package/assets/skills/forms-patterns.md +264 -0
  102. package/assets/skills/gcp-patterns.md +189 -0
  103. package/assets/skills/git-workflow.md +187 -0
  104. package/assets/skills/golang-patterns.md +185 -0
  105. package/assets/skills/graphql-patterns.md +244 -0
  106. package/assets/skills/i18n-patterns.md +172 -0
  107. package/assets/skills/image-processing.md +350 -0
  108. package/assets/skills/java-springboot.md +226 -0
  109. package/assets/skills/kotlin-patterns.md +207 -0
  110. package/assets/skills/kubernetes-patterns.md +326 -0
  111. package/assets/skills/laravel-patterns.md +261 -0
  112. package/assets/skills/llm-fine-tuning.md +335 -0
  113. package/assets/skills/load-testing.md +303 -0
  114. package/assets/skills/logging-observability.md +228 -0
  115. package/assets/skills/markdown-processing.md +318 -0
  116. package/assets/skills/mcp-server-patterns.md +292 -0
  117. package/assets/skills/microservices.md +272 -0
  118. package/assets/skills/migration-patterns.md +239 -0
  119. package/assets/skills/mongodb-patterns.md +189 -0
  120. package/assets/skills/monorepo-patterns.md +287 -0
  121. package/assets/skills/nextjs-app-router.md +237 -0
  122. package/assets/skills/notification-patterns.md +348 -0
  123. package/assets/skills/oauth-patterns.md +246 -0
  124. package/assets/skills/payment-integration.md +222 -0
  125. package/assets/skills/pdf-generation.md +307 -0
  126. package/assets/skills/performance-optimization.md +277 -0
  127. package/assets/skills/php-patterns.md +210 -0
  128. package/assets/skills/prisma-patterns.md +241 -0
  129. package/assets/skills/prompt-engineering.md +193 -0
  130. package/assets/skills/pwa-patterns.md +247 -0
  131. package/assets/skills/python-patterns.md +158 -0
  132. package/assets/skills/python-testing.md +172 -0
  133. package/assets/skills/queue-patterns.md +295 -0
  134. package/assets/skills/rag-patterns.md +159 -0
  135. package/assets/skills/rate-limiting.md +319 -0
  136. package/assets/skills/react-components.md +201 -0
  137. package/assets/skills/react-native-patterns.md +299 -0
  138. package/assets/skills/real-time-patterns.md +181 -0
  139. package/assets/skills/redis-patterns.md +188 -0
  140. package/assets/skills/refactoring.md +218 -0
  141. package/assets/skills/regex-patterns.md +191 -0
  142. package/assets/skills/remix-patterns.md +262 -0
  143. package/assets/skills/responsive-design.md +199 -0
  144. package/assets/skills/ruby-rails-patterns.md +178 -0
  145. package/assets/skills/rust-patterns.md +211 -0
  146. package/assets/skills/search-patterns.md +227 -0
  147. package/assets/skills/security-hardening.md +237 -0
  148. package/assets/skills/seo-patterns.md +179 -0
  149. package/assets/skills/serverless-patterns.md +223 -0
  150. package/assets/skills/sql-optimization.md +154 -0
  151. package/assets/skills/state-management.md +254 -0
  152. package/assets/skills/storybook-patterns.md +330 -0
  153. package/assets/skills/svelte-patterns.md +258 -0
  154. package/assets/skills/swift-patterns.md +227 -0
  155. package/assets/skills/tailwind-patterns.md +272 -0
  156. package/assets/skills/tdd-workflow.md +199 -0
  157. package/assets/skills/terraform-patterns.md +270 -0
  158. package/assets/skills/testing-react.md +240 -0
  159. package/assets/skills/testing-vitest.md +232 -0
  160. package/assets/skills/typescript-strict.md +159 -0
  161. package/assets/skills/video-processing.md +340 -0
  162. package/assets/skills/vue-patterns.md +247 -0
  163. package/assets/skills/web-workers.md +327 -0
  164. package/assets/skills/webhooks-patterns.md +283 -0
  165. package/assets/skills/websocket-patterns.md +306 -0
  166. package/dist/cli/index.js +941 -958
  167. package/dist/core/index.d.ts +341 -11
  168. package/dist/core.js +58 -95
  169. package/dist/mcp/index.d.ts +33 -1
  170. package/dist/mcp-server.js +177 -255
  171. package/package.json +4 -1
@@ -0,0 +1,268 @@
1
+ ---
2
+ name: edge-computing
3
+ description: Edge computing patterns for Cloudflare Workers, edge middleware, geolocation routing, KV storage, and Durable Objects.
4
+ ---
5
+
6
+ # Edge Computing Patterns
7
+
8
+ ## When to Use
9
+ Deploy logic to the edge when you need sub-50ms response times globally, geolocation-based routing, request transformation before reaching origin servers, or lightweight compute that does not require a full server. Edge functions are ideal for A/B testing, auth token validation, redirects, rate limiting, and personalization. Avoid edge for CPU-heavy workloads or anything requiring persistent connections to a single database.
10
+
11
+ ## How It Works
12
+
13
+ ### Cloudflare Worker Basics
14
+
15
+ ```typescript
16
+ // src/worker.ts
17
+ export interface Env {
18
+ MY_KV: KVNamespace;
19
+ MY_R2: R2Bucket;
20
+ API_KEY: string;
21
+ }
22
+
23
+ export default {
24
+ async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
25
+ const url = new URL(request.url);
26
+
27
+ // Route to handlers
28
+ if (url.pathname.startsWith('/api/')) return handleAPI(request, env, ctx);
29
+ if (url.pathname === '/health') return new Response('ok', { status: 200 });
30
+
31
+ return new Response('Not found', { status: 404 });
32
+ },
33
+ } satisfies ExportedHandler<Env>;
34
+
35
+ async function handleAPI(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
36
+ // Verify API key
37
+ const apiKey = request.headers.get('X-API-Key');
38
+ if (apiKey !== env.API_KEY) {
39
+ return Response.json({ error: 'Unauthorized' }, { status: 401 });
40
+ }
41
+
42
+ const data = await env.MY_KV.get('cache:data', 'json');
43
+ return Response.json(data ?? { items: [] });
44
+ }
45
+ ```
46
+
47
+ ### Edge Middleware (Next.js / Vercel)
48
+
49
+ ```typescript
50
+ // middleware.ts (project root)
51
+ import { NextRequest, NextResponse } from 'next/server';
52
+
53
+ export function middleware(request: NextRequest) {
54
+ const { pathname, searchParams } = request.nextUrl;
55
+ const country = request.geo?.country ?? 'US';
56
+ const city = request.geo?.city ?? 'Unknown';
57
+
58
+ // Geolocation-based redirect
59
+ if (pathname === '/' && country === 'DE') {
60
+ return NextResponse.redirect(new URL('/de', request.url));
61
+ }
62
+
63
+ // A/B testing via cookie
64
+ const bucket = request.cookies.get('ab-bucket')?.value;
65
+ if (!bucket && pathname === '/pricing') {
66
+ const assigned = Math.random() < 0.5 ? 'control' : 'variant';
67
+ const response = NextResponse.rewrite(
68
+ new URL(`/pricing/${assigned}`, request.url)
69
+ );
70
+ response.cookies.set('ab-bucket', assigned, { maxAge: 60 * 60 * 24 * 30 });
71
+ return response;
72
+ }
73
+
74
+ // Add custom headers
75
+ const response = NextResponse.next();
76
+ response.headers.set('X-Country', country);
77
+ response.headers.set('X-City', city);
78
+ return response;
79
+ }
80
+
81
+ export const config = {
82
+ matcher: ['/', '/pricing/:path*', '/api/:path*'],
83
+ };
84
+ ```
85
+
86
+ ### KV Storage Patterns
87
+
88
+ ```typescript
89
+ // src/kv-cache.ts
90
+ export async function cachedFetch(
91
+ kv: KVNamespace,
92
+ cacheKey: string,
93
+ fetcher: () => Promise<unknown>,
94
+ ttlSeconds: number = 300
95
+ ): Promise<unknown> {
96
+ // Try KV cache first
97
+ const cached = await kv.get(cacheKey, 'json');
98
+ if (cached !== null) return cached;
99
+
100
+ // Fetch from origin
101
+ const data = await fetcher();
102
+
103
+ // Store in KV with TTL (non-blocking)
104
+ await kv.put(cacheKey, JSON.stringify(data), {
105
+ expirationTtl: ttlSeconds,
106
+ });
107
+
108
+ return data;
109
+ }
110
+
111
+ // KV with metadata for cache management
112
+ export async function putWithMetadata(
113
+ kv: KVNamespace,
114
+ key: string,
115
+ value: unknown,
116
+ metadata: { version: number; source: string }
117
+ ) {
118
+ await kv.put(key, JSON.stringify(value), {
119
+ expirationTtl: 3600,
120
+ metadata,
121
+ });
122
+ }
123
+
124
+ export async function getWithMetadata(kv: KVNamespace, key: string) {
125
+ const { value, metadata } = await kv.getWithMetadata<{ version: number; source: string }>(
126
+ key, 'json'
127
+ );
128
+ return { data: value, metadata };
129
+ }
130
+ ```
131
+
132
+ ### Durable Objects (Stateful Edge)
133
+
134
+ ```typescript
135
+ // src/rate-limiter.ts
136
+ export class RateLimiter implements DurableObject {
137
+ private requests: number[] = [];
138
+ private readonly limit = 100;
139
+ private readonly windowMs = 60_000;
140
+
141
+ constructor(private state: DurableObjectState, private env: Env) {}
142
+
143
+ async fetch(request: Request): Promise<Response> {
144
+ const now = Date.now();
145
+
146
+ // Load state
147
+ this.requests = (await this.state.storage.get<number[]>('requests')) ?? [];
148
+
149
+ // Prune old entries
150
+ this.requests = this.requests.filter((t) => now - t < this.windowMs);
151
+
152
+ if (this.requests.length >= this.limit) {
153
+ const retryAfter = Math.ceil((this.requests[0] + this.windowMs - now) / 1000);
154
+ return new Response('Rate limit exceeded', {
155
+ status: 429,
156
+ headers: {
157
+ 'Retry-After': String(retryAfter),
158
+ 'X-RateLimit-Limit': String(this.limit),
159
+ 'X-RateLimit-Remaining': '0',
160
+ },
161
+ });
162
+ }
163
+
164
+ this.requests.push(now);
165
+ await this.state.storage.put('requests', this.requests);
166
+
167
+ return Response.json({
168
+ remaining: this.limit - this.requests.length,
169
+ limit: this.limit,
170
+ });
171
+ }
172
+ }
173
+
174
+ // Worker entry — route to Durable Object
175
+ export default {
176
+ async fetch(request: Request, env: Env): Promise<Response> {
177
+ const ip = request.headers.get('CF-Connecting-IP') ?? 'unknown';
178
+ const id = env.RATE_LIMITER.idFromName(ip);
179
+ const stub = env.RATE_LIMITER.get(id);
180
+ return stub.fetch(request);
181
+ },
182
+ };
183
+ ```
184
+
185
+ ### R2 Object Storage at the Edge
186
+
187
+ ```typescript
188
+ // src/r2-handler.ts
189
+ export async function handleR2(request: Request, env: Env): Promise<Response> {
190
+ const url = new URL(request.url);
191
+ const key = url.pathname.slice(1); // remove leading /
192
+
193
+ if (request.method === 'GET') {
194
+ const object = await env.MY_R2.get(key);
195
+ if (!object) return new Response('Not found', { status: 404 });
196
+
197
+ return new Response(object.body, {
198
+ headers: {
199
+ 'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream',
200
+ 'ETag': object.etag,
201
+ 'Cache-Control': 'public, max-age=31536000, immutable',
202
+ },
203
+ });
204
+ }
205
+
206
+ if (request.method === 'PUT') {
207
+ const contentType = request.headers.get('Content-Type') ?? 'application/octet-stream';
208
+ await env.MY_R2.put(key, request.body, {
209
+ httpMetadata: { contentType },
210
+ });
211
+ return new Response('Created', { status: 201 });
212
+ }
213
+
214
+ return new Response('Method not allowed', { status: 405 });
215
+ }
216
+ ```
217
+
218
+ ### Geolocation-Based Content
219
+
220
+ ```typescript
221
+ // src/geo-router.ts
222
+ interface GeoConfig {
223
+ country: string;
224
+ redirects: Record<string, string>;
225
+ blockedCountries: string[];
226
+ }
227
+
228
+ export function geoRoute(request: Request, cf: IncomingRequestCfProperties): Response | null {
229
+ const country = cf.country ?? 'US';
230
+ const continent = cf.continent ?? 'NA';
231
+
232
+ // Block sanctioned regions
233
+ const blocked = ['KP', 'IR', 'SY'];
234
+ if (blocked.includes(country)) {
235
+ return new Response('Service unavailable in your region', { status: 451 });
236
+ }
237
+
238
+ // Inject geolocation headers for downstream
239
+ const headers = new Headers();
240
+ headers.set('X-Geo-Country', country);
241
+ headers.set('X-Geo-Continent', continent);
242
+ headers.set('X-Geo-City', cf.city ?? 'Unknown');
243
+ headers.set('X-Geo-Latitude', String(cf.latitude ?? 0));
244
+ headers.set('X-Geo-Longitude', String(cf.longitude ?? 0));
245
+
246
+ return null; // continue to origin with headers
247
+ }
248
+ ```
249
+
250
+ ## Examples
251
+
252
+ | Pattern | Latency | State | Use Case |
253
+ |---------|---------|-------|----------|
254
+ | KV cache | ~10ms global | Eventually consistent | Config, feature flags, cached API |
255
+ | Durable Object | ~20ms | Strongly consistent | Rate limiting, counters, sessions |
256
+ | R2 storage | ~50ms | Strongly consistent | File uploads, static assets |
257
+ | Edge middleware | ~1ms overhead | Stateless | Auth, redirects, headers |
258
+ | Worker fetch | ~5ms cold start | Stateless | API proxy, transformation |
259
+
260
+ ## Checklist
261
+ - [ ] Workers handle errors gracefully and return proper HTTP status codes
262
+ - [ ] KV keys include version or TTL metadata for cache invalidation
263
+ - [ ] Durable Objects used only when strong consistency is required
264
+ - [ ] Geolocation checks use `request.cf` (Cloudflare) or `request.geo` (Vercel)
265
+ - [ ] R2 responses include Cache-Control and ETag headers
266
+ - [ ] Sensitive logic (API keys, auth) runs at the edge, not in client
267
+ - [ ] Worker bundle size stays under 1MB (compressed) for fast cold starts
268
+ - [ ] `waitUntil()` used for non-blocking background work
@@ -0,0 +1,266 @@
1
+ ---
2
+ name: electron-patterns
3
+ description: Build Electron apps — IPC communication, preload scripts, auto-update, window management, security, and packaging.
4
+ ---
5
+
6
+ # Electron Patterns
7
+
8
+ ## When to Use
9
+
10
+ Use Electron when building cross-platform desktop applications with web
11
+ technologies. Covers the critical security boundary between main and renderer
12
+ processes, IPC communication, preload scripts for safe API exposure,
13
+ auto-updates, window management, and packaging for distribution. Apply these
14
+ patterns from the start — Electron security mistakes are hard to retrofit.
15
+
16
+ ## How It Works
17
+
18
+ ### 1. Process Architecture
19
+
20
+ Electron has two process types. Never bypass this boundary.
21
+
22
+ ```
23
+ Main Process (Node.js) Renderer Process (Chromium)
24
+ |- File system access |- UI rendering
25
+ |- Native APIs |- DOM manipulation
26
+ |- Window management |- Web APIs only
27
+ |- System tray +- No Node.js (when secure)
28
+ +- IPC handler
29
+ <-> IPC bridge (preload.ts)
30
+ ```
31
+
32
+ ### 2. Preload Script — Safe API Surface
33
+
34
+ ```typescript
35
+ // preload.ts — runs in renderer context with Node.js access
36
+ import { contextBridge, ipcRenderer } from 'electron';
37
+
38
+ contextBridge.exposeInMainWorld('electronAPI', {
39
+ // File operations — exposed as async functions
40
+ readFile: (path: string) => ipcRenderer.invoke('file:read', path),
41
+ writeFile: (path: string, data: string) => ipcRenderer.invoke('file:write', path, data),
42
+ selectFile: () => ipcRenderer.invoke('dialog:openFile'),
43
+
44
+ // App info
45
+ getVersion: () => ipcRenderer.invoke('app:version'),
46
+
47
+ // One-way events (renderer -> main)
48
+ minimize: () => ipcRenderer.send('window:minimize'),
49
+ maximize: () => ipcRenderer.send('window:maximize'),
50
+
51
+ // Subscriptions (main -> renderer)
52
+ onUpdateAvailable: (callback: (info: UpdateInfo) => void) => {
53
+ const handler = (_event: Event, info: UpdateInfo) => callback(info);
54
+ ipcRenderer.on('update:available', handler);
55
+ return () => ipcRenderer.removeListener('update:available', handler);
56
+ },
57
+ });
58
+ ```
59
+
60
+ ```typescript
61
+ // Type declaration for renderer
62
+ declare global {
63
+ interface Window {
64
+ electronAPI: {
65
+ readFile: (path: string) => Promise<string>;
66
+ writeFile: (path: string, data: string) => Promise<void>;
67
+ selectFile: () => Promise<string | null>;
68
+ getVersion: () => Promise<string>;
69
+ minimize: () => void;
70
+ maximize: () => void;
71
+ onUpdateAvailable: (callback: (info: UpdateInfo) => void) => () => void;
72
+ };
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### 3. IPC Handlers — Main Process
78
+
79
+ ```typescript
80
+ // main.ts
81
+ import { app, BrowserWindow, ipcMain, dialog } from 'electron';
82
+ import fs from 'fs/promises';
83
+ import path from 'path';
84
+
85
+ // Invoke handlers (bidirectional — returns a value)
86
+ ipcMain.handle('file:read', async (_event, filePath: string) => {
87
+ // Validate path to prevent directory traversal
88
+ const resolved = path.resolve(filePath);
89
+ if (!resolved.startsWith(app.getPath('userData'))) {
90
+ throw new Error('Access denied: path outside user data directory');
91
+ }
92
+ return fs.readFile(resolved, 'utf-8');
93
+ });
94
+
95
+ ipcMain.handle('dialog:openFile', async () => {
96
+ const result = await dialog.showOpenDialog({
97
+ properties: ['openFile'],
98
+ filters: [{ name: 'Text', extensions: ['txt', 'md', 'json'] }],
99
+ });
100
+ return result.canceled ? null : result.filePaths[0];
101
+ });
102
+
103
+ ipcMain.handle('app:version', () => app.getVersion());
104
+
105
+ // One-way handlers
106
+ ipcMain.on('window:minimize', (event) => {
107
+ BrowserWindow.fromWebContents(event.sender)?.minimize();
108
+ });
109
+ ```
110
+
111
+ ### 4. Window Management
112
+
113
+ ```typescript
114
+ function createMainWindow(): BrowserWindow {
115
+ const win = new BrowserWindow({
116
+ width: 1200,
117
+ height: 800,
118
+ minWidth: 800,
119
+ minHeight: 600,
120
+ titleBarStyle: 'hiddenInset', // macOS frameless with traffic lights
121
+ webPreferences: {
122
+ preload: path.join(__dirname, 'preload.js'),
123
+ contextIsolation: true, // REQUIRED — never disable
124
+ nodeIntegration: false, // REQUIRED — never enable
125
+ sandbox: true, // extra isolation
126
+ },
127
+ });
128
+
129
+ // Save/restore window position
130
+ const bounds = store.get('windowBounds');
131
+ if (bounds) win.setBounds(bounds);
132
+
133
+ win.on('close', () => {
134
+ store.set('windowBounds', win.getBounds());
135
+ });
136
+
137
+ if (isDev) {
138
+ win.loadURL('http://localhost:3000');
139
+ win.webContents.openDevTools();
140
+ } else {
141
+ win.loadFile(path.join(__dirname, '../renderer/index.html'));
142
+ }
143
+
144
+ return win;
145
+ }
146
+ ```
147
+
148
+ ### 5. Auto-Update
149
+
150
+ ```typescript
151
+ import { autoUpdater } from 'electron-updater';
152
+ import log from 'electron-log';
153
+
154
+ autoUpdater.logger = log;
155
+ autoUpdater.autoDownload = false; // let user decide
156
+
157
+ export function setupAutoUpdater(mainWindow: BrowserWindow) {
158
+ autoUpdater.on('update-available', (info) => {
159
+ mainWindow.webContents.send('update:available', {
160
+ version: info.version,
161
+ releaseNotes: info.releaseNotes,
162
+ });
163
+ });
164
+
165
+ autoUpdater.on('download-progress', (progress) => {
166
+ mainWindow.webContents.send('update:progress', {
167
+ percent: progress.percent,
168
+ });
169
+ });
170
+
171
+ autoUpdater.on('update-downloaded', () => {
172
+ mainWindow.webContents.send('update:ready');
173
+ });
174
+
175
+ // Check every 4 hours
176
+ setInterval(() => autoUpdater.checkForUpdates(), 4 * 60 * 60 * 1000);
177
+ autoUpdater.checkForUpdates();
178
+ }
179
+
180
+ // IPC handler for user-initiated download/install
181
+ ipcMain.handle('update:download', () => autoUpdater.downloadUpdate());
182
+ ipcMain.handle('update:install', () => autoUpdater.quitAndInstall());
183
+ ```
184
+
185
+ ### 6. Security Hardening
186
+
187
+ ```typescript
188
+ // main.ts — security headers
189
+ app.on('web-contents-created', (_event, contents) => {
190
+ // Prevent navigation away from the app
191
+ contents.on('will-navigate', (event, url) => {
192
+ const parsed = new URL(url);
193
+ if (parsed.origin !== 'http://localhost:3000' && parsed.protocol !== 'file:') {
194
+ event.preventDefault();
195
+ }
196
+ });
197
+
198
+ // Prevent new windows (open links in default browser)
199
+ contents.setWindowOpenHandler(({ url }) => {
200
+ shell.openExternal(url);
201
+ return { action: 'deny' };
202
+ });
203
+ });
204
+
205
+ // Content Security Policy
206
+ session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
207
+ callback({
208
+ responseHeaders: {
209
+ ...details.responseHeaders,
210
+ 'Content-Security-Policy': [
211
+ "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
212
+ ],
213
+ },
214
+ });
215
+ });
216
+ ```
217
+
218
+ ### 7. Packaging — electron-builder
219
+
220
+ ```json
221
+ {
222
+ "build": {
223
+ "appId": "com.myapp.desktop",
224
+ "productName": "MyApp",
225
+ "mac": {
226
+ "target": ["dmg", "zip"],
227
+ "category": "public.app-category.developer-tools",
228
+ "hardenedRuntime": true,
229
+ "notarize": true
230
+ },
231
+ "win": {
232
+ "target": ["nsis"],
233
+ "certificateSubjectName": "My Company"
234
+ },
235
+ "linux": {
236
+ "target": ["AppImage", "deb"],
237
+ "category": "Development"
238
+ },
239
+ "publish": {
240
+ "provider": "github"
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
246
+ ## Examples
247
+
248
+ | Pattern | Process | Purpose |
249
+ |---------|---------|---------|
250
+ | `contextBridge.exposeInMainWorld` | Preload | Safe API for renderer |
251
+ | `ipcMain.handle` / `ipcRenderer.invoke` | Main/Renderer | Bidirectional async IPC |
252
+ | `autoUpdater` | Main | Seamless updates |
253
+ | `BrowserWindow` options | Main | Security + UX config |
254
+
255
+ ## Checklist
256
+
257
+ - [ ] `contextIsolation: true` and `nodeIntegration: false` on all windows
258
+ - [ ] `sandbox: true` enabled for extra process isolation
259
+ - [ ] All renderer-to-main communication goes through preload + IPC
260
+ - [ ] IPC handlers validate and sanitize all arguments
261
+ - [ ] File paths validated against allowed directories (no traversal)
262
+ - [ ] Navigation and new-window events restricted
263
+ - [ ] CSP headers set to prevent XSS
264
+ - [ ] Auto-updater configured with code signing
265
+ - [ ] macOS builds notarized, Windows builds code-signed
266
+ - [ ] Dev tools disabled in production builds