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

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 (176) hide show
  1. package/dist/common/src/collections/CollectionRegistry.d.ts +8 -0
  2. package/dist/common/src/util/entities.d.ts +22 -0
  3. package/dist/common/src/util/relations.d.ts +14 -4
  4. package/dist/common/src/util/resolutions.d.ts +1 -1
  5. package/dist/index-DXVBFp5V.js +37 -0
  6. package/dist/index-DXVBFp5V.js.map +1 -0
  7. package/dist/index.es.js +49931 -55
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/index.umd.js +28475 -34569
  10. package/dist/index.umd.js.map +1 -1
  11. package/dist/server-core/src/api/openapi-generator.d.ts +15 -1
  12. package/dist/server-core/src/api/types.d.ts +1 -1
  13. package/dist/server-core/src/auth/admin-routes.d.ts +10 -1
  14. package/dist/server-core/src/auth/apple-oauth.d.ts +30 -0
  15. package/dist/server-core/src/auth/bitbucket-oauth.d.ts +11 -0
  16. package/dist/server-core/src/auth/discord-oauth.d.ts +14 -0
  17. package/dist/server-core/src/auth/facebook-oauth.d.ts +14 -0
  18. package/dist/server-core/src/auth/github-oauth.d.ts +15 -0
  19. package/dist/server-core/src/auth/gitlab-oauth.d.ts +13 -0
  20. package/dist/server-core/src/auth/google-oauth.d.ts +5 -11
  21. package/dist/server-core/src/auth/index.d.ts +13 -2
  22. package/dist/server-core/src/auth/interfaces.d.ts +45 -6
  23. package/dist/server-core/src/auth/jwt.d.ts +1 -0
  24. package/dist/server-core/src/auth/linkedin-oauth.d.ts +18 -0
  25. package/dist/server-core/src/auth/microsoft-oauth.d.ts +16 -0
  26. package/dist/server-core/src/auth/middleware.d.ts +36 -11
  27. package/dist/server-core/src/auth/rate-limiter.d.ts +2 -2
  28. package/dist/server-core/src/auth/routes.d.ts +13 -3
  29. package/dist/server-core/src/auth/slack-oauth.d.ts +12 -0
  30. package/dist/server-core/src/auth/spotify-oauth.d.ts +12 -0
  31. package/dist/server-core/src/auth/twitter-oauth.d.ts +18 -0
  32. package/dist/server-core/src/cron/cron-loader.d.ts +17 -0
  33. package/dist/server-core/src/cron/cron-routes.d.ts +14 -0
  34. package/dist/server-core/src/cron/cron-scheduler.d.ts +61 -0
  35. package/dist/server-core/src/cron/cron-store.d.ts +32 -0
  36. package/dist/server-core/src/cron/index.d.ts +6 -0
  37. package/dist/server-core/src/email/index.d.ts +2 -2
  38. package/dist/server-core/src/email/templates.d.ts +9 -0
  39. package/dist/server-core/src/email/types.d.ts +20 -23
  40. package/dist/server-core/src/history/history-routes.d.ts +2 -2
  41. package/dist/server-core/src/index.d.ts +5 -0
  42. package/dist/server-core/src/init.d.ts +112 -2
  43. package/dist/server-core/src/singleton.d.ts +35 -0
  44. package/dist/server-core/src/storage/LocalStorageController.d.ts +9 -9
  45. package/dist/server-core/src/storage/S3StorageController.d.ts +8 -8
  46. package/dist/server-core/src/storage/index.d.ts +18 -11
  47. package/dist/server-core/src/storage/routes.d.ts +3 -3
  48. package/dist/server-core/src/storage/types.d.ts +28 -16
  49. package/dist/server-core/src/utils/dev-port.d.ts +35 -0
  50. package/dist/server-core/src/utils/logger.d.ts +31 -0
  51. package/dist/server-core/src/utils/request-logger.d.ts +19 -0
  52. package/dist/types/src/controllers/auth.d.ts +2 -0
  53. package/dist/types/src/controllers/client.d.ts +119 -7
  54. package/dist/types/src/controllers/collection_registry.d.ts +4 -3
  55. package/dist/types/src/controllers/customization_controller.d.ts +7 -1
  56. package/dist/types/src/controllers/data.d.ts +34 -7
  57. package/dist/types/src/controllers/data_driver.d.ts +20 -28
  58. package/dist/types/src/controllers/database_admin.d.ts +2 -2
  59. package/dist/types/src/controllers/email.d.ts +34 -0
  60. package/dist/types/src/controllers/index.d.ts +1 -0
  61. package/dist/types/src/controllers/local_config_persistence.d.ts +4 -4
  62. package/dist/types/src/controllers/navigation.d.ts +5 -5
  63. package/dist/types/src/controllers/registry.d.ts +6 -3
  64. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -6
  65. package/dist/types/src/controllers/storage.d.ts +24 -26
  66. package/dist/types/src/rebase_context.d.ts +8 -4
  67. package/dist/types/src/types/backend.d.ts +4 -1
  68. package/dist/types/src/types/builders.d.ts +5 -4
  69. package/dist/types/src/types/chips.d.ts +1 -1
  70. package/dist/types/src/types/collections.d.ts +169 -125
  71. package/dist/types/src/types/cron.d.ts +102 -0
  72. package/dist/types/src/types/data_source.d.ts +1 -1
  73. package/dist/types/src/types/entity_actions.d.ts +8 -8
  74. package/dist/types/src/types/entity_callbacks.d.ts +15 -15
  75. package/dist/types/src/types/entity_link_builder.d.ts +1 -1
  76. package/dist/types/src/types/entity_overrides.d.ts +2 -1
  77. package/dist/types/src/types/entity_views.d.ts +8 -8
  78. package/dist/types/src/types/export_import.d.ts +3 -3
  79. package/dist/types/src/types/index.d.ts +1 -0
  80. package/dist/types/src/types/plugins.d.ts +72 -18
  81. package/dist/types/src/types/properties.d.ts +118 -33
  82. package/dist/types/src/types/relations.d.ts +1 -1
  83. package/dist/types/src/types/slots.d.ts +30 -6
  84. package/dist/types/src/types/translations.d.ts +44 -0
  85. package/dist/types/src/types/user_management_delegate.d.ts +1 -0
  86. package/package.json +84 -84
  87. package/scratch.ts +6 -5
  88. package/src/api/ast-schema-editor.ts +11 -11
  89. package/src/api/collections_for_test/callbacks_test_collection.ts +5 -2
  90. package/src/api/errors.ts +38 -14
  91. package/src/api/graphql/graphql-schema-generator.ts +5 -3
  92. package/src/api/openapi-generator.ts +613 -58
  93. package/src/api/rest/api-generator.ts +17 -11
  94. package/src/api/rest/query-parser.ts +1 -1
  95. package/src/api/schema-editor-routes.ts +2 -0
  96. package/src/api/server.ts +8 -5
  97. package/src/api/types.ts +1 -1
  98. package/src/auth/admin-routes.ts +58 -17
  99. package/src/auth/apple-oauth.ts +130 -0
  100. package/src/auth/bitbucket-oauth.ts +82 -0
  101. package/src/auth/discord-oauth.ts +83 -0
  102. package/src/auth/facebook-oauth.ts +72 -0
  103. package/src/auth/github-oauth.ts +110 -0
  104. package/src/auth/gitlab-oauth.ts +70 -0
  105. package/src/auth/google-oauth.ts +34 -46
  106. package/src/auth/index.ts +15 -2
  107. package/src/auth/interfaces.ts +54 -7
  108. package/src/auth/jwt.ts +22 -5
  109. package/src/auth/linkedin-oauth.ts +81 -0
  110. package/src/auth/microsoft-oauth.ts +88 -0
  111. package/src/auth/middleware.ts +194 -45
  112. package/src/auth/password.ts +3 -1
  113. package/src/auth/rate-limiter.ts +4 -4
  114. package/src/auth/routes.ts +197 -139
  115. package/src/auth/slack-oauth.ts +71 -0
  116. package/src/auth/spotify-oauth.ts +67 -0
  117. package/src/auth/twitter-oauth.ts +120 -0
  118. package/src/collections/loader.ts +6 -6
  119. package/src/cron/cron-loader.ts +89 -0
  120. package/src/cron/cron-routes.test.ts +265 -0
  121. package/src/cron/cron-routes.ts +85 -0
  122. package/src/cron/cron-scheduler.test.ts +421 -0
  123. package/src/cron/cron-scheduler.ts +413 -0
  124. package/src/cron/cron-store.ts +163 -0
  125. package/src/cron/index.ts +6 -0
  126. package/src/db/interfaces.ts +2 -2
  127. package/src/email/index.ts +3 -2
  128. package/src/email/smtp-email-service.ts +5 -2
  129. package/src/email/templates.ts +93 -6
  130. package/src/email/types.ts +17 -24
  131. package/src/functions/function-loader.ts +34 -6
  132. package/src/functions/function-routes.ts +2 -2
  133. package/src/history/history-routes.ts +4 -3
  134. package/src/index.ts +10 -0
  135. package/src/init.ts +475 -57
  136. package/src/services/driver-registry.ts +1 -1
  137. package/src/singleton.test.ts +28 -0
  138. package/src/singleton.ts +70 -0
  139. package/src/storage/LocalStorageController.ts +50 -53
  140. package/src/storage/S3StorageController.ts +49 -46
  141. package/src/storage/index.ts +27 -16
  142. package/src/storage/routes.ts +76 -59
  143. package/src/storage/storage-registry.ts +5 -5
  144. package/src/storage/types.ts +44 -32
  145. package/src/types/index.ts +4 -4
  146. package/src/utils/dev-port.ts +176 -0
  147. package/src/utils/logger.ts +143 -0
  148. package/src/utils/logging.ts +5 -2
  149. package/src/utils/request-logger.ts +66 -0
  150. package/test/admin-routes.test.ts +114 -65
  151. package/test/api-generator.test.ts +73 -30
  152. package/test/ast-schema-editor.test.ts +5 -3
  153. package/test/auth-middleware-hono.test.ts +268 -33
  154. package/test/auth-routes.test.ts +325 -146
  155. package/test/driver-registry.test.ts +4 -2
  156. package/test/error-propagation.test.ts +226 -0
  157. package/test/errors.test.ts +12 -7
  158. package/test/jwt-security.test.ts +18 -9
  159. package/test/jwt.test.ts +26 -13
  160. package/test/middleware.test.ts +13 -8
  161. package/test/query-parser.test.ts +13 -8
  162. package/test/rate-limiter.test.ts +7 -7
  163. package/test/safe-compare.test.ts +66 -0
  164. package/test/singleton.test.ts +59 -0
  165. package/test/storage-local.test.ts +36 -43
  166. package/test/storage-registry.test.ts +38 -36
  167. package/test/storage-routes.test.ts +9 -5
  168. package/test/storage-s3.test.ts +51 -48
  169. package/test.ts +6 -0
  170. package/tsconfig.json +1 -1
  171. package/vite.config.ts +7 -5
  172. package/dist/index-BeMqpmfQ.js +0 -239
  173. package/dist/index-BeMqpmfQ.js.map +0 -1
  174. package/dist/index-bl4J3lNb.js +0 -55823
  175. package/dist/index-bl4J3lNb.js.map +0 -1
  176. package/vite.config.ts.timestamp-1775065397568-8a853255edf6e.mjs +0 -46
