@prmichaelsen/acp-visualizer 0.1.0 → 0.1.2

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 (159) hide show
  1. package/package.json +8 -10
  2. package/src/components/ExtraFieldsBadge.tsx +1 -1
  3. package/src/components/FilterBar.tsx +1 -1
  4. package/src/components/Header.tsx +1 -1
  5. package/src/components/MilestoneTable.tsx +1 -1
  6. package/src/components/MilestoneTree.tsx +2 -2
  7. package/src/components/StatusBadge.tsx +1 -1
  8. package/src/components/StatusDot.tsx +1 -1
  9. package/src/components/TaskList.tsx +1 -1
  10. package/src/routes/__root.tsx +5 -5
  11. package/src/routes/api/watch.ts +1 -1
  12. package/src/routes/index.tsx +2 -2
  13. package/src/routes/milestones.tsx +7 -7
  14. package/src/routes/search.tsx +4 -4
  15. package/src/routes/tasks.tsx +3 -3
  16. package/src/services/progress-database.service.ts +3 -3
  17. package/agent/commands/acp.clarification-address.md +0 -417
  18. package/agent/commands/acp.clarification-capture.md +0 -386
  19. package/agent/commands/acp.clarification-create.md +0 -437
  20. package/agent/commands/acp.clarifications-research.md +0 -326
  21. package/agent/commands/acp.command-create.md +0 -432
  22. package/agent/commands/acp.design-create.md +0 -286
  23. package/agent/commands/acp.design-reference.md +0 -355
  24. package/agent/commands/acp.handoff.md +0 -270
  25. package/agent/commands/acp.index.md +0 -423
  26. package/agent/commands/acp.init.md +0 -546
  27. package/agent/commands/acp.package-create.md +0 -895
  28. package/agent/commands/acp.package-info.md +0 -212
  29. package/agent/commands/acp.package-install.md +0 -539
  30. package/agent/commands/acp.package-list.md +0 -280
  31. package/agent/commands/acp.package-publish.md +0 -541
  32. package/agent/commands/acp.package-remove.md +0 -293
  33. package/agent/commands/acp.package-search.md +0 -307
  34. package/agent/commands/acp.package-update.md +0 -361
  35. package/agent/commands/acp.package-validate.md +0 -540
  36. package/agent/commands/acp.pattern-create.md +0 -386
  37. package/agent/commands/acp.plan.md +0 -587
  38. package/agent/commands/acp.proceed.md +0 -882
  39. package/agent/commands/acp.project-create.md +0 -675
  40. package/agent/commands/acp.project-info.md +0 -312
  41. package/agent/commands/acp.project-list.md +0 -226
  42. package/agent/commands/acp.project-remove.md +0 -379
  43. package/agent/commands/acp.project-set.md +0 -227
  44. package/agent/commands/acp.project-update.md +0 -307
  45. package/agent/commands/acp.projects-restore.md +0 -228
  46. package/agent/commands/acp.projects-sync.md +0 -347
  47. package/agent/commands/acp.report.md +0 -407
  48. package/agent/commands/acp.resume.md +0 -239
  49. package/agent/commands/acp.sessions.md +0 -301
  50. package/agent/commands/acp.status.md +0 -293
  51. package/agent/commands/acp.sync.md +0 -364
  52. package/agent/commands/acp.task-create.md +0 -500
  53. package/agent/commands/acp.update.md +0 -302
  54. package/agent/commands/acp.validate.md +0 -466
  55. package/agent/commands/acp.version-check-for-updates.md +0 -276
  56. package/agent/commands/acp.version-check.md +0 -191
  57. package/agent/commands/acp.version-update.md +0 -289
  58. package/agent/commands/command.template.md +0 -339
  59. package/agent/commands/git.commit.md +0 -526
  60. package/agent/commands/git.init.md +0 -514
  61. package/agent/commands/tanstack-cloudflare.deploy.md +0 -272
  62. package/agent/commands/tanstack-cloudflare.tail.md +0 -275
  63. package/agent/design/.gitkeep +0 -0
  64. package/agent/design/design.template.md +0 -154
  65. package/agent/design/local.dashboard-layout-routing.md +0 -288
  66. package/agent/design/local.data-model-yaml-parsing.md +0 -310
  67. package/agent/design/local.search-filtering.md +0 -331
  68. package/agent/design/local.server-api-auto-refresh.md +0 -235
  69. package/agent/design/local.table-tree-views.md +0 -299
  70. package/agent/design/local.visualizer-requirements.md +0 -349
  71. package/agent/design/requirements.template.md +0 -387
  72. package/agent/index/.gitkeep +0 -0
  73. package/agent/index/acp.core.yaml +0 -137
  74. package/agent/index/local.main.template.yaml +0 -37
  75. package/agent/manifest.template.yaml +0 -13
  76. package/agent/manifest.yaml +0 -302
  77. package/agent/milestones/.gitkeep +0 -0
  78. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +0 -67
  79. package/agent/milestones/milestone-1-{title}.template.md +0 -206
  80. package/agent/milestones/milestone-2-dashboard-views-interaction.md +0 -79
  81. package/agent/package.template.yaml +0 -86
  82. package/agent/patterns/.gitkeep +0 -0
  83. package/agent/patterns/bootstrap.template.md +0 -1237
  84. package/agent/patterns/pattern.template.md +0 -382
  85. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +0 -332
  86. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +0 -416
  87. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +0 -401
  88. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +0 -387
  89. package/agent/patterns/tanstack-cloudflare.card-and-list.md +0 -271
  90. package/agent/patterns/tanstack-cloudflare.chat-engine.md +0 -353
  91. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +0 -346
  92. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +0 -516
  93. package/agent/patterns/tanstack-cloudflare.email-service.md +0 -431
  94. package/agent/patterns/tanstack-cloudflare.expander.md +0 -98
  95. package/agent/patterns/tanstack-cloudflare.fcm-push.md +0 -115
  96. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +0 -441
  97. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +0 -348
  98. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +0 -550
  99. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +0 -369
  100. package/agent/patterns/tanstack-cloudflare.form-controls.md +0 -145
  101. package/agent/patterns/tanstack-cloudflare.global-search-context.md +0 -93
  102. package/agent/patterns/tanstack-cloudflare.image-carousel.md +0 -126
  103. package/agent/patterns/tanstack-cloudflare.library-services.md +0 -553
  104. package/agent/patterns/tanstack-cloudflare.lightbox.md +0 -169
  105. package/agent/patterns/tanstack-cloudflare.markdown-content.md +0 -115
  106. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +0 -98
  107. package/agent/patterns/tanstack-cloudflare.modal.md +0 -156
  108. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +0 -461
  109. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +0 -151
  110. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +0 -90
  111. package/agent/patterns/tanstack-cloudflare.og-metadata.md +0 -296
  112. package/agent/patterns/tanstack-cloudflare.pagination.md +0 -442
  113. package/agent/patterns/tanstack-cloudflare.pill-input.md +0 -220
  114. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +0 -401
  115. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +0 -323
  116. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +0 -338
  117. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +0 -375
  118. package/agent/patterns/tanstack-cloudflare.slide-over.md +0 -129
  119. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +0 -571
  120. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +0 -508
  121. package/agent/patterns/tanstack-cloudflare.toast-system.md +0 -142
  122. package/agent/patterns/tanstack-cloudflare.unified-header.md +0 -280
  123. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +0 -628
  124. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +0 -237
  125. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +0 -358
  126. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +0 -336
  127. package/agent/progress.template.yaml +0 -161
  128. package/agent/progress.yaml +0 -145
  129. package/agent/schemas/package.schema.yaml +0 -276
  130. package/agent/scripts/acp.common.sh +0 -1781
  131. package/agent/scripts/acp.install.sh +0 -333
  132. package/agent/scripts/acp.package-create.sh +0 -924
  133. package/agent/scripts/acp.package-info.sh +0 -288
  134. package/agent/scripts/acp.package-install.sh +0 -893
  135. package/agent/scripts/acp.package-list.sh +0 -311
  136. package/agent/scripts/acp.package-publish.sh +0 -420
  137. package/agent/scripts/acp.package-remove.sh +0 -348
  138. package/agent/scripts/acp.package-search.sh +0 -156
  139. package/agent/scripts/acp.package-update.sh +0 -517
  140. package/agent/scripts/acp.package-validate.sh +0 -1018
  141. package/agent/scripts/acp.uninstall.sh +0 -85
  142. package/agent/scripts/acp.version-check-for-updates.sh +0 -98
  143. package/agent/scripts/acp.version-check.sh +0 -47
  144. package/agent/scripts/acp.version-update.sh +0 -176
  145. package/agent/scripts/acp.yaml-parser.sh +0 -985
  146. package/agent/scripts/acp.yaml-validate.sh +0 -205
  147. package/agent/tasks/.gitkeep +0 -0
  148. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +0 -210
  149. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +0 -294
  150. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +0 -193
  151. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +0 -262
  152. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +0 -156
  153. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +0 -178
  154. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +0 -141
  155. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +0 -153
  156. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +0 -174
  157. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +0 -233
  158. package/agent/tasks/task-1-{title}.template.md +0 -244
  159. package/vitest.config.ts +0 -27
@@ -1,237 +0,0 @@
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
@@ -1,358 +0,0 @@
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