alepha 0.20.2 → 0.20.4

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 (304) hide show
  1. package/README.md +0 -1
  2. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  3. package/assets/swagger-ui/swagger-ui.css +1 -1
  4. package/dist/api/audits/index.browser.js +49 -0
  5. package/dist/api/audits/index.browser.js.map +1 -1
  6. package/dist/api/audits/index.js +49 -0
  7. package/dist/api/audits/index.js.map +1 -1
  8. package/dist/api/files/index.js.map +1 -1
  9. package/dist/api/jobs/index.d.ts +2 -61
  10. package/dist/api/jobs/index.d.ts.map +1 -1
  11. package/dist/api/jobs/index.js.map +1 -1
  12. package/dist/api/keys/index.d.ts +4 -4
  13. package/dist/api/keys/index.js.map +1 -1
  14. package/dist/api/notifications/index.d.ts +1 -10
  15. package/dist/api/notifications/index.d.ts.map +1 -1
  16. package/dist/api/parameters/index.browser.js +37 -0
  17. package/dist/api/parameters/index.browser.js.map +1 -1
  18. package/dist/api/parameters/index.d.ts +12 -68
  19. package/dist/api/parameters/index.d.ts.map +1 -1
  20. package/dist/api/parameters/index.js +57 -4
  21. package/dist/api/parameters/index.js.map +1 -1
  22. package/dist/api/payments/index.js.map +1 -1
  23. package/dist/api/users/index.browser.js +6 -0
  24. package/dist/api/users/index.browser.js.map +1 -1
  25. package/dist/api/users/index.d.ts +148 -227
  26. package/dist/api/users/index.d.ts.map +1 -1
  27. package/dist/api/users/index.js +60 -14
  28. package/dist/api/users/index.js.map +1 -1
  29. package/dist/api/verifications/index.d.ts.map +1 -1
  30. package/dist/api/verifications/index.js +2 -1
  31. package/dist/api/verifications/index.js.map +1 -1
  32. package/dist/bucket/index.d.ts +77 -107
  33. package/dist/bucket/index.d.ts.map +1 -1
  34. package/dist/bucket/index.js +153 -5
  35. package/dist/bucket/index.js.map +1 -1
  36. package/dist/bucket/index.workerd.js +12 -2
  37. package/dist/bucket/index.workerd.js.map +1 -1
  38. package/dist/cache/core/index.d.ts +26 -0
  39. package/dist/cache/core/index.d.ts.map +1 -1
  40. package/dist/cache/core/index.js +11 -1
  41. package/dist/cache/core/index.js.map +1 -1
  42. package/dist/cache/core/index.workerd.js +11 -1
  43. package/dist/cache/core/index.workerd.js.map +1 -1
  44. package/dist/captcha/index.js.map +1 -1
  45. package/dist/cli/config/index.d.ts +7 -5
  46. package/dist/cli/config/index.d.ts.map +1 -1
  47. package/dist/cli/config/index.js +2 -3
  48. package/dist/cli/config/index.js.map +1 -1
  49. package/dist/cli/core/index.d.ts +637 -11660
  50. package/dist/cli/core/index.d.ts.map +1 -1
  51. package/dist/cli/core/index.js +707 -532
  52. package/dist/cli/core/index.js.map +1 -1
  53. package/dist/cli/devtools/index.d.ts +4 -8
  54. package/dist/cli/devtools/index.d.ts.map +1 -1
  55. package/dist/cli/devtools/index.js +20 -16
  56. package/dist/cli/devtools/index.js.map +1 -1
  57. package/dist/cli/platform/index.d.ts +51 -77
  58. package/dist/cli/platform/index.d.ts.map +1 -1
  59. package/dist/cli/platform/index.js +65 -15
  60. package/dist/cli/platform/index.js.map +1 -1
  61. package/dist/cli/vendor/index.d.ts +10 -13
  62. package/dist/cli/vendor/index.d.ts.map +1 -1
  63. package/dist/cli/vendor/index.js +30 -12
  64. package/dist/cli/vendor/index.js.map +1 -1
  65. package/dist/command/index.js +1 -1
  66. package/dist/command/index.js.map +1 -1
  67. package/dist/core/index.browser.js +27 -3
  68. package/dist/core/index.browser.js.map +1 -1
  69. package/dist/core/index.d.ts +8 -11
  70. package/dist/core/index.d.ts.map +1 -1
  71. package/dist/core/index.js +27 -3
  72. package/dist/core/index.js.map +1 -1
  73. package/dist/core/index.native.js +27 -3
  74. package/dist/core/index.native.js.map +1 -1
  75. package/dist/core/index.workerd.js +27 -3
  76. package/dist/core/index.workerd.js.map +1 -1
  77. package/dist/crypto/index.js.map +1 -1
  78. package/dist/datetime/index.d.ts +69 -10
  79. package/dist/datetime/index.d.ts.map +1 -1
  80. package/dist/datetime/index.js +135 -13
  81. package/dist/datetime/index.js.map +1 -1
  82. package/dist/email/core/index.js.map +1 -1
  83. package/dist/email/smtp/index.js +130 -16
  84. package/dist/email/smtp/index.js.map +1 -1
  85. package/dist/fake/index.js.map +1 -1
  86. package/dist/lock/core/index.d.ts +30 -2
  87. package/dist/lock/core/index.d.ts.map +1 -1
  88. package/dist/lock/core/index.js +35 -12
  89. package/dist/lock/core/index.js.map +1 -1
  90. package/dist/lock/redis/index.js.map +1 -1
  91. package/dist/logger/index.js +32 -1
  92. package/dist/logger/index.js.map +1 -1
  93. package/dist/mcp/index.d.ts +238 -31
  94. package/dist/mcp/index.d.ts.map +1 -1
  95. package/dist/mcp/index.js +198 -67
  96. package/dist/mcp/index.js.map +1 -1
  97. package/dist/orm/core/index.browser.js +2 -362
  98. package/dist/orm/core/index.browser.js.map +1 -1
  99. package/dist/orm/core/index.bun.js +18 -409
  100. package/dist/orm/core/index.bun.js.map +1 -1
  101. package/dist/orm/core/index.d.ts +41 -194
  102. package/dist/orm/core/index.d.ts.map +1 -1
  103. package/dist/orm/core/index.js +27 -422
  104. package/dist/orm/core/index.js.map +1 -1
  105. package/dist/orm/postgres/index.bun.js +17 -20
  106. package/dist/orm/postgres/index.bun.js.map +1 -1
  107. package/dist/orm/postgres/index.d.ts +1 -5
  108. package/dist/orm/postgres/index.d.ts.map +1 -1
  109. package/dist/orm/postgres/index.js +17 -20
  110. package/dist/orm/postgres/index.js.map +1 -1
  111. package/dist/react/core/index.d.ts +102 -1
  112. package/dist/react/core/index.d.ts.map +1 -1
  113. package/dist/react/core/index.js +65 -1
  114. package/dist/react/core/index.js.map +1 -1
  115. package/dist/react/form/index.d.ts +6 -0
  116. package/dist/react/form/index.d.ts.map +1 -1
  117. package/dist/react/form/index.js +7 -7
  118. package/dist/react/form/index.js.map +1 -1
  119. package/dist/react/i18n/index.d.ts +7 -1
  120. package/dist/react/i18n/index.d.ts.map +1 -1
  121. package/dist/react/i18n/index.js +6 -0
  122. package/dist/react/i18n/index.js.map +1 -1
  123. package/dist/react/intro/index.js +22 -17
  124. package/dist/react/intro/index.js.map +1 -1
  125. package/dist/react/router/index.browser.js +98 -4
  126. package/dist/react/router/index.browser.js.map +1 -1
  127. package/dist/react/router/index.d.ts +58 -5
  128. package/dist/react/router/index.d.ts.map +1 -1
  129. package/dist/react/router/index.js +122 -6
  130. package/dist/react/router/index.js.map +1 -1
  131. package/dist/react/testing/{chunk-DBEY4PJZ.js → chunk-6Ep1yQYe.js} +1 -1
  132. package/dist/react/testing/index.js +1 -1
  133. package/dist/react/testing/index.js.map +1 -1
  134. package/dist/react/ui/index.d.ts +195 -1
  135. package/dist/react/ui/index.d.ts.map +1 -1
  136. package/dist/react/ui/index.js +64 -1
  137. package/dist/react/ui/index.js.map +1 -1
  138. package/dist/react/websocket/index.js.map +1 -1
  139. package/dist/redis/index.js.map +1 -1
  140. package/dist/scheduler/index.d.ts +1 -2
  141. package/dist/scheduler/index.d.ts.map +1 -1
  142. package/dist/scheduler/index.js +1 -1
  143. package/dist/scheduler/index.js.map +1 -1
  144. package/dist/scheduler/index.workerd.js +1 -1
  145. package/dist/scheduler/index.workerd.js.map +1 -1
  146. package/dist/security/index.browser.js.map +1 -1
  147. package/dist/security/index.d.ts.map +1 -1
  148. package/dist/security/index.js +2 -2
  149. package/dist/security/index.js.map +1 -1
  150. package/dist/server/auth/index.d.ts.map +1 -1
  151. package/dist/server/auth/index.js +24 -10
  152. package/dist/server/auth/index.js.map +1 -1
  153. package/dist/server/cookies/index.js.map +1 -1
  154. package/dist/server/core/index.browser.js +10 -3
  155. package/dist/server/core/index.browser.js.map +1 -1
  156. package/dist/server/core/index.d.ts +1 -4
  157. package/dist/server/core/index.d.ts.map +1 -1
  158. package/dist/server/core/index.js +47 -9
  159. package/dist/server/core/index.js.map +1 -1
  160. package/dist/server/links/index.browser.js.map +1 -1
  161. package/dist/server/links/index.js.map +1 -1
  162. package/dist/server/metrics/index.js +19 -1
  163. package/dist/server/metrics/index.js.map +1 -1
  164. package/dist/server/rate-limit/index.js.map +1 -1
  165. package/dist/server/static/index.js.map +1 -1
  166. package/dist/server/swagger/index.d.ts.map +1 -1
  167. package/dist/server/swagger/index.js +4 -5
  168. package/dist/server/swagger/index.js.map +1 -1
  169. package/dist/sms/index.js.map +1 -1
  170. package/dist/system/index.browser.js.map +1 -1
  171. package/dist/system/index.js.map +1 -1
  172. package/dist/system/index.workerd.js.map +1 -1
  173. package/dist/topic/core/index.js.map +1 -1
  174. package/dist/websocket/index.browser.js +32 -5
  175. package/dist/websocket/index.browser.js.map +1 -1
  176. package/dist/websocket/index.d.ts +3 -1
  177. package/dist/websocket/index.d.ts.map +1 -1
  178. package/dist/websocket/index.js +42 -6
  179. package/dist/websocket/index.js.map +1 -1
  180. package/package.json +685 -274
  181. package/src/api/files/__tests__/FileController.spec.ts +1 -1
  182. package/src/api/jobs/__tests__/$job.spec.ts +5 -1
  183. package/src/api/parameters/services/ParameterProvider.ts +21 -4
  184. package/src/api/users/__tests__/SessionService.spec.ts +99 -0
  185. package/src/api/users/__tests__/UserJobs.spec.ts +67 -0
  186. package/src/api/users/atoms/realmAuthSettingsAtom.ts +15 -0
  187. package/src/api/users/entities/sessions.ts +6 -0
  188. package/src/api/users/jobs/UserJobs.ts +44 -17
  189. package/src/api/users/providers/RealmProvider.ts +4 -0
  190. package/src/api/users/schemas/userQuerySchema.ts +0 -1
  191. package/src/api/users/services/SessionService.ts +27 -0
  192. package/src/api/users/services/UserService.ts +1 -5
  193. package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
  194. package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
  195. package/src/api/verifications/services/VerificationService.ts +1 -0
  196. package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +74 -0
  197. package/src/bucket/index.ts +19 -2
  198. package/src/bucket/primitives/$bucket.ts +9 -1
  199. package/src/bucket/providers/CloudflareR2Provider.ts +2 -137
  200. package/src/bucket/providers/NodeS3BucketProvider.ts +218 -0
  201. package/src/cache/core/index.ts +29 -0
  202. package/src/cache/core/primitives/$cache.ts +14 -1
  203. package/src/cli/config/defineConfig.ts +13 -15
  204. package/src/cli/core/__tests__/init.spec.ts +214 -7
  205. package/src/cli/core/commands/init.ts +12 -0
  206. package/src/cli/core/services/PackageManagerUtils.ts +23 -6
  207. package/src/cli/core/services/ProjectScaffolder.ts +315 -33
  208. package/src/cli/core/tasks/BuildCloudflareTask.ts +5 -0
  209. package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
  210. package/src/cli/core/tasks/BuildServerTask.ts +8 -0
  211. package/src/cli/core/templates/agentMd.ts +2 -10
  212. package/src/cli/core/templates/apiIndexTs.ts +23 -1
  213. package/src/cli/core/templates/componentsJsonTs.ts +39 -0
  214. package/src/cli/core/templates/mainCss.ts +1 -0
  215. package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
  216. package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
  217. package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
  218. package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
  219. package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
  220. package/src/cli/core/templates/webAppRouterTs.ts +104 -1
  221. package/src/cli/core/templates/webIndexTs.ts +23 -1
  222. package/src/cli/devtools/index.ts +12 -26
  223. package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
  224. package/src/cli/platform/index.ts +15 -24
  225. package/src/cli/vendor/atoms/vendorOptions.ts +1 -1
  226. package/src/cli/vendor/index.ts +14 -23
  227. package/src/command/providers/CliProvider.ts +1 -1
  228. package/src/core/Alepha.ts +11 -1
  229. package/src/core/helpers/ref.ts +18 -0
  230. package/src/core/index.shared.ts +1 -0
  231. package/src/core/interfaces/Service.ts +3 -1
  232. package/src/core/providers/SchemaValidator.ts +9 -1
  233. package/src/core/providers/TypeProvider.ts +2 -3
  234. package/src/datetime/REFACTORING.md +118 -0
  235. package/src/datetime/providers/DateTimeProvider.ts +203 -24
  236. package/src/lock/core/index.ts +31 -0
  237. package/src/lock/core/primitives/$lock.ts +14 -1
  238. package/src/logger/services/Logger.ts +1 -1
  239. package/src/mcp/__tests__/$resource.spec.ts +1 -1
  240. package/src/mcp/__tests__/$tool.spec.ts +1 -1
  241. package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
  242. package/src/mcp/__tests__/jsonrpc.spec.ts +1 -1
  243. package/src/mcp/helpers/jsonrpc.ts +26 -1
  244. package/src/mcp/index.ts +10 -5
  245. package/src/mcp/interfaces/McpTypes.ts +83 -6
  246. package/src/mcp/primitives/$prompt.ts +18 -1
  247. package/src/mcp/primitives/$resource.ts +18 -1
  248. package/src/mcp/primitives/$tool.ts +83 -7
  249. package/src/mcp/providers/McpServerProvider.ts +74 -16
  250. package/src/mcp/transports/StreamableHttpMcpTransport.ts +226 -0
  251. package/src/orm/REFACTORING.md +330 -0
  252. package/src/orm/__tests__/$repository-tests.ts +1 -0
  253. package/src/orm/__tests__/orm-next-tests.ts +2 -67
  254. package/src/orm/__tests__/orm-next.spec.ts +0 -21
  255. package/src/orm/core/index.shared.ts +0 -2
  256. package/src/orm/core/index.ts +1 -2
  257. package/src/orm/core/primitives/$repository.ts +3 -6
  258. package/src/orm/core/primitives/$transactional.ts +11 -0
  259. package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
  260. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
  261. package/src/orm/core/schemas/updateSchema.ts +1 -1
  262. package/src/orm/core/services/ModelBuilder.ts +1 -13
  263. package/src/orm/core/services/PgRelationManager.ts +4 -2
  264. package/src/orm/core/services/Repository.ts +1 -42
  265. package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
  266. package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
  267. package/src/react/core/__tests__/useQuery.browser.spec.tsx +86 -0
  268. package/src/react/core/hooks/useQuery.ts +153 -0
  269. package/src/react/core/index.ts +1 -0
  270. package/src/react/form/services/FormModel.ts +15 -6
  271. package/src/react/form/services/parseField.ts +8 -0
  272. package/src/react/i18n/providers/I18nProvider.ts +8 -2
  273. package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
  274. package/src/react/router/__tests__/$page.spec.tsx +0 -16
  275. package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
  276. package/src/react/router/__tests__/ssr.spec.tsx +339 -0
  277. package/src/react/router/primitives/$page.ts +28 -4
  278. package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
  279. package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
  280. package/src/react/router/providers/ReactPageProvider.ts +27 -9
  281. package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
  282. package/src/react/router/providers/ReactServerProvider.ts +1 -0
  283. package/src/react/ui/atoms/uiThemeListAtom.ts +36 -0
  284. package/src/react/ui/index.ts +6 -0
  285. package/src/react/ui/services/SchemaControl.ts +209 -0
  286. package/src/scheduler/providers/CronProvider.ts +1 -1
  287. package/src/security/primitives/$basicAuth.ts +1 -1
  288. package/src/security/primitives/$issuer.ts +6 -3
  289. package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
  290. package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +75 -0
  291. package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +306 -0
  292. package/src/server/core/errors/ValidationError.ts +13 -1
  293. package/src/server/core/interfaces/ServerRequest.ts +1 -0
  294. package/src/server/core/primitives/$action.ts +16 -5
  295. package/src/server/core/providers/ServerProvider.ts +1 -1
  296. package/src/server/core/providers/ServerRouterProvider.ts +28 -6
  297. package/src/server/core/services/HttpClient.ts +1 -1
  298. package/src/server/swagger/providers/ServerSwaggerProvider.ts +6 -8
  299. package/src/websocket/providers/NodeWebSocketServerProvider.ts +10 -4
  300. package/src/websocket/services/WebSocketClient.ts +11 -5
  301. package/src/mcp/transports/SseMcpTransport.ts +0 -182
  302. package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
  303. package/src/orm/core/helpers/parseQueryString.ts +0 -502
  304. package/src/orm/core/primitives/$view.ts +0 -88