@@ -44,6 +44,8 @@ export interface RebaseTranslations {
44
44
  clear_filter: string;
45
45
  clear_filter_sort: string;
46
46
  clear_sort: string;
47
+ /** Reset all active filters */
48
+ clear_all: string;
47
49
  no_items: string;
48
50
  no_entries_found: string;
49
51
  all_entries_loaded: string;
@@ -124,6 +126,20 @@ export interface RebaseTranslations {
124
126
  /** Shown in unsaved-changes dialogs */
125
127
  are_you_sure_leave: string;
126
128
  passkey_error_unsupported: string;
129
+ /** Snackbar message after a successful save */
130
+ saved_correctly: string;
131
+ /** Snackbar title when a beforeSave callback throws */
132
+ error_before_saving: string;
133
+ /** Snackbar title when an afterSave callback throws */
134
+ error_after_saving: string;
135
+ /** Snackbar title when the save itself fails */
136
+ error_saving_entity: string;
137
+ /** Alert shown when the entity does not exist in the database */
138
+ entity_does_not_exist: string;
139
+ /** Tooltip when the form has unsaved modifications */
140
+ form_modified: string;
141
+ /** Tooltip when the form is in sync with the database */
142
+ form_in_sync: string;
127
143
  admin: string;
128
144
  home: string;
129
145
  this_form_has_errors: string;
@@ -267,6 +283,8 @@ export interface RebaseTranslations {
267
283
  any_of_these: string;
268
284
  only_admins_edit_roles: string;
269
285
  error_user_not_found: string;
286
+ /** Placeholder / label for the "all roles" filter option */
287
+ all_roles: string;
270
288
  role: string;
271
289
  name_of_this_role: string;
272
290
  id_of_this_role: string;
@@ -373,6 +391,7 @@ export interface RebaseTranslations {
373
391
  no_filterable_properties: string;
374
392
  apply_filters: string;
375
393
  list: string;
394
+ table_view_mode: string;
376
395
  cards: string;
377
396
  board: string;
378
397
  initialize_kanban_order_desc: string;
@@ -380,6 +399,7 @@ export interface RebaseTranslations {
380
399
  kanban_view_requires_enum: string;
381
400
  no_enum_values_configured: string;
382
401
  items_need_backfill: string;
402
+ kanban_order_not_configured: string;
383
403
  initialize: string;
384
404
  confirm_multiple_delete: string;
385
405
  delete_entity_confirm_title: string;
@@ -823,4 +843,28 @@ export interface RebaseTranslations {
823
843
  studio_kanban_configure?: string;
824
844
  studio_missing_reference_error?: string;
825
845
  studio_new_collection_add?: string;
846
+ db_column_type?: string;
847
+ primary_key_unique_id?: string;
848
+ spread_children_as_columns?: string;
849
+ mode?: string;
850
+ timezone?: string;
851
+ target_collection?: string;
852
+ storage_file_name?: string;
853
+ storage_path?: string;
854
+ storage_max_size?: string;
855
+ storage_resize_mode?: string;
856
+ storage_output_format?: string;
857
+ storage_max_width?: string;
858
+ storage_max_height?: string;
859
+ storage_quality?: string;
860
+ storage_file_upload_config?: string;
861
+ storage_image_resize_config?: string;
862
+ storage_all_file_types?: string;
863
+ storage_allowed_file_types?: string;
864
+ storage_include_bucket_url?: string;
865
+ storage_save_url?: string;
866
+ datetime_automatic_value?: string;
867
+ markdown_paste_behavior?: string;
868
+ markdown_strip_html?: string;
869
+ markdown_convert_pasted?: string;
826
870
  }
@@ -51,6 +51,7 @@ export interface UserManagementDelegate<USER extends User = User> {
51
51
  offset?: number;
52
52
  orderBy?: string;
53
53
  orderDir?: "asc" | "desc";
54
+ roleId?: string;
54
55
  }) => Promise<{
55
56
  users: USER[];
56
57
  total: number;
package/package.json CHANGED
@@ -1,86 +1,86 @@
1
1
  {
2
- "name": "@rebasepro/server-core",
3
- "type": "module",
4
- "version": "0.0.1-canary.4d4fb3e",
5
- "description": "Database-Agnostic Backend Core for Rebase",
6
- "funding": {
7
- "url": "https://github.com/sponsors/rebaseco"
2
+ "name": "@rebasepro/server-core",
3
+ "type": "module",
4
+ "version": "0.0.1-canary.ca2cb6e",
5
+ "description": "Database-Agnostic Backend Core for Rebase",
6
+ "funding": {
7
+ "url": "https://github.com/sponsors/rebaseco"
8
+ },
9
+ "author": "Rebase",
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/rebasepro/rebase.git",
14
+ "directory": "packages/backend"
15
+ },
16
+ "main": "./dist/index.umd.js",
17
+ "module": "./dist/index.es.js",
18
+ "types": "./dist/server-core/src/index.d.ts",
19
+ "source": "src/index.ts",
20
+ "engines": {
21
+ "node": ">=14"
22
+ },
23
+ "keywords": [
24
+ "rebase",
25
+ "cms",
26
+ "admin",
27
+ "admin panel",
28
+ "postgresql",
29
+ "drizzle",
30
+ "backend",
31
+ "database"
32
+ ],
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/server-core/src/index.d.ts",
36
+ "development": "./src/index.ts",
37
+ "import": "./dist/index.es.js",
38
+ "require": "./dist/index.umd.js"
8
39
  },
9
- "author": "Rebase",
10
- "license": "MIT",
11
- "repository": {
12
- "type": "git",
13
- "url": "https://github.com/rebasepro/rebase.git",
14
- "directory": "packages/backend"
15
- },
16
- "main": "./dist/index.umd.js",
17
- "module": "./dist/index.es.js",
18
- "types": "./dist/server-core/src/index.d.ts",
19
- "source": "src/index.ts",
20
- "engines": {
21
- "node": ">=14"
22
- },
23
- "keywords": [
24
- "firebase",
25
- "cms",
26
- "admin",
27
- "admin panel",
28
- "postgresql",
29
- "drizzle",
30
- "backend",
31
- "database",
32
- "rebase"
33
- ],
34
- "scripts": {
35
- "watch": "vite build --watch",
36
- "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
37
- "prepublishOnly": "pnpm run build",
38
- "test:lint": "eslint \"src/**\" --quiet",
39
- "test": "jest --passWithNoTests",
40
- "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
41
- },
42
- "exports": {
43
- ".": {
44
- "types": "./dist/server-core/src/index.d.ts",
45
- "development": "./src/index.ts",
46
- "import": "./dist/index.es.js",
47
- "require": "./dist/index.umd.js"
48
- },
49
- "./package.json": "./package.json"
50
- },
51
- "dependencies": {
52
- "@aws-sdk/client-s3": "^3.654.0",
53
- "@aws-sdk/s3-request-presigner": "^3.654.0",
54
- "@hono/graphql-server": "0.7.0",
55
- "@hono/node-server": "1.19.12",
56
- "@rebasepro/common": "0.0.1-canary.4d4fb3e",
57
- "@rebasepro/types": "0.0.1-canary.4d4fb3e",
58
- "@rebasepro/utils": "0.0.1-canary.4d4fb3e",
59
- "google-auth-library": "^9.0.0",
60
- "graphql": "^16.8.1",
61
- "hono": "4.12.10",
62
- "jsonwebtoken": "^9.0.0",
63
- "nodemailer": "^6.9.0",
64
- "ws": "^8.16.0",
65
- "zod": "^3.22.4"
66
- },
67
- "devDependencies": {
68
- "@rebasepro/common": "workspace:*",
69
- "@rebasepro/types": "workspace:*",
70
- "@types/jest": "^29.5.14",
71
- "@types/jsonwebtoken": "^9.0.0",
72
- "@types/node": "^20.10.5",
73
- "@types/nodemailer": "^6.4.0",
74
- "@types/react": "^19.0.8",
75
- "@types/react-dom": "^19.0.3",
76
- "@types/ws": "^8.5.10",
77
- "jest": "^29.7.0",
78
- "ts-jest": "29.4.1",
79
- "typescript": "^5.0.0",
80
- "vite": "^5.0.0"
81
- },
82
- "gitHead": "71bcef3c51a458cd054f7924cc18efbbe515dcc8",
83
- "publishConfig": {
84
- "access": "public"
85
- }
86
- }
40
+ "./package.json": "./package.json"
41
+ },
42
+ "dependencies": {
43
+ "@aws-sdk/client-s3": "^3.654.0",
44
+ "@aws-sdk/s3-request-presigner": "^3.654.0",
45
+ "@hono/graphql-server": "0.7.0",
46
+ "@hono/node-server": "1.19.12",
47
+ "google-auth-library": "^9.0.0",
48
+ "graphql": "^16.8.1",
49
+ "hono": "4.12.10",
50
+ "jose": "^6.1.3",
51
+ "jsonwebtoken": "^9.0.0",
52
+ "nodemailer": "^6.9.0",
53
+ "ws": "^8.16.0",
54
+ "zod": "^3.22.4",
55
+ "@rebasepro/client": "0.0.1-canary.ca2cb6e",
56
+ "@rebasepro/common": "0.0.1-canary.ca2cb6e",
57
+ "@rebasepro/utils": "0.0.1-canary.ca2cb6e",
58
+ "@rebasepro/types": "0.0.1-canary.ca2cb6e"
59
+ },
60
+ "devDependencies": {
61
+ "@types/jest": "^29.5.14",
62
+ "@types/jsonwebtoken": "^9.0.0",
63
+ "@types/node": "^20.10.5",
64
+ "@types/nodemailer": "^6.4.0",
65
+ "@types/react": "^19.0.8",
66
+ "@types/react-dom": "^19.0.3",
67
+ "@types/ws": "^8.5.10",
68
+ "jest": "^29.7.0",
69
+ "ts-jest": "29.4.1",
70
+ "typescript": "^5.0.0",
71
+ "vite": "^5.0.0",
72
+ "@rebasepro/types": "0.0.1-canary.ca2cb6e",
73
+ "@rebasepro/common": "0.0.1-canary.ca2cb6e"
74
+ },
75
+ "gitHead": "d935eefa5aa8d1009a2398cfac2c1e4ee9aeb6b6",
76
+ "publishConfig": {
77
+ "access": "public"
78
+ },
79
+ "scripts": {
80
+ "watch": "vite build --watch",
81
+ "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
82
+ "test:lint": "eslint \"src/**\" --quiet",
83
+ "test": "jest --passWithNoTests",
84
+ "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
85
+ }
86
+ }
package/scratch.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { Hono } from 'hono';
1
+ import { Hono } from "hono";
2
2
  const app = new Hono();
3
3
  const child = new Hono();
4
- child.get('/*', (c) => {
5
- return c.json({ star: c.req.param('*'), path: c.req.path });
4
+ child.get("/*", (c) => {
5
+ return c.json({ star: c.req.param("*"),
6
+ path: c.req.path });
6
7
  })
7
- app.route('/api', child);
8
- app.request(new Request('http://localhost/api/users/1/posts')).then(r => r.json()).then(console.log);
8
+ app.route("/api", child);
9
+ app.request(new Request("http://localhost/api/users/1/posts")).then(r => r.json()).then(console.log);
@@ -9,7 +9,7 @@ export class AstSchemaEditor {
9
9
  constructor(collectionsDir: string) {
10
10
  this.project = new Project({
11
11
  manipulationSettings: {
12
- indentationText: IndentationText.FourSpaces,
12
+ indentationText: IndentationText.FourSpaces
13
13
  }
14
14
  });
15
15
  if (fs.existsSync(collectionsDir)) {
@@ -77,8 +77,8 @@ export class AstSchemaEditor {
77
77
  return null;
78
78
  }
79
79
 
80
- private convertJsonToAstString(obj: unknown, indentLevel: number = 0, oldAstNode?: ObjectLiteralExpression): string {
81
- // Base TS-morph parses arrays as 2 levels deep from the property key:
80
+ private convertJsonToAstString(obj: unknown, indentLevel = 0, oldAstNode?: ObjectLiteralExpression): string {
81
+ // Base TS-morph parses arrays as 2 levels deep from the property key:
82
82
  // PropertiesObject = level 1, PropertyConfig = level 2.
83
83
  // We calibrate the spacing multiples to keep the items flush with standard TS format.
84
84
  const indentStr = " ";
@@ -145,7 +145,7 @@ export class AstSchemaEditor {
145
145
  let childAstNode: ObjectLiteralExpression | undefined;
146
146
  if (oldAstNode && typeof record[key] === "object" && record[key] !== null && !Array.isArray(record[key])) {
147
147
  const oldProp = oldAstNode.getProperty(
148
- (p: ObjectLiteralElementLike) => 'getName' in p && typeof (p as PropertyAssignment).getName === 'function' && ((p as PropertyAssignment).getName() === key || (p as PropertyAssignment).getName() === `"${key}"` || (p as PropertyAssignment).getName() === `'${key}'`)
148
+ (p: ObjectLiteralElementLike) => "getName" in p && typeof (p as PropertyAssignment).getName === "function" && ((p as PropertyAssignment).getName() === key || (p as PropertyAssignment).getName() === `"${key}"` || (p as PropertyAssignment).getName() === `'${key}'`)
149
149
  );
150
150
  if (oldProp && oldProp.isKind(SyntaxKind.PropertyAssignment)) {
151
151
  childAstNode = oldProp.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
@@ -175,8 +175,8 @@ export class AstSchemaEditor {
175
175
 
176
176
  const propsObj = propertiesProp.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
177
177
  if (propsObj) {
178
- let existingProp = propsObj.getProperty(
179
- (p: ObjectLiteralElementLike) => 'getName' in p && typeof (p as PropertyAssignment).getName === 'function' && ((p as PropertyAssignment).getName() === propertyKey || (p as PropertyAssignment).getName() === `"${propertyKey}"`)
178
+ const existingProp = propsObj.getProperty(
179
+ (p: ObjectLiteralElementLike) => "getName" in p && typeof (p as PropertyAssignment).getName === "function" && ((p as PropertyAssignment).getName() === propertyKey || (p as PropertyAssignment).getName() === `"${propertyKey}"`)
180
180
  );
181
181
 
182
182
  let oldPropAstNode: ObjectLiteralExpression | undefined;
@@ -214,7 +214,7 @@ export class AstSchemaEditor {
214
214
  const propsObj = propertiesProp.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
215
215
  if (propsObj) {
216
216
  const existingProp = propsObj.getProperty(
217
- (p: ObjectLiteralElementLike) => 'getName' in p && typeof (p as PropertyAssignment).getName === 'function' && ((p as PropertyAssignment).getName() === propertyKey || (p as PropertyAssignment).getName() === `"${propertyKey}"`)
217
+ (p: ObjectLiteralElementLike) => "getName" in p && typeof (p as PropertyAssignment).getName === "function" && ((p as PropertyAssignment).getName() === propertyKey || (p as PropertyAssignment).getName() === `"${propertyKey}"`)
218
218
  );
219
219
  if (existingProp) {
220
220
  existingProp.remove();
@@ -230,7 +230,7 @@ export class AstSchemaEditor {
230
230
 
231
231
  public async saveCollection(collectionId: string, collectionData: Record<string, unknown>) {
232
232
  let file = this.getCollectionFile(collectionId);
233
- let collectionObj = this.getCollectionObject(collectionId);
233
+ const collectionObj = this.getCollectionObject(collectionId);
234
234
 
235
235
  if (!file || !collectionObj) {
236
236
  // Create a new file
@@ -239,14 +239,14 @@ export class AstSchemaEditor {
239
239
  file = this.project.createSourceFile(newFilePath, `import { EntityCollection } from "@rebasepro/types";\n\nconst ${safeId}Collection: EntityCollection = ${this.convertJsonToAstString(collectionData)};\n\nexport default ${safeId}Collection;\n`, { overwrite: true });
240
240
  } else {
241
241
  // Update root level properties gracefully
242
-
242
+
243
243
  // Force delete securityRules if empty or undefined to handle Formex / serialization stripping
244
244
  if (!("securityRules" in collectionData) || collectionData.securityRules === undefined || (Array.isArray(collectionData.securityRules) && collectionData.securityRules.length === 0)) {
245
245
  const srProp = collectionObj.getProperty("securityRules");
246
246
  if (srProp) {
247
247
  srProp.remove();
248
248
  }
249
-
249
+
250
250
  // If it was in collectionData as an empty array, delete it so the loop below doesn't add it back as "[]"
251
251
  // Actually, if it's "[]", omitting it entirely from the TS file achieves the same logical effect (no RLS rules)
252
252
  // and correctly triggers "unmapped policies" if the DB still has them.
@@ -256,7 +256,7 @@ export class AstSchemaEditor {
256
256
  for (const key of Object.keys(collectionData)) {
257
257
  if (key === "relations") continue; // Kept via other AST functions or handled separately.
258
258
 
259
- let prop = collectionObj.getProperty(key) as PropertyAssignment;
259
+ const prop = collectionObj.getProperty(key) as PropertyAssignment;
260
260
 
261
261
  let oldAstNode: ObjectLiteralExpression | undefined;
262
262
  if (prop && prop.isKind(SyntaxKind.PropertyAssignment)) {
@@ -43,8 +43,11 @@ export const callbacksTestCollection: PostgresCollection = {
43
43
  afterRead: (props: EntityAfterReadProps) => {
44
44
  console.log("🔥 [BACKEND_CALLBACK] afterRead Triggered!", props);
45
45
  return {
46
- ...props.entity.values,
47
- hasFetchTriggered: true
46
+ ...props.entity,
47
+ values: {
48
+ ...props.entity.values,
49
+ hasFetchTriggered: true
50
+ }
48
51
  };
49
52
  },
50
53
  beforeDelete: (props: EntityBeforeDeleteProps) => {
package/src/api/errors.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  import { ErrorHandler } from "hono";
2
2
  import { ContentfulStatusCode } from "hono/utils/http-status";
3
3
 
4
+ /** Shape of Postgres / network errors with diagnostic codes */
5
+ interface PgLikeError {
6
+ code?: string;
7
+ address?: string;
8
+ port?: number;
9
+ message?: string;
10
+ }
11
+
4
12
  /**
5
13
  * Standardized API error class.
6
14
  * Throw this from any route handler — the errorHandler middleware
@@ -68,9 +76,9 @@ export interface ErrorResponse {
68
76
  */
69
77
  export const errorHandler: ErrorHandler = (err, c) => {
70
78
  // Typecast custom error properties
71
- const error = err as Error & { statusCode?: number; code?: string; details?: unknown };
79
+ const error = err as Error & { statusCode?: number; code?: string; details?: unknown, name?: string };
72
80
 
73
- if (error instanceof ApiError) {
81
+ if (error instanceof ApiError || error.name === "ApiError") {
74
82
  // Operational errors — log at warn level
75
83
  console.warn(
76
84
  `⚠️ [API] ${c.req.method} ${c.req.path} → ${error.statusCode} ${error.code}: ${error.message}`
@@ -78,7 +86,7 @@ export const errorHandler: ErrorHandler = (err, c) => {
78
86
  return c.json({
79
87
  error: {
80
88
  message: error.message,
81
- code: error.code,
89
+ code: error.code || "INTERNAL_ERROR",
82
90
  ...(error.details !== undefined && { details: error.details })
83
91
  }
84
92
  } satisfies ErrorResponse, (error.statusCode || 500) as ContentfulStatusCode);
@@ -89,22 +97,35 @@ export const errorHandler: ErrorHandler = (err, c) => {
89
97
 
90
98
  // Handle DB connection and specific system errors for better logging
91
99
  let logMessage = error.message;
92
- if (error.cause && typeof error.cause === 'object' && 'code' in error.cause) {
93
- const cause = error.cause as any;
94
- if (cause.code === 'ENETUNREACH') {
100
+ if (error.cause && typeof error.cause === "object" && error.cause !== null && "code" in error.cause) {
101
+ const cause = error.cause as PgLikeError;
102
+ if (cause.code === "ENETUNREACH") {
95
103
  logMessage = `Network unreachable. Cannot connect to database at ${cause.address}:${cause.port}.`;
96
- } else if (cause.code === 'ECONNREFUSED') {
104
+ } else if (cause.code === "ECONNREFUSED") {
97
105
  logMessage = `Connection refused to database at ${cause.address}:${cause.port}.`;
106
+ } else if (cause.code === "42703" || cause.code === "42P01") {
107
+ const issue = cause.code === "42703" ? "column" : "table";
108
+ logMessage = `Database schema mismatch (${issue} missing): ${cause.message}. Did you forget to run migrations ('pnpm db:push' or 'pnpm db:migrate')?`;
98
109
  }
99
- } else if ('code' in error && error.code === 'ENETUNREACH') {
100
- logMessage = `Network unreachable. Cannot connect to service at ${(error as any).address}:${(error as any).port}.`;
110
+ } else if ("code" in error && error.code === "ENETUNREACH") {
111
+ const netErr = error as unknown as PgLikeError;
112
+ logMessage = `Network unreachable. Cannot connect to service at ${netErr.address}:${netErr.port}.`;
113
+ } else if ("code" in error && (error.code === "42703" || error.code === "42P01")) {
114
+ const issue = error.code === "42703" ? "column" : "table";
115
+ logMessage = `Database schema mismatch (${issue} missing): ${error.message}. Did you forget to run migrations ('pnpm db:push' or 'pnpm db:migrate')?`;
101
116
  }
102
117
 
103
- // Unexpected errors — log at error level with full stack
118
+ // Unexpected errors — log at error level
104
119
  console.error(
105
120
  `❌ [API] ${c.req.method} ${c.req.path} → ${statusCode} ${code}: ${logMessage}`
106
121
  );
107
- console.error(error.stack || error);
122
+
123
+ // Suppress the huge stack trace for known missing schema errors (it's noisy and not a code bug)
124
+ const causePg = (error.cause && typeof error.cause === "object") ? (error.cause as PgLikeError) : undefined;
125
+ const pgErrorCode = causePg?.code || error.code;
126
+ if (pgErrorCode !== "42703" && pgErrorCode !== "42P01") {
127
+ console.error(error.stack || error);
128
+ }
108
129
 
109
130
  // Sanitize the message for the client to prevent leaking sensitive details
110
131
  // like SQL queries or internal IP addresses.
@@ -112,10 +133,13 @@ export const errorHandler: ErrorHandler = (err, c) => {
112
133
  if (statusCode < 500 && error.message) {
113
134
  // If it's a 4xx error (e.g. from validation), it's generally safe to send the message
114
135
  clientMessage = error.message;
115
- } else if (error instanceof ApiError) {
136
+ } else if (error instanceof ApiError || error.name === "ApiError") {
116
137
  // We already handled ApiError above, but just in case
117
138
  clientMessage = error.message;
118
- } else if (code === 'INTERNAL_ERROR') {
139
+ } else if (pgErrorCode === "42703" || pgErrorCode === "42P01") {
140
+ const issue = pgErrorCode === "42703" ? "column" : "table";
141
+ clientMessage = `Database schema mismatch (${issue} missing). Ensure backend migrations are up to date!`;
142
+ } else if (code === "INTERNAL_ERROR") {
119
143
  clientMessage = "Internal Server Error";
120
144
  }
121
145
 
@@ -147,7 +171,7 @@ function codeToStatus(code?: string): number | undefined {
147
171
  ROLE_EXISTS: 409,
148
172
  INTERNAL_ERROR: 500,
149
173
  NOT_CONFIGURED: 503,
150
- SERVICE_UNAVAILABLE: 503,
174
+ SERVICE_UNAVAILABLE: 503
151
175
  };
152
176
  return map[code];
153
177
  }
@@ -43,7 +43,7 @@ export class GraphQLSchemaGenerator {
43
43
 
44
44
  return new GraphQLSchema({
45
45
  query: queryType,
46
- mutation: mutationType,
46
+ mutation: mutationType
47
47
  });
48
48
  }
49
49
 
@@ -192,8 +192,10 @@ export class GraphQLSchemaGenerator {
192
192
  fields[this.getListQueryName(collection)] = {
193
193
  type: new GraphQLList(entityType),
194
194
  args: {
195
- limit: { type: GraphQLInt, defaultValue: 20 },
196
- offset: { type: GraphQLInt, defaultValue: 0 },
195
+ limit: { type: GraphQLInt,
196
+ defaultValue: 20 },
197
+ offset: { type: GraphQLInt,
198
+ defaultValue: 0 },
197
199
  where: { type: GraphQLString },
198
200
  orderBy: { type: GraphQLString }
199
201
  },