raffel 0.1.2 → 0.2.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 (268) hide show
  1. package/README.md +314 -346
  2. package/dist/adapters/index.d.ts +3 -1
  3. package/dist/adapters/index.d.ts.map +1 -1
  4. package/dist/adapters/index.js +3 -1
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/adapters/s3db/adapter.d.ts.map +1 -1
  7. package/dist/adapters/s3db/adapter.js +0 -3
  8. package/dist/adapters/s3db/adapter.js.map +1 -1
  9. package/dist/adapters/udp.d.ts +83 -0
  10. package/dist/adapters/udp.d.ts.map +1 -0
  11. package/dist/adapters/udp.int.test.d.ts +5 -0
  12. package/dist/adapters/udp.int.test.d.ts.map +1 -0
  13. package/dist/adapters/udp.int.test.js +397 -0
  14. package/dist/adapters/udp.int.test.js.map +1 -0
  15. package/dist/adapters/udp.js +391 -0
  16. package/dist/adapters/udp.js.map +1 -0
  17. package/dist/cache/drivers/file.d.ts.map +1 -1
  18. package/dist/cache/drivers/file.js +13 -1
  19. package/dist/cache/drivers/file.js.map +1 -1
  20. package/dist/cache/drivers/memory.d.ts.map +1 -1
  21. package/dist/cache/drivers/memory.js +1 -0
  22. package/dist/cache/drivers/memory.js.map +1 -1
  23. package/dist/cache/types.d.ts +1 -0
  24. package/dist/cache/types.d.ts.map +1 -1
  25. package/dist/docs/generators/http-generator.d.ts.map +1 -1
  26. package/dist/docs/generators/http-generator.js +0 -1
  27. package/dist/docs/generators/http-generator.js.map +1 -1
  28. package/dist/graphql/graphql.int.test.d.ts +10 -0
  29. package/dist/graphql/graphql.int.test.d.ts.map +1 -0
  30. package/dist/graphql/graphql.int.test.js +698 -0
  31. package/dist/graphql/graphql.int.test.js.map +1 -0
  32. package/dist/graphql/schema-generator.d.ts.map +1 -1
  33. package/dist/graphql/schema-generator.js +20 -7
  34. package/dist/graphql/schema-generator.js.map +1 -1
  35. package/dist/http/auth.d.ts.map +1 -1
  36. package/dist/http/auth.js +15 -1
  37. package/dist/http/auth.js.map +1 -1
  38. package/dist/http/http.int.test.d.ts +7 -0
  39. package/dist/http/http.int.test.d.ts.map +1 -0
  40. package/dist/http/http.int.test.js +604 -0
  41. package/dist/http/http.int.test.js.map +1 -0
  42. package/dist/http/index.d.ts +2 -0
  43. package/dist/http/index.d.ts.map +1 -1
  44. package/dist/http/index.js +2 -0
  45. package/dist/http/index.js.map +1 -1
  46. package/dist/http/oauth2.d.ts.map +1 -1
  47. package/dist/http/oauth2.js +39 -0
  48. package/dist/http/oauth2.js.map +1 -1
  49. package/dist/http/oidc.d.ts.map +1 -1
  50. package/dist/http/oidc.js +9 -1
  51. package/dist/http/oidc.js.map +1 -1
  52. package/dist/http/session-redis.d.ts +187 -0
  53. package/dist/http/session-redis.d.ts.map +1 -0
  54. package/dist/http/session-redis.int.test.d.ts +8 -0
  55. package/dist/http/session-redis.int.test.d.ts.map +1 -0
  56. package/dist/http/session-redis.int.test.js +492 -0
  57. package/dist/http/session-redis.int.test.js.map +1 -0
  58. package/dist/http/session-redis.js +320 -0
  59. package/dist/http/session-redis.js.map +1 -0
  60. package/dist/index.d.ts +2 -1
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +25 -0
  63. package/dist/index.js.map +1 -1
  64. package/dist/mcp/cli.js +2 -1
  65. package/dist/mcp/cli.js.map +1 -1
  66. package/dist/mcp/docs/adapters.d.ts.map +1 -1
  67. package/dist/mcp/docs/adapters.js +175 -145
  68. package/dist/mcp/docs/adapters.js.map +1 -1
  69. package/dist/mcp/docs/interceptors.d.ts +1 -1
  70. package/dist/mcp/docs/interceptors.d.ts.map +1 -1
  71. package/dist/mcp/docs/interceptors.js +231 -305
  72. package/dist/mcp/docs/interceptors.js.map +1 -1
  73. package/dist/mcp/docs/patterns.d.ts.map +1 -1
  74. package/dist/mcp/docs/patterns.js +20 -18
  75. package/dist/mcp/docs/patterns.js.map +1 -1
  76. package/dist/mcp/docs/quickstart.d.ts +1 -1
  77. package/dist/mcp/docs/quickstart.d.ts.map +1 -1
  78. package/dist/mcp/docs/quickstart.js +48 -46
  79. package/dist/mcp/docs/quickstart.js.map +1 -1
  80. package/dist/mcp/server.d.ts +1 -1
  81. package/dist/mcp/server.d.ts.map +1 -1
  82. package/dist/mcp/server.js +6 -7
  83. package/dist/mcp/server.js.map +1 -1
  84. package/dist/mcp/version.d.ts +7 -0
  85. package/dist/mcp/version.d.ts.map +1 -0
  86. package/dist/mcp/version.js +20 -0
  87. package/dist/mcp/version.js.map +1 -0
  88. package/dist/middleware/auth/oauth2.d.ts +294 -0
  89. package/dist/middleware/auth/oauth2.d.ts.map +1 -0
  90. package/dist/middleware/auth/oauth2.int.test.d.ts +2 -0
  91. package/dist/middleware/auth/oauth2.int.test.d.ts.map +1 -0
  92. package/dist/middleware/auth/oauth2.int.test.js +714 -0
  93. package/dist/middleware/auth/oauth2.int.test.js.map +1 -0
  94. package/dist/middleware/auth/oauth2.js +671 -0
  95. package/dist/middleware/auth/oauth2.js.map +1 -0
  96. package/dist/middleware/auth.d.ts +2 -0
  97. package/dist/middleware/auth.d.ts.map +1 -1
  98. package/dist/middleware/auth.js +16 -0
  99. package/dist/middleware/auth.js.map +1 -1
  100. package/dist/middleware/index.d.ts +5 -2
  101. package/dist/middleware/index.d.ts.map +1 -1
  102. package/dist/middleware/index.js +4 -0
  103. package/dist/middleware/index.js.map +1 -1
  104. package/dist/middleware/interceptors/circuit-breaker.d.ts.map +1 -1
  105. package/dist/middleware/interceptors/circuit-breaker.js +0 -1
  106. package/dist/middleware/interceptors/circuit-breaker.js.map +1 -1
  107. package/dist/middleware/interceptors/envelope.d.ts +176 -0
  108. package/dist/middleware/interceptors/envelope.d.ts.map +1 -0
  109. package/dist/middleware/interceptors/envelope.int.test.d.ts +5 -0
  110. package/dist/middleware/interceptors/envelope.int.test.d.ts.map +1 -0
  111. package/dist/middleware/interceptors/envelope.int.test.js +409 -0
  112. package/dist/middleware/interceptors/envelope.int.test.js.map +1 -0
  113. package/dist/middleware/interceptors/envelope.js +294 -0
  114. package/dist/middleware/interceptors/envelope.js.map +1 -0
  115. package/dist/middleware/interceptors/index.d.ts +2 -0
  116. package/dist/middleware/interceptors/index.d.ts.map +1 -1
  117. package/dist/middleware/interceptors/index.js +2 -0
  118. package/dist/middleware/interceptors/index.js.map +1 -1
  119. package/dist/middleware/types.d.ts +25 -0
  120. package/dist/middleware/types.d.ts.map +1 -1
  121. package/dist/rate-limit/drivers/drivers.int.test.d.ts +7 -0
  122. package/dist/rate-limit/drivers/drivers.int.test.d.ts.map +1 -0
  123. package/dist/rate-limit/drivers/drivers.int.test.js +466 -0
  124. package/dist/rate-limit/drivers/drivers.int.test.js.map +1 -0
  125. package/dist/server/builder.d.ts.map +1 -1
  126. package/dist/server/builder.int.test.js +41 -0
  127. package/dist/server/builder.int.test.js.map +1 -1
  128. package/dist/server/builder.js +72 -15
  129. package/dist/server/builder.js.map +1 -1
  130. package/dist/server/channel-utils.d.ts +4 -1
  131. package/dist/server/channel-utils.d.ts.map +1 -1
  132. package/dist/server/channel-utils.js +12 -2
  133. package/dist/server/channel-utils.js.map +1 -1
  134. package/dist/server/errors.d.ts.map +1 -1
  135. package/dist/server/errors.js +0 -22
  136. package/dist/server/errors.js.map +1 -1
  137. package/dist/server/fs-routes/watcher.js +1 -1
  138. package/dist/server/fs-routes/watcher.js.map +1 -1
  139. package/dist/server/index.d.ts +1 -1
  140. package/dist/server/index.d.ts.map +1 -1
  141. package/dist/server/index.js.map +1 -1
  142. package/dist/server/types.d.ts +37 -33
  143. package/dist/server/types.d.ts.map +1 -1
  144. package/dist/tracing/interceptor.d.ts.map +1 -1
  145. package/dist/tracing/interceptor.js +4 -5
  146. package/dist/tracing/interceptor.js.map +1 -1
  147. package/dist/types/envelope.d.ts +1 -1
  148. package/dist/types/envelope.d.ts.map +1 -1
  149. package/dist/types/envelope.js.map +1 -1
  150. package/dist/types/handlers.d.ts +8 -0
  151. package/dist/types/handlers.d.ts.map +1 -1
  152. package/dist/ui/core/index.d.ts +7 -0
  153. package/dist/ui/core/index.d.ts.map +1 -0
  154. package/dist/ui/docs/generators/content-types.d.ts +10 -0
  155. package/dist/ui/docs/generators/content-types.d.ts.map +1 -0
  156. package/dist/ui/docs/generators/errors-types.d.ts +409 -0
  157. package/dist/ui/docs/generators/errors-types.d.ts.map +1 -0
  158. package/dist/ui/docs/generators/errors.d.ts +88 -0
  159. package/dist/ui/docs/generators/errors.d.ts.map +1 -0
  160. package/dist/ui/docs/generators/grpc-generator.d.ts +53 -0
  161. package/dist/ui/docs/generators/grpc-generator.d.ts.map +1 -0
  162. package/dist/ui/docs/generators/http-generator.d.ts +49 -0
  163. package/dist/ui/docs/generators/http-generator.d.ts.map +1 -0
  164. package/dist/ui/docs/generators/index.d.ts +17 -0
  165. package/dist/ui/docs/generators/index.d.ts.map +1 -0
  166. package/dist/ui/docs/generators/jsonrpc-generator.d.ts +53 -0
  167. package/dist/ui/docs/generators/jsonrpc-generator.d.ts.map +1 -0
  168. package/dist/ui/docs/generators/schema-converter.d.ts +117 -0
  169. package/dist/ui/docs/generators/schema-converter.d.ts.map +1 -0
  170. package/dist/ui/docs/generators/streams-generator.d.ts +85 -0
  171. package/dist/ui/docs/generators/streams-generator.d.ts.map +1 -0
  172. package/dist/ui/docs/generators/tcp-generator.d.ts +133 -0
  173. package/dist/ui/docs/generators/tcp-generator.d.ts.map +1 -0
  174. package/dist/ui/docs/generators/udp-generator.d.ts +119 -0
  175. package/dist/ui/docs/generators/udp-generator.d.ts.map +1 -0
  176. package/dist/ui/docs/generators/usd-generator.d.ts +182 -0
  177. package/dist/ui/docs/generators/usd-generator.d.ts.map +1 -0
  178. package/dist/ui/docs/generators/websocket-generator.d.ts +49 -0
  179. package/dist/ui/docs/generators/websocket-generator.d.ts.map +1 -0
  180. package/dist/ui/docs/index.d.ts +31 -0
  181. package/dist/ui/docs/index.d.ts.map +1 -0
  182. package/dist/ui/docs/usd-middleware.d.ts +157 -0
  183. package/dist/ui/docs/usd-middleware.d.ts.map +1 -0
  184. package/dist/ui/errors/factories.d.ts +142 -0
  185. package/dist/ui/errors/factories.d.ts.map +1 -0
  186. package/dist/ui/errors/index.d.ts +9 -0
  187. package/dist/ui/errors/index.d.ts.map +1 -0
  188. package/dist/ui/server/fs-routes/index.d.ts +66 -0
  189. package/dist/ui/server/fs-routes/index.d.ts.map +1 -0
  190. package/dist/ui/server/fs-routes/loader.d.ts +28 -0
  191. package/dist/ui/server/fs-routes/loader.d.ts.map +1 -0
  192. package/dist/ui/server/fs-routes/middleware-processor.d.ts +19 -0
  193. package/dist/ui/server/fs-routes/middleware-processor.d.ts.map +1 -0
  194. package/dist/ui/server/fs-routes/resources/index.d.ts +8 -0
  195. package/dist/ui/server/fs-routes/resources/index.d.ts.map +1 -0
  196. package/dist/ui/server/fs-routes/resources/loader.d.ts +16 -0
  197. package/dist/ui/server/fs-routes/resources/loader.d.ts.map +1 -0
  198. package/dist/ui/server/fs-routes/resources/types.d.ts +256 -0
  199. package/dist/ui/server/fs-routes/resources/types.d.ts.map +1 -0
  200. package/dist/ui/server/fs-routes/rest/index.d.ts +8 -0
  201. package/dist/ui/server/fs-routes/rest/index.d.ts.map +1 -0
  202. package/dist/ui/server/fs-routes/rest/loader.d.ts +11 -0
  203. package/dist/ui/server/fs-routes/rest/loader.d.ts.map +1 -0
  204. package/dist/ui/server/fs-routes/rest/types.d.ts +288 -0
  205. package/dist/ui/server/fs-routes/rest/types.d.ts.map +1 -0
  206. package/dist/ui/server/fs-routes/tcp/index.d.ts +8 -0
  207. package/dist/ui/server/fs-routes/tcp/index.d.ts.map +1 -0
  208. package/dist/ui/server/fs-routes/tcp/loader.d.ts +15 -0
  209. package/dist/ui/server/fs-routes/tcp/loader.d.ts.map +1 -0
  210. package/dist/ui/server/fs-routes/tcp/types.d.ts +215 -0
  211. package/dist/ui/server/fs-routes/tcp/types.d.ts.map +1 -0
  212. package/dist/ui/server/fs-routes/types.d.ts +437 -0
  213. package/dist/ui/server/fs-routes/types.d.ts.map +1 -0
  214. package/dist/ui/server/fs-routes/udp/index.d.ts +8 -0
  215. package/dist/ui/server/fs-routes/udp/index.d.ts.map +1 -0
  216. package/dist/ui/server/fs-routes/udp/loader.d.ts +15 -0
  217. package/dist/ui/server/fs-routes/udp/loader.d.ts.map +1 -0
  218. package/dist/ui/server/fs-routes/udp/types.d.ts +164 -0
  219. package/dist/ui/server/fs-routes/udp/types.d.ts.map +1 -0
  220. package/dist/ui/server/fs-routes/watcher.d.ts +34 -0
  221. package/dist/ui/server/fs-routes/watcher.d.ts.map +1 -0
  222. package/dist/ui/types/envelope.d.ts +1 -1
  223. package/dist/ui/types/envelope.d.ts.map +1 -1
  224. package/dist/ui/types/handlers.d.ts +8 -0
  225. package/dist/ui/types/handlers.d.ts.map +1 -1
  226. package/dist/ui/usd/builder/document.d.ts.map +1 -1
  227. package/dist/ui/usd/export/openapi.d.ts.map +1 -1
  228. package/dist/ui/usd/parser/normalize.d.ts.map +1 -1
  229. package/dist/ui/usd/spec/types.d.ts +14 -20
  230. package/dist/ui/usd/spec/types.d.ts.map +1 -1
  231. package/dist/ui/usd/utils/refs.d.ts.map +1 -1
  232. package/dist/ui/usd/validator/index.d.ts.map +1 -1
  233. package/dist/ui/usd/validator/schema.d.ts.map +1 -1
  234. package/dist/ui/usd/validator/semantic.d.ts.map +1 -1
  235. package/dist/ui/utils/logger.d.ts +15 -0
  236. package/dist/ui/utils/logger.d.ts.map +1 -0
  237. package/dist/usd/builder/document.d.ts.map +1 -1
  238. package/dist/usd/builder/document.js.map +1 -1
  239. package/dist/usd/export/openapi.d.ts.map +1 -1
  240. package/dist/usd/export/openapi.js +2 -4
  241. package/dist/usd/export/openapi.js.map +1 -1
  242. package/dist/usd/parser/normalize.d.ts.map +1 -1
  243. package/dist/usd/parser/normalize.js +0 -1
  244. package/dist/usd/parser/normalize.js.map +1 -1
  245. package/dist/usd/usd.int.test.d.ts +10 -0
  246. package/dist/usd/usd.int.test.d.ts.map +1 -0
  247. package/dist/usd/usd.int.test.js +719 -0
  248. package/dist/usd/usd.int.test.js.map +1 -0
  249. package/dist/usd/utils/refs.d.ts.map +1 -1
  250. package/dist/usd/validator/index.d.ts.map +1 -1
  251. package/dist/usd/validator/index.js.map +1 -1
  252. package/dist/usd/validator/schema.d.ts.map +1 -1
  253. package/dist/usd/validator/schema.js.map +1 -1
  254. package/dist/usd/validator/semantic.d.ts.map +1 -1
  255. package/dist/usd/validator/semantic.js.map +1 -1
  256. package/package.json +1 -1
  257. package/dist/middleware/rate-limit.d.ts +0 -105
  258. package/dist/middleware/rate-limit.d.ts.map +0 -1
  259. package/dist/middleware/rate-limit.int.test.d.ts +0 -5
  260. package/dist/middleware/rate-limit.int.test.d.ts.map +0 -1
  261. package/dist/middleware/rate-limit.int.test.js +0 -350
  262. package/dist/middleware/rate-limit.int.test.js.map +0 -1
  263. package/dist/middleware/rate-limit.js +0 -206
  264. package/dist/middleware/rate-limit.js.map +0 -1
  265. package/dist/openapi/index.d.ts +0 -9
  266. package/dist/openapi/index.d.ts.map +0 -1
  267. package/dist/openapi/index.js +0 -9
  268. package/dist/openapi/index.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Raffel MCP - Interceptor Documentation
