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
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export const QueryProjectionsPlugin = {
|
|
2
|
+
name: 'query-projections',
|
|
3
|
+
dependencies: ['rest-api'],
|
|
4
|
+
|
|
5
|
+
install ({ addHook, log }) {
|
|
6
|
+
const normalizeQueryFields = ({ scopeName, scopeOptions = {} }) => {
|
|
7
|
+
const schema = scopeOptions.schema || {}
|
|
8
|
+
const relationships = scopeOptions.relationships || {}
|
|
9
|
+
const rawQueryFields = scopeOptions.queryFields || {}
|
|
10
|
+
const normalized = {}
|
|
11
|
+
const reservedNames = new Set(Object.keys(schema))
|
|
12
|
+
|
|
13
|
+
if (!rawQueryFields || typeof rawQueryFields !== 'object' || Array.isArray(rawQueryFields)) {
|
|
14
|
+
throw new Error(`Invalid queryFields configuration for scope '${scopeName}'. Expected an object.`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (const relName of Object.keys(relationships)) {
|
|
18
|
+
reservedNames.add(relName)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const fieldDef of Object.values(schema)) {
|
|
22
|
+
if (fieldDef?.belongsTo && fieldDef?.as) {
|
|
23
|
+
reservedNames.add(fieldDef.as)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const [fieldName, fieldDef] of Object.entries(rawQueryFields)) {
|
|
28
|
+
if (!fieldDef || typeof fieldDef !== 'object' || Array.isArray(fieldDef)) {
|
|
29
|
+
throw new Error(`Query field '${fieldName}' in scope '${scopeName}' must be an object.`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (reservedNames.has(fieldName)) {
|
|
33
|
+
throw new Error(`Query field '${fieldName}' in scope '${scopeName}' conflicts with an existing schema or relationship name.`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!fieldDef.type) {
|
|
37
|
+
throw new Error(`Query field '${fieldName}' in scope '${scopeName}' must have a type.`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const select = fieldDef.select || fieldDef.project
|
|
41
|
+
if (typeof select !== 'function') {
|
|
42
|
+
throw new Error(`Query field '${fieldName}' in scope '${scopeName}' must define a select() function.`)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
normalized[fieldName] = {
|
|
46
|
+
...fieldDef,
|
|
47
|
+
select,
|
|
48
|
+
sortable: fieldDef.sortable === true,
|
|
49
|
+
hidden: fieldDef.hidden === true,
|
|
50
|
+
normallyHidden: fieldDef.normallyHidden === true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return normalized
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const stripQueryFieldInput = ({ context, scopeName, scope, scopes }) => {
|
|
58
|
+
const inputAttributes = context?.inputRecord?.data?.attributes
|
|
59
|
+
const queryFields = scopes?.[scopeName]?.vars?.queryFields || scope?.vars?.queryFields || {}
|
|
60
|
+
|
|
61
|
+
if (!inputAttributes || typeof inputAttributes !== 'object' || Array.isArray(inputAttributes)) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const stripped = []
|
|
66
|
+
for (const fieldName of Object.keys(queryFields)) {
|
|
67
|
+
if (Object.hasOwn(inputAttributes, fieldName)) {
|
|
68
|
+
delete inputAttributes[fieldName]
|
|
69
|
+
stripped.push(fieldName)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (stripped.length > 0) {
|
|
74
|
+
const message = `Query fields [${stripped.join(', ')}] were sent in input for resource '${scopeName}' but will be ignored as they are query output only`
|
|
75
|
+
if (typeof log?.warn === 'function') {
|
|
76
|
+
log.warn(message)
|
|
77
|
+
} else {
|
|
78
|
+
console.warn(message)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const validateCompiledQueryFieldNamespace = ({ scopeName, scope, vars, scopes }) => {
|
|
84
|
+
const activeScope = scope || scopes?.[scopeName]
|
|
85
|
+
const scopeVars = vars || activeScope?.vars || {}
|
|
86
|
+
const queryFields = scopeVars.queryFields || {}
|
|
87
|
+
const schemaInfo = activeScope?.vars?.schemaInfo || scopeVars.schemaInfo || {}
|
|
88
|
+
|
|
89
|
+
if (Object.keys(queryFields).length === 0) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const reservedNames = new Set([
|
|
94
|
+
...Object.keys(schemaInfo.schemaStructure || {}),
|
|
95
|
+
...Object.keys(schemaInfo.computed || {}),
|
|
96
|
+
...Object.keys(schemaInfo.schemaRelationships || {})
|
|
97
|
+
])
|
|
98
|
+
|
|
99
|
+
for (const fieldDef of Object.values(schemaInfo.schemaStructure || {})) {
|
|
100
|
+
if (fieldDef?.belongsTo && fieldDef?.as) {
|
|
101
|
+
reservedNames.add(fieldDef.as)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const fieldName of Object.keys(queryFields)) {
|
|
106
|
+
if (reservedNames.has(fieldName)) {
|
|
107
|
+
throw new Error(`Query field '${fieldName}' in scope '${scopeName}' conflicts with an existing schema, computed, or relationship name.`)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
addHook('scope:added', 'compile-query-projections', { afterFunction: 'turnScopeInitIntoVars' }, ({ context, scopes }) => {
|
|
113
|
+
const scopeName = context.scopeName
|
|
114
|
+
const scope = scopes[scopeName]
|
|
115
|
+
const vars = scope?.vars || {}
|
|
116
|
+
const scopeOptions = scope?.scopeOptions || context.scopeOptions || {}
|
|
117
|
+
const queryFields = normalizeQueryFields({ scopeName, scopeOptions })
|
|
118
|
+
|
|
119
|
+
vars.queryFields = queryFields
|
|
120
|
+
validateCompiledQueryFieldNamespace({ scopeName, scope, vars, scopes })
|
|
121
|
+
|
|
122
|
+
log.debug(`Compiled query fields for '${scopeName}'`, {
|
|
123
|
+
queryFields: Object.keys(queryFields),
|
|
124
|
+
sortable: Object.keys(queryFields).filter((fieldName) => queryFields[fieldName].sortable === true)
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
addHook('beforeSchemaValidate', 'strip-query-field-input', {}, stripQueryFieldInput)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -206,9 +206,7 @@ async function registerSubscription ({
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
const { validatedObject, errors } = await searchSchemaInstance.
|
|
210
|
-
onlyObjectValues: true
|
|
211
|
-
})
|
|
209
|
+
const { validatedObject, errors } = await searchSchemaInstance.patch(validatedFilters)
|
|
212
210
|
|
|
213
211
|
if (errors && Object.keys(errors).length > 0) {
|
|
214
212
|
const error = new Error('Invalid filter values')
|
|
@@ -395,7 +393,6 @@ export const SocketIOPlugin = {
|
|
|
395
393
|
let io
|
|
396
394
|
|
|
397
395
|
api.startSocketServer = async (server, startOptions = {}) => {
|
|
398
|
-
const transportConfig = { ...config.transport, ...startOptions.transport }
|
|
399
396
|
const authConfig = { ...config.auth, ...(startOptions.auth || {}) }
|
|
400
397
|
const redisConfig = startOptions.redis ?? pluginOptions.redis ?? null
|
|
401
398
|
|
|
@@ -92,7 +92,7 @@ export class LocalStorage {
|
|
|
92
92
|
return filename
|
|
93
93
|
// Remove path traversal attempts
|
|
94
94
|
.replace(/\.\./g, '')
|
|
95
|
-
.replace(/[
|
|
95
|
+
.replace(/[/\\]/g, '')
|
|
96
96
|
// Remove control characters and special chars
|
|
97
97
|
.replace(/[^\w\s.-]/g, '_')
|
|
98
98
|
// Remove leading/trailing dots and spaces
|
|
@@ -100,13 +100,16 @@ export class S3Storage {
|
|
|
100
100
|
* @returns {Promise<void>}
|
|
101
101
|
*/
|
|
102
102
|
async delete (url) {
|
|
103
|
-
// Extract key from URL
|
|
104
103
|
const urlObj = new URL(url)
|
|
105
|
-
const key = urlObj.pathname.substring(1) // Remove leading /
|
|
106
104
|
|
|
107
105
|
if (this.mockMode) {
|
|
108
106
|
// Mock mode - just simulate deletion
|
|
109
107
|
await new Promise(resolve => setTimeout(resolve, 50))
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (urlObj.pathname.length === 0) {
|
|
112
|
+
throw new Error('Invalid S3 object URL')
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
// Real S3 delete would go here
|
package/quickTest.js
CHANGED
|
@@ -70,6 +70,7 @@ const harperResult = await api.resources.publishers.post({
|
|
|
70
70
|
name: 'HarperCollins'
|
|
71
71
|
}
|
|
72
72
|
})
|
|
73
|
+
console.log('Created second publisher:', inspect(harperResult))
|
|
73
74
|
|
|
74
75
|
// Method 3: Full JSON:API mode (standards compliant)
|
|
75
76
|
const oxfordResult = await api.resources.publishers.post({
|
package/scripts/run-docs.js
CHANGED
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Run the documentation site
|
|
5
|
-
*
|
|
6
|
-
* This script:
|
|
7
|
-
* 1. Syncs documentation files
|
|
8
|
-
* 2. Builds the Jekyll site
|
|
9
|
-
* 3. Starts the server
|
|
10
|
-
* 4. Opens the browser
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
3
|
import { spawn } from 'child_process'
|
|
14
|
-
import { promises as fs } from 'fs'
|
|
15
4
|
import path from 'path'
|
|
16
5
|
import { fileURLToPath } from 'url'
|
|
17
6
|
|
|
18
7
|
const __filename = fileURLToPath(import.meta.url)
|
|
19
8
|
const __dirname = path.dirname(__filename)
|
|
20
9
|
const projectRoot = path.join(__dirname, '..')
|
|
10
|
+
const docsRoot = path.join(projectRoot, 'docs')
|
|
11
|
+
const LOCAL_URL = 'http://localhost:4000/json-rest-api/'
|
|
12
|
+
const BROWSER_DELAY_MS = 3000
|
|
21
13
|
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
function parseMode (argv = []) {
|
|
15
|
+
if (argv.includes('--serve') || argv.includes('--dev')) {
|
|
16
|
+
return 'serve'
|
|
17
|
+
}
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const GITHUB_PAGES_URL = 'https://mobily-enterprises.github.io/json-rest-api/'
|
|
19
|
+
return 'build'
|
|
20
|
+
}
|
|
28
21
|
|
|
29
22
|
async function runCommand (command, args, options = {}) {
|
|
30
23
|
return new Promise((resolve, reject) => {
|
|
@@ -38,100 +31,103 @@ async function runCommand (command, args, options = {}) {
|
|
|
38
31
|
proc.on('exit', (code) => {
|
|
39
32
|
if (code === 0) {
|
|
40
33
|
resolve()
|
|
41
|
-
|
|
42
|
-
reject(new Error(`Command failed with code ${code}`))
|
|
34
|
+
return
|
|
43
35
|
}
|
|
36
|
+
|
|
37
|
+
reject(new Error(`Command failed with code ${code}`))
|
|
44
38
|
})
|
|
45
39
|
})
|
|
46
40
|
}
|
|
47
41
|
|
|
42
|
+
async function ensureBundlerDependencies () {
|
|
43
|
+
try {
|
|
44
|
+
await runCommand('bundle', ['check'], { cwd: docsRoot })
|
|
45
|
+
} catch {
|
|
46
|
+
console.log('Installing Jekyll dependencies...')
|
|
47
|
+
await runCommand('bundle', ['install'], { cwd: docsRoot })
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
48
51
|
async function openBrowser (url) {
|
|
49
52
|
const platform = process.platform
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
command = 'start'
|
|
56
|
-
} else {
|
|
57
|
-
// Linux
|
|
58
|
-
command = 'xdg-open'
|
|
59
|
-
}
|
|
53
|
+
const command = platform === 'darwin'
|
|
54
|
+
? 'open'
|
|
55
|
+
: platform === 'win32'
|
|
56
|
+
? 'start'
|
|
57
|
+
: 'xdg-open'
|
|
60
58
|
|
|
61
59
|
try {
|
|
62
60
|
await runCommand(command, [url])
|
|
63
|
-
console.log(
|
|
64
|
-
} catch
|
|
65
|
-
console.log(
|
|
61
|
+
console.log(`Opened browser at ${url}`)
|
|
62
|
+
} catch {
|
|
63
|
+
console.log(`Visit ${url} in your browser`)
|
|
66
64
|
}
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
async function
|
|
70
|
-
console.log('
|
|
67
|
+
async function buildDocs () {
|
|
68
|
+
console.log('Building documentation site...')
|
|
69
|
+
await runCommand('bundle', ['exec', 'jekyll', 'build'], { cwd: docsRoot })
|
|
70
|
+
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
async function serveDocs () {
|
|
73
|
+
console.log('Starting documentation server...')
|
|
74
|
+
|
|
75
|
+
const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve', '--watch'], {
|
|
76
|
+
cwd: docsRoot,
|
|
77
|
+
stdio: 'pipe',
|
|
78
|
+
shell: true
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
jekyll.stdout.on('data', (data) => {
|
|
82
|
+
const output = data.toString()
|
|
83
|
+
process.stdout.write(output)
|
|
84
|
+
|
|
85
|
+
if (output.includes('Server running') || output.includes('Server address:')) {
|
|
86
|
+
setTimeout(() => openBrowser(LOCAL_URL), 1000)
|
|
84
87
|
}
|
|
88
|
+
})
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
cwd: path.join(projectRoot, 'docs'),
|
|
90
|
-
stdio: 'pipe',
|
|
91
|
-
shell: true
|
|
92
|
-
})
|
|
90
|
+
jekyll.stderr.on('data', (data) => {
|
|
91
|
+
process.stderr.write(data)
|
|
92
|
+
})
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
process.on('SIGINT', () => {
|
|
95
|
+
console.log('\nShutting down Jekyll server...')
|
|
96
|
+
jekyll.kill()
|
|
97
|
+
process.exit(0)
|
|
98
|
+
})
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
100
|
+
jekyll.on('error', (err) => {
|
|
101
|
+
console.error('Jekyll server error:', err)
|
|
102
|
+
process.exit(1)
|
|
103
|
+
})
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
jekyll.on('exit', (code) => {
|
|
106
|
+
if (code !== 0 && code !== null) {
|
|
107
|
+
console.error(`Jekyll server exited with code ${code}`)
|
|
108
|
+
process.exit(code)
|
|
109
|
+
}
|
|
110
|
+
})
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
console.log('\n\n👋 Shutting down Jekyll server...')
|
|
112
|
-
jekyll.kill()
|
|
113
|
-
process.exit(0)
|
|
114
|
-
})
|
|
112
|
+
setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY_MS)
|
|
113
|
+
}
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
process.exit(1)
|
|
119
|
-
})
|
|
115
|
+
async function main () {
|
|
116
|
+
const mode = parseMode(process.argv.slice(2))
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
try {
|
|
119
|
+
await ensureBundlerDependencies()
|
|
120
|
+
|
|
121
|
+
if (mode === 'serve') {
|
|
122
|
+
await serveDocs()
|
|
123
|
+
return
|
|
124
|
+
}
|
|
127
125
|
|
|
128
|
-
|
|
129
|
-
setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY)
|
|
126
|
+
await buildDocs()
|
|
130
127
|
} catch (error) {
|
|
131
|
-
console.error('
|
|
128
|
+
console.error('Error:', error.message)
|
|
132
129
|
process.exit(1)
|
|
133
130
|
}
|
|
134
131
|
}
|
|
135
132
|
|
|
136
|
-
// Run the script
|
|
137
133
|
main()
|
package/test-debug.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createBasicApi } from './tests/fixtures/api-configs.js'
|
|
2
|
-
import { cleanTables, createJsonApiDocument
|
|
2
|
+
import { cleanTables, createJsonApiDocument } from './tests/helpers/test-utils.js'
|
|
3
3
|
import knex from 'knex'
|
|
4
4
|
|
|
5
5
|
const dbConfig = {
|
package/tests/README.md
CHANGED
|
@@ -163,9 +163,16 @@ const result = await api.resources.books.query({
|
|
|
163
163
|
# Run all tests
|
|
164
164
|
npm test
|
|
165
165
|
|
|
166
|
+
# Run the focused normalizeId verification path plus docs rebuild
|
|
167
|
+
npm run verify
|
|
168
|
+
|
|
166
169
|
# Run all tests against the AnyAPI storage backend
|
|
167
170
|
npm run test:anyapi
|
|
168
171
|
|
|
172
|
+
# Run only the normalizeId contract suites
|
|
173
|
+
npm run test:id-contracts
|
|
174
|
+
npm run test:id-contracts:anyapi
|
|
175
|
+
|
|
169
176
|
# Windows PowerShell (AnyAPI run)
|
|
170
177
|
$Env:JSON_REST_API_STORAGE = 'anyapi'; npm test
|
|
171
178
|
|
|
@@ -70,6 +70,7 @@ describe('AnyAPI Knex Plugin - Basic Attributes', () => {
|
|
|
70
70
|
assert.equal(result.data.attributes.name, 'Australia')
|
|
71
71
|
|
|
72
72
|
const stored = await knex('any_records').first()
|
|
73
|
+
assert.equal(stored.logical_id, result.data.id)
|
|
73
74
|
assert.equal(stored.string_1, 'Australia')
|
|
74
75
|
assert.equal(stored.string_2, 'AU')
|
|
75
76
|
|
|
@@ -83,11 +84,13 @@ describe('AnyAPI Knex Plugin - Basic Attributes', () => {
|
|
|
83
84
|
|
|
84
85
|
it('lists records', async () => {
|
|
85
86
|
await knex('any_records').insert([{
|
|
87
|
+
logical_id: '1',
|
|
86
88
|
tenant_id: 'default',
|
|
87
89
|
resource: 'countries',
|
|
88
90
|
string_1: 'Canada',
|
|
89
91
|
string_2: 'CA',
|
|
90
92
|
}, {
|
|
93
|
+
logical_id: '2',
|
|
91
94
|
tenant_id: 'default',
|
|
92
95
|
resource: 'countries',
|
|
93
96
|
string_1: 'Brazil',
|