json-rest-api 1.0.22 → 1.0.23
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/CLAUDE.md +1 -2
- package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +180 -0
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
- package/docs/API.md +51 -14
- package/docs/COMPARISON.md +2 -2
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +28 -1
- package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +5 -1
- package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +3 -1
- package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +12 -60
- package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +2 -2
- package/docs/GUIDE/GUIDE_3_Field_Transformations.md +5 -1
- package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +2 -0
- package/docs/GUIDE/GUIDE_X_Autofiltering.md +355 -0
- package/docs/GUIDE/GUIDE_X_Fastify.md +78 -0
- package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +250 -0
- package/docs/GUIDE/GUIDE_X_Query_Projections.md +159 -0
- package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +199 -0
- package/docs/GUIDE/index.md +18 -9
- package/docs/QUICKSTART.md +5 -1
- package/docs/index.md +1 -1
- package/index.js +3 -2
- package/package.json +2 -2
- package/plugins/core/connectors/express-plugin.js +97 -184
- package/plugins/core/connectors/fastify-plugin.js +206 -0
- package/plugins/core/connectors/lib/connector-core.js +195 -0
- package/plugins/core/connectors/lib/transport-http-helpers.js +122 -0
- package/plugins/core/connectors/lib/transport-route-schemas.js +92 -0
- package/plugins/core/lib/dbIntrospection.js +1078 -0
- package/plugins/core/lib/dbTablesOperations.js +1104 -160
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -2
- package/plugins/core/lib/querying/knex-process-includes.js +3 -4
- package/plugins/core/lib/querying/knex-query-helpers.js +17 -71
- package/plugins/core/lib/querying/knex-relationship-includes.js +466 -206
- package/plugins/core/lib/querying/query-builder-utils.js +19 -0
- package/plugins/core/lib/querying/query-field-sort-helpers.js +135 -0
- package/plugins/core/lib/querying/sort-helpers.js +33 -0
- package/plugins/core/lib/querying/storage-adapter-utils.js +51 -0
- package/plugins/core/lib/querying/url-helpers.js +8 -2
- package/plugins/core/lib/querying-writing/compile-schemas.js +12 -1
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -13
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +13 -12
- package/plugins/core/lib/querying-writing/query-field-helpers.js +88 -0
- package/plugins/core/lib/querying-writing/request-contracts.js +590 -0
- package/plugins/core/lib/storage/canonical-storage-mapping.js +113 -0
- package/plugins/core/lib/storage/storage-adapter.js +79 -2
- package/plugins/core/lib/storage/storage-mapping.js +204 -0
- package/plugins/core/rest-api-anyapi-knex-plugin.js +355 -228
- package/plugins/core/rest-api-autofilter-plugin.js +414 -0
- package/plugins/core/rest-api-knex-plugin.js +249 -211
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +10 -5
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +12 -6
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
- package/plugins/core/rest-api-plugin-methods/common.js +121 -83
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
- package/plugins/core/rest-api-plugin-methods/get.js +23 -14
- package/plugins/core/rest-api-plugin-methods/patch.js +28 -12
- package/plugins/core/rest-api-plugin-methods/post.js +13 -8
- package/plugins/core/rest-api-plugin-methods/put.js +45 -21
- package/plugins/core/rest-api-plugin-methods/query.js +15 -53
- package/plugins/core/rest-api-plugin.js +2 -0
- package/plugins/core/rest-api-positioning-plugin.js +1 -1
- package/plugins/core/rest-api-query-projections-plugin.js +130 -0
- package/plugins/core/socketio-plugin.js +1 -3
- package/tests/autofilter.test.js +463 -0
- package/tests/custom-id-simplified-post.test.js +75 -0
- package/tests/custom-idproperty-relationships.test.js +33 -0
- package/tests/db-introspection.test.js +518 -0
- package/tests/db-table-operations.test.js +781 -0
- package/tests/fastify-plugin.test.js +141 -0
- package/tests/field-getters.test.js +1 -2
- package/tests/field-setters.test.js +0 -4
- package/tests/fixtures/api-configs.js +188 -219
- package/tests/helpers/fake-fastify.js +99 -0
- package/tests/http-connectors-parity.test.js +235 -0
- package/tests/projected-fields.test.js +319 -0
- package/tests/relationships.test.js +3 -3
- package/tests/searchschema-knex-behavior.test.js +187 -0
- package/tests/searchschema-merge.test.js +21 -69
- package/tests/storage-mapping.test.js +210 -0
- package/audit/00-charter.md +0 -103
- package/audit/01-scope-map.md +0 -84
- package/audit/02-coverage-matrix.csv +0 -174
- package/audit/03-invariants.md +0 -123
- package/audit/04-standards-rubric.md +0 -56
- package/audit/05-competitor-rubric.md +0 -77
- package/audit/06-findings.md +0 -160
- package/audit/07-risk-register.csv +0 -10
- package/audit/08-remediation-roadmap.md +0 -177
- package/audit/09-signoff-check.md +0 -23
- package/audit/10-final-synthesis.md +0 -29
- package/audit/evidence/code/all-files-json-rest-api.txt +0 -168
- package/audit/evidence/code/all-files-json-rest-schema.txt +0 -12
- package/audit/evidence/code/boundary-leak-checks.txt +0 -72
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +0 -480
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +0 -532
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +0 -175
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +0 -138
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +0 -222
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +0 -342
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +0 -304
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +0 -188
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +0 -336
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +0 -165
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +0 -265
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +0 -369
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +0 -72
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +0 -139
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +0 -45
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +0 -396
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +0 -162
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +0 -1314
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +0 -488
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +0 -484
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +0 -857
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +0 -565
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +0 -485
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +0 -560
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +0 -167
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +0 -109
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +0 -1064
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +0 -1983
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +0 -328
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +0 -119
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +0 -160
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +0 -300
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +0 -245
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +0 -459
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +0 -237
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +0 -1135
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +0 -314
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +0 -7
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +0 -71
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +0 -102
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +0 -49
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +0 -39
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +0 -23
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +0 -13
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +0 -639
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +0 -117
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +0 -104
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +0 -199
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +0 -353
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +0 -61
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +0 -184
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +0 -55
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +0 -191
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +0 -110
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +0 -168
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +0 -253
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +0 -207
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +0 -12
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +0 -165
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +0 -668
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +0 -621
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +0 -218
- package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +0 -124
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +0 -269
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +0 -242
- package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +0 -77
- package/audit/evidence/code/critical-pass1-risk-keywords.txt +0 -238
- package/audit/evidence/code/critical-pass1-summary.csv +0 -67
- package/audit/evidence/code/critical-pass2-summary.csv +0 -67
- package/audit/evidence/code/early-silent-zones-no-test-token.txt +0 -57
- package/audit/evidence/code/error-model-signals.txt +0 -98
- package/audit/evidence/code/git-files-json-rest-api.txt +0 -171
- package/audit/evidence/code/git-files-json-rest-schema.txt +0 -27
- package/audit/evidence/code/hook-flow-signals.txt +0 -282
- package/audit/evidence/code/idproperty-signals.txt +0 -157
- package/audit/evidence/code/import-cycles-non-anyapi.txt +0 -3
- package/audit/evidence/code/import-hotspots-non-anyapi.txt +0 -96
- package/audit/evidence/code/imports-json-rest-api.txt +0 -354
- package/audit/evidence/code/imports-json-rest-schema.txt +0 -15
- package/audit/evidence/code/in-scope-files-json-rest-api.txt +0 -160
- package/audit/evidence/code/in-scope-files-json-rest-schema.txt +0 -13
- package/audit/evidence/code/non-anyapi-core-files.txt +0 -101
- package/audit/evidence/code/permission-signals.txt +0 -193
- package/audit/evidence/code/query-include-signals.txt +0 -687
- package/audit/evidence/code/transaction-signals.txt +0 -28
- package/audit/evidence/code/validation-signals.txt +0 -650
- package/audit/evidence/code/write-path-signals.txt +0 -61
- package/audit/evidence/docs/docs-claims-signals.txt +0 -1075
- package/audit/evidence/docs/schema-docs-claims-signals.txt +0 -179
- package/audit/evidence/external/corpus-freeze.md +0 -21
- package/audit/evidence/external/npm-competitor-metadata.txt +0 -70
- package/audit/evidence/external/npm-download-signals.txt +0 -23
- package/audit/evidence/external/npm-jsonapi-server.txt +0 -8
- package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +0 -38
- package/audit/evidence/external/readme-fortune-signals.txt +0 -26
- package/audit/evidence/external/readme-fortune.md +0 -165
- package/audit/evidence/external/readme-json-api-serializer-signals.txt +0 -80
- package/audit/evidence/external/readme-json-api-serializer.md +0 -690
- package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
- package/audit/evidence/external/readme-jsonapi-serde-server.md +0 -22
- package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +0 -63
- package/audit/evidence/external/readme-jsonapi-serializer.md +0 -315
- package/audit/evidence/external/readme-jsonapi-server-signals.txt +0 -19
- package/audit/evidence/external/readme-jsonapi-server.md +0 -104
- package/audit/evidence/external/readme-nestjs-json-api-signals.txt +0 -4
- package/audit/evidence/external/readme-nestjs-json-api.md +0 -94
- package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +0 -47
- package/audit/evidence/external/readme-yaser-json-api-nestjs.md +0 -447
- package/audit/evidence/external/standard-jsonapi-snippets.txt +0 -84
- package/audit/evidence/external/standard-rfc-snippets.txt +0 -168
- package/audit/evidence/external/standards-sources.txt +0 -6
- package/audit/evidence/runtime/baseline-commits.txt +0 -2
- package/audit/evidence/runtime/db-adapter-assumptions.txt +0 -3
- package/audit/evidence/runtime/environment.txt +0 -4
- package/audit/evidence/runtime/invariant-runtime-mapping.md +0 -38
- package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +0 -1
- package/audit/evidence/runtime/probe-patch-relationship-error.log +0 -76
- package/audit/evidence/runtime/probe-patch-relationship-error.mjs +0 -67
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +0 -1
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +0 -62
- package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +0 -47
- package/audit/evidence/runtime/test-exitcodes.txt +0 -4
- package/audit/evidence/runtime/test-summary.md +0 -107
- package/audit/evidence/runtime/trace-anchors.txt +0 -61
- package/audit/evidence/tests/access-multitenancy-test-signals.txt +0 -125
- package/audit/evidence/tests/failing-tests-summary.txt +0 -25
- package/audit/evidence/tests/npm-test-json-rest-api.exitcode +0 -1
- package/audit/evidence/tests/npm-test-json-rest-api.log +0 -5885
- package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +0 -1
- package/audit/evidence/tests/npm-test-json-rest-schema.log +0 -356
- package/audit/evidence/tests/query-include-test-signals.txt +0 -948
- package/audit/evidence/tests/relationship-test-signals.txt +0 -223
- package/audit/evidence/tests/skipped-tests.txt +0 -10
- package/audit/evidence/tests/test-suite-list-non-anyapi.txt +0 -30
- package/audit/evidence/tests/test-suite-list.txt +0 -32
- package/audit/subsystems/docs-drift.md +0 -49
- package/audit/subsystems/pass2-cross-review.md +0 -131
- package/audit/subsystems/plugins-access.md +0 -51
- package/audit/subsystems/plugins-bulk.md +0 -50
- package/audit/subsystems/plugins-cors.md +0 -48
- package/audit/subsystems/plugins-file.md +0 -53
- package/audit/subsystems/plugins-multihome.md +0 -50
- package/audit/subsystems/plugins-positioning.md +0 -54
- package/audit/subsystems/plugins-socketio.md +0 -50
- package/audit/subsystems/query-engine.md +0 -61
- package/audit/subsystems/relationships.md +0 -55
- package/audit/subsystems/rest-orchestration.md +0 -66
- package/audit/subsystems/schema-core.md +0 -64
- package/audit/subsystems/storage-knex.md +0 -57
- package/audit/subsystems/tests.md +0 -48
- package/audit/subsystems/transport-express.md +0 -55
- package/audit/traces/trace-read-get.md +0 -22
- package/audit/traces/trace-read-query.md +0 -25
- package/audit/traces/trace-relationship-endpoints.md +0 -31
- package/audit/traces/trace-write-delete.md +0 -17
- package/audit/traces/trace-write-patch.md +0 -26
- package/audit/traces/trace-write-post.md +0 -22
- package/audit/traces/trace-write-put.md +0 -23
- package/docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md +0 -707
- package/docs/GUIDE/GUIDE_X_Multihome.md +0 -666
- package/plugins/core/lib/querying-writing/payload-validators.js +0 -1314
- package/plugins/core/rest-api-access.js +0 -459
- package/plugins/core/rest-api-multihome-plugin.js +0 -314
- package/tests/multihome.test.js +0 -553
- package/tests/multihome.test.js.bak +0 -550
- package/tests/ownership-optout.test.js +0 -76
- package/tests/rest-api-access.test.js +0 -206
|
@@ -1,532 +0,0 @@
|
|
|
1
|
-
1 /**
|
|
2
|
-
2 * Express Plugin for Hooked API
|
|
3
|
-
3 *
|
|
4
|
-
4 * This plugin creates HTTP endpoints for your REST API by listening to
|
|
5
|
-
5 * route registrations from the REST API plugin and creating Express routes.
|
|
6
|
-
6 *
|
|
7
|
-
7 * Features:
|
|
8
|
-
8 * - Automatic route creation via addRoute hook
|
|
9
|
-
9 * - JSON:API compliant request/response handling
|
|
10
|
-
10 * - Query parameter parsing
|
|
11
|
-
11 * - Error mapping to HTTP status codes
|
|
12
|
-
12 * - Content type validation
|
|
13
|
-
13 * - Middleware injection points
|
|
14
|
-
14 * - File upload support with busboy or formidable
|
|
15
|
-
15 */
|
|
16
|
-
16
|
|
17
|
-
17 import { requirePackage } from 'hooked-api'
|
|
18
|
-
18 import { parseJsonApiQuery } from '../lib/querying-writing/connectors-query-parser.js'
|
|
19
|
-
19 import { createContext } from './lib/request-helpers.js'
|
|
20
|
-
20 import { createEnhancedLogger } from '../../../lib/enhanced-logger.js'
|
|
21
|
-
21
|
|
22
|
-
22 export const ExpressPlugin = {
|
|
23
|
-
23 name: 'express',
|
|
24
|
-
24 dependencies: ['rest-api'],
|
|
25
|
-
25
|
|
26
|
-
26 async install ({ on, vars, helpers, pluginOptions, log, scopes, api, runHooks, addHook }) {
|
|
27
|
-
27 addHook('release', 'releaseHook', {},
|
|
28
|
-
28 async ({ api }) => {} // TODO: Anything to do here?
|
|
29
|
-
29 )
|
|
30
|
-
30
|
|
31
|
-
31 // Dynamic import for Express
|
|
32
|
-
32 let express
|
|
33
|
-
33 try {
|
|
34
|
-
34 express = (await import('express')).default
|
|
35
|
-
35 } catch (e) {
|
|
36
|
-
36 requirePackage('express', 'express',
|
|
37
|
-
37 'Express.js is required for HTTP server functionality. This is a peer dependency.')
|
|
38
|
-
38 }
|
|
39
|
-
39 // Enhance the logger
|
|
40
|
-
40 const enhancedLog = createEnhancedLogger(log, {
|
|
41
|
-
41 logFullErrors: true,
|
|
42
|
-
42 includeStack: true
|
|
43
|
-
43 })
|
|
44
|
-
44
|
|
45
|
-
45 // Initialize express namespace
|
|
46
|
-
46 if (!api.http) {
|
|
47
|
-
47 api.http = {}
|
|
48
|
-
48 }
|
|
49
|
-
49 api.http.express = {}
|
|
50
|
-
50
|
|
51
|
-
51 const expressOptions = pluginOptions || {}
|
|
52
|
-
52
|
|
53
|
-
53 // Get mountPath from options (this is now a transport concern)
|
|
54
|
-
54 const mountPath = expressOptions.mountPath || ''
|
|
55
|
-
55 const basePath = mountPath // Keep basePath for internal use
|
|
56
|
-
56 const strictContentType = expressOptions.strictContentType !== false
|
|
57
|
-
57 const requestSizeLimit = expressOptions.requestSizeLimit || '1mb'
|
|
58
|
-
58
|
|
59
|
-
59 // Set transport information for other plugins
|
|
60
|
-
60 vars.transport = {
|
|
61
|
-
61 type: 'express',
|
|
62
|
-
62 matchAll: '*', // Express wildcard pattern for matching all routes
|
|
63
|
-
63 mountPath // Transport-specific mount path
|
|
64
|
-
64 }
|
|
65
|
-
65
|
|
66
|
-
66 // Register file detector if enabled
|
|
67
|
-
67 if (expressOptions.enableFileUploads !== false && api.rest?.registerFileDetector) {
|
|
68
|
-
68 const parserLib = expressOptions.fileParser || 'busboy'
|
|
69
|
-
69 const parserOptions = expressOptions.fileParserOptions || {}
|
|
70
|
-
70
|
|
71
|
-
71 let detector
|
|
72
|
-
72
|
|
73
|
-
73 if (parserLib === 'busboy') {
|
|
74
|
-
74 try {
|
|
75
|
-
75 const { createBusboyDetector } = await import('../lib/busboy-detector.js')
|
|
76
|
-
76 detector = createBusboyDetector(parserOptions)
|
|
77
|
-
77 } catch (e) {
|
|
78
|
-
78 log.warn('Busboy not installed. Install with: npm install busboy')
|
|
79
|
-
79 }
|
|
80
|
-
80 } else if (parserLib === 'formidable') {
|
|
81
|
-
81 try {
|
|
82
|
-
82 const { createFormidableDetector } = await import('../lib/formidable-detector.js')
|
|
83
|
-
83 detector = createFormidableDetector(parserOptions)
|
|
84
|
-
84 } catch (e) {
|
|
85
|
-
85 log.warn('Formidable not installed. Install with: npm install formidable')
|
|
86
|
-
86 }
|
|
87
|
-
87 }
|
|
88
|
-
88
|
|
89
|
-
89 if (detector) {
|
|
90
|
-
90 api.rest.registerFileDetector({
|
|
91
|
-
91 name: `express-${detector.name}`,
|
|
92
|
-
92 detect: (params, context) => {
|
|
93
|
-
93 if (!context || !context.raw || !context.raw.req) return false
|
|
94
|
-
94 const detectParams = { ...params, _expressReq: context.raw.req }
|
|
95
|
-
95 return detector.detect(detectParams)
|
|
96
|
-
96 },
|
|
97
|
-
97 parse: (params, context) => {
|
|
98
|
-
98 const parseParams = { ...params, _expressReq: context.raw.req, _expressRes: context.raw.res }
|
|
99
|
-
99 return detector.parse(parseParams)
|
|
100
|
-
100 }
|
|
101
|
-
101 })
|
|
102
|
-
102 log.info(`Express plugin registered file detector: ${detector.name}`)
|
|
103
|
-
103 }
|
|
104
|
-
104 }
|
|
105
|
-
105
|
|
106
|
-
106 // Create Express routers
|
|
107
|
-
107 const router = expressOptions.router || express.Router()
|
|
108
|
-
108 const notFoundRouter = express.Router()
|
|
109
|
-
109
|
|
110
|
-
110 // Add body parsing middleware
|
|
111
|
-
111 router.use(express.json({
|
|
112
|
-
112 limit: requestSizeLimit,
|
|
113
|
-
113 type: ['application/json', 'application/vnd.api+json']
|
|
114
|
-
114 }))
|
|
115
|
-
115
|
|
116
|
-
116 // Add transport hook middleware
|
|
117
|
-
117 router.use(async (req, res, next) => {
|
|
118
|
-
118 const context = createContext(req, res, 'express')
|
|
119
|
-
119
|
|
120
|
-
120 // Check for Express middleware override first
|
|
121
|
-
121 if (req.urlPrefixOverride) {
|
|
122
|
-
122 context.urlPrefixOverride = req.urlPrefixOverride
|
|
123
|
-
123 }
|
|
124
|
-
124
|
|
125
|
-
125 // Calculate and cache URL prefix (getUrlPrefix handles all logic)
|
|
126
|
-
126 const { getUrlPrefix } = await import('../lib/querying/url-helpers.js')
|
|
127
|
-
127 context.urlPrefix = getUrlPrefix(context, { vars: { transport: { mountPath: basePath } } }, req)
|
|
128
|
-
128
|
|
129
|
-
129 // Transport-specific data for hooks
|
|
130
|
-
130 const transportData = {
|
|
131
|
-
131 request: {
|
|
132
|
-
132 method: req.method,
|
|
133
|
-
133 url: req.url,
|
|
134
|
-
134 path: req.path,
|
|
135
|
-
135 headers: req.headers,
|
|
136
|
-
136 body: req.body,
|
|
137
|
-
137 params: req.params,
|
|
138
|
-
138 query: req.query
|
|
139
|
-
139 },
|
|
140
|
-
140 response: {
|
|
141
|
-
141 headers: {},
|
|
142
|
-
142 status: null
|
|
143
|
-
143 }
|
|
144
|
-
144 }
|
|
145
|
-
145
|
|
146
|
-
146 // Add transport data to context
|
|
147
|
-
147 context.transport = transportData
|
|
148
|
-
148
|
|
149
|
-
149 // Run transport hooks - don't check return value for consistency with other hooks
|
|
150
|
-
150 // Hooks communicate via context flags (rejection, handled) not return values
|
|
151
|
-
151 await runHooks('transport:request', context)
|
|
152
|
-
152
|
|
153
|
-
153 // Check if request was rejected (e.g., authentication failure)
|
|
154
|
-
154 if (context.rejection) {
|
|
155
|
-
155 // Apply response headers from hooks
|
|
156
|
-
156 if (transportData.response.headers) {
|
|
157
|
-
157 res.set(transportData.response.headers)
|
|
158
|
-
158 }
|
|
159
|
-
159 return res.status(context.rejection.status || 500).json({
|
|
160
|
-
160 errors: [{
|
|
161
|
-
161 status: String(context.rejection.status || 500),
|
|
162
|
-
162 title: context.rejection.title || 'Request Rejected',
|
|
163
|
-
163 detail: context.rejection.message
|
|
164
|
-
164 }]
|
|
165
|
-
165 })
|
|
166
|
-
166 }
|
|
167
|
-
167
|
|
168
|
-
168 // Check if request was already handled by a hook
|
|
169
|
-
169 if (context.handled) {
|
|
170
|
-
170 return
|
|
171
|
-
171 }
|
|
172
|
-
172
|
|
173
|
-
173 // Store transport data and context for later use
|
|
174
|
-
174 req.transportData = transportData
|
|
175
|
-
175 req.context = context
|
|
176
|
-
176 next()
|
|
177
|
-
177 })
|
|
178
|
-
178
|
|
179
|
-
179 // Content type validation middleware
|
|
180
|
-
180 if (strictContentType) {
|
|
181
|
-
181 router.use((req, res, next) => {
|
|
182
|
-
182 if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
|
|
183
|
-
183 const contentType = req.get('Content-Type')
|
|
184
|
-
184
|
|
185
|
-
185 if (contentType && !contentType.includes('application/vnd.api+json') &&
|
|
186
|
-
186 !contentType.includes('application/json') && !contentType.includes('multipart/form-data')) {
|
|
187
|
-
187 return res.status(415).json({
|
|
188
|
-
188 errors: [{
|
|
189
|
-
189 status: '415',
|
|
190
|
-
190 title: 'Unsupported Media Type',
|
|
191
|
-
191 detail: 'Content-Type must be application/vnd.api+json or application/json'
|
|
192
|
-
192 }]
|
|
193
|
-
193 })
|
|
194
|
-
194 }
|
|
195
|
-
195 }
|
|
196
|
-
196 next()
|
|
197
|
-
197 })
|
|
198
|
-
198 }
|
|
199
|
-
199
|
|
200
|
-
200 /**
|
|
201
|
-
201 * Error handler - maps REST API errors to HTTP responses
|
|
202
|
-
202 */
|
|
203
|
-
203 const handleError = async (error, req, res) => {
|
|
204
|
-
204 enhancedLog.logError('HTTP request error', error, {
|
|
205
|
-
205 method: req.method,
|
|
206
|
-
206 path: req.path,
|
|
207
|
-
207 url: req.url
|
|
208
|
-
208 })
|
|
209
|
-
209
|
|
210
|
-
210 let status = 500
|
|
211
|
-
211 const errorResponse = {
|
|
212
|
-
212 errors: [{
|
|
213
|
-
213 status: '500',
|
|
214
|
-
214 title: 'Internal Server Error',
|
|
215
|
-
215 detail: error.message
|
|
216
|
-
216 }]
|
|
217
|
-
217 }
|
|
218
|
-
218
|
|
219
|
-
219 // Map error codes to HTTP status
|
|
220
|
-
220 if (error.code === 'REST_API_VALIDATION') {
|
|
221
|
-
221 status = 422
|
|
222
|
-
222 errorResponse.errors = [{
|
|
223
|
-
223 status: '422',
|
|
224
|
-
224 title: 'Validation Error',
|
|
225
|
-
225 detail: error.message,
|
|
226
|
-
226 source: error.details
|
|
227
|
-
227 }]
|
|
228
|
-
228 if (error.details?.violations) {
|
|
229
|
-
229 errorResponse.errors = error.details.violations.map(v => ({
|
|
230
|
-
230 status: '422',
|
|
231
|
-
231 title: 'Validation Error',
|
|
232
|
-
232 detail: v.message,
|
|
233
|
-
233 source: { pointer: v.field }
|
|
234
|
-
234 }))
|
|
235
|
-
235 }
|
|
236
|
-
236 } else if (error.code === 'REST_API_RESOURCE') {
|
|
237
|
-
237 switch (error.subtype) {
|
|
238
|
-
238 case 'not_found':
|
|
239
|
-
239 status = 404
|
|
240
|
-
240 errorResponse.errors[0].status = '404'
|
|
241
|
-
241 errorResponse.errors[0].title = 'Not Found'
|
|
242
|
-
242 break
|
|
243
|
-
243 case 'conflict':
|
|
244
|
-
244 status = 409
|
|
245
|
-
245 errorResponse.errors[0].status = '409'
|
|
246
|
-
246 errorResponse.errors[0].title = 'Conflict'
|
|
247
|
-
247 break
|
|
248
|
-
248 case 'forbidden':
|
|
249
|
-
249 status = 403
|
|
250
|
-
250 errorResponse.errors[0].status = '403'
|
|
251
|
-
251 errorResponse.errors[0].title = 'Forbidden'
|
|
252
|
-
252 break
|
|
253
|
-
253 default:
|
|
254
|
-
254 status = 400
|
|
255
|
-
255 errorResponse.errors[0].status = '400'
|
|
256
|
-
256 errorResponse.errors[0].title = 'Bad Request'
|
|
257
|
-
257 }
|
|
258
|
-
258 } else if (error.code === 'REST_API_PAYLOAD') {
|
|
259
|
-
259 status = 400
|
|
260
|
-
260 errorResponse.errors = [{
|
|
261
|
-
261 status: '400',
|
|
262
|
-
262 title: 'Bad Request',
|
|
263
|
-
263 detail: error.message,
|
|
264
|
-
264 source: { pointer: error.path }
|
|
265
|
-
265 }]
|
|
266
|
-
266 }
|
|
267
|
-
267
|
|
268
|
-
268 // Run transport:response hook for errors
|
|
269
|
-
269 if (req.transportData && req.context) {
|
|
270
|
-
270 req.transportData.response.status = status
|
|
271
|
-
271 req.transportData.response.body = errorResponse
|
|
272
|
-
272 req.context.transport = req.transportData
|
|
273
|
-
273 await runHooks('transport:response', req.context)
|
|
274
|
-
274
|
|
275
|
-
275 // Apply response headers from hooks
|
|
276
|
-
276 if (req.transportData.response.headers) {
|
|
277
|
-
277 res.set(req.transportData.response.headers)
|
|
278
|
-
278 }
|
|
279
|
-
279 }
|
|
280
|
-
280
|
|
281
|
-
281 res.status(status).json(errorResponse)
|
|
282
|
-
282 }
|
|
283
|
-
283
|
|
284
|
-
284 /**
|
|
285
|
-
285 * Listen to addRoute hook to create Express routes
|
|
286
|
-
286 */
|
|
287
|
-
287 addHook('addRoute', 'expressRouteCreator', {}, async ({ context }) => {
|
|
288
|
-
288 const { method, path, handler } = context
|
|
289
|
-
289
|
|
290
|
-
290 // Apply any global before middleware
|
|
291
|
-
291 const beforeMiddleware = expressOptions.middleware?.beforeAll || []
|
|
292
|
-
292
|
|
293
|
-
293 try {
|
|
294
|
-
294 // Extract the handler logic into a shared function to keep it DRY (Don't Repeat Yourself).
|
|
295
|
-
295 const expressHandler = async (req, res) => {
|
|
296
|
-
296 try {
|
|
297
|
-
297 // Extract request data
|
|
298
|
-
298 const queryString = req.url.split('?')[1] || ''
|
|
299
|
-
299 const context = req.context || createContext(req, res, 'express')
|
|
300
|
-
300
|
|
301
|
-
301 // Call the generic handler
|
|
302
|
-
302 const result = await handler({
|
|
303
|
-
303 queryString,
|
|
304
|
-
304 headers: req.headers,
|
|
305
|
-
305 params: req.params,
|
|
306
|
-
306 body: req.body,
|
|
307
|
-
307 context
|
|
308
|
-
308 })
|
|
309
|
-
309
|
|
310
|
-
310 // Prepare response status
|
|
311
|
-
311 let responseStatus = 200
|
|
312
|
-
312 if (result && typeof result.statusCode === 'number') {
|
|
313
|
-
313 responseStatus = result.statusCode
|
|
314
|
-
314 } else if (req.method === 'POST' && result) {
|
|
315
|
-
315 // POST with content returns 201 Created
|
|
316
|
-
316 responseStatus = 201
|
|
317
|
-
317 } else if (req.method === 'POST' && !result) {
|
|
318
|
-
318 // POST without content returns 204 No Content
|
|
319
|
-
319 responseStatus = 204
|
|
320
|
-
320 } else if (req.method === 'DELETE') {
|
|
321
|
-
321 // DELETE always returns 204 No Content
|
|
322
|
-
322 responseStatus = 204
|
|
323
|
-
323 } else if ((req.method === 'PUT' || req.method === 'PATCH') && !result) {
|
|
324
|
-
324 // PUT/PATCH return 204 when no content is returned
|
|
325
|
-
325 responseStatus = 204
|
|
326
|
-
326 }
|
|
327
|
-
327
|
|
328
|
-
328 // Apply headers from the handler result
|
|
329
|
-
329 if (result && result.headers) {
|
|
330
|
-
330 res.set(result.headers)
|
|
331
|
-
331 }
|
|
332
|
-
332
|
|
333
|
-
333 // Update transport data for response (if transport data exists)
|
|
334
|
-
334 if (req.transportData) {
|
|
335
|
-
335 req.transportData.response.status = responseStatus
|
|
336
|
-
336 req.transportData.response.body = result
|
|
337
|
-
337 context.transport = req.transportData
|
|
338
|
-
338 await runHooks('transport:response', context)
|
|
339
|
-
339 if (req.transportData.response.headers) {
|
|
340
|
-
340 res.set(req.transportData.response.headers)
|
|
341
|
-
341 }
|
|
342
|
-
342 }
|
|
343
|
-
343
|
|
344
|
-
344 // Set content type
|
|
345
|
-
345 res.set('Content-Type', 'application/vnd.api+json')
|
|
346
|
-
346
|
|
347
|
-
347 // Set Location header for successful POST requests
|
|
348
|
-
348 if (req.method === 'POST' && context.id) {
|
|
349
|
-
349 // Extract scopeName from the path (e.g., /api/countries -> countries)
|
|
350
|
-
350 const pathParts = path.split('/')
|
|
351
|
-
351 const scopeName = pathParts[pathParts.length - 1]
|
|
352
|
-
352
|
|
353
|
-
353 // Set Location header for any successful POST (201 or 204)
|
|
354
|
-
354 if (helpers.getLocation) {
|
|
355
|
-
355 const location = helpers.getLocation({ scopeName, id: context.id })
|
|
356
|
-
356 const baseUrl = context.urlPrefix || basePath
|
|
357
|
-
357 res.set('Location', `${baseUrl}${location}`)
|
|
358
|
-
358 }
|
|
359
|
-
359 }
|
|
360
|
-
360
|
|
361
|
-
361 // Handle response based on status
|
|
362
|
-
362 if (responseStatus === 204) {
|
|
363
|
-
363 res.sendStatus(204)
|
|
364
|
-
364 } else {
|
|
365
|
-
365 // If result has a body property, that's what we should send
|
|
366
|
-
366 // This happens when handler returns { statusCode, body, headers }
|
|
367
|
-
367 const responseBody = result && result.body !== undefined ? result.body : result
|
|
368
|
-
368 res.status(responseStatus).json(responseBody)
|
|
369
|
-
369 }
|
|
370
|
-
370 } catch (error) {
|
|
371
|
-
371 handleError(error, req, res)
|
|
372
|
-
372 }
|
|
373
|
-
373 }
|
|
374
|
-
374
|
|
375
|
-
375 // CRITICAL: Express routing method selection - wildcard vs specific routes
|
|
376
|
-
376 //
|
|
377
|
-
377 // Express provides two different ways to register routes:
|
|
378
|
-
378 // 1. router.METHOD(path, handler) - e.g., router.get('/users', handler)
|
|
379
|
-
379 // - Only responds to the SPECIFIC HTTP method
|
|
380
|
-
380 // - Perfect for normal REST endpoints
|
|
381
|
-
381 //
|
|
382
|
-
382 // 2. router.use(path, handler)
|
|
383
|
-
383 // - Responds to ALL HTTP methods
|
|
384
|
-
384 // - Needed for wildcard paths that must handle any method
|
|
385
|
-
385 //
|
|
386
|
-
386 // The CORS plugin needs wildcard routes because it must handle OPTIONS
|
|
387
|
-
387 // requests for ANY path under the API prefix, even paths that don't exist
|
|
388
|
-
388 // as defined routes. For example:
|
|
389
|
-
389 // - Defined route: GET /api/users
|
|
390
|
-
390 // - Browser might send: OPTIONS /api/users/invalid/path
|
|
391
|
-
391 // - CORS must still respond with proper headers
|
|
392
|
-
392 //
|
|
393
|
-
393 if (path === vars.transport.matchAll) {
|
|
394
|
-
394 // This is a wildcard route (path = '*')
|
|
395
|
-
395 // We MUST use router.use() because:
|
|
396
|
-
396 // - We need to catch ALL paths (using '*' or '/api/*')
|
|
397
|
-
397 // - We need to handle a SPECIFIC method (e.g., OPTIONS)
|
|
398
|
-
398 // - router.options('*') would NOT work for paths like '/api/some/nested/path'
|
|
399
|
-
399
|
|
400
|
-
400 // Since router.use() responds to ALL methods, we need a wrapper
|
|
401
|
-
401 // that only handles our specific method (e.g., OPTIONS)
|
|
402
|
-
402 const methodSpecificMiddleware = (req, res, next) => {
|
|
403
|
-
403 if (req.method.toLowerCase() === method.toLowerCase()) {
|
|
404
|
-
404 expressHandler(req, res)
|
|
405
|
-
405 } else {
|
|
406
|
-
406 // Not our method, pass to next middleware
|
|
407
|
-
407 next()
|
|
408
|
-
408 }
|
|
409
|
-
409 }
|
|
410
|
-
410 // IMPORTANT: We do NOT need to pass a path to router.use() here!
|
|
411
|
-
411 // When no path is provided, router.use() matches ALL requests
|
|
412
|
-
412 // This is exactly what we want for wildcard routes
|
|
413
|
-
413 router.use(...beforeMiddleware, methodSpecificMiddleware)
|
|
414
|
-
414 } else {
|
|
415
|
-
415 // This is a normal route with a specific path (e.g., '/api/users')
|
|
416
|
-
416 // We use router.METHOD() because:
|
|
417
|
-
417 // - We want to respond to ONLY this specific HTTP method
|
|
418
|
-
418 // - The path is exact, not a wildcard
|
|
419
|
-
419 // - This is more efficient than router.use() with method checking
|
|
420
|
-
420 //
|
|
421
|
-
421 // Note: Routes from RestApiPlugin already include the full path with mountPath
|
|
422
|
-
422 // So we use them as-is without adding basePath to avoid double-prefixing
|
|
423
|
-
423
|
|
424
|
-
424 router[method.toLowerCase()](path, ...beforeMiddleware, expressHandler)
|
|
425
|
-
425
|
|
426
|
-
426 // Debug logging for route registration
|
|
427
|
-
427
|
|
428
|
-
428 // Check if the route was actually added
|
|
429
|
-
429 if (router.stack) {
|
|
430
|
-
430 const lastRoute = router.stack[router.stack.length - 1]
|
|
431
|
-
431 }
|
|
432
|
-
432 }
|
|
433
|
-
433 } catch (routeError) {
|
|
434
|
-
434 log.error('[EXPRESS DEBUG] Error creating route:', {
|
|
435
|
-
435 error: routeError.message,
|
|
436
|
-
436 stack: routeError.stack,
|
|
437
|
-
437 path,
|
|
438
|
-
438 method: method.toLowerCase()
|
|
439
|
-
439 })
|
|
440
|
-
440 throw routeError
|
|
441
|
-
441 }
|
|
442
|
-
442
|
|
443
|
-
443 const logPath = path === vars.transport.matchAll
|
|
444
|
-
444 ? '(all paths)' // router.use() with no path matches everything
|
|
445
|
-
445 : path
|
|
446
|
-
446 log.trace(`Express route created: ${method} ${logPath}`)
|
|
447
|
-
447 })
|
|
448
|
-
448
|
|
449
|
-
449 // Apply global middleware if configured
|
|
450
|
-
450 let finalRouter = router
|
|
451
|
-
451 if (expressOptions.middleware?.beforeAll) {
|
|
452
|
-
452 const globalRouter = express.Router()
|
|
453
|
-
453 globalRouter.use(...expressOptions.middleware.beforeAll)
|
|
454
|
-
454 globalRouter.use(router)
|
|
455
|
-
455 finalRouter = globalRouter
|
|
456
|
-
456 }
|
|
457
|
-
457
|
|
458
|
-
458 // Set up 404 handler in separate router (unless disabled)
|
|
459
|
-
459 if (expressOptions.handle404 !== false) {
|
|
460
|
-
460 notFoundRouter.use(async (req, res, next) => {
|
|
461
|
-
461 if (basePath && req.path.startsWith(basePath)) {
|
|
462
|
-
462 // Create minimal context for 404
|
|
463
|
-
463 const context = createContext(req, res, 'express')
|
|
464
|
-
464 const transportData = {
|
|
465
|
-
465 request: {
|
|
466
|
-
466 method: req.method,
|
|
467
|
-
467 url: req.url,
|
|
468
|
-
468 path: req.path,
|
|
469
|
-
469 headers: req.headers
|
|
470
|
-
470 },
|
|
471
|
-
471 response: {
|
|
472
|
-
472 headers: {},
|
|
473
|
-
473 status: 404,
|
|
474
|
-
474 body: {
|
|
475
|
-
475 errors: [{
|
|
476
|
-
476 status: '404',
|
|
477
|
-
477 title: 'Not Found',
|
|
478
|
-
478 detail: `The requested endpoint ${req.method} ${req.path} does not exist`
|
|
479
|
-
479 }]
|
|
480
|
-
480 }
|
|
481
|
-
481 }
|
|
482
|
-
482 }
|
|
483
|
-
483
|
|
484
|
-
484 // Add transport data to context
|
|
485
|
-
485 context.transport = transportData
|
|
486
|
-
486
|
|
487
|
-
487 // Run transport:response hook for 404
|
|
488
|
-
488 await runHooks('transport:response', context)
|
|
489
|
-
489
|
|
490
|
-
490 // Apply response headers from hooks
|
|
491
|
-
491 if (transportData.response.headers) {
|
|
492
|
-
492 res.set(transportData.response.headers)
|
|
493
|
-
493 }
|
|
494
|
-
494
|
|
495
|
-
495 res.status(404).json(transportData.response.body)
|
|
496
|
-
496 } else {
|
|
497
|
-
497 next()
|
|
498
|
-
498 }
|
|
499
|
-
499 })
|
|
500
|
-
500 }
|
|
501
|
-
501
|
|
502
|
-
502 // Store routers in api.http.express namespace
|
|
503
|
-
503 api.http.express.router = finalRouter
|
|
504
|
-
504 api.http.express.notFoundRouter = notFoundRouter
|
|
505
|
-
505
|
|
506
|
-
506 // Allow other plugins to add middleware before 404 handler
|
|
507
|
-
507 const beforeNotFoundMiddleware = []
|
|
508
|
-
508 api.http.express.beforeNotFound = (middleware) => {
|
|
509
|
-
509 beforeNotFoundMiddleware.push(middleware)
|
|
510
|
-
510 }
|
|
511
|
-
511
|
|
512
|
-
512 // Add convenient mounting method
|
|
513
|
-
513 api.http.express.mount = (app, path = '') => {
|
|
514
|
-
514 // Mount main router with all routes
|
|
515
|
-
515 app.use(path, finalRouter)
|
|
516
|
-
516
|
|
517
|
-
517 // Mount any middleware that should come before 404
|
|
518
|
-
518 beforeNotFoundMiddleware.forEach(middleware => {
|
|
519
|
-
519 app.use(path, middleware)
|
|
520
|
-
520 })
|
|
521
|
-
521
|
|
522
|
-
522 // Mount 404 handler router after all other routes (if enabled)
|
|
523
|
-
523 if (expressOptions.handle404 !== false) {
|
|
524
|
-
524 app.use(path, notFoundRouter)
|
|
525
|
-
525 }
|
|
526
|
-
526
|
|
527
|
-
527 log.info(`Express routes mounted at ${path || '/'}`)
|
|
528
|
-
528 }
|
|
529
|
-
529
|
|
530
|
-
530 log.info('Express plugin initialized successfully')
|
|
531
|
-
531 }
|
|
532
|
-
532 }
|