@prmichaelsen/acp-visualizer 0.1.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 (180) hide show
  1. package/README.md +68 -0
  2. package/agent/commands/acp.clarification-address.md +417 -0
  3. package/agent/commands/acp.clarification-capture.md +386 -0
  4. package/agent/commands/acp.clarification-create.md +437 -0
  5. package/agent/commands/acp.clarifications-research.md +326 -0
  6. package/agent/commands/acp.command-create.md +432 -0
  7. package/agent/commands/acp.design-create.md +286 -0
  8. package/agent/commands/acp.design-reference.md +355 -0
  9. package/agent/commands/acp.handoff.md +270 -0
  10. package/agent/commands/acp.index.md +423 -0
  11. package/agent/commands/acp.init.md +546 -0
  12. package/agent/commands/acp.package-create.md +895 -0
  13. package/agent/commands/acp.package-info.md +212 -0
  14. package/agent/commands/acp.package-install.md +539 -0
  15. package/agent/commands/acp.package-list.md +280 -0
  16. package/agent/commands/acp.package-publish.md +541 -0
  17. package/agent/commands/acp.package-remove.md +293 -0
  18. package/agent/commands/acp.package-search.md +307 -0
  19. package/agent/commands/acp.package-update.md +361 -0
  20. package/agent/commands/acp.package-validate.md +540 -0
  21. package/agent/commands/acp.pattern-create.md +386 -0
  22. package/agent/commands/acp.plan.md +587 -0
  23. package/agent/commands/acp.proceed.md +882 -0
  24. package/agent/commands/acp.project-create.md +675 -0
  25. package/agent/commands/acp.project-info.md +312 -0
  26. package/agent/commands/acp.project-list.md +226 -0
  27. package/agent/commands/acp.project-remove.md +379 -0
  28. package/agent/commands/acp.project-set.md +227 -0
  29. package/agent/commands/acp.project-update.md +307 -0
  30. package/agent/commands/acp.projects-restore.md +228 -0
  31. package/agent/commands/acp.projects-sync.md +347 -0
  32. package/agent/commands/acp.report.md +407 -0
  33. package/agent/commands/acp.resume.md +239 -0
  34. package/agent/commands/acp.sessions.md +301 -0
  35. package/agent/commands/acp.status.md +293 -0
  36. package/agent/commands/acp.sync.md +364 -0
  37. package/agent/commands/acp.task-create.md +500 -0
  38. package/agent/commands/acp.update.md +302 -0
  39. package/agent/commands/acp.validate.md +466 -0
  40. package/agent/commands/acp.version-check-for-updates.md +276 -0
  41. package/agent/commands/acp.version-check.md +191 -0
  42. package/agent/commands/acp.version-update.md +289 -0
  43. package/agent/commands/command.template.md +339 -0
  44. package/agent/commands/git.commit.md +526 -0
  45. package/agent/commands/git.init.md +514 -0
  46. package/agent/commands/tanstack-cloudflare.deploy.md +272 -0
  47. package/agent/commands/tanstack-cloudflare.tail.md +275 -0
  48. package/agent/design/.gitkeep +0 -0
  49. package/agent/design/design.template.md +154 -0
  50. package/agent/design/local.dashboard-layout-routing.md +288 -0
  51. package/agent/design/local.data-model-yaml-parsing.md +310 -0
  52. package/agent/design/local.search-filtering.md +331 -0
  53. package/agent/design/local.server-api-auto-refresh.md +235 -0
  54. package/agent/design/local.table-tree-views.md +299 -0
  55. package/agent/design/local.visualizer-requirements.md +349 -0
  56. package/agent/design/requirements.template.md +387 -0
  57. package/agent/index/.gitkeep +0 -0
  58. package/agent/index/acp.core.yaml +137 -0
  59. package/agent/index/local.main.template.yaml +37 -0
  60. package/agent/manifest.template.yaml +13 -0
  61. package/agent/manifest.yaml +302 -0
  62. package/agent/milestones/.gitkeep +0 -0
  63. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +67 -0
  64. package/agent/milestones/milestone-1-{title}.template.md +206 -0
  65. package/agent/milestones/milestone-2-dashboard-views-interaction.md +79 -0
  66. package/agent/package.template.yaml +86 -0
  67. package/agent/patterns/.gitkeep +0 -0
  68. package/agent/patterns/bootstrap.template.md +1237 -0
  69. package/agent/patterns/pattern.template.md +382 -0
  70. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +332 -0
  71. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +416 -0
  72. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +401 -0
  73. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +387 -0
  74. package/agent/patterns/tanstack-cloudflare.card-and-list.md +271 -0
  75. package/agent/patterns/tanstack-cloudflare.chat-engine.md +353 -0
  76. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +346 -0
  77. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +516 -0
  78. package/agent/patterns/tanstack-cloudflare.email-service.md +431 -0
  79. package/agent/patterns/tanstack-cloudflare.expander.md +98 -0
  80. package/agent/patterns/tanstack-cloudflare.fcm-push.md +115 -0
  81. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +441 -0
  82. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +348 -0
  83. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +550 -0
  84. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +369 -0
  85. package/agent/patterns/tanstack-cloudflare.form-controls.md +145 -0
  86. package/agent/patterns/tanstack-cloudflare.global-search-context.md +93 -0
  87. package/agent/patterns/tanstack-cloudflare.image-carousel.md +126 -0
  88. package/agent/patterns/tanstack-cloudflare.library-services.md +553 -0
  89. package/agent/patterns/tanstack-cloudflare.lightbox.md +169 -0
  90. package/agent/patterns/tanstack-cloudflare.markdown-content.md +115 -0
  91. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +98 -0
  92. package/agent/patterns/tanstack-cloudflare.modal.md +156 -0
  93. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +461 -0
  94. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +151 -0
  95. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +90 -0
  96. package/agent/patterns/tanstack-cloudflare.og-metadata.md +296 -0
  97. package/agent/patterns/tanstack-cloudflare.pagination.md +442 -0
  98. package/agent/patterns/tanstack-cloudflare.pill-input.md +220 -0
  99. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +401 -0
  100. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +323 -0
  101. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +338 -0
  102. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +375 -0
  103. package/agent/patterns/tanstack-cloudflare.slide-over.md +129 -0
  104. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +571 -0
  105. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +508 -0
  106. package/agent/patterns/tanstack-cloudflare.toast-system.md +142 -0
  107. package/agent/patterns/tanstack-cloudflare.unified-header.md +280 -0
  108. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +628 -0
  109. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +237 -0
  110. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +358 -0
  111. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +336 -0
  112. package/agent/progress.template.yaml +161 -0
  113. package/agent/progress.yaml +145 -0
  114. package/agent/schemas/package.schema.yaml +276 -0
  115. package/agent/scripts/acp.common.sh +1781 -0
  116. package/agent/scripts/acp.install.sh +333 -0
  117. package/agent/scripts/acp.package-create.sh +924 -0
  118. package/agent/scripts/acp.package-info.sh +288 -0
  119. package/agent/scripts/acp.package-install.sh +893 -0
  120. package/agent/scripts/acp.package-list.sh +311 -0
  121. package/agent/scripts/acp.package-publish.sh +420 -0
  122. package/agent/scripts/acp.package-remove.sh +348 -0
  123. package/agent/scripts/acp.package-search.sh +156 -0
  124. package/agent/scripts/acp.package-update.sh +517 -0
  125. package/agent/scripts/acp.package-validate.sh +1018 -0
  126. package/agent/scripts/acp.uninstall.sh +85 -0
  127. package/agent/scripts/acp.version-check-for-updates.sh +98 -0
  128. package/agent/scripts/acp.version-check.sh +47 -0
  129. package/agent/scripts/acp.version-update.sh +176 -0
  130. package/agent/scripts/acp.yaml-parser.sh +985 -0
  131. package/agent/scripts/acp.yaml-validate.sh +205 -0
  132. package/agent/tasks/.gitkeep +0 -0
  133. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +210 -0
  134. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +294 -0
  135. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +193 -0
  136. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +262 -0
  137. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +156 -0
  138. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +178 -0
  139. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +141 -0
  140. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +153 -0
  141. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +174 -0
  142. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +233 -0
  143. package/agent/tasks/task-1-{title}.template.md +244 -0
  144. package/bin/visualize.mjs +84 -0
  145. package/package.json +48 -0
  146. package/src/components/ExtraFieldsBadge.tsx +15 -0
  147. package/src/components/FilterBar.tsx +33 -0
  148. package/src/components/Header.tsx +23 -0
  149. package/src/components/MilestoneTable.tsx +167 -0
  150. package/src/components/MilestoneTree.tsx +84 -0
  151. package/src/components/ProgressBar.tsx +20 -0
  152. package/src/components/SearchInput.tsx +22 -0
  153. package/src/components/Sidebar.tsx +54 -0
  154. package/src/components/StatusBadge.tsx +23 -0
  155. package/src/components/StatusDot.tsx +12 -0
  156. package/src/components/TaskList.tsx +36 -0
  157. package/src/components/ViewToggle.tsx +31 -0
  158. package/src/lib/config.ts +8 -0
  159. package/src/lib/file-watcher.ts +43 -0
  160. package/src/lib/search.ts +48 -0
  161. package/src/lib/types.ts +73 -0
  162. package/src/lib/useAutoRefresh.ts +31 -0
  163. package/src/lib/useCollapse.ts +31 -0
  164. package/src/lib/useFilteredData.ts +55 -0
  165. package/src/lib/yaml-loader-real.spec.ts +47 -0
  166. package/src/lib/yaml-loader.spec.ts +201 -0
  167. package/src/lib/yaml-loader.ts +265 -0
  168. package/src/routeTree.gen.ts +140 -0
  169. package/src/router.tsx +10 -0
  170. package/src/routes/__root.tsx +75 -0
  171. package/src/routes/api/watch.ts +29 -0
  172. package/src/routes/index.tsx +115 -0
  173. package/src/routes/milestones.tsx +50 -0
  174. package/src/routes/search.tsx +84 -0
  175. package/src/routes/tasks.tsx +63 -0
  176. package/src/services/progress-database.service.ts +46 -0
  177. package/src/styles.css +25 -0
  178. package/tsconfig.json +24 -0
  179. package/vite.config.ts +16 -0
  180. package/vitest.config.ts +27 -0
