json-rest-api 1.0.22 → 1.0.24
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/README.md +22 -1
- package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
- package/docs/API.md +196 -38
- package/docs/COMPARISON.md +2 -2
- package/docs/GUIDE/GUIDE_1_Initial_Setup.md +111 -5
- 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 +370 -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/lib/enhanced-logger.js +1 -1
- package/package.json +6 -2
- package/plugins/core/bulk-operations-plugin.js +26 -34
- package/plugins/core/connectors/express-plugin.js +97 -190
- package/plugins/core/connectors/fastify-plugin.js +206 -0
- package/plugins/core/connectors/lib/busboy-detector.js +4 -4
- 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/anyapi/schema-utils.js +43 -4
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +4 -1
- package/plugins/core/lib/dbIntrospection.js +1078 -0
- package/plugins/core/lib/dbTablesOperations.js +1111 -160
- package/plugins/core/lib/querying/knex-cross-table-search.js +0 -7
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -3
- package/plugins/core/lib/querying/knex-process-includes.js +3 -4
- package/plugins/core/lib/querying/knex-query-helpers.js +21 -76
- package/plugins/core/lib/querying/knex-relationship-includes.js +468 -215
- 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 +20 -5
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -14
- 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/querying-writing/resource-id-normalization.js +131 -0
- package/plugins/core/lib/querying-writing/schema-helpers.js +0 -2
- package/plugins/core/lib/querying-writing/simplified-helpers.js +4 -11
- package/plugins/core/lib/storage/canonical-storage-mapping.js +133 -0
- package/plugins/core/lib/storage/storage-adapter.js +82 -4
- package/plugins/core/lib/storage/storage-mapping.js +274 -0
- package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -2
- package/plugins/core/rest-api-anyapi-knex-plugin.js +531 -312
- package/plugins/core/rest-api-autofilter-plugin.js +414 -0
- package/plugins/core/rest-api-knex-plugin.js +271 -226
- 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-hooks/turn-scope-init-into-vars.js +1 -0
- package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
- package/plugins/core/rest-api-plugin-methods/common.js +148 -92
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +11 -2
- package/plugins/core/rest-api-plugin-methods/delete.js +6 -1
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
- package/plugins/core/rest-api-plugin-methods/get-related.js +7 -2
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +7 -2
- package/plugins/core/rest-api-plugin-methods/get.js +29 -14
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +10 -3
- package/plugins/core/rest-api-plugin-methods/patch.js +56 -12
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +11 -2
- package/plugins/core/rest-api-plugin-methods/post.js +21 -8
- package/plugins/core/rest-api-plugin-methods/put.js +73 -21
- package/plugins/core/rest-api-plugin-methods/query.js +15 -53
- package/plugins/core/rest-api-plugin-methods/release.js +0 -2
- package/plugins/core/rest-api-plugin.js +6 -0
- package/plugins/core/rest-api-positioning-plugin.js +2 -5
- package/plugins/core/rest-api-query-projections-plugin.js +130 -0
- package/plugins/core/socketio-plugin.js +1 -4
- package/plugins/storage/local-storage.js +1 -1
- package/plugins/storage/s3-storage.js +5 -2
- package/quickTest.js +1 -0
- package/scripts/run-docs.js +80 -84
- package/test-debug.js +1 -1
- package/tests/README.md +7 -0
- package/tests/anyapi-basic.test.js +3 -0
- package/tests/autofilter.test.js +463 -0
- package/tests/custom-id-mysql-returning-fallback.test.js +128 -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 +521 -0
- package/tests/db-table-operations.test.js +786 -0
- package/tests/fastify-plugin.test.js +156 -0
- package/tests/field-getters.test.js +1 -2
- package/tests/field-setters.test.js +0 -4
- package/tests/fixtures/api-configs.js +278 -176
- package/tests/helpers/fake-fastify.js +99 -0
- package/tests/http-connectors-parity.test.js +235 -0
- package/tests/id-normalization.test.js +444 -0
- package/tests/logical-id-write-validation.test.js +151 -0
- package/tests/pagination-cursor-multifield.test.js +11 -11
- 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 +259 -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,8 +1,9 @@
|
|
|
1
1
|
import { RestApiResourceError } from '../../../lib/rest-api-errors.js'
|
|
2
|
-
import { validateGetPayload } from '../lib/querying-writing/payload-validators.js'
|
|
3
2
|
import { normalizeRecordAttributes } from '../lib/querying-writing/database-value-normalizers.js'
|
|
4
3
|
import { getRequestedComputedFields } from '../lib/querying-writing/knex-field-helpers.js'
|
|
5
4
|
import { transformJsonApiToSimplified } from '../lib/querying-writing/simplified-helpers.js'
|
|
5
|
+
import { getRequestContracts, validateRequestContractOrThrow } from '../lib/querying-writing/request-contracts.js'
|
|
6
|
+
import { requireExistingResourceId } from '../lib/querying-writing/resource-id-normalization.js'
|
|
6
7
|
import { cascadeConfig } from './common.js'
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -41,11 +42,11 @@ export default async function getMethod ({
|
|
|
41
42
|
|
|
42
43
|
// Assign common context properties
|
|
43
44
|
context.schemaInfo = scopes[scopeName].vars.schemaInfo
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const rawQueryParams = params.queryParams || {}
|
|
46
|
+
context.queryParams = {
|
|
47
|
+
fields: cascadeConfig('fields', [rawQueryParams], {}),
|
|
48
|
+
include: cascadeConfig('include', [rawQueryParams], [])
|
|
49
|
+
}
|
|
49
50
|
|
|
50
51
|
context.transaction = params.transaction
|
|
51
52
|
context.db = context.transaction || api.knex.instance
|
|
@@ -56,14 +57,28 @@ export default async function getMethod ({
|
|
|
56
57
|
const schemaStructure = context.schemaInfo.schemaInstance.structure
|
|
57
58
|
const schemaRelationships = context.schemaInfo.schemaRelationships
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
const requestContracts = getRequestContracts({
|
|
61
|
+
scopeName,
|
|
62
|
+
schemaInfo: context.schemaInfo,
|
|
63
|
+
includeDepthLimit: vars.includeDepthLimit,
|
|
64
|
+
sortableFields: vars.sortableFields
|
|
65
|
+
})
|
|
66
|
+
const normalizedId = requireExistingResourceId(params.id, {
|
|
67
|
+
scopeOptions,
|
|
68
|
+
vars,
|
|
69
|
+
scopeName
|
|
70
|
+
})
|
|
71
|
+
const validatedRequest = validateRequestContractOrThrow(
|
|
72
|
+
requestContracts.get,
|
|
73
|
+
{
|
|
74
|
+
id: normalizedId,
|
|
75
|
+
queryParams: context.queryParams
|
|
76
|
+
},
|
|
77
|
+
'GET request parameters are invalid'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
context.id = validatedRequest.id
|
|
81
|
+
context.queryParams = validatedRequest.queryParams || {}
|
|
67
82
|
|
|
68
83
|
// Fetch minimal record for authorization checks
|
|
69
84
|
const minimalRecord = await helpers.dataGetMinimal({
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { handleWriteMethodError } from './common.js'
|
|
2
|
+
import { requireExistingResourceId } from '../lib/querying-writing/resource-id-normalization.js'
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* PATCH RELATIONSHIP
|
|
3
6
|
* Completely replaces a relationship
|
|
@@ -8,9 +11,13 @@
|
|
|
8
11
|
* @param {object|array} relationshipData - New relationship data
|
|
9
12
|
* @returns {Promise<void>} 204 No Content
|
|
10
13
|
*/
|
|
11
|
-
export default async function patchRelationshipMethod ({ params, context, vars, helpers, scope, scopes, runHooks, scopeName, api }) {
|
|
14
|
+
export default async function patchRelationshipMethod ({ params, context, vars, helpers, scope, scopes, runHooks, scopeOptions, scopeName, api, log }) {
|
|
12
15
|
context.method = 'patchRelationship'
|
|
13
|
-
context.id = params.id
|
|
16
|
+
context.id = requireExistingResourceId(params.id, {
|
|
17
|
+
scopeOptions,
|
|
18
|
+
vars,
|
|
19
|
+
scopeName
|
|
20
|
+
})
|
|
14
21
|
context.relationshipName = params.relationshipName
|
|
15
22
|
|
|
16
23
|
// Transaction handling
|
|
@@ -50,6 +57,6 @@ export default async function patchRelationshipMethod ({ params, context, vars,
|
|
|
50
57
|
|
|
51
58
|
// 204 No Content
|
|
52
59
|
} catch (error) {
|
|
53
|
-
await handleWriteMethodError(error, context, 'PATCH_RELATIONSHIP', scopeName, log)
|
|
60
|
+
await handleWriteMethodError(error, context, 'PATCH_RELATIONSHIP', scopeName, log, runHooks)
|
|
54
61
|
}
|
|
55
62
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { RestApiResourceError } from '../../../lib/rest-api-errors.js'
|
|
2
|
-
import { validatePatchPayload } from '../lib/querying-writing/payload-validators.js'
|
|
1
|
+
import { RestApiResourceError, RestApiValidationError } from '../../../lib/rest-api-errors.js'
|
|
3
2
|
import { processRelationships } from '../lib/writing/relationship-processor.js'
|
|
4
3
|
import { updateManyToManyRelationship } from '../lib/writing/many-to-many-manipulations.js'
|
|
5
4
|
import { ERROR_SUBTYPES } from '../lib/querying-writing/knex-constants.js'
|
|
5
|
+
import { getRequestContracts, validateRequestContractOrThrow } from '../lib/querying-writing/request-contracts.js'
|
|
6
|
+
import {
|
|
7
|
+
requireDocumentResourceId,
|
|
8
|
+
requireExistingResourceId
|
|
9
|
+
} from '../lib/querying-writing/resource-id-normalization.js'
|
|
6
10
|
import {
|
|
7
11
|
setupCommonRequest,
|
|
8
12
|
validateResourceAttributesBeforeWrite,
|
|
@@ -49,23 +53,63 @@ export default async function patchMethod ({
|
|
|
49
53
|
api,
|
|
50
54
|
helpers
|
|
51
55
|
})
|
|
52
|
-
context.id = context.inputRecord.data.id
|
|
53
|
-
|
|
54
56
|
// Run early hooks for pre-processing (e.g., file handling)
|
|
55
57
|
await runHooks('beforeProcessing')
|
|
56
58
|
await runHooks('beforeProcessingPatch')
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
const requestContracts = getRequestContracts({
|
|
61
|
+
scopeName,
|
|
62
|
+
schemaInfo: context.schemaInfo,
|
|
63
|
+
includeDepthLimit: vars.includeDepthLimit,
|
|
64
|
+
sortableFields: vars.sortableFields
|
|
65
|
+
})
|
|
66
|
+
const normalizedPathId = params.id === undefined
|
|
67
|
+
? null
|
|
68
|
+
: requireExistingResourceId(params.id, {
|
|
69
|
+
scopeOptions,
|
|
70
|
+
vars,
|
|
71
|
+
scopeName
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if (normalizedPathId && !context.inputRecord?.data?.id) {
|
|
75
|
+
context.inputRecord = {
|
|
76
|
+
...context.inputRecord,
|
|
77
|
+
data: {
|
|
78
|
+
...(context.inputRecord?.data || {}),
|
|
79
|
+
id: normalizedPathId
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
context.inputRecord = validateRequestContractOrThrow(
|
|
85
|
+
requestContracts.patch,
|
|
86
|
+
context.inputRecord,
|
|
87
|
+
'PATCH request body is invalid'
|
|
88
|
+
)
|
|
89
|
+
const normalizedBodyId = requireDocumentResourceId(context.inputRecord.data.id, {
|
|
90
|
+
scopeOptions,
|
|
91
|
+
vars
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
if (normalizedPathId && normalizedPathId !== normalizedBodyId) {
|
|
95
|
+
throw new RestApiValidationError(
|
|
96
|
+
`ID mismatch. URL path ID '${normalizedPathId}' does not match request body ID '${normalizedBodyId}'`,
|
|
97
|
+
{
|
|
98
|
+
fields: ['data.id'],
|
|
99
|
+
violations: [{
|
|
100
|
+
field: 'data.id',
|
|
101
|
+
rule: 'id_consistency',
|
|
102
|
+
message: 'Request body ID must match URL path ID when both are provided'
|
|
103
|
+
}]
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
context.inputRecord.data.id = normalizedBodyId
|
|
108
|
+
context.id = normalizedPathId || normalizedBodyId
|
|
65
109
|
|
|
66
110
|
// Validate that user has read access to all related resources
|
|
67
111
|
// This ensures users can only create relationships to resources they can access
|
|
68
|
-
await validateRelationshipAccess(context, context.inputRecord, helpers,
|
|
112
|
+
await validateRelationshipAccess(context, context.inputRecord, helpers, api)
|
|
69
113
|
|
|
70
114
|
// Extract foreign keys from JSON:API relationships and prepare many-to-many operations
|
|
71
115
|
// Example: relationships.author -> author_id: '123' for storage
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { RestApiResourceError, RestApiValidationError, RestApiPayloadError } from '../../../lib/rest-api-errors.js'
|
|
2
2
|
import { findRelationshipDefinition, handleWriteMethodError } from './common.js'
|
|
3
3
|
import { createPivotRecords } from '../lib/writing/many-to-many-manipulations.js'
|
|
4
|
+
import {
|
|
5
|
+
normalizeRelationshipIdentifiers,
|
|
6
|
+
requireExistingResourceId
|
|
7
|
+
} from '../lib/querying-writing/resource-id-normalization.js'
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* POST RELATIONSHIP
|
|
@@ -12,9 +16,13 @@ import { createPivotRecords } from '../lib/writing/many-to-many-manipulations.js
|
|
|
12
16
|
* @param {array} relationshipData - Array of resource identifiers to add
|
|
13
17
|
* @returns {Promise<void>} 204 No Content
|
|
14
18
|
*/
|
|
15
|
-
export default async function postRelationshipMethod ({ params, context, vars, helpers, scope, scopes, runHooks, scopeName, api, log }) {
|
|
19
|
+
export default async function postRelationshipMethod ({ params, context, vars, helpers, scope, scopes, runHooks, scopeOptions, scopeName, api, log }) {
|
|
16
20
|
context.method = 'postRelationship'
|
|
17
|
-
context.id = params.id
|
|
21
|
+
context.id = requireExistingResourceId(params.id, {
|
|
22
|
+
scopeOptions,
|
|
23
|
+
vars,
|
|
24
|
+
scopeName
|
|
25
|
+
})
|
|
18
26
|
context.relationshipName = params.relationshipName
|
|
19
27
|
context.schemaInfo = scopes[scopeName].vars.schemaInfo
|
|
20
28
|
|
|
@@ -45,6 +53,7 @@ export default async function postRelationshipMethod ({ params, context, vars, h
|
|
|
45
53
|
if (!Array.isArray(params.relationshipData)) {
|
|
46
54
|
throw new RestApiPayloadError('POST to relationship requires array of resource identifiers')
|
|
47
55
|
}
|
|
56
|
+
params.relationshipData = normalizeRelationshipIdentifiers(params.relationshipData, { api })
|
|
48
57
|
|
|
49
58
|
// Check permissions
|
|
50
59
|
await runHooks('checkPermissions')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { validatePostPayload } from '../lib/querying-writing/payload-validators.js'
|
|
2
1
|
import { processRelationships } from '../lib/writing/relationship-processor.js'
|
|
2
|
+
import { getRequestContracts, validateRequestContractOrThrow } from '../lib/querying-writing/request-contracts.js'
|
|
3
3
|
import { createPivotRecords } from '../lib/writing/many-to-many-manipulations.js'
|
|
4
|
+
import { requireDocumentResourceId } from '../lib/querying-writing/resource-id-normalization.js'
|
|
4
5
|
import {
|
|
5
6
|
setupCommonRequest,
|
|
6
7
|
validateResourceAttributesBeforeWrite,
|
|
@@ -50,16 +51,28 @@ export default async function postMethod ({
|
|
|
50
51
|
await runHooks('beforeProcessing')
|
|
51
52
|
await runHooks('beforeProcessingPost')
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
const requestContracts = getRequestContracts({
|
|
55
|
+
scopeName,
|
|
56
|
+
schemaInfo: context.schemaInfo,
|
|
57
|
+
includeDepthLimit: vars.includeDepthLimit,
|
|
58
|
+
sortableFields: vars.sortableFields
|
|
59
|
+
})
|
|
60
|
+
context.inputRecord = validateRequestContractOrThrow(
|
|
61
|
+
requestContracts.post,
|
|
62
|
+
context.inputRecord,
|
|
63
|
+
'POST request body is invalid'
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if (context.inputRecord?.data?.id !== undefined) {
|
|
67
|
+
context.inputRecord.data.id = requireDocumentResourceId(context.inputRecord.data.id, {
|
|
68
|
+
scopeOptions,
|
|
69
|
+
vars
|
|
70
|
+
})
|
|
71
|
+
}
|
|
59
72
|
|
|
60
73
|
// Validate that user has read access to all related resources
|
|
61
74
|
// This ensures users can only create relationships to resources they can access
|
|
62
|
-
await validateRelationshipAccess(context, context.inputRecord, helpers,
|
|
75
|
+
await validateRelationshipAccess(context, context.inputRecord, helpers, api)
|
|
63
76
|
|
|
64
77
|
// Extract foreign keys from JSON:API relationships and prepare many-to-many operations
|
|
65
78
|
// Example: relationships.author -> author_id: '123' for storage
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { RestApiResourceError } from '../../../lib/rest-api-errors.js'
|
|
2
|
-
import { validatePutPayload } from '../lib/querying-writing/payload-validators.js'
|
|
1
|
+
import { RestApiResourceError, RestApiValidationError } from '../../../lib/rest-api-errors.js'
|
|
3
2
|
import { processRelationships } from '../lib/writing/relationship-processor.js'
|
|
4
3
|
import { updateManyToManyRelationship, createPivotRecords } from '../lib/writing/many-to-many-manipulations.js'
|
|
5
4
|
import { ERROR_SUBTYPES } from '../lib/querying-writing/knex-constants.js'
|
|
5
|
+
import { getRequestContracts, validateRequestContractOrThrow } from '../lib/querying-writing/request-contracts.js'
|
|
6
|
+
import {
|
|
7
|
+
requireDocumentResourceId,
|
|
8
|
+
requireExistingResourceId
|
|
9
|
+
} from '../lib/querying-writing/resource-id-normalization.js'
|
|
6
10
|
import {
|
|
7
11
|
setupCommonRequest,
|
|
12
|
+
validateCompleteReplacePayload,
|
|
8
13
|
validateResourceAttributesBeforeWrite,
|
|
9
14
|
validateRelationshipAccess,
|
|
10
15
|
applyFieldSetters,
|
|
@@ -17,7 +22,9 @@ import {
|
|
|
17
22
|
* PUT
|
|
18
23
|
* Updates an existing top-level resource by completely replacing it.
|
|
19
24
|
* This method supports updating both attributes and relationships (1:1 and n:n).
|
|
20
|
-
*
|
|
25
|
+
* Existing persisted values cannot be silently dropped: if a stored attribute or belongsTo
|
|
26
|
+
* relationship already has a value, PUT must include it explicitly. Relationship collections
|
|
27
|
+
* still follow replacement semantics when a relationships object is provided.
|
|
21
28
|
* This method does NOT support creating new related resources via an `included` array.
|
|
22
29
|
*/
|
|
23
30
|
export default async function putMethod ({
|
|
@@ -48,23 +55,63 @@ export default async function putMethod ({
|
|
|
48
55
|
api,
|
|
49
56
|
helpers
|
|
50
57
|
})
|
|
51
|
-
context.id = context.inputRecord.data.id
|
|
52
|
-
|
|
53
58
|
// Run early hooks for pre-processing (e.g., file handling)
|
|
54
59
|
await runHooks('beforeProcessing')
|
|
55
60
|
await runHooks('beforeProcessingPut')
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const requestContracts = getRequestContracts({
|
|
63
|
+
scopeName,
|
|
64
|
+
schemaInfo: context.schemaInfo,
|
|
65
|
+
includeDepthLimit: vars.includeDepthLimit,
|
|
66
|
+
sortableFields: vars.sortableFields
|
|
67
|
+
})
|
|
68
|
+
const normalizedPathId = params.id === undefined
|
|
69
|
+
? null
|
|
70
|
+
: requireExistingResourceId(params.id, {
|
|
71
|
+
scopeOptions,
|
|
72
|
+
vars,
|
|
73
|
+
scopeName
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
if (normalizedPathId && !context.inputRecord?.data?.id) {
|
|
77
|
+
context.inputRecord = {
|
|
78
|
+
...context.inputRecord,
|
|
79
|
+
data: {
|
|
80
|
+
...(context.inputRecord?.data || {}),
|
|
81
|
+
id: normalizedPathId
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
context.inputRecord = validateRequestContractOrThrow(
|
|
87
|
+
requestContracts.put,
|
|
88
|
+
context.inputRecord,
|
|
89
|
+
'PUT request body is invalid'
|
|
90
|
+
)
|
|
91
|
+
const normalizedBodyId = requireDocumentResourceId(context.inputRecord.data.id, {
|
|
92
|
+
scopeOptions,
|
|
93
|
+
vars
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
if (normalizedPathId && normalizedPathId !== normalizedBodyId) {
|
|
97
|
+
throw new RestApiValidationError(
|
|
98
|
+
`ID mismatch. URL path ID '${normalizedPathId}' does not match request body ID '${normalizedBodyId}'`,
|
|
99
|
+
{
|
|
100
|
+
fields: ['data.id'],
|
|
101
|
+
violations: [{
|
|
102
|
+
field: 'data.id',
|
|
103
|
+
rule: 'id_consistency',
|
|
104
|
+
message: 'Request body ID must match URL path ID when both are provided'
|
|
105
|
+
}]
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
context.inputRecord.data.id = normalizedBodyId
|
|
110
|
+
context.id = normalizedPathId || normalizedBodyId
|
|
64
111
|
|
|
65
112
|
// Validate that user has read access to all related resources
|
|
66
113
|
// This ensures users can only create relationships to resources they can access
|
|
67
|
-
await validateRelationshipAccess(context, context.inputRecord, helpers,
|
|
114
|
+
await validateRelationshipAccess(context, context.inputRecord, helpers, api)
|
|
68
115
|
|
|
69
116
|
// Extract foreign keys from JSON:API relationships and prepare many-to-many operations
|
|
70
117
|
// Example: relationships.author -> author_id: '123' for storage
|
|
@@ -74,13 +121,6 @@ export default async function putMethod ({
|
|
|
74
121
|
{ context }
|
|
75
122
|
)
|
|
76
123
|
|
|
77
|
-
await validateResourceAttributesBeforeWrite({
|
|
78
|
-
context,
|
|
79
|
-
schema,
|
|
80
|
-
belongsToUpdates,
|
|
81
|
-
runHooks
|
|
82
|
-
})
|
|
83
|
-
|
|
84
124
|
// Check existence first
|
|
85
125
|
context.exists = await helpers.dataExists({
|
|
86
126
|
scopeName,
|
|
@@ -108,8 +148,20 @@ export default async function putMethod ({
|
|
|
108
148
|
context.minimalRecord = minimalRecord
|
|
109
149
|
}
|
|
110
150
|
|
|
151
|
+
validateCompleteReplacePayload({
|
|
152
|
+
context,
|
|
153
|
+
belongsToUpdates
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
await validateResourceAttributesBeforeWrite({
|
|
157
|
+
context,
|
|
158
|
+
schema,
|
|
159
|
+
belongsToUpdates,
|
|
160
|
+
runHooks
|
|
161
|
+
})
|
|
162
|
+
|
|
111
163
|
// For PUT, we also need to handle relationships that are NOT provided
|
|
112
|
-
// (they should be set to null/empty
|
|
164
|
+
// (they should be set to null/empty when a relationships object is provided)
|
|
113
165
|
const allRelationships = {}
|
|
114
166
|
|
|
115
167
|
// Collect all defined relationships for this resource
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RestApiValidationError } from '../../../lib/rest-api-errors.js'
|
|
2
|
-
import { validateQueryPayload } from '../lib/querying-writing/payload-validators.js'
|
|
3
1
|
import { normalizeRecordAttributes } from '../lib/querying-writing/database-value-normalizers.js'
|
|
4
2
|
import { getRequestedComputedFields } from '../lib/querying-writing/knex-field-helpers.js'
|
|
3
|
+
import { getEffectiveSortableFields } from '../lib/querying/query-field-sort-helpers.js'
|
|
5
4
|
import { transformJsonApiToSimplified } from '../lib/querying-writing/simplified-helpers.js'
|
|
5
|
+
import { getRequestContracts, validateRequestContractOrThrow } from '../lib/querying-writing/request-contracts.js'
|
|
6
6
|
import { cascadeConfig } from './common.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -61,66 +61,28 @@ export default async function queryMethod ({
|
|
|
61
61
|
context.scopeName = scopeName
|
|
62
62
|
|
|
63
63
|
// These are just shortcuts used in this function and will be returned
|
|
64
|
-
const searchSchema = context.schemaInfo.searchSchemaInstance
|
|
65
64
|
const schemaStructure = context.schemaInfo.schemaInstance.structure
|
|
66
65
|
const schemaRelationships = context.schemaInfo.schemaRelationships
|
|
67
66
|
|
|
68
67
|
// Sortable fields and sort (mab)
|
|
69
|
-
context.sortableFields = vars
|
|
68
|
+
context.sortableFields = getEffectiveSortableFields(vars)
|
|
70
69
|
// Apply default sort if no sort specified
|
|
71
70
|
if (context.queryParams.sort.length === 0 && vars.defaultSort) {
|
|
72
71
|
context.queryParams.sort = Array.isArray(vars.defaultSort) ? vars.defaultSort : [vars.defaultSort]
|
|
73
72
|
}
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`Filtering is not enabled for resource '${scopeName}'. To enable filtering, add 'search: true' to schema fields or define a searchSchema.`,
|
|
88
|
-
{
|
|
89
|
-
fields: Object.keys(context.queryParams.filters).map(field => `filters.${field}`),
|
|
90
|
-
violations: [{
|
|
91
|
-
field: 'filters',
|
|
92
|
-
rule: 'filtering_not_enabled',
|
|
93
|
-
message: 'Resource does not have searchable fields defined'
|
|
94
|
-
}]
|
|
95
|
-
}
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Validate the filter parameters searchSchema
|
|
100
|
-
const { validatedObject, errors } = await searchSchema.validate(context.queryParams.filters, {
|
|
101
|
-
onlyObjectValues: true // Partial validation for filters
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
// If there are validation errors, throw an error
|
|
105
|
-
if (Object.keys(errors).length > 0) {
|
|
106
|
-
const violations = Object.entries(errors).map(([field, error]) => ({
|
|
107
|
-
field: `filters.${field}`,
|
|
108
|
-
rule: error.code || 'invalid_value',
|
|
109
|
-
message: error.message
|
|
110
|
-
}))
|
|
111
|
-
|
|
112
|
-
throw new RestApiValidationError(
|
|
113
|
-
'Invalid filter parameters',
|
|
114
|
-
{
|
|
115
|
-
fields: Object.keys(errors).map(field => `filters.${field}`),
|
|
116
|
-
violations
|
|
117
|
-
}
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Replace filter with validated/transformed values
|
|
122
|
-
context.queryParams.filters = validatedObject
|
|
123
|
-
}
|
|
74
|
+
const requestContracts = getRequestContracts({
|
|
75
|
+
scopeName,
|
|
76
|
+
schemaInfo: context.schemaInfo,
|
|
77
|
+
includeDepthLimit: vars.includeDepthLimit,
|
|
78
|
+
sortableFields: context.sortableFields
|
|
79
|
+
})
|
|
80
|
+
const validatedRequest = validateRequestContractOrThrow(
|
|
81
|
+
requestContracts.query,
|
|
82
|
+
{ queryParams: context.queryParams },
|
|
83
|
+
'Query parameters are invalid'
|
|
84
|
+
)
|
|
85
|
+
context.queryParams = validatedRequest.queryParams || {}
|
|
124
86
|
|
|
125
87
|
// Centralised checkPermissions function
|
|
126
88
|
await scope.checkPermissions({
|
|
@@ -16,6 +16,7 @@ import patchMethod from './rest-api-plugin-methods/patch.js'
|
|
|
16
16
|
import deleteMethod from './rest-api-plugin-methods/delete.js'
|
|
17
17
|
import enrichAttributesMethod from './rest-api-plugin-methods/enrich-attributes.js'
|
|
18
18
|
import checkPermissionsMethod from './rest-api-plugin-methods/check-permissions.js'
|
|
19
|
+
import applyQueryFiltersMethod from './rest-api-plugin-methods/apply-query-filters.js'
|
|
19
20
|
import addRouteMethod from './rest-api-plugin-methods/add-route.js'
|
|
20
21
|
import releaseMethod from './rest-api-plugin-methods/release.js'
|
|
21
22
|
import { defaultDataHelpers } from './lib/querying-writing/default-data-helpers.js'
|
|
@@ -26,6 +27,7 @@ import postRelationshipMethod from './rest-api-plugin-methods/post-relationship.
|
|
|
26
27
|
import getRelationshipMethod from './rest-api-plugin-methods/get-relationship.js'
|
|
27
28
|
import patchRelationshipMethod from './rest-api-plugin-methods/patch-relationship.js'
|
|
28
29
|
import deleteRelationshipMethod from './rest-api-plugin-methods/delete-relationship.js'
|
|
30
|
+
import { defaultNormalizeResourceId } from './lib/querying-writing/resource-id-normalization.js'
|
|
29
31
|
|
|
30
32
|
export const RestApiPlugin = {
|
|
31
33
|
name: 'rest-api',
|
|
@@ -65,6 +67,9 @@ export const RestApiPlugin = {
|
|
|
65
67
|
: true // Default true for better DX in programmatic API
|
|
66
68
|
|
|
67
69
|
vars.idProperty = restApiOptions.idProperty || 'id'
|
|
70
|
+
vars.normalizeId = typeof restApiOptions.normalizeId === 'function'
|
|
71
|
+
? restApiOptions.normalizeId
|
|
72
|
+
: defaultNormalizeResourceId
|
|
68
73
|
|
|
69
74
|
// Return full record configuration for API and Transport
|
|
70
75
|
// Support values: 'no', 'minimal', 'full'
|
|
@@ -148,6 +153,7 @@ export const RestApiPlugin = {
|
|
|
148
153
|
// Non-URL methods
|
|
149
154
|
addScopeMethod('enrichAttributes', enrichAttributesMethod)
|
|
150
155
|
addScopeMethod('checkPermissions', checkPermissionsMethod)
|
|
156
|
+
addScopeMethod('applyQueryFilters', applyQueryFiltersMethod)
|
|
151
157
|
|
|
152
158
|
// *********
|
|
153
159
|
// Helpers
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
calculatePosition,
|
|
3
3
|
getInitialPosition,
|
|
4
|
-
isValidPosition,
|
|
5
|
-
assignInitialPositions,
|
|
6
4
|
} from './lib/fractional-positioning.js'
|
|
7
5
|
import { createStorageAdapter } from './lib/storage/storage-adapter.js'
|
|
8
6
|
|
|
@@ -27,7 +25,7 @@ export const PositioningPlugin = {
|
|
|
27
25
|
// Get configuration - hooked-api namespaces options by plugin name
|
|
28
26
|
const positioningOptions = pluginOptions || {}
|
|
29
27
|
|
|
30
|
-
// Store configuration in vars (data only)
|
|
28
|
+
// Store configuration in vars (data only) so hooks can use it without re-reading plugin options.
|
|
31
29
|
vars.positioning = {
|
|
32
30
|
field: positioningOptions.field || 'position',
|
|
33
31
|
filters: positioningOptions.filters || [],
|
|
@@ -167,7 +165,7 @@ export const PositioningPlugin = {
|
|
|
167
165
|
fieldExists = true
|
|
168
166
|
} else {
|
|
169
167
|
// Check if it's a relationship name (as property)
|
|
170
|
-
for (const [
|
|
168
|
+
for (const [, fieldDef] of Object.entries(schema)) {
|
|
171
169
|
if (fieldDef.as === filterField) {
|
|
172
170
|
fieldExists = true
|
|
173
171
|
break
|
|
@@ -419,7 +417,6 @@ export const PositioningPlugin = {
|
|
|
419
417
|
log.debug('*** Position filter conditions', { scopeName, filterConditions })
|
|
420
418
|
|
|
421
419
|
// Query existing items in the same position group
|
|
422
|
-
const knex = api.knex.instance
|
|
423
420
|
const tableName = adapter.getTableName()
|
|
424
421
|
const idProperty = schemaInfo.idProperty
|
|
425
422
|
const idColumn = adapter.getIdColumn()
|