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.
Files changed (290) hide show
  1. package/CLAUDE.md +1 -2
  2. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +180 -0
  3. package/README.md +22 -1
  4. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
  5. package/docs/API.md +196 -38
  6. package/docs/COMPARISON.md +2 -2
  7. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +111 -5
  8. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +5 -1
  9. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +3 -1
  10. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +12 -60
  11. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +2 -2
  12. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +5 -1
  13. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +2 -0
  14. package/docs/GUIDE/GUIDE_X_Autofiltering.md +355 -0
  15. package/docs/GUIDE/GUIDE_X_Fastify.md +78 -0
  16. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +370 -0
  17. package/docs/GUIDE/GUIDE_X_Query_Projections.md +159 -0
  18. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +199 -0
  19. package/docs/GUIDE/index.md +18 -9
  20. package/docs/QUICKSTART.md +5 -1
  21. package/docs/index.md +1 -1
  22. package/index.js +3 -2
  23. package/lib/enhanced-logger.js +1 -1
  24. package/package.json +6 -2
  25. package/plugins/core/bulk-operations-plugin.js +26 -34
  26. package/plugins/core/connectors/express-plugin.js +97 -190
  27. package/plugins/core/connectors/fastify-plugin.js +206 -0
  28. package/plugins/core/connectors/lib/busboy-detector.js +4 -4
  29. package/plugins/core/connectors/lib/connector-core.js +195 -0
  30. package/plugins/core/connectors/lib/transport-http-helpers.js +122 -0
  31. package/plugins/core/connectors/lib/transport-route-schemas.js +92 -0
  32. package/plugins/core/lib/anyapi/schema-utils.js +43 -4
  33. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +4 -1
  34. package/plugins/core/lib/dbIntrospection.js +1078 -0
  35. package/plugins/core/lib/dbTablesOperations.js +1111 -160
  36. package/plugins/core/lib/querying/knex-cross-table-search.js +0 -7
  37. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -3
  38. package/plugins/core/lib/querying/knex-process-includes.js +3 -4
  39. package/plugins/core/lib/querying/knex-query-helpers.js +21 -76
  40. package/plugins/core/lib/querying/knex-relationship-includes.js +468 -215
  41. package/plugins/core/lib/querying/query-builder-utils.js +19 -0
  42. package/plugins/core/lib/querying/query-field-sort-helpers.js +135 -0
  43. package/plugins/core/lib/querying/sort-helpers.js +33 -0
  44. package/plugins/core/lib/querying/storage-adapter-utils.js +51 -0
  45. package/plugins/core/lib/querying/url-helpers.js +8 -2
  46. package/plugins/core/lib/querying-writing/compile-schemas.js +20 -5
  47. package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -14
  48. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +13 -12
  49. package/plugins/core/lib/querying-writing/query-field-helpers.js +88 -0
  50. package/plugins/core/lib/querying-writing/request-contracts.js +590 -0
  51. package/plugins/core/lib/querying-writing/resource-id-normalization.js +131 -0
  52. package/plugins/core/lib/querying-writing/schema-helpers.js +0 -2
  53. package/plugins/core/lib/querying-writing/simplified-helpers.js +4 -11
  54. package/plugins/core/lib/storage/canonical-storage-mapping.js +133 -0
  55. package/plugins/core/lib/storage/storage-adapter.js +82 -4
  56. package/plugins/core/lib/storage/storage-mapping.js +274 -0
  57. package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -2
  58. package/plugins/core/rest-api-anyapi-knex-plugin.js +531 -312
  59. package/plugins/core/rest-api-autofilter-plugin.js +414 -0
  60. package/plugins/core/rest-api-knex-plugin.js +271 -226
  61. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +10 -5
  62. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +12 -6
  63. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +1 -0
  64. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
  65. package/plugins/core/rest-api-plugin-methods/common.js +148 -92
  66. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +11 -2
  67. package/plugins/core/rest-api-plugin-methods/delete.js +6 -1
  68. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
  69. package/plugins/core/rest-api-plugin-methods/get-related.js +7 -2
  70. package/plugins/core/rest-api-plugin-methods/get-relationship.js +7 -2
  71. package/plugins/core/rest-api-plugin-methods/get.js +29 -14
  72. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +10 -3
  73. package/plugins/core/rest-api-plugin-methods/patch.js +56 -12
  74. package/plugins/core/rest-api-plugin-methods/post-relationship.js +11 -2
  75. package/plugins/core/rest-api-plugin-methods/post.js +21 -8
  76. package/plugins/core/rest-api-plugin-methods/put.js +73 -21
  77. package/plugins/core/rest-api-plugin-methods/query.js +15 -53
  78. package/plugins/core/rest-api-plugin-methods/release.js +0 -2
  79. package/plugins/core/rest-api-plugin.js +6 -0
  80. package/plugins/core/rest-api-positioning-plugin.js +2 -5
  81. package/plugins/core/rest-api-query-projections-plugin.js +130 -0
  82. package/plugins/core/socketio-plugin.js +1 -4
  83. package/plugins/storage/local-storage.js +1 -1
  84. package/plugins/storage/s3-storage.js +5 -2
  85. package/quickTest.js +1 -0
  86. package/scripts/run-docs.js +80 -84
  87. package/test-debug.js +1 -1
  88. package/tests/README.md +7 -0
  89. package/tests/anyapi-basic.test.js +3 -0
  90. package/tests/autofilter.test.js +463 -0
  91. package/tests/custom-id-mysql-returning-fallback.test.js +128 -0
  92. package/tests/custom-id-simplified-post.test.js +75 -0
  93. package/tests/custom-idproperty-relationships.test.js +33 -0
  94. package/tests/db-introspection.test.js +521 -0
  95. package/tests/db-table-operations.test.js +786 -0
  96. package/tests/fastify-plugin.test.js +156 -0
  97. package/tests/field-getters.test.js +1 -2
  98. package/tests/field-setters.test.js +0 -4
  99. package/tests/fixtures/api-configs.js +278 -176
  100. package/tests/helpers/fake-fastify.js +99 -0
  101. package/tests/http-connectors-parity.test.js +235 -0
  102. package/tests/id-normalization.test.js +444 -0
  103. package/tests/logical-id-write-validation.test.js +151 -0
  104. package/tests/pagination-cursor-multifield.test.js +11 -11
  105. package/tests/projected-fields.test.js +319 -0
  106. package/tests/relationships.test.js +3 -3
  107. package/tests/searchschema-knex-behavior.test.js +187 -0
  108. package/tests/searchschema-merge.test.js +21 -69
  109. package/tests/storage-mapping.test.js +259 -0
  110. package/audit/00-charter.md +0 -103
  111. package/audit/01-scope-map.md +0 -84
  112. package/audit/02-coverage-matrix.csv +0 -174
  113. package/audit/03-invariants.md +0 -123
  114. package/audit/04-standards-rubric.md +0 -56
  115. package/audit/05-competitor-rubric.md +0 -77
  116. package/audit/06-findings.md +0 -160
  117. package/audit/07-risk-register.csv +0 -10
  118. package/audit/08-remediation-roadmap.md +0 -177
  119. package/audit/09-signoff-check.md +0 -23
  120. package/audit/10-final-synthesis.md +0 -29
  121. package/audit/evidence/code/all-files-json-rest-api.txt +0 -168
  122. package/audit/evidence/code/all-files-json-rest-schema.txt +0 -12
  123. package/audit/evidence/code/boundary-leak-checks.txt +0 -72
  124. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +0 -480
  125. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +0 -532
  126. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +0 -175
  127. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +0 -138
  128. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +0 -222
  129. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +0 -342
  130. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +0 -304
  131. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +0 -188
  132. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +0 -336
  133. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +0 -165
  134. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +0 -265
  135. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +0 -369
  136. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +0 -72
  137. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +0 -139
  138. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +0 -45
  139. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +0 -396
  140. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +0 -162
  141. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +0 -1314
  142. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +0 -488
  143. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +0 -484
  144. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +0 -857
  145. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +0 -565
  146. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +0 -485
  147. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +0 -560
  148. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +0 -167
  149. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +0 -109
  150. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +0 -1064
  151. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +0 -1983
  152. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +0 -328
  153. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +0 -119
  154. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +0 -160
  155. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +0 -300
  156. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +0 -245
  157. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +0 -459
  158. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +0 -237
  159. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +0 -1135
  160. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +0 -314
  161. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +0 -7
  162. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +0 -71
  163. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +0 -102
  164. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +0 -49
  165. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +0 -39
  166. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +0 -23
  167. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +0 -13
  168. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +0 -639
  169. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +0 -117
  170. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +0 -104
  171. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +0 -199
  172. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +0 -353
  173. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +0 -61
  174. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +0 -184
  175. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +0 -55
  176. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +0 -191
  177. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +0 -110
  178. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +0 -168
  179. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +0 -253
  180. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +0 -207
  181. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +0 -12
  182. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +0 -165
  183. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +0 -668
  184. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +0 -621
  185. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +0 -218
  186. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +0 -124
  187. package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +0 -269
  188. package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +0 -242
  189. package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +0 -77
  190. package/audit/evidence/code/critical-pass1-risk-keywords.txt +0 -238
  191. package/audit/evidence/code/critical-pass1-summary.csv +0 -67
  192. package/audit/evidence/code/critical-pass2-summary.csv +0 -67
  193. package/audit/evidence/code/early-silent-zones-no-test-token.txt +0 -57
  194. package/audit/evidence/code/error-model-signals.txt +0 -98
  195. package/audit/evidence/code/git-files-json-rest-api.txt +0 -171
  196. package/audit/evidence/code/git-files-json-rest-schema.txt +0 -27
  197. package/audit/evidence/code/hook-flow-signals.txt +0 -282
  198. package/audit/evidence/code/idproperty-signals.txt +0 -157
  199. package/audit/evidence/code/import-cycles-non-anyapi.txt +0 -3
  200. package/audit/evidence/code/import-hotspots-non-anyapi.txt +0 -96
  201. package/audit/evidence/code/imports-json-rest-api.txt +0 -354
  202. package/audit/evidence/code/imports-json-rest-schema.txt +0 -15
  203. package/audit/evidence/code/in-scope-files-json-rest-api.txt +0 -160
  204. package/audit/evidence/code/in-scope-files-json-rest-schema.txt +0 -13
  205. package/audit/evidence/code/non-anyapi-core-files.txt +0 -101
  206. package/audit/evidence/code/permission-signals.txt +0 -193
  207. package/audit/evidence/code/query-include-signals.txt +0 -687
  208. package/audit/evidence/code/transaction-signals.txt +0 -28
  209. package/audit/evidence/code/validation-signals.txt +0 -650
  210. package/audit/evidence/code/write-path-signals.txt +0 -61
  211. package/audit/evidence/docs/docs-claims-signals.txt +0 -1075
  212. package/audit/evidence/docs/schema-docs-claims-signals.txt +0 -179
  213. package/audit/evidence/external/corpus-freeze.md +0 -21
  214. package/audit/evidence/external/npm-competitor-metadata.txt +0 -70
  215. package/audit/evidence/external/npm-download-signals.txt +0 -23
  216. package/audit/evidence/external/npm-jsonapi-server.txt +0 -8
  217. package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +0 -38
  218. package/audit/evidence/external/readme-fortune-signals.txt +0 -26
  219. package/audit/evidence/external/readme-fortune.md +0 -165
  220. package/audit/evidence/external/readme-json-api-serializer-signals.txt +0 -80
  221. package/audit/evidence/external/readme-json-api-serializer.md +0 -690
  222. package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
  223. package/audit/evidence/external/readme-jsonapi-serde-server.md +0 -22
  224. package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +0 -63
  225. package/audit/evidence/external/readme-jsonapi-serializer.md +0 -315
  226. package/audit/evidence/external/readme-jsonapi-server-signals.txt +0 -19
  227. package/audit/evidence/external/readme-jsonapi-server.md +0 -104
  228. package/audit/evidence/external/readme-nestjs-json-api-signals.txt +0 -4
  229. package/audit/evidence/external/readme-nestjs-json-api.md +0 -94
  230. package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +0 -47
  231. package/audit/evidence/external/readme-yaser-json-api-nestjs.md +0 -447
  232. package/audit/evidence/external/standard-jsonapi-snippets.txt +0 -84
  233. package/audit/evidence/external/standard-rfc-snippets.txt +0 -168
  234. package/audit/evidence/external/standards-sources.txt +0 -6
  235. package/audit/evidence/runtime/baseline-commits.txt +0 -2
  236. package/audit/evidence/runtime/db-adapter-assumptions.txt +0 -3
  237. package/audit/evidence/runtime/environment.txt +0 -4
  238. package/audit/evidence/runtime/invariant-runtime-mapping.md +0 -38
  239. package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +0 -1
  240. package/audit/evidence/runtime/probe-patch-relationship-error.log +0 -76
  241. package/audit/evidence/runtime/probe-patch-relationship-error.mjs +0 -67
  242. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +0 -1
  243. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +0 -62
  244. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +0 -47
  245. package/audit/evidence/runtime/test-exitcodes.txt +0 -4
  246. package/audit/evidence/runtime/test-summary.md +0 -107
  247. package/audit/evidence/runtime/trace-anchors.txt +0 -61
  248. package/audit/evidence/tests/access-multitenancy-test-signals.txt +0 -125
  249. package/audit/evidence/tests/failing-tests-summary.txt +0 -25
  250. package/audit/evidence/tests/npm-test-json-rest-api.exitcode +0 -1
  251. package/audit/evidence/tests/npm-test-json-rest-api.log +0 -5885
  252. package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +0 -1
  253. package/audit/evidence/tests/npm-test-json-rest-schema.log +0 -356
  254. package/audit/evidence/tests/query-include-test-signals.txt +0 -948
  255. package/audit/evidence/tests/relationship-test-signals.txt +0 -223
  256. package/audit/evidence/tests/skipped-tests.txt +0 -10
  257. package/audit/evidence/tests/test-suite-list-non-anyapi.txt +0 -30
  258. package/audit/evidence/tests/test-suite-list.txt +0 -32
  259. package/audit/subsystems/docs-drift.md +0 -49
  260. package/audit/subsystems/pass2-cross-review.md +0 -131
  261. package/audit/subsystems/plugins-access.md +0 -51
  262. package/audit/subsystems/plugins-bulk.md +0 -50
  263. package/audit/subsystems/plugins-cors.md +0 -48
  264. package/audit/subsystems/plugins-file.md +0 -53
  265. package/audit/subsystems/plugins-multihome.md +0 -50
  266. package/audit/subsystems/plugins-positioning.md +0 -54
  267. package/audit/subsystems/plugins-socketio.md +0 -50
  268. package/audit/subsystems/query-engine.md +0 -61
  269. package/audit/subsystems/relationships.md +0 -55
  270. package/audit/subsystems/rest-orchestration.md +0 -66
  271. package/audit/subsystems/schema-core.md +0 -64
  272. package/audit/subsystems/storage-knex.md +0 -57
  273. package/audit/subsystems/tests.md +0 -48
  274. package/audit/subsystems/transport-express.md +0 -55
  275. package/audit/traces/trace-read-get.md +0 -22
  276. package/audit/traces/trace-read-query.md +0 -25
  277. package/audit/traces/trace-relationship-endpoints.md +0 -31
  278. package/audit/traces/trace-write-delete.md +0 -17
  279. package/audit/traces/trace-write-patch.md +0 -26
  280. package/audit/traces/trace-write-post.md +0 -22
  281. package/audit/traces/trace-write-put.md +0 -23
  282. package/docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md +0 -707
  283. package/docs/GUIDE/GUIDE_X_Multihome.md +0 -666
  284. package/plugins/core/lib/querying-writing/payload-validators.js +0 -1314
  285. package/plugins/core/rest-api-access.js +0 -459
  286. package/plugins/core/rest-api-multihome-plugin.js +0 -314
  287. package/tests/multihome.test.js +0 -553
  288. package/tests/multihome.test.js.bak +0 -550
  289. package/tests/ownership-optout.test.js +0 -76
  290. package/tests/rest-api-access.test.js +0 -206
