ts-procedures 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +150 -0
  2. package/agent_config/bin/postinstall.mjs +105 -0
  3. package/agent_config/bin/setup.mjs +286 -0
  4. package/agent_config/claude-code/.claude-plugin/plugin.json +5 -0
  5. package/agent_config/claude-code/agents/ts-procedures-architect.md +188 -0
  6. package/agent_config/claude-code/skills/guide/SKILL.md +142 -0
  7. package/agent_config/claude-code/skills/guide/anti-patterns.md +608 -0
  8. package/agent_config/claude-code/skills/guide/api-reference.md +696 -0
  9. package/agent_config/claude-code/skills/guide/patterns.md +727 -0
  10. package/agent_config/claude-code/skills/review/SKILL.md +53 -0
  11. package/agent_config/claude-code/skills/review/checklist.md +163 -0
  12. package/agent_config/claude-code/skills/scaffold/SKILL.md +56 -0
  13. package/agent_config/claude-code/skills/scaffold/templates/express-rpc.md +134 -0
  14. package/agent_config/claude-code/skills/scaffold/templates/hono-api.md +169 -0
  15. package/agent_config/claude-code/skills/scaffold/templates/hono-rpc.md +139 -0
  16. package/agent_config/claude-code/skills/scaffold/templates/hono-stream.md +134 -0
  17. package/agent_config/claude-code/skills/scaffold/templates/procedure.md +77 -0
  18. package/agent_config/claude-code/skills/scaffold/templates/stream-procedure.md +113 -0
  19. package/agent_config/copilot/copilot-instructions.md +290 -0
  20. package/agent_config/cursor/cursorrules +290 -0
  21. package/agent_config/lib/install-claude.mjs +109 -0
  22. package/build/implementations/http/hono-api/index.d.ts +102 -0
  23. package/build/implementations/http/hono-api/index.js +339 -0
  24. package/build/implementations/http/hono-api/index.js.map +1 -0
  25. package/build/implementations/http/hono-api/index.test.d.ts +1 -0
  26. package/build/implementations/http/hono-api/index.test.js +983 -0
  27. package/build/implementations/http/hono-api/index.test.js.map +1 -0
  28. package/build/implementations/http/hono-api/types.d.ts +13 -0
  29. package/build/implementations/http/hono-api/types.js +2 -0
  30. package/build/implementations/http/hono-api/types.js.map +1 -0
  31. package/build/implementations/types.d.ts +44 -0
  32. package/build/index.d.ts +28 -6
  33. package/build/index.js +28 -0
  34. package/build/index.js.map +1 -1
  35. package/build/schema/compute-schema.d.ts +5 -0
  36. package/build/schema/compute-schema.js +8 -1
  37. package/build/schema/compute-schema.js.map +1 -1
  38. package/build/schema/parser.d.ts +6 -5
  39. package/build/schema/parser.js +54 -0
  40. package/build/schema/parser.js.map +1 -1
  41. package/package.json +14 -4
  42. package/src/implementations/http/README.md +45 -2
  43. package/src/implementations/http/hono-api/index.test.ts +1328 -0
  44. package/src/implementations/http/hono-api/index.ts +461 -0
  45. package/src/implementations/http/hono-api/types.ts +16 -0
  46. package/src/implementations/types.ts +52 -0
  47. package/src/index.ts +87 -10
  48. package/src/schema/compute-schema.ts +23 -2
  49. package/src/schema/parser.ts +70 -3
