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
@@ -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.validate(validatedFilters, {
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(/[\/\\]/g, '')
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({
@@ -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
- // Delay before opening browser (milliseconds)
23
- const BROWSER_DELAY = 3000
14
+ function parseMode (argv = []) {
15
+ if (argv.includes('--serve') || argv.includes('--dev')) {
16
+ return 'serve'
17
+ }
24
18
 
25
- // Site URLs
26
- const LOCAL_URL = 'http://localhost:4000/json-rest-api/'
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
- } else {
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
- let command
51
-
52
- if (platform === 'darwin') {
53
- command = 'open'
54
- } else if (platform === 'win32') {
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(`\n🌐 Opened browser at ${url}`)
64
- } catch (err) {
65
- console.log(`\n💡 Visit ${url} in your browser`)
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 main () {
70
- console.log('📚 Starting documentation site...\n')
67
+ async function buildDocs () {
68
+ console.log('Building documentation site...')
69
+ await runCommand('bundle', ['exec', 'jekyll', 'build'], { cwd: docsRoot })
70
+ }
71
71
 
72
- try {
73
- // Step 1: There is no step 1
74
-
75
- // Step 2: Install Jekyll dependencies if needed
76
- const bundleLockPath = path.join(projectRoot, 'docs', 'Gemfile.lock')
77
- try {
78
- await fs.access(bundleLockPath)
79
- } catch {
80
- console.log('\n2️⃣ Installing Jekyll dependencies...')
81
- await runCommand('bundle', ['install'], {
82
- cwd: path.join(projectRoot, 'docs')
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
- // Step 3: Start Jekyll server in background
87
- console.log('\n3️⃣ Starting Jekyll server...')
88
- const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve', '--watch'], {
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
- // Handle server output
95
- jekyll.stdout.on('data', (data) => {
96
- const output = data.toString()
97
- process.stdout.write(output)
94
+ process.on('SIGINT', () => {
95
+ console.log('\nShutting down Jekyll server...')
96
+ jekyll.kill()
97
+ process.exit(0)
98
+ })
98
99
 
99
- // Open browser when server is ready
100
- if (output.includes('Server running') || output.includes('Server address:')) {
101
- setTimeout(() => openBrowser(LOCAL_URL), 1000)
102
- }
103
- })
100
+ jekyll.on('error', (err) => {
101
+ console.error('Jekyll server error:', err)
102
+ process.exit(1)
103
+ })
104
104
 
105
- jekyll.stderr.on('data', (data) => {
106
- process.stderr.write(data)
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
- // Handle shutdown
110
- process.on('SIGINT', () => {
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
- jekyll.on('error', (err) => {
117
- console.error('❌ Jekyll server error:', err)
118
- process.exit(1)
119
- })
115
+ async function main () {
116
+ const mode = parseMode(process.argv.slice(2))
120
117
 
121
- jekyll.on('exit', (code) => {
122
- if (code !== 0 && code !== null) {
123
- console.error(`❌ Jekyll server exited with code ${code}`)
124
- process.exit(code)
125
- }
126
- })
118
+ try {
119
+ await ensureBundlerDependencies()
120
+
121
+ if (mode === 'serve') {
122
+ await serveDocs()
123
+ return
124
+ }
127
125
 
128
- // Wait a bit then try to open browser anyway (in case we missed the server ready message)
129
- setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY)
126
+ await buildDocs()
130
127
  } catch (error) {
131
- console.error('❌ Error:', error.message)
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, createRelationship } from './tests/helpers/test-utils.js'
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',