@@ -314,66 +314,17 @@ await api.resources.books.put({
314
314
  // publisher_id and genres NOT included!
315
315
  });
316
316
  ```
317
- **Effects on the database:**
317
+ **Result: request rejected**
318
318
 
319
- | Table | Changes |
320
- |-------|---------|
321
- | **books** | • title: Updated<br>• author_id: Remains 1 (Tolkien)<br>• publisher_id: **SET TO NULL** |
322
- | **book_genres** | **ALL 3 RECORDS DELETED** - Book no longer has any genres |
323
- | **Other books** | **NO CHANGES** - LOTR and Silmarillion unchanged |
319
+ PUT now fails fast when you omit a persisted field that already has a stored value. Since this book already has a `publisher_id`, leaving it out would silently discard data, so the API rejects the request instead of clearing it.
324
320
 
325
- Again, PUT is a **complete replacement** operation. Since we didn't include `publisher_id` or `genres` in our request, the API treats this as "I want a book with no publisher and no genres." The result:
326
- - `publisher_id` becomes NULL (it's nullable, so this is allowed)
327
- - All genre relationships are removed from the pivot table
328
- - Missing fields are NOT preserved from the current state - they're cleared
321
+ Relationship collections still follow replacement semantics when you provide a `relationships` object. The rejection in this example happens because `publisher_id` is an existing stored belongsTo value that was omitted entirely.
329
322
 
330
323
  **Expected output**
331
324
 
332
325
  ```text