@@ -0,0 +1,608 @@
1
+ # ts-procedures Anti-Patterns
2
+
3
+ These are common mistakes when using ts-procedures. Each anti-pattern includes a fix.
4
+
5
+ ---
6
+
7
+ ## 1. Throwing Raw Errors Instead of ctx.error()
8
+
9
+ **Problem:** Throwing plain `Error` loses procedure metadata and makes error handling inconsistent.
10
+
11
+ ```typescript
12
+ // BAD
13
+ async (ctx, params) => {
14
+ if (!params.id) {
15
+ throw new Error('ID is required')
16
+ }
17
+ }
18
+ ```
19
+
20
+ **Fix:** Use `ctx.error()` for business logic errors.
21
+
22
+ ```typescript
23
+ // GOOD
24
+ async (ctx, params) => {
25
+ if (!params.id) {
26
+ throw ctx.error('ID is required', { code: 'MISSING_ID' })
27
+ }
28
+ }
29
+ ```
30
+
31
+ **Why:** `ctx.error()` creates a `ProcedureError` with `procedureName`, `meta`, `definedAt`, and enhanced stack trace. Raw errors get wrapped but lose the `meta` field and intentional error semantics.
32
+
33
+ ---
34
+
35
+ ## 2. Putting Validation Logic in the Handler
36
+
37
+ **Problem:** Manually validating params when schema validation handles it automatically.
38
+
39
+ ```typescript
40
+ // BAD
41
+ Create('GetUser', {}, async (ctx, params) => {
42
+ if (!params.userId || typeof params.userId !== 'string') {
43
+ throw ctx.error('userId is required and must be a string')
44
+ }
45
+ return fetchUser(params.userId)
46
+ })
47
+ ```
48
+
49
+ **Fix:** Use `schema.params` — AJV validates automatically.
50
+
51
+ ```typescript
52
+ // GOOD
53
+ Create('GetUser', {
54
+ schema: {
55
+ params: Type.Object({ userId: Type.String() }),
56
+ },
57
+ }, async (ctx, params) => {
58
+ // params.userId is guaranteed to be a string
59
+ return fetchUser(params.userId)
60
+ })
61
+ ```
62
+
63
+ **Why:** AJV provides detailed error messages, collects all errors (`allErrors: true`), coerces types, and removes additional properties. Manual validation duplicates this and is less thorough.
64
+
65
+ ---
66
+
67
+ ## 3. Expecting returnType to Be Validated at Runtime
68
+
69
+ **Problem:** Assuming `schema.returnType` validates the handler's return value.
70
+
71
+ ```typescript
72
+ // BAD — developer expects runtime validation of return value
73
+ Create('GetUser', {
74
+ schema: {
75
+ params: Type.Object({ id: Type.String() }),
76
+ returnType: Type.Object({ id: Type.String(), name: Type.String() }),
77
+ },
78
+ }, async (ctx, params) => {
79
+ return { id: 123, wrong: 'field' } // No error thrown!
80
+ })
81
+ ```
82
+
83
+ **Fix:** Understand that `returnType` is documentation only. Rely on TypeScript for return type safety.
84
+
85
+ ```typescript
86
+ // GOOD — TypeScript enforces return type via generic inference
87
+ Create('GetUser', {
88
+ schema: {
89
+ params: Type.Object({ id: Type.String() }),
90
+ returnType: Type.Object({ id: Type.String(), name: Type.String() }),
91
+ },
92
+ }, async (ctx, params): Promise<{ id: string; name: string }> => {
93
+ return { id: params.id, name: 'John' } // TypeScript catches mismatches
94
+ })
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 4. Ignoring ctx.signal in Async Operations
100
+
101
+ **Problem:** Not passing `signal` to downstream calls, preventing cancellation on client disconnect.
102
+
103
+ ```typescript
104
+ // BAD
105
+ async (ctx, params) => {
106
+ const data = await fetch('https://api.example.com/heavy-query')
107
+ const processed = await heavyComputation(data)
108
+ return processed
109
+ }
110
+ ```
111
+
112
+ **Fix:** Pass `ctx.signal` to all async calls.
113
+
114
+ ```typescript
115
+ // GOOD
116
+ async (ctx, params) => {
117
+ const data = await fetch('https://api.example.com/heavy-query', {
118
+ signal: ctx.signal,
119
+ })
120
+ const processed = await heavyComputation(data, { signal: ctx.signal })
121
+ return processed
122
+ }
123
+ ```
124
+
125
+ **Why:** When a client disconnects, the HTTP implementation aborts the signal. Without passing it, the handler continues wasting resources on a response nobody will receive.
126
+
127
+ ---
128
+
129
+ ## 5. Not Checking signal.aborted in Stream Loops
130
+
131
+ **Problem:** Stream continues producing values after client disconnects.
132
+
133
+ ```typescript
134
+ // BAD
135
+ async function* (ctx, params) {
136
+ while (true) {
137
+ const data = await pollForData()
138
+ yield data
139
+ await delay(1000)
140
+ }
141
+ }
142
+ ```
143
+
144
+ **Fix:** Check `ctx.signal.aborted` in the loop condition.
145
+
146
+ ```typescript
147
+ // GOOD
148
+ async function* (ctx, params) {
149
+ while (!ctx.signal.aborted) {
150
+ const data = await pollForData({ signal: ctx.signal })
151
+ yield data
152
+ await delay(1000)
153
+ }
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ## 6. Duplicate Procedure Names
160
+
161
+ **Problem:** Registering two procedures with the same name in the same factory.
162
+
163
+ ```typescript
164
+ // BAD — throws ProcedureRegistrationError
165
+ Create('GetUser', { scope: 'users', version: 1 }, handler1)
166
+ Create('GetUser', { scope: 'admin', version: 1 }, handler2)
167
+ ```
168
+
169
+ **Fix:** Use unique names. Use scope/version to differentiate routes.
170
+
171
+ ```typescript
172
+ // GOOD
173
+ Create('GetUser', { scope: 'users', version: 1 }, handler1)
174
+ Create('GetUserAdmin', { scope: 'admin', version: 1 }, handler2)
175
+
176
+ // Or use separate factories
177
+ const UserRPC = Procedures<UserContext, RPCConfig>()
178
+ const AdminRPC = Procedures<AdminContext, RPCConfig>()
179
+ UserRPC.Create('GetUser', { scope: 'users', version: 1 }, handler1)
180
+ AdminRPC.Create('GetUser', { scope: 'admin', version: 1 }, handler2)
181
+ ```
182
+
183
+ ---
184
+
185
+ ## 7. Using validateYields Without yieldType Schema
186
+
187
+ **Problem:** Setting `validateYields: true` without providing a `yieldType` schema.
188
+
189
+ ```typescript
190
+ // BAD — validateYields has no effect without yieldType schema
191
+ CreateStream('Stream', {
192
+ validateYields: true,
193
+ schema: {
194
+ params: Type.Object({ id: Type.String() }),
195
+ },
196
+ }, async function* (ctx, params) {
197
+ yield { anything: 'goes' }
198
+ })
199
+ ```
200
+
201
+ **Fix:** Provide `yieldType` schema when using `validateYields`.
202
+
203
+ ```typescript
204
+ // GOOD
205
+ CreateStream('Stream', {
206
+ validateYields: true,
207
+ schema: {
208
+ params: Type.Object({ id: Type.String() }),
209
+ yieldType: Type.Object({ id: Type.String(), value: Type.Number() }),
210
+ },
211
+ }, async function* (ctx, params) {
212
+ yield { id: '1', value: 42 }
213
+ })
214
+ ```
215
+
216
+ ---
217
+
218
+ ## 8. Swallowing Errors in Handlers
219
+
220
+ **Problem:** Catching errors without re-throwing, hiding failures from the caller.
221
+
222
+ ```typescript
223
+ // BAD
224
+ async (ctx, params) => {
225
+ try {
226
+ return await riskyOperation(params)
227
+ } catch (err) {
228
+ console.error('Operation failed:', err)
229
+ return null // Caller thinks it succeeded
230
+ }
231
+ }
232
+ ```
233
+
234
+ **Fix:** Let errors propagate. The framework wraps them in `ProcedureError` with enhanced stack traces.
235
+
236
+ ```typescript
237
+ // GOOD — let the framework handle it
238
+ async (ctx, params) => {
239
+ return await riskyOperation(params)
240
+ }
241
+
242
+ // Or rethrow as a business error with context
243
+ async (ctx, params) => {
244
+ try {
245
+ return await riskyOperation(params)
246
+ } catch (err) {
247
+ throw ctx.error('Operation failed', { originalError: err.message, params })
248
+ }
249
+ }
250
+ ```
251
+
252
+ ---
253
+
254
+ ## 9. Not Using AJV's coerceTypes Behavior
255
+
256
+ **Problem:** Treating query string values as strings when AJV will coerce them.
257
+
258
+ ```typescript
259
+ // BAD — unnecessary manual parsing
260
+ async (ctx, params) => {
261
+ const page = parseInt(params.page, 10)
262
+ const limit = parseInt(params.limit, 10)
263
+ return fetchPage(page, limit)
264
+ }
265
+ ```
266
+
267
+ **Fix:** Let AJV coerce types via the schema.
268
+
269
+ ```typescript
270
+ // GOOD — AJV coerces "5" → 5 automatically
271
+ Create('ListUsers', {
272
+ schema: {
273
+ params: Type.Object({
274
+ page: Type.Number(),
275
+ limit: Type.Number(),
276
+ }),
277
+ },
278
+ }, async (ctx, params) => {
279
+ // params.page and params.limit are already numbers
280
+ return fetchPage(params.page, params.limit)
281
+ })
282
+ ```
283
+
284
+ **Why:** AJV is configured with `coerceTypes: true`. String `"5"` from query params becomes number `5` after validation.
285
+
286
+ ---
287
+
288
+ ## 10. Forgetting removeAdditional Strips Extra Fields
289
+
290
+ **Problem:** Passing extra fields in params and expecting them to survive validation.
291
+
292
+ ```typescript
293
+ // BAD — extra fields silently removed
294
+ const result = await GetUser(ctx, {
295
+ userId: '123',
296
+ debug: true, // Stripped by AJV
297
+ extraData: 'value', // Stripped by AJV
298
+ })
299
+ ```
300
+
301
+ **Fix:** Only pass fields defined in the schema. If you need additional fields, add them to the schema.
302
+
303
+ ```typescript
304
+ // GOOD
305
+ Create('GetUser', {
306
+ schema: {
307
+ params: Type.Object({
308
+ userId: Type.String(),
309
+ debug: Type.Optional(Type.Boolean()), // Include in schema if needed
310
+ }),
311
+ },
312
+ }, handler)
313
+ ```
314
+
315
+ **Why:** AJV is configured with `removeAdditional: true`. Any property not defined in the schema is silently removed before the handler receives params.
316
+
317
+ ---
318
+
319
+ ## 11. Creating Factory Without Context Type When Using HTTP Builders
320
+
321
+ **Problem:** Using `Procedures()` without a context type, then registering with an HTTP builder that injects context.
322
+
323
+ ```typescript
324
+ // BAD — handler ctx has no type information
325
+ const { Create } = Procedures()
326
+
327
+ Create('GetUser', {}, async (ctx, params) => {
328
+ ctx.userId // Type error: Property 'userId' does not exist
329
+ })
330
+ ```
331
+
332
+ **Fix:** Always specify the context type.
333
+
334
+ ```typescript
335
+ // GOOD
336
+ const { Create } = Procedures<{ userId: string }>()
337
+
338
+ Create('GetUser', {}, async (ctx, params) => {
339
+ ctx.userId // Typed correctly
340
+ })
341
+ ```
342
+
343
+ ---
344
+
345
+ ## 12. Registering Standard Procedures with HonoStreamAppBuilder
346
+
347
+ **Problem:** Using `Create` procedures with `HonoStreamAppBuilder` — it only handles `CreateStream` procedures.
348
+
349
+ ```typescript
350
+ // BAD — Create procedures are silently ignored
351
+ const { Create, CreateStream } = Procedures<AppContext, RPCConfig>()
352
+ Create('GetUser', { scope: 'users', version: 1 }, handler)
353
+ CreateStream('StreamEvents', { scope: 'events', version: 1 }, streamHandler)
354
+
355
+ new HonoStreamAppBuilder()
356
+ .register(factory, ctx) // Only StreamEvents is registered
357
+ .build()
358
+ ```
359
+
360
+ **Fix:** Use `HonoRPCAppBuilder` or `ExpressRPCAppBuilder` for standard procedures. Use `HonoStreamAppBuilder` only for stream procedures.
361
+
362
+ ```typescript
363
+ // GOOD
364
+ const rpcApp = new HonoRPCAppBuilder().register(RPC, ctx).build()
365
+ const streamApp = new HonoStreamAppBuilder().register(StreamRPC, ctx).build()
366
+ ```
367
+
368
+ ---
369
+
370
+ ## 13. Missing Schema at Registration Time
371
+
372
+ **Problem:** Providing malformed or incompatible schema objects.
373
+
374
+ ```typescript
375
+ // BAD — plain objects are not valid schemas
376
+ Create('GetUser', {
377
+ schema: {
378
+ params: { type: 'object', properties: { id: { type: 'string' } } },
379
+ },
380
+ }, handler)
381
+ ```
382
+
383
+ **Fix:** Use TypeBox schema builders.
384
+
385
+ ```typescript
386
+ // GOOD — TypeBox
387
+ Create('GetUser', {
388
+ schema: { params: Type.Object({ id: Type.String() }) },
389
+ }, handler)
390
+ ```
391
+
392
+ **Why:** ts-procedures detects schema type via TypeBox's `~kind` symbol. Plain JSON Schema objects are not recognized and will throw `ProcedureRegistrationError`.
393
+
394
+ ---
395
+
396
+ ## 14. Not Handling Pre-Stream vs Mid-Stream Errors Differently
397
+
398
+ **Problem:** Using a single error handler for both validation errors (before streaming) and runtime errors (during streaming).
399
+
400
+ ```typescript
401
+ // BAD — onError doesn't apply to streaming
402
+ new HonoStreamAppBuilder({
403
+ onError: (proc, c, err) => { /* This doesn't exist */ },
404
+ })
405
+ ```
406
+
407
+ **Fix:** Use `onPreStreamError` for validation errors and `onMidStreamError` for runtime errors.
408
+
409
+ ```typescript
410
+ // GOOD
411
+ new HonoStreamAppBuilder({
412
+ onPreStreamError: (proc, c, error) => {
413
+ // Validation/context error — return normal HTTP response
414
+ return c.json({ error: error.message }, 400)
415
+ },
416
+ onMidStreamError: (proc, c, error) => {
417
+ // Runtime error during streaming — yield error event, then close
418
+ return { data: { error: error.message }, closeStream: true }
419
+ },
420
+ })
421
+ ```
422
+
423
+ ---
424
+
425
+ ## 15. Not Using extendProcedureDoc for Documentation
426
+
427
+ **Problem:** Manually building documentation from procedure metadata instead of using the built-in extension point.
428
+
429
+ ```typescript
430
+ // BAD — manual doc building, fragile and incomplete
431
+ const docs = getProcedures().map(p => ({
432
+ name: p.name,
433
+ path: `/${p.config.scope}/${p.name}/${p.config.version}`,
434
+ }))
435
+ ```
436
+
437
+ **Fix:** Use `extendProcedureDoc` in the HTTP builder registration.
438
+
439
+ ```typescript
440
+ // GOOD — base doc auto-generated with correct paths and schemas
441
+ builder.register(factory, context, ({ base, procedure }) => ({
442
+ summary: procedure.config.description,
443
+ tags: [base.scope],
444
+ }))
445
+
446
+ // Access via builder.docs
447
+ console.log(builder.docs)
448
+ ```
449
+
450
+ **Why:** The builder generates correct kebab-case paths, includes JSON schemas for body/response, and merges your extensions. Manual building duplicates this logic and easily drifts.
451
+
452
+ ---
453
+
454
+ ## 16. Using Async Context Factory Without Error Handling
455
+
456
+ **Problem:** Async context factories that throw unhandled errors, crashing the request.
457
+
458
+ ```typescript
459
+ // BAD — if authenticate() throws, request crashes
460
+ builder.register(factory, async (req) => {
461
+ const user = await authenticate(req.headers.authorization)
462
+ return { userId: user.id }
463
+ })
464
+ ```
465
+
466
+ **Fix:** Use the builder's `onError` callback to handle context resolution failures gracefully.
467
+
468
+ ```typescript
469
+ // GOOD
470
+ new ExpressRPCAppBuilder({
471
+ onError: (procedure, req, res, error) => {
472
+ if (error.message.includes('Unauthorized')) {
473
+ res.status(401).json({ error: 'Unauthorized' })
474
+ } else {
475
+ res.status(500).json({ error: 'Internal server error' })
476
+ }
477
+ },
478
+ })
479
+ ```
480
+
481
+ ---
482
+
483
+ ## 17. Using Both schema.params and schema.input
484
+
485
+ **Problem:** Defining both `schema.params` and `schema.input` on the same procedure.
486
+
487
+ ```typescript
488
+ // BAD — throws ProcedureRegistrationError at registration
489
+ Create('GetUser', {
490
+ path: '/users/:id',
491
+ method: 'get',
492
+ schema: {
493
+ params: Type.Object({ id: Type.String() }),
494
+ input: {
495
+ pathParams: Type.Object({ id: Type.String() }),
496
+ },
497
+ },
498
+ }, handler)
499
+ ```
500
+
501
+ **Fix:** Choose one. Use `schema.params` for flat RPC-style input, `schema.input` for structured multi-channel input.
502
+
503
+ ```typescript
504
+ // GOOD — schema.input for REST-style with per-channel validation
505
+ Create('GetUser', {
506
+ path: '/users/:id',
507
+ method: 'get',
508
+ schema: {
509
+ input: {
510
+ pathParams: Type.Object({ id: Type.String() }),
511
+ },
512
+ },
513
+ }, async (ctx, { pathParams }) => fetchUser(pathParams.id))
514
+
515
+ // GOOD — schema.params for simple RPC-style
516
+ Create('GetUser', {
517
+ scope: 'users', version: 1,
518
+ schema: { params: Type.Object({ id: Type.String() }) },
519
+ }, async (ctx, params) => fetchUser(params.id))
520
+ ```
521
+
522
+ **Why:** `schema.params` and `schema.input` are mutually exclusive by design. They represent different input paradigms — flat (RPC) vs structured (HTTP API).
523
+
524
+ ---
525
+
526
+ ## 18. Mismatched Path Param Names in schema.input
527
+
528
+ **Problem:** Path template param names don't match `schema.input.pathParams` property names.
529
+
530
+ ```typescript
531
+ // BAD — path has :id but schema declares userId — throws at build time
532
+ Create('GetUser', {
533
+ path: '/users/:id',
534
+ method: 'get',
535
+ schema: {
536
+ input: {
537
+ pathParams: Type.Object({ userId: Type.String() }), // Wrong name!
538
+ },
539
+ },
540
+ }, handler)
541
+ ```
542
+
543
+ **Fix:** Ensure path param names match schema property names exactly.
544
+
545
+ ```typescript
546
+ // GOOD
547
+ Create('GetUser', {
548
+ path: '/users/:id',
549
+ method: 'get',
550
+ schema: {
551
+ input: {
552
+ pathParams: Type.Object({ id: Type.String() }), // Matches :id
553
+ },
554
+ },
555
+ }, handler)
556
+ ```
557
+
558
+ **Why:** `HonoAPIAppBuilder` validates at build time that `:param` names in the path match schema properties. A mismatch would cause runtime validation failures with confusing error messages.
559
+
560
+ ---
561
+
562
+ ## 19. Forgetting build() is Async on HonoAPIAppBuilder
563
+
564
+ **Problem:** Not awaiting `build()` on `HonoAPIAppBuilder`.
565
+
566
+ ```typescript
567
+ // BAD — build() returns Promise<Hono>, not Hono
568
+ const app = new HonoAPIAppBuilder()
569
+ .register(API, ctx)
570
+ .build() // This is a Promise!
571
+ ```
572
+
573
+ **Fix:** Await the build call.
574
+
575
+ ```typescript
576
+ // GOOD
577
+ const app = await new HonoAPIAppBuilder()
578
+ .register(API, ctx)
579
+ .build()
580
+ ```
581
+
582
+ **Why:** `HonoAPIAppBuilder.build()` is async because it resolves the query parser (lazy-loads `qs` optional peer dependency) once at build time for synchronous per-request usage.
583
+
584
+ ---
585
+
586
+ ## Summary Table
587
+
588
+ | # | Anti-Pattern | Risk | Severity |
589
+ |---|-------------|------|----------|
590
+ | 1 | Raw Error instead of ctx.error() | Lost metadata, inconsistent handling | CRITICAL |
591
+ | 2 | Manual validation in handler | Duplicated logic, less thorough | WARNING |
592
+ | 3 | Expecting returnType validation | Silent data contract violations | CRITICAL |
593
+ | 4 | Ignoring ctx.signal | Resource waste on cancelled requests | WARNING |
594
+ | 5 | No signal check in stream loops | Infinite resource consumption | CRITICAL |
595
+ | 6 | Duplicate procedure names | ProcedureRegistrationError at startup | CRITICAL |
596
+ | 7 | validateYields without yieldType | Silent no-op, false confidence | WARNING |
597
+ | 8 | Swallowing errors | Hidden failures, debugging difficulty | CRITICAL |
598
+ | 9 | Manual type coercion | Unnecessary code, coercion mismatch | SUGGESTION |
599
+ | 10 | Expecting extra fields to survive | Silent data loss | WARNING |
600
+ | 11 | Missing context type | No type safety in handlers | WARNING |
601
+ | 12 | Create with HonoStreamAppBuilder | Procedures silently ignored | CRITICAL |
602
+ | 13 | Plain JSON Schema objects instead of TypeBox | ProcedureRegistrationError | CRITICAL |
603
+ | 14 | Wrong error handler for streams | Unhandled errors or wrong response format | WARNING |
604
+ | 15 | Manual doc building | Fragile, incomplete documentation | SUGGESTION |
605
+ | 16 | Unhandled async context factory | Request crashes | WARNING |
606
+ | 17 | Both schema.params and schema.input | ProcedureRegistrationError at startup | CRITICAL |
607
+ | 18 | Mismatched path param names | Build-time error or confusing validation failures | CRITICAL |
608
+ | 19 | Not awaiting HonoAPIAppBuilder.build() | Using unresolved Promise as app | CRITICAL |