3
3
  *
4
- * All built-in interceptors with options, examples, and use cases.
4
+ * Built-in interceptors with options, examples, and use cases.
5
5
  */
6
6
  export const interceptors = [
7
7
  // === Auth ===
@@ -11,30 +11,22 @@ export const interceptors = [
11
11
  category: 'auth',
12
12
  options: [
13
13
  {
14
- name: 'strategy',
15
- type: 'AuthStrategy',
14
+ name: 'strategies',
15
+ type: 'AuthStrategy[]',
16
16
  required: true,
17
- description: 'Authentication strategy (bearer, apiKey, static)',
17
+ description: 'Authentication strategies to try in order',
18
18
  },
19
19
  {
20
- name: 'extractFrom',
21
- type: "'header' | 'query' | 'cookie'",
20
+ name: 'publicProcedures',
21
+ type: 'string[]',
22
22
  required: false,
23
- default: "'header'",
24
- description: 'Where to extract the credential from',
23
+ description: 'Procedures that skip authentication',
25
24
  },
26
25
  {
27
- name: 'headerName',
28
- type: 'string',
29
- required: false,
30
- default: "'Authorization'",
31
- description: 'Header name for credential extraction',
32
- },
33
- {
34
- name: 'onUnauthenticated',
35
- type: '(ctx) => void',
26
+ name: 'onError',
27
+ type: '(error, envelope) => void',
36
28
  required: false,
37
- description: 'Callback when authentication fails',
29
+ description: 'Hook for strategy errors (non-fatal)',
38
30
  },
39
31
  ],
40
32
  examples: [
@@ -44,47 +36,18 @@ export const interceptors = [
44
36
 
45
37
  const server = createServer()
46
38
  .use(createAuthMiddleware({
47
- strategy: createBearerStrategy({
48
- validate: async (token) => {
49
- const user = await verifyJwt(token)
50
- return user ? { authenticated: true, principal: user } : { authenticated: false }
39
+ strategies: [createBearerStrategy({
40
+ verify: async (token) => {
41
+ const payload = await verifyJwt(token)
42
+ return payload ? { authenticated: true, principal: payload.sub, claims: payload } : null
51
43
  }
52
- })
44
+ })]
53
45
  }))
54
46
  .procedure('users.me')
55
- .handler(async (input, ctx) => {
56
- // ctx.auth.principal contains the authenticated user
57
- return ctx.auth.principal
47
+ .handler(async (_input, ctx) => {
48
+ return { userId: ctx.auth?.principal }
58
49
  })`,
59
50
  },
60
- {
61
- title: 'API Key Authentication',
62
- code: `import { createServer, createAuthMiddleware, createApiKeyStrategy } from 'raffel'
63
-
64
- const server = createServer()
65
- .use(createAuthMiddleware({
66
- strategy: createApiKeyStrategy({
67
- validate: async (key) => {
68
- const app = await db.apiKeys.findByKey(key)
69
- return app ? { authenticated: true, principal: app } : { authenticated: false }
70
- },
71
- extractFrom: 'header',
72
- headerName: 'X-API-Key'
73
- })
74
- }))`,
75
- },
76
- {
77
- title: 'Static API Key (Development)',
78
- code: `import { createServer, createAuthMiddleware, createStaticApiKeyStrategy } from 'raffel'
79
-
80
- const server = createServer()
81
- .use(createAuthMiddleware({
82
- strategy: createStaticApiKeyStrategy({
83
- keys: ['dev-key-123', 'test-key-456'],
84
- principal: { role: 'admin' }
85
- })
86
- }))`,
87
- },
88
51
  ],
89
52
  },
90
53
  {
@@ -99,24 +62,24 @@ const server = createServer()
99
62
  description: 'Array of authorization rules to evaluate',
100
63
  },
101
64
  {
102
- name: 'defaultDeny',
65
+ name: 'defaultAllow',
103
66
  type: 'boolean',
104
67
  required: false,
105
- default: 'true',
106
- description: 'Deny access if no rule matches',
68
+ default: 'false',
69
+ description: 'Allow access if no rule matches',
107
70
  },
108
71
  ],
109
72
  examples: [
110
73
  {
111
74
  title: 'Role-Based Access Control',
112
- code: `import { createServer, createAuthzMiddleware, hasRole, hasAnyRole } from 'raffel'
75
+ code: `import { createServer, createAuthzMiddleware, hasRole, hasAnyRole, requireAuth } from 'raffel'
113
76
 
114
77
  const server = createServer()
115
78
  .use(createAuthzMiddleware({
116
79
  rules: [
117
80
  { pattern: 'admin.*', check: hasRole('admin') },
118
81
  { pattern: 'users.delete', check: hasAnyRole(['admin', 'moderator']) },
119
- { pattern: 'users.*', check: requireAuth() },
82
+ { pattern: 'users.*', check: requireAuth },
120
83
  ]
121
84
  }))`,
122
85
  },
@@ -142,11 +105,23 @@ const server = createServer()
142
105
  default: '100',
143
106
  description: 'Maximum requests per window',
144
107
  },
108
+ {
109
+ name: 'maxUniqueKeys',
110
+ type: 'number',
111
+ required: false,
112
+ description: 'Maximum unique keys to track',
113
+ },
114
+ {
115
+ name: 'skipSuccessfulRequests',
116
+ type: 'boolean',
117
+ required: false,
118
+ description: 'If true, successful requests are not counted',
119
+ },
145
120
  {
146
121
  name: 'keyGenerator',
147
122
  type: '(envelope, ctx) => string',
148
123
  required: false,
149
- description: 'Function to generate rate limit key (default: user or IP)',
124
+ description: 'Function to generate rate limit key (default: user or metadata)',
150
125
  },
151
126
  {
152
127
  name: 'rules',
@@ -156,9 +131,8 @@ const server = createServer()
156
131
  },
157
132
  {
158
133
  name: 'driver',
159
- type: 'string | RateLimitDriver',
134
+ type: 'RateLimitDriverConfig | RateLimitDriver',
160
135
  required: false,
161
- default: 'memory',
162
136
  description: 'Storage driver (memory, filesystem, redis, or custom)',
163
137
  },
164
138
  ],
@@ -170,27 +144,14 @@ const server = createServer()
170
144
  const server = createServer()
171
145
  .use(createRateLimitInterceptor({
172
146
  windowMs: 60 * 1000, // 1 minute
173
- maxRequests: 100, // 100 requests per minute
174
- }))`,
175
- },
176
- {
177
- title: 'Per-Procedure Rules',
178
- code: `import { createServer, createRateLimitInterceptor } from 'raffel'
179
-
180
- const server = createServer()
181
- .use(createRateLimitInterceptor({
182
147
  maxRequests: 100,
183
- rules: [
184
- { id: 'auth', pattern: 'auth.*', maxRequests: 5, windowMs: 60000 },
185
- { id: 'reports', pattern: 'reports.*', maxRequests: 10, windowMs: 3600000 },
186
- ]
187
148
  }))`,
188
149
  },
189
150
  ],
190
151
  },
191
152
  {
192
- name: 'retry',
193
- description: 'Automatic retry with exponential backoff for transient failures. Use for downstream service calls.',
153
+ name: 'createRetryInterceptor',
154
+ description: 'Automatic retry with backoff for transient failures. Use for downstream service calls.',
194
155
  category: 'resilience',
195
156
  options: [
196
157
  {
@@ -201,50 +162,55 @@ const server = createServer()
201
162
  description: 'Maximum retry attempts',
202
163
  },
203
164
  {
204
- name: 'initialDelay',
165
+ name: 'initialDelayMs',
205
166
  type: 'number',
206
167
  required: false,
207
- default: '1000',
168
+ default: '100',
208
169
  description: 'Initial delay in ms before first retry',
209
170
  },
210
171
  {
211
- name: 'maxDelay',
172
+ name: 'maxDelayMs',
212
173
  type: 'number',
213
174
  required: false,
214
- default: '30000',
175
+ default: '10000',
215
176
  description: 'Maximum delay between retries',
216
177
  },
217
178
  {
218
- name: 'backoffMultiplier',
219
- type: 'number',
179
+ name: 'backoffStrategy',
180
+ type: "'linear' | 'exponential' | 'decorrelated'",
220
181
  required: false,
221
- default: '2',
222
- description: 'Multiplier for exponential backoff',
182
+ default: "'exponential'",
183
+ description: 'Backoff strategy',
223
184
  },
224
185
  {
225
- name: 'retryOn',
226
- type: '(error) => boolean',
186
+ name: 'retryableCodes',
187
+ type: 'string[]',
227
188
  required: false,
228
- description: 'Predicate to decide if error is retryable',
189
+ description: 'Error codes that should trigger retry',
190
+ },
191
+ {
192
+ name: 'shouldRetry',
193
+ type: '(error, attempt) => boolean',
194
+ required: false,
195
+ description: 'Custom retry predicate',
229
196
  },
230
197
  ],
231
198
  examples: [
232
199
  {
233
- title: 'Retry with Exponential Backoff',
234
- code: `import { createServer, forPattern, retry } from 'raffel'
200
+ title: 'Retry External Calls',
201
+ code: `import { createServer, forPattern, createRetryInterceptor } from 'raffel'
235
202
 
236
203
  const server = createServer()
237
- .use(forPattern('external.*', retry({
204
+ .use(forPattern('external.*', createRetryInterceptor({
238
205
  maxAttempts: 3,
239
- initialDelay: 1000,
240
- backoffMultiplier: 2,
241
- retryOn: (err) => err.code === 'ECONNREFUSED' || err.status >= 500
206
+ initialDelayMs: 200,
207
+ retryableCodes: ['UNAVAILABLE', 'DEADLINE_EXCEEDED'],
242
208
  })))`,
243
209
  },
244
210
  ],
245
211
  },
246
212
  {
247
- name: 'circuitBreaker',
213
+ name: 'createCircuitBreakerInterceptor',
248
214
  description: 'Circuit breaker pattern to prevent cascading failures. Opens circuit after threshold failures.',
249
215
  category: 'resilience',
250
216
  options: [
@@ -259,19 +225,32 @@ const server = createServer()
259
225
  name: 'successThreshold',
260
226
  type: 'number',
261
227
  required: false,
262
- default: '2',
228
+ default: '3',
263
229
  description: 'Successes before circuit closes',
264
230
  },
265
231
  {
266
- name: 'timeout',
232
+ name: 'resetTimeoutMs',
267
233
  type: 'number',
268
234
  required: false,
269
235
  default: '30000',
270
- description: 'Time in ms before attempting to close',
236
+ description: 'Time in ms before attempting recovery',
237
+ },
238
+ {
239
+ name: 'windowMs',
240
+ type: 'number',
241
+ required: false,
242
+ default: '60000',
243
+ description: 'Failure counting window in ms',
244
+ },
245
+ {
246
+ name: 'failureCodes',
247
+ type: 'string[]',
248
+ required: false,
249
+ description: 'Error codes that count as failures',
271
250
  },
272
251
  {
273
252
  name: 'onStateChange',
274
- type: '(state) => void',
253
+ type: '(state, procedure) => void',
275
254
  required: false,
276
255
  description: 'Callback when circuit state changes',
277
256
  },
@@ -279,70 +258,64 @@ const server = createServer()
279
258
  examples: [
280
259
  {
281
260
  title: 'Circuit Breaker for External Service',
282
- code: `import { createServer, forPattern, circuitBreaker } from 'raffel'
261
+ code: `import { createServer, forPattern, createCircuitBreakerInterceptor } from 'raffel'
283
262
 
284
263
  const server = createServer()
285
- .use(forPattern('payments.*', circuitBreaker({
286
- failureThreshold: 5, // Open after 5 failures
287
- successThreshold: 2, // Close after 2 successes in half-open
288
- timeout: 30000, // Try half-open after 30s
289
- onStateChange: (state) => {
290
- console.log(\`Circuit breaker state: \${state}\`)
291
- if (state === 'open') alertOps('Payment service circuit open!')
292
- }
264
+ .use(forPattern('payments.*', createCircuitBreakerInterceptor({
265
+ failureThreshold: 5,
266
+ resetTimeoutMs: 30000,
293
267
  })))`,
294
268
  },
295
269
  ],
296
270
  },
297
271
  {
298
- name: 'timeout',
299
- description: 'Enforces deadline on handler execution. Rejects with DEADLINE_EXCEEDED if exceeded.',
272
+ name: 'createTimeoutInterceptor',
273
+ description: 'Enforces deadline on handler execution (DEADLINE_EXCEEDED on timeout).',
300
274
  category: 'resilience',
301
275
  options: [
302
276
  {
303
- name: 'ms',
277
+ name: 'defaultMs',
304
278
  type: 'number',
305
- required: true,
306
- description: 'Timeout in milliseconds',
279
+ required: false,
280
+ default: '30000',
281
+ description: 'Default timeout in ms',
282
+ },
283
+ {
284
+ name: 'procedures',
285
+ type: 'Record<string, number>',
286
+ required: false,
287
+ description: 'Per-procedure timeouts',
307
288
  },
308
289
  {
309
- name: 'onTimeout',
310
- type: '(ctx) => void',
290
+ name: 'patterns',
291
+ type: 'Record<string, number>',
311
292
  required: false,
312
- description: 'Callback when timeout occurs',
293
+ description: 'Pattern-based timeouts',
313
294
  },
314
295
  ],
315
296
  examples: [
316
297
  {
317
298
  title: 'Global Timeout',
318
- code: `import { createServer, timeout } from 'raffel'
319
-
320
- const server = createServer()
321
- .use(timeout({ ms: 30000 })) // 30 second timeout for all procedures`,
322
- },
323
- {
324
- title: 'Per-Procedure Timeout',
325
- code: `import { createServer, forPattern, timeout } from 'raffel'
299
+ code: `import { createServer, createTimeoutInterceptor } from 'raffel'
326
300
 
327
301
  const server = createServer()
328
- .use(forPattern('reports.*', timeout({ ms: 120000 }))) // 2 min for reports
329
- .use(timeout({ ms: 10000 })) // 10s default`,
302
+ .use(createTimeoutInterceptor({ defaultMs: 30000 }))`,
330
303
  },
331
304
  ],
332
305
  },
333
306
  {
334
- name: 'bulkhead',
307
+ name: 'createBulkheadInterceptor',
335
308
  description: 'Limits concurrent executions to isolate failures. Prevents one slow procedure from consuming all resources.',
336
309
  category: 'resilience',
337
310
  options: [
338
311
  {
339
- name: 'maxConcurrent',
312
+ name: 'concurrency',
340
313
  type: 'number',
341
314
  required: true,
342
315
  description: 'Maximum concurrent executions',
343
316
  },
344
317
  {
345
- name: 'maxQueue',
318
+ name: 'maxQueueSize',
346
319
  type: 'number',
347
320
  required: false,
348
321
  default: '0',
@@ -352,36 +325,49 @@ const server = createServer()
352
325
  name: 'queueTimeout',
353
326
  type: 'number',
354
327
  required: false,
328
+ default: '0',
355
329
  description: 'Max time to wait in queue (ms)',
356
330
  },
331
+ {
332
+ name: 'onReject',
333
+ type: '(procedure) => void',
334
+ required: false,
335
+ description: 'Callback when a request is rejected',
336
+ },
357
337
  ],
358
338
  examples: [
359
339
  {
360
340
  title: 'Limit Concurrent Database Queries',
361
- code: `import { createServer, forPattern, bulkhead } from 'raffel'
341
+ code: `import { createServer, forPattern, createBulkheadInterceptor } from 'raffel'
362
342
 
363
343
  const server = createServer()
364
- .use(forPattern('db.*', bulkhead({
365
- maxConcurrent: 10, // Max 10 concurrent DB queries
366
- maxQueue: 50, // Queue up to 50 more
367
- queueTimeout: 5000 // Wait max 5s in queue
344
+ .use(forPattern('db.*', createBulkheadInterceptor({
345
+ concurrency: 10,
346
+ maxQueueSize: 50,
347
+ queueTimeout: 5000,
368
348
  })))`,
369
349
  },
370
350
  ],
371
351
  },
372
352
  {
373
- name: 'fallback',
353
+ name: 'createFallbackInterceptor',
374
354
  description: 'Provides fallback response when handler fails. Useful for graceful degradation.',
375
355
  category: 'resilience',
376
356
  options: [
377
357
  {
378
- name: 'fallback',
379
- type: '(error, ctx) => unknown',
380
- required: true,
381
- description: 'Function returning fallback value',
358
+ name: 'response',
359
+ type: 'unknown',
360
+ required: false,
361
+ description: 'Static fallback response',
362
+ },
363
+ {
364
+ name: 'handler',
365
+ type: '(ctx, error) => unknown',
366
+ required: false,
367
+ description: 'Dynamic fallback handler',
382
368
  },
383
369
  {
384
- name: 'shouldFallback',
370
+ name: 'when',
385
371
  type: '(error) => boolean',
386
372
  required: false,
387
373
  description: 'Predicate to decide if fallback should be used',
@@ -390,15 +376,14 @@ const server = createServer()
390
376
  examples: [
391
377
  {
392
378
  title: 'Fallback to Cached Data',
393
- code: `import { createServer, forPattern, fallback } from 'raffel'
379
+ code: `import { createServer, forPattern, createFallbackInterceptor } from 'raffel'
394
380
 
395
381
  const server = createServer()
396
- .use(forPattern('prices.*', fallback({
397
- fallback: async (error, ctx) => {
398
- // Return cached data on failure
399
- return await cache.get(\`prices:\${ctx.procedure}\`) || { prices: [], stale: true }
382
+ .use(forPattern('prices.*', createFallbackInterceptor({
383
+ handler: async (_ctx, error) => {
384
+ return await cache.get('prices') || { prices: [], stale: true, reason: error.message }
400
385
  },
401
- shouldFallback: (err) => err.code === 'SERVICE_UNAVAILABLE'
386
+ when: (err) => (err as any).code === 'UNAVAILABLE',
402
387
  })))`,
403
388
  },
404
389
  ],
@@ -406,7 +391,7 @@ const server = createServer()
406
391
  // === Observability ===
407
392
  {
408
393
  name: 'createMetricsInterceptor',
409
- description: 'Auto-instruments all procedures with Prometheus-compatible metrics (latency, count, errors).',
394
+ description: 'Auto-instruments procedures with metrics (latency, count, errors).',
410
395
  category: 'observability',
411
396
  options: [
412
397
  {
@@ -415,18 +400,6 @@ const server = createServer()
415
400
  required: true,
416
401
  description: 'Metric registry for storing metrics',
417
402
  },
418
- {
419
- name: 'buckets',
420
- type: 'number[]',
421
- required: false,
422
- description: 'Histogram buckets for latency',
423
- },
424
- {
425
- name: 'labels',
426
- type: '(ctx) => Record<string, string>',
427
- required: false,
428
- description: 'Additional labels to add to metrics',
429
- },
430
403
  ],
431
404
  examples: [
432
405
  {
@@ -435,15 +408,7 @@ const server = createServer()
435
408
 
436
409
  const metrics = createMetricRegistry()
437
410
  const server = createServer()
438
- .use(createMetricsInterceptor({ registry: metrics }))
439
-
440
- // Metrics automatically collected:
441
- // - raffel_procedure_duration_seconds (histogram)
442
- // - raffel_procedure_total (counter)
443
- // - raffel_procedure_errors_total (counter)
444
-
445
- server.procedure('metrics.export')
446
- .handler(async () => exportPrometheus(metrics))`,
411
+ .use(createMetricsInterceptor(metrics))`,
447
412
  },
448
413
  ],
449
414
  },
@@ -458,18 +423,6 @@ server.procedure('metrics.export')
458
423
  required: true,
459
424
  description: 'Tracer instance for creating spans',
460
425
  },
461
- {
462
- name: 'spanName',
463
- type: '(ctx) => string',
464
- required: false,
465
- description: 'Custom span name generator',
466
- },
467
- {
468
- name: 'attributes',
469
- type: '(ctx) => SpanAttributes',
470
- required: false,
471
- description: 'Additional span attributes',
472
- },
473
426
  ],
474
427
  examples: [
475
428
  {
@@ -483,22 +436,22 @@ server.procedure('metrics.export')
483
436
 
484
437
  const tracer = createTracer({
485
438
  serviceName: 'my-api',
486
- exporter: createJaegerExporter({ endpoint: 'http://localhost:14268/api/traces' })
439
+ exporters: [createJaegerExporter({ serviceName: 'my-api' })],
487
440
  })
488
441
 
489
442
  const server = createServer()
490
- .use(createTracingInterceptor({ tracer }))`,
443
+ .use(createTracingInterceptor(tracer))`,
491
444
  },
492
445
  ],
493
446
  },
494
447
  {
495
- name: 'logging',
448
+ name: 'createLoggingInterceptor',
496
449
  description: 'Structured logging for request/response with configurable levels and formats.',
497
450
  category: 'observability',
498
451
  options: [
499
452
  {
500
453
  name: 'level',
501
- type: "'debug' | 'info' | 'warn' | 'error'",
454
+ type: "'trace' | 'debug' | 'info' | 'warn' | 'error'",
502
455
  required: false,
503
456
  default: "'info'",
504
457
  description: 'Log level',
@@ -507,35 +460,47 @@ const server = createServer()
507
460
  name: 'format',
508
461
  type: "'json' | 'pretty'",
509
462
  required: false,
510
- default: "'json'",
463
+ default: "'pretty'",
511
464
  description: 'Log output format',
512
465
  },
513
466
  {
514
- name: 'includeInput',
467
+ name: 'includePayload',
468
+ type: 'boolean',
469
+ required: false,
470
+ default: 'false',
471
+ description: 'Include request payload in logs',
472
+ },
473
+ {
474
+ name: 'includeResponse',
515
475
  type: 'boolean',
516
476
  required: false,
517
477
  default: 'false',
518
- description: 'Include request input in logs (careful with PII)',
478
+ description: 'Include response payload in logs',
519
479
  },
520
480
  {
521
- name: 'includeOutput',
481
+ name: 'includeMetadata',
522
482
  type: 'boolean',
523
483
  required: false,
524
484
  default: 'false',
525
- description: 'Include response output in logs',
485
+ description: 'Include metadata (headers) in logs',
486
+ },
487
+ {
488
+ name: 'excludeProcedures',
489
+ type: 'string[]',
490
+ required: false,
491
+ description: 'Procedure patterns to exclude',
526
492
  },
527
493
  ],
528
494
  examples: [
529
495
  {
530
496
  title: 'Production Logging',
531
- code: `import { createServer, logging, forPattern, except } from 'raffel'
497
+ code: `import { createServer, createLoggingInterceptor, except } from 'raffel'
532
498
 
533
499
  const server = createServer()
534
- .use(except('health.*', logging({
500
+ .use(except(['health.*'], createLoggingInterceptor({
535
501
  level: 'info',
536
502
  format: 'json',
537
- includeInput: false, // Don't log PII
538
- includeOutput: false
503
+ includeMetadata: false,
539
504
  })))`,
540
505
  },
541
506
  ],
@@ -543,155 +508,118 @@ const server = createServer()
543
508
  // === Validation ===
544
509
  {
545
510
  name: 'createValidationInterceptor',
546
- description: 'Validates input/output against registered schemas. Supports Zod, Yup, Joi, Ajv, fastest-validator.',
511
+ description: 'Validates input/output against a schema for a specific handler.',
547
512
  category: 'validation',
548
513
  options: [
549
514
  {
550
- name: 'validateInput',
551
- type: 'boolean',
552
- required: false,
553
- default: 'true',
554
- description: 'Validate request input',
555
- },
556
- {
557
- name: 'validateOutput',
558
- type: 'boolean',
559
- required: false,
560
- default: 'false',
561
- description: 'Validate response output',
562
- },
563
- {
564
- name: 'onError',
565
- type: '(errors) => void',
566
- required: false,
567
- description: 'Callback on validation error',
515
+ name: 'schema',
516
+ type: 'HandlerSchema',
517
+ required: true,
518
+ description: 'Schema with input/output validators',
568
519
  },
569
520
  ],
570
521
  examples: [
571
522
  {
572
523
  title: 'Zod Validation',
573
- code: `import { createServer, createValidationInterceptor, registerValidator, createZodAdapter } from 'raffel'
524
+ code: `import { createServer, createValidationInterceptor } from 'raffel'
574
525
  import { z } from 'zod'
575
526
 
576
- registerValidator(createZodAdapter(z))
527
+ const schema = {
528
+ input: z.object({ email: z.string().email() }),
529
+ output: z.object({ id: z.string(), email: z.string() }),
530
+ }
577
531
 
578
532
  const server = createServer()
579
- .use(createValidationInterceptor({ validateInput: true, validateOutput: true }))
580
533
  .procedure('users.create')
581
- .input(z.object({
582
- email: z.string().email(),
583
- name: z.string().min(2).max(100),
584
- age: z.number().min(18).optional()
585
- }))
586
- .output(z.object({
587
- id: z.string(),
588
- email: z.string(),
589
- name: z.string()
590
- }))
591
- .handler(async (input, ctx) => {
592
- // Input is already validated and typed!
593
- return await db.users.create(input)
594
- })`,
534
+ .use(createValidationInterceptor(schema))
535
+ .handler(async (input) => createUser(input))`,
595
536
  },
596
537
  ],
597
538
  },
598
539
  // === Caching ===
599
540
  {
600
- name: 'cache',
601
- description: 'Response caching with pluggable drivers (memory, file, Redis, S3DB). Supports TTL and invalidation.',
541
+ name: 'createCacheInterceptor',
542
+ description: 'Response caching with pluggable drivers. Supports TTL, stale-while-revalidate, and invalidation.',
602
543
  category: 'caching',
603
544
  options: [
545
+ {
546
+ name: 'ttlMs',
547
+ type: 'number',
548
+ required: false,
549
+ default: '60000',
550
+ description: 'Time-to-live in milliseconds',
551
+ },
604
552
  {
605
553
  name: 'driver',
606
554
  type: 'CacheDriver',
607
- required: true,
608
- description: 'Cache driver instance',
555
+ required: false,
556
+ description: 'Cache driver instance (memory, redis, file, s3db)',
609
557
  },
610
558
  {
611
- name: 'ttl',
612
- type: 'number',
559
+ name: 'procedures',
560
+ type: 'string[]',
613
561
  required: false,
614
- default: '60000',
615
- description: 'Time-to-live in milliseconds',
562
+ description: 'Procedures to include (glob patterns supported)',
616
563
  },
617
564
  {
618
- name: 'keyGenerator',
619
- type: '(ctx, input) => string',
565
+ name: 'excludeProcedures',
566
+ type: 'string[]',
620
567
  required: false,
621
- description: 'Custom cache key generator',
568
+ description: 'Procedures to exclude',
622
569
  },
623
570
  {
624
- name: 'shouldCache',
625
- type: '(ctx, result) => boolean',
571
+ name: 'keyGenerator',
572
+ type: '(envelope) => string',
626
573
  required: false,
627
- description: 'Predicate to decide if response should be cached',
574
+ description: 'Custom cache key generator',
628
575
  },
629
576
  ],
630
577
  examples: [
631
578
  {
632
- title: 'In-Memory Caching',
633
- code: `import { createServer, forPattern, cache, createCacheMemoryDriver } from 'raffel'
579
+ title: 'Redis Cache',
580
+ code: `import { createServer } from 'raffel'
581
+ import { createCacheInterceptor } from 'raffel/middleware'
582
+ import { createDriver } from 'raffel/cache'
634
583
 
635
- const memoryCache = createCacheMemoryDriver({
636
- maxSize: 1000,
637
- evictionPolicy: 'lru'
638
- })
584
+ const redisDriver = await createDriver('redis', { client: redis })
585
+ const cache = createCacheInterceptor({ ttlMs: 60000, driver: redisDriver })
639
586
 
640
- const server = createServer()
641
- .use(forPattern('products.list', cache({
642
- driver: memoryCache,
643
- ttl: 5 * 60 * 1000, // 5 minutes
644
- keyGenerator: (ctx, input) => \`products:\${JSON.stringify(input)}\`
645
- })))`,
646
- },
647
- {
648
- title: 'Redis Distributed Cache',
649
- code: `import { createServer, forPattern, cache, createCacheRedisDriver } from 'raffel'
650
- import Redis from 'ioredis'
651
-
652
- const redisCache = createCacheRedisDriver({
653
- client: new Redis(process.env.REDIS_URL),
654
- prefix: 'cache:'
655
- })
656
-
657
- const server = createServer()
658
- .use(forPattern('*', cache({
659
- driver: redisCache,
660
- ttl: 60000,
661
- shouldCache: (ctx, result) => !ctx.auth // Don't cache authenticated responses
662
- })))`,
587
+ const server = createServer().use(cache)`,
663
588
  },
664
589
  ],
665
590
  },
666
591
  {
667
- name: 'dedup',
592
+ name: 'createDedupInterceptor',
668
593
  description: 'Request deduplication to prevent duplicate processing of identical concurrent requests.',
669
594
  category: 'caching',
670
595
  options: [
671
596
  {
672
- name: 'windowMs',
597
+ name: 'ttlMs',
673
598
  type: 'number',
674
599
  required: false,
675
- default: '1000',
676
- description: 'Deduplication window in milliseconds',
600
+ default: '30000',
601
+ description: 'TTL for pending requests',
677
602
  },
678
603
  {
679
604
  name: 'keyGenerator',
680
- type: '(ctx, input) => string',
605
+ type: '(envelope, ctx) => string',
681
606
  required: false,
682
607
  description: 'Custom dedup key generator',
683
608
  },
609
+ {
610
+ name: 'procedures',
611
+ type: 'string[]',
612
+ required: false,
613
+ description: 'Procedures to deduplicate (glob patterns)',
614
+ },
684
615
  ],
685
616
  examples: [
686
617
  {
687
618
  title: 'Prevent Double Submit',
688
- code: `import { createServer, forPattern, dedup } from 'raffel'
619
+ code: `import { createServer, forPattern, createDedupInterceptor } from 'raffel'
689
620
 
690
621
  const server = createServer()
691
- .use(forPattern('orders.create', dedup({
692
- windowMs: 5000, // 5 second window
693
- keyGenerator: (ctx, input) => \`order:\${ctx.auth.principal.id}:\${input.idempotencyKey}\`
694
- })))`,
622
+ .use(forPattern('orders.create', createDedupInterceptor()))`,
695
623
  },
696
624
  ],
697
625
  },
@@ -711,16 +639,14 @@ const server = createServer()
711
639
  examples: [
712
640
  {
713
641
  title: 'Compose Production Stack',
714
- code: `import { createServer, compose, timeout, logging, cache } from 'raffel'
642
+ code: `import { createServer, compose, createTimeoutInterceptor, createLoggingInterceptor } from 'raffel'
715
643
 
716
644
  const productionStack = compose(
717
- timeout({ ms: 30000 }),
718
- logging({ level: 'info', format: 'json' }),
719
- cache({ driver: memoryCache, ttl: 60000 })
645
+ createTimeoutInterceptor({ defaultMs: 30000 }),
646
+ createLoggingInterceptor({ level: 'info', format: 'json' })
720
647
  )
721
648
 
722
- const server = createServer()
723
- .use(productionStack)`,
649
+ const server = createServer().use(productionStack)`,
724
650
  },
725
651
  ],
726
652
  },
@@ -731,7 +657,7 @@ const server = createServer()
731
657
  options: [
732
658
  {
733
659
  name: 'predicate',
734
- type: '(ctx) => boolean',
660
+ type: '(envelope, ctx) => boolean',
735
661
  required: true,
736
662
  description: 'Condition to evaluate',
737
663
  },
@@ -744,13 +670,13 @@ const server = createServer()
744
670
  ],
745
671
  examples: [
746
672
  {
747
- title: 'Environment-Based Middleware',
748
- code: `import { createServer, when, logging } from 'raffel'
673
+ title: 'Environment-Based Logging',
674
+ code: `import { createServer, when, createLoggingInterceptor } from 'raffel'
749
675
 
750
676
  const server = createServer()
751
677
  .use(when(
752
678
  () => process.env.NODE_ENV === 'development',
753
- logging({ level: 'debug', format: 'pretty', includeInput: true })
679
+ createLoggingInterceptor({ level: 'debug', format: 'pretty' })
754
680
  ))`,
755
681
  },
756
682
  ],
@@ -762,9 +688,9 @@ const server = createServer()
762
688
  options: [
763
689
  {
764
690
  name: 'pattern',
765
- type: 'string | string[]',
691
+ type: 'string',
766
692
  required: true,
767
- description: 'Glob pattern(s) to match (e.g., "users.*", "admin.**")',
693
+ description: 'Glob pattern to match (e.g., "users.*", "admin.**")',
768
694
  },
769
695
  {
770
696
  name: 'interceptor',
@@ -787,14 +713,14 @@ const server = createServer()
787
713
  },
788
714
  {
789
715
  name: 'except',
790
- description: 'Applies interceptor to all procedures except those matching patterns.',
716
+ description: 'Applies interceptor to all procedures except those matching names.',
791
717
  category: 'composition',
792
718
  options: [
793
719
  {
794
- name: 'pattern',
795
- type: 'string | string[]',
720
+ name: 'procedures',
721
+ type: 'string[]',
796
722
  required: true,
797
- description: 'Pattern(s) to exclude',
723
+ description: 'Procedures to exclude',
798
724
  },
799
725
  {
800
726
  name: 'interceptor',
@@ -806,10 +732,10 @@ const server = createServer()
806
732
  examples: [
807
733
  {
808
734
  title: 'Exclude Health Checks from Logging',
809
- code: `import { createServer, except, logging } from 'raffel'
735
+ code: `import { createServer, except, createLoggingInterceptor } from 'raffel'
810
736
 
811
737
  const server = createServer()
812
- .use(except('health.*', logging({ level: 'info' })))`,
738
+ .use(except(['health.check'], createLoggingInterceptor({ level: 'info' })))`,
813
739
  },
814
740
  ],
815
741
  },
@@ -820,7 +746,7 @@ const server = createServer()
820
746
  options: [
821
747
  {
822
748
  name: 'predicate',
823
- type: '(ctx) => boolean',
749
+ type: '(envelope, ctx) => boolean',
824
750
  required: true,
825
751
  description: 'Condition to branch on',
826
752
  },
@@ -840,13 +766,13 @@ const server = createServer()
840
766
  examples: [
841
767
  {
842
768
  title: 'Different Caching by Auth Status',
843
- code: `import { createServer, branch, cache } from 'raffel'
769
+ code: `import { createServer, branch, createCacheInterceptor } from 'raffel'
844
770
 
845
771
  const server = createServer()
846
772
  .use(branch(
847
- (ctx) => !ctx.auth?.authenticated,
848
- cache({ driver: publicCache, ttl: 300000 }), // 5 min for public
849
- cache({ driver: privateCache, ttl: 60000 }) // 1 min for authenticated
773
+ (_env, ctx) => !ctx.auth?.authenticated,
774
+ createCacheInterceptor({ ttlMs: 300000 }), // 5 min for public
775
+ createCacheInterceptor({ ttlMs: 60000 }) // 1 min for authenticated
850
776
  ))`,
851
777
  },
852
778
  ],