create-backbone-template 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 (182) hide show
  1. package/README.md +33 -0
  2. package/bin/create-backbone-template.js +5 -0
  3. package/package.json +30 -0
  4. package/src/create-backbone-template.js +204 -0
  5. package/template/.agents/skills/agent-browser/SKILL.md +55 -0
  6. package/template/.agents/skills/create-plan/SKILL.md +52 -0
  7. package/template/.agents/skills/create-plan/agents/openai.yaml +4 -0
  8. package/template/.agents/skills/create-pr-presentation/SKILL.md +86 -0
  9. package/template/.agents/skills/create-pr-presentation/agents/openai.yaml +4 -0
  10. package/template/.agents/skills/implement-plan/SKILL.md +26 -0
  11. package/template/.agents/skills/implement-plan/agents/openai.yaml +4 -0
  12. package/template/.agents/skills/review-plan/SKILL.md +38 -0
  13. package/template/.agents/skills/review-plan/agents/openai.yaml +4 -0
  14. package/template/.env.schema +30 -0
  15. package/template/.env.test +6 -0
  16. package/template/.oxlintrc.json +67 -0
  17. package/template/.vscode/extensions.json +3 -0
  18. package/template/.vscode/settings.json +23 -0
  19. package/template/AGENTS.md +55 -0
  20. package/template/Cargo.lock +2648 -0
  21. package/template/Cargo.toml +29 -0
  22. package/template/Justfile +140 -0
  23. package/template/README.md +72 -0
  24. package/template/TODO.md +1 -0
  25. package/template/_gitignore +12 -0
  26. package/template/buf.gen.yaml +7 -0
  27. package/template/buf.yaml +10 -0
  28. package/template/client/.oxfmtrc.json +8 -0
  29. package/template/client/.oxlintrc.json +57 -0
  30. package/template/client/README.md +19 -0
  31. package/template/client/_gitignore +5 -0
  32. package/template/client/index.html +12 -0
  33. package/template/client/package.json +47 -0
  34. package/template/client/packages/design-system/package.json +19 -0
  35. package/template/client/packages/design-system/src/index.ts +2 -0
  36. package/template/client/packages/design-system-basic/package.json +18 -0
  37. package/template/client/packages/design-system-basic/src/button.stories.tsx +50 -0
  38. package/template/client/packages/design-system-basic/src/button.tsx +26 -0
  39. package/template/client/packages/design-system-basic/src/empty-state.stories.tsx +18 -0
  40. package/template/client/packages/design-system-basic/src/empty-state.tsx +17 -0
  41. package/template/client/packages/design-system-basic/src/form-field.stories.tsx +15 -0
  42. package/template/client/packages/design-system-basic/src/form-field.tsx +10 -0
  43. package/template/client/packages/design-system-basic/src/form.stories.tsx +27 -0
  44. package/template/client/packages/design-system-basic/src/form.tsx +9 -0
  45. package/template/client/packages/design-system-basic/src/heading.stories.tsx +14 -0
  46. package/template/client/packages/design-system-basic/src/heading.tsx +25 -0
  47. package/template/client/packages/design-system-basic/src/index.tsx +15 -0
  48. package/template/client/packages/design-system-basic/src/inline.stories.tsx +13 -0
  49. package/template/client/packages/design-system-basic/src/inline.tsx +5 -0
  50. package/template/client/packages/design-system-basic/src/layout.stories.tsx +24 -0
  51. package/template/client/packages/design-system-basic/src/layout.tsx +14 -0
  52. package/template/client/packages/design-system-basic/src/loader.stories.tsx +8 -0
  53. package/template/client/packages/design-system-basic/src/loader.tsx +11 -0
  54. package/template/client/packages/design-system-basic/src/navigation.stories.tsx +16 -0
  55. package/template/client/packages/design-system-basic/src/navigation.tsx +18 -0
  56. package/template/client/packages/design-system-basic/src/notice.stories.tsx +13 -0
  57. package/template/client/packages/design-system-basic/src/notice.tsx +5 -0
  58. package/template/client/packages/design-system-basic/src/stack.stories.tsx +17 -0
  59. package/template/client/packages/design-system-basic/src/stack.tsx +5 -0
  60. package/template/client/packages/design-system-basic/src/styles.css +254 -0
  61. package/template/client/packages/design-system-basic/src/text-input.stories.tsx +13 -0
  62. package/template/client/packages/design-system-basic/src/text-input.tsx +5 -0
  63. package/template/client/packages/design-system-basic/src/text.stories.tsx +21 -0
  64. package/template/client/packages/design-system-basic/src/text.tsx +5 -0
  65. package/template/client/packages/design-system-contract/package.json +15 -0
  66. package/template/client/packages/design-system-contract/src/button.ts +10 -0
  67. package/template/client/packages/design-system-contract/src/empty-state.ts +9 -0
  68. package/template/client/packages/design-system-contract/src/form-field.ts +9 -0
  69. package/template/client/packages/design-system-contract/src/form.ts +9 -0
  70. package/template/client/packages/design-system-contract/src/heading.ts +9 -0
  71. package/template/client/packages/design-system-contract/src/index.ts +13 -0
  72. package/template/client/packages/design-system-contract/src/inline.ts +7 -0
  73. package/template/client/packages/design-system-contract/src/layout.ts +8 -0
  74. package/template/client/packages/design-system-contract/src/loader.ts +7 -0
  75. package/template/client/packages/design-system-contract/src/navigation.ts +13 -0
  76. package/template/client/packages/design-system-contract/src/notice.ts +8 -0
  77. package/template/client/packages/design-system-contract/src/stack.ts +8 -0
  78. package/template/client/packages/design-system-contract/src/text-input.ts +5 -0
  79. package/template/client/packages/design-system-contract/src/text.ts +9 -0
  80. package/template/client/packages/design-system-lint/fixtures/invalid/external-ui-import.tsx +5 -0
  81. package/template/client/packages/design-system-lint/fixtures/invalid/raw-dom-jsx.tsx +3 -0
  82. package/template/client/packages/design-system-lint/fixtures/invalid/two-violations.tsx +7 -0
  83. package/template/client/packages/design-system-lint/fixtures/valid/design-system-only.tsx +13 -0
  84. package/template/client/packages/design-system-lint/package.json +23 -0
  85. package/template/client/packages/design-system-lint/src/check-design-system-architecture.ts +22 -0
  86. package/template/client/packages/design-system-lint/src/design-system-architecture.ts +286 -0
  87. package/template/client/packages/design-system-lint/src/oxlint-plugin.ts +11 -0
  88. package/template/client/packages/design-system-lint/src/page-architecture.ts +382 -0
  89. package/template/client/packages/design-system-lint/src/rules.ts +111 -0
  90. package/template/client/packages/design-system-lint/test/design-system-architecture.test.ts +243 -0
  91. package/template/client/packages/design-system-lint/test/oxlint-fixtures.test.ts +159 -0
  92. package/template/client/packages/design-system-lint/test/page-architecture.test.ts +175 -0
  93. package/template/client/packages/design-system-lint/test/rules.test.ts +65 -0
  94. package/template/client/packages/design-system-lint/tsconfig.json +29 -0
  95. package/template/client/src/App.tsx +77 -0
  96. package/template/client/src/design-system-components.test.tsx +75 -0
  97. package/template/client/src/gen/helloworld/v1/helloworld_pb.ts +63 -0
  98. package/template/client/src/main.tsx +18 -0
  99. package/template/client/src/pages/hello/hello-page.stories.tsx +20 -0
  100. package/template/client/src/pages/hello/hello-page.test.tsx +90 -0
  101. package/template/client/src/pages/hello/hello-page.tsx +126 -0
  102. package/template/client/src/pages/page.ts +20 -0
  103. package/template/client/src/testing/create-preview-events.test.ts +36 -0
  104. package/template/client/src/testing/create-preview-events.ts +30 -0
  105. package/template/client/src/vite-env.d.ts +1 -0
  106. package/template/client/tsconfig.json +32 -0
  107. package/template/client/vite.config.ts +21 -0
  108. package/template/client/vite.ladle.config.ts +5 -0
  109. package/template/e2e/.gherkin-lintrc +20 -0
  110. package/template/e2e/.oxfmtrc.json +15 -0
  111. package/template/e2e/.oxlintrc.json +37 -0
  112. package/template/e2e/_gitignore +4 -0
  113. package/template/e2e/features/helloworld.feature +10 -0
  114. package/template/e2e/package.json +42 -0
  115. package/template/e2e/playwright.config.ts +16 -0
  116. package/template/e2e/support/app-gherkin.ts +4 -0
  117. package/template/e2e/support/fixtures.ts +236 -0
  118. package/template/e2e/support/gherkin-fixtures/duplicate-id.feature +9 -0
  119. package/template/e2e/support/gherkin-fixtures/duplicate-id.spec.ts +7 -0
  120. package/template/e2e/support/gherkin-fixtures/extra-implementation.spec.ts +7 -0
  121. package/template/e2e/support/gherkin-fixtures/extra-step.spec.ts +10 -0
  122. package/template/e2e/support/gherkin-fixtures/happy-path.spec.ts +4 -0
  123. package/template/e2e/support/gherkin-fixtures/missing-id.feature +4 -0
  124. package/template/e2e/support/gherkin-fixtures/missing-id.spec.ts +7 -0
  125. package/template/e2e/support/gherkin-fixtures/missing-implementation.spec.ts +7 -0
  126. package/template/e2e/support/gherkin-fixtures/missing-step.spec.ts +7 -0
  127. package/template/e2e/support/gherkin-fixtures/playwright.config.ts +7 -0
  128. package/template/e2e/support/gherkin-fixtures/scenario-outline.feature +9 -0
  129. package/template/e2e/support/gherkin-fixtures/scenario-outline.spec.ts +7 -0
  130. package/template/e2e/support/gherkin-fixtures/step-mismatch.spec.ts +9 -0
  131. package/template/e2e/support/gherkin-fixtures/valid-implementations.ts +23 -0
  132. package/template/e2e/support/gherkin-fixtures/valid-scenarios.feature +26 -0
  133. package/template/e2e/support/gherkin.test.ts +184 -0
  134. package/template/e2e/support/gherkin.ts +321 -0
  135. package/template/e2e/support/oxlint-plugin.test.ts +328 -0
  136. package/template/e2e/support/oxlint-plugin.ts +485 -0
  137. package/template/e2e/tests/helloworld.spec.ts +39 -0
  138. package/template/e2e/tsconfig.json +26 -0
  139. package/template/e2e/tsconfig.oxlint-plugin.json +12 -0
  140. package/template/package.json +9 -0
  141. package/template/pnpm-lock.yaml +10723 -0
  142. package/template/pnpm-workspace.yaml +8 -0
  143. package/template/pr-slide/README.md +95 -0
  144. package/template/pr-slide/package.json +23 -0
  145. package/template/pr-slide/src/cli.js +262 -0
  146. package/template/pr-slide/src/generate-pr-deck.js +833 -0
  147. package/template/pr-slide/src/git-context.js +91 -0
  148. package/template/pr-slide/src/presentation-paths.js +9 -0
  149. package/template/pr-slide/src/presentations.js +53 -0
  150. package/template/pr-slide/test/generate-pr-deck.test.js +118 -0
  151. package/template/pr-slide/test/presentation-paths.test.js +14 -0
  152. package/template/pr-slide/test/presentations.test.js +50 -0
  153. package/template/proto/helloworld/v1/helloworld.proto +15 -0
  154. package/template/scripts/run-e2e.sh +10 -0
  155. package/template/server/Cargo.toml +26 -0
  156. package/template/server/build.rs +9 -0
  157. package/template/server/dylint/backbone_server_lints/.cargo/config.toml +6 -0
  158. package/template/server/dylint/backbone_server_lints/Cargo.lock +1581 -0
  159. package/template/server/dylint/backbone_server_lints/Cargo.toml +21 -0
  160. package/template/server/dylint/backbone_server_lints/README.md +5 -0
  161. package/template/server/dylint/backbone_server_lints/_gitignore +1 -0
  162. package/template/server/dylint/backbone_server_lints/rust-toolchain +3 -0
  163. package/template/server/dylint/backbone_server_lints/src/lib.rs +612 -0
  164. package/template/server/dylint/backbone_server_lints/ui/lib.rs +4 -0
  165. package/template/server/dylint/backbone_server_lints/ui/lib.stderr +10 -0
  166. package/template/server/dylint/backbone_server_lints/ui/long_file.rs +303 -0
  167. package/template/server/dylint/backbone_server_lints/ui/long_file.stderr +6 -0
  168. package/template/server/dylint/backbone_server_lints/ui/main.rs +59 -0
  169. package/template/server/dylint/backbone_server_lints/ui/main.stderr +85 -0
  170. package/template/server/migrations/20260520120000_create_projects.sql +12 -0
  171. package/template/server/migrations/20260524160000_create_hello_world_inputs.sql +12 -0
  172. package/template/server/src/config.rs +27 -0
  173. package/template/server/src/db/hello_world.rs +34 -0
  174. package/template/server/src/db/hello_world_tests.rs +11 -0
  175. package/template/server/src/db/mod.rs +39 -0
  176. package/template/server/src/lib.rs +10 -0
  177. package/template/server/src/main.rs +43 -0
  178. package/template/server/src/rpc/greeter/mod.rs +31 -0
  179. package/template/server/src/rpc/greeter/say_hello.rs +27 -0
  180. package/template/server/src/rpc/mod.rs +8 -0
  181. package/template/server/src/state.rs +13 -0
  182. package/template/skills-lock.json +11 -0
