@rebasepro/server-core 0.0.1-canary.4d4fb3e

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 (254) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +40 -0
  3. package/build-errors.txt +52 -0
  4. package/coverage/clover.xml +3739 -0
  5. package/coverage/coverage-final.json +31 -0
  6. package/coverage/lcov-report/base.css +224 -0
  7. package/coverage/lcov-report/block-navigation.js +87 -0
  8. package/coverage/lcov-report/favicon.png +0 -0
  9. package/coverage/lcov-report/index.html +266 -0
  10. package/coverage/lcov-report/prettify.css +1 -0
  11. package/coverage/lcov-report/prettify.js +2 -0
  12. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  13. package/coverage/lcov-report/sorter.js +210 -0
  14. package/coverage/lcov-report/src/api/ast-schema-editor.ts.html +952 -0
  15. package/coverage/lcov-report/src/api/errors.ts.html +472 -0
  16. package/coverage/lcov-report/src/api/graphql/graphql-schema-generator.ts.html +1069 -0
  17. package/coverage/lcov-report/src/api/graphql/index.html +116 -0
  18. package/coverage/lcov-report/src/api/index.html +176 -0
  19. package/coverage/lcov-report/src/api/openapi-generator.ts.html +565 -0
  20. package/coverage/lcov-report/src/api/rest/api-generator.ts.html +994 -0
  21. package/coverage/lcov-report/src/api/rest/index.html +131 -0
  22. package/coverage/lcov-report/src/api/rest/query-parser.ts.html +550 -0
  23. package/coverage/lcov-report/src/api/schema-editor-routes.ts.html +202 -0
  24. package/coverage/lcov-report/src/api/server.ts.html +823 -0
  25. package/coverage/lcov-report/src/auth/admin-routes.ts.html +973 -0
  26. package/coverage/lcov-report/src/auth/index.html +176 -0
  27. package/coverage/lcov-report/src/auth/jwt.ts.html +574 -0
  28. package/coverage/lcov-report/src/auth/middleware.ts.html +745 -0
  29. package/coverage/lcov-report/src/auth/password.ts.html +310 -0
  30. package/coverage/lcov-report/src/auth/services.ts.html +2074 -0
  31. package/coverage/lcov-report/src/collections/index.html +116 -0
  32. package/coverage/lcov-report/src/collections/loader.ts.html +232 -0
  33. package/coverage/lcov-report/src/db/auth-schema.ts.html +523 -0
  34. package/coverage/lcov-report/src/db/data-transformer.ts.html +1753 -0
  35. package/coverage/lcov-report/src/db/entityService.ts.html +700 -0
  36. package/coverage/lcov-report/src/db/index.html +146 -0
  37. package/coverage/lcov-report/src/db/services/EntityFetchService.ts.html +4048 -0
  38. package/coverage/lcov-report/src/db/services/EntityPersistService.ts.html +883 -0
  39. package/coverage/lcov-report/src/db/services/RelationService.ts.html +3121 -0
  40. package/coverage/lcov-report/src/db/services/entity-helpers.ts.html +442 -0
  41. package/coverage/lcov-report/src/db/services/index.html +176 -0
  42. package/coverage/lcov-report/src/db/services/index.ts.html +124 -0
  43. package/coverage/lcov-report/src/generate-drizzle-schema-logic.ts.html +1960 -0
  44. package/coverage/lcov-report/src/index.html +116 -0
  45. package/coverage/lcov-report/src/services/driver-registry.ts.html +631 -0
  46. package/coverage/lcov-report/src/services/index.html +131 -0
  47. package/coverage/lcov-report/src/services/postgresDataDriver.ts.html +3025 -0
  48. package/coverage/lcov-report/src/storage/LocalStorageController.ts.html +1189 -0
  49. package/coverage/lcov-report/src/storage/S3StorageController.ts.html +970 -0
  50. package/coverage/lcov-report/src/storage/index.html +161 -0
  51. package/coverage/lcov-report/src/storage/storage-registry.ts.html +646 -0
  52. package/coverage/lcov-report/src/storage/types.ts.html +451 -0
  53. package/coverage/lcov-report/src/utils/drizzle-conditions.ts.html +3082 -0
  54. package/coverage/lcov-report/src/utils/index.html +116 -0
  55. package/coverage/lcov.info +7179 -0
  56. package/dist/common/src/collections/CollectionRegistry.d.ts +48 -0
  57. package/dist/common/src/collections/index.d.ts +1 -0
  58. package/dist/common/src/data/buildRebaseData.d.ts +14 -0
  59. package/dist/common/src/index.d.ts +3 -0
  60. package/dist/common/src/util/builders.d.ts +57 -0
  61. package/dist/common/src/util/callbacks.d.ts +6 -0
  62. package/dist/common/src/util/collections.d.ts +11 -0
  63. package/dist/common/src/util/common.d.ts +2 -0
  64. package/dist/common/src/util/conditions.d.ts +26 -0
  65. package/dist/common/src/util/entities.d.ts +36 -0
  66. package/dist/common/src/util/enums.d.ts +3 -0
  67. package/dist/common/src/util/index.d.ts +16 -0
  68. package/dist/common/src/util/navigation_from_path.d.ts +34 -0
  69. package/dist/common/src/util/navigation_utils.d.ts +20 -0
  70. package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
  71. package/dist/common/src/util/paths.d.ts +14 -0
  72. package/dist/common/src/util/permissions.d.ts +5 -0
  73. package/dist/common/src/util/references.d.ts +2 -0
  74. package/dist/common/src/util/relations.d.ts +12 -0
  75. package/dist/common/src/util/resolutions.d.ts +72 -0
  76. package/dist/common/src/util/storage.d.ts +24 -0
  77. package/dist/index-BeMqpmfQ.js +239 -0
  78. package/dist/index-BeMqpmfQ.js.map +1 -0
  79. package/dist/index-bl4J3lNb.js +55823 -0
  80. package/dist/index-bl4J3lNb.js.map +1 -0
  81. package/dist/index.es.js +58 -0
  82. package/dist/index.es.js.map +1 -0
  83. package/dist/index.umd.js +56062 -0
  84. package/dist/index.umd.js.map +1 -0
  85. package/dist/server-core/src/api/ast-schema-editor.d.ts +21 -0
  86. package/dist/server-core/src/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
  87. package/dist/server-core/src/api/errors.d.ts +35 -0
  88. package/dist/server-core/src/api/graphql/graphql-schema-generator.d.ts +35 -0
  89. package/dist/server-core/src/api/graphql/index.d.ts +1 -0
  90. package/dist/server-core/src/api/index.d.ts +9 -0
  91. package/dist/server-core/src/api/openapi-generator.d.ts +2 -0
  92. package/dist/server-core/src/api/rest/api-generator.d.ts +64 -0
  93. package/dist/server-core/src/api/rest/index.d.ts +1 -0
  94. package/dist/server-core/src/api/rest/query-parser.d.ts +9 -0
  95. package/dist/server-core/src/api/schema-editor-routes.d.ts +3 -0
  96. package/dist/server-core/src/api/server.d.ts +40 -0
  97. package/dist/server-core/src/api/types.d.ts +90 -0
  98. package/dist/server-core/src/auth/admin-routes.d.ts +7 -0
  99. package/dist/server-core/src/auth/google-oauth.d.ts +20 -0
  100. package/dist/server-core/src/auth/index.d.ts +12 -0
  101. package/dist/server-core/src/auth/interfaces.d.ts +270 -0
  102. package/dist/server-core/src/auth/jwt.d.ts +42 -0
  103. package/dist/server-core/src/auth/middleware.d.ts +56 -0
  104. package/dist/server-core/src/auth/password.d.ts +22 -0
  105. package/dist/server-core/src/auth/rate-limiter.d.ts +31 -0
  106. package/dist/server-core/src/auth/routes.d.ts +17 -0
  107. package/dist/server-core/src/bootstrappers/index.d.ts +0 -0
  108. package/dist/server-core/src/collections/BackendCollectionRegistry.d.ts +13 -0
  109. package/dist/server-core/src/collections/loader.d.ts +5 -0
  110. package/dist/server-core/src/db/interfaces.d.ts +18 -0
  111. package/dist/server-core/src/email/index.d.ts +6 -0
  112. package/dist/server-core/src/email/smtp-email-service.d.ts +25 -0
  113. package/dist/server-core/src/email/templates.d.ts +33 -0
  114. package/dist/server-core/src/email/types.d.ts +110 -0
  115. package/dist/server-core/src/functions/function-loader.d.ts +17 -0
  116. package/dist/server-core/src/functions/function-routes.d.ts +10 -0
  117. package/dist/server-core/src/functions/index.d.ts +3 -0
  118. package/dist/server-core/src/history/history-routes.d.ts +23 -0
  119. package/dist/server-core/src/history/index.d.ts +1 -0
  120. package/dist/server-core/src/index.d.ts +24 -0
  121. package/dist/server-core/src/init.d.ts +49 -0
  122. package/dist/server-core/src/serve-spa.d.ts +30 -0
  123. package/dist/server-core/src/services/driver-registry.d.ts +78 -0
  124. package/dist/server-core/src/storage/LocalStorageController.d.ts +46 -0
  125. package/dist/server-core/src/storage/S3StorageController.d.ts +36 -0
  126. package/dist/server-core/src/storage/index.d.ts +18 -0
  127. package/dist/server-core/src/storage/routes.d.ts +38 -0
  128. package/dist/server-core/src/storage/storage-registry.d.ts +78 -0
  129. package/dist/server-core/src/storage/types.d.ts +91 -0
  130. package/dist/server-core/src/types/index.d.ts +11 -0
  131. package/dist/server-core/src/utils/logging.d.ts +9 -0
  132. package/dist/server-core/src/utils/sql.d.ts +27 -0
  133. package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
  134. package/dist/types/src/controllers/auth.d.ts +117 -0
  135. package/dist/types/src/controllers/client.d.ts +58 -0
  136. package/dist/types/src/controllers/collection_registry.d.ts +44 -0
  137. package/dist/types/src/controllers/customization_controller.d.ts +54 -0
  138. package/dist/types/src/controllers/data.d.ts +141 -0
  139. package/dist/types/src/controllers/data_driver.d.ts +168 -0
  140. package/dist/types/src/controllers/database_admin.d.ts +11 -0
  141. package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
  142. package/dist/types/src/controllers/effective_role.d.ts +4 -0
  143. package/dist/types/src/controllers/index.d.ts +17 -0
  144. package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
  145. package/dist/types/src/controllers/navigation.d.ts +213 -0
  146. package/dist/types/src/controllers/registry.d.ts +51 -0
  147. package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
  148. package/dist/types/src/controllers/side_entity_controller.d.ts +89 -0
  149. package/dist/types/src/controllers/snackbar.d.ts +24 -0
  150. package/dist/types/src/controllers/storage.d.ts +173 -0
  151. package/dist/types/src/index.d.ts +4 -0
  152. package/dist/types/src/rebase_context.d.ts +101 -0
  153. package/dist/types/src/types/backend.d.ts +533 -0
  154. package/dist/types/src/types/builders.d.ts +14 -0
  155. package/dist/types/src/types/chips.d.ts +5 -0
  156. package/dist/types/src/types/collections.d.ts +812 -0
  157. package/dist/types/src/types/data_source.d.ts +64 -0
  158. package/dist/types/src/types/entities.d.ts +145 -0
  159. package/dist/types/src/types/entity_actions.d.ts +98 -0
  160. package/dist/types/src/types/entity_callbacks.d.ts +173 -0
  161. package/dist/types/src/types/entity_link_builder.d.ts +7 -0
  162. package/dist/types/src/types/entity_overrides.d.ts +9 -0
  163. package/dist/types/src/types/entity_views.d.ts +61 -0
  164. package/dist/types/src/types/export_import.d.ts +21 -0
  165. package/dist/types/src/types/index.d.ts +22 -0
  166. package/dist/types/src/types/locales.d.ts +4 -0
  167. package/dist/types/src/types/modify_collections.d.ts +5 -0
  168. package/dist/types/src/types/plugins.d.ts +225 -0
  169. package/dist/types/src/types/properties.d.ts +1091 -0
  170. package/dist/types/src/types/property_config.d.ts +70 -0
  171. package/dist/types/src/types/relations.d.ts +336 -0
  172. package/dist/types/src/types/slots.d.ts +228 -0
  173. package/dist/types/src/types/translations.d.ts +826 -0
  174. package/dist/types/src/types/user_management_delegate.d.ts +120 -0
  175. package/dist/types/src/types/websockets.d.ts +78 -0
  176. package/dist/types/src/users/index.d.ts +2 -0
  177. package/dist/types/src/users/roles.d.ts +22 -0
  178. package/dist/types/src/users/user.d.ts +46 -0
  179. package/history_diff.log +385 -0
  180. package/jest.config.cjs +16 -0
  181. package/package.json +86 -0
  182. package/scratch.ts +8 -0
  183. package/src/api/ast-schema-editor.ts +289 -0
  184. package/src/api/collections_for_test/callbacks_test_collection.ts +57 -0
  185. package/src/api/errors.ts +155 -0
  186. package/src/api/graphql/graphql-schema-generator.ts +334 -0
  187. package/src/api/graphql/index.ts +2 -0
  188. package/src/api/index.ts +11 -0
  189. package/src/api/openapi-generator.ts +160 -0
  190. package/src/api/rest/api-generator.ts +466 -0
  191. package/src/api/rest/index.ts +2 -0
  192. package/src/api/rest/query-parser.ts +155 -0
  193. package/src/api/schema-editor-routes.ts +39 -0
  194. package/src/api/server.ts +245 -0
  195. package/src/api/types.ts +90 -0
  196. package/src/auth/admin-routes.ts +488 -0
  197. package/src/auth/google-oauth.ts +60 -0
  198. package/src/auth/index.ts +21 -0
  199. package/src/auth/interfaces.ts +316 -0
  200. package/src/auth/jwt.ts +164 -0
  201. package/src/auth/middleware.ts +235 -0
  202. package/src/auth/password.ts +75 -0
  203. package/src/auth/rate-limiter.ts +129 -0
  204. package/src/auth/routes.ts +730 -0
  205. package/src/bootstrappers/index.ts +1 -0
  206. package/src/collections/BackendCollectionRegistry.ts +20 -0
  207. package/src/collections/loader.ts +49 -0
  208. package/src/db/interfaces.ts +60 -0
  209. package/src/email/index.ts +17 -0
  210. package/src/email/smtp-email-service.ts +88 -0
  211. package/src/email/templates.ts +301 -0
  212. package/src/email/types.ts +112 -0
  213. package/src/functions/function-loader.ts +91 -0
  214. package/src/functions/function-routes.ts +31 -0
  215. package/src/functions/index.ts +3 -0
  216. package/src/history/history-routes.ts +128 -0
  217. package/src/history/index.ts +2 -0
  218. package/src/index.ts +56 -0
  219. package/src/init.ts +309 -0
  220. package/src/serve-spa.ts +81 -0
  221. package/src/services/driver-registry.ts +182 -0
  222. package/src/storage/LocalStorageController.ts +368 -0
  223. package/src/storage/S3StorageController.ts +295 -0
  224. package/src/storage/index.ts +32 -0
  225. package/src/storage/routes.ts +247 -0
  226. package/src/storage/storage-registry.ts +187 -0
  227. package/src/storage/types.ts +122 -0
  228. package/src/types/index.ts +27 -0
  229. package/src/utils/logging.ts +35 -0
  230. package/src/utils/sql.ts +38 -0
  231. package/test/admin-routes.test.ts +591 -0
  232. package/test/api-generator.test.ts +458 -0
  233. package/test/ast-schema-editor.test.ts +61 -0
  234. package/test/auth-middleware-hono.test.ts +321 -0
  235. package/test/auth-routes.test.ts +868 -0
  236. package/test/driver-registry.test.ts +280 -0
  237. package/test/errors-hono.test.ts +133 -0
  238. package/test/errors.test.ts +150 -0
  239. package/test/jwt-security.test.ts +173 -0
  240. package/test/jwt.test.ts +311 -0
  241. package/test/middleware.test.ts +295 -0
  242. package/test/password.test.ts +165 -0
  243. package/test/query-parser.test.ts +258 -0
  244. package/test/rate-limiter.test.ts +102 -0
  245. package/test/storage-local.test.ts +278 -0
  246. package/test/storage-registry.test.ts +280 -0
  247. package/test/storage-routes.test.ts +218 -0
  248. package/test/storage-s3.test.ts +301 -0
  249. package/test-ast.ts +28 -0
  250. package/test_output.txt +1133 -0
  251. package/tsconfig.json +49 -0
  252. package/tsconfig.prod.json +20 -0
  253. package/vite.config.ts +78 -0
  254. package/vite.config.ts.timestamp-1775065397568-8a853255edf6e.mjs +46 -0
