@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.
- package/dist/common/src/collections/CollectionRegistry.d.ts +8 -0
- package/dist/common/src/util/entities.d.ts +22 -0
- package/dist/common/src/util/relations.d.ts +14 -4
- package/dist/common/src/util/resolutions.d.ts +1 -1
- package/dist/index-DXVBFp5V.js +37 -0
- package/dist/index-DXVBFp5V.js.map +1 -0
- package/dist/index.es.js +49931 -55
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +28475 -34569
- package/dist/index.umd.js.map +1 -1
- package/dist/server-core/src/api/openapi-generator.d.ts +15 -1
- package/dist/server-core/src/api/types.d.ts +1 -1
- package/dist/server-core/src/auth/admin-routes.d.ts +10 -1
- package/dist/server-core/src/auth/apple-oauth.d.ts +30 -0
- package/dist/server-core/src/auth/bitbucket-oauth.d.ts +11 -0
- package/dist/server-core/src/auth/discord-oauth.d.ts +14 -0
- package/dist/server-core/src/auth/facebook-oauth.d.ts +14 -0
- package/dist/server-core/src/auth/github-oauth.d.ts +15 -0
- package/dist/server-core/src/auth/gitlab-oauth.d.ts +13 -0
- package/dist/server-core/src/auth/google-oauth.d.ts +5 -11
- package/dist/server-core/src/auth/index.d.ts +13 -2
- package/dist/server-core/src/auth/interfaces.d.ts +45 -6
- package/dist/server-core/src/auth/jwt.d.ts +1 -0
- package/dist/server-core/src/auth/linkedin-oauth.d.ts +18 -0
- package/dist/server-core/src/auth/microsoft-oauth.d.ts +16 -0
- package/dist/server-core/src/auth/middleware.d.ts +36 -11
- package/dist/server-core/src/auth/rate-limiter.d.ts +2 -2
- package/dist/server-core/src/auth/routes.d.ts +13 -3
- package/dist/server-core/src/auth/slack-oauth.d.ts +12 -0
- package/dist/server-core/src/auth/spotify-oauth.d.ts +12 -0
- package/dist/server-core/src/auth/twitter-oauth.d.ts +18 -0
- package/dist/server-core/src/cron/cron-loader.d.ts +17 -0
- package/dist/server-core/src/cron/cron-routes.d.ts +14 -0
- package/dist/server-core/src/cron/cron-scheduler.d.ts +61 -0
- package/dist/server-core/src/cron/cron-store.d.ts +32 -0
- package/dist/server-core/src/cron/index.d.ts +6 -0
- package/dist/server-core/src/email/index.d.ts +2 -2
- package/dist/server-core/src/email/templates.d.ts +9 -0
- package/dist/server-core/src/email/types.d.ts +20 -23
- package/dist/server-core/src/history/history-routes.d.ts +2 -2
- package/dist/server-core/src/index.d.ts +5 -0
- package/dist/server-core/src/init.d.ts +112 -2
- package/dist/server-core/src/singleton.d.ts +35 -0
- package/dist/server-core/src/storage/LocalStorageController.d.ts +9 -9
- package/dist/server-core/src/storage/S3StorageController.d.ts +8 -8
- package/dist/server-core/src/storage/index.d.ts +18 -11
- package/dist/server-core/src/storage/routes.d.ts +3 -3
- package/dist/server-core/src/storage/types.d.ts +28 -16
- package/dist/server-core/src/utils/dev-port.d.ts +35 -0
- package/dist/server-core/src/utils/logger.d.ts +31 -0
- package/dist/server-core/src/utils/request-logger.d.ts +19 -0
- package/dist/types/src/controllers/auth.d.ts +2 -0
- package/dist/types/src/controllers/client.d.ts +119 -7
- package/dist/types/src/controllers/collection_registry.d.ts +4 -3
- package/dist/types/src/controllers/customization_controller.d.ts +7 -1
- package/dist/types/src/controllers/data.d.ts +34 -7
- package/dist/types/src/controllers/data_driver.d.ts +20 -28
- package/dist/types/src/controllers/database_admin.d.ts +2 -2
- package/dist/types/src/controllers/email.d.ts +34 -0
- package/dist/types/src/controllers/index.d.ts +1 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +4 -4
- package/dist/types/src/controllers/navigation.d.ts +5 -5
- package/dist/types/src/controllers/registry.d.ts +6 -3
- package/dist/types/src/controllers/side_entity_controller.d.ts +7 -6
- package/dist/types/src/controllers/storage.d.ts +24 -26
- package/dist/types/src/rebase_context.d.ts +8 -4
- package/dist/types/src/types/backend.d.ts +4 -1
- package/dist/types/src/types/builders.d.ts +5 -4
- package/dist/types/src/types/chips.d.ts +1 -1
- package/dist/types/src/types/collections.d.ts +169 -125
- package/dist/types/src/types/cron.d.ts +102 -0
- package/dist/types/src/types/data_source.d.ts +1 -1
- package/dist/types/src/types/entity_actions.d.ts +8 -8
- package/dist/types/src/types/entity_callbacks.d.ts +15 -15
- package/dist/types/src/types/entity_link_builder.d.ts +1 -1
- package/dist/types/src/types/entity_overrides.d.ts +2 -1
- package/dist/types/src/types/entity_views.d.ts +8 -8
- package/dist/types/src/types/export_import.d.ts +3 -3
- package/dist/types/src/types/index.d.ts +1 -0
- package/dist/types/src/types/plugins.d.ts +72 -18
- package/dist/types/src/types/properties.d.ts +118 -33
- package/dist/types/src/types/relations.d.ts +1 -1
- package/dist/types/src/types/slots.d.ts +30 -6
- package/dist/types/src/types/translations.d.ts +44 -0
- package/dist/types/src/types/user_management_delegate.d.ts +1 -0
- package/package.json +84 -84
- package/scratch.ts +6 -5
- package/src/api/ast-schema-editor.ts +11 -11
- package/src/api/collections_for_test/callbacks_test_collection.ts +5 -2
- package/src/api/errors.ts +38 -14
- package/src/api/graphql/graphql-schema-generator.ts +5 -3
- package/src/api/openapi-generator.ts +613 -58
- package/src/api/rest/api-generator.ts +17 -11
- package/src/api/rest/query-parser.ts +1 -1
- package/src/api/schema-editor-routes.ts +2 -0
- package/src/api/server.ts +8 -5
- package/src/api/types.ts +1 -1
- package/src/auth/admin-routes.ts +58 -17
- package/src/auth/apple-oauth.ts +130 -0
- package/src/auth/bitbucket-oauth.ts +82 -0
- package/src/auth/discord-oauth.ts +83 -0
- package/src/auth/facebook-oauth.ts +72 -0
- package/src/auth/github-oauth.ts +110 -0
- package/src/auth/gitlab-oauth.ts +70 -0
- package/src/auth/google-oauth.ts +34 -46
- package/src/auth/index.ts +15 -2
- package/src/auth/interfaces.ts +54 -7
- package/src/auth/jwt.ts +22 -5
- package/src/auth/linkedin-oauth.ts +81 -0
- package/src/auth/microsoft-oauth.ts +88 -0
- package/src/auth/middleware.ts +194 -45
- package/src/auth/password.ts +3 -1
- package/src/auth/rate-limiter.ts +4 -4
- package/src/auth/routes.ts +197 -139
- package/src/auth/slack-oauth.ts +71 -0
- package/src/auth/spotify-oauth.ts +67 -0
- package/src/auth/twitter-oauth.ts +120 -0
- package/src/collections/loader.ts +6 -6
- package/src/cron/cron-loader.ts +89 -0
- package/src/cron/cron-routes.test.ts +265 -0
- package/src/cron/cron-routes.ts +85 -0
- package/src/cron/cron-scheduler.test.ts +421 -0
- package/src/cron/cron-scheduler.ts +413 -0
- package/src/cron/cron-store.ts +163 -0
- package/src/cron/index.ts +6 -0
- package/src/db/interfaces.ts +2 -2
- package/src/email/index.ts +3 -2
- package/src/email/smtp-email-service.ts +5 -2
- package/src/email/templates.ts +93 -6
- package/src/email/types.ts +17 -24
- package/src/functions/function-loader.ts +34 -6
- package/src/functions/function-routes.ts +2 -2
- package/src/history/history-routes.ts +4 -3
- package/src/index.ts +10 -0
- package/src/init.ts +475 -57
- package/src/services/driver-registry.ts +1 -1
- package/src/singleton.test.ts +28 -0
- package/src/singleton.ts +70 -0
- package/src/storage/LocalStorageController.ts +50 -53
- package/src/storage/S3StorageController.ts +49 -46
- package/src/storage/index.ts +27 -16
- package/src/storage/routes.ts +76 -59
- package/src/storage/storage-registry.ts +5 -5
- package/src/storage/types.ts +44 -32
- package/src/types/index.ts +4 -4
- package/src/utils/dev-port.ts +176 -0
- package/src/utils/logger.ts +143 -0
- package/src/utils/logging.ts +5 -2
- package/src/utils/request-logger.ts +66 -0
- package/test/admin-routes.test.ts +114 -65
- package/test/api-generator.test.ts +73 -30
- package/test/ast-schema-editor.test.ts +5 -3
- package/test/auth-middleware-hono.test.ts +268 -33
- package/test/auth-routes.test.ts +325 -146
- package/test/driver-registry.test.ts +4 -2
- package/test/error-propagation.test.ts +226 -0
- package/test/errors.test.ts +12 -7
- package/test/jwt-security.test.ts +18 -9
- package/test/jwt.test.ts +26 -13
- package/test/middleware.test.ts +13 -8
- package/test/query-parser.test.ts +13 -8
- package/test/rate-limiter.test.ts +7 -7
- package/test/safe-compare.test.ts +66 -0
- package/test/singleton.test.ts +59 -0
- package/test/storage-local.test.ts +36 -43
- package/test/storage-registry.test.ts +38 -36
- package/test/storage-routes.test.ts +9 -5
- package/test/storage-s3.test.ts +51 -48
- package/test.ts +6 -0
- package/tsconfig.json +1 -1
- package/vite.config.ts +7 -5
- package/dist/index-BeMqpmfQ.js +0 -239
- package/dist/index-BeMqpmfQ.js.map +0 -1
- package/dist/index-bl4J3lNb.js +0 -55823
- package/dist/index-bl4J3lNb.js.map +0 -1
- 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
|
}
|
package/package.json
CHANGED
|
@@ -1,86 +1,86 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
1
|
+
import { Hono } from "hono";
|
|
2
2
|
const app = new Hono();
|
|
3
3
|
const child = new Hono();
|
|
4
|
-
child.get(
|
|
5
|
-
return c.json({ star: c.req.param(
|
|
4
|
+
child.get("/*", (c) => {
|
|
5
|
+
return c.json({ star: c.req.param("*"),
|
|
6
|
+
path: c.req.path });
|
|
6
7
|
})
|
|
7
|
-
app.route(
|
|
8
|
-
app.request(new Request(
|
|
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
|
|
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) =>
|
|
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
|
-
|
|
179
|
-
(p: ObjectLiteralElementLike) =>
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
47
|
-
|
|
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 ===
|
|
93
|
-
const cause = error.cause as
|
|
94
|
-
if (cause.code ===
|
|
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 ===
|
|
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 (
|
|
100
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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,
|
|
196
|
-
|
|
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
|
},
|