json-rest-api 1.0.29 → 2.1.0

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 (294) hide show
  1. package/LICENSE +10 -670
  2. package/LICENSE-GPL-3.0 +674 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +39 -30
  5. package/docs/API.md +744 -1273
  6. package/docs/GUIDE/01-getting-started.md +338 -0
  7. package/docs/GUIDE/02-resources-and-relationships.md +33 -0
  8. package/docs/GUIDE/03-running-example.md +87 -0
  9. package/docs/GUIDE/04-creating-and-querying.md +181 -0
  10. package/docs/GUIDE/05-belongs-to.md +177 -0
  11. package/docs/GUIDE/06-has-many.md +184 -0
  12. package/docs/GUIDE/07-polymorphic-relationships.md +191 -0
  13. package/docs/GUIDE/08-many-to-many.md +184 -0
  14. package/docs/GUIDE/09-pagination-and-sorting.md +149 -0
  15. package/docs/GUIDE/10-put-and-patch.md +174 -0
  16. package/docs/GUIDE/11-relationship-endpoints.md +174 -0
  17. package/docs/GUIDE/12-field-transformations.md +287 -0
  18. package/docs/GUIDE/13-hooks-and-lifecycle.md +479 -0
  19. package/docs/GUIDE/14-custom-resource-methods.md +125 -0
  20. package/docs/GUIDE/15-query-projections.md +266 -0
  21. package/docs/GUIDE/{GUIDE_X_Autofiltering.md → 16-autofiltering.md} +77 -15
  22. package/docs/GUIDE/{GUIDE_X_Row_Policies.md → 17-row-policies.md} +137 -44
  23. package/docs/GUIDE/18-labels.md +86 -0
  24. package/docs/GUIDE/19-managed-transactions.md +179 -0
  25. package/docs/GUIDE/20-transaction-outcomes.md +207 -0
  26. package/docs/GUIDE/21-schema-and-migrations.md +733 -0
  27. package/docs/GUIDE/22-version-field-migrations.md +208 -0
  28. package/docs/GUIDE/23-fastify.md +179 -0
  29. package/docs/GUIDE/24-cors.md +172 -0
  30. package/docs/GUIDE/{GUIDE_X_URL_Management.md → 25-url-management.md} +7 -1
  31. package/docs/GUIDE/26-file-uploads.md +278 -0
  32. package/docs/GUIDE/27-bulk-operations.md +277 -0
  33. package/docs/GUIDE/28-socketio.md +325 -0
  34. package/docs/GUIDE/29-writing-plugins.md +278 -0
  35. package/docs/GUIDE/30-backend-capabilities.md +103 -0
  36. package/docs/GUIDE/31-positioning.md +181 -0
  37. package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +74 -30
  38. package/docs/GUIDE/33-migrating-to-v2.md +3838 -0
  39. package/docs/GUIDE/index.md +51 -59
  40. package/docs/QUICKSTART.md +120 -287
  41. package/docs/architecture.md +75 -0
  42. package/docs/contributing.md +178 -0
  43. package/index.d.ts +37 -0
  44. package/index.js +3 -22
  45. package/lib/enhanced-logger.js +91 -85
  46. package/lib/error-context.js +445 -5
  47. package/lib/error-formatter.js +219 -59
  48. package/lib/knex-transaction.js +70 -0
  49. package/lib/logger-types.d.ts +22 -0
  50. package/lib/missing-package.js +4 -0
  51. package/lib/rest-api-errors.js +103 -8
  52. package/lib/runtime/json-rest-api.js +172 -0
  53. package/lib/transaction-types.d.ts +59 -0
  54. package/package.json +97 -27
  55. package/plugins/core/bulk-operations-plugin.js +191 -184
  56. package/plugins/core/connectors/express-plugin.js +148 -219
  57. package/plugins/core/connectors/fastify-plugin.js +125 -82
  58. package/plugins/core/connectors/lib/busboy-detector.js +74 -156
  59. package/plugins/core/connectors/lib/connector-core.js +144 -20
  60. package/plugins/core/connectors/lib/formidable-detector.js +63 -120
  61. package/plugins/core/connectors/lib/http-validators.js +77 -0
  62. package/plugins/core/connectors/lib/multipart-helpers.js +18 -0
  63. package/plugins/core/connectors/lib/request-helpers.js +10 -1
  64. package/plugins/core/connectors/lib/transport-http-helpers.js +89 -8
  65. package/plugins/core/connectors/lib/transport-route-schemas.js +7 -4
  66. package/plugins/core/file-handling-plugin.js +87 -177
  67. package/plugins/core/lib/anyapi/anyapi-registry.js +586 -418
  68. package/plugins/core/lib/anyapi/canonical-link-store.js +507 -0
  69. package/plugins/core/lib/anyapi/canonical-relationship-reader.js +598 -0
  70. package/plugins/core/lib/anyapi/schema-utils.js +120 -56
  71. package/plugins/core/lib/anyapi/stored-definition.js +109 -0
  72. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
  73. package/plugins/core/lib/dbIntrospection.js +228 -21
  74. package/plugins/core/lib/dbTablesOperations.js +409 -92
  75. package/plugins/core/lib/fractional-positioning.js +12 -48
  76. package/plugins/core/lib/querying/identifier-query.js +19 -0
  77. package/plugins/core/lib/querying/include-query-helpers.js +364 -0
  78. package/plugins/core/lib/querying/include-to-many.js +428 -0
  79. package/plugins/core/lib/querying/include-to-one.js +579 -0
  80. package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
  81. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
  82. package/plugins/core/lib/querying/knex-pagination-helpers.js +48 -317
  83. package/plugins/core/lib/querying/knex-process-includes.js +5 -110
  84. package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
  85. package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
  86. package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
  87. package/plugins/core/lib/querying/knex-window-queries.js +62 -253
  88. package/plugins/core/lib/querying/query-builder-utils.js +44 -4
  89. package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
  90. package/plugins/core/lib/querying/query-constraint.js +27 -0
  91. package/plugins/core/lib/querying/query-field-sort-helpers.js +134 -37
  92. package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
  93. package/plugins/core/lib/querying/sort-helpers.js +13 -1
  94. package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
  95. package/plugins/core/lib/querying/url-helpers.js +11 -4
  96. package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
  97. package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
  98. package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
  99. package/plugins/core/lib/querying-writing/database-value-normalizers.js +179 -194
  100. package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
  101. package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
  102. package/plugins/core/lib/querying-writing/field-utils.js +113 -92
  103. package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
  104. package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
  105. package/plugins/core/lib/querying-writing/knex-field-helpers.js +100 -290
  106. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
  107. package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
  108. package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
  109. package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
  110. package/plugins/core/lib/querying-writing/request-contracts.js +93 -38
  111. package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
  112. package/plugins/core/lib/querying-writing/response-options.js +35 -0
  113. package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
  114. package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
  115. package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
  116. package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
  117. package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
  118. package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
  119. package/plugins/core/lib/storage/storage-adapter.js +128 -62
  120. package/plugins/core/lib/storage/storage-mapping.js +78 -28
  121. package/plugins/core/lib/storage/storage-types.d.ts +502 -0
  122. package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
  123. package/plugins/core/lib/writing/relationship-processor.js +94 -158
  124. package/plugins/core/lib/writing/resource-version.js +172 -0
  125. package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
  126. package/plugins/core/rest-api-anyapi-knex-plugin.js +290 -2475
  127. package/plugins/core/rest-api-autofilter-plugin.js +17 -19
  128. package/plugins/core/rest-api-cors-plugin.js +52 -205
  129. package/plugins/core/rest-api-knex-plugin.js +45 -1077
  130. package/plugins/core/rest-api-label-plugin.js +25 -38
  131. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
  132. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
  133. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
  134. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
  135. package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
  136. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
  137. package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
  138. package/plugins/core/rest-api-plugin-methods/common.js +291 -395
  139. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
  140. package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
  141. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -148
  142. package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
  143. package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
  144. package/plugins/core/rest-api-plugin-methods/get.js +36 -68
  145. package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
  146. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
  147. package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
  148. package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
  149. package/plugins/core/rest-api-plugin-methods/post.js +51 -51
  150. package/plugins/core/rest-api-plugin-methods/put.js +69 -148
  151. package/plugins/core/rest-api-plugin-methods/query.js +37 -81
  152. package/plugins/core/rest-api-plugin-methods/release.js +2 -1
  153. package/plugins/core/rest-api-plugin.js +32 -46
  154. package/plugins/core/rest-api-positioning-plugin.js +183 -628
  155. package/plugins/core/rest-api-query-projections-plugin.js +19 -102
  156. package/plugins/core/rest-api-row-policy-plugin.js +3 -3
  157. package/plugins/core/socketio-plugin.js +364 -344
  158. package/plugins/storage/local-storage.js +40 -36
  159. package/types/anyapi.d.ts +30 -0
  160. package/types/autofilter.d.ts +57 -0
  161. package/types/bulk-methods.d.ts +63 -0
  162. package/types/errors.d.ts +118 -0
  163. package/types/fastify-options.d.ts +19 -0
  164. package/types/file-detectors.d.ts +33 -0
  165. package/types/file-storage.d.ts +48 -0
  166. package/types/hook-context.d.ts +180 -0
  167. package/types/plugin-options.d.ts +65 -0
  168. package/types/relationship-methods.d.ts +74 -0
  169. package/types/representations.d.ts +50 -0
  170. package/types/resource-methods.d.ts +95 -0
  171. package/types/resource-schema.d.ts +157 -0
  172. package/types/row-policy.d.ts +31 -0
  173. package/types/runtime.d.ts +132 -0
  174. package/types/transactions.d.ts +21 -0
  175. package/.claude/agents/library-guide-expert.md +0 -30
  176. package/.claude/agents/rest-api-internals-expert.md +0 -54
  177. package/.claude/settings.local.json +0 -70
  178. package/AGENTS.md +0 -34
  179. package/CLAUDE.md +0 -160
  180. package/CRUSH.md +0 -55
  181. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
  182. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
  183. package/TODO.todo +0 -13
  184. package/connectors_ideas/fastify.js +0 -217
  185. package/connectors_ideas/koa-plugin.js +0 -112
  186. package/docs/.bundle/config +0 -2
  187. package/docs/COMPARISON.md +0 -433
  188. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
  189. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
  190. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
  191. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
  192. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
  193. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
  194. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
  195. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1247
  196. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
  197. package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
  198. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
  199. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
  200. package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
  201. package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
  202. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
  203. package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
  204. package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
  205. package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
  206. package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
  207. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
  208. package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
  209. package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
  210. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
  211. package/docs/Gemfile +0 -6
  212. package/docs/Gemfile.lock +0 -308
  213. package/docs/ONBOARDING.md +0 -315
  214. package/docs/_config.yml +0 -36
  215. package/docs/_layouts/default.html +0 -123
  216. package/docs/apple-touch-icon.svg +0 -4
  217. package/docs/assets/css/style.scss +0 -392
  218. package/docs/favicon.svg +0 -4
  219. package/docs/index.md +0 -164
  220. package/docs/mini-guides/file-uploads-complete.md +0 -161
  221. package/eslint.config.js +0 -13
  222. package/examples/url-override-example.js +0 -137
  223. package/fixing_plan.md +0 -112
  224. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
  225. package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
  226. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
  227. package/plugins/storage/s3-storage.js +0 -93
  228. package/quickTest.js +0 -136
  229. package/scripts/debug-anyapi-review-filter.mjs +0 -63
  230. package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
  231. package/scripts/inspect-anyapi-descriptor.mjs +0 -19
  232. package/scripts/run-docs.js +0 -133
  233. package/test-debug.js +0 -59
  234. package/tests/README.md +0 -202
  235. package/tests/TEST_TEMPLATE.test.js +0 -178
  236. package/tests/anyapi-basic.test.js +0 -105
  237. package/tests/anyapi-cursor-pagination.test.js +0 -148
  238. package/tests/anyapi-custom-idproperty.test.js +0 -163
  239. package/tests/autofilter.test.js +0 -463
  240. package/tests/bulk-operations.test.js +0 -657
  241. package/tests/computed-fields.test.js +0 -586
  242. package/tests/cors.test.js +0 -834
  243. package/tests/curl.test.js +0 -467
  244. package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
  245. package/tests/custom-id-simplified-post.test.js +0 -75
  246. package/tests/custom-idproperty-relationships.test.js +0 -932
  247. package/tests/db-introspection.test.js +0 -521
  248. package/tests/db-table-operations.test.js +0 -798
  249. package/tests/fastify-plugin.test.js +0 -184
  250. package/tests/field-getters.test.js +0 -370
  251. package/tests/field-setters.test.js +0 -306
  252. package/tests/file-handling.test.js +0 -155
  253. package/tests/fixtures/api-configs.js +0 -2566
  254. package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
  255. package/tests/helpers/fake-fastify.js +0 -99
  256. package/tests/helpers/storage-mode.js +0 -65
  257. package/tests/helpers/test-utils.js +0 -203
  258. package/tests/http-connectors-parity.test.js +0 -395
  259. package/tests/id-normalization.test.js +0 -444
  260. package/tests/include-depth-validation.test.js +0 -331
  261. package/tests/includes.test.js +0 -427
  262. package/tests/local-storage.test.js +0 -96
  263. package/tests/logical-id-write-validation.test.js +0 -151
  264. package/tests/nested-includes.test.js +0 -617
  265. package/tests/pagination-boundaries.test.js +0 -154
  266. package/tests/pagination-contract.test.js +0 -122
  267. package/tests/pagination-cursor-multifield.test.js +0 -641
  268. package/tests/pagination-enhanced.test.js +0 -563
  269. package/tests/polymorphic-relationships.test.js +0 -347
  270. package/tests/polymorphic-simple.test.js +0 -148
  271. package/tests/positioning-advanced.test.js +0 -692
  272. package/tests/positioning-extended.test.js +0 -915
  273. package/tests/positioning-multifilter.test.js +0 -699
  274. package/tests/positioning.test.js +0 -560
  275. package/tests/post-commit-hooks.test.js +0 -120
  276. package/tests/projected-fields.test.js +0 -319
  277. package/tests/public-exports.test.js +0 -15
  278. package/tests/put-create-parity.test.js +0 -216
  279. package/tests/queries.test.js +0 -521
  280. package/tests/query-limits.test.js +0 -584
  281. package/tests/relationship-endpoints.test.js +0 -620
  282. package/tests/relationship-include-storage-adapter.test.js +0 -56
  283. package/tests/relationships.test.js +0 -681
  284. package/tests/rest-api.test.js +0 -337
  285. package/tests/return-record-settings.test.js +0 -184
  286. package/tests/row-policy.test.js +0 -489
  287. package/tests/s3-storage.test.js +0 -38
  288. package/tests/searchschema-knex-behavior.test.js +0 -187
  289. package/tests/searchschema-merge.test.js +0 -151
  290. package/tests/socketio.test.js +0 -860
  291. package/tests/storage-mapping.test.js +0 -362
  292. package/tests/temporal-boundaries.test.js +0 -208
  293. package/tests/test-development-guide.md +0 -370
  294. package/tests/virtual-fields.test.js +0 -404