333
- Book state BEFORE the change: {
334
- id: '1',
335
- title: 'The Hobbit',
336
- isbn: '9780547928227',
337
- published_year: 1937,
338
- page_count: 310,
339
- genres_ids: [ '1', '2', '3' ],
340
- genres: [
341
- { id: '1', name: 'Fantasy' },
342
- { id: '2', name: 'Adventure' },
343
- { id: '3', name: 'Classic' }
344
- ],
345
- author_id: '1',
346
- author: {
347
- id: '1',
348
- name: 'J.R.R.',
349
- surname: 'Tolkien',
350
- birth_year: 1892,
351
- books_ids: []
352
- },
353
- publisher_id: '1',
354
- publisher: {
355
- id: '1',
356
- name: 'Penguin Random House',
357
- country: 'USA',
358
- books_ids: []
359
- }
360
- }
361
- Book state AFTER the change: {
362
- id: '1',
363
- title: 'The Hobbit - Revised',
364
- isbn: '9780547928227',
365
- published_year: 1937,
366
- page_count: 310,
367
- genres_ids: [],
368
- author_id: '1',
369
- author: {
370
- id: '1',
371
- name: 'J.R.R.',
372
- surname: 'Tolkien',
373
- birth_year: 1892,
374
- books_ids: []
375
- }
376
- }
326
+ RestApiValidationError: PUT request omits persisted fields that already have stored values
327
+ fields: [ 'data.attributes.publisher_id' ]
377
328
  ```
378
329
 
379
330
  ### Example 3: PUT with Explicit Nulls
@@ -400,9 +351,10 @@ await api.resources.books.put({
400
351
  | **book_genres** | **ALL 3 RECORDS DELETED** |
401
352
  | **Other books** | **NO CHANGES** |
402
353
 
403
- This example shows PUT with **explicit nulls and empty arrays**. There's no difference between omitting a field and explicitly setting it to null/[] in a PUT operation - both result in clearing the data. This reinforces that PUT is about **complete state replacement**:
354
+ This example shows PUT with **explicit nulls and empty arrays**. Explicit clearing is still allowed when the schema permits it, but it must be intentional. This reinforces that PUT is about **complete state replacement**:
404
355
  - You must include ALL data you want to keep
405
- - Anything missing or null is cleared
356
+ - Existing stored values are not cleared by omission; omission is rejected
357
+ - Explicit `null` / `[]` is how you clear data intentionally
406
358
  - Required fields (like `author_id`) must always be provided and cannot be null
407
359
 
408
360
 
@@ -782,8 +734,8 @@ This preservation is crucial for:
782
734
  ## Best Practices
783
735
 
784
736
  1. **Use PATCH for targeted updates** - When you only want to change specific fields
785
- 2. **Use PUT when replacing everything** - When you have the complete new state
786
- 3. **Always include relationships you want to keep with PUT** - They will be cleared otherwise
737
+ 2. **Use PUT when replacing everything** - When you are explicitly resending the stored values you want to keep
738
+ 3. **Always include existing stored fields you want to preserve with PUT** - Omitted persisted values are rejected
787
739
  4. **Remember required fields** - PUT must include all required fields like author_id
788
740
  5. **Child records are independent** - Other books by the same author are never affected
789
741
 
@@ -791,6 +743,6 @@ This preservation is crucial for:
791
743
 
792
744
  Now that you understand how updates affect relationships:
793
745
  - Practice with PATCH for surgical updates
794
- - Use PUT for complete replacements
746
+ - Use PUT for explicit full-state replacements
795
747
  - Plan your API calls to avoid unintended data loss
796
- - Remember that the intelligent sync preserves pivot table metadata
748
+ - Remember that the intelligent sync preserves pivot table metadata
@@ -49,7 +49,7 @@ This guide has been split into the following sections for easier navigation:
49
49
 
50
50
  ## [2.8 Effects of PUT and PATCH](./GUIDE_2_8_Effects_of_PUT_and_PATCH.md)
51
51
  - Understanding the difference between PUT and PATCH
52
- - How PUT affects relationships (complete replacement)
52
+ - How PUT affects relationships and existing stored fields
53
53
  - How PATCH affects relationships (partial updates)
54
54
  - Managing belongsTo relationships
55
55
  - Handling hasMany relationships
@@ -63,4 +63,4 @@ This guide has been split into the following sections for easier navigation:
63
63
 
64
64
  ---
65
65
 
66
- [Back to Guide](./index.md)
66
+ [Back to Guide](./index.md)
@@ -11,6 +11,8 @@ Field transformations allow you to:
11
11
  - Calculate values from other fields (computed fields)
12
12
  - Control which fields are visible in responses (hidden fields)
13
13
 
14
+ For SQL-backed derived values that must participate in sorting or cursor pagination, use [Query Projections](GUIDE_X_Query_Projections.md). Those are query-layer fields, not normal computed fields.
15
+
14
16
  ## The Data Transformation Pipeline
15
17
 
16
18
  Understanding when each transformation occurs is crucial for building robust APIs:
@@ -235,6 +237,8 @@ setter: (value, context) => {
235
237
 
236
238
  Computed fields are output-only fields calculated from other fields. They're never stored and always calculated fresh when requested.
237
239
 
240
+ If a derived field must participate in SQL list behavior such as sorting or cursor pagination, use a query projection instead. Query projections are documented separately in [Query Projections](GUIDE_X_Query_Projections.md).
241
+
238
242
  ### Basic Computed Fields
239
243
 
240
244
  ```javascript