@@ -0,0 +1,237 @@
1
+ # WebSocket Manager
2
+
3
+ **Category**: Architecture
4
+ **Applicable To**: Real-time WebSocket connections with auto-reconnect, visibility recovery, and discriminated union message types
5
+ **Status**: Stable
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ A class-based WebSocket client (`ChatWebSocket`) with exponential backoff reconnection (5 attempts, 1s base), page visibility recovery, discriminated union message types, and init-based pre-warming. The server side uses a Cloudflare Durable Object (`ChatRoom`) for session multiplexing with ACL-filtered broadcasting. Each component instance creates its own WebSocket with proper message handlers.
12
+
13
+ ---
14
+
15
+ ## Implementation
16
+
17
+ ### ChatWebSocket Client
18
+
19
+ **File**: `src/lib/chat/websocket.ts`
20
+
21
+ ```typescript
22
+ interface ChatWebSocketConfig {
23
+ userId: string
24
+ conversationId?: string
25
+ ghostOwner?: string
26
+ onMessage: (message: WebSocketMessage) => void
27
+ }
28
+
29
+ class ChatWebSocket {
30
+ private ws: WebSocket | null = null
31
+ private reconnectAttempts = 0
32
+ private maxReconnectAttempts = 5
33
+ private reconnectDelay = 1000 // Base delay (ms)
34
+ private intentionalDisconnect = false
35
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null
36
+ private visibilityHandler: (() => void) | null = null
37
+ }
38
+ ```
39
+
40
+ ### Connection Lifecycle
41
+
42
+ ```
43
+ connect()
44
+ ├─ Set intentionalDisconnect = false
45
+ ├─ Clean up old visibility handler
46
+ ├─ Cancel pending reconnect timer
47
+ ├─ Close zombie WebSocket (clear handlers first)
48
+ ├─ Construct URL: wss://{host}/api/chat-ws?userId=X&conversationId=Y
49
+ └─ Create new WebSocket
50
+ ├─ onopen:
51
+ │ ├─ Reset reconnectAttempts = 0
52
+ │ ├─ Emit connection_change { connected: true }
53
+ │ └─ Send init message (triggers server pre-warming)
54
+ ├─ onmessage: Parse JSON → handleMessage(data)
55
+ ├─ onerror: Emit error event
56
+ └─ onclose:
57
+ ├─ Emit connection_change { connected: false }
58
+ ├─ Register visibilitychange handler
59
+ └─ attemptReconnect()
60
+ ```
61
+
62
+ ### Reconnection (Exponential Backoff)
63
+
64
+ ```typescript
65
+ private attemptReconnect() {
66
+ if (this.intentionalDisconnect) return
67
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
68
+ this.config.onMessage({ type: 'error', error: 'Failed to reconnect' })
69
+ return
70
+ }
71
+ this.reconnectAttempts++
72
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1)
73
+ // Sequence: 1s, 2s, 4s, 8s, 16s → give up
74
+ this.reconnectTimer = setTimeout(() => this.connect(), delay)
75
+ }
76
+ ```
77
+
78
+ ### Visibility Recovery
79
+
80
+ When the tab becomes visible and the WebSocket is dead, reconnect immediately with reset retry counter:
81
+
82
+ ```typescript
83
+ this.visibilityHandler = () => {
84
+ if (document.visibilityState === 'visible' &&
85
+ (!this.ws || this.ws.readyState === WebSocket.CLOSED)) {
86
+ this.reconnectAttempts = 0
87
+ this.connect()
88
+ }
89
+ }
90
+ document.addEventListener('visibilitychange', this.visibilityHandler)
91
+ ```
92
+
93
+ ### Discriminated Union Message Types
94
+
95
+ ```typescript
96
+ type WebSocketMessage =
97
+ | { type: 'chunk'; content: string }
98
+ | { type: 'tool_call'; toolCall: ToolCall; persistedToolCallId?: string }
99
+ | { type: 'tool_result'; toolResult: ToolResult; persistedToolCallId?: string }
100
+ | { type: 'message'; message: Message }
101
+ | { type: 'messages_loaded'; messages: Message[]; hasMore: boolean }
102
+ | { type: 'connection_change'; connected: boolean }
103
+ | { type: 'complete' }
104
+ | { type: 'cancelled' }
105
+ | { type: 'error'; error: string }
106
+ | { type: 'generation_in_progress' }
107
+ | { type: 'token_limit_warning'; percentage: number; estimatedTokens: number; maxTokens: number }
108
+ | { type: 'progress_start'; toolCallId: string; command: string }
109
+ | { type: 'progress_update'; toolCallId: string; output: string }
110
+ | { type: 'progress_complete'; toolCallId: string; exitCode: number }
111
+ | { type: 'progress_error'; toolCallId: string; error: string }
112
+ | { type: 'status'; serverName?: string; statusMessage?: string }
113
+ | { type: 'conversation_created'; conversationId: string }
114
+ | { type: 'usage'; input_tokens: number; output_tokens: number }
115
+ ```
116
+
117
+ ### Sending Messages
118
+
119
+ ```typescript
120
+ sendMessage(content: string | ContentBlock[], conversationId?: string) {
121
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
122
+ this.config.onMessage({ type: 'error', error: 'Not connected' })
123
+ return
124
+ }
125
+ this.ws.send(JSON.stringify({
126
+ type: 'message', message: content,
127
+ userId: this.config.userId, conversationId, ghostOwner: this.config.ghostOwner,
128
+ }))
129
+ }
130
+
131
+ cancelGeneration(conversationId?: string) { /* send type: 'cancel' */ }
132
+ loadMessages(conversationId: string, limit?: number, startAfter?: string) { /* send type: 'load_messages' */ }
133
+ ```
134
+
135
+ ### Graceful Disconnect
136
+
137
+ ```typescript
138
+ disconnect() {
139
+ this.intentionalDisconnect = true
140
+ clearTimeout(this.reconnectTimer)
141
+ document.removeEventListener('visibilitychange', this.visibilityHandler)
142
+ if (this.ws) {
143
+ this.ws.onclose = null; this.ws.onmessage = null; this.ws.onerror = null
144
+ this.ws.close()
145
+ this.ws = null
146
+ }
147
+ }
148
+ ```
149
+
150
+ ### Component Integration
151
+
152
+ ```typescript
153
+ // Each ChatInterface creates its own WebSocket
154
+ useEffect(() => {
155
+ if (!user) return
156
+ const ws = new ChatWebSocket({
157
+ userId: user.uid,
158
+ conversationId,
159
+ ghostOwner,
160
+ onMessage: (msg) => {
161
+ switch (msg.type) {
162
+ case 'chunk': /* append to streaming blocks */ break
163
+ case 'message': /* add to message list */ break
164
+ case 'complete': /* finalize assistant message */ break
165
+ // ...
166
+ }
167
+ },
168
+ })
169
+ ws.connect()
170
+ wsClientRef.current = ws
171
+ return () => ws.disconnect()
172
+ }, [user, conversationId, ghostOwner])
173
+ ```
174
+
175
+ ### Server: Init Pre-Warming
176
+
177
+ On `init` message, the ChatRoom DO:
178
+ 1. Registers user session
179
+ 2. Loads last 50 messages from Firestore
180
+ 3. Sends `messages_loaded` event
181
+ 4. If active generation exists, sends `generation_in_progress`
182
+ 5. Sends `ready` signal
183
+
184
+ ### Server: ACL-Filtered Broadcasting
185
+
186
+ ```typescript
187
+ private broadcastMessage(message: ServerMessage, conversationId?: string) {
188
+ for (const [socket, userId] of this.sessions.entries()) {
189
+ if (conversationId && this.sessionConversations.get(socket) !== conversationId) continue
190
+ if (message.visible_to_user_ids && !message.visible_to_user_ids.includes(userId)) continue
191
+ socket.send(JSON.stringify(message))
192
+ }
193
+ }
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Anti-Patterns
199
+
200
+ ### Sharing a Single WebSocket Across Components
201
+
202
+ ```typescript
203
+ // Bad: Pre-connected WebSocket has no-op handlers — messages get lost
204
+ const ws = useWebSocketManager() // Returns shared instance
205
+ <ChatInterface ws={ws} /> // Can't register proper handlers
206
+
207
+ // Good: Each component creates its own WebSocket
208
+ const ws = new ChatWebSocket({ userId, conversationId, onMessage: handleMessage })
209
+ ```
210
+
211
+ ### Not Clearing Handlers Before Closing
212
+
213
+ ```typescript
214
+ // Bad: Old onclose fires and triggers reconnect
215
+ this.ws.close()
216
+
217
+ // Good: Clear handlers first
218
+ this.ws.onclose = null; this.ws.onmessage = null; this.ws.onerror = null
219
+ this.ws.close()
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Checklist
225
+
226
+ - [ ] Each component creates its own `ChatWebSocket` instance
227
+ - [ ] `onMessage` handler covers all discriminated union cases
228
+ - [ ] `disconnect()` called on component unmount
229
+ - [ ] Visibility handler registered for tab recovery
230
+ - [ ] Event handlers cleared before closing WebSocket
231
+ - [ ] Server broadcasts filter by conversationId + ACL visibility
232
+
233
+ ---
234
+
235
+ **Status**: Stable
236
+ **Last Updated**: 2026-03-14
237
+ **Contributors**: Community
@@ -0,0 +1,358 @@
1
+ # Wrangler Configuration Pattern
2
+
3
+ **Category**: Infrastructure
4
+ **Applicable To**: TanStack Start + Cloudflare Workers applications
5
+ **Status**: Stable
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ The `wrangler.toml` file configures how your TanStack Start application runs on Cloudflare Workers. This pattern documents the complete configuration required for a production TanStack Start application, including Durable Object bindings, rate limiting, migrations, observability, and environment management.
12
+
13
+ Getting the wrangler configuration right is essential — incorrect settings can cause deployment failures, missing bindings, or production runtime errors.
14
+
15
+ ---
16
+
17
+ ## When to Use This Pattern
18
+
19
+ ✅ **Use this pattern when:**
20
+ - Deploying TanStack Start applications to Cloudflare Workers
21
+ - Using Durable Objects for stateful features
22
+ - Need rate limiting, observability, or environment variables
23
+ - Setting up production deployment configuration
24
+
25
+ ❌ **Don't use this pattern when:**
26
+ - Not using Cloudflare Workers
27
+ - Using Cloudflare Pages instead of Workers
28
+
29
+ ---
30
+
31
+ ## Core Principles
32
+
33
+ 1. **Single Configuration File**: All Worker configuration in `wrangler.toml`
34
+ 2. **Explicit Bindings**: All Durable Objects, rate limiters, and KV namespaces explicitly declared
35
+ 3. **Migration Tags**: Durable Object class changes tracked via sequential migration tags
36
+ 4. **Secrets via CLI**: Sensitive values stored as Cloudflare secrets, never in wrangler.toml
37
+ 5. **Compatibility Date**: Pin to a specific date for API stability
38
+
39
+ ---
40
+
41
+ ## Implementation
42
+
43
+ ### Complete wrangler.toml Reference
44
+
45
+ ```toml
46
+ # ─── Basic Configuration ─────────────────────────────────────────────────────
47
+
48
+ name = "my-app"
49
+ main = "src/server.ts"
50
+ compatibility_date = "2026-02-10"
51
+ compatibility_flags = ["nodejs_compat"]
52
+
53
+ # ─── CPU Limits (Workers Paid) ────────────────────────────────────────────────
54
+
55
+ [limits]
56
+ cpu_ms = 300000 # 5 minutes (300,000 ms) — maximum for Workers Paid plan
57
+
58
+ # ─── Observability ────────────────────────────────────────────────────────────
59
+
60
+ [observability]
61
+ enabled = true
62
+
63
+ [observability.logs]
64
+ enabled = true
65
+ invocation_logs = true
66
+
67
+ # ─── Durable Objects ──────────────────────────────────────────────────────────
68
+
69
+ [[durable_objects.bindings]]
70
+ name = "CHAT_ROOM"
71
+ class_name = "ChatRoom"
72
+
73
+ [[durable_objects.bindings]]
74
+ name = "UPLOAD_MANAGER"
75
+ class_name = "UploadManager"
76
+
77
+ # ─── Durable Object Migrations ───────────────────────────────────────────────
78
+ # Tags must be sequential. Each deployment reads these to determine schema changes.
79
+
80
+ [[migrations]]
81
+ tag = "v1"
82
+ new_sqlite_classes = ["ChatRoom"]
83
+
84
+ [[migrations]]
85
+ tag = "v2"
86
+ new_sqlite_classes = ["UploadManager"]
87
+
88
+ # To delete a Durable Object class:
89
+ # [[migrations]]
90
+ # tag = "v3"
91
+ # deleted_classes = ["ObsoleteClass"]
92
+
93
+ # ─── Rate Limiting ────────────────────────────────────────────────────────────
94
+ # namespace_id must be a string containing a positive integer
95
+
96
+ [[unsafe.bindings]]
97
+ name = "AUTH_RATE_LIMITER"
98
+ type = "ratelimit"
99
+ namespace_id = "1001"
100
+ simple = { limit = 5, period = 60 }
101
+
102
+ [[unsafe.bindings]]
103
+ name = "API_RATE_LIMITER"
104
+ type = "ratelimit"
105
+ namespace_id = "1002"
106
+ simple = { limit = 100, period = 60 }
107
+
108
+ [[unsafe.bindings]]
109
+ name = "WS_RATE_LIMITER"
110
+ type = "ratelimit"
111
+ namespace_id = "1003"
112
+ simple = { limit = 10, period = 60 }
113
+
114
+ # ─── Environment Variables (non-secret) ──────────────────────────────────────
115
+ # [vars]
116
+ # APP_ENV = "production"
117
+ # LOG_LEVEL = "info"
118
+
119
+ # ─── Secrets (set via CLI, never in this file) ───────────────────────────────
120
+ # wrangler secret put AWS_ACCESS_KEY_ID
121
+ # wrangler secret put AWS_SECRET_ACCESS_KEY
122
+ # wrangler secret put FIREBASE_PROJECT_ID
123
+ # wrangler secret put FIREBASE_CLIENT_EMAIL
124
+ # wrangler secret put FIREBASE_PRIVATE_KEY
125
+ ```
126
+
127
+ ### Vite Configuration
128
+
129
+ ```typescript
130
+ // vite.config.ts
131
+ import { defineConfig } from 'vite'
132
+ import { cloudflare } from '@opennextjs/cloudflare'
133
+ import { TanStackStartVite as tanstackStart } from '@tanstack/start/vite-plugin'
134
+ import react from '@vitejs/plugin-react'
135
+ import tailwindcss from '@tailwindcss/vite'
136
+ import viteTsConfigPaths from 'vite-tsconfig-paths'
137
+
138
+ export default defineConfig({
139
+ plugins: [
140
+ cloudflare({ viteEnvironment: { name: 'ssr' } }),
141
+ viteTsConfigPaths(),
142
+ tailwindcss(),
143
+ tanstackStart(),
144
+ react(),
145
+ ],
146
+ })
147
+ ```
148
+
149
+ ### TypeScript Env Types
150
+
151
+ ```typescript
152
+ // src/env.d.ts (or generated via wrangler types)
153
+ interface Env {
154
+ // Durable Objects
155
+ CHAT_ROOM: DurableObjectNamespace
156
+ UPLOAD_MANAGER: DurableObjectNamespace
157
+
158
+ // Rate Limiters
159
+ AUTH_RATE_LIMITER: RateLimit
160
+ API_RATE_LIMITER: RateLimit
161
+ WS_RATE_LIMITER: RateLimit
162
+
163
+ // Secrets
164
+ AWS_ACCESS_KEY_ID: string
165
+ AWS_SECRET_ACCESS_KEY: string
166
+ FIREBASE_PROJECT_ID: string
167
+ FIREBASE_CLIENT_EMAIL: string
168
+ FIREBASE_PRIVATE_KEY: string
169
+ }
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Configuration Sections Explained
175
+
176
+ ### Basic Configuration
177
+
178
+ | Field | Purpose | Example |
179
+ |-------|---------|---------|
180
+ | `name` | Worker name (used in deployment) | `"my-app"` |
181
+ | `main` | Entry point file | `"src/server.ts"` |
182
+ | `compatibility_date` | Pin Cloudflare API version | `"2026-02-10"` |
183
+ | `compatibility_flags` | Enable Node.js APIs | `["nodejs_compat"]` |
184
+
185
+ ### CPU Limits
186
+
187
+ | Field | Purpose | Default | Paid Plan Max |
188
+ |-------|---------|---------|---------------|
189
+ | `cpu_ms` | Max CPU time per request | 10ms (free) | 300,000ms (paid) |
190
+
191
+ ### Durable Object Bindings
192
+
193
+ Each binding creates a `DurableObjectNamespace` accessible via `env.BINDING_NAME`:
194
+ - `name`: The binding name in your code (e.g., `env.CHAT_ROOM`)
195
+ - `class_name`: The exported class name in your source code
196
+
197
+ ### Migrations
198
+
199
+ Migrations track Durable Object schema changes:
200
+ - `new_sqlite_classes`: New DO classes that use SQLite storage
201
+ - `new_classes`: New DO classes (without SQLite)
202
+ - `deleted_classes`: Classes being removed
203
+ - Tags must be sequential and never reused
204
+
205
+ ### Secrets Management
206
+
207
+ ```bash
208
+ # Upload individual secrets
209
+ wrangler secret put FIREBASE_PRIVATE_KEY
210
+
211
+ # Upload from .env file (script)
212
+ while IFS='=' read -r key value; do
213
+ echo "$value" | wrangler secret put "$key"
214
+ done < .env.secrets
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Examples
220
+
221
+ ### Example 1: Adding a New Durable Object
222
+
223
+ ```toml
224
+ # 1. Add binding
225
+ [[durable_objects.bindings]]
226
+ name = "TASK_EXECUTOR"
227
+ class_name = "TaskExecutor"
228
+
229
+ # 2. Add migration (use next sequential tag)
230
+ [[migrations]]
231
+ tag = "v3"
232
+ new_sqlite_classes = ["TaskExecutor"]
233
+ ```
234
+
235
+ ### Example 2: Removing a Durable Object
236
+
237
+ ```toml
238
+ # Migration to delete — add this, don't remove the binding yet
239
+ [[migrations]]
240
+ tag = "v4"
241
+ deleted_classes = ["TaskExecutor"]
242
+
243
+ # After deploying, remove the binding:
244
+ # [[durable_objects.bindings]]
245
+ # name = "TASK_EXECUTOR"
246
+ # class_name = "TaskExecutor"
247
+ ```
248
+
249
+ ### Example 3: Custom Domain Route
250
+
251
+ ```toml
252
+ # Route to custom domain
253
+ [[routes]]
254
+ pattern = "app.example.com/*"
255
+ zone_name = "example.com"
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Benefits
261
+
262
+ ### 1. Declarative Configuration
263
+ All infrastructure described in a single, version-controlled file.
264
+
265
+ ### 2. Type-Safe Bindings
266
+ Generate TypeScript types with `wrangler types` for full type safety.
267
+
268
+ ### 3. Sequential Migrations
269
+ Durable Object schema changes are tracked and applied in order.
270
+
271
+ ### 4. Edge Observability
272
+ Built-in logging and invocation tracking without external services.
273
+
274
+ ---
275
+
276
+ ## Trade-offs
277
+
278
+ ### 1. Rate Limiting Uses unsafe.bindings
279
+ **Downside**: The `unsafe.bindings` API may change in future Cloudflare versions.
280
+ **Mitigation**: Abstract rate limiting behind utility functions for easy migration.
281
+
282
+ ### 2. No Environment Inheritance
283
+ **Downside**: No built-in way to share config between staging and production.
284
+ **Mitigation**: Use separate wrangler.toml files or environment sections.
285
+
286
+ ---
287
+
288
+ ## Anti-Patterns
289
+
290
+ ### ❌ Anti-Pattern 1: Secrets in wrangler.toml
291
+
292
+ ```toml
293
+ # ❌ BAD: Secrets in config file (committed to git!)
294
+ [vars]
295
+ FIREBASE_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----..."
296
+
297
+ # ✅ GOOD: Use wrangler secret
298
+ # wrangler secret put FIREBASE_PRIVATE_KEY
299
+ ```
300
+
301
+ ### ❌ Anti-Pattern 2: Reusing Migration Tags
302
+
303
+ ```toml
304
+ # ❌ BAD: Reusing tag "v1" after changing it
305
+ [[migrations]]
306
+ tag = "v1"
307
+ new_sqlite_classes = ["ChatRoom", "UploadManager"] # Changed!
308
+
309
+ # ✅ GOOD: Sequential tags, never modified
310
+ [[migrations]]
311
+ tag = "v1"
312
+ new_sqlite_classes = ["ChatRoom"]
313
+
314
+ [[migrations]]
315
+ tag = "v2"
316
+ new_sqlite_classes = ["UploadManager"]
317
+ ```
318
+
319
+ ### ❌ Anti-Pattern 3: Missing nodejs_compat
320
+
321
+ ```toml
322
+ # ❌ BAD: Missing Node.js compatibility (crypto, Buffer, etc. won't work)
323
+ compatibility_flags = []
324
+
325
+ # ✅ GOOD: Enable Node.js compatibility
326
+ compatibility_flags = ["nodejs_compat"]
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Related Patterns
332
+
333
+ - **[Durable Objects WebSocket](./tanstack-cloudflare.durable-objects-websocket.md)**: DO bindings and migrations
334
+ - **[Rate Limiting](./tanstack-cloudflare.rate-limiting.md)**: Rate limiter bindings
335
+ - **[Auth Session Management](./tanstack-cloudflare.auth-session-management.md)**: Secret management for auth keys
336
+
337
+ ---
338
+
339
+ ## Checklist for Implementation
340
+
341
+ - [ ] `name` set to your worker name
342
+ - [ ] `main` points to server entry point
343
+ - [ ] `compatibility_date` set to recent date
344
+ - [ ] `nodejs_compat` flag enabled
345
+ - [ ] CPU limits configured for paid plan
346
+ - [ ] Observability and invocation logs enabled
347
+ - [ ] All Durable Objects have bindings
348
+ - [ ] Migrations use sequential, never-reused tags
349
+ - [ ] Rate limiters configured per endpoint category
350
+ - [ ] Secrets stored via `wrangler secret`, never in config
351
+ - [ ] Env types generated or manually maintained
352
+
353
+ ---
354
+
355
+ **Status**: Stable - Essential configuration for Cloudflare Workers deployment
356
+ **Recommendation**: Review and customize for every new TanStack Start + Cloudflare project
357
+ **Last Updated**: 2026-02-28
358
+ **Contributors**: Patrick Michaelsen