@@ -0,0 +1,334 @@
1
+ import {
2
+ GraphQLSchema,
3
+ GraphQLObjectType,
4
+ GraphQLString,
5
+ GraphQLInt,
6
+ GraphQLFloat,
7
+ GraphQLBoolean,
8
+ GraphQLList,
9
+ GraphQLNonNull,
10
+ GraphQLFieldConfig,
11
+ GraphQLInputObjectType,
12
+ GraphQLInputFieldConfig
13
+ } from "graphql";
14
+ import { DataDriver, EntityCollection, FetchCollectionProps, Property, Entity } from "@rebasepro/types";
15
+
16
+ /**
17
+ * Lightweight GraphQL schema generator that leverages existing DataDriver
18
+ * No duplication - uses your existing data layer and services
19
+ */
20
+ export class GraphQLSchemaGenerator {
21
+ private collections: EntityCollection[];
22
+ private driver: DataDriver;
23
+ private typeRegistry = new Map<string, GraphQLObjectType>();
24
+ private inputTypeRegistry = new Map<string, GraphQLInputObjectType>();
25
+
26
+ constructor(collections: EntityCollection[], driver: DataDriver) {
27
+ this.collections = collections;
28
+ this.driver = driver;
29
+ }
30
+
31
+ /**
32
+ * Generate complete GraphQL schema using existing DataDriver
33
+ */
34
+ generateSchema(): GraphQLSchema {
35
+ // Create all types first
36
+ this.collections.forEach(collection => {
37
+ this.createEntityType(collection);
38
+ this.createInputType(collection);
39
+ });
40
+
41
+ const queryType = this.createQueryType();
42
+ const mutationType = this.createMutationType();
43
+
44
+ return new GraphQLSchema({
45
+ query: queryType,
46
+ mutation: mutationType,
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Create GraphQL type for an entity collection
52
+ */
53
+ private createEntityType(collection: EntityCollection): GraphQLObjectType {
54
+ const typeName = this.getTypeName(collection);
55
+
56
+ if (this.typeRegistry.has(typeName)) {
57
+ return this.typeRegistry.get(typeName)!;
58
+ }
59
+
60
+ const fields: Record<string, GraphQLFieldConfig<unknown, unknown>> = {};
61
+
62
+ // Add ID field
63
+ fields.id = {
64
+ type: new GraphQLNonNull(GraphQLString),
65
+ description: "Unique identifier",
66
+ resolve: (source: unknown) => (source as Entity<Record<string, unknown>>).id
67
+ };
68
+
69
+ // Convert properties to GraphQL fields
70
+ Object.entries(collection.properties).forEach(([key, property]) => {
71
+ if (property.type !== "relation" && key !== "id") {
72
+ const fieldConfig = this.convertPropertyToField(property);
73
+ fieldConfig.resolve = (source: unknown) => (source as Entity<Record<string, unknown>>).values?.[key];
74
+ fields[key] = fieldConfig;
75
+ }
76
+ });
77
+
78
+ const entityType = new GraphQLObjectType({
79
+ name: typeName,
80
+ description: collection.description || `${collection.singularName} entity`,
81
+ fields: () => fields
82
+ });
83
+
84
+ this.typeRegistry.set(typeName, entityType);
85
+ return entityType;
86
+ }
87
+
88
+ private convertPropertyToField(property: Property): GraphQLFieldConfig<unknown, unknown> {
89
+ let type;
90
+
91
+ switch (property.type) {
92
+ case "string":
93
+ type = GraphQLString;
94
+ break;
95
+ case "number":
96
+ type = GraphQLFloat;
97
+ break;
98
+ case "boolean":
99
+ type = GraphQLBoolean;
100
+ break;
101
+ case "date":
102
+ type = GraphQLString;
103
+ break;
104
+ case "array":
105
+ type = new GraphQLList(GraphQLString);
106
+ break;
107
+ default:
108
+ type = GraphQLString;
109
+ }
110
+
111
+ return {
112
+ type: property.validation?.required ? new GraphQLNonNull(type) : type,
113
+ description: property.name || property.description
114
+ };
115
+ }
116
+
117
+ private createInputType(collection: EntityCollection): GraphQLInputObjectType {
118
+ const typeName = `${this.getTypeName(collection)}Input`;
119
+
120
+ if (this.inputTypeRegistry.has(typeName)) {
121
+ return this.inputTypeRegistry.get(typeName)!;
122
+ }
123
+
124
+ const fields: Record<string, GraphQLInputFieldConfig> = {};
125
+
126
+ Object.entries(collection.properties).forEach(([key, property]) => {
127
+ if (property.type !== "relation") {
128
+ fields[key] = {
129
+ type: this.convertPropertyToInputType(property)
130
+ };
131
+ }
132
+ });
133
+
134
+ const inputType = new GraphQLInputObjectType({
135
+ name: typeName,
136
+ description: `Input for creating/updating ${collection.singularName}`,
137
+ fields
138
+ });
139
+
140
+ this.inputTypeRegistry.set(typeName, inputType);
141
+ return inputType;
142
+ }
143
+
144
+ private convertPropertyToInputType(property: Property) {
145
+ switch (property.type) {
146
+ case "string":
147
+ return GraphQLString;
148
+ case "number":
149
+ return GraphQLFloat;
150
+ case "boolean":
151
+ return GraphQLBoolean;
152
+ case "date":
153
+ return GraphQLString;
154
+ case "array":
155
+ return new GraphQLList(GraphQLString);
156
+ default:
157
+ return GraphQLString;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Create Query type using existing DataDriver methods
163
+ */
164
+ private createQueryType(): GraphQLObjectType {
165
+ const fields: Record<string, GraphQLFieldConfig<unknown, unknown>> = {};
166
+
167
+ this.collections.forEach(collection => {
168
+ const typeName = this.getTypeName(collection);
169
+ const entityType = this.typeRegistry.get(typeName);
170
+
171
+ if (!entityType) return;
172
+
173
+ // Single entity query - uses existing fetchEntity
174
+ fields[this.getSingleQueryName(collection)] = {
175
+ type: entityType,
176
+ args: {
177
+ id: { type: new GraphQLNonNull(GraphQLString) }
178
+ },
179
+ resolve: async (_, args, context: unknown) => {
180
+ const ctx = context as { driver: DataDriver };
181
+ const ds = ctx.driver || this.driver;
182
+ const entity = await ds.fetchEntity({
183
+ path: collection.slug,
184
+ entityId: args.id,
185
+ collection
186
+ });
187
+ return entity;
188
+ }
189
+ };
190
+
191
+ // List query - uses existing fetchCollection
192
+ fields[this.getListQueryName(collection)] = {
193
+ type: new GraphQLList(entityType),
194
+ args: {
195
+ limit: { type: GraphQLInt, defaultValue: 20 },
196
+ offset: { type: GraphQLInt, defaultValue: 0 },
197
+ where: { type: GraphQLString },
198
+ orderBy: { type: GraphQLString }
199
+ },
200
+ resolve: async (_, args, context: unknown) => {
201
+ const ctx = context as { driver: DataDriver };
202
+ const ds = ctx.driver || this.driver;
203
+ let filter: FetchCollectionProps["filter"] | undefined;
204
+ if (args.where) {
205
+ try {
206
+ const parsed = JSON.parse(args.where);
207
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
208
+ throw new Error("Filter must be a JSON object");
209
+ }
210
+ filter = parsed;
211
+ } catch (e) {
212
+ throw new Error(`Invalid 'where' filter: ${e instanceof Error ? e.message : "malformed JSON"}`);
213
+ }
214
+ }
215
+ const entities = await ds.fetchCollection({
216
+ path: collection.slug,
217
+ collection,
218
+ filter,
219
+ limit: args.limit,
220
+ startAfter: args.offset ? String(args.offset) : undefined
221
+ });
222
+ return entities;
223
+ }
224
+ };
225
+ });
226
+
227
+ return new GraphQLObjectType({
228
+ name: "Query",
229
+ fields
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Create Mutation type using existing DataDriver methods
235
+ */
236
+ private createMutationType(): GraphQLObjectType {
237
+ const fields: Record<string, GraphQLFieldConfig<unknown, unknown>> = {};
238
+
239
+ this.collections.forEach(collection => {
240
+ const typeName = this.getTypeName(collection);
241
+ const entityType = this.typeRegistry.get(typeName);
242
+ const inputType = this.inputTypeRegistry.get(`${typeName}Input`);
243
+
244
+ if (!entityType || !inputType) return;
245
+
246
+ // Create mutation - uses existing saveEntity
247
+ fields[`create${typeName}`] = {
248
+ type: entityType,
249
+ args: {
250
+ input: { type: new GraphQLNonNull(inputType) }
251
+ },
252
+ resolve: async (_, args, context: unknown) => {
253
+ const ctx = context as { driver: DataDriver };
254
+ const ds = ctx.driver || this.driver;
255
+ const path = collection.slug;
256
+ const entity = await ds.saveEntity({
257
+ path,
258
+ values: args.input,
259
+ collection,
260
+ status: "new"
261
+ });
262
+ return entity;
263
+ }
264
+ };
265
+
266
+ // Update mutation - uses existing saveEntity
267
+ fields[`update${typeName}`] = {
268
+ type: entityType,
269
+ args: {
270
+ id: { type: new GraphQLNonNull(GraphQLString) },
271
+ input: { type: new GraphQLNonNull(inputType) }
272
+ },
273
+ resolve: async (_, args, context: unknown) => {
274
+ const ctx = context as { driver: DataDriver };
275
+ const ds = ctx.driver || this.driver;
276
+ const entity = await ds.saveEntity({
277
+ path: collection.slug,
278
+ entityId: args.id,
279
+ values: args.input,
280
+ collection,
281
+ status: "existing"
282
+ });
283
+ return entity;
284
+ }
285
+ };
286
+
287
+ // Delete mutation - uses existing deleteEntity
288
+ fields[`delete${typeName}`] = {
289
+ type: GraphQLBoolean,
290
+ args: {
291
+ id: { type: new GraphQLNonNull(GraphQLString) }
292
+ },
293
+ resolve: async (_, args, context: unknown) => {
294
+ try {
295
+ const ctx = context as { driver: DataDriver };
296
+ const ds = ctx.driver || this.driver;
297
+ const existingEntity = await ds.fetchEntity({
298
+ path: collection.slug,
299
+ entityId: args.id,
300
+ collection
301
+ });
302
+ if (!existingEntity) return false;
303
+ await ds.deleteEntity({
304
+ entity: existingEntity,
305
+ collection
306
+ });
307
+ return true;
308
+ } catch {
309
+ return false;
310
+ }
311
+ }
312
+ };
313
+ });
314
+
315
+ return new GraphQLObjectType({
316
+ name: "Mutation",
317
+ fields
318
+ });
319
+ }
320
+
321
+ // Helper methods
322
+ private getTypeName(collection: EntityCollection): string {
323
+ return collection.singularName?.replace(/\s+/g, "") ||
324
+ collection.name.slice(0, -1).replace(/\s+/g, "");
325
+ }
326
+
327
+ private getSingleQueryName(collection: EntityCollection): string {
328
+ return this.getTypeName(collection).toLowerCase();
329
+ }
330
+
331
+ private getListQueryName(collection: EntityCollection): string {
332
+ return collection.slug;
333
+ }
334
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./graphql-schema-generator";
2
+
@@ -0,0 +1,11 @@
1
+ /**
2
+ * API generation infrastructure for Rebase
3
+ * Automatically generates GraphQL and REST APIs from EntityCollection definitions
4
+ */
5
+
6
+ export * from "./graphql";
7
+ export * from "./rest";
8
+
9
+ export * from "./types";
10
+ export * from "./errors";
11
+ export * from "./server";
@@ -0,0 +1,160 @@
1
+ import { EntityCollection, Property } from "@rebasepro/types";
2
+
3
+ export function generateOpenApiSpec(collections: EntityCollection[], basePath: string = "/api"): Record<string, unknown> {
4
+ const spec = {
5
+ openapi: "3.0.0",
6
+ info: {
7
+ title: "Rebase Auto-Generated API",
8
+ version: "1.0.0",
9
+ description: "Automatically generated REST API from Rebase collections"
10
+ },
11
+ servers: [
12
+ {
13
+ url: basePath,
14
+ description: "API Server"
15
+ }
16
+ ],
17
+ paths: {} as Record<string, unknown>,
18
+ components: {
19
+ schemas: {} as Record<string, unknown>
20
+ }
21
+ };
22
+
23
+ (collections || []).forEach(collection => {
24
+ const schemaName = collection.singularName || collection.name;
25
+ spec.components.schemas[schemaName] = {
26
+ type: "object",
27
+ properties: {
28
+ id: { type: "string" },
29
+ ...Object.entries(collection.properties).reduce((props, [key, property]) => {
30
+ if (property.type !== "relation") {
31
+ props[key] = convertPropertyToOpenApiType(property);
32
+ }
33
+ return props;
34
+ }, {} as Record<string, unknown>)
35
+ }
36
+ };
37
+
38
+ const collectionPath = `/${collection.slug}`;
39
+
40
+ spec.paths[collectionPath] = {
41
+ get: {
42
+ summary: `List ${collection.name}`,
43
+ parameters: [
44
+ { name: "limit", in: "query", schema: { type: "integer", default: 20 } },
45
+ { name: "offset", in: "query", schema: { type: "integer", default: 0 } },
46
+ { name: "where", in: "query", schema: { type: "string" } },
47
+ { name: "orderBy", in: "query", schema: { type: "string" } }
48
+ ],
49
+ responses: {
50
+ 200: {
51
+ description: "Success",
52
+ content: {
53
+ "application/json": {
54
+ schema: {
55
+ type: "object",
56
+ properties: {
57
+ data: {
58
+ type: "array",
59
+ items: { $ref: `#/components/schemas/${schemaName}` }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ },
68
+ post: {
69
+ summary: `Create ${schemaName}`,
70
+ requestBody: {
71
+ content: {
72
+ "application/json": {
73
+ schema: { $ref: `#/components/schemas/${schemaName}` }
74
+ }
75
+ }
76
+ },
77
+ responses: {
78
+ 201: {
79
+ description: "Created",
80
+ content: {
81
+ "application/json": {
82
+ schema: { $ref: `#/components/schemas/${schemaName}` }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
88
+ };
89
+
90
+ spec.paths[`${collectionPath}/{id}`] = {
91
+ get: {
92
+ summary: `Get ${schemaName} by ID`,
93
+ parameters: [
94
+ { name: "id", in: "path", required: true, schema: { type: "string" } }
95
+ ],
96
+ responses: {
97
+ 200: {
98
+ description: "Success",
99
+ content: {
100
+ "application/json": {
101
+ schema: { $ref: `#/components/schemas/${schemaName}` }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ },
107
+ put: {
108
+ summary: `Update ${schemaName}`,
109
+ parameters: [
110
+ { name: "id", in: "path", required: true, schema: { type: "string" } }
111
+ ],
112
+ requestBody: {
113
+ content: {
114
+ "application/json": {
115
+ schema: { $ref: `#/components/schemas/${schemaName}` }
116
+ }
117
+ }
118
+ },
119
+ responses: {
120
+ 200: {
121
+ description: "Updated",
122
+ content: {
123
+ "application/json": {
124
+ schema: { $ref: `#/components/schemas/${schemaName}` }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ },
130
+ delete: {
131
+ summary: `Delete ${schemaName}`,
132
+ parameters: [
133
+ { name: "id", in: "path", required: true, schema: { type: "string" } }
134
+ ],
135
+ responses: {
136
+ 204: { description: "Deleted" }
137
+ }
138
+ }
139
+ };
140
+ });
141
+
142
+ return spec;
143
+ }
144
+
145
+ function convertPropertyToOpenApiType(property: Property): Record<string, unknown> {
146
+ switch (property.type) {
147
+ case "string":
148
+ return { type: "string" };
149
+ case "number":
150
+ return { type: "number" };
151
+ case "boolean":
152
+ return { type: "boolean" };
153
+ case "date":
154
+ return { type: "string", format: "date-time" };
155
+ case "array":
156
+ return { type: "array", items: { type: "string" } };
157
+ default:
158
+ return { type: "string" };
159
+ }
160
+ }