@@ -0,0 +1,303 @@
1
+ // filler line 001
2
+ // filler line 002
3
+ // filler line 003
4
+ // filler line 004
5
+ // filler line 005
6
+ // filler line 006
7
+ // filler line 007
8
+ // filler line 008
9
+ // filler line 009
10
+ // filler line 010
11
+ // filler line 011
12
+ // filler line 012
13
+ // filler line 013
14
+ // filler line 014
15
+ // filler line 015
16
+ // filler line 016
17
+ // filler line 017
18
+ // filler line 018
19
+ // filler line 019
20
+ // filler line 020
21
+ // filler line 021
22
+ // filler line 022
23
+ // filler line 023
24
+ // filler line 024
25
+ // filler line 025
26
+ // filler line 026
27
+ // filler line 027
28
+ // filler line 028
29
+ // filler line 029
30
+ // filler line 030
31
+ // filler line 031
32
+ // filler line 032
33
+ // filler line 033
34
+ // filler line 034
35
+ // filler line 035
36
+ // filler line 036
37
+ // filler line 037
38
+ // filler line 038
39
+ // filler line 039
40
+ // filler line 040
41
+ // filler line 041
42
+ // filler line 042
43
+ // filler line 043
44
+ // filler line 044
45
+ // filler line 045
46
+ // filler line 046
47
+ // filler line 047
48
+ // filler line 048
49
+ // filler line 049
50
+ // filler line 050
51
+ // filler line 051
52
+ // filler line 052
53
+ // filler line 053
54
+ // filler line 054
55
+ // filler line 055
56
+ // filler line 056
57
+ // filler line 057
58
+ // filler line 058
59
+ // filler line 059
60
+ // filler line 060
61
+ // filler line 061
62
+ // filler line 062
63
+ // filler line 063
64
+ // filler line 064
65
+ // filler line 065
66
+ // filler line 066
67
+ // filler line 067
68
+ // filler line 068
69
+ // filler line 069
70
+ // filler line 070
71
+ // filler line 071
72
+ // filler line 072
73
+ // filler line 073
74
+ // filler line 074
75
+ // filler line 075
76
+ // filler line 076
77
+ // filler line 077
78
+ // filler line 078
79
+ // filler line 079
80
+ // filler line 080
81
+ // filler line 081
82
+ // filler line 082
83
+ // filler line 083
84
+ // filler line 084
85
+ // filler line 085
86
+ // filler line 086
87
+ // filler line 087
88
+ // filler line 088
89
+ // filler line 089
90
+ // filler line 090
91
+ // filler line 091
92
+ // filler line 092
93
+ // filler line 093
94
+ // filler line 094
95
+ // filler line 095
96
+ // filler line 096
97
+ // filler line 097
98
+ // filler line 098
99
+ // filler line 099
100
+ // filler line 100
101
+ // filler line 101
102
+ // filler line 102
103
+ // filler line 103
104
+ // filler line 104
105
+ // filler line 105
106
+ // filler line 106
107
+ // filler line 107
108
+ // filler line 108
109
+ // filler line 109
110
+ // filler line 110
111
+ // filler line 111
112
+ // filler line 112
113
+ // filler line 113
114
+ // filler line 114
115
+ // filler line 115
116
+ // filler line 116
117
+ // filler line 117
118
+ // filler line 118
119
+ // filler line 119
120
+ // filler line 120
121
+ // filler line 121
122
+ // filler line 122
123
+ // filler line 123
124
+ // filler line 124
125
+ // filler line 125
126
+ // filler line 126
127
+ // filler line 127
128
+ // filler line 128
129
+ // filler line 129
130
+ // filler line 130
131
+ // filler line 131
132
+ // filler line 132
133
+ // filler line 133
134
+ // filler line 134
135
+ // filler line 135
136
+ // filler line 136
137
+ // filler line 137
138
+ // filler line 138
139
+ // filler line 139
140
+ // filler line 140
141
+ // filler line 141
142
+ // filler line 142
143
+ // filler line 143
144
+ // filler line 144
145
+ // filler line 145
146
+ // filler line 146
147
+ // filler line 147
148
+ // filler line 148
149
+ // filler line 149
150
+ // filler line 150
151
+ // filler line 151
152
+ // filler line 152
153
+ // filler line 153
154
+ // filler line 154
155
+ // filler line 155
156
+ // filler line 156
157
+ // filler line 157
158
+ // filler line 158
159
+ // filler line 159
160
+ // filler line 160
161
+ // filler line 161
162
+ // filler line 162
163
+ // filler line 163
164
+ // filler line 164
165
+ // filler line 165
166
+ // filler line 166
167
+ // filler line 167
168
+ // filler line 168
169
+ // filler line 169
170
+ // filler line 170
171
+ // filler line 171
172
+ // filler line 172
173
+ // filler line 173
174
+ // filler line 174
175
+ // filler line 175
176
+ // filler line 176
177
+ // filler line 177
178
+ // filler line 178
179
+ // filler line 179
180
+ // filler line 180
181
+ // filler line 181
182
+ // filler line 182
183
+ // filler line 183
184
+ // filler line 184
185
+ // filler line 185
186
+ // filler line 186
187
+ // filler line 187
188
+ // filler line 188
189
+ // filler line 189
190
+ // filler line 190
191
+ // filler line 191
192
+ // filler line 192
193
+ // filler line 193
194
+ // filler line 194
195
+ // filler line 195
196
+ // filler line 196
197
+ // filler line 197
198
+ // filler line 198
199
+ // filler line 199
200
+ // filler line 200
201
+ // filler line 201
202
+ // filler line 202
203
+ // filler line 203
204
+ // filler line 204
205
+ // filler line 205
206
+ // filler line 206
207
+ // filler line 207
208
+ // filler line 208
209
+ // filler line 209
210
+ // filler line 210
211
+ // filler line 211
212
+ // filler line 212
213
+ // filler line 213
214
+ // filler line 214
215
+ // filler line 215
216
+ // filler line 216
217
+ // filler line 217
218
+ // filler line 218
219
+ // filler line 219
220
+ // filler line 220
221
+ // filler line 221
222
+ // filler line 222
223
+ // filler line 223
224
+ // filler line 224
225
+ // filler line 225
226
+ // filler line 226
227
+ // filler line 227
228
+ // filler line 228
229
+ // filler line 229
230
+ // filler line 230
231
+ // filler line 231
232
+ // filler line 232
233
+ // filler line 233
234
+ // filler line 234
235
+ // filler line 235
236
+ // filler line 236
237
+ // filler line 237
238
+ // filler line 238
239
+ // filler line 239
240
+ // filler line 240
241
+ // filler line 241
242
+ // filler line 242
243
+ // filler line 243
244
+ // filler line 244
245
+ // filler line 245
246
+ // filler line 246
247
+ // filler line 247
248
+ // filler line 248
249
+ // filler line 249
250
+ // filler line 250
251
+ // filler line 251
252
+ // filler line 252
253
+ // filler line 253
254
+ // filler line 254
255
+ // filler line 255
256
+ // filler line 256
257
+ // filler line 257
258
+ // filler line 258
259
+ // filler line 259
260
+ // filler line 260
261
+ // filler line 261
262
+ // filler line 262
263
+ // filler line 263
264
+ // filler line 264
265
+ // filler line 265
266
+ // filler line 266
267
+ // filler line 267
268
+ // filler line 268
269
+ // filler line 269
270
+ // filler line 270
271
+ // filler line 271
272
+ // filler line 272
273
+ // filler line 273
274
+ // filler line 274
275
+ // filler line 275
276
+ // filler line 276
277
+ // filler line 277
278
+ // filler line 278
279
+ // filler line 279
280
+ // filler line 280
281
+ // filler line 281
282
+ // filler line 282
283
+ // filler line 283
284
+ // filler line 284
285
+ // filler line 285
286
+ // filler line 286
287
+ // filler line 287
288
+ // filler line 288
289
+ // filler line 289
290
+ // filler line 290
291
+ // filler line 291
292
+ // filler line 292
293
+ // filler line 293
294
+ // filler line 294
295
+ // filler line 295
296
+ // filler line 296
297
+ // filler line 297
298
+ // filler line 298
299
+ // filler line 299
300
+ // filler line 300
301
+ // filler line 301
302
+
303
+ fn main() {}
@@ -0,0 +1,6 @@
1
+ warning: Rust source file has 303 lines; split files above 300 lines
2
+ |
3
+ = note: `#[warn(max_file_length)]` on by default
4
+
5
+ warning: 1 warning emitted
6
+
@@ -0,0 +1,59 @@
1
+ mod sqlx {
2
+ pub fn query<T>(_sql: T) {}
3
+ }
4
+
5
+ mod reqwest {
6
+ pub struct Client;
7
+ }
8
+
9
+ mod connectrpc {
10
+ pub struct ConnectError;
11
+ pub struct ErrorCode;
12
+ }
13
+
14
+ mod axum {
15
+ pub mod http {
16
+ pub struct StatusCode;
17
+ }
18
+
19
+ pub mod response {
20
+ pub trait IntoResponse {}
21
+ }
22
+ }
23
+
24
+ use axum::{http::StatusCode, response::IntoResponse};
25
+ use connectrpc::{ConnectError, ErrorCode};
26
+ use reqwest::Client;
27
+
28
+ trait TasksService {
29
+ fn list_tasks(&self);
30
+ }
31
+
32
+ struct TasksRpcService;
33
+
34
+ impl TasksService for TasksRpcService {
35
+ fn list_tasks(&self) {}
36
+ }
37
+
38
+ pub fn external_webhook_handler() {}
39
+
40
+ fn read_database_url() {
41
+ let _ = std::env::var("DATABASE_URL");
42
+ }
43
+
44
+ fn list_rows() {
45
+ sqlx::query("SELECT 1");
46
+ }
47
+
48
+ fn dynamic_rows(table: &str) {
49
+ sqlx::query(format!("SELECT * FROM {table}"));
50
+ }
51
+
52
+ fn main() {
53
+ read_database_url();
54
+ list_rows();
55
+ dynamic_rows("tasks");
56
+ let _ = (Client, ConnectError, ErrorCode, StatusCode);
57
+ let service = TasksRpcService;
58
+ service.list_tasks();
59
+ }
@@ -0,0 +1,85 @@
1
+ error: Axum response error types should only be mapped in rest modules
2
+ --> $DIR/main.rs:24:12
3
+ |
4
+ LL | use axum::{http::StatusCode, response::IntoResponse};
5
+ | ^^^^^^^^^^^^^^^^
6
+ |
7
+ = note: `#[deny(rest_errors_mapped_at_boundary)]` on by default
8
+
9
+ error: Axum response error types should only be mapped in rest modules
10
+ --> $DIR/main.rs:24:30
11
+ |
12
+ LL | use axum::{http::StatusCode, response::IntoResponse};
13
+ | ^^^^^^^^^^^^^^^^^^^^^^
14
+
15
+ error: Connect RPC errors should only be mapped in rpc modules
16
+ --> $DIR/main.rs:25:18
17
+ |
18
+ LL | use connectrpc::{ConnectError, ErrorCode};
19
+ | ^^^^^^^^^^^^
20
+ |
21
+ = note: `#[deny(rpc_errors_mapped_at_boundary)]` on by default
22
+
23
+ error: Connect RPC errors should only be mapped in rpc modules
24
+ --> $DIR/main.rs:25:32
25
+ |
26
+ LL | use connectrpc::{ConnectError, ErrorCode};
27
+ | ^^^^^^^^^
28
+
29
+ error: reqwest usage should live behind integrations modules
30
+ --> $DIR/main.rs:26:1
31
+ |
32
+ LL | use reqwest::Client;
33
+ | ^^^^^^^^^^^^^^^^^^^^
34
+ |
35
+ = note: `#[deny(no_http_client_outside_integrations)]` on by default
36
+
37
+ error: RPC method implementations should be bridged from rpc/<service>/mod.rs with logic in a sibling method file
38
+ --> $DIR/main.rs:35:5
39
+ |
40
+ LL | fn list_tasks(&self) {}
41
+ | ^^^^^^^^^^^^^^^^^^^^^^^
42
+ |
43
+ = note: `#[deny(rpc_method_in_separate_file)]` on by default
44
+
45
+ error: Axum endpoint handlers should live in rest modules
46
+ --> $DIR/main.rs:38:1
47
+ |
48
+ LL | pub fn external_webhook_handler() {}
49
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50
+ |
51
+ = note: `#[deny(rest_endpoint_in_rest_folder)]` on by default
52
+
53
+ error: environment variable access should be centralized in config modules
54
+ --> $DIR/main.rs:41:13
55
+ |
56
+ LL | let _ = std::env::var("DATABASE_URL");
57
+ | ^^^^^^^^^^^^^
58
+ |
59
+ = note: `#[deny(no_direct_env_var_outside_config)]` on by default
60
+
61
+ error: sqlx calls are only allowed in db modules
62
+ --> $DIR/main.rs:45:5
63
+ |
64
+ LL | sqlx::query("SELECT 1");
65
+ | ^^^^^^^^^^^
66
+ |
67
+ = note: `#[deny(sqlx_only_in_db_folder)]` on by default
68
+
69
+ warning: sqlx query strings should be string literals or sqlx macros
70
+ --> $DIR/main.rs:48:1
71
+ |
72
+ LL | / fn dynamic_rows(table: &str) {
73
+ LL | | sqlx::query(format!("SELECT * FROM {table}"));
74
+ LL | | }
75
+ | |_^
76
+ |
77
+ = note: `#[warn(no_sql_string_construction)]` on by default
78
+
79
+ error: sqlx calls are only allowed in db modules
80
+ --> $DIR/main.rs:49:5
81
+ |
82
+ LL | sqlx::query(format!("SELECT * FROM {table}"));
83
+ | ^^^^^^^^^^^
84
+
85
+ error: aborting due to 10 previous errors; 1 warning emitted
@@ -0,0 +1,12 @@
1
+ CREATE TABLE projects (
2
+ id TEXT PRIMARY KEY NOT NULL DEFAULT (
3
+ lower(hex(randomblob(4))) || '-' ||
4
+ lower(hex(randomblob(2))) || '-4' ||
5
+ substr(lower(hex(randomblob(2))), 2) || '-' ||
6
+ substr('89ab', abs(random()) % 4 + 1, 1) ||
7
+ substr(lower(hex(randomblob(2))), 2) || '-' ||
8
+ lower(hex(randomblob(6)))
9
+ ),
10
+ project_user TEXT NOT NULL,
11
+ project_name TEXT NOT NULL
12
+ );
@@ -0,0 +1,12 @@
1
+ CREATE TABLE hello_world_inputs (
2
+ id TEXT PRIMARY KEY NOT NULL DEFAULT (
3
+ lower(hex(randomblob(4))) || '-' ||
4
+ lower(hex(randomblob(2))) || '-4' ||
5
+ substr(lower(hex(randomblob(2))), 2) || '-' ||
6
+ substr('89ab', abs(random()) % 4 + 1, 1) ||
7
+ substr(lower(hex(randomblob(2))), 2) || '-' ||
8
+ lower(hex(randomblob(6)))
9
+ ),
10
+ input TEXT NOT NULL,
11
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
12
+ );
@@ -0,0 +1,27 @@
1
+ use anyhow::Context as _;
2
+
3
+ #[derive(Clone)]
4
+ pub struct ServerConfig {
5
+ pub host: String,
6
+ pub port: String,
7
+ pub database_url: String,
8
+ }
9
+
10
+ impl ServerConfig {
11
+ pub fn from_env() -> anyhow::Result<Self> {
12
+ Ok(Self {
13
+ host: read_env("SERVER_HOST")?,
14
+ port: read_env("SERVER_PORT")?,
15
+ database_url: read_env("DATABASE_URL")?,
16
+ })
17
+ }
18
+
19
+ #[must_use]
20
+ pub fn bind_addr(&self) -> String {
21
+ format!("{}:{}", self.host, self.port)
22
+ }
23
+ }
24
+
25
+ fn read_env(name: &str) -> anyhow::Result<String> {
26
+ std::env::var(name).with_context(|| format!("read {name}"))
27
+ }
@@ -0,0 +1,34 @@
1
+ use super::Db;
2
+
3
+ impl Db {
4
+ pub async fn record_hello_world_input(&self, input: &str) -> anyhow::Result<()> {
5
+ sqlx::query(
6
+ r"
7
+ INSERT INTO hello_world_inputs (input)
8
+ VALUES (?)
9
+ ",
10
+ )
11
+ .bind(input)
12
+ .execute(&self.pool)
13
+ .await?;
14
+
15
+ Ok(())
16
+ }
17
+
18
+ #[cfg(test)]
19
+ pub async fn list_hello_world_inputs(&self) -> anyhow::Result<Vec<String>> {
20
+ let rows = sqlx::query(
21
+ r"
22
+ SELECT input
23
+ FROM hello_world_inputs
24
+ ORDER BY created_at, id
25
+ ",
26
+ )
27
+ .fetch_all(&self.pool)
28
+ .await?;
29
+
30
+ rows.into_iter()
31
+ .map(|row| Ok(sqlx::Row::try_get(&row, "input")?))
32
+ .collect()
33
+ }
34
+ }
@@ -0,0 +1,11 @@
1
+ use super::Db;
2
+
3
+ #[tokio::test]
4
+ async fn record_hello_world_input_persists_submitted_names() -> anyhow::Result<()> {
5
+ let db = Db::in_memory().await?;
6
+
7
+ db.record_hello_world_input("Playwright").await?;
8
+
9
+ assert_eq!(db.list_hello_world_inputs().await?, vec!["Playwright"]);
10
+ Ok(())
11
+ }
@@ -0,0 +1,39 @@
1
+ mod hello_world;
2
+ #[cfg(test)]
3
+ mod hello_world_tests;
4
+
5
+ use anyhow::Context as _;
6
+ use sqlx::{SqlitePool, sqlite::SqlitePoolOptions};
7
+
8
+ #[derive(Clone)]
9
+ pub struct Db {
10
+ pool: SqlitePool,
11
+ }
12
+
13
+ impl Db {
14
+ pub async fn connect(database_url: &str) -> anyhow::Result<Self> {
15
+ let pool = SqlitePoolOptions::new()
16
+ .max_connections(5)
17
+ .connect(database_url)
18
+ .await
19
+ .context("connect database")?;
20
+
21
+ sqlx::migrate!("./migrations")
22
+ .run(&pool)
23
+ .await
24
+ .context("run database migrations")?;
25
+
26
+ Ok(Self { pool })
27
+ }
28
+
29
+ #[cfg(test)]
30
+ async fn in_memory() -> anyhow::Result<Self> {
31
+ let pool = SqlitePoolOptions::new()
32
+ .max_connections(1)
33
+ .connect("sqlite::memory:")
34
+ .await?;
35
+
36
+ sqlx::migrate!("./migrations").run(&pool).await?;
37
+ Ok(Self { pool })
38
+ }
39
+ }
@@ -0,0 +1,10 @@
1
+ pub mod config;
2
+ pub mod db;
3
+
4
+ #[allow(clippy::pedantic)]
5
+ pub mod proto {
6
+ connectrpc::include_generated!();
7
+ }
8
+
9
+ pub mod rpc;
10
+ pub mod state;
@@ -0,0 +1,43 @@
1
+ use std::{net::SocketAddr, sync::Arc};
2
+
3
+ use anyhow::Context as _;
4
+ use axum::{Router, routing::get};
5
+ use connectrpc::Router as ConnectRouter;
6
+ use server::{
7
+ config::ServerConfig, db::Db, proto::helloworld::v1::GreeterServiceExt,
8
+ rpc::greeter::GreeterRpcService, state::AppState,
9
+ };
10
+ use tower_http::{cors::CorsLayer, trace::TraceLayer};
11
+ use tracing::info;
12
+ use tracing_subscriber::{EnvFilter, fmt};
13
+
14
+ #[tokio::main]
15
+ async fn main() -> anyhow::Result<()> {
16
+ fmt()
17
+ .with_env_filter(EnvFilter::from_default_env().add_directive("server=info".parse()?))
18
+ .init();
19
+
20
+ let config = ServerConfig::from_env()?;
21
+ let bind_addr = config.bind_addr();
22
+ let db = Db::connect(&config.database_url).await?;
23
+ let app_state = AppState::new(db);
24
+
25
+ let connect =
26
+ Arc::new(GreeterRpcService::new(app_state.clone())).register(ConnectRouter::new());
27
+ let app = Router::new()
28
+ .route("/health", get(|| async { "OK" }))
29
+ .fallback_service(connect.into_axum_service())
30
+ .with_state(app_state)
31
+ .layer(CorsLayer::permissive())
32
+ .layer(TraceLayer::new_for_http());
33
+
34
+ let listener = tokio::net::TcpListener::bind(&bind_addr)
35
+ .await
36
+ .with_context(|| format!("bind {bind_addr}"))?;
37
+ let addr: SocketAddr = listener.local_addr().context("read bound address")?;
38
+
39
+ info!("server listening on http://{addr}");
40
+ axum::serve(listener, app).await.context("serve")?;
41
+
42
+ Ok(())
43
+ }
@@ -0,0 +1,31 @@
1
+ mod say_hello;
2
+
3
+ use connectrpc::{ConnectError, RequestContext, Response};
4
+
5
+ use crate::{
6
+ proto::helloworld::v1::{GreeterService, OwnedSayHelloRequestView, SayHelloResponse},
7
+ state::AppState,
8
+ };
9
+
10
+ #[derive(Clone)]
11
+ pub struct GreeterRpcService {
12
+ pub(super) state: AppState,
13
+ }
14
+
15
+ impl GreeterRpcService {
16
+ #[must_use]
17
+ pub fn new(state: AppState) -> Self {
18
+ Self { state }
19
+ }
20
+ }
21
+
22
+ #[allow(refining_impl_trait)]
23
+ impl GreeterService for GreeterRpcService {
24
+ async fn say_hello(
25
+ &self,
26
+ ctx: RequestContext,
27
+ request: OwnedSayHelloRequestView,
28
+ ) -> Result<Response<SayHelloResponse>, ConnectError> {
29
+ say_hello::handle(self, ctx, &request).await
30
+ }
31
+ }