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
@@ -1,485 +0,0 @@
1
- 1 import { getForeignKeyFields as getForeignKeyFieldsFromUtils } from '../querying-writing/field-utils.js'
2
- 2 import { RELATIONSHIPS_KEY, RELATIONSHIP_METADATA_KEY, ROW_NUMBER_KEY, COMPUTED_DEPENDENCIES_KEY, getSchemaStructure } from '../querying-writing/knex-constants.js'
3
- 3 import { getUrlPrefix, buildResourceUrl, buildRelationshipUrl } from './url-helpers.js'
4
- 4
5
- 5 /**
6
- 6 * Transforms a flat database record into JSON:API resource format
7
- 7 *
8
- 8 * @private
9
- 9 * @param {Object} scope - Scope containing schema and configuration
10
- 10 * @param {Object} record - Database record to transform
11
- 11 * @param {Object} deps - Dependencies including context with scopeName and polymorphicFields
12
- 12 * @returns {Object|null} JSON:API resource object or null if no record
13
- 13 *
14
- 14 * @example
15
- 15 * // Input: Database record with foreign keys and internal fields
16
- 16 * const record = {
17
- 17 * id: 1,
18
- 18 * title: 'Hello World',
19
- 19 * content: 'Article content',
20
- 20 * author_id: 2, // Foreign key
21
- 21 * category_id: 5, // Foreign key
22
- 22 * __$jsonrestapi_rn$__: 1 // Internal field
23
- 23 * };
24
- 24 *
25
- 25 * const jsonApiResource = toJsonApi(scope, record, deps);
26
- 26 *
27
- 27 * // Output: Clean JSON:API resource
28
- 28 * // {
29
- 29 * // type: 'articles',
30
- 30 * // id: '1',
31
- 31 * // attributes: {
32
- 32 * // title: 'Hello World',
33
- 33 * // content: 'Article content'
34
- 34 * // // Note: author_id, category_id, and internal fields are removed
35
- 35 * // }
36
- 36 * // }
37
- 37 *
38
- 38 * @example
39
- 39 * // Input: Polymorphic record
40
- 40 * const record = {
41
- 41 * id: 10,
42
- 42 * text: 'Great article!',
43
- 43 * commentable_type: 'articles', // Polymorphic type field
44
- 44 * commentable_id: 1 // Polymorphic id field
45
- 45 * };
46
- 46 * // deps.context.polymorphicFields = Set(['commentable_type', 'commentable_id'])
47
- 47 *
48
- 48 * const jsonApiResource = toJsonApi(scope, record, deps);
49
- 49 *
50
- 50 * // Output: Polymorphic fields filtered out
51
- 51 * // {
52
- 52 * // type: 'comments',
53
- 53 * // id: '10',
54
- 54 * // attributes: {
55
- 55 * // text: 'Great article!'
56
- 56 * // }
57
- 57 * // }
58
- 58 *
59
- 59 * @description
60
- 60 * Used by:
61
- 61 * - toJsonApiRecord calls this as the core transformation logic
62
- 62 * - buildJsonApiResponse uses this indirectly through toJsonApiRecord
63
- 63 *
64
- 64 * Purpose:
65
- 65 * - Separates database structure from API structure
66
- 66 * - Filters out foreign keys that become relationships in JSON:API
67
- 67 * - Removes internal fields used for query optimization
68
- 68 * - Ensures clean attribute objects without implementation details
69
- 69 *
70
- 70 * Data flow:
71
- 71 * - Called after database query returns flat records
72
- 72 * - Transforms each record individually
73
- 73 * - Output feeds into relationship building and response assembly
74
- 74 */
75
- 75 const toJsonApi = (scope, record, deps) => {
76
- 76 if (!record) return null
77
- 77
78
- 78 const schemaInstance = scope.vars.schemaInfo.schemaInstance
79
- 79
80
- 80 const { context } = deps
81
- 81 const scopeName = context.scopeName
82
- 82 const idProperty = context.schemaInfo?.idProperty || 'id'
83
- 83 const polymorphicFields = context.polymorphicFields || new Set()
84
- 84
85
- 85 const { id, ...allAttributes } = record
86
- 86
87
- 87 const foreignKeys = schemaInstance ? getForeignKeyFieldsFromUtils(schemaInstance) : new Set()
88
- 88
89
- 89 const internalFields = new Set([
90
- 90 RELATIONSHIPS_KEY,
91
- 91 RELATIONSHIP_METADATA_KEY,
92
- 92 ROW_NUMBER_KEY,
93
- 93 COMPUTED_DEPENDENCIES_KEY
94
- 94 ])
95
- 95
96
- 96 const attributes = {}
97
- 97 Object.entries(allAttributes).forEach(([key, value]) => {
98
- 98 if (!foreignKeys.has(key) && !polymorphicFields.has(key) && !internalFields.has(key) && key !== idProperty) {
99
- 99 attributes[key] = value
100
- 100 }
101
- 101 })
102
- 102
103
- 103 return {
104
- 104 type: scopeName,
105
- 105 id: String(id),
106
- 106 attributes
107
- 107 }
108
- 108 }
109
- 109
110
- 110 /**
111
- 111 * Converts a database record to JSON:API format with proper field filtering
112
- 112 *
113
- 113 * @param {Object} scope - Scope containing schema and relationship definitions
114
- 114 * @param {Object} record - Raw database record
115
- 115 * @param {string} scopeName - Resource type name
116
- 116 * @returns {Object} JSON:API formatted resource
117
- 117 *
118
- 118 * @example
119
- 119 * // Input: Database record with various field types
120
- 120 * const record = {
121
- 121 * id: 1,
122
- 122 * title: 'My Article',
123
- 123 * author_id: 2, // belongsTo relationship
124
- 124 * category_id: 3, // belongsTo relationship
125
- 125 * views: 150,
126
- 126 * published: true
127
- 127 * };
128
- 128 *
129
- 129 * const jsonApi = toJsonApiRecord(scope, record, 'articles');
130
- 130 *
131
- 131 * // Output: Foreign keys filtered out
132
- 132 * // {
133
- 133 * // type: 'articles',
134
- 134 * // id: '1',
135
- 135 * // attributes: {
136
- 136 * // title: 'My Article',
137
- 137 * // views: 150,
138
- 138 * // published: true
139
- 139 * // }
140
- 140 * // }
141
- 141 *
142
- 142 * @example
143
- 143 * // Input: Record with polymorphic relationship
144
- 144 * const record = {
145
- 145 * id: 5,
146
- 146 * body: 'Nice post!',
147
- 147 * author_id: 10,
148
- 148 * commentable_type: 'posts', // Polymorphic
149
- 149 * commentable_id: 3 // Polymorphic
150
- 150 * };
151
- 151 * // Schema has polymorphic relationship defined
152
- 152 *
153
- 153 * const jsonApi = toJsonApiRecord(scope, record, 'comments');
154
- 154 *
155
- 155 * // Output: Both foreign keys and polymorphic fields filtered
156
- 156 * // {
157
- 157 * // type: 'comments',
158
- 158 * // id: '5',
159
- 159 * // attributes: {
160
- 160 * // body: 'Nice post!'
161
- 161 * // }
162
- 162 * // }
163
- 163 *
164
- 164 * @description
165
- 165 * Used by:
166
- 166 * - rest-api-knex-plugin's dataGet method for single resource responses
167
- 167 * - rest-api-knex-plugin's dataQuery method for collection responses
168
- 168 * - processIncludes when transforming included resources
169
- 169 * - buildJsonApiResponse as the primary transformation function
170
- 170 *
171
- 171 * Purpose:
172
- 172 * - Provides consistent JSON:API transformation across all query operations
173
- 173 * - Automatically identifies and filters foreign keys based on schema
174
- 174 * - Handles polymorphic relationship fields (type/id pairs)
175
- 175 * - Ensures IDs are always strings as required by JSON:API spec
176
- 176 *
177
- 177 * Data flow:
178
- 178 * 1. Database query returns flat records with all fields
179
- 179 * 2. toJsonApiRecord identifies foreign keys from schema
180
- 180 * 3. Filters out foreign keys and internal fields from attributes
181
- 181 * 4. Returns clean JSON:API resource ready for relationship processing
182
- 182 * 5. buildJsonApiResponse adds relationships and links to complete the response
183
- 183 */
184
- 184 export const toJsonApiRecord = (scope, record, scopeName) => {
185
- 185 const {
186
- 186 vars: {
187
- 187 schemaInfo: { schemaRelationships: relationships, idProperty }
188
- 188 }
189
- 189 } = scope
190
- 190
191
- 191 const polymorphicFields = new Set()
192
- 192 try {
193
- 193 Object.entries(relationships || {}).forEach(([relName, relDef]) => {
194
- 194 if (relDef.belongsToPolymorphic) {
195
- 195 const typeFieldName = relDef.belongsToPolymorphic.typeField || `${relName}_type`
196
- 196 const idFieldName = relDef.belongsToPolymorphic.idField || `${relName}_id`
197
- 197 polymorphicFields.add(typeFieldName)
198
- 198 polymorphicFields.add(idFieldName)
199
- 199 }
200
- 200 })
201
- 201 } catch (e) {
202
- 202 }
203
- 203
204
- 204 const deps = {
205
- 205 context: {
206
- 206 scopeName,
207
- 207 schemaInfo: { idProperty },
208
- 208 polymorphicFields
209
- 209 }
210
- 210 }
211
- 211
212
- 212 return toJsonApi(scope, record, deps)
213
- 213 }
214
- 214
215
- 215 /**
216
- 216 * Builds complete JSON:API response with data, relationships, links, and optional includes
217
- 217 *
218
- 218 * @async
219
- 219 * @param {Object} scope - Scope containing schema and configuration
220
- 220 * @param {Array<Object>} records - Primary records to include in response
221
- 221 * @param {Array<Object>} included - Resources to include in 'included' array
222
- 222 * @param {boolean} isSingle - Whether this is a single resource response
223
- 223 * @param {string} scopeName - Resource type name
224
- 224 * @param {Object} context - Request context with pagination metadata
225
- 225 * @returns {Promise<Object>} Complete JSON:API response document
226
- 226 *
227
- 227 * @example
228
- 228 * // Input: Single article with author include
229
- 229 * const records = [{
230
- 230 * id: 1,
231
- 231 * title: 'Article Title',
232
- 232 * content: 'Article content',
233
- 233 * author_id: 2,
234
- 234 * category_id: 3
235
- 235 * }];
236
- 236 *
237
- 237 * const included = [{
238
- 238 * type: 'authors',
239
- 239 * id: '2',
240
- 240 * attributes: { name: 'John Doe', email: 'john@example.com' }
241
- 241 * }];
242
- 242 *
243
- 243 * const response = await buildJsonApiResponse(scope, records, included, true, 'articles', context);
244
- 244 *
245
- 245 * // Output: Complete JSON:API document
246
- 246 * // {
247
- 247 * // data: {
248
- 248 * // type: 'articles',
249
- 249 * // id: '1',
250
- 250 * // attributes: {
251
- 251 * // title: 'Article Title',
252
- 252 * // content: 'Article content'
253
- 253 * // },
254
- 254 * // relationships: {
255
- 255 * // author: {
256
- 256 * // data: { type: 'authors', id: '2' },
257
- 257 * // links: {
258
- 258 * // self: '/articles/1/relationships/author',
259
- 259 * // related: '/articles/1/author'
260
- 260 * // }
261
- 261 * // },
262
- 262 * // category: {
263
- 263 * // data: { type: 'categories', id: '3' },
264
- 264 * // links: {
265
- 265 * // self: '/articles/1/relationships/category',
266
- 266 * // related: '/articles/1/category'
267
- 267 * // }
268
- 268 * // }
269
- 269 * // },
270
- 270 * // links: {
271
- 271 * // self: '/articles/1'
272
- 272 * // }
273
- 273 * // },
274
- 274 * // included: [{
275
- 275 * // type: 'authors',
276
- 276 * // id: '2',
277
- 277 * // attributes: { name: 'John Doe', email: 'john@example.com' },
278
- 278 * // links: { self: '/authors/2' }
279
- 279 * // }],
280
- 280 * // links: {
281
- 281 * // self: '/articles/1'
282
- 282 * // }
283
- 283 * // }
284
- 284 *
285
- 285 * @example
286
- 286 * // Input: Collection with pagination
287
- 287 * const records = [
288
- 288 * { id: 1, title: 'Article 1', author_id: 10 },
289
- 289 * { id: 2, title: 'Article 2', author_id: 10 },
290
- 290 * { id: 3, title: 'Article 3', author_id: 11 }
291
- 291 * ];
292
- 292 *
293
- 293 * context.returnMeta = {
294
- 294 * paginationMeta: { page: 2, pageSize: 3, pageCount: 10, total: 30 },
295
- 295 * paginationLinks: {
296
- 296 * self: '/articles?page[number]=2&page[size]=3',
297
- 297 * first: '/articles?page[number]=1&page[size]=3',
298
- 298 * prev: '/articles?page[number]=1&page[size]=3',
299
- 299 * next: '/articles?page[number]=3&page[size]=3',
300
- 300 * last: '/articles?page[number]=10&page[size]=3'
301
- 301 * }
302
- 302 * };
303
- 303 *
304
- 304 * const response = await buildJsonApiResponse(scope, records, [], false, 'articles', context);
305
- 305 *
306
- 306 * // Output: Collection with pagination metadata
307
- 307 * // {
308
- 308 * // data: [
309
- 309 * // { type: 'articles', id: '1', attributes: { title: 'Article 1' }, ... },
310
- 310 * // { type: 'articles', id: '2', attributes: { title: 'Article 2' }, ... },
311
- 311 * // { type: 'articles', id: '3', attributes: { title: 'Article 3' }, ... }
312
- 312 * // ],
313
- 313 * // meta: {
314
- 314 * // pagination: { page: 2, pageSize: 3, pageCount: 10, total: 30 }
315
- 315 * // },
316
- 316 * // links: {
317
- 317 * // self: '/articles?page[number]=2&page[size]=3',
318
- 318 * // first: '/articles?page[number]=1&page[size]=3',
319
- 319 * // prev: '/articles?page[number]=1&page[size]=3',
320
- 320 * // next: '/articles?page[number]=3&page[size]=3',
321
- 321 * // last: '/articles?page[number]=10&page[size]=3'
322
- 322 * // }
323
- 323 * // }
324
- 324 *
325
- 325 * @description
326
- 326 * Used by:
327
- 327 * - rest-api-knex-plugin's dataGet method for single resource responses
328
- 328 * - rest-api-knex-plugin's dataQuery method for collection responses
329
- 329 * - Called at the end of the query pipeline to assemble the final response
330
- 330 *
331
- 331 * Purpose:
332
- 332 * - Assembles all parts of a JSON:API response in the correct structure
333
- 333 * - Adds relationship objects with proper links for each foreign key
334
- 334 * - Handles both regular belongsTo and polymorphic relationships
335
- 335 * - Adds self links to all resources as required by JSON:API
336
- 336 * - Includes pagination metadata and links when applicable
337
- 337 *
338
- 338 * Data flow:
339
- 339 * 1. Query operations fetch primary records and optional includes
340
- 340 * 2. Records are transformed to JSON:API format via toJsonApiRecord
341
- 341 * 3. buildJsonApiResponse adds relationship objects for all foreign keys
342
- 342 * 4. Adds proper links (self, related) for navigating the API
343
- 343 * 5. Assembles included resources with their own links
344
- 344 * 6. Adds pagination metadata and links if provided
345
- 345 * 7. Returns complete JSON:API document ready for HTTP response
346
- 346 */
347
- 347 export const buildJsonApiResponse = async (scope, records, included = [], isSingle = false, scopeName, context) => {
348
- 348 const {
349
- 349 vars: {
350
- 350 schemaInfo: { schemaInstance, schemaRelationships: relationships, idProperty }
351
- 351 }
352
- 352 } = scope
353
- 353
354
- 354 const idField = idProperty || 'id'
355
- 355
356
- 356 const schemaStructure = getSchemaStructure(schemaInstance)
357
- 357
358
- 358 const processedRecords = records.map(record => {
359
- 359 const { [RELATIONSHIPS_KEY]: _relationships, ...cleanRecord } = record
360
- 360 const jsonApiRecord = toJsonApiRecord(scope, cleanRecord, scopeName)
361
- 361
362
- 362 if (_relationships) {
363
- 363 jsonApiRecord.relationships = _relationships
364
- 364 }
365
- 365
366
- 366 for (const [fieldName, fieldDef] of Object.entries(schemaStructure)) {
367
- 367 if (fieldDef.belongsTo && fieldDef.as && fieldName in cleanRecord) {
368
- 368 jsonApiRecord.relationships = jsonApiRecord.relationships || {}
369
- 369 if (!jsonApiRecord.relationships[fieldDef.as]) {
370
- 370 if (cleanRecord[fieldName] !== null && cleanRecord[fieldName] !== undefined) {
371
- 371 const relationshipObject = {
372
- 372 data: {
373
- 373 type: fieldDef.belongsTo,
374
- 374 id: String(cleanRecord[fieldName])
375
- 375 }
376
- 376 }
377
- 377
378
- 378 relationshipObject.links = {
379
- 379 self: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, true),
380
- 380 related: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, false)
381
- 381 }
382
- 382
383
- 383 jsonApiRecord.relationships[fieldDef.as] = relationshipObject
384
- 384 } else {
385
- 385 const relationshipObject = {
386
- 386 data: null
387
- 387 }
388
- 388
389
- 389 relationshipObject.links = {
390
- 390 self: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, true),
391
- 391 related: buildRelationshipUrl(context, scope, scopeName, record[idField], fieldDef.as, false)
392
- 392 }
393
- 393
394
- 394 jsonApiRecord.relationships[fieldDef.as] = relationshipObject
395
- 395 }
396
- 396 }
397
- 397 }
398
- 398 }
399
- 399
400
- 400 Object.entries(relationships || {}).forEach(([relName, relDef]) => {
401
- 401 if (relDef.belongsToPolymorphic) {
402
- 402 const typeValue = cleanRecord[relDef.belongsToPolymorphic.typeField]
403
- 403 const idValue = cleanRecord[relDef.belongsToPolymorphic.idField]
404
- 404
405
- 405 if (typeValue && idValue) {
406
- 406 jsonApiRecord.relationships = jsonApiRecord.relationships || {}
407
- 407 const relationshipObject = {
408
- 408 data: {
409
- 409 type: typeValue,
410
- 410 id: String(idValue)
411
- 411 }
412
- 412 }
413
- 413
414
- 414 relationshipObject.links = {
415
- 415 self: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, true),
416
- 416 related: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, false)
417
- 417 }
418
- 418
419
- 419 jsonApiRecord.relationships[relName] = relationshipObject
420
- 420 } else if (typeValue === null || idValue === null) {
421
- 421 jsonApiRecord.relationships = jsonApiRecord.relationships || {}
422
- 422 const relationshipObject = {
423
- 423 data: null
424
- 424 }
425
- 425
426
- 426 relationshipObject.links = {
427
- 427 self: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, true),
428
- 428 related: buildRelationshipUrl(context, scope, scopeName, record[idField], relName, false)
429
- 429 }
430
- 430
431
- 431 jsonApiRecord.relationships[relName] = relationshipObject
432
- 432 }
433
- 433 }
434
- 434 })
435
- 435
436
- 436 return jsonApiRecord
437
- 437 })
438
- 438
439
- 439 const urlPrefix = context.urlPrefix || scope.vars.transport?.mountPath || ''
440
- 440 const normalizedData = isSingle ? processedRecords[0] : processedRecords
441
- 441
442
- 442 if (normalizedData) {
443
- 443 if (Array.isArray(normalizedData)) {
444
- 444 normalizedData.forEach(item => {
445
- 445 if (!item.links) item.links = {}
446
- 446 item.links.self = buildResourceUrl(context, scope, scopeName, item.id)
447
- 447 })
448
- 448 } else {
449
- 449 if (!normalizedData.links) normalizedData.links = {}
450
- 450 normalizedData.links.self = buildResourceUrl(context, scope, scopeName, normalizedData.id)
451
- 451 }
452
- 452 }
453
- 453
454
- 454 const response = {
455
- 455 data: normalizedData
456
- 456 }
457
- 457
458
- 458 if (included.length > 0) {
459
- 459 included.forEach(item => {
460
- 460 if (!item.links) item.links = {}
461
- 461 item.links.self = buildResourceUrl(context, scope, item.type, item.id)
462
- 462 })
463
- 463
464
- 464 response.included = included
465
- 465 }
466
- 466
467
- 467 if (context?.returnMeta?.paginationMeta) {
468
- 468 response.meta = {
469
- 469 pagination: context.returnMeta.paginationMeta
470
- 470 }
471
- 471 }
472
- 472
473
- 473 if (context?.returnMeta?.paginationLinks) {
474
- 474 response.links = context.returnMeta.paginationLinks
475
- 475 } else {
476
- 476 const urlPrefix = getUrlPrefix(context, scope)
477
- 477 response.links = {
478
- 478 self: isSingle
479
- 479 ? buildResourceUrl(context, scope, scopeName, normalizedData.id)
480
- 480 : `${urlPrefix}/${scopeName}${context?.returnMeta?.queryString || ''}`
481
- 481 }
482
- 482 }
483
- 483
484
- 484 return response
485
- 485 }