@@ -1243,4 +1247,4 @@ Common uses:
1243
1247
  - Title case formatting
1244
1248
  - Password hashing
1245
1249
  - Price calculations
1246
- - Data consistency across related records
1250
+ - Data consistency across related records
@@ -2,6 +2,8 @@
2
2
 
3
3
  This guide provides a comprehensive reference for all hooks available in the json-rest-api system, including system-wide hooks from hooked-api and method-specific hooks from the REST API plugin.
4
4
 
5
+ If you are building a reusable plugin rather than just attaching hooks to one API, see [Writing Plugins](GUIDE_X_Writing_Plugins.md). This guide focuses on hook behavior; the plugin guide focuses on the supported extension surface.
6
+
5
7
  An important concept when working with hooks is understanding how simplified mode affects data flow.
6
8
 
7
9
  Inside hooks, JSON:API format is king _regardless of simplified mode_.
@@ -0,0 +1,355 @@
1
+ # Autofiltering
2
+
3
+ The `AutoFilterPlugin` provides declarative dataset scoping for `json-rest-api`.
4
+
5
+ It does one job:
6
+
7
+ - resolve scope values from request/runtime context
8
+ - apply those values as automatic filters
9
+ - stamp scoped fields on create
10
+ - preserve scoped fields on replace
11
+ - reject inconsistent scoped-field updates
12
+
13
+ It does **not** define authentication, roles, or permissions.
14
+
15
+ ## Overview
16
+
17
+ Autofiltering is useful whenever a resource should be constrained by one or more persisted fields:
18
+
19
+ - `workspace_id`
20
+ - `user_id`
21
+ - `workspace_id + user_id`
22
+ - any other application-defined scope field
23
+
24
+ The plugin is generic. It does not assume:
25
+
26
+ - `context.auth`
27
+ - `authenticated`
28
+ - `admin`
29
+ - JWTs
30
+ - sessions
31
+
32
+ Your application decides where scope values come from. The plugin only consumes configured resolver functions.
33
+
34
+ ## Installation
35
+
36
+ ```js
37
+ import { Api } from 'hooked-api'
38
+ import {
39
+ RestApiPlugin,
40
+ RestApiKnexPlugin,
41
+ AutoFilterPlugin
42
+ } from 'json-rest-api'
43
+
44
+ const api = new Api({ name: 'scoped-api' })
45
+
46
+ await api.use(RestApiPlugin)
47
+ await api.use(RestApiKnexPlugin, { knex })
48
+
49
+ await api.use(AutoFilterPlugin, {
50
+ resolvers: {
51
+ workspace: ({ context }) => context.session?.workspaceId,
52
+ user: ({ context }) => context.subject?.id,
53
+ },
54
+
55
+ presets: {
56
+ public: { filters: [] },
57
+
58
+ workspace: {
59
+ filters: [
60
+ { field: 'workspace_id', resolver: 'workspace' }
61
+ ]
62
+ },
63
+
64
+ user: {
65
+ filters: [
66
+ { field: 'user_id', resolver: 'user' }
67
+ ]
68
+ },
69
+
70
+ workspace_user: {
71
+ filters: [
72
+ { field: 'workspace_id', resolver: 'workspace' },
73
+ { field: 'user_id', resolver: 'user' }
74
+ ]
75
+ }
76
+ }
77
+ })
78
+ ```
79
+
80
+ ## Resource Configuration
81
+
82
+ Apply a preset by name:
83
+
84
+ ```js
85
+ await api.addResource('projects', {
86
+ schema: {
87
+ id: { type: 'id' },
88
+ name: { type: 'string', required: true },
89
+ workspace_id: { type: 'string', required: true },
90
+ user_id: { type: 'number', required: true }
91
+ },
92
+ autofilter: 'workspace_user'
93
+ })
94
+ ```
95
+
96
+ Use a preset with extra filters:
97
+
98
+ ```js
99
+ await api.addResource('documents', {
100
+ schema: {
101
+ id: { type: 'id' },
102
+ workspace_id: { type: 'string', required: true },
103
+ user_id: { type: 'number', required: true },
104
+ locale: { type: 'string', required: true }
105
+ },
106
+ autofilter: {
107
+ preset: 'workspace_user',
108
+ filters: [
109
+ {
110
+ field: 'locale',
111
+ resolve: ({ context }) => context.requestState?.locale
112
+ }
113
+ ]
114
+ }
115
+ })
116
+ ```
117
+
118
+ Use inline filters with no preset:
119
+
120
+ ```js
121
+ await api.addResource('reports', {
122
+ schema: {
123
+ id: { type: 'id' },
124
+ account_id: { type: 'string', required: true }
125
+ },
126
+ autofilter: {
127
+ filters: [
128
+ {
129
+ field: 'account_id',
130
+ resolve: ({ context }) => context.scopeValues?.accountId
131
+ }
132
+ ]
133
+ }
134
+ })
135
+ ```
136
+
137
+ Declare a public resource explicitly:
138
+
139
+ ```js
140
+ await api.addResource('system_settings', {
141
+ schema: {
142
+ id: { type: 'id' },
143
+ key: { type: 'string', required: true },
144
+ value: { type: 'string', required: true }
145
+ },
146
+ autofilter: 'public'
147
+ })
148
+ ```
149
+
150
+ If a resource has no `autofilter` setting, the plugin does nothing for that resource.
151
+
152
+ ## Runtime Behavior
153
+
154
+ ### Query Scoping
155
+
156
+ Collection queries automatically receive all configured filters.
157
+
158
+ For a `workspace_user` resource:
159
+
160
+ ```js
161
+ await api.resources.projects.query(
162
+ { simplified: false },
163
+ {
164
+ session: { workspaceId: 'acme' },
165
+ subject: { id: 101 }
166
+ }
167
+ )
168
+ ```
169
+
170
+ behaves like:
171
+
172
+ ```sql
173
+ SELECT * FROM projects
174
+ WHERE workspace_id = 'acme'
175
+ AND user_id = 101
176
+ ```
177
+
178
+ ### Single-Record Scoping
179
+
180
+ `get`, `put`, `patch`, and `delete` operate on the already-scoped dataset.
181
+
182
+ If a record is outside the current scope, it behaves as not found.
183
+
184
+ ### Create-Time Stamping
185
+
186
+ On `POST`, scoped fields are injected automatically when missing.
187
+
188
+ Example:
189
+
190
+ ```js
191
+ await api.resources.projects.post({
192
+ inputRecord: {
193
+ data: {
194
+ type: 'projects',
195
+ attributes: {
196
+ name: 'Roadmap'
197
+ }
198
+ }
199
+ },
200
+ simplified: false
201
+ }, {
202
+ session: { workspaceId: 'acme' },
203
+ subject: { id: 101 }
204
+ })
205
+ ```
206
+
207
+ Stored attributes:
208
+
209
+ ```js
210
+ {
211
+ name: 'Roadmap',
212
+ workspace_id: 'acme',
213
+ user_id: 101
214
+ }
215
+ ```
216
+
217
+ ### Replace/Update Consistency
218
+
219
+ On `PUT`:
220
+
221
+ - missing scoped fields are injected so replacement stays consistent
222
+ - mismatched scoped fields are rejected
223
+
224
+ On `PATCH`:
225
+
226
+ - omitted scoped fields stay omitted
227
+ - explicitly provided mismatched scoped fields are rejected
228
+
229
+ ## Relationship-Aware Scoping
230
+
231
+ Autofiltering also affects relationship validation because scoped single-record lookups are used when checking related resources.
232
+
233
+ So this will fail if the referenced project is outside scope:
234
+
235
+ ```js
236
+ await api.resources.tasks.post({
237
+ inputRecord: {
238
+ data: {
239
+ type: 'tasks',
240
+ attributes: { title: 'Cross-scope task' },
241
+ relationships: {
242
+ project: {
243
+ data: { type: 'projects', id: '123' }
244
+ }
245
+ }
246
+ }
247
+ },
248
+ simplified: false
249
+ }, {
250
+ scopeValues: {
251
+ workspaceId: 'workspace-a',
252
+ userId: 101
253
+ }
254
+ })
255
+ ```
256
+
257
+ ## Missing Scope Values
258
+
259
+ By default, each filter is required.
260
+
261
+ If a resolver returns `undefined`, the plugin throws:
262
+
263
+ ```text
264
+ Missing autofilter value for resolver 'workspace' on resource 'projects'
265
+ ```
266
+
267
+ To make a filter optional, set `required: false`:
268
+
269
+ ```js
270
+ {
271
+ field: 'workspace_id',
272
+ resolver: 'workspace',
273
+ required: false
274
+ }
275
+ ```
276
+
277
+ When `required: false` and the resolver returns `undefined`, that filter is skipped.
278
+
279
+ ## BelongsTo Foreign Keys
280
+
281
+ If the scoped field is a `belongsTo` foreign key with an alias, the plugin works through the JSON:API relationship shape.
282
+
283
+ Example:
284
+
285
+ ```js
286
+ user_id: {
287
+ type: 'number',
288
+ belongsTo: 'users',
289
+ as: 'user'
290
+ }
291
+ ```
292
+
293
+ The plugin will stamp or validate:
294
+
295
+ ```js
296
+ data.relationships.user.data.id
297
+ ```
298
+
299
+ instead of treating it as a direct client-owned attribute.
300
+
301
+ ## Storage Mapping
302
+
303
+ Autofiltering uses the compiled storage adapter automatically.
304
+
305
+ So this works correctly:
306
+
307
+ ```js
308
+ workspace_id: {
309
+ type: 'string',
310
+ storage: { column: 'workspace_key' }
311
+ }
312
+ ```
313
+
314
+ The plugin scopes using the logical field name, while Knex filtering uses the mapped storage column.
315
+
316
+ ## Introspection Helpers
317
+
318
+ The plugin exposes light runtime inspection helpers:
319
+
320
+ ```js
321
+ api.autofilter.getConfig()
322
+ api.autofilter.getScopeConfig('projects')
323
+ ```
324
+
325
+ Example:
326
+
327
+ ```js
328
+ api.autofilter.getScopeConfig('projects')
329
+ // {
330
+ // preset: 'workspace_user',
331
+ // filters: [
332
+ // { field: 'workspace_id', resolver: 'workspace', required: true },
333
+ // { field: 'user_id', resolver: 'user', required: true }
334
+ // ]
335
+ // }
336
+ ```
337
+
338
+ ## Design Boundary
339
+
340
+ `AutoFilterPlugin` is intentionally narrower than an auth plugin.
341
+
342
+ It owns:
343
+
344
+ - dataset scoping
345
+ - scoped-field stamping
346
+ - scoped-field consistency
347
+
348
+ It does **not** own:
349
+
350
+ - authentication meaning
351
+ - role policy
352
+ - admission checks
353
+ - permissions like `authenticated` or `owns`
354
+
355
+ That logic belongs in higher layers or custom `checkPermissions` hooks.
@@ -0,0 +1,78 @@
1
+ # Fastify Integration
2
+
3
+ `json-rest-api` now ships a Fastify-oriented connector:
4
+
5
+ ```js
6
+ import fastify from 'fastify'
7
+ import {
8
+ RestApiPlugin,
9
+ RestApiKnexPlugin,
10
+ FastifyPlugin
11
+ } from 'json-rest-api'
12
+
13
+ const app = fastify()
14
+
15
+ await api.use(RestApiPlugin, {
16
+ simplifiedApi: false,
17
+ simplifiedTransport: false
18
+ })
19
+
20
+ await api.use(RestApiKnexPlugin, { knex })
21
+
22
+ await api.use(FastifyPlugin, {
23
+ app,
24
+ mountPath: '/api'
25
+ })
26
+ ```
27
+
28
+ ## What the connector does
29
+
30
+ The Fastify connector listens to the same `addRoute` hook as the Express connector and registers the generated REST routes on the Fastify instance you pass in `pluginOptions.app`.
31
+
32
+ It also consumes the transport schema exported by `json-rest-schema` before the request reaches the resource method:
33
+
34
+ - `POST` routes use the schema export in `create` mode
35
+ - `PUT` routes use the schema export in `replace` mode
36
+ - `PATCH` routes use the schema export in `patch` mode
37
+ - relationship `POST` / `PATCH` / `DELETE` routes use JSON:API relationship document schemas
38
+
39
+ Those field schemas are wrapped in the JSON:API document envelope expected by `json-rest-api`.
40
+
41
+ ## What gets rejected early
42
+
43
+ Fastify can now stop malformed write payloads before they reach the app layer:
44
+
45
+ - missing `data`
46
+ - invalid `data.type`
47
+ - invalid `data.id` on `PUT` / `PATCH`
48
+ - malformed attribute payloads
49
+ - unknown attribute fields
50
+ - invalid scalar types according to the resource schema
51
+ - malformed relationship write documents
52
+
53
+ The transport schema also reflects the existing write contract:
54
+
55
+ - output-only computed fields are removed from `data.attributes`
56
+ - direct `belongsTo` foreign keys are removed from `data.attributes`
57
+ - relationship linkage still belongs under `data.relationships`
58
+
59
+ This keeps Fastify transport validation aligned with the same transport rules already enforced by the runtime methods.
60
+
61
+ ## Content types
62
+
63
+ The connector registers an `application/vnd.api+json` parser and rejects unsupported write content types before the route handler runs.
64
+
65
+ Accepted write content types are:
66
+
67
+ - `application/vnd.api+json`
68
+ - `application/json`
69
+
70
+ ## Scope
71
+
72
+ This connector is intentionally narrow:
73
+
74
+ - it uses the exported schema already owned by `json-rest-schema`
75
+ - it does not add a JSKIT-specific compatibility layer
76
+ - it does not move business validation out of the resource methods
77
+
78
+ The goal is transport-level shape rejection, not a second validation system.