@@ -1,172 +0,0 @@
1
- Single Validation Contract TODO
2
-
3
- Goal
4
- - Make `json-rest-schema` the single authored validation contract in `json-rest-api`.
5
- - Keep plain JSON Schema only as a derived transport artifact for connectors.
6
- - Remove the split between:
7
- - resource/search validation via `json-rest-schema`
8
- - hand-written JSON:API/query validators in `plugins/core/lib/querying-writing/payload-validators.js`
9
-
10
- Current audit status
11
- - [done] Audit the live validation paths and identify the actual indirection.
12
-
13
- Root cause
14
- - Validation is split across three places:
15
- 1. `plugins/core/lib/querying-writing/compile-schemas.js`
16
- - compiles resource and search schemas with `createSchema(...)`
17
- 2. `plugins/core/lib/querying-writing/payload-validators.js`
18
- - manually validates JSON:API request envelopes and query parameter objects
19
- 3. `plugins/core/connectors/lib/transport-route-schemas.js`
20
- - separately builds connector-facing JSON Schemas from `schemaInfo`
21
- - This duplicates contract meaning across runtime and transport.
22
- - Route methods still call imperative payload validators before calling
23
- `schemaInstance.create()`, `schemaInstance.replace()`, or `schemaInstance.patch()`.
24
- - `setupCommonRequest()` in `plugins/core/rest-api-plugin-methods/common.js`
25
- also repeats some checks that are already transport-contract concerns.
26
-
27
- What the neat end state looks like
28
- - Authored contract:
29
- - `json-rest-schema` only
30
- - Derived transport schema:
31
- - plain JSON Schema, generated from the same compiled contract
32
- - Runtime write validation:
33
- - uses the same compiled contract as Fastify pre-validation
34
- - Remaining imperative checks:
35
- - only stateful/business checks that are not schema concerns
36
- - examples: permission checks, record existence, relationship access, complete-replace semantics
37
-
38
- What should stay imperative
39
- - `validateRelationshipAccess()` in `plugins/core/rest-api-plugin-methods/common.js`
40
- - `validateCompleteReplacePayload()` in `plugins/core/rest-api-plugin-methods/common.js`
41
- - path/body cross-source checks such as URL id vs body id consistency
42
- - permission and data existence checks
43
-
44
- What should stop existing
45
- - `validateGetPayload()`
46
- - `validateQueryPayload()`
47
- - `validatePostPayload()`
48
- - `validatePutPayload()`
49
- - `validatePatchPayload()`
50
- - duplicate route/body/query syntax checks spread across route methods and `setupCommonRequest()`
51
-
52
- Work list
53
-
54
- 1. [done] Define one compiled request-contract surface for resource `get/query/post/put/patch`.
55
- Target files:
56
- - `plugins/core/lib/querying-writing/compile-schemas.js`
57
- - `plugins/core/connectors/lib/transport-route-schemas.js`
58
- Deliverables:
59
- - compile request contracts once per scope
60
- - store them on `scope.vars.schemaInfo` or an adjacent compiled-contract object
61
- - separate:
62
- - write document contracts (`post`, `put`, `patch`)
63
- - query/get contracts (`get`, `query`)
64
- - relationship route contracts
65
- Status:
66
- - resource route contracts now compile once in `request-contracts.js`
67
- - relationship route contracts are still separate and remain pending work
68
-
69
- 2. [done] Replace manual write-document validation with compiled schema contracts.
70
- Target files:
71
- - `plugins/core/lib/querying-writing/payload-validators.js`
72
- - `plugins/core/rest-api-plugin-methods/post.js`
73
- - `plugins/core/rest-api-plugin-methods/put.js`
74
- - `plugins/core/rest-api-plugin-methods/patch.js`
75
- Deliverables:
76
- - one compiled JSON:API document contract per write mode
77
- - `data.type` constrained to the scope name inside the contract
78
- - `data.id` required/optional according to mode
79
- - `attributes` contract derived from `schemaInstance.toJsonSchema({ mode })`
80
- - relationship identifier contracts derived from `schemaRelationships` and `belongsTo` metadata
81
- - `included` rules expressed once in the contract rather than repeated manually
82
-
83
- 3. [done] Replace manual GET/query parameter validation with compiled schema contracts.
84
- Target files:
85
- - `plugins/core/lib/querying-writing/payload-validators.js`
86
- - `plugins/core/rest-api-plugin-methods/get.js`
87
- - `plugins/core/rest-api-plugin-methods/query.js`
88
- Deliverables:
89
- - a compiled `get` contract for:
90
- - `id`
91
- - `queryParams.include`
92
- - `queryParams.fields`
93
- - a compiled `query` contract for:
94
- - `include`
95
- - `fields`
96
- - `filters`
97
- - `sort`
98
- - `page`
99
- - include-depth validation and sortable-field restrictions represented in the compiled contract, not duplicated in ad hoc code
100
- Notes:
101
- - `searchSchemaInstance` should remain the value contract for `filters`
102
- - the query contract should validate the envelope/shape, not duplicate filter semantics
103
-
104
- 4. [done] Collapse Fastify pre-validation and in-process validation onto the same source for resource write routes.
105
- Target files:
106
- - `plugins/core/connectors/lib/transport-route-schemas.js`
107
- - `plugins/core/connectors/fastify-plugin.js`
108
- - route methods in `plugins/core/rest-api-plugin-methods/`
109
- Deliverables:
110
- - Fastify consumes transport JSON Schema exported from the compiled request contract
111
- - route methods consume the same compiled contract directly for runtime validation
112
- - no second hand-written envelope contract path
113
-
114
- 5. [done] Shrink `setupCommonRequest()` to non-schema responsibilities.
115
- Target file:
116
- - `plugins/core/rest-api-plugin-methods/common.js`
117
- Deliverables:
118
- - keep simplified-mode conversion, transaction setup, context wiring
119
- - keep stateful/business checks only
120
- - remove syntax/envelope checks that belong in the compiled contract
121
- - keep only cross-input checks that a single schema cannot express cleanly
122
-
123
- 6. [done] Delete `payload-validators.js`.
124
- Target file:
125
- - `plugins/core/lib/querying-writing/payload-validators.js`
126
- Deliverables:
127
- - no route method imports it anymore
128
- - helper logic worth keeping is either:
129
- - absorbed into compiled contracts
130
- - or moved into narrowly named stateful helpers
131
-
132
- 7. [done] Tighten tests around the single-contract flow.
133
- Target areas:
134
- - `tests/fastify-plugin.test.js`
135
- - route method coverage exercised by the existing REST suites
136
- - add one focused contract test suite if needed
137
- Deliverables:
138
- - prove Fastify pre-validation and runtime validation reject the same bad inputs
139
- - cover:
140
- - wrong `data.type`
141
- - missing/invalid `data.id`
142
- - invalid relationships
143
- - invalid query/include/page/sort shapes
144
- - verify there is no drift between transport schema and runtime schema behavior
145
-
146
- 8. [done] Proof cleanup.
147
- Deliverables:
148
- - `rg` proof that route methods no longer import `payload-validators.js`
149
- - `rg` proof that `validateGetPayload`, `validateQueryPayload`, `validatePostPayload`,
150
- `validatePutPayload`, and `validatePatchPayload` are gone
151
- - `npm test`
152
-
153
- Current state
154
- - Resource `get/query/post/put/patch` now use one compiled contract source.
155
- - Fastify transport schemas for those resource routes are derived from the same compiled contract.
156
- - `payload-validators.js` is deleted.
157
- - `npm test` passes.
158
- - The main remaining simplification is the separate relationship-route contract path.
159
-
160
- File map for the next implementation pass
161
- - Remaining relationship-route cleanup:
162
- - `plugins/core/rest-api-plugin-methods/post-relationship.js`
163
- - `plugins/core/rest-api-plugin-methods/patch-relationship.js`
164
- - `plugins/core/rest-api-plugin-methods/delete-relationship.js`
165
- - Transport schema generator to reuse, not duplicate:
166
- - `plugins/core/connectors/lib/transport-route-schemas.js`
167
-
168
- Explicit non-goals
169
- - Do not move permission checks into schemas.
170
- - Do not move DB existence checks into schemas.
171
- - Do not turn `searchSchema` into a generic filter DSL.
172
- - Do not add a compatibility layer that preserves both manual validators and compiled contracts.
package/TODO.todo DELETED
@@ -1,13 +0,0 @@
1
- Potential Enhancements
2
-
3
- 1. Provider Priority: Consider adding a "primary_provider" field to handle users who authenticate through multiple providers.
4
- 2. Field Cleanup: Maybe add a helper to remove provider fields when a user unlinks that provider.
5
- 3. Migration Safety: The automatic column creation via RestApiKnexPlugin is convenient, but you might want provider plugins to check if their
6
- fields already exist before extending.
7
-
8
-
9
- ☐ Delete "Creating Custom Storage Plugins for JSON REST API", make an op plugin instead.
10
- ☐ Improve the look of the CSS, especially black and long code fragments, title fonts
11
- ☐ Check manually that the API is OK
12
- ☐ Check that the guide has full coverage of features, map the missing parts
13
-
@@ -1,217 +0,0 @@
1
- /**
2
- * http-plugin-fastify.js
3
- * This plugin for Hooked API provides a high-performance HTTP layer using the Fastify framework.
4
- * It automatically generates JSON:API compliant RESTful routes and schemas for each scope.
5
- *
6
- * You'll need to install dependencies: npm install fastify
7
- */
8
- import { HookedApiError } from './hooked-api.js'
9
- import { handleFastifyApiError } from './error-handler-fastify.js'
10
-
11
- /**
12
- * **UPGRADED:** Automatically generates a comprehensive Fastify schema object that conforms
13
- * to the full JSON:API specification, including relationships, links, and meta.
14
- * @param {string} scopeName - The name of the resource type (e.g., 'articles').
15
- * @param {object} scopeOptions - The full options object for the scope.
16
- * @returns {object} A complete Fastify schema for all CRUD routes.
17
- */
18
- function _generateFastifySchema (scopeName, scopeOptions = {}) {
19
- const appSchema = scopeOptions.schema || {}
20
- const relationshipsSchema = scopeOptions.relationships || {}
21
-
22
- // --- Reusable Schema Components ---
23
- const metaObject = { type: 'object', additionalProperties: true }
24
- const linksObject = {
25
- type: 'object',
26
- properties: {
27
- self: { type: 'string', format: 'uri-reference' },
28
- related: { type: 'string', format: 'uri-reference' },
29
- }
30
- }
31
- const resourceIdentifierObject = {
32
- type: 'object',
33
- required: ['type', 'id'],
34
- properties: {
35
- type: { type: 'string' },
36
- id: { type: 'string' }
37
- }
38
- }
39
-
40
- // --- Build Attribute Properties from simple schema ---
41
- const attributeProperties = {}
42
- const requiredAttributes = []
43
- for (const [key, value] of Object.entries(appSchema)) {
44
- let jsonSchemaType = 'string'
45
- if (value.type === 'number') jsonSchemaType = 'number'
46
- if (value.type === 'boolean') jsonSchemaType = 'boolean'
47
-
48
- attributeProperties[key] = { type: jsonSchemaType }
49
- if (value.format) attributeProperties[key].format = value.format
50
- if (value.required) requiredAttributes.push(key)
51
- }
52
-
53
- // --- Build Relationship Properties ---
54
- const relationshipProperties = {}
55
- for (const [key, value] of Object.entries(relationshipsSchema)) {
56
- const isToMany = value.type === 'hasMany'
57
- relationshipProperties[key] = {
58
- type: 'object',
59
- properties: {
60
- links: linksObject,
61
- data: isToMany
62
- ? { type: 'array', items: resourceIdentifierObject }
63
- : resourceIdentifierObject
64
- }
65
- }
66
- }
67
-
68
- // --- Define the core Resource Object schema ---
69
- const resourceObject = {
70
- type: 'object',
71
- required: ['type', 'id'],
72
- properties: {
73
- id: { type: 'string' },
74
- type: { type: 'string', const: scopeName },
75
- attributes: {
76
- type: 'object',
77
- properties: attributeProperties
78
- },
79
- relationships: {
80
- type: 'object',
81
- properties: relationshipProperties
82
- },
83
- links: linksObject
84
- }
85
- }
86
-
87
- // --- Define the full top-level JSON:API Document ---
88
- const singleDocument = {
89
- type: 'object',
90
- properties: {
91
- data: resourceObject,
92
- included: { type: 'array', items: { type: 'object' } }, // Generic included for simplicity
93
- links: linksObject,
94
- meta: metaObject
95
- }
96
- }
97
- const collectionDocument = {
98
- type: 'object',
99
- properties: {
100
- data: { type: 'array', items: resourceObject },
101
- included: { type: 'array', items: { type: 'object' } },
102
- links: { ...linksObject, properties: { ...linksObject.properties, next: { type: 'string' }, prev: { type: 'string' } } },
103
- meta: metaObject
104
- }
105
- }
106
-
107
- // --- Build the final schema for each route ---
108
- return {
109
- post: {
110
- body: {
111
- type: 'object',
112
- required: ['data'],
113
- properties: {
114
- data: {
115
- type: 'object',
116
- required: ['type', 'attributes'],
117
- properties: {
118
- type: { type: 'string', const: scopeName },
119
- attributes: {
120
- type: 'object',
121
- required: requiredAttributes,
122
- properties: attributeProperties
123
- },
124
- relationships: {
125
- type: 'object',
126
- properties: relationshipProperties
127
- }
128
- }
129
- }
130
- }
131
- },
132
- response: { 201: singleDocument }
133
- },
134
- get: {
135
- response: { 200: singleDocument }
136
- },
137
- query: {
138
- response: { 200: collectionDocument }
139
- },
140
- patch: {
141
- body: { /* A more complex partial schema would be needed for full validation */ },
142
- response: { 200: singleDocument }
143
- },
144
- put: {
145
- body: { /* Similar to POST body */ },
146
- response: { 200: singleDocument }
147
- }
148
- }
149
- }
150
-
151
- export const HttpFastifyPlugin = {
152
- name: 'http-fastify',
153
-
154
- install (context, api) {
155
- const { pluginOptions, log } = context
156
- const httpOptions = pluginOptions.http || {}
157
- const { app, prefix = '/api' } = httpOptions
158
-
159
- if (!app) {
160
- throw new HookedApiError(
161
- "The 'http-fastify' plugin requires a Fastify 'app' instance to be passed in the options. Example: api.use(HttpFastifyPlugin, { http: { app: myFastifyApp } })",
162
- 'CONFIGURATION_ERROR'
163
- )
164
- }
165
-
166
- log.info(`Fastify HTTP plugin installed. Routes will be prefixed with '${prefix}'.`)
167
-
168
- const _createFastifyHandler = (methodName) => {
169
- return async (request, reply) => {
170
- const { scopeName, id } = request.params
171
- const apiParams = {
172
- id,
173
- inputRecord: request.body,
174
- queryParams: request.query,
175
- }
176
- log.debug(`Fastify request for ${scopeName}.${methodName}`, { id, query: apiParams.queryParams })
177
- const result = await api.scopes[scopeName][methodName](apiParams)
178
- switch (methodName) {
179
- case 'post':
180
- reply.code(201).send(result)
181
- break
182
- case 'delete':
183
- reply.code(204).send()
184
- break
185
- default:
186
- reply.code(200).send(result)
187
- }
188
- }
189
- }
190
-
191
- const _createScopePlugin = (scopeName, scopeOptions) => {
192
- const fastifySchema = scopeOptions.fastifySchema || _generateFastifySchema(scopeName, scopeOptions)
193
-
194
- return async (fastifyInstance) => {
195
- log.info(`Creating Fastify HTTP routes for scope: '${scopeName}'`)
196
- fastifyInstance.get(`/${scopeName}`, { schema: fastifySchema.query }, _createFastifyHandler('query'))
197
- fastifyInstance.get(`/${scopeName}/:id`, { schema: fastifySchema.get }, _createFastifyHandler('get'))
198
- fastifyInstance.post(`/${scopeName}`, { schema: fastifySchema.post }, _createFastifyHandler('post'))
199
- fastifyInstance.put(`/${scopeName}/:id`, { schema: fastifySchema.put }, _createFastifyHandler('put'))
200
- fastifyInstance.patch(`/${scopeName}/:id`, { schema: fastifySchema.patch }, _createFastifyHandler('patch'))
201
- fastifyInstance.delete(`/${scopeName}/:id`, { schema: fastifySchema.delete }, _createFastifyHandler('delete'))
202
- }
203
- }
204
-
205
- const originalAddScope = api.addScope
206
-
207
- api.addScope = (name, options, extras) => {
208
- const result = originalAddScope.call(api, name, options, extras)
209
- app.register(_createScopePlugin(name, options), { prefix })
210
- return result
211
- }
212
-
213
- app.setErrorHandler((error, request, reply) => {
214
- handleFastifyApiError(error, request, reply, log)
215
- })
216
- }
217
- }
@@ -1,112 +0,0 @@
1
- /**
2
- * http-plugin-koa.js
3
- * This plugin for Hooked API provides a lightweight HTTP layer using the Koa.js framework.
4
- * It automatically generates JSON:API compliant RESTful routes for each scope using `koa-router`.
5
- *
6
- * It assumes you have `koa-bodyparser` installed and used before this plugin.
7
- * You'll need to install dependencies: npm install koa koa-router koa-bodyparser qs
8
- */
9
- import KoaRouter from 'koa-router'
10
- import qs from 'qs' // The same query string parser Express uses
11
- import { HookedApiError } from './hooked-api.js'
12
- import { handleKoaApiError } from './error-handler-koa.js'
13
-
14
- export const HttpKoaPlugin = {
15
- name: 'http-koa',
16
-
17
- install (context, api) {
18
- const { pluginOptions, log } = context
19
- const httpOptions = pluginOptions.http || {}
20
- const { app, prefix = '/api' } = httpOptions
21
-
22
- if (!app) {
23
- throw new HookedApiError(
24
- "The 'http-koa' plugin requires a Koa 'app' instance to be passed in the options. Example: api.use(HttpKoaPlugin, { http: { app: myKoaApp } })",
25
- 'CONFIGURATION_ERROR'
26
- )
27
- }
28
-
29
- // Create a router instance for our API routes
30
- const router = new KoaRouter({ prefix })
31
-
32
- /**
33
- * Creates a generic Koa middleware for a specific API method.
34
- * @param {string} methodName - The name of the scope method to call (e.g., 'get', 'query').
35
- * @returns {Function} An async Koa middleware function.
36
- */
37
- const _createKoaHandler = (methodName) => {
38
- return async (ctx) => {
39
- const { scopeName, id } = ctx.params
40
-
41
- try {
42
- // 1. Translate Koa ctx into API method params
43
- const apiParams = {}
44
-
45
- if (['get', 'put', 'patch', 'delete'].includes(methodName)) {
46
- apiParams.id = id
47
- }
48
- if (['post', 'put', 'patch'].includes(methodName)) {
49
- // Assumes koa-bodyparser is used
50
- apiParams.inputRecord = ctx.request.body
51
- }
52
- // Use qs to properly parse nested query objects
53
- apiParams.queryParams = ctx.querystring ? qs.parse(ctx.querystring) : {}
54
-
55
- log.debug(`Koa request for ${scopeName}.${methodName}`, { id, query: apiParams.queryParams })
56
-
57
- // 2. Execute the corresponding API method
58
- const result = await api.scopes[scopeName][methodName](apiParams)
59
-
60
- // 3. Set the successful Koa response
61
- switch (methodName) {
62
- case 'post':
63
- ctx.status = 201
64
- ctx.body = result
65
- break
66
- case 'delete':
67
- ctx.status = 204
68
- // No body for 204
69
- break
70
- default:
71
- ctx.status = 200
72
- ctx.body = result
73
- }
74
- } catch (error) {
75
- // 4. Handle any errors thrown by the API
76
- handleKoaApiError(error, ctx, log)
77
- }
78
- }
79
- }
80
-
81
- /**
82
- * Creates all the standard RESTful routes for a given scope on the router.
83
- * @param {string} scopeName - The name of the scope to create routes for.
84
- */
85
- const _createRoutesForScope = (scopeName) => {
86
- const collectionPath = `/${scopeName}`
87
- const resourcePath = `${collectionPath}/:id`
88
-
89
- log.info(`Creating Koa HTTP routes for scope: '${scopeName}'`)
90
-
91
- router.get(collectionPath, _createKoaHandler('query'))
92
- router.get(resourcePath, _createKoaHandler('get'))
93
- router.post(collectionPath, _createKoaHandler('post'))
94
- router.put(resourcePath, _createKoaHandler('put'))
95
- router.patch(resourcePath, _createKoaHandler('patch'))
96
- router.del(resourcePath, _createKoaHandler('delete')) // .del is koa-router's alias for delete
97
- }
98
-
99
- // --- Main Logic: Wrap `addScope` to automate route creation ---
100
- const originalAddScope = api.addScope
101
-
102
- api.addScope = (name, options, extras) => {
103
- const result = originalAddScope.call(api, name, options, extras)
104
- _createRoutesForScope(name)
105
- return result
106
- }
107
-
108
- // Apply the router middleware to the Koa app
109
- app.use(router.routes()).use(router.allowedMethods())
110
- log.info(`Koa router installed with prefix '${prefix}'.`)
111
- }
112
- }
@@ -1,2 +0,0 @@
1
- ---
2
- BUNDLE_PATH: "vendor/bundle"