@rebasepro/server-core 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/README.md +2 -2
  2. package/dist/api/ast-schema-editor.d.ts +21 -0
  3. package/dist/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
  4. package/dist/api/errors.d.ts +53 -0
  5. package/dist/api/index.d.ts +7 -0
  6. package/dist/api/logs-routes.d.ts +37 -0
  7. package/dist/api/openapi-generator.d.ts +16 -0
  8. package/dist/api/rest/api-generator.d.ts +68 -0
  9. package/{src/api/rest/index.ts → dist/api/rest/index.d.ts} +0 -1
  10. package/dist/api/rest/query-parser.d.ts +6 -0
  11. package/dist/api/schema-editor-routes.d.ts +3 -0
  12. package/dist/api/types.d.ts +56 -0
  13. package/dist/auth/adapter-middleware.d.ts +43 -0
  14. package/dist/auth/admin-roles-route.d.ts +18 -0
  15. package/dist/auth/admin-user-ops.d.ts +79 -0
  16. package/dist/auth/admin-users-route.d.ts +28 -0
  17. package/dist/auth/api-keys/api-key-middleware.d.ts +39 -0
  18. package/{src/auth/api-keys/api-key-permission-guard.ts → dist/auth/api-keys/api-key-permission-guard.d.ts} +2 -34
  19. package/dist/auth/api-keys/api-key-routes.d.ts +20 -0
  20. package/dist/auth/api-keys/api-key-store.d.ts +35 -0
  21. package/{src/auth/api-keys/api-key-types.ts → dist/auth/api-keys/api-key-types.d.ts} +0 -6
  22. package/{src/auth/api-keys/index.ts → dist/auth/api-keys/index.d.ts} +2 -22
  23. package/dist/auth/apple-oauth.d.ts +30 -0
  24. package/{src/auth/auth-hooks.ts → dist/auth/auth-hooks.d.ts} +15 -73
  25. package/dist/auth/bitbucket-oauth.d.ts +11 -0
  26. package/dist/auth/builtin-auth-adapter.d.ts +55 -0
  27. package/dist/auth/cookie-utils.d.ts +32 -0
  28. package/{src/auth/crypto-utils.ts → dist/auth/crypto-utils.d.ts} +1 -16
  29. package/dist/auth/custom-auth-adapter.d.ts +39 -0
  30. package/dist/auth/discord-oauth.d.ts +14 -0
  31. package/dist/auth/facebook-oauth.d.ts +14 -0
  32. package/dist/auth/github-oauth.d.ts +15 -0
  33. package/dist/auth/gitlab-oauth.d.ts +13 -0
  34. package/dist/auth/google-oauth.d.ts +47 -0
  35. package/{src/auth/index.ts → dist/auth/index.d.ts} +4 -22
  36. package/{src/auth/interfaces.ts → dist/auth/interfaces.d.ts} +20 -89
  37. package/dist/auth/jwt.d.ts +67 -0
  38. package/dist/auth/linkedin-oauth.d.ts +18 -0
  39. package/dist/auth/magic-link-routes.d.ts +32 -0
  40. package/dist/auth/mfa-crypto.d.ts +23 -0
  41. package/dist/auth/mfa-routes.d.ts +7 -0
  42. package/dist/auth/mfa.d.ts +49 -0
  43. package/dist/auth/microsoft-oauth.d.ts +16 -0
  44. package/dist/auth/middleware.d.ts +158 -0
  45. package/dist/auth/password.d.ts +22 -0
  46. package/dist/auth/rate-limiter.d.ts +50 -0
  47. package/dist/auth/reset-password-admin.d.ts +29 -0
  48. package/dist/auth/rls-scope.d.ts +31 -0
  49. package/dist/auth/routes.d.ts +66 -0
  50. package/dist/auth/session-routes.d.ts +29 -0
  51. package/dist/auth/slack-oauth.d.ts +12 -0
  52. package/dist/auth/spotify-oauth.d.ts +12 -0
  53. package/dist/auth/twitter-oauth.d.ts +18 -0
  54. package/dist/collections/BackendCollectionRegistry.d.ts +13 -0
  55. package/dist/collections/loader.d.ts +5 -0
  56. package/dist/cron/cron-loader.d.ts +18 -0
  57. package/dist/cron/cron-routes.d.ts +14 -0
  58. package/dist/cron/cron-scheduler.d.ts +106 -0
  59. package/dist/cron/cron-store.d.ts +32 -0
  60. package/dist/cron/define-cron.d.ts +28 -0
  61. package/{src/cron/index.ts → dist/cron/index.d.ts} +1 -0
  62. package/dist/db/interfaces.d.ts +18 -0
  63. package/dist/dynamic-import-Dvh-K5fl.js +22 -0
  64. package/dist/dynamic-import-Dvh-K5fl.js.map +1 -0
  65. package/dist/email/index.d.ts +6 -0
  66. package/dist/email/smtp-email-service.d.ts +30 -0
  67. package/dist/email/templates.d.ts +50 -0
  68. package/{src/email/types.ts → dist/email/types.d.ts} +40 -36
  69. package/dist/env.d.ts +102 -0
  70. package/dist/functions/define-function.d.ts +55 -0
  71. package/dist/functions/function-loader.d.ts +18 -0
  72. package/dist/functions/function-routes.d.ts +10 -0
  73. package/{src/functions/index.ts → dist/functions/index.d.ts} +2 -0
  74. package/dist/history/history-routes.d.ts +23 -0
  75. package/{src/history/index.ts → dist/history/index.d.ts} +0 -1
  76. package/dist/index.d.ts +35 -0
  77. package/dist/index.es.js +18184 -0
  78. package/dist/index.es.js.map +1 -0
  79. package/dist/index.umd.js +48629 -0
  80. package/dist/index.umd.js.map +1 -0
  81. package/dist/init/docs.d.ts +4 -0
  82. package/dist/init/health.d.ts +2 -0
  83. package/dist/init/middlewares.d.ts +10 -0
  84. package/dist/init/shutdown.d.ts +65 -0
  85. package/dist/init/storage.d.ts +5 -0
  86. package/dist/init.d.ts +344 -0
  87. package/dist/jwt-BwIn8xmk.js +4200 -0
  88. package/dist/jwt-BwIn8xmk.js.map +1 -0
  89. package/dist/logger-BYU66ENZ.js +94 -0
  90. package/dist/logger-BYU66ENZ.js.map +1 -0
  91. package/dist/ms-DnYXB-Wd.js +162 -0
  92. package/dist/ms-DnYXB-Wd.js.map +1 -0
  93. package/dist/openapi-generator-Z9oYWLf_.js +586 -0
  94. package/dist/openapi-generator-Z9oYWLf_.js.map +1 -0
  95. package/dist/schema-editor-routes-D3ef8zu1.js +219 -0
  96. package/dist/schema-editor-routes-D3ef8zu1.js.map +1 -0
  97. package/dist/serve-spa.d.ts +36 -0
  98. package/dist/services/driver-registry.d.ts +78 -0
  99. package/dist/services/routed-realtime-service.d.ts +43 -0
  100. package/dist/services/webhook-service.d.ts +29 -0
  101. package/dist/singleton.d.ts +51 -0
  102. package/dist/src-B4OLmNVa.js +437 -0
  103. package/dist/src-B4OLmNVa.js.map +1 -0
  104. package/dist/src-B5WkP1Rv.js +24778 -0
  105. package/dist/src-B5WkP1Rv.js.map +1 -0
  106. package/dist/storage/GCSStorageController.d.ts +43 -0
  107. package/dist/storage/LocalStorageController.d.ts +46 -0
  108. package/dist/storage/S3StorageController.d.ts +40 -0
  109. package/dist/storage/image-transform.d.ts +50 -0
  110. package/{src/storage/index.ts → dist/storage/index.d.ts} +6 -21
  111. package/dist/storage/routes.d.ts +70 -0
  112. package/dist/storage/storage-registry.d.ts +78 -0
  113. package/dist/storage/tus-handler.d.ts +53 -0
  114. package/{src/storage/types.ts → dist/storage/types.d.ts} +32 -38
  115. package/dist/types/index.d.ts +11 -0
  116. package/dist/utils/dev-port.d.ts +45 -0
  117. package/dist/utils/dynamic-import.d.ts +25 -0
  118. package/dist/utils/logger.d.ts +31 -0
  119. package/dist/utils/logging.d.ts +9 -0
  120. package/dist/utils/request-id.d.ts +4 -0
  121. package/dist/utils/request-logger.d.ts +19 -0
  122. package/{src/utils/sql.ts → dist/utils/sql.d.ts} +5 -16
  123. package/package.json +49 -22
  124. package/coverage/clover.xml +0 -3739
  125. package/coverage/coverage-final.json +0 -31
  126. package/coverage/lcov-report/base.css +0 -224
  127. package/coverage/lcov-report/block-navigation.js +0 -87
  128. package/coverage/lcov-report/favicon.png +0 -0
  129. package/coverage/lcov-report/index.html +0 -266
  130. package/coverage/lcov-report/prettify.css +0 -1
  131. package/coverage/lcov-report/prettify.js +0 -2
  132. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  133. package/coverage/lcov-report/sorter.js +0 -210
  134. package/coverage/lcov-report/src/api/ast-schema-editor.ts.html +0 -952
  135. package/coverage/lcov-report/src/api/errors.ts.html +0 -472
  136. package/coverage/lcov-report/src/api/graphql/graphql-schema-generator.ts.html +0 -1069
  137. package/coverage/lcov-report/src/api/graphql/index.html +0 -116
  138. package/coverage/lcov-report/src/api/index.html +0 -176
  139. package/coverage/lcov-report/src/api/openapi-generator.ts.html +0 -565
  140. package/coverage/lcov-report/src/api/rest/api-generator.ts.html +0 -994
  141. package/coverage/lcov-report/src/api/rest/index.html +0 -131
  142. package/coverage/lcov-report/src/api/rest/query-parser.ts.html +0 -550
  143. package/coverage/lcov-report/src/api/schema-editor-routes.ts.html +0 -202
  144. package/coverage/lcov-report/src/api/server.ts.html +0 -823
  145. package/coverage/lcov-report/src/auth/admin-routes.ts.html +0 -973
  146. package/coverage/lcov-report/src/auth/index.html +0 -176
  147. package/coverage/lcov-report/src/auth/jwt.ts.html +0 -574
  148. package/coverage/lcov-report/src/auth/middleware.ts.html +0 -745
  149. package/coverage/lcov-report/src/auth/password.ts.html +0 -310
  150. package/coverage/lcov-report/src/auth/services.ts.html +0 -2074
  151. package/coverage/lcov-report/src/collections/index.html +0 -116
  152. package/coverage/lcov-report/src/collections/loader.ts.html +0 -232
  153. package/coverage/lcov-report/src/db/auth-schema.ts.html +0 -523
  154. package/coverage/lcov-report/src/db/data-transformer.ts.html +0 -1753
  155. package/coverage/lcov-report/src/db/entityService.ts.html +0 -700
  156. package/coverage/lcov-report/src/db/index.html +0 -146
  157. package/coverage/lcov-report/src/db/services/EntityFetchService.ts.html +0 -4048
  158. package/coverage/lcov-report/src/db/services/EntityPersistService.ts.html +0 -883
  159. package/coverage/lcov-report/src/db/services/RelationService.ts.html +0 -3121
  160. package/coverage/lcov-report/src/db/services/entity-helpers.ts.html +0 -442
  161. package/coverage/lcov-report/src/db/services/index.html +0 -176
  162. package/coverage/lcov-report/src/db/services/index.ts.html +0 -124
  163. package/coverage/lcov-report/src/generate-drizzle-schema-logic.ts.html +0 -1960
  164. package/coverage/lcov-report/src/index.html +0 -116
  165. package/coverage/lcov-report/src/services/driver-registry.ts.html +0 -631
  166. package/coverage/lcov-report/src/services/index.html +0 -131
  167. package/coverage/lcov-report/src/services/postgresDataDriver.ts.html +0 -3025
  168. package/coverage/lcov-report/src/storage/LocalStorageController.ts.html +0 -1189
  169. package/coverage/lcov-report/src/storage/S3StorageController.ts.html +0 -970
  170. package/coverage/lcov-report/src/storage/index.html +0 -161
  171. package/coverage/lcov-report/src/storage/storage-registry.ts.html +0 -646
  172. package/coverage/lcov-report/src/storage/types.ts.html +0 -451
  173. package/coverage/lcov-report/src/utils/drizzle-conditions.ts.html +0 -3082
  174. package/coverage/lcov-report/src/utils/index.html +0 -116
  175. package/coverage/lcov.info +0 -7179
  176. package/jest.config.cjs +0 -19
  177. package/src/api/ast-schema-editor.ts +0 -289
  178. package/src/api/collections_for_test/callbacks_test_collection.ts +0 -61
  179. package/src/api/errors.ts +0 -278
  180. package/src/api/graphql/graphql-schema-generator.ts +0 -383
  181. package/src/api/graphql/index.ts +0 -2
  182. package/src/api/index.ts +0 -11
  183. package/src/api/logs-routes.ts +0 -132
  184. package/src/api/openapi-generator.ts +0 -727
  185. package/src/api/rest/api-generator-count.test.ts +0 -126
  186. package/src/api/rest/api-generator.ts +0 -747
  187. package/src/api/rest/query-parser.ts +0 -300
  188. package/src/api/schema-editor-routes.ts +0 -41
  189. package/src/api/server.ts +0 -271
  190. package/src/api/types.ts +0 -104
  191. package/src/auth/adapter-middleware.ts +0 -114
  192. package/src/auth/admin-roles-route.ts +0 -36
  193. package/src/auth/admin-user-ops.ts +0 -236
  194. package/src/auth/admin-users-route.ts +0 -302
  195. package/src/auth/api-keys/api-key-middleware.ts +0 -133
  196. package/src/auth/api-keys/api-key-routes.ts +0 -193
  197. package/src/auth/api-keys/api-key-store.ts +0 -340
  198. package/src/auth/apple-oauth.ts +0 -122
  199. package/src/auth/bitbucket-oauth.ts +0 -84
  200. package/src/auth/builtin-auth-adapter.ts +0 -380
  201. package/src/auth/custom-auth-adapter.ts +0 -86
  202. package/src/auth/discord-oauth.ts +0 -85
  203. package/src/auth/facebook-oauth.ts +0 -74
  204. package/src/auth/github-oauth.ts +0 -112
  205. package/src/auth/gitlab-oauth.ts +0 -72
  206. package/src/auth/google-oauth.ts +0 -223
  207. package/src/auth/jwt.ts +0 -208
  208. package/src/auth/linkedin-oauth.ts +0 -83
  209. package/src/auth/magic-link-routes.ts +0 -167
  210. package/src/auth/mfa-crypto.ts +0 -91
  211. package/src/auth/mfa-routes.ts +0 -323
  212. package/src/auth/mfa.ts +0 -161
  213. package/src/auth/microsoft-oauth.ts +0 -90
  214. package/src/auth/middleware.ts +0 -369
  215. package/src/auth/password.ts +0 -77
  216. package/src/auth/rate-limiter.ts +0 -225
  217. package/src/auth/reset-password-admin.ts +0 -160
  218. package/src/auth/rls-scope.ts +0 -58
  219. package/src/auth/routes.ts +0 -802
  220. package/src/auth/session-routes.ts +0 -353
  221. package/src/auth/slack-oauth.ts +0 -73
  222. package/src/auth/spotify-oauth.ts +0 -69
  223. package/src/auth/twitter-oauth.ts +0 -128
  224. package/src/collections/BackendCollectionRegistry.ts +0 -20
  225. package/src/collections/loader.ts +0 -50
  226. package/src/cron/cron-loader.ts +0 -84
  227. package/src/cron/cron-routes.test.ts +0 -265
  228. package/src/cron/cron-routes.ts +0 -85
  229. package/src/cron/cron-scheduler.test.ts +0 -559
  230. package/src/cron/cron-scheduler.ts +0 -581
  231. package/src/cron/cron-store.ts +0 -166
  232. package/src/db/interfaces.ts +0 -60
  233. package/src/email/index.ts +0 -19
  234. package/src/email/smtp-email-service.ts +0 -123
  235. package/src/email/templates.ts +0 -470
  236. package/src/env.ts +0 -227
  237. package/src/functions/function-loader.ts +0 -116
  238. package/src/functions/function-routes.ts +0 -31
  239. package/src/history/history-routes.ts +0 -129
  240. package/src/index.ts +0 -70
  241. package/src/init/docs.ts +0 -47
  242. package/src/init/health.ts +0 -37
  243. package/src/init/middlewares.ts +0 -61
  244. package/src/init/shutdown.ts +0 -56
  245. package/src/init/storage.ts +0 -57
  246. package/src/init.ts +0 -1041
  247. package/src/serve-spa.ts +0 -89
  248. package/src/services/driver-registry.ts +0 -183
  249. package/src/services/routed-realtime-service.ts +0 -113
  250. package/src/services/webhook-service.ts +0 -155
  251. package/src/singleton.ts +0 -70
  252. package/src/storage/LocalStorageController.ts +0 -389
  253. package/src/storage/S3StorageController.ts +0 -300
  254. package/src/storage/image-transform.ts +0 -218
  255. package/src/storage/routes.ts +0 -368
  256. package/src/storage/storage-registry.ts +0 -188
  257. package/src/storage/tus-handler.ts +0 -315
  258. package/src/types/index.ts +0 -27
  259. package/src/utils/dev-port.ts +0 -196
  260. package/src/utils/logger.ts +0 -143
  261. package/src/utils/logging.ts +0 -40
  262. package/src/utils/request-id.ts +0 -40
  263. package/src/utils/request-logger.ts +0 -72
  264. package/test/api-generator.test.ts +0 -588
  265. package/test/api-key-permission-guard.test.ts +0 -144
  266. package/test/ast-schema-editor.test.ts +0 -89
  267. package/test/auth-middleware-hono.test.ts +0 -556
  268. package/test/auth-routes.test.ts +0 -1098
  269. package/test/backend-hooks-data.test.ts +0 -477
  270. package/test/custom-auth-adapter.test.ts +0 -189
  271. package/test/driver-registry.test.ts +0 -282
  272. package/test/email-templates.test.ts +0 -174
  273. package/test/env.test.ts +0 -128
  274. package/test/error-propagation.test.ts +0 -226
  275. package/test/errors-hono.test.ts +0 -133
  276. package/test/errors.test.ts +0 -155
  277. package/test/function-loader.test.ts +0 -127
  278. package/test/graphql-schema-generator.test.ts +0 -554
  279. package/test/jwt-security.test.ts +0 -182
  280. package/test/jwt.test.ts +0 -326
  281. package/test/mfa.test.ts +0 -197
  282. package/test/middleware.test.ts +0 -305
  283. package/test/multi-datasource-routing.test.ts +0 -113
  284. package/test/password.test.ts +0 -165
  285. package/test/query-parser.test.ts +0 -233
  286. package/test/rate-limiter.test.ts +0 -102
  287. package/test/reset-password-admin.test.ts +0 -113
  288. package/test/routed-realtime-service.test.ts +0 -86
  289. package/test/safe-compare.test.ts +0 -66
  290. package/test/singleton.test.ts +0 -59
  291. package/test/smtp-email-service.test.ts +0 -169
  292. package/test/storage-local.test.ts +0 -271
  293. package/test/storage-registry.test.ts +0 -282
  294. package/test/storage-routes.test.ts +0 -222
  295. package/test/storage-s3.test.ts +0 -304
  296. package/test/transform-auth-response.test.ts +0 -305
  297. package/test/webhook-service.test.ts +0 -260
  298. package/tsconfig.json +0 -54
  299. package/tsconfig.prod.json +0 -23
  300. package/vite.config.ts +0 -86