@@ -0,0 +1,226 @@
1
+ import { $atom, $inject, $state, t } from "alepha";
2
+ import { $logger } from "alepha/logger";
3
+ import { $route } from "alepha/server";
4
+ import {
5
+ createErrorResponse,
6
+ createParseError,
7
+ JsonRpcParseError,
8
+ parseMessage,
9
+ } from "../helpers/jsonrpc.ts";
10
+ import type { McpContext } from "../interfaces/McpTypes.ts";
11
+ import { McpServerProvider } from "../providers/McpServerProvider.ts";
12
+
13
+ // ---------------------------------------------------------------------------------------------------------------------
14
+
15
+ export const mcpStreamableHttpOptions = $atom({
16
+ name: "alepha.mcp.streamableHttp.options",
17
+ description: "Configuration options for the MCP Streamable HTTP transport.",
18
+ schema: t.object({
19
+ /**
20
+ * Path for the MCP endpoint. Single endpoint for both requests and
21
+ * (optional) server-streamed responses, per spec 2025-03-26+.
22
+ */
23
+ path: t.text({ default: "/mcp" }),
24
+ /**
25
+ * Allow-list of `Origin` header values accepted on incoming requests.
26
+ * Empty array (default) means "allow any". When set, browser-originated
27
+ * requests with a non-matching `Origin` are rejected with 403 Forbidden,
28
+ * blocking DNS-rebinding attacks against localhost MCP servers.
29
+ *
30
+ * Server-to-server callers (no `Origin` header) are always allowed.
31
+ *
32
+ * Spec 2025-11-25, PR #1439.
33
+ */
34
+ allowedOrigins: t.array(t.text(), { default: [] }),
35
+ }),
36
+ default: {
37
+ path: "/mcp",
38
+ allowedOrigins: [],
39
+ },
40
+ });
41
+
42
+ // Backward-compat alias for the legacy atom name. Prefer
43
+ // `mcpStreamableHttpOptions` going forward; this re-export keeps existing
44
+ // consumer imports compiling and will be removed once they migrate.
45
+ export const mcpSseOptions = mcpStreamableHttpOptions;
46
+
47
+ // ---------------------------------------------------------------------------------------------------------------------
48
+
49
+ /**
50
+ * Streamable HTTP transport for MCP communication.
51
+ *
52
+ * Implements the 2025-03-26+ Streamable HTTP transport: a single `/mcp`
53
+ * endpoint that accepts JSON-RPC over POST and returns either
54
+ * `application/json` (single response, the default) or
55
+ * `text/event-stream` (when the server wants to stream multiple messages).
56
+ *
57
+ * Designed for serverless deployment (Cloudflare Workers, etc.) — there is
58
+ * no long-lived GET stream. GET on the endpoint returns 405 Method Not
59
+ * Allowed; clients that want server-initiated push must rely on the POST
60
+ * response stream when the server upgrades to SSE for that particular call.
61
+ *
62
+ * Spec compliance:
63
+ * - 2025-06-18: validates `MCP-Protocol-Version` header on every request
64
+ * after `initialize` against the version negotiated and stored on
65
+ * `McpServerProvider`.
66
+ * - 2025-11-25: rejects requests with a non-allow-listed `Origin` header
67
+ * (PR #1439). See {@link mcpStreamableHttpOptions.allowedOrigins}.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { Alepha, run } from "alepha";
72
+ * import { AlephaServer } from "alepha/server";
73
+ * import { AlephaMcp, StreamableHttpMcpTransport } from "alepha/mcp";
74
+ *
75
+ * class MyTools {
76
+ * // ... tool definitions
77
+ * }
78
+ *
79
+ * run(
80
+ * Alepha.create()
81
+ * .with(AlephaServer)
82
+ * .with(AlephaMcp)
83
+ * .with(StreamableHttpMcpTransport)
84
+ * .with(MyTools)
85
+ * );
86
+ * ```
87
+ */
88
+ export class StreamableHttpMcpTransport {
89
+ protected readonly log = $logger();
90
+ protected readonly options = $state(mcpStreamableHttpOptions);
91
+ protected readonly mcpServer = $inject(McpServerProvider);
92
+
93
+ /**
94
+ * GET on the MCP endpoint is not supported in this transport. Returning
95
+ * 405 (rather than serving the legacy two-endpoint SSE pattern) is the
96
+ * spec-allowed response for servers that don't offer server-initiated
97
+ * push outside of an active POST.
98
+ */
99
+ notAllowed = $route({
100
+ method: "GET",
101
+ path: this.options.path,
102
+ handler: (request) => {
103
+ request.reply.status = 405;
104
+ request.reply.headers.allow = "POST";
105
+ request.reply.headers["content-type"] = "application/json";
106
+ request.reply.body = JSON.stringify({
107
+ error: "Method Not Allowed. Use POST for MCP messages.",
108
+ });
109
+ },
110
+ });
111
+
112
+ /**
113
+ * POST endpoint for client-to-server JSON-RPC messages.
114
+ * Returns `application/json` for single responses; tools that need to
115
+ * stream progress would upgrade to `text/event-stream` (deferred until a
116
+ * concrete need exists).
117
+ */
118
+ message = $route({
119
+ method: "POST",
120
+ path: this.options.path,
121
+ schema: {
122
+ body: t.json(),
123
+ },
124
+ handler: async (request) => {
125
+ try {
126
+ // Origin allow-list check (spec 2025-11-25 / PR #1439).
127
+ const originRaw = request.headers.origin;
128
+ const origin = Array.isArray(originRaw) ? originRaw[0] : originRaw;
129
+ if (
130
+ origin &&
131
+ this.options.allowedOrigins.length > 0 &&
132
+ !this.options.allowedOrigins.includes(origin)
133
+ ) {
134
+ this.log.warn("Rejected MCP request with non-allowed Origin", {
135
+ origin,
136
+ allowed: this.options.allowedOrigins,
137
+ });
138
+ request.reply.status = 403;
139
+ request.reply.headers["content-type"] = "application/json";
140
+ request.reply.body = JSON.stringify({
141
+ error: "Forbidden: Origin not allowed",
142
+ });
143
+ return;
144
+ }
145
+
146
+ const body =
147
+ typeof request.body === "string"
148
+ ? request.body
149
+ : JSON.stringify(request.body);
150
+
151
+ this.log.debug("MCP request body", {
152
+ body,
153
+ bodyType: typeof request.body,
154
+ });
155
+
156
+ const rpcRequest = parseMessage(body);
157
+
158
+ // Build context from request headers
159
+ const headers = { ...request.headers } as Record<
160
+ string,
161
+ string | string[] | undefined
162
+ >;
163
+
164
+ // Spec 2025-06-18+: every HTTP request after `initialize` MUST carry
165
+ // an `MCP-Protocol-Version` header matching the negotiated version.
166
+ // Reject mismatches with 400 so the client doesn't silently drift.
167
+ if (rpcRequest.method !== "initialize") {
168
+ const headerRaw = headers["mcp-protocol-version"];
169
+ const headerVersion = Array.isArray(headerRaw)
170
+ ? headerRaw[0]
171
+ : headerRaw;
172
+ if (
173
+ headerVersion &&
174
+ headerVersion !== this.mcpServer.negotiatedVersion
175
+ ) {
176
+ this.log.warn("MCP-Protocol-Version header mismatch", {
177
+ header: headerVersion,
178
+ negotiated: this.mcpServer.negotiatedVersion,
179
+ });
180
+ request.reply.status = 400;
181
+ request.reply.headers["content-type"] = "application/json";
182
+ request.reply.body = JSON.stringify({
183
+ error: `MCP-Protocol-Version mismatch: expected ${this.mcpServer.negotiatedVersion}, got ${headerVersion}`,
184
+ });
185
+ return;
186
+ }
187
+ }
188
+
189
+ const context: McpContext = { headers };
190
+
191
+ const response = await this.mcpServer.handleMessage(
192
+ rpcRequest,
193
+ context,
194
+ );
195
+
196
+ if (response) {
197
+ request.reply.headers["content-type"] = "application/json";
198
+ request.reply.body = JSON.stringify(response);
199
+ } else {
200
+ request.reply.status = 204;
201
+ }
202
+ } catch (error) {
203
+ if (error instanceof JsonRpcParseError) {
204
+ request.reply.status = 400;
205
+ request.reply.headers["content-type"] = "application/json";
206
+ request.reply.body = JSON.stringify(
207
+ createErrorResponse(0, createParseError(error.message)),
208
+ );
209
+ } else {
210
+ this.log.error("Failed to process MCP message", error);
211
+ request.reply.status = 500;
212
+ request.reply.body = JSON.stringify({
213
+ error: (error as Error).message,
214
+ });
215
+ }
216
+ }
217
+ },
218
+ });
219
+ }
220
+
221
+ /**
222
+ * @deprecated Use {@link StreamableHttpMcpTransport}. The 2024-11-05
223
+ * two-endpoint HTTP+SSE pattern was replaced by Streamable HTTP in spec
224
+ * 2025-03-26. This alias is preserved for one release to ease migration.
225
+ */
226
+ export const SseMcpTransport = StreamableHttpMcpTransport;
@@ -0,0 +1,330 @@
1
+ # ORM — Refactoring Roadmap
2
+
3
+ ## Context
4
+
5
+ Alepha currently runs on `drizzle-orm@0.45.x` (stable). This document captures the planned overhaul to **Drizzle v1** — the version that ships **Relations v2**, the official `node:sqlite` driver, and a rewritten `drizzle-kit`.
6
+
7
+ This refactoring is **deferred** until Drizzle v1 reaches GA. As of writing (2026-05) v1 is still in beta (`v1.0.0-beta.20`, March 2025) with no GA date announced. The framework's stability needs the upstream library to be stable too — pulling in a beta would force every consumer to absorb breakage on someone else's release schedule.
8
+
9
+ When v1 GA ships, this becomes a **bigbang upgrade** (no incremental migration path). The plan below is the playbook to execute on that day.
10
+
11
+ ## Why upgrade
12
+
13
+ Alepha wraps Drizzle at the wrong layer. The `Repository` uses the low-level SQL builder (`db.select().from().leftJoin()`) and re-implements join handling manually via `PgRelationManager`. Drizzle's real power — the relational query API — is completely bypassed.
14
+
15
+ Drizzle v1 Relations v2 solves every limitation of Alepha's current join system:
16
+
17
+ | Current limitation | Drizzle v1 solution |
18
+ |---|---|
19
+ | No one-to-many joins | `r.many()` — lateral join + `json_agg` under the hood |
20
+ | No many-to-many | `through()` — junction tables hidden from results |
21
+ | No per-relation `where`/`orderBy`/`limit` | First-class in `db.query.table.findMany({ with: { posts: { where, orderBy, limit } } })` |
22
+ | No `columns` on joined tables | `with: { posts: { columns: { id: true, title: true } } }` |
23
+ | No computed fields on relations | `extras: { fullName: sql\`...\` }` |
24
+ | Manual `.alias()` for self-joins | Handled by relation definition (`alias` param) |
25
+ | `node:sqlite` shim around `better-sqlite3` | Official `drizzle-orm/node-sqlite` driver |
26
+
27
+ ## What Alepha keeps (the genuine value-add)
28
+
29
+ These layers justify the Repository pattern. None of this exists in raw Drizzle and they survive the upgrade unchanged:
30
+
31
+ - **Soft deletes** — automatic `deletedAt IS NULL` injection, transparent to all queries
32
+ - **Multi-tenancy** — automatic org scoping via `currentUserAtom`
33
+ - **Optimistic locking** — `save()` with version checking, `DbVersionMismatchError`
34
+ - **Typed error hierarchy** — `DbConflictError`, `DbForeignKeyError`, `DbDeadlockError`, etc.
35
+ - **Pagination** — `paginate()` with count, metadata, sort string parsing
36
+ - **Aggregate API** — type-safe `aggregate()` with GROUP BY, HAVING, dot-notation ordering
37
+ - **Transaction propagation** — implicit via `alepha.store`, no manual `{ tx }` drilling
38
+ - **Query caching** — per-table TTL cache with auto-invalidation on writes
39
+ - **Lifecycle events** — `repository:create:before/after`, `repository:read:before/after`, etc.
40
+ - **Codec integration** — `DateTime`, custom types auto-encoded in WHERE clauses
41
+ - **Schema transforms** — `insertSchema` / `updateSchema` — auto-exclude generated cols, handle defaults
42
+ - **DI integration** — `$repository()`, `$inject()`, service substitution for tests
43
+ - **JSON query DSL** — `{ where: { age: { gt: 18 } } }` — composable, serializable, loggable
44
+
45
+ ## What the current wrapper blocks
46
+
47
+ Drizzle features the current Alepha layer hides from users:
48
+
49
+ | Blocked feature | Impact |
50
+ |---|---|
51
+ | Relational query API (`db.query.table.findMany({ with })`) | Critical — one-to-many, per-relation filtering/ordering/limiting |
52
+ | Lateral joins (`leftJoinLateral`) | High — top-N-per-group patterns |
53
+ | CTEs (`$with` / `with`) | High — recursive queries, complex analytics |
54
+ | Per-relation `where`/`orderBy`/`limit` | High |
55
+ | `columns` on relations | Medium |
56
+ | `extras` / computed fields | Medium |
57
+ | Set operators (`union`, `intersect`, `except`) | Medium |
58
+ | UPDATE with FROM/JOINs | Medium — join-based batch updates |
59
+ | INSERT from SELECT | Medium |
60
+ | `onConflictDoNothing` | Low-medium |
61
+ | `selectDistinctOn` | Low-medium |
62
+
63
+ ## Drizzle v1 — feature reference
64
+
65
+ ### Relations v2
66
+
67
+ ```typescript
68
+ const relations = defineRelations({ users, posts, comments }, (r) => ({
69
+ users: {
70
+ posts: r.many.posts(), // one-to-many
71
+ groups: r.many.groups({ // many-to-many via junction
72
+ from: r.users.id.through(r.usersToGroups.userId),
73
+ to: r.groups.id.through(r.usersToGroups.groupId),
74
+ }),
75
+ },
76
+ posts: {
77
+ author: r.one.users({ // many-to-one
78
+ from: r.posts.authorId,
79
+ to: r.users.id,
80
+ }),
81
+ comments: r.many.comments(),
82
+ },
83
+ comments: {
84
+ post: r.one.posts({
85
+ from: r.comments.postId,
86
+ to: r.posts.id,
87
+ }),
88
+ },
89
+ }));
90
+ ```
91
+
92
+ Key features:
93
+ - `r.one` / `r.many` — declarative relation types
94
+ - `through()` — many-to-many, junction table hidden from query results
95
+ - `optional: true` — nullable relations (type-level)
96
+ - `alias` — disambiguate multiple relations between same tables
97
+ - `where` — predefined filters on target table (polymorphic relations)
98
+ - `defineRelationsPart()` — modules define their own relations independently, then merge
99
+
100
+ ### Relational Query Builder v2
101
+
102
+ ```typescript
103
+ const result = await db.query.users.findMany({
104
+ columns: { id: true, name: true },
105
+ where: { verified: true, age: { gt: 18 } },
106
+ orderBy: { name: "asc" },
107
+ limit: 10,
108
+ offset: 20,
109
+ extras: {
110
+ postCount: (users) => db.$count(posts, eq(posts.authorId, users.id)),
111
+ },
112
+ with: {
113
+ posts: {
114
+ columns: { id: true, title: true },
115
+ where: { publishedAt: { isNotNull: true } },
116
+ orderBy: { publishedAt: "desc" },
117
+ limit: 5,
118
+ with: {
119
+ comments: {
120
+ limit: 3,
121
+ orderBy: { createdAt: "desc" },
122
+ },
123
+ },
124
+ },
125
+ },
126
+ });
127
+ ```
128
+
129
+ Compiles to a single SQL statement using lateral joins with `json_agg`:
130
+
131
+ ```sql
132
+ SELECT ...
133
+ FROM "users" AS "d0"
134
+ LEFT JOIN LATERAL (
135
+ SELECT coalesce(json_agg(row_to_json("t".*)), '[]') AS "r"
136
+ FROM (
137
+ SELECT ... FROM "posts" AS "d1"
138
+ WHERE "d0"."id" = "d1"."author_id"
139
+ AND "d1"."published_at" IS NOT NULL
140
+ ORDER BY "d1"."published_at" DESC
141
+ LIMIT 5
142
+ ) AS "t"
143
+ ) AS "posts" ON true
144
+ ```
145
+
146
+ Where syntax operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `like`, `ilike`, `notLike`, `notIlike`, `isNull`, `isNotNull`, `arrayOverlaps`, `arrayContained`, `arrayContains`, `OR`, `AND`, `NOT`, `RAW`.
147
+
148
+ ### Official `node:sqlite` driver
149
+
150
+ ```typescript
151
+ import { drizzle } from "drizzle-orm/node-sqlite";
152
+
153
+ // Simple — just a path
154
+ const db = drizzle("sqlite.db");
155
+
156
+ // Advanced — pass existing DatabaseSync
157
+ import { DatabaseSync } from "node:sqlite";
158
+ const sqlite = new DatabaseSync("sqlite.db");
159
+ const db = drizzle({ client: sqlite });
160
+ ```
161
+
162
+ No more `better-sqlite3` shim, no `aliasSelectColumns` SQL rewriting.
163
+
164
+ ### Other v1 features
165
+
166
+ - **MSSQL support** — full dialect with drizzle-orm, drizzle-kit, drizzle-seed
167
+ - **CockroachDB support** — new dialect
168
+ - **Migration folders v3** — no `journal.json`, grouped folders, fewer Git conflicts
169
+ - **`drizzle-kit` rewrite** — DDL snapshots, ~10x faster introspection
170
+ - **Validator consolidation** — `drizzle-zod` → `drizzle-orm/zod`, `drizzle-typebox` → `drizzle-orm/typebox`
171
+ - **Alternation engine** — advanced query branching (beta)
172
+ - **Commutativity checks** (`drizzle-kit check`) — detect migration collisions in teams
173
+ - **Column `.as()` alias** — direct column aliasing
174
+ - **Subqueries in select fields** — computed columns inline
175
+ - **RLS** — moved to `pgTable.withRLS()`
176
+ - **Prepared statements** — work inside relational queries with `sql.placeholder()`
177
+ - **PostgreSQL type fixes** — arrays of intervals, timestamps, dates now map correctly
178
+
179
+ ## Breaking changes to handle
180
+
181
+ | Breaking change | Alepha impact |
182
+ |---|---|
183
+ | Migration folder restructure (v3 layout) | Run `drizzle-kit up` once. Update `DrizzleKitProvider`. |
184
+ | Relations v1 → v2 | Alepha doesn't use Drizzle relations today — adopt v2 fresh. |
185
+ | PostgreSQL array/timestamp type fixes | Audit `db.createdAt()`, `db.updatedAt()` and any array columns. |
186
+ | Database/session/migrator gain 2 new generics | Update `DatabaseProvider` types. |
187
+ | `DrizzleConfig` gains `TRelations` generic + `relations` field | Pass relations to `drizzle()` constructor. |
188
+ | Validator packages moved into `drizzle-orm/*` | Low impact — Alepha uses TypeBox directly. |
189
+ | `.enableRLS()` → `pgTable.withRLS()` | Audit Alepha for RLS usage (currently none expected). |
190
+
191
+ ## Migration playbook (when v1 GA ships)
192
+
193
+ ### 1. Bump dependencies
194
+
195
+ ```bash
196
+ yarn add drizzle-orm@^1.0.0
197
+ yarn add -D drizzle-kit@^1.0.0
198
+ ```
199
+
200
+ ### 2. Replace the `node:sqlite` shim
201
+
202
+ Delete the `better-sqlite3` shim code in `core/providers/drivers/`:
203
+ - `shimDatabaseSync()` (~50 lines)
204
+ - `aliasSelectColumns()` (~60 lines)
205
+ - `initDrizzle()` manual session construction (~20 lines)
206
+
207
+ Replace with the official driver:
208
+
209
+ ```typescript
210
+ import { drizzle } from "drizzle-orm/node-sqlite";
211
+ this.drizzleDb = drizzle({ client: this.sqlite, relations });
212
+ ```
213
+
214
+ ### 3. Auto-generate `defineRelations()` from `db.ref()`
215
+
216
+ The FK info already exists in `$entity` schemas. Either extend `ModelBuilder` or add a new `RelationBuilder` that walks all registered entities and emits:
217
+
218
+ ```typescript
219
+ const relations = defineRelations(tables, (r) => ({
220
+ players: {
221
+ team: r.one.teams({
222
+ from: r.players.teamId,
223
+ to: r.teams.id,
224
+ }),
225
+ },
226
+ teams: {
227
+ players: r.many.players(),
228
+ },
229
+ }));
230
+ ```
231
+
232
+ This is fully derivable from `db.ref()` declarations — each ref knows its source column and target `EntityColumn`.
233
+
234
+ ### 4. Add `relationalQuery()` to `Repository`
235
+
236
+ A new method that delegates to `db.query.table.findMany()` while applying Alepha's concerns:
237
+
238
+ ```typescript
239
+ public async relationalQuery<Config>(config: RelationalQueryConfig<T>) {
240
+ // Inject soft-delete filter
241
+ // Inject org scoping
242
+ // Encode values via codec
243
+ // Emit repository:read:before/after events
244
+ // Handle caching
245
+ return await db.query[this.tableName].findMany(config);
246
+ }
247
+ ```
248
+
249
+ ### 5. Deprecate `findMany({ with })` for joins
250
+
251
+ Keep it working for backward compatibility but log a deprecation warning pointing to `relationalQuery()`. Remove in a follow-up release once consumers migrate.
252
+
253
+ ### 6. Run `drizzle-kit up`
254
+
255
+ Migrate existing migration folders to the v3 layout.
256
+
257
+ ### 7. Audit timestamp/array column types
258
+
259
+ PostgreSQL type fixes in v1 may change runtime values for:
260
+ - `db.createdAt()` / `db.updatedAt()` — timestamp columns
261
+ - Any array columns (intervals, timestamps, dates)
262
+
263
+ ### 8. Pass relations to `drizzle()`
264
+
265
+ Update `DatabaseProvider` subclasses to pass the auto-generated relations when constructing the Drizzle instance.
266
+
267
+ ## Files affected
268
+
269
+ ### Delete / heavily simplify
270
+
271
+ | File | Approx. lines | Reason |
272
+ |---|---|---|
273
+ | `core/services/PgRelationManager.ts` | 131 | Replaced by Drizzle's relational query engine |
274
+ | `node:sqlite` driver shim | ~150 | `shimDatabaseSync()`, `aliasSelectColumns()` gone |
275
+ | Join types in query layer (`PgRelation`, `PgRelationMap`, `PgStatic`) | ~40 | Drizzle handles relation types natively |
276
+ | Relation where types (`PgQueryWhereRelations`) | ~10 | Drizzle v2 where syntax handles this |
277
+
278
+ ### Modify
279
+
280
+ | File | Change |
281
+ |---|---|
282
+ | `core/services/Repository.ts` | Add `relationalQuery()`, deprecate `findMany({ with })` joins |
283
+ | `core/providers/RepositoryProvider.ts` / `DatabaseTypeProvider.ts` | Accept and pass `relations` to Drizzle constructor |
284
+ | `core/services/ModelBuilder.ts` (or new `RelationBuilder.ts`) | Generate `defineRelations()` from `db.ref()` |
285
+ | `core/providers/DrizzleKitProvider.ts` | Update for migration folder v3 |
286
+ | `postgres/` ModelBuilder | Audit timestamp/array type changes |
287
+ | `core/providers/drivers/` (sqlite) | Replace shim with official driver |
288
+
289
+ ## Where syntax — Alepha → Drizzle v2
290
+
291
+ Alepha's current syntax maps almost 1:1 to Drizzle v2:
292
+
293
+ ```
294
+ Alepha Drizzle v2
295
+ ────── ──────────
296
+ { age: { gt: 18 } } { age: { gt: 18 } }
297
+ { age: { gte: 18, lte: 65 } } { age: { gte: 18, lte: 65 } }
298
+ { name: { contains: "foo" } } { name: { ilike: "%foo%" } }
299
+ { status: { inArray: [...] } } { status: { in: [...] } }
300
+ { isNull: true } { isNull: true }
301
+ { and: [...] } { AND: [...] }
302
+ { or: [...] } { OR: [...] }
303
+ { not: {...} } { NOT: {...} }
304
+ ```
305
+
306
+ Differences to bridge:
307
+ - `inArray` → `in`, `notInArray` → `notIn`
308
+ - `and` / `or` / `not` → `AND` / `OR` / `NOT` (capitalized)
309
+ - `contains` / `startsWith` / `endsWith` — Alepha sugar with no direct Drizzle equivalent (expand to `ilike`)
310
+ - Drizzle adds `RAW: (table) => sql\`...\`` for inline raw SQL inside `where`
311
+
312
+ Alepha's JSON DSL stays the public API; the bridge to Drizzle v2 lives inside `Repository` / `QueryManager`.
313
+
314
+ ## Why not now
315
+
316
+ - **Beta risk** — Drizzle v1 is still in beta. Pinning Alepha to a beta would couple every Alepha release to upstream's stabilization timeline.
317
+ - **Bigbang nature** — the upgrade is not incremental (Relations v2, migration folder layout, type generics, driver swap all land together). Better executed in one focused window post-GA than dripped over months.
318
+ - **No urgent user pain** — current Repository covers ~95% of usage. The blocked features (one-to-many joins, lateral joins, CTEs) are real gaps but have manual workarounds today.
319
+
320
+ ## Estimated effort when triggered
321
+
322
+ Multi-day, not single-day:
323
+ - Replace `node:sqlite` shim — ~half day
324
+ - Auto-generate `defineRelations()` from entity refs — 1 day
325
+ - Add `relationalQuery()` with all Repository concerns wired through — 1 day
326
+ - Migration folder v3 + `drizzle-kit` provider update — half day
327
+ - PG type audit + test suite stabilization — 1 day
328
+ - Total: ~4 days of focused work, plus regression hunt against the existing test suite.
329
+
330
+ The framework's `~3400` ORM-touching tests are the safety net. If they pass, the upgrade landed cleanly.
@@ -1014,6 +1014,7 @@ export const testTransactionThrowsWhenUnsupported = async (alepha: Alepha) => {
1014
1014
  original,
1015
1015
  );
