json-rest-api 1.0.28 → 2.0.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 (289) 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 +746 -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 +634 -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 +100 -0
  36. package/docs/GUIDE/31-positioning.md +181 -0
  37. package/docs/GUIDE/{GUIDE_Y_Appendices.md → 32-date-and-time.md} +90 -31
  38. package/docs/GUIDE/33-migrating-to-v2.md +3827 -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 +36 -0
  44. package/index.js +1 -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 +64 -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 -174
  67. package/plugins/core/lib/anyapi/anyapi-registry.js +213 -164
  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 +25 -16
  71. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +0 -64
  72. package/plugins/core/lib/dbIntrospection.js +228 -21
  73. package/plugins/core/lib/dbTablesOperations.js +409 -92
  74. package/plugins/core/lib/fractional-positioning.js +12 -48
  75. package/plugins/core/lib/querying/identifier-query.js +19 -0
  76. package/plugins/core/lib/querying/include-query-helpers.js +364 -0
  77. package/plugins/core/lib/querying/include-to-many.js +428 -0
  78. package/plugins/core/lib/querying/include-to-one.js +579 -0
  79. package/plugins/core/lib/querying/knex-cross-table-search.js +31 -307
  80. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +99 -401
  81. package/plugins/core/lib/querying/knex-pagination-helpers.js +67 -330
  82. package/plugins/core/lib/querying/knex-process-includes.js +5 -110
  83. package/plugins/core/lib/querying/knex-query-helpers-base.js +21 -56
  84. package/plugins/core/lib/querying/knex-query-helpers.js +298 -448
  85. package/plugins/core/lib/querying/knex-relationship-includes.js +120 -2138
  86. package/plugins/core/lib/querying/knex-window-queries.js +62 -253
  87. package/plugins/core/lib/querying/query-builder-utils.js +44 -4
  88. package/plugins/core/lib/querying/query-constraint.d.ts +12 -0
  89. package/plugins/core/lib/querying/query-constraint.js +27 -0
  90. package/plugins/core/lib/querying/query-field-sort-helpers.js +205 -30
  91. package/plugins/core/lib/querying/relationship-identifiers.js +208 -0
  92. package/plugins/core/lib/querying/sort-helpers.js +20 -1
  93. package/plugins/core/lib/querying/storage-adapter-utils.js +13 -5
  94. package/plugins/core/lib/querying/url-helpers.js +11 -4
  95. package/plugins/core/lib/querying-writing/compile-schemas.js +148 -249
  96. package/plugins/core/lib/querying-writing/connectors-query-parser.js +33 -118
  97. package/plugins/core/lib/querying-writing/database-capabilities.js +149 -223
  98. package/plugins/core/lib/querying-writing/database-value-normalizers.js +238 -187
  99. package/plugins/core/lib/querying-writing/default-data-helpers.js +15 -45
  100. package/plugins/core/lib/querying-writing/field-selection-types.d.ts +43 -0
  101. package/plugins/core/lib/querying-writing/field-utils.js +113 -92
  102. package/plugins/core/lib/querying-writing/knex-constants.d.ts +18 -0
  103. package/plugins/core/lib/querying-writing/knex-constants.js +2 -26
  104. package/plugins/core/lib/querying-writing/knex-field-helpers.js +111 -287
  105. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +31 -120
  106. package/plugins/core/lib/querying-writing/query-field-helpers.js +108 -32
  107. package/plugins/core/lib/querying-writing/query-field-types.d.ts +60 -0
  108. package/plugins/core/lib/querying-writing/relationship-contracts.js +33 -13
  109. package/plugins/core/lib/querying-writing/request-contracts.js +109 -44
  110. package/plugins/core/lib/querying-writing/resource-id-normalization.js +23 -5
  111. package/plugins/core/lib/querying-writing/response-options.js +35 -0
  112. package/plugins/core/lib/querying-writing/schema-helpers.js +203 -324
  113. package/plugins/core/lib/querying-writing/scope-validations.js +92 -290
  114. package/plugins/core/lib/querying-writing/simplified-helpers.js +113 -712
  115. package/plugins/core/lib/storage/canonical-data-helpers.js +683 -0
  116. package/plugins/core/lib/storage/canonical-storage-mapping.js +51 -20
  117. package/plugins/core/lib/storage/ordinary-data-helpers.js +710 -0
  118. package/plugins/core/lib/storage/storage-adapter.js +142 -62
  119. package/plugins/core/lib/storage/storage-mapping.js +78 -28
  120. package/plugins/core/lib/storage/storage-types.d.ts +502 -0
  121. package/plugins/core/lib/writing/many-to-many-manipulations.js +114 -284
  122. package/plugins/core/lib/writing/relationship-processor.js +94 -158
  123. package/plugins/core/lib/writing/resource-version.js +172 -0
  124. package/plugins/core/lib/writing/reverse-relationship-manipulations.js +110 -0
  125. package/plugins/core/rest-api-anyapi-knex-plugin.js +116 -2509
  126. package/plugins/core/rest-api-autofilter-plugin.js +17 -19
  127. package/plugins/core/rest-api-cors-plugin.js +52 -205
  128. package/plugins/core/rest-api-knex-plugin.js +45 -1069
  129. package/plugins/core/rest-api-label-plugin.js +25 -38
  130. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +5 -5
  131. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +9 -6
  132. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +7 -26
  133. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +20 -26
  134. package/plugins/core/rest-api-plugin-methods/add-route.js +4 -6
  135. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +42 -13
  136. package/plugins/core/rest-api-plugin-methods/check-permissions.js +11 -5
  137. package/plugins/core/rest-api-plugin-methods/common.js +291 -385
  138. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +49 -47
  139. package/plugins/core/rest-api-plugin-methods/delete.js +31 -25
  140. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +108 -145
  141. package/plugins/core/rest-api-plugin-methods/get-related.js +113 -305
  142. package/plugins/core/rest-api-plugin-methods/get-relationship.js +25 -18
  143. package/plugins/core/rest-api-plugin-methods/get.js +38 -69
  144. package/plugins/core/rest-api-plugin-methods/lifecycle-types.d.ts +225 -0
  145. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +28 -25
  146. package/plugins/core/rest-api-plugin-methods/patch.js +46 -99
  147. package/plugins/core/rest-api-plugin-methods/post-relationship.js +49 -53
  148. package/plugins/core/rest-api-plugin-methods/post.js +51 -51
  149. package/plugins/core/rest-api-plugin-methods/put.js +69 -148
  150. package/plugins/core/rest-api-plugin-methods/query.js +39 -82
  151. package/plugins/core/rest-api-plugin-methods/release.js +2 -1
  152. package/plugins/core/rest-api-plugin.js +32 -46
  153. package/plugins/core/rest-api-positioning-plugin.js +183 -628
  154. package/plugins/core/rest-api-query-projections-plugin.js +19 -102
  155. package/plugins/core/rest-api-row-policy-plugin.js +3 -3
  156. package/plugins/core/socketio-plugin.js +364 -344
  157. package/plugins/storage/local-storage.js +40 -36
  158. package/types/autofilter.d.ts +57 -0
  159. package/types/bulk-methods.d.ts +63 -0
  160. package/types/errors.d.ts +118 -0
  161. package/types/fastify-options.d.ts +19 -0
  162. package/types/file-detectors.d.ts +33 -0
  163. package/types/file-storage.d.ts +48 -0
  164. package/types/hook-context.d.ts +180 -0
  165. package/types/plugin-options.d.ts +53 -0
  166. package/types/relationship-methods.d.ts +74 -0
  167. package/types/representations.d.ts +50 -0
  168. package/types/resource-methods.d.ts +95 -0
  169. package/types/resource-schema.d.ts +157 -0
  170. package/types/row-policy.d.ts +31 -0
  171. package/types/runtime.d.ts +132 -0
  172. package/types/transactions.d.ts +21 -0
  173. package/.claude/agents/library-guide-expert.md +0 -30
  174. package/.claude/agents/rest-api-internals-expert.md +0 -54
  175. package/.claude/settings.local.json +0 -70
  176. package/AGENTS.md +0 -34
  177. package/CLAUDE.md +0 -160
  178. package/CRUSH.md +0 -55
  179. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +0 -180
  180. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +0 -172
  181. package/TODO.todo +0 -13
  182. package/connectors_ideas/fastify.js +0 -217
  183. package/connectors_ideas/koa-plugin.js +0 -112
  184. package/docs/.bundle/config +0 -2
  185. package/docs/COMPARISON.md +0 -433
  186. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +0 -1057
  187. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +0 -88
  188. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +0 -808
  189. package/docs/GUIDE/GUIDE_2_3_BelongsTo_Relationships.md +0 -491
  190. package/docs/GUIDE/GUIDE_2_4_HasMany_Records.md +0 -398
  191. package/docs/GUIDE/GUIDE_2_5_HasMany_Polymorphic.md +0 -898
  192. package/docs/GUIDE/GUIDE_2_6_Many_To_Many.md +0 -712
  193. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +0 -1238
  194. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +0 -748
  195. package/docs/GUIDE/GUIDE_2_9_Relationships_Urls.md +0 -517
  196. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +0 -66
  197. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +0 -1252
  198. package/docs/GUIDE/GUIDE_5_Non-Db_Resources.md +0 -1107
  199. package/docs/GUIDE/GUIDE_6_Positioning.md +0 -692
  200. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +0 -1491
  201. package/docs/GUIDE/GUIDE_X_Bulk_Operations.md +0 -732
  202. package/docs/GUIDE/GUIDE_X_Cors.md +0 -1957
  203. package/docs/GUIDE/GUIDE_X_Fastify.md +0 -78
  204. package/docs/GUIDE/GUIDE_X_File_Uploads.md +0 -729
  205. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +0 -370
  206. package/docs/GUIDE/GUIDE_X_Query_Projections.md +0 -159
  207. package/docs/GUIDE/GUIDE_X_SocketIO.md +0 -1040
  208. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +0 -201
  209. package/docs/Gemfile +0 -6
  210. package/docs/Gemfile.lock +0 -308
  211. package/docs/ONBOARDING.md +0 -315
  212. package/docs/_config.yml +0 -36
  213. package/docs/_layouts/default.html +0 -123
  214. package/docs/apple-touch-icon.svg +0 -4
  215. package/docs/assets/css/style.scss +0 -392
  216. package/docs/favicon.svg +0 -4
  217. package/docs/index.md +0 -164
  218. package/docs/mini-guides/file-uploads-complete.md +0 -161
  219. package/eslint.config.js +0 -13
  220. package/examples/url-override-example.js +0 -137
  221. package/fixing_plan.md +0 -112
  222. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +0 -657
  223. package/plugins/core/lib/querying-writing/return-record-settings.js +0 -47
  224. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +0 -110
  225. package/plugins/storage/s3-storage.js +0 -93
  226. package/quickTest.js +0 -136
  227. package/scripts/debug-anyapi-review-filter.mjs +0 -63
  228. package/scripts/inspect-anyapi-descriptor-country.mjs +0 -19
  229. package/scripts/inspect-anyapi-descriptor.mjs +0 -19
  230. package/scripts/run-docs.js +0 -133
  231. package/test-debug.js +0 -59
  232. package/tests/README.md +0 -202
  233. package/tests/TEST_TEMPLATE.test.js +0 -178
  234. package/tests/anyapi-basic.test.js +0 -105
  235. package/tests/anyapi-cursor-pagination.test.js +0 -150
  236. package/tests/anyapi-custom-idproperty.test.js +0 -163
  237. package/tests/autofilter.test.js +0 -463
  238. package/tests/bulk-operations.test.js +0 -657
  239. package/tests/computed-fields.test.js +0 -586
  240. package/tests/cors.test.js +0 -834
  241. package/tests/curl.test.js +0 -467
  242. package/tests/custom-id-mysql-returning-fallback.test.js +0 -128
  243. package/tests/custom-id-simplified-post.test.js +0 -75
  244. package/tests/custom-idproperty-relationships.test.js +0 -932
  245. package/tests/db-introspection.test.js +0 -521
  246. package/tests/db-table-operations.test.js +0 -798
  247. package/tests/fastify-plugin.test.js +0 -184
  248. package/tests/field-getters.test.js +0 -370
  249. package/tests/field-setters.test.js +0 -306
  250. package/tests/file-handling.test.js +0 -118
  251. package/tests/fixtures/api-configs.js +0 -2509
  252. package/tests/full-jsonapi-belongsto-linkage.test.js +0 -150
  253. package/tests/helpers/fake-fastify.js +0 -99
  254. package/tests/helpers/storage-mode.js +0 -65
  255. package/tests/helpers/test-utils.js +0 -203
  256. package/tests/http-connectors-parity.test.js +0 -395
  257. package/tests/id-normalization.test.js +0 -444
  258. package/tests/include-depth-validation.test.js +0 -331
  259. package/tests/includes.test.js +0 -427
  260. package/tests/local-storage.test.js +0 -96
  261. package/tests/logical-id-write-validation.test.js +0 -151
  262. package/tests/nested-includes.test.js +0 -617
  263. package/tests/pagination-cursor-multifield.test.js +0 -643
  264. package/tests/pagination-enhanced.test.js +0 -563
  265. package/tests/polymorphic-relationships.test.js +0 -347
  266. package/tests/polymorphic-simple.test.js +0 -148
  267. package/tests/positioning-advanced.test.js +0 -692
  268. package/tests/positioning-extended.test.js +0 -915
  269. package/tests/positioning-multifilter.test.js +0 -699
  270. package/tests/positioning.test.js +0 -560
  271. package/tests/post-commit-hooks.test.js +0 -120
  272. package/tests/projected-fields.test.js +0 -319
  273. package/tests/public-exports.test.js +0 -15
  274. package/tests/put-create-parity.test.js +0 -216
  275. package/tests/queries.test.js +0 -521
  276. package/tests/query-limits.test.js +0 -584
  277. package/tests/relationship-endpoints.test.js +0 -620
  278. package/tests/relationship-include-storage-adapter.test.js +0 -56
  279. package/tests/relationships.test.js +0 -681
  280. package/tests/rest-api.test.js +0 -337
  281. package/tests/return-record-settings.test.js +0 -184
  282. package/tests/row-policy.test.js +0 -489
  283. package/tests/s3-storage.test.js +0 -38
  284. package/tests/searchschema-knex-behavior.test.js +0 -187
  285. package/tests/searchschema-merge.test.js +0 -151
  286. package/tests/socketio.test.js +0 -860
  287. package/tests/storage-mapping.test.js +0 -362
  288. package/tests/test-development-guide.md +0 -370
  289. package/tests/virtual-fields.test.js +0 -404
