json-rest-api 1.0.7 → 1.0.8

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 (146) hide show
  1. package/.claude/agents/library-guide-expert.md +29 -0
  2. package/.claude/agents/rest-api-internals-expert.md +53 -0
  3. package/CLAUDE.md +139 -1
  4. package/README.md +2 -5
  5. package/docTest.js +238 -0
  6. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +955 -0
  7. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +54 -0
  8. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +750 -0
  9. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +494 -0
  10. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +398 -0
  11. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +882 -0
  12. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +709 -0
  13. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +1233 -0
  14. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +796 -0
  15. package/{README_X_Relationship_Plugin.md → docs/GUIDE/GUIDE_2_9_Relationships_Urls.md} +1 -4
  16. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +66 -0
  17. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +1246 -0
  18. package/docs/GUIDE/GUIDE_5_Non-Db_Stores.md +0 -0
  19. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +1490 -0
  20. package/{README_X_SocketIO.md → docs/GUIDE/GUIDE_X_SocketIO.md} +17 -17
  21. package/docs/GUIDE/index.md +58 -0
  22. package/docs/GUIDE.md +61 -2238
  23. package/docs/ONBOARDING/Computed_Properties_And_Sparse_Fields.md +398 -0
  24. package/docs/README.md +57 -2239
  25. package/{README_2_Computed_and_hidden_fields.md → docs/README_VARIOUS/GUIDE_2_Computed_and_hidden_fields.md} +22 -17
  26. package/docs/README_VARIOUS/GUIDE_IN_DOCS.md +2277 -0
  27. package/{README.ORIG.md → docs/README_VARIOUS/README.ORIG.md} +8 -8
  28. package/{README_8_Polymorphic_Relationships.md → docs/README_VARIOUS/README_8_Polymorphic_Relationships.md} +1 -1
  29. package/docs/README_VARIOUS/README_IN_DOCS.ms +2277 -0
  30. package/{RELATIONSHIPS_ADVANCED.md → docs/README_VARIOUS/RELATIONSHIPS_ADVANCED.md} +3 -3
  31. package/{correct-schema-format.md → docs/README_VARIOUS/correct-schema-format.md} +13 -13
  32. package/{pagination.md → docs/README_VARIOUS/pagination.md} +11 -8
  33. package/docs/assets/css/style.scss +78 -5
  34. package/docs/index.md +2 -12
  35. package/helper-reorganization-plan.md +85 -0
  36. package/helper-usage-analysis.md +94 -0
  37. package/package.json +5 -4
  38. package/plugins/core/bulk-operations-plugin.js +2 -2
  39. package/plugins/core/connectors/express-plugin.js +90 -32
  40. package/plugins/core/lib/querying/knex-cross-table-search.js +609 -0
  41. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +491 -0
  42. package/plugins/core/lib/querying/knex-pagination-helpers.js +544 -0
  43. package/plugins/core/lib/{knex-process-includes.js → querying/knex-process-includes.js} +65 -50
  44. package/plugins/core/lib/querying/knex-query-helpers-base.js +74 -0
  45. package/plugins/core/lib/{knex-query-helpers.js → querying/knex-query-helpers.js} +416 -180
  46. package/plugins/core/lib/{knex-relationship-includes.js → querying/knex-relationship-includes.js} +430 -114
  47. package/plugins/core/lib/querying/knex-window-queries.js +328 -0
  48. package/plugins/core/lib/querying-writing/compile-schemas.js +328 -0
  49. package/plugins/core/{utils → lib/querying-writing}/connectors-query-parser.js +62 -57
  50. package/plugins/core/lib/{database-capabilities.js → querying-writing/database-capabilities.js} +113 -7
  51. package/plugins/core/lib/querying-writing/database-value-normalizers.js +369 -0
  52. package/plugins/core/lib/querying-writing/default-data-helpers.js +72 -0
  53. package/plugins/core/{utils → lib/querying-writing}/field-utils.js +41 -31
  54. package/plugins/core/{utils → lib/querying-writing}/knex-constants.js +1 -0
  55. package/plugins/core/lib/{knex-field-helpers.js → querying-writing/knex-field-helpers.js} +190 -57
  56. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +162 -0
  57. package/plugins/core/lib/{payload-validators.js → querying-writing/payload-validators.js} +297 -217
  58. package/plugins/core/lib/querying-writing/schema-helpers.js +497 -0
  59. package/plugins/core/lib/querying-writing/scope-validations.js +431 -0
  60. package/plugins/core/lib/{simplified-helpers.js → querying-writing/simplified-helpers.js} +216 -176
  61. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +110 -0
  62. package/plugins/core/lib/writing/many-to-many-manipulations.js +300 -0
  63. package/plugins/core/lib/writing/relationship-processor.js +252 -0
  64. package/plugins/core/rest-api-knex-plugin.js +183 -62
  65. package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +7 -0
  66. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +72 -0
  67. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +102 -0
  68. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +50 -0
  69. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +39 -0
  70. package/plugins/core/rest-api-plugin-methods/add-route.js +23 -0
  71. package/plugins/core/rest-api-plugin-methods/check-permissions.js +18 -0
  72. package/plugins/core/rest-api-plugin-methods/common.js +605 -0
  73. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +115 -0
  74. package/plugins/core/rest-api-plugin-methods/delete.js +109 -0
  75. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +186 -0
  76. package/plugins/core/rest-api-plugin-methods/get-related.js +295 -0
  77. package/plugins/core/rest-api-plugin-methods/get-relationship.js +62 -0
  78. package/plugins/core/rest-api-plugin-methods/get.js +187 -0
  79. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +56 -0
  80. package/plugins/core/rest-api-plugin-methods/patch.js +193 -0
  81. package/plugins/core/rest-api-plugin-methods/post-relationship.js +104 -0
  82. package/plugins/core/rest-api-plugin-methods/post.js +157 -0
  83. package/plugins/core/rest-api-plugin-methods/put.js +257 -0
  84. package/plugins/core/rest-api-plugin-methods/query.js +208 -0
  85. package/plugins/core/rest-api-plugin.js +108 -2498
  86. package/plugins/core/socketio-plugin.js +28 -5
  87. package/plugins/storage/local-storage.js +2 -2
  88. package/tests/computed-fields.test.js +483 -0
  89. package/tests/cors.test.js +4 -4
  90. package/tests/curl.test.js +5 -4
  91. package/tests/custom-idproperty-relationships.test.js +891 -0
  92. package/tests/field-getters.test.js +353 -0
  93. package/tests/field-setters.test.js +310 -0
  94. package/tests/fixtures/api-configs.js +800 -28
  95. package/tests/jwt-auth.test.js +0 -2
  96. package/tests/nested-includes.test.js +1 -1
  97. package/tests/pagination-cursor-multifield.test.js +514 -0
  98. package/tests/pagination-enhanced.test.js +12 -9
  99. package/tests/polymorphic-relationships.test.js +10 -8
  100. package/tests/polymorphic-simple.test.js +6 -4
  101. package/tests/positioning-advanced.test.js +12 -12
  102. package/tests/positioning-extended.test.js +25 -25
  103. package/tests/positioning-multifilter.test.js +24 -24
  104. package/tests/positioning.test.js +3 -3
  105. package/tests/query-limits.test.js +24 -8
  106. package/tests/relationship-endpoints.test.js +4 -5
  107. package/tests/relationships.test.js +0 -1
  108. package/tests/socketio.test.js +12 -1
  109. package/tests/virtual-fields.test.js +13 -13
  110. package/PLAN_FOR_WEBSOCKETS.md +0 -398
  111. package/README_1_Initial_Setup.md +0 -393
  112. package/README_X_Hooks.md +0 -647
  113. package/TODO_rest-api-plugin-extras.todo +0 -23
  114. package/connectors_ideas/express-plugin.js +0 -120
  115. package/connectors_ideas/http-plugin.js +0 -138
  116. package/docs/examples/express-plugin.js +0 -366
  117. package/example.js +0 -301
  118. package/plugins/core/HELPER_MODULES.md +0 -285
  119. package/plugins/core/lib/compile-schemas.js +0 -245
  120. package/plugins/core/lib/database-value-normalizers.js +0 -192
  121. package/plugins/core/lib/default-data-helpers.js +0 -100
  122. package/plugins/core/lib/knex-cross-table-search.js +0 -442
  123. package/plugins/core/lib/knex-json-api-helpers.js +0 -84
  124. package/plugins/core/lib/knex-json-api-transformers.js +0 -449
  125. package/plugins/core/lib/knex-pagination-helpers.js +0 -193
  126. package/plugins/core/lib/knex-window-queries.js +0 -142
  127. package/plugins/core/lib/many-to-many-manipulations.js +0 -343
  128. package/plugins/core/lib/relationship-processor.js +0 -278
  129. package/plugins/core/lib/schema-helpers.js +0 -343
  130. package/plugins/core/lib/scope-validations.js +0 -252
  131. package/plugins/core/rest-api-relationships-plugin.js +0 -700
  132. package/plugins/core/utils/knex-query-helpers-base.js +0 -56
  133. /package/{README_X_Permissions.md → docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md} +0 -0
  134. /package/{README_X_Positioning.md → docs/GUIDE/GUIDE_6_Positioning.md} +0 -0
  135. /package/{README_X_Bulk_Operations.md → docs/GUIDE/GUIDE_X_Bulk_Operations.md} +0 -0
  136. /package/{README_X_Cors.md → docs/GUIDE/GUIDE_X_Cors.md} +0 -0
  137. /package/{README_X_Multihome.md → docs/GUIDE/GUIDE_X_Multihome.md} +0 -0
  138. /package/{README_X_Appendices.md → docs/GUIDE/GUIDE_Y_Appendices.md} +0 -0
  139. /package/{QUERY_DEPTH_PROTECTION.md → docs/README_VARIOUS/QUERY_DEPTH_PROTECTION.md} +0 -0
  140. /package/{RELATIONSHIPS.md → docs/README_VARIOUS/RELATIONSHIPS.md} +0 -0
  141. /package/{WEBSOCKET_IMPLEMENTATION_STATUS.md → docs/README_VARIOUS/WEBSOCKET_IMPLEMENTATION_STATUS.md} +0 -0
  142. /package/{helper-functions-chart.md → docs/README_VARIOUS/helper-functions-chart.md} +0 -0
  143. /package/docs/{implementation-hidden-computed-fields.md → README_VARIOUS/implementation-hidden-computed-fields.md} +0 -0
  144. /package/docs/{include-limits-migration-guide.md → README_VARIOUS/include-limits-migration-guide.md} +0 -0
  145. /package/{readmeSnippets → docs/README_VARIOUS}/test_put_behavior.js +0 -0
  146. /package/{readmeSnippets → docs/README_VARIOUS}/test_put_fields_without_defaults.js +0 -0
@@ -1,252 +0,0 @@
1
- /**
2
- * @module scope-validations
3
- * @description Scope validation functions for REST API plugin
4
- *
5
- * These validations run when scopes are added to ensure proper configuration,
6
- * particularly for complex features like polymorphic relationships. By validating
7
- * at scope registration time, we catch configuration errors early before any
8
- * API requests are made.
9
- */
10
-
11
-
12
- /**
13
- * Validates polymorphic relationships in scope configuration to ensure they are properly defined.
14
- *
15
- * Polymorphic relationships allow a single foreign key to reference multiple different types
16
- * of resources. For example, a 'comments' table might have commentable_type and commentable_id
17
- * fields that can reference either 'posts' or 'videos'. This validation ensures:
18
- *
19
- * 1. All required fields (types, typeField, idField) are defined
20
- * 2. The referenced types actually exist as registered scopes
21
- * 3. The configuration follows the expected structure
22
- *
23
- * This function runs automatically when a scope is added via the 'scope:added' event hook.
24
- * It prevents runtime errors by catching misconfigurations at startup.
25
- *
26
- * @param {Object} params - Parameters object
27
- * @param {Object} params.eventData - The scope:added event data
28
- * @param {string} params.eventData.scopeName - Name of the scope being added
29
- * @param {Object} params.eventData.scopeOptions - Scope options including relationships
30
- * @param {Object} params.api - The API instance for accessing scopes and logging
31
- * @throws {Error} If any polymorphic relationship is invalid
32
- *
33
- * @example <caption>Valid polymorphic relationship - Comments on multiple types</caption>
34
- * // In your comments scope configuration:
35
- * api.addScope('comments', {
36
- * schema: {
37
- * id: { type: 'id' },
38
- * body: { type: 'text' },
39
- * commentable_type: { type: 'string' }, // Stores 'posts' or 'videos'
40
- * commentable_id: { type: 'integer' } // Stores the ID
41
- * },
42
- * relationships: {
43
- * commentable: {
44
- * belongsToPolymorphic: {
45
- * types: ['posts', 'videos'], // Both scopes must already exist
46
- * typeField: 'commentable_type', // Which field stores the type
47
- * idField: 'commentable_id' // Which field stores the ID
48
- * }
49
- * }
50
- * }
51
- * });
52
- * // This configuration allows: comment.commentable_type='posts', comment.commentable_id=123
53
- *
54
- * @example <caption>Invalid - missing required field</caption>
55
- * // This will throw an error:
56
- * api.addScope('attachments', {
57
- * relationships: {
58
- * attachable: {
59
- * belongsToPolymorphic: {
60
- * types: ['documents', 'images'],
61
- * typeField: 'attachable_type'
62
- * // ERROR: Missing idField!
63
- * }
64
- * }
65
- * }
66
- * });
67
- * // Throws: "Invalid polymorphic relationship 'attachable' in scope 'attachments':
68
- * // belongsToPolymorphic.idField must be specified"
69
- *
70
- * @example <caption>Invalid - referencing non-existent scope</caption>
71
- * // This will throw if 'unicorns' scope doesn't exist:
72
- * api.addScope('likes', {
73
- * relationships: {
74
- * likeable: {
75
- * belongsToPolymorphic: {
76
- * types: ['posts', 'unicorns'], // ERROR: 'unicorns' not registered
77
- * typeField: 'likeable_type',
78
- * idField: 'likeable_id'
79
- * }
80
- * }
81
- * }
82
- * });
83
- * // Throws: "Invalid polymorphic relationship 'likeable' in scope 'likes':
84
- * // Polymorphic type 'unicorns' is not a registered scope"
85
- *
86
- * @example <caption>Complex use case - Activity feed with multiple polymorphic relationships</caption>
87
- * // An activity log that tracks different types of events:
88
- * api.addScope('activities', {
89
- * schema: {
90
- * id: { type: 'id' },
91
- * action: { type: 'string' }, // 'created', 'updated', 'deleted'
92
- * // What was acted upon
93
- * trackable_type: { type: 'string' },
94
- * trackable_id: { type: 'integer' },
95
- * // Who performed the action
96
- * actor_type: { type: 'string' },
97
- * actor_id: { type: 'integer' },
98
- * created_at: { type: 'datetime' }
99
- * },
100
- * relationships: {
101
- * // The resource that was changed
102
- * trackable: {
103
- * belongsToPolymorphic: {
104
- * types: ['posts', 'comments', 'users', 'products'],
105
- * typeField: 'trackable_type',
106
- * idField: 'trackable_id'
107
- * }
108
- * },
109
- * // The user or system that made the change
110
- * actor: {
111
- * belongsToPolymorphic: {
112
- * types: ['users', 'api_clients', 'cron_jobs'],
113
- * typeField: 'actor_type',
114
- * idField: 'actor_id'
115
- * }
116
- * }
117
- * }
118
- * });
119
- * // Both polymorphic relationships are validated independently
120
- *
121
- * @example <caption>Why this is useful upstream</caption>
122
- * // This validation prevents:
123
- * // 1. Runtime errors when trying to resolve non-existent scope types
124
- * // 2. Database foreign key violations from invalid type values
125
- * // 3. Confusion from typos in scope names (caught at startup)
126
- * // 4. API inconsistencies from incomplete polymorphic configurations
127
- * // 5. Complex debugging sessions from misconfigured relationships
128
- */
129
- export function validatePolymorphicRelationships({ context, scopes }) {
130
- const { scopeName, scopeOptions } = context;
131
- const relationships = scopeOptions.relationships || {};
132
-
133
- for (const [relName, relDef] of Object.entries(relationships)) {
134
- if (relDef.belongsToPolymorphic) {
135
- const validation = validatePolymorphicRelationship(relDef, scopeName, scopes);
136
- if (!validation.valid) {
137
- throw new Error(
138
- `Invalid polymorphic relationship '${relName}' in scope '${scopeName}': ${validation.error}`
139
- );
140
- }
141
- }
142
- }
143
- }
144
-
145
-
146
- /**
147
- * Validates a polymorphic relationship definition
148
- *
149
- * Called during scope registration to ensure configuration is correct.
150
- * Performs comprehensive validation of polymorphic relationship setup.
151
- * This is a private helper used by validatePolymorphicRelationships.
152
- *
153
- * @param {Object} relDef - The relationship definition object
154
- * @param {Object} relDef.belongsToPolymorphic - Polymorphic configuration
155
- * @param {Array<string>} relDef.belongsToPolymorphic.types - Allowed target types
156
- * @param {string} relDef.belongsToPolymorphic.typeField - Field storing the type
157
- * @param {string} relDef.belongsToPolymorphic.idField - Field storing the ID
158
- * @param {string} scopeName - The scope being registered (for error messages)
159
- * @param {Object} scopes - The hooked-api scopes object containing all registered scopes
160
- * @returns {Object} Validation result
161
- * @returns {boolean} returns.valid - Whether the configuration is valid
162
- * @returns {string} [returns.error] - Error message if invalid
163
- *
164
- * @example <caption>Valid polymorphic configuration</caption>
165
- * const relDef = {
166
- * belongsToPolymorphic: {
167
- * types: ['articles', 'videos', 'products'],
168
- * typeField: 'commentable_type',
169
- * idField: 'commentable_id'
170
- * },
171
- * as: 'commentable'
172
- * };
173
- *
174
- * const result = validatePolymorphicRelationship(relDef, 'comments', scopes);
175
- * // Returns: { valid: true }
176
- *
177
- * @example <caption>Invalid configuration (missing types)</caption>
178
- * const relDef = {
179
- * belongsToPolymorphic: {
180
- * typeField: 'commentable_type',
181
- * idField: 'commentable_id'
182
- * // Missing: types array!
183
- * }
184
- * };
185
- *
186
- * const result = validatePolymorphicRelationship(relDef, 'comments', scopes);
187
- * // Returns: { valid: false, error: 'belongsToPolymorphic.types must be a non-empty array' }
188
- *
189
- * @example <caption>Invalid configuration (unknown scope type)</caption>
190
- * const relDef = {
191
- * belongsToPolymorphic: {
192
- * types: ['articles', 'unicorns'], // 'unicorns' scope doesn't exist
193
- * typeField: 'attachable_type',
194
- * idField: 'attachable_id'
195
- * }
196
- * };
197
- *
198
- * const result = validatePolymorphicRelationship(relDef, 'attachments', scopes);
199
- * // Returns: { valid: false, error: "Polymorphic type 'unicorns' is not a registered scope" }
200
- *
201
- * @private
202
- */
203
- const validatePolymorphicRelationship = (relDef, scopeName, scopes) => {
204
- // Validation logic:
205
- // 1. Check relDef.belongsToPolymorphic exists
206
- // 2. Validate required properties: types, typeField, idField
207
- // 3. Ensure types is non-empty array
208
- // 4. Verify all types are registered scopes
209
- // 5. Check that typeField and idField exist in the schema
210
-
211
- const { belongsToPolymorphic } = relDef;
212
-
213
- if (!belongsToPolymorphic) {
214
- return { valid: false, error: 'Missing belongsToPolymorphic definition' };
215
- }
216
-
217
- const { types, typeField, idField } = belongsToPolymorphic;
218
-
219
- if (!types || !Array.isArray(types) || types.length === 0) {
220
- return {
221
- valid: false,
222
- error: 'belongsToPolymorphic.types must be a non-empty array'
223
- };
224
- }
225
-
226
- if (!typeField || typeof typeField !== 'string') {
227
- return {
228
- valid: false,
229
- error: 'belongsToPolymorphic.typeField must be specified'
230
- };
231
- }
232
-
233
- if (!idField || typeof idField !== 'string') {
234
- return {
235
- valid: false,
236
- error: 'belongsToPolymorphic.idField must be specified'
237
- };
238
- }
239
-
240
- // Check that all types are valid scopes
241
- for (const type of types) {
242
- if (!scopes[type]) {
243
- return {
244
- valid: false,
245
- error: `Polymorphic type '${type}' is not a registered scope`
246
- };
247
- }
248
- }
249
-
250
- return { valid: true };
251
- };
252
-