1016
1016
  } else {
1017
+ // biome-ignore lint/performance/noDelete: setting to undefined fails because the prototype has a getter
1017
1018
  delete provider.supportsTransactions;
1018
1019
  }
1019
1020
  }
@@ -1,8 +1,8 @@
1
- import { type Alepha, AlephaError, t } from "alepha";
1
+ import { type Alepha, t } from "alepha";
2
2
  import { sql } from "drizzle-orm";
3
3
  import { expect } from "vitest";
4
4
  import { PG_GENERATED } from "../core/constants/PG_SYMBOLS.ts";
5
- import { $entity, $repository, $view, db, pgAttr } from "../core/index.ts";
5
+ import { $entity, $repository, db, pgAttr } from "../core/index.ts";
6
6
 
7
7
  // ============================================================================
8
8
  // Shared entity definitions
@@ -425,68 +425,3 @@ export const testQueryCacheCustomKey = async (alepha: Alepha) => {
425
425
  );
426
426
  expect(cached).toHaveLength(1);
427
427
  };
428
-
429
- // ============================================================================
430
- // Feature 8: Database Views
431
- // ============================================================================
432
-
433
- export const testViewReadOnly = async (alepha: Alepha) => {
434
- // Create the underlying table
435
- const itemEntity = $entity({
436
- name: "view_items",
437
- schema: t.object({
438
- id: db.primaryKey(),
439
- name: t.text(),
440
- price: t.number(),
441
- }),
442
- });
443
-
444
- // Create a view
445
- const itemView = $view({
446
- name: "view_items_summary",
447
- schema: t.object({
448
- id: t.integer(),
449
- name: t.text(),
450
- price: t.number(),
451
- }),
452
- query: sql`SELECT id, name, price FROM view_items`,
453
- });
454
-
455
- class App {
456
- items = $repository(itemEntity);
457
- summary = $repository(itemView);
458
- }
459
-
460
- const app = alepha.inject(App);
461
- await alepha.start();
462
-
463
- // Verify the repository detects it's a view
464
- expect(app.summary.isReadOnly).toBe(true);
465
- expect(app.items.isReadOnly).toBe(false);
466
-
467
- // Write operations should throw on views
468
- await expect(
469
- app.summary.create({ id: 1, name: "test", price: 10 } as any),
470
- ).rejects.toThrow(AlephaError);
471
- };
472
-
473
- export const testViewRefreshThrowsForNonMaterialized = async (
474
- alepha: Alepha,
475
- ) => {
476
- const view = $view({
477
- name: "non_mat_view",
478
- schema: t.object({
479
- id: t.integer(),
480
- }),
481
- query: sql`SELECT 1 as id`,
482
- });
483
-
484
- class App {
485
- repo = $repository(view);
486
- }
487
-
488
- const app = alepha.inject(App);
489
- await alepha.start();
490
-
491
- await expect(app.repo.refresh()).rejects.toThrow(AlephaError);
492
- };
@@ -14,8 +14,6 @@ import {
14
14
  testPartialIndex,
15
15
  testQueryCache,
16
16
  testQueryCacheCustomKey,
17
- testViewReadOnly,
18
- testViewRefreshThrowsForNonMaterialized,
19
17
  } from "./orm-next-tests.ts";
20
18
 
21
19
  const sqlite = () =>
@@ -119,22 +117,3 @@ describe("query caching", () => {
119
117
  await testQueryCacheCustomKey(postgres());
120
118
  });
121
119
  });
122
-
123
- // =============================================================================
124
- // Feature 8: Database Views
125
- // =============================================================================
126
-
127
- describe("database views", () => {
128
- it("should block writes on view repositories (sqlite)", async () => {
129
- await testViewReadOnly(sqlite());
130
- });
131
- it("should block writes on view repositories (postgres)", async () => {
132
- await testViewReadOnly(postgres());
133
- });
134
- it("should throw on refresh for non-materialized view (sqlite)", async () => {
135
- await testViewRefreshThrowsForNonMaterialized(sqlite());
136
- });
137
- it("should throw on refresh for non-materialized view (postgres)", async () => {
138
- await testViewRefreshThrowsForNonMaterialized(postgres());
139
- });
140
- });
@@ -12,13 +12,11 @@ export * from "./errors/DbEntityNotFoundError.ts";
12
12
  export * from "./errors/DbForeignKeyError.ts";
13
13
  export * from "./errors/DbNotNullError.ts";
14
14
  export * from "./errors/DbTableNotFoundError.ts";
15
- export * from "./helpers/parseQueryString.ts";
16
15
  export * from "./helpers/pgAttr.ts";
17
16
  export * from "./interfaces/AggregateQuery.ts";
18
17
  export * from "./interfaces/FilterOperators.ts";
19
18
  export * from "./interfaces/PgQuery.ts";
20
19
  export * from "./interfaces/PgQueryWhere.ts";
21
20
  export * from "./primitives/$entity.ts";
22
- export * from "./primitives/$view.ts";
23
21
  export * from "./providers/DatabaseTypeProvider.ts";
24
22
  export * from "./schemas/legacyIdSchema.ts";