@@ -1,300 +0,0 @@
1
- import type { VectorSearchParams, LogicalCondition, FilterCondition } from "@rebasepro/types";
2
- import { QueryOptions } from "../types";
3
-
4
- /**
5
- * Map PostgREST-style operators to Rebase WhereFilterOp
6
- */
7
- export function mapOperator(op: string): string | null {
8
- switch (op) {
9
- case "eq": return "==";
10
- case "neq": return "!=";
11
- case "gt": return ">";
12
- case "gte": return ">=";
13
- case "lt": return "<";
14
- case "lte": return "<=";
15
- case "in": return "in";
16
- case "nin": return "not-in";
17
- case "cs": return "array-contains";
18
- case "csa": return "array-contains-any";
19
- default: return null;
20
- }
21
- }
22
-
23
- function getLastValue(val: unknown): unknown {
24
- if (Array.isArray(val)) {
25
- return val[val.length - 1];
26
- }
27
- return val;
28
- }
29
-
30
- export function parseLogicalString(str: string): FilterCondition | LogicalCondition {
31
- str = str.trim();
32
- if (str.startsWith("or(") && str.endsWith(")")) {
33
- const inner = str.slice(3, -1);
34
- return { type: "or",
35
- conditions: parseLogicalList(inner) };
36
- }
37
- if (str.startsWith("and(") && str.endsWith(")")) {
38
- const inner = str.slice(4, -1);
39
- return { type: "and",
40
- conditions: parseLogicalList(inner) };
41
- }
42
-
43
- // It's a leaf condition: field.op.val
44
- const firstDot = str.indexOf(".");
45
- if (firstDot === -1) {
46
- return { column: str,
47
- operator: "==",
48
- value: true };
49
- }
50
- const field = str.substring(0, firstDot);
51
- const rest = str.substring(firstDot + 1);
52
- const secondDot = rest.indexOf(".");
53
- let op = "eq";
54
- let valStr = rest;
55
- if (secondDot !== -1) {
56
- op = rest.substring(0, secondDot);
57
- valStr = rest.substring(secondDot + 1);
58
- } else {
59
- op = "eq";
60
- valStr = rest;
61
- }
62
-
63
- const rebaseOp = (mapOperator(op) || "==") as FilterCondition["operator"];
64
- let parsedVal: unknown = valStr;
65
- if (valStr === "true") parsedVal = true;
66
- else if (valStr === "false") parsedVal = false;
67
- else if (valStr === "null") parsedVal = null;
68
- else if (!isNaN(Number(valStr)) && valStr.trim() !== "") parsedVal = Number(valStr);
69
- else if (valStr.startsWith("(")) {
70
- const arrayContent = valStr.endsWith(")") ? valStr.slice(1, -1) : valStr.slice(1);
71
- parsedVal = arrayContent.split(",").map(v => {
72
- const trimmed = v.trim();
73
- if (!isNaN(Number(trimmed)) && trimmed !== "") return Number(trimmed);
74
- if (trimmed === "true") return true;
75
- if (trimmed === "false") return false;
76
- if (trimmed === "null") return null;
77
- return trimmed;
78
- });
79
- }
80
-
81
- return { column: field,
82
- operator: rebaseOp,
83
- value: parsedVal };
84
- }
85
-
86
- function parseLogicalList(str: string): (FilterCondition | LogicalCondition)[] {
87
- const list: (FilterCondition | LogicalCondition)[] = [];
88
- let depth = 0;
89
- let current = "";
90
-
91
- for (let i = 0; i < str.length; i++) {
92
- const char = str[i];
93
- if (char === "(") depth++;
94
- if (char === ")") depth--;
95
-
96
- if (char === "," && depth === 0) {
97
- list.push(parseLogicalString(current));
98
- current = "";
99
- } else {
100
- current += char;
101
- }
102
- }
103
- if (current) {
104
- list.push(parseLogicalString(current));
105
- }
106
- return list;
107
- }
108
-
109
- /**
110
- * Parse query parameters into QueryOptions
111
- */
112
- export function parseQueryOptions(query: Record<string, unknown>): QueryOptions {
113
- const options: QueryOptions = {};
114
-
115
- // Pagination
116
- const limitVal = getLastValue(query.limit);
117
- if (limitVal) options.limit = parseInt(String(limitVal));
118
-
119
- const offsetVal = getLastValue(query.offset);
120
- if (offsetVal) options.offset = parseInt(String(offsetVal));
121
-
122
- const pageVal = getLastValue(query.page);
123
- if (pageVal) {
124
- const page = parseInt(String(pageVal));
125
- const limit = options.limit || 20;
126
- options.offset = (page - 1) * limit;
127
- }
128
-
129
- // Filtering
130
- options.where = {};
131
-
132
- // Handle logical conditions
133
- const orVal = getLastValue(query.or);
134
- const andVal = getLastValue(query.and);
135
- if (orVal) {
136
- let orStr = String(orVal).trim();
137
- if (orStr.startsWith("(") && orStr.endsWith(")")) {
138
- orStr = orStr.slice(1, -1);
139
- }
140
- options.logical = {
141
- type: "or",
142
- conditions: parseLogicalList(orStr)
143
- };
144
- } else if (andVal) {
145
- let andStr = String(andVal).trim();
146
- if (andStr.startsWith("(") && andStr.endsWith(")")) {
147
- andStr = andStr.slice(1, -1);
148
- }
149
- options.logical = {
150
- type: "and",
151
- conditions: parseLogicalList(andStr)
152
- };
153
- }
154
-
155
- // PostgREST-style filtering: ?field=op.value
156
- const reservedQueryKeys = ["limit", "offset", "page", "orderBy", "include", "fields", "searchString", "vector_search", "vector", "vector_distance", "vector_threshold", "or", "and"];
157
- for (const [key, rawValue] of Object.entries(query)) {
158
- if (reservedQueryKeys.includes(key)) continue;
159
-
160
- const rawValues = Array.isArray(rawValue) ? rawValue : [rawValue];
161
- const conditions: [string, unknown][] = [];
162
-
163
- for (const value of rawValues) {
164
- if (typeof value === "string") {
165
- const parts = value.split(".");
166
- if (parts.length >= 2) {
167
- const op = parts[0];
168
- const val = parts.slice(1).join(".");
169
- const rebaseOp = mapOperator(op);
170
-
171
- if (rebaseOp) {
172
- let parsedVal: string | number | boolean | null | (string | number | boolean | null)[] = val;
173
- // Attempt to parse primitive types or arrays
174
- if (val === "true") parsedVal = true;
175
- else if (val === "false") parsedVal = false;
176
- else if (val === "null") parsedVal = null;
177
- else if (!isNaN(Number(val)) && val.trim() !== "") parsedVal = Number(val);
178
- else if (val.startsWith("(")) {
179
- // Array for 'in' or 'not-in' ops (e.g. (1,2,3) or (a,b,c))
180
- const arrayContent = val.endsWith(")") ? val.slice(1, -1) : val.slice(1);
181
- parsedVal = arrayContent.split(",").map(v => {
182
- const trimmed = v.trim();
183
- if (!isNaN(Number(trimmed)) && trimmed !== "") return Number(trimmed);
184
- if (trimmed === "true") return true;
185
- if (trimmed === "false") return false;
186
- if (trimmed === "null") return null;
187
- return trimmed;
188
- });
189
- }
190
-
191
- conditions.push([rebaseOp, parsedVal]);
192
- } else {
193
- // Fallback: assume implicit eq if the dot wasn't an operator (e.g. email or float)
194
- let parsedVal: string | number | boolean | null = value;
195
- if (!isNaN(Number(value)) && value.trim() !== "") parsedVal = Number(value);
196
- conditions.push(["==", parsedVal]);
197
- }
198
- } else {
199
- // Implicit eq
200
- let parsedVal: string | number | boolean | null = value;
201
- if (value === "true") parsedVal = true;
202
- else if (value === "false") parsedVal = false;
203
- else if (value === "null") parsedVal = null;
204
- else if (!isNaN(Number(value)) && value.trim() !== "") parsedVal = Number(value);
205
-
206
- conditions.push(["==", parsedVal]);
207
- }
208
- }
209
- }
210
-
211
- if (conditions.length > 0) {
212
- options.where[key] = conditions.length === 1 ? conditions[0] : conditions;
213
- }
214
- }
215
-
216
- if (Object.keys(options.where).length === 0) {
217
- delete options.where;
218
- }
219
-
220
- // Sorting
221
- const orderByVal = getLastValue(query.orderBy);
222
- if (orderByVal) {
223
- try {
224
- options.orderBy = typeof orderByVal === "string"
225
- ? JSON.parse(orderByVal)
226
- : orderByVal;
227
- } catch {
228
- // Try simple format: "field:direction"
229
- if (typeof orderByVal === "string") {
230
- const [field, direction] = orderByVal.split(":");
231
- const dir = (direction === "desc" ? "desc" : "asc") as "asc" | "desc";
232
- options.orderBy = [
233
- {
234
- field,
235
- direction: dir
236
- }
237
- ];
238
- }
239
- }
240
- }
241
-
242
- // Relation includes
243
- const includeVal = getLastValue(query.include);
244
- if (includeVal) {
245
- const includeStr = String(includeVal).trim();
246
- if (includeStr === "*") {
247
- options.include = ["*"];
248
- } else {
249
- options.include = includeStr.split(",").map(s => s.trim()).filter(Boolean);
250
- }
251
- }
252
-
253
- // Field selection
254
- const fieldsVal = getLastValue(query.fields);
255
- if (fieldsVal) {
256
- const fieldsStr = String(fieldsVal).trim();
257
- options.fields = fieldsStr.split(",").map(s => s.trim()).filter(Boolean);
258
- }
259
-
260
- // Vector similarity search
261
- const vectorSearchVal = getLastValue(query.vector_search);
262
- const vectorVal = getLastValue(query.vector);
263
- if (vectorSearchVal && vectorVal) {
264
- const vectorStr = String(vectorVal);
265
- let queryVector: number[];
266
- try {
267
- queryVector = JSON.parse(vectorStr) as number[];
268
- if (!Array.isArray(queryVector) || !queryVector.every(v => typeof v === "number")) {
269
- throw new Error("Expected array of numbers");
270
- }
271
- } catch {
272
- throw new Error("Invalid vector format. Expected JSON array of numbers, e.g. [0.1,0.2,0.3]");
273
- }
274
-
275
- const distanceParamVal = getLastValue(query.vector_distance);
276
- const distanceParam = distanceParamVal ? String(distanceParamVal) : "cosine";
277
- if (distanceParam !== "cosine" && distanceParam !== "l2" && distanceParam !== "inner_product") {
278
- throw new Error(`Invalid vector_distance: ${distanceParam}. Expected: cosine, l2, or inner_product`);
279
- }
280
-
281
- const vectorSearch: VectorSearchParams = {
282
- property: String(vectorSearchVal),
283
- vector: queryVector,
284
- distance: distanceParam
285
- };
286
-
287
- const thresholdVal = getLastValue(query.vector_threshold);
288
- if (thresholdVal) {
289
- const threshold = parseFloat(String(thresholdVal));
290
- if (isNaN(threshold)) {
291
- throw new Error("Invalid vector_threshold. Expected a number.");
292
- }
293
- vectorSearch.threshold = threshold;
294
- }
295
-
296
- options.vectorSearch = vectorSearch;
297
- }
298
-
299
- return options;
300
- }
@@ -1,41 +0,0 @@
1
- import { Hono } from "hono";
2
- import { AstSchemaEditor } from "./ast-schema-editor";
3
- import { errorHandler } from "./errors";
4
- import { HonoEnv } from "./types";
5
-
6
- export function createSchemaEditorRoutes(collectionsDir: string): Hono<HonoEnv> {
7
- const router = new Hono<HonoEnv>();
8
- router.onError(errorHandler);
9
- const editor = new AstSchemaEditor(collectionsDir);
10
-
11
- router.post("/property/save", async (c) => {
12
- const body = await c.req.json();
13
- const { collectionId, propertyKey, propertyConfig } = body;
14
- await editor.saveProperty(collectionId, propertyKey, propertyConfig);
15
- return c.json({ success: true });
16
- });
17
-
18
- router.post("/property/delete", async (c) => {
19
- const body = await c.req.json();
20
- const { collectionId, propertyKey } = body;
21
- await editor.deleteProperty(collectionId, propertyKey);
22
- return c.json({ success: true });
23
- });
24
-
25
- router.post("/collection/save", async (c) => {
26
- const body = await c.req.json();
27
- const { collectionId, collectionData } = body;
28
- await editor.saveCollection(collectionId, collectionData);
29
- return c.json({ success: true });
30
- });
31
-
32
- router.post("/collection/delete", async (c) => {
33
- const body = await c.req.json();
34
- const { collectionId } = body;
35
- await editor.deleteCollection(collectionId);
36
- return c.json({ success: true });
37
- });
38
-
39
- return router;
40
- }
41
-
package/src/api/server.ts DELETED
@@ -1,271 +0,0 @@
1
- import { Hono } from "hono";
2
- import { cors } from "hono/cors";
3
- import { secureHeaders } from "hono/secure-headers";
4
- import { graphqlServer } from "@hono/graphql-server";
5
- import { serve } from "@hono/node-server";
6
- import { GraphQLSchemaGenerator } from "./graphql/graphql-schema-generator";
7
- import { RestApiGenerator } from "./rest/api-generator";
8
- import { DataDriver, EntityCollection, Relation } from "@rebasepro/types";
9
- import { createDataSourceRegistry, resolveDataSource } from "@rebasepro/common";
10
- import { ApiConfig, HonoEnv } from "./types";
11
- import { loadCollectionsFromDirectory } from "../collections/loader";
12
- import { createSchemaEditorRoutes } from "./schema-editor-routes";
13
- import { createAuthMiddleware, requireAuth, requireAdmin } from "../auth/middleware";
14
- import { errorHandler } from "./errors";
15
- import { generateOpenApiSpec } from "./openapi-generator";
16
- import { requestId } from "../utils/request-id";
17
- import { logger } from "../utils/logger";
18
-
19
- /**
20
- * Simplified API server that leverages existing Rebase infrastructure
21
- * Can be used standalone or mounted on existing Hono app
22
- */
23
- export class RebaseApiServer {
24
- private app: Hono<HonoEnv>;
25
- private router: Hono<HonoEnv>;
26
- private config: ApiConfig;
27
- private driver: DataDriver;
28
-
29
- private constructor(config: ApiConfig & { driver: DataDriver }) {
30
- this.config = {
31
- basePath: "/api",
32
- enableGraphQL: true,
33
- enableREST: true,
34
- pagination: {
35
- defaultLimit: 20,
36
- maxLimit: 100
37
- },
38
- ...config
39
- };
40
-
41
- this.driver = config.driver;
42
-
43
- this.app = new Hono<HonoEnv>();
44
- this.router = new Hono<HonoEnv>();
45
-
46
- this.setupMiddleware();
47
- }
48
-
49
- /**
50
- * Factory method to create an asynchronously initialized ApiServer instance
51
- */
52
- public static async create(config: ApiConfig & { driver: DataDriver }): Promise<RebaseApiServer> {
53
- if (config.collectionsDir && (!config.collections || config.collections.length === 0)) {
54
- config.collections = await loadCollectionsFromDirectory(config.collectionsDir);
55
- } else if (!config.collections) {
56
- config.collections = [];
57
- }
58
-
59
- const server = new RebaseApiServer(config);
60
- server.setupRoutes();
61
- // Since we mount routes directly to router, we can let consumer attach it
62
- server.app.route("/", server.router);
63
-
64
- // Hono global error handler on the root app
65
- server.app.onError(errorHandler);
66
- server.router.onError(errorHandler);
67
-
68
- return server;
69
- }
70
-
71
- /**
72
- * Setup Hono middleware
73
- */
74
- private setupMiddleware(): void {
75
- // Request ID — must be first so all downstream middleware can access it
76
- this.router.use("/*", requestId());
77
-
78
- // Security headers — use same-origin-allow-popups for COOP so that
79
- // OAuth popup flows (Google, etc.) can postMessage back to the opener.
80
- this.router.use("/*", secureHeaders({
81
- crossOriginOpenerPolicy: "same-origin-allow-popups"
82
- }));
83
-
84
- // CORS — only applied if explicitly configured via `cors` option.
85
- // If omitted, the user is expected to configure CORS on their own
86
- // Hono app before mounting the API (recommended approach).
87
- if (this.config.cors) {
88
- const origin = this.config.cors.origin;
89
- this.router.use("/*", cors({
90
- origin: typeof origin === "boolean"
91
- ? (origin ? ((o: string) => o) : "")
92
- : (origin ?? "*"),
93
- credentials: this.config.cors.credentials ?? false
94
- }));
95
- } else if (process.env.NODE_ENV !== "production") {
96
- logger.warn(
97
- "⚠️ [RebaseApiServer] No CORS configuration provided. " +
98
- "The API will accept requests from any origin. " +
99
- "Pass a `cors` option or configure CORS on your Hono app."
100
- );
101
- }
102
-
103
- // Auth middleware
104
- this.router.use("/*", createAuthMiddleware({
105
- driver: this.driver,
106
- requireAuth: this.config.requireAuth ?? true,
107
- validator: this.config.authValidator
108
- }));
109
- }
110
-
111
- /**
112
- * Setup API routes using existing services
113
- */
114
- private setupRoutes(): void {
115
- const basePath = this.config.basePath!;
116
-
117
- // Health check
118
- this.router.get(`${basePath}/health`, (c) => {
119
- return c.json({
120
- status: "healthy",
121
- timestamp: new Date().toISOString(),
122
- collections: this.config.collections?.map((col: EntityCollection) => col.slug) || [],
123
- driver: this.driver.key
124
- });
125
- });
126
-
127
- // Collections metadata endpoint
128
- this.router.get(`${basePath}/collections`, (c) => {
129
- const collectionsMetadata = (this.config.collections || []).map((col: EntityCollection) => ({
130
- slug: col.slug,
131
- name: col.name,
132
- singularName: col.singularName,
133
- description: col.description,
134
- properties: Object.keys(col.properties),
135
- relations: col.relations?.map((r: Relation) => ({
136
- relationName: r.relationName,
137
- target: typeof r.target === "function" ? r.target().slug : r.target,
138
- cardinality: r.cardinality,
139
- direction: r.direction
140
- })) || []
141
- }));
142
-
143
- return c.json({ data: collectionsMetadata });
144
- });
145
-
146
- // Server data routes are only generated for server-transport
147
- // collections; direct/custom sources are client-only.
148
- const dataSourceRegistry = createDataSourceRegistry(this.config.dataSources);
149
- const serverCollections = (this.config.collections || []).filter(
150
- (collection) => resolveDataSource(collection, dataSourceRegistry).transport === "server"
151
- );
152
-
153
- // GraphQL endpoint
154
- if (this.config.enableGraphQL) {
155
- const schemaGenerator = new GraphQLSchemaGenerator(serverCollections, this.driver);
156
- const schema = schemaGenerator.generateSchema();
157
-
158
- // Context is automatically passed to resolvers via contextValue containing Hono's 'c'
159
- this.router.use(`${basePath}/graphql`, graphqlServer({
160
- schema
161
- }));
162
-
163
- // Lightweight GraphiQL IDE
164
- if (process.env.NODE_ENV !== "production") {
165
- this.router.get(`${basePath}/graphiql`, (c) => {
166
- return c.html(`<!DOCTYPE html>
167
- <html>
168
- <head>
169
- <meta charset=utf-8/>
170
- <title>Rebase GraphiQL</title>
171
- <link rel="stylesheet" href="https://unpkg.com/graphiql/graphiql.min.css" />
172
- <style>body,html,#graphiql{height:100%;margin:0;width:100%;}</style>
173
- </head>
174
- <body>
175
- <div id="graphiql">Loading...</div>
176
- <script crossorigin src="https://unpkg.com/react/umd/react.production.min.js"></script>
177
- <script crossorigin src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
178
- <script src="https://unpkg.com/graphiql/graphiql.min.js"></script>
179
- <script>
180
- const fetcher = GraphiQL.createFetcher({ url: '${basePath}/graphql' });
181
- ReactDOM.render(
182
- React.createElement(GraphiQL, { fetcher }),
183
- document.getElementById('graphiql'),
184
- );
185
- </script>
186
- </body>
187
- </html>`);
188
- });
189
- }
190
- }
191
-
192
- if (this.config.enableREST) {
193
- const restGenerator = new RestApiGenerator(serverCollections, this.driver);
194
- const restRoutes = restGenerator.generateRoutes();
195
- this.router.route(basePath, restRoutes);
196
- }
197
-
198
- // Schema Editor endpoints
199
- if (this.config.collectionsDir) {
200
- if (process.env.NODE_ENV === "production") {
201
- logger.warn("[RebaseApiServer] Schema Editor is disabled in production environments for security.");
202
- } else {
203
- // Auth middlewares applied to schema-editor via the router prefix
204
- // MUST be declared before .route() so they execute first
205
- this.router.use(`${basePath}/schema-editor/*`, requireAuth, requireAdmin);
206
- const schemaEditorRoutes = createSchemaEditorRoutes(this.config.collectionsDir);
207
- this.router.route(`${basePath}/schema-editor`, schemaEditorRoutes);
208
- }
209
- }
210
-
211
- // OpenAPI endpoint
212
- this.router.get(`${basePath}/docs`, (c) => {
213
- const openApiSpec = generateOpenApiSpec(this.config.collections || [], {
214
- basePath: this.config.basePath,
215
- requireAuth: this.config.requireAuth ?? true
216
- });
217
- return c.json(openApiSpec);
218
- });
219
-
220
- // Simple Swagger UI
221
- if (process.env.NODE_ENV !== "production") {
222
- this.router.get(`${basePath}/swagger`, (c) => {
223
- return c.html(`
224
- <!DOCTYPE html>
225
- <html>
226
- <head>
227
- <title>Rebase API Documentation</title>
228
- <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui.css" />
229
- </head>
230
- <body>
231
- <div id="swagger-ui"></div>
232
- <script src="https://unpkg.com/swagger-ui-dist@4.15.5/swagger-ui-bundle.js"></script>
233
- <script>
234
- SwaggerUIBundle({
235
- url: '${basePath}/docs',
236
- dom_id: '#swagger-ui'
237
- });
238
- </script>
239
- </body>
240
- </html>
241
- `);
242
- });
243
- }
244
- }
245
-
246
- /**
247
- * Get the Hono router with all API routes
248
- */
249
- getRouter(): Hono<HonoEnv> {
250
- return this.router;
251
- }
252
-
253
- /**
254
- * Get the standalone Hono app
255
- */
256
- getApp(): Hono<HonoEnv> {
257
- return this.app;
258
- }
259
-
260
- /**
261
- * Start the server (standalone mode) via @hono/node-server
262
- */
263
- listen(port = 3000, callback?: () => void): void {
264
- serve({
265
- fetch: this.app.fetch,
266
- port
267
- }, () => {
268
- if (callback) callback();
269
- });
270
- }
271
- }