@@ -0,0 +1,502 @@
1
+ import type { JsonApiDocument, JsonApiLinks, JsonApiRelationship, JsonApiResource } from '../../../../types/representations.js'
2
+ import type { SelectionParams } from '../../../../types/resource-methods.js'
3
+ import { RELATIONSHIPS_KEY } from '../querying-writing/knex-constants.js'
4
+ import { queryConstraint } from '../querying/query-constraint.js'
5
+ import type { TransactionContext } from '../../../../lib/transaction-types.js'
6
+ import type { Knex } from 'knex'
7
+
8
+ // Internal boundary types. Values remain unknown until their schema/driver owns conversion.
9
+ export type StorageRow = Record<string, unknown>
10
+ export type StorageQuery = Knex.QueryBuilder<StorageRow, StorageRow[]>
11
+ export type StorageDatabase = Knex<StorageRow, StorageRow[]>
12
+ export interface MandatoryQueryConstraint {
13
+ scopeName: string
14
+ values?: StorageRow
15
+ idsQuery?: StorageQuery
16
+ }
17
+ export type SelectColumn = string | Knex.Raw<unknown> | StorageQuery | Record<string, string>
18
+ export type SelectColumns = SelectColumn[] | Record<string, string> | null | undefined
19
+ export type SelectTranslator = (field: string, alias?: string | null) => string
20
+ export type StorageNaming = 'snake_case' | 'exact'
21
+
22
+ export interface StorageConfig {
23
+ naming?: 'snake' | 'snake_case' | 'snakeCase' | 'exact' | 'field' | 'verbatim'
24
+ [option: string]: unknown
25
+ }
26
+
27
+ export interface StorageContext {
28
+ scopeName?: string
29
+ [key: string]: unknown
30
+ }
31
+
32
+ export interface StorageWriteOptions {
33
+ context?: StorageContext | null
34
+ operation?: string | null
35
+ databaseClient?: string
36
+ }
37
+
38
+ export interface StorageSerializerDetails extends StorageWriteOptions {
39
+ fieldName?: string
40
+ columnName?: string
41
+ definition: StorageFieldDefinition
42
+ schemaInfo?: Partial<StorageSchemaInfo>
43
+ }
44
+
45
+ export interface StorageFieldDefinition {
46
+ type?: string
47
+ dataType?: string
48
+ temporalPrecision?: number
49
+ virtual?: boolean
50
+ computed?: boolean
51
+ hidden?: boolean
52
+ normallyHidden?: boolean
53
+ belongsTo?: string
54
+ as?: string
55
+ belongsToPolymorphic?: unknown
56
+ actualField?: string
57
+ isRelationship?: boolean
58
+ storage?: {
59
+ column?: string
60
+ serialize?: (value: unknown, details: StorageSerializerDetails) => unknown
61
+ }
62
+ [option: string]: unknown
63
+ }
64
+
65
+ export interface FieldStorage {
66
+ column: string
67
+ serialize: NonNullable<StorageFieldDefinition['storage']>['serialize'] | null
68
+ persisted: boolean
69
+ definition: StorageFieldDefinition
70
+ }
71
+
72
+ export interface StorageInfo {
73
+ idColumn: string
74
+ storage: StorageConfig & { naming: StorageNaming }
75
+ fields: Record<string, FieldStorage>
76
+ columns: Record<string, string>
77
+ }
78
+
79
+ export interface CanonicalFieldSlot {
80
+ slot: string
81
+ slotType: string
82
+ alias?: string
83
+ }
84
+
85
+ export interface CanonicalDescriptor {
86
+ tenant: string
87
+ resource: string
88
+ idProperty?: string
89
+ canonical: {
90
+ tableName: string
91
+ tenantColumn: string
92
+ resourceColumn: string
93
+ logicalIdColumn?: string
94
+ }
95
+ fields?: Record<string, CanonicalFieldSlot>
96
+ schema?: Record<string, StorageFieldDefinition>
97
+ reverseAttributes?: Record<string, string>
98
+ canonicalFieldMap?: Record<string, string | {
99
+ slot?: string
100
+ slotColumn?: string
101
+ idSlot?: string
102
+ typeSlot?: string
103
+ }>
104
+ belongsTo?: Record<string, { idColumn: string; typeColumn: string; target: string }>
105
+ polymorphicBelongsTo?: Record<string, {
106
+ typeField: string
107
+ idField: string
108
+ typeColumn?: string
109
+ idColumn?: string
110
+ types: string[]
111
+ }>
112
+ }
113
+
114
+ export interface StorageSchemaInfo {
115
+ tableName: string
116
+ idProperty?: string
117
+ schemaStructure: Record<string, StorageFieldDefinition>
118
+ searchSchemaStructure?: Record<string, StorageFieldDefinition>
119
+ computed?: Record<string, StorageFieldDefinition>
120
+ storage?: StorageConfig
121
+ storageInfo?: StorageInfo
122
+ descriptor?: CanonicalDescriptor
123
+ }
124
+
125
+ export interface ResourceConversionSchema extends StorageSchemaInfo {
126
+ foreignKeyFields: ReadonlySet<string>
127
+ schemaRelationships?: Record<string, StorageFieldDefinition & {
128
+ belongsToPolymorphic?: { typeField: string; idField: string; types?: readonly string[] }
129
+ }>
130
+ }
131
+
132
+ export interface ResourceConversionScope {
133
+ vars: { schemaInfo: ResourceConversionSchema }
134
+ }
135
+
136
+ export interface StorageAdapter {
137
+ isCanonical(): boolean
138
+ getTableName(): string
139
+ getIdColumn(): string
140
+ translateColumn(field: string): string
141
+ translateFilterValue(field: string, value: unknown): unknown
142
+ translateCursorValue(field: string, value: unknown): unknown
143
+ applyResourceScope(query: StorageQuery, tableAlias?: string): StorageQuery
144
+ toStorageRow(attributes: StorageRow, options?: StorageWriteOptions): StorageRow
145
+ getFieldValue(record: StorageRow | null | undefined, fieldName: string): unknown
146
+ // Some internal callers pass a Knex instance through this option; neither handle is owned here.
147
+ buildBaseQuery(options?: { transaction?: StorageDatabase | null; tableAlias?: string }): StorageQuery
148
+ selectColumns(builder: StorageQuery, columns: SelectColumns): StorageQuery
149
+ }
150
+
151
+ export interface StorageAdapterOptions {
152
+ knex: StorageDatabase
153
+ schemaInfo: StorageSchemaInfo
154
+ }
155
+
156
+ export interface BaseStorageAdapterOptions {
157
+ knex: StorageDatabase
158
+ tableName: string
159
+ idColumn: string
160
+ translateColumn: StorageAdapter['translateColumn']
161
+ translateFilterValue?: StorageAdapter['translateFilterValue']
162
+ translateCursorValue?: StorageAdapter['translateCursorValue']
163
+ applyResourceScope?: StorageAdapter['applyResourceScope']
164
+ toStorageRow?: StorageAdapter['toStorageRow']
165
+ getFieldValue?: StorageAdapter['getFieldValue']
166
+ isCanonical?: boolean
167
+ }
168
+
169
+ export interface StorageHookParams {
170
+ context?: {
171
+ knexQuery?: { scopeName?: string; tableName?: string; storageAdapter?: StorageAdapter }
172
+ storageAdapter?: StorageAdapter
173
+ }
174
+ }
175
+
176
+ export interface StorageResource {
177
+ vars?: { schemaInfo?: StorageSchemaInfo; storageAdapter?: StorageAdapter }
178
+ }
179
+
180
+ export interface StorageAdapterLookupOptions {
181
+ knex: StorageDatabase
182
+ getResource: (scopeName: string) => StorageResource | null | undefined
183
+ }
184
+
185
+ // Hook state may be cleared; entering filtering always requires a live builder.
186
+ export interface QueryFilteringState {
187
+ query?: StorageQuery | null
188
+ filters?: Record<string, unknown>
189
+ schemaInfo?: StorageSchemaInfo
190
+ scopeName?: string
191
+ tableName?: string
192
+ db?: StorageDatabase
193
+ queryPurpose?: string
194
+ adapter?: StorageAdapter
195
+ storageAdapter?: StorageAdapter
196
+ isAnyApi?: boolean
197
+ }
198
+
199
+ // Attributes have passed setters; their values need not be public JSON values.
200
+ export interface StorageInputRecord {
201
+ data: {
202
+ id?: string | number
203
+ type?: string
204
+ attributes?: StorageRow
205
+ relationships?: Record<string, unknown>
206
+ }
207
+ }
208
+
209
+ export interface DataWriteContext extends TransactionContext, StorageContext {
210
+ db: StorageDatabase
211
+ schemaInfo: DataOperationSchema
212
+ storageAdapter?: StorageAdapter
213
+ inputRecord: StorageInputRecord
214
+ }
215
+
216
+ export interface DataIdentityContext extends TransactionContext, StorageContext {
217
+ db: StorageDatabase
218
+ schemaInfo: DataOperationSchema
219
+ storageAdapter?: StorageAdapter
220
+ id: string | number
221
+ }
222
+
223
+ export interface DataWriteHelpers<UpdateResult, DeleteResult> {
224
+ dataExists: (request: { scopeName: string, context: DataIdentityContext }) => Promise<boolean>
225
+ // POST preserves backend-dependent insert results; do not assume a scalar type here.
226
+ dataPost: (request: { scopeName: string, context: DataWriteContext }) => Promise<unknown>
227
+ dataPut: (request: {
228
+ scopeName: string
229
+ context: DataWriteContext & DataIdentityContext & { isCreate: boolean }
230
+ }) => Promise<UpdateResult>
231
+ dataPatch: (request: {
232
+ scopeName: string
233
+ context: DataWriteContext & DataIdentityContext
234
+ }) => Promise<UpdateResult>
235
+ dataDelete: (request: { scopeName: string, context: DataIdentityContext }) => Promise<DeleteResult>
236
+ }
237
+
238
+ export type OrdinaryDataWriteHelpers = DataWriteHelpers<void, { success: true }>
239
+ export type CanonicalDataWriteHelpers = DataWriteHelpers<number, number>
240
+
241
+ // Read helpers assemble resource-shaped values before final output normalization.
242
+ export interface DataResource extends JsonApiResource {
243
+ __$jsonrestapi_computed_deps$__?: string[]
244
+ }
245
+
246
+ export type DataDocument<T> = JsonApiDocument<T>
247
+
248
+ export interface DataStorageRow extends StorageRow {
249
+ [RELATIONSHIPS_KEY]?: Record<string, JsonApiRelationship>
250
+ }
251
+
252
+ export interface DataReadContext extends TransactionContext, StorageContext {
253
+ scopeName: string
254
+ [queryConstraint]?: MandatoryQueryConstraint
255
+ db: StorageDatabase
256
+ schemaInfo: DataOperationSchema
257
+ storageAdapter?: StorageAdapter
258
+ id?: string | number
259
+ queryParams?: {
260
+ filters?: StorageRow
261
+ fields?: SelectionParams['fields']
262
+ include?: string[]
263
+ sort?: string[]
264
+ page?: { size?: number; number?: number; before?: string; after?: string }
265
+ }
266
+ knexQuery?: QueryFilteringState | null
267
+ computedDependencies?: string[]
268
+ returnMeta?: {
269
+ queryString?: string
270
+ paginationMeta?: object
271
+ paginationLinks?: JsonApiLinks | null
272
+ [key: string]: unknown
273
+ }
274
+ sortableFields?: string[]
275
+ }
276
+
277
+ export interface DataReadRequest {
278
+ scopeName: string
279
+ context: DataReadContext
280
+ runHooks?: (name: 'knexQueryFiltering') => unknown | Promise<unknown>
281
+ }
282
+
283
+ export type QueryBuilderResult = StorageQuery | { query: QueryBuilderResult }
284
+
285
+ export interface DataMinimalRequest extends DataReadRequest {
286
+ filters?: StorageRow
287
+ queryPurpose?: string
288
+ applyQueryFilters?: (params: QueryFilteringState & { query: StorageQuery }) => Promise<{ query: QueryBuilderResult } | null | undefined>
289
+ }
290
+
291
+ export interface DataMinimalReader {
292
+ (request: DataMinimalRequest & { ids: Array<string | number> }): Promise<DataResource[]>
293
+ (request: DataMinimalRequest & {
294
+ ids?: undefined
295
+ context: DataReadContext & { id: string | number }
296
+ }): Promise<DataResource | null>
297
+ }
298
+
299
+ export interface DataReadHelpers<GetResult> {
300
+ dataGetMinimal: DataMinimalReader
301
+ dataGet: (request: DataReadRequest & {
302
+ context: DataReadContext & { id: string | number }
303
+ }) => Promise<GetResult>
304
+ dataQuery: (request: DataReadRequest & {
305
+ runHooks: NonNullable<DataReadRequest['runHooks']>
306
+ context: DataReadContext & {
307
+ queryParams: NonNullable<DataReadContext['queryParams']>
308
+ }
309
+ }) => Promise<DataDocument<DataResource[]>>
310
+ }
311
+
312
+ export type OrdinaryDataReadHelpers = DataReadHelpers<DataDocument<DataResource>>
313
+ export type CanonicalDataReadHelpers = DataReadHelpers<DataDocument<DataResource> | null>
314
+
315
+ export interface DatabaseInfo {
316
+ client: string
317
+ version: string
318
+ error?: string
319
+ }
320
+
321
+ export interface CapabilityLogger {
322
+ warn(message: string, details: unknown): unknown
323
+ }
324
+
325
+ export type InsertResultMode = 'insert-id' | 'rows' | 'driver-defined'
326
+
327
+ export interface TemporalStorageCapabilities {
328
+ dateMinYear: number
329
+ dateTimeMinYear: number
330
+ maxYear: number
331
+ dateTimeFractionDigits: number
332
+ timeFractionDigits: number | null
333
+ }
334
+
335
+ export interface SchemaCapabilities {
336
+ recognizedDialect: boolean
337
+ fieldAlteration: 'standalone' | 'sqlite-rebuild' | 'transaction'
338
+ callerFieldAlteration: 'forbidden' | 'foreign-keys-off' | 'savepoint'
339
+ temporalColumnFractionDigits: number | null
340
+ setValues: boolean
341
+ }
342
+
343
+ export interface SerializationCapabilities {
344
+ readonly customSerializerResult: 'synchronous'
345
+ readonly structuredTypes: readonly string[]
346
+ readonly structuredEncoding: 'json'
347
+ readonly wholeDocumentPredicates: false
348
+ }
349
+
350
+ export interface RelationshipCapabilities {
351
+ readonly attributeKinds: readonly string[]
352
+ readonly declaredCardinalities: {
353
+ readonly hasOne: 'one'
354
+ readonly hasMany: 'many'
355
+ readonly manyToMany: 'many'
356
+ }
357
+ }
358
+
359
+ export interface DatabaseCapabilities {
360
+ dbInfo: DatabaseInfo
361
+ windowFunctions: boolean
362
+ insertResult: InsertResultMode
363
+ serialization: SerializationCapabilities
364
+ relationships: RelationshipCapabilities
365
+ temporal: { native: TemporalStorageCapabilities; text: TemporalStorageCapabilities }
366
+ schema: SchemaCapabilities
367
+ }
368
+
369
+ export interface PivotRelationship {
370
+ through: string
371
+ foreignKey: string
372
+ otherKey: string
373
+ }
374
+
375
+ export interface RelatedQueryRequest {
376
+ scopeName: string
377
+ context: TransactionContext & { db: StorageDatabase; id: string | number; relationshipName: string }
378
+ relDef: PivotRelationship
379
+ }
380
+
381
+ // Wrap thenable builders so awaiting the helper does not execute its subquery.
382
+ export type DataRelatedIdsQuery = (request: RelatedQueryRequest) => Promise<{ query: StorageQuery }>
383
+ export type CanonicalDataRelatedIdsQuery = (request: Omit<RelatedQueryRequest, 'relDef'> & { relDef?: unknown }) => Promise<{ query: StorageQuery }>
384
+
385
+ export interface CanonicalLinkContext extends TransactionContext {
386
+ db?: StorageDatabase
387
+ id: string | number
388
+ }
389
+
390
+ export interface CanonicalLinkRequest {
391
+ scopeName: string
392
+ relName: string
393
+ context: CanonicalLinkContext
394
+ }
395
+
396
+ export interface CanonicalLinkMutation extends CanonicalLinkRequest {
397
+ relData: Array<{ type: string; id: string | number }>
398
+ relDef?: unknown
399
+ }
400
+
401
+ export interface CanonicalLinkHelpers {
402
+ attachMany(request: CanonicalLinkMutation): Promise<void>
403
+ syncMany(request: CanonicalLinkMutation & { isUpdate: boolean }): Promise<void>
404
+ removeMany(request: CanonicalLinkMutation): Promise<void>
405
+ listMany(request: CanonicalLinkRequest): Promise<Array<{ type: string; id: string | null }>>
406
+ fetchManyToManyRows(request: {
407
+ scopeName: string
408
+ relName: string
409
+ parentIds: Array<string | number>
410
+ context: Omit<CanonicalLinkContext, 'id'>
411
+ }): Promise<Array<{ parentId: string; childId: string; childType: string }>>
412
+ }
413
+
414
+ export interface DataOperationSchema extends ResourceConversionSchema {
415
+ idProperty: string
416
+ queryFields?: Record<string, import('../querying-writing/query-field-types.js').CompiledQueryField>
417
+ }
418
+
419
+ export interface DataOperationScope {
420
+ checkPermissions(request: { method: 'query', originalContext: DataReadContext }): Promise<unknown>
421
+ applyQueryFilters(request: QueryFilteringState, context: DataReadContext): Promise<{ query: QueryBuilderResult } | null | undefined>
422
+ name?: string
423
+ scopeName?: string
424
+ vars: {
425
+ schemaInfo: DataOperationSchema
426
+ defaultSort?: string[]
427
+ enablePaginationCounts?: boolean
428
+ queryDefaultLimit?: number
429
+ queryMaxLimit?: number
430
+ [option: string]: unknown
431
+ }
432
+ }
433
+
434
+ export interface DataOperationApi {
435
+ resources: Record<string, DataOperationScope>
436
+ knex: { instance: StorageDatabase }
437
+ }
438
+
439
+ export interface DataSortDescriptor {
440
+ field: string
441
+ direction: string
442
+ column?: string
443
+ resultColumn?: string
444
+ actualField?: string
445
+ referenceField?: string
446
+ definition?: StorageFieldDefinition | null
447
+ isRelationship: boolean
448
+ queryFieldRuntime?: import('../querying-writing/query-field-types.js').ProjectionRuntime
449
+ }
450
+
451
+ export interface DataSortRequest {
452
+ query: StorageQuery
453
+ sort?: unknown
454
+ schemaInfo: StorageSchemaInfo
455
+ sortableFields?: string[]
456
+ storageAdapter: StorageAdapter
457
+ defaultSort?: string[]
458
+ scopeName: string
459
+ context: DataReadContext
460
+ before?: boolean
461
+ queryFieldRuntimeByField: Map<string, import('../querying-writing/query-field-types.js').ProjectionRuntime>
462
+ }
463
+
464
+ export interface OrdinaryDataDependencies {
465
+ api: DataOperationApi
466
+ scopes: Record<string, DataOperationScope>
467
+ knex: StorageDatabase
468
+ log: import('../../../../types/runtime.js').RuntimeLogger
469
+ getScopeStorageAdapter(scopeName: string): StorageAdapter | null
470
+ }
471
+
472
+ export interface DataCursorOptions {
473
+ schemaInfo?: StorageSchemaInfo | null
474
+ definitions?: Record<string, StorageFieldDefinition | null | undefined>
475
+ before?: boolean
476
+ }
477
+
478
+ export interface CanonicalDataDependencies {
479
+ api: DataOperationApi
480
+ knex: StorageDatabase
481
+ getScopeStorageAdapter(scopeName: string): StorageAdapter | null
482
+ getDescriptor(scopeName: string): CanonicalDescriptor
483
+ linkStore: {
484
+ invalidateDeletedLinkTargets(scopeName: string, context: DataIdentityContext): Promise<void>
485
+ deleteResourceLinks(request: { descriptor: CanonicalDescriptor, scopeName: string, id: string | number, db: StorageDatabase }): Promise<void>
486
+ }
487
+ buildIncludes(request: { parentResources: DataResource[], descriptor: CanonicalDescriptor, context: DataReadContext }): Promise<DataResource[]>
488
+ attachReverseRelationships(request: { resources: DataResource[], descriptor: CanonicalDescriptor, context: DataReadContext }): Promise<void>
489
+ attachManyToManyRelationships(request: { resources: DataResource[], descriptor: CanonicalDescriptor, context: DataReadContext }): Promise<void>
490
+ applyBuiltInAnyApiQueryFilters(context: DataReadContext): Promise<void>
491
+ }
492
+
493
+ export interface CanonicalDataSortRequest {
494
+ query: StorageQuery
495
+ sort?: string[]
496
+ descriptor: CanonicalDescriptor
497
+ scope: DataOperationScope
498
+ tableAlias: string
499
+ context: DataReadContext
500
+ before?: boolean
501
+ queryFieldRuntimeByField: Map<string, import('../querying-writing/query-field-types.js').ProjectionRuntime>
502
+ }