@warp-drive/legacy 5.9.0-beta.0 → 5.9.0-beta.2

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 (468) hide show
  1. package/README.md +6 -0
  2. package/dist/-private-DQ6Iap2t.js +193 -0
  3. package/dist/-private-DQ6Iap2t.js.map +1 -0
  4. package/dist/-private-DccRZQsm.js +904 -0
  5. package/dist/-private-DccRZQsm.js.map +1 -0
  6. package/dist/adapter/-private.d.ts +33 -0
  7. package/dist/adapter/-private.d.ts.map +1 -0
  8. package/dist/adapter/-private.js +3 -1
  9. package/dist/adapter/error.d.ts +2 -0
  10. package/dist/adapter/error.js +425 -311
  11. package/dist/adapter/error.js.map +1 -0
  12. package/{declarations → dist}/adapter/json-api.d.ts +31 -19
  13. package/dist/adapter/json-api.d.ts.map +1 -0
  14. package/dist/adapter/json-api.js +265 -131
  15. package/dist/adapter/json-api.js.map +1 -0
  16. package/dist/adapter/rest.d.ts +2 -0
  17. package/dist/adapter/rest.js +937 -1100
  18. package/dist/adapter/rest.js.map +1 -0
  19. package/dist/adapter-CARrK3-8.d.ts +784 -0
  20. package/dist/adapter-CARrK3-8.d.ts.map +1 -0
  21. package/dist/adapter-eYo2pIuM.js +1130 -0
  22. package/dist/adapter-eYo2pIuM.js.map +1 -0
  23. package/dist/adapter.d.ts +2 -0
  24. package/dist/adapter.js +1 -1251
  25. package/dist/compat/-private.d.ts +2 -0
  26. package/dist/compat/-private.js +3 -1
  27. package/dist/compat/builders.d.ts +169 -0
  28. package/dist/compat/builders.d.ts.map +1 -0
  29. package/dist/compat/builders.js +205 -246
  30. package/dist/compat/builders.js.map +1 -0
  31. package/dist/compat/extensions.d.ts +2 -0
  32. package/dist/compat/extensions.js +271 -233
  33. package/dist/compat/extensions.js.map +1 -0
  34. package/dist/compat/utils.d.ts +151 -0
  35. package/dist/compat/utils.d.ts.map +1 -0
  36. package/dist/compat/utils.js +189 -194
  37. package/dist/compat/utils.js.map +1 -0
  38. package/dist/compat-BbNNmTM-.d.ts +1386 -0
  39. package/dist/compat-BbNNmTM-.d.ts.map +1 -0
  40. package/dist/compat-DcHVxuuZ.js +734 -0
  41. package/dist/compat-DcHVxuuZ.js.map +1 -0
  42. package/dist/compat.d.ts +2 -0
  43. package/dist/compat.js +1 -1019
  44. package/dist/error-CzkyXr1Q.d.ts +435 -0
  45. package/dist/error-CzkyXr1Q.d.ts.map +1 -0
  46. package/dist/errors-BEEsrHbl.js +2134 -0
  47. package/dist/errors-BEEsrHbl.js.map +1 -0
  48. package/dist/extensions-DumNm4dA.d.ts +102 -0
  49. package/dist/extensions-DumNm4dA.d.ts.map +1 -0
  50. package/dist/index.d.ts +243 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +271 -188
  53. package/dist/index.js.map +1 -0
  54. package/dist/json-BXNPTlcH.js +1106 -0
  55. package/dist/json-BXNPTlcH.js.map +1 -0
  56. package/dist/model/-private.d.ts +3 -0
  57. package/dist/model/-private.js +3 -1
  58. package/dist/model/migration-support.d.ts +335 -0
  59. package/dist/model/migration-support.d.ts.map +1 -0
  60. package/dist/model/migration-support.js +506 -564
  61. package/dist/model/migration-support.js.map +1 -0
  62. package/dist/model-62hn5_PD.d.ts +3107 -0
  63. package/dist/model-62hn5_PD.d.ts.map +1 -0
  64. package/dist/model-DcXZdNMu.js +683 -0
  65. package/dist/model-DcXZdNMu.js.map +1 -0
  66. package/dist/model-fragments-DSqu0ptR.js +334 -0
  67. package/dist/model-fragments-DSqu0ptR.js.map +1 -0
  68. package/dist/model-fragments.d.ts +294 -0
  69. package/dist/model-fragments.d.ts.map +1 -0
  70. package/dist/model-fragments.js +2 -75
  71. package/dist/model.d.ts +404 -0
  72. package/dist/model.d.ts.map +1 -0
  73. package/dist/model.js +3 -666
  74. package/{declarations/adapter/rest.d.ts → dist/rest-0NhtexIq.d.ts} +187 -103
  75. package/dist/rest-0NhtexIq.d.ts.map +1 -0
  76. package/dist/runtime--fcdnjmJ-DMTJ0Kb3.js +53 -0
  77. package/dist/runtime--fcdnjmJ-DMTJ0Kb3.js.map +1 -0
  78. package/dist/schema-provider-H4zNXtry.js +1929 -0
  79. package/dist/schema-provider-H4zNXtry.js.map +1 -0
  80. package/{declarations → dist}/serializer/json-api.d.ts +4 -1
  81. package/dist/serializer/json-api.d.ts.map +1 -0
  82. package/dist/serializer/json-api.js +527 -514
  83. package/dist/serializer/json-api.js.map +1 -0
  84. package/{declarations → dist}/serializer/json.d.ts +3 -0
  85. package/dist/serializer/json.d.ts.map +1 -0
  86. package/dist/serializer/json.js +3 -6
  87. package/{declarations/serializer/-private/embedded-records-mixin.d.ts → dist/serializer/rest.d.ts} +56 -1
  88. package/dist/serializer/rest.d.ts.map +1 -0
  89. package/dist/serializer/rest.js +958 -1200
  90. package/dist/serializer/rest.js.map +1 -0
  91. package/dist/serializer/transform.d.ts +313 -0
  92. package/dist/serializer/transform.d.ts.map +1 -0
  93. package/dist/serializer/transform.js +283 -260
  94. package/dist/serializer/transform.js.map +1 -0
  95. package/dist/serializer.d.ts +151 -0
  96. package/dist/serializer.d.ts.map +1 -0
  97. package/dist/serializer.js +205 -208
  98. package/dist/serializer.js.map +1 -0
  99. package/dist/store-C4qYzXei.js +473 -0
  100. package/dist/store-C4qYzXei.js.map +1 -0
  101. package/dist/store.d.ts +13 -0
  102. package/dist/store.d.ts.map +1 -0
  103. package/dist/store.js +1 -635
  104. package/dist/unpkg/dev/-private-CrEyBE-B.js +189 -0
  105. package/dist/unpkg/dev/-private-CrEyBE-B.js.map +1 -0
  106. package/dist/unpkg/dev/-private-vOhxVExH.js +896 -0
  107. package/dist/unpkg/dev/-private-vOhxVExH.js.map +1 -0
  108. package/dist/unpkg/dev/adapter/-private.js +3 -1
  109. package/dist/unpkg/dev/adapter/error.js +424 -310
  110. package/dist/unpkg/dev/adapter/error.js.map +1 -0
  111. package/dist/unpkg/dev/adapter/json-api.js +239 -245
  112. package/dist/unpkg/dev/adapter/json-api.js.map +1 -0
  113. package/dist/unpkg/dev/adapter/rest.js +935 -1098
  114. package/dist/unpkg/dev/adapter/rest.js.map +1 -0
  115. package/dist/unpkg/dev/adapter-oLwyr47q.js +1129 -0
  116. package/dist/unpkg/dev/adapter-oLwyr47q.js.map +1 -0
  117. package/dist/unpkg/dev/adapter.js +1 -1250
  118. package/dist/unpkg/dev/compat/-private.js +3 -1
  119. package/dist/unpkg/dev/compat/builders.js +204 -248
  120. package/dist/unpkg/dev/compat/builders.js.map +1 -0
  121. package/dist/unpkg/dev/compat/extensions.js +270 -232
  122. package/dist/unpkg/dev/compat/extensions.js.map +1 -0
  123. package/dist/unpkg/dev/compat/utils.js +188 -193
  124. package/dist/unpkg/dev/compat/utils.js.map +1 -0
  125. package/dist/unpkg/dev/compat-D48B8sXv.js +825 -0
  126. package/dist/unpkg/dev/compat-D48B8sXv.js.map +1 -0
  127. package/dist/unpkg/dev/compat.js +1 -1145
  128. package/dist/unpkg/dev/errors-8GnRWcxo.js +2127 -0
  129. package/dist/unpkg/dev/errors-8GnRWcxo.js.map +1 -0
  130. package/dist/unpkg/dev/index.js +270 -190
  131. package/dist/unpkg/dev/index.js.map +1 -0
  132. package/dist/unpkg/dev/json-DDJji3V3.js +1104 -0
  133. package/dist/unpkg/dev/json-DDJji3V3.js.map +1 -0
  134. package/dist/unpkg/dev/model/-private.js +3 -1
  135. package/dist/unpkg/dev/model/migration-support.js +483 -537
  136. package/dist/unpkg/dev/model/migration-support.js.map +1 -0
  137. package/dist/unpkg/dev/model-LK7ethC5.js +655 -0
  138. package/dist/unpkg/dev/model-LK7ethC5.js.map +1 -0
  139. package/dist/unpkg/dev/model-fragments-DSqu0ptR.js +334 -0
  140. package/dist/unpkg/dev/model-fragments-DSqu0ptR.js.map +1 -0
  141. package/dist/unpkg/dev/model-fragments.js +2 -75
  142. package/dist/unpkg/dev/model.js +3 -677
  143. package/dist/unpkg/dev/runtime--fcdnjmJ-DMTJ0Kb3.js +53 -0
  144. package/dist/unpkg/dev/runtime--fcdnjmJ-DMTJ0Kb3.js.map +1 -0
  145. package/dist/unpkg/dev/schema-provider-CRzoMoTO.js +1834 -0
  146. package/dist/unpkg/dev/schema-provider-CRzoMoTO.js.map +1 -0
  147. package/dist/unpkg/dev/serializer/json-api.js +514 -629
  148. package/dist/unpkg/dev/serializer/json-api.js.map +1 -0
  149. package/dist/unpkg/dev/serializer/json.js +3 -4
  150. package/dist/unpkg/dev/serializer/rest.js +954 -1197
  151. package/dist/unpkg/dev/serializer/rest.js.map +1 -0
  152. package/dist/unpkg/dev/serializer/transform.js +283 -260
  153. package/dist/unpkg/dev/serializer/transform.js.map +1 -0
  154. package/dist/unpkg/dev/serializer.js +205 -208
  155. package/dist/unpkg/dev/serializer.js.map +1 -0
  156. package/dist/unpkg/dev/store-D_V8-HQl.js +472 -0
  157. package/dist/unpkg/dev/store-D_V8-HQl.js.map +1 -0
  158. package/dist/unpkg/dev/store.js +1 -635
  159. package/dist/unpkg/dev/util-dSKEgQDp.js +12 -0
  160. package/dist/unpkg/dev/util-dSKEgQDp.js.map +1 -0
  161. package/dist/unpkg/dev/utils-DYC9utVJ.js +11 -0
  162. package/dist/unpkg/dev/utils-DYC9utVJ.js.map +1 -0
  163. package/dist/unpkg/dev-deprecated/-private-CrEyBE-B.js +189 -0
  164. package/dist/unpkg/dev-deprecated/-private-CrEyBE-B.js.map +1 -0
  165. package/dist/unpkg/dev-deprecated/-private-vOhxVExH.js +896 -0
  166. package/dist/unpkg/dev-deprecated/-private-vOhxVExH.js.map +1 -0
  167. package/dist/unpkg/dev-deprecated/adapter/-private.js +3 -1
  168. package/dist/unpkg/dev-deprecated/adapter/error.js +424 -310
  169. package/dist/unpkg/dev-deprecated/adapter/error.js.map +1 -0
  170. package/dist/unpkg/dev-deprecated/adapter/json-api.js +239 -245
  171. package/dist/unpkg/dev-deprecated/adapter/json-api.js.map +1 -0
  172. package/dist/unpkg/dev-deprecated/adapter/rest.js +935 -1098
  173. package/dist/unpkg/dev-deprecated/adapter/rest.js.map +1 -0
  174. package/dist/unpkg/dev-deprecated/adapter-oLwyr47q.js +1129 -0
  175. package/dist/unpkg/dev-deprecated/adapter-oLwyr47q.js.map +1 -0
  176. package/dist/unpkg/dev-deprecated/adapter.js +1 -1250
  177. package/dist/unpkg/dev-deprecated/compat/-private.js +3 -1
  178. package/dist/unpkg/dev-deprecated/compat/builders.js +204 -248
  179. package/dist/unpkg/dev-deprecated/compat/builders.js.map +1 -0
  180. package/dist/unpkg/dev-deprecated/compat/extensions.js +270 -232
  181. package/dist/unpkg/dev-deprecated/compat/extensions.js.map +1 -0
  182. package/dist/unpkg/dev-deprecated/compat/utils.js +188 -193
  183. package/dist/unpkg/dev-deprecated/compat/utils.js.map +1 -0
  184. package/dist/unpkg/dev-deprecated/compat-DGSurLh7.js +825 -0
  185. package/dist/unpkg/dev-deprecated/compat-DGSurLh7.js.map +1 -0
  186. package/dist/unpkg/dev-deprecated/compat.js +1 -1145
  187. package/dist/unpkg/dev-deprecated/errors-0ydn94s0.js +2128 -0
  188. package/dist/unpkg/dev-deprecated/errors-0ydn94s0.js.map +1 -0
  189. package/dist/unpkg/dev-deprecated/index.js +270 -189
  190. package/dist/unpkg/dev-deprecated/index.js.map +1 -0
  191. package/dist/unpkg/dev-deprecated/json-DDJji3V3.js +1104 -0
  192. package/dist/unpkg/dev-deprecated/json-DDJji3V3.js.map +1 -0
  193. package/dist/unpkg/dev-deprecated/model/-private.js +3 -1
  194. package/dist/unpkg/dev-deprecated/model/migration-support.js +494 -554
  195. package/dist/unpkg/dev-deprecated/model/migration-support.js.map +1 -0
  196. package/dist/unpkg/dev-deprecated/model-C1ts6Mod.js +660 -0
  197. package/dist/unpkg/dev-deprecated/model-C1ts6Mod.js.map +1 -0
  198. package/dist/unpkg/dev-deprecated/model-fragments-DSqu0ptR.js +334 -0
  199. package/dist/unpkg/dev-deprecated/model-fragments-DSqu0ptR.js.map +1 -0
  200. package/dist/unpkg/dev-deprecated/model-fragments.js +2 -75
  201. package/dist/unpkg/dev-deprecated/model.js +3 -681
  202. package/dist/unpkg/dev-deprecated/runtime--fcdnjmJ-DMTJ0Kb3.js +53 -0
  203. package/dist/unpkg/dev-deprecated/runtime--fcdnjmJ-DMTJ0Kb3.js.map +1 -0
  204. package/dist/unpkg/dev-deprecated/schema-provider-D2ESMsA8.js +1835 -0
  205. package/dist/unpkg/dev-deprecated/schema-provider-D2ESMsA8.js.map +1 -0
  206. package/dist/unpkg/dev-deprecated/serializer/json-api.js +514 -629
  207. package/dist/unpkg/dev-deprecated/serializer/json-api.js.map +1 -0
  208. package/dist/unpkg/dev-deprecated/serializer/json.js +3 -4
  209. package/dist/unpkg/dev-deprecated/serializer/rest.js +954 -1197
  210. package/dist/unpkg/dev-deprecated/serializer/rest.js.map +1 -0
  211. package/dist/unpkg/dev-deprecated/serializer/transform.js +283 -260
  212. package/dist/unpkg/dev-deprecated/serializer/transform.js.map +1 -0
  213. package/dist/unpkg/dev-deprecated/serializer.js +205 -208
  214. package/dist/unpkg/dev-deprecated/serializer.js.map +1 -0
  215. package/dist/unpkg/dev-deprecated/store-BX7GvXC_.js +472 -0
  216. package/dist/unpkg/dev-deprecated/store-BX7GvXC_.js.map +1 -0
  217. package/dist/unpkg/dev-deprecated/store.js +1 -635
  218. package/dist/unpkg/dev-deprecated/util-9mgEBJ3W.js +18 -0
  219. package/dist/unpkg/dev-deprecated/util-9mgEBJ3W.js.map +1 -0
  220. package/dist/unpkg/dev-deprecated/utils-Cl86-e7F.js +17 -0
  221. package/dist/unpkg/dev-deprecated/utils-Cl86-e7F.js.map +1 -0
  222. package/dist/unpkg/prod/-private-B4bxoTuK.js +160 -0
  223. package/dist/unpkg/prod/-private-B4bxoTuK.js.map +1 -0
  224. package/dist/unpkg/prod/-private-SfXkkHKd.js +745 -0
  225. package/dist/unpkg/prod/-private-SfXkkHKd.js.map +1 -0
  226. package/dist/unpkg/prod/adapter/-private.js +3 -1
  227. package/dist/unpkg/prod/adapter/error.js +421 -305
  228. package/dist/unpkg/prod/adapter/error.js.map +1 -0
  229. package/dist/unpkg/prod/adapter/json-api.js +236 -240
  230. package/dist/unpkg/prod/adapter/json-api.js.map +1 -0
  231. package/dist/unpkg/prod/adapter/rest.js +911 -1061
  232. package/dist/unpkg/prod/adapter/rest.js.map +1 -0
  233. package/dist/unpkg/prod/adapter-DQ9UA7FC.js +1111 -0
  234. package/dist/unpkg/prod/adapter-DQ9UA7FC.js.map +1 -0
  235. package/dist/unpkg/prod/adapter.js +1 -1217
  236. package/dist/unpkg/prod/compat/-private.js +3 -1
  237. package/dist/unpkg/prod/compat/builders.js +165 -183
  238. package/dist/unpkg/prod/compat/builders.js.map +1 -0
  239. package/dist/unpkg/prod/compat/extensions.js +258 -222
  240. package/dist/unpkg/prod/compat/extensions.js.map +1 -0
  241. package/dist/unpkg/prod/compat/utils.js +185 -188
  242. package/dist/unpkg/prod/compat/utils.js.map +1 -0
  243. package/dist/unpkg/prod/compat-DxiVkCUb.js +547 -0
  244. package/dist/unpkg/prod/compat-DxiVkCUb.js.map +1 -0
  245. package/dist/unpkg/prod/compat.js +1 -725
  246. package/dist/unpkg/prod/errors-CVXWrUjP.js +1977 -0
  247. package/dist/unpkg/prod/errors-CVXWrUjP.js.map +1 -0
  248. package/dist/unpkg/prod/index.js +249 -146
  249. package/dist/unpkg/prod/index.js.map +1 -0
  250. package/dist/unpkg/prod/json-BD1kRTfB.js +1080 -0
  251. package/dist/unpkg/prod/json-BD1kRTfB.js.map +1 -0
  252. package/dist/unpkg/prod/model/-private.js +3 -1
  253. package/dist/unpkg/prod/model/migration-support.js +479 -530
  254. package/dist/unpkg/prod/model/migration-support.js.map +1 -0
  255. package/dist/unpkg/prod/model-D3WMsNNE.js +603 -0
  256. package/dist/unpkg/prod/model-D3WMsNNE.js.map +1 -0
  257. package/dist/unpkg/prod/model-fragments-DSqu0ptR.js +334 -0
  258. package/dist/unpkg/prod/model-fragments-DSqu0ptR.js.map +1 -0
  259. package/dist/unpkg/prod/model-fragments.js +2 -75
  260. package/dist/unpkg/prod/model.js +3 -592
  261. package/dist/unpkg/prod/runtime--fcdnjmJ-DMTJ0Kb3.js +53 -0
  262. package/dist/unpkg/prod/runtime--fcdnjmJ-DMTJ0Kb3.js.map +1 -0
  263. package/dist/unpkg/prod/schema-provider-_pimTZ3P.js +1622 -0
  264. package/dist/unpkg/prod/schema-provider-_pimTZ3P.js.map +1 -0
  265. package/dist/unpkg/prod/serializer/json-api.js +497 -587
  266. package/dist/unpkg/prod/serializer/json-api.js.map +1 -0
  267. package/dist/unpkg/prod/serializer/json.js +3 -4
  268. package/dist/unpkg/prod/serializer/rest.js +938 -1167
  269. package/dist/unpkg/prod/serializer/rest.js.map +1 -0
  270. package/dist/unpkg/prod/serializer/transform.js +283 -260
  271. package/dist/unpkg/prod/serializer/transform.js.map +1 -0
  272. package/dist/unpkg/prod/serializer.js +205 -208
  273. package/dist/unpkg/prod/serializer.js.map +1 -0
  274. package/dist/unpkg/prod/store-RGGc1ilN.js +392 -0
  275. package/dist/unpkg/prod/store-RGGc1ilN.js.map +1 -0
  276. package/dist/unpkg/prod/store.js +1 -503
  277. package/dist/unpkg/prod/util-dSKEgQDp.js +12 -0
  278. package/dist/unpkg/prod/util-dSKEgQDp.js.map +1 -0
  279. package/dist/unpkg/prod/utils-DYC9utVJ.js +11 -0
  280. package/dist/unpkg/prod/utils-DYC9utVJ.js.map +1 -0
  281. package/dist/unpkg/prod-deprecated/-private-B4bxoTuK.js +160 -0
  282. package/dist/unpkg/prod-deprecated/-private-B4bxoTuK.js.map +1 -0
  283. package/dist/unpkg/prod-deprecated/-private-SfXkkHKd.js +745 -0
  284. package/dist/unpkg/prod-deprecated/-private-SfXkkHKd.js.map +1 -0
  285. package/dist/unpkg/prod-deprecated/adapter/-private.js +3 -1
  286. package/dist/unpkg/prod-deprecated/adapter/error.js +421 -305
  287. package/dist/unpkg/prod-deprecated/adapter/error.js.map +1 -0
  288. package/dist/unpkg/prod-deprecated/adapter/json-api.js +236 -240
  289. package/dist/unpkg/prod-deprecated/adapter/json-api.js.map +1 -0
  290. package/dist/unpkg/prod-deprecated/adapter/rest.js +911 -1061
  291. package/dist/unpkg/prod-deprecated/adapter/rest.js.map +1 -0
  292. package/{declarations/adapter.d.ts → dist/unpkg/prod-deprecated/adapter-DQ9UA7FC.js} +451 -110
  293. package/dist/unpkg/prod-deprecated/adapter-DQ9UA7FC.js.map +1 -0
  294. package/dist/unpkg/prod-deprecated/adapter.js +1 -1217
  295. package/dist/unpkg/prod-deprecated/compat/-private.js +3 -1
  296. package/dist/unpkg/prod-deprecated/compat/builders.js +165 -183
  297. package/dist/unpkg/prod-deprecated/compat/builders.js.map +1 -0
  298. package/dist/unpkg/prod-deprecated/compat/extensions.js +258 -222
  299. package/dist/unpkg/prod-deprecated/compat/extensions.js.map +1 -0
  300. package/dist/unpkg/prod-deprecated/compat/utils.js +185 -188
  301. package/dist/unpkg/prod-deprecated/compat/utils.js.map +1 -0
  302. package/dist/unpkg/prod-deprecated/compat-DxiVkCUb.js +547 -0
  303. package/dist/unpkg/prod-deprecated/compat-DxiVkCUb.js.map +1 -0
  304. package/dist/unpkg/prod-deprecated/compat.js +1 -725
  305. package/dist/unpkg/prod-deprecated/errors-9LXqpfRd.js +1978 -0
  306. package/dist/unpkg/prod-deprecated/errors-9LXqpfRd.js.map +1 -0
  307. package/dist/unpkg/prod-deprecated/index.js +249 -145
  308. package/dist/unpkg/prod-deprecated/index.js.map +1 -0
  309. package/dist/unpkg/prod-deprecated/json-BD1kRTfB.js +1080 -0
  310. package/dist/unpkg/prod-deprecated/json-BD1kRTfB.js.map +1 -0
  311. package/dist/unpkg/prod-deprecated/model/-private.js +3 -1
  312. package/dist/unpkg/prod-deprecated/model/migration-support.js +490 -547
  313. package/dist/unpkg/prod-deprecated/model/migration-support.js.map +1 -0
  314. package/dist/unpkg/prod-deprecated/model-aiVrr1fz.js +604 -0
  315. package/dist/unpkg/prod-deprecated/model-aiVrr1fz.js.map +1 -0
  316. package/dist/unpkg/prod-deprecated/model-fragments-DSqu0ptR.js +334 -0
  317. package/dist/unpkg/prod-deprecated/model-fragments-DSqu0ptR.js.map +1 -0
  318. package/dist/unpkg/prod-deprecated/model-fragments.js +2 -75
  319. package/dist/unpkg/prod-deprecated/model.js +3 -595
  320. package/dist/unpkg/prod-deprecated/runtime--fcdnjmJ-DMTJ0Kb3.js +53 -0
  321. package/dist/unpkg/prod-deprecated/runtime--fcdnjmJ-DMTJ0Kb3.js.map +1 -0
  322. package/dist/unpkg/prod-deprecated/schema-provider-DyfSd9Cv.js +1635 -0
  323. package/dist/unpkg/prod-deprecated/schema-provider-DyfSd9Cv.js.map +1 -0
  324. package/dist/unpkg/prod-deprecated/serializer/json-api.js +497 -587
  325. package/dist/unpkg/prod-deprecated/serializer/json-api.js.map +1 -0
  326. package/dist/unpkg/prod-deprecated/serializer/json.js +3 -4
  327. package/dist/unpkg/prod-deprecated/serializer/rest.js +938 -1167
  328. package/dist/unpkg/prod-deprecated/serializer/rest.js.map +1 -0
  329. package/dist/unpkg/prod-deprecated/serializer/transform.js +283 -260
  330. package/dist/unpkg/prod-deprecated/serializer/transform.js.map +1 -0
  331. package/dist/unpkg/prod-deprecated/serializer.js +205 -208
  332. package/dist/unpkg/prod-deprecated/serializer.js.map +1 -0
  333. package/dist/unpkg/prod-deprecated/store-0L2CkYzh.js +392 -0
  334. package/dist/unpkg/prod-deprecated/store-0L2CkYzh.js.map +1 -0
  335. package/dist/unpkg/prod-deprecated/store.js +1 -503
  336. package/dist/unpkg/prod-deprecated/util-CQQdHX3n.js +14 -0
  337. package/dist/unpkg/prod-deprecated/util-CQQdHX3n.js.map +1 -0
  338. package/dist/unpkg/prod-deprecated/utils-BMI_JwFP.js +13 -0
  339. package/dist/unpkg/prod-deprecated/utils-BMI_JwFP.js.map +1 -0
  340. package/dist/util-Bnx8nm-D.js +29 -0
  341. package/dist/util-Bnx8nm-D.js.map +1 -0
  342. package/dist/utils-ZAytYep8.js +28 -0
  343. package/dist/utils-ZAytYep8.js.map +1 -0
  344. package/package.json +21 -25
  345. package/declarations/adapter/-private/build-url-mixin.d.ts +0 -33
  346. package/declarations/adapter/-private/fastboot-interface.d.ts +0 -8
  347. package/declarations/adapter/-private/utils/continue-on-reject.d.ts +0 -1
  348. package/declarations/adapter/-private/utils/determine-body-promise.d.ts +0 -4
  349. package/declarations/adapter/-private/utils/fetch.d.ts +0 -8
  350. package/declarations/adapter/-private/utils/parse-response-headers.d.ts +0 -1
  351. package/declarations/adapter/-private/utils/serialize-into-hash.d.ts +0 -6
  352. package/declarations/adapter/-private/utils/serialize-query-params.d.ts +0 -5
  353. package/declarations/adapter/-private.d.ts +0 -5
  354. package/declarations/adapter/error.d.ts +0 -215
  355. package/declarations/compat/-private.d.ts +0 -13
  356. package/declarations/compat/builders/find-all.d.ts +0 -35
  357. package/declarations/compat/builders/find-record.d.ts +0 -56
  358. package/declarations/compat/builders/query.d.ts +0 -66
  359. package/declarations/compat/builders/save-record.d.ts +0 -34
  360. package/declarations/compat/builders/utils.d.ts +0 -3
  361. package/declarations/compat/builders.d.ts +0 -14
  362. package/declarations/compat/extensions.d.ts +0 -59
  363. package/declarations/compat/legacy-network-handler/fetch-manager.d.ts +0 -55
  364. package/declarations/compat/legacy-network-handler/identifier-has-id.d.ts +0 -2
  365. package/declarations/compat/legacy-network-handler/legacy-data-fetch.d.ts +0 -11
  366. package/declarations/compat/legacy-network-handler/legacy-data-utils.d.ts +0 -5
  367. package/declarations/compat/legacy-network-handler/legacy-network-handler.d.ts +0 -2
  368. package/declarations/compat/legacy-network-handler/minimum-adapter-interface.d.ts +0 -524
  369. package/declarations/compat/legacy-network-handler/minimum-serializer-interface.d.ts +0 -213
  370. package/declarations/compat/legacy-network-handler/serializer-response.d.ts +0 -6
  371. package/declarations/compat/legacy-network-handler/snapshot-record-array.d.ts +0 -110
  372. package/declarations/compat/legacy-network-handler/snapshot.d.ts +0 -255
  373. package/declarations/compat/utils.d.ts +0 -137
  374. package/declarations/compat.d.ts +0 -157
  375. package/declarations/index.d.ts +0 -102
  376. package/declarations/model/-private/attr.d.ts +0 -170
  377. package/declarations/model/-private/belongs-to.d.ts +0 -174
  378. package/declarations/model/-private/debug/assert-polymorphic-type.d.ts +0 -5
  379. package/declarations/model/-private/errors.d.ts +0 -289
  380. package/declarations/model/-private/has-many.d.ts +0 -162
  381. package/declarations/model/-private/hooks.d.ts +0 -10
  382. package/declarations/model/-private/legacy-relationships-support.d.ts +0 -47
  383. package/declarations/model/-private/model-for-mixin.d.ts +0 -3
  384. package/declarations/model/-private/model-methods.d.ts +0 -39
  385. package/declarations/model/-private/model.d.ts +0 -1228
  386. package/declarations/model/-private/notify-changes.d.ts +0 -4
  387. package/declarations/model/-private/promise-belongs-to.d.ts +0 -40
  388. package/declarations/model/-private/promise-many-array.d.ts +0 -106
  389. package/declarations/model/-private/record-state.d.ts +0 -58
  390. package/declarations/model/-private/references/belongs-to.d.ts +0 -488
  391. package/declarations/model/-private/references/has-many.d.ts +0 -498
  392. package/declarations/model/-private/schema-provider.d.ts +0 -56
  393. package/declarations/model/-private/type-utils.d.ts +0 -57
  394. package/declarations/model/-private/util.d.ts +0 -5
  395. package/declarations/model/-private.d.ts +0 -8
  396. package/declarations/model/migration-support.d.ts +0 -280
  397. package/declarations/model-fragments/extensions/fragment-array.d.ts +0 -16
  398. package/declarations/model-fragments/extensions/fragment.d.ts +0 -15
  399. package/declarations/model-fragments/hooks/model-for.d.ts +0 -20
  400. package/declarations/model-fragments/index.d.ts +0 -5
  401. package/declarations/model-fragments/instance-initializers/fragment-extensions.d.ts +0 -9
  402. package/declarations/model-fragments/utilities/with-array-defaults.d.ts +0 -15
  403. package/declarations/model-fragments/utilities/with-fragment-array-defaults.d.ts +0 -20
  404. package/declarations/model-fragments/utilities/with-fragment-defaults.d.ts +0 -19
  405. package/declarations/model-fragments/utilities/with-legacy.d.ts +0 -3
  406. package/declarations/model-fragments.d.ts +0 -9
  407. package/declarations/model.d.ts +0 -49
  408. package/declarations/serializer/-private/transforms/boolean.d.ts +0 -47
  409. package/declarations/serializer/-private/transforms/date.d.ts +0 -28
  410. package/declarations/serializer/-private/transforms/number.d.ts +0 -29
  411. package/declarations/serializer/-private/transforms/string.d.ts +0 -29
  412. package/declarations/serializer/-private/transforms/transform.d.ts +0 -118
  413. package/declarations/serializer/-private/utils.d.ts +0 -3
  414. package/declarations/serializer/rest.d.ts +0 -51
  415. package/declarations/serializer/transform.d.ts +0 -5
  416. package/declarations/serializer.d.ts +0 -254
  417. package/declarations/store/-private.d.ts +0 -223
  418. package/declarations/store.d.ts +0 -3
  419. package/dist/-private-BG3bMiKp.js +0 -1211
  420. package/dist/errors-Cz5KrzBk.js +0 -2566
  421. package/dist/hooks-D6diaM34.js +0 -74
  422. package/dist/json-ChdEfB0X.js +0 -1259
  423. package/dist/model-for-CqXsIKws.js +0 -221
  424. package/dist/runtime-BPCpkOf1-BKOwiRJp.js +0 -65
  425. package/dist/schema-provider-DJCV_6AF.js +0 -2295
  426. package/dist/serialize-into-hash-DPZYoF-i.js +0 -261
  427. package/dist/unpkg/dev/-private-DtjBbEgy.js +0 -1206
  428. package/dist/unpkg/dev/errors-DmGGJr3T.js +0 -2562
  429. package/dist/unpkg/dev/hooks-CkYiE6Ud.js +0 -73
  430. package/dist/unpkg/dev/json-Cu1LNgmQ.js +0 -1256
  431. package/dist/unpkg/dev/model-for-CqXsIKws.js +0 -221
  432. package/dist/unpkg/dev/runtime-BPCpkOf1-BKOwiRJp.js +0 -65
  433. package/dist/unpkg/dev/schema-provider-DDVYxmUV.js +0 -2186
  434. package/dist/unpkg/dev/serialize-into-hash-B2xDbuo5.js +0 -259
  435. package/dist/unpkg/dev/util-DvanW33H.js +0 -20
  436. package/dist/unpkg/dev/utils-BhvS1iTS.js +0 -8
  437. package/dist/unpkg/dev-deprecated/-private-DtjBbEgy.js +0 -1206
  438. package/dist/unpkg/dev-deprecated/errors-Spt6ubMd.js +0 -2565
  439. package/dist/unpkg/dev-deprecated/hooks-DOXegvhL.js +0 -73
  440. package/dist/unpkg/dev-deprecated/json-Cu1LNgmQ.js +0 -1256
  441. package/dist/unpkg/dev-deprecated/model-for-CqXsIKws.js +0 -221
  442. package/dist/unpkg/dev-deprecated/runtime-BPCpkOf1-BKOwiRJp.js +0 -65
  443. package/dist/unpkg/dev-deprecated/schema-provider-BP6_8N-V.js +0 -2211
  444. package/dist/unpkg/dev-deprecated/serialize-into-hash-B2xDbuo5.js +0 -259
  445. package/dist/unpkg/dev-deprecated/util-CWr5WQOT.js +0 -24
  446. package/dist/unpkg/dev-deprecated/utils-C9PJehtL.js +0 -12
  447. package/dist/unpkg/prod/-private-BdyZaGEh.js +0 -971
  448. package/dist/unpkg/prod/errors-BGVFCBmi.js +0 -2314
  449. package/dist/unpkg/prod/hooks-BztVA_x0.js +0 -41
  450. package/dist/unpkg/prod/json-BWrZ5546.js +0 -1243
  451. package/dist/unpkg/prod/model-for-CqXsIKws.js +0 -221
  452. package/dist/unpkg/prod/runtime-BPCpkOf1-BKOwiRJp.js +0 -65
  453. package/dist/unpkg/prod/schema-provider-DJtD_8jZ.js +0 -1861
  454. package/dist/unpkg/prod/serialize-into-hash-DGlzQteF.js +0 -215
  455. package/dist/unpkg/prod/util-DvanW33H.js +0 -20
  456. package/dist/unpkg/prod/utils-BhvS1iTS.js +0 -8
  457. package/dist/unpkg/prod-deprecated/-private-BdyZaGEh.js +0 -971
  458. package/dist/unpkg/prod-deprecated/errors-CdDaK81x.js +0 -2317
  459. package/dist/unpkg/prod-deprecated/hooks-yId87yyG.js +0 -41
  460. package/dist/unpkg/prod-deprecated/json-BWrZ5546.js +0 -1243
  461. package/dist/unpkg/prod-deprecated/model-for-CqXsIKws.js +0 -221
  462. package/dist/unpkg/prod-deprecated/runtime-BPCpkOf1-BKOwiRJp.js +0 -65
  463. package/dist/unpkg/prod-deprecated/schema-provider-CjX55uSY.js +0 -1904
  464. package/dist/unpkg/prod-deprecated/serialize-into-hash-DGlzQteF.js +0 -215
  465. package/dist/unpkg/prod-deprecated/util-B6cn-i93.js +0 -23
  466. package/dist/unpkg/prod-deprecated/utils-BUWwQwCh.js +0 -11
  467. package/dist/util-Dul6TZts.js +0 -35
  468. package/dist/utils-Cqw9eRj5.js +0 -23
@@ -1,1173 +1,1010 @@
1
- import { getOwner } from '@ember/application';
2
- import { warn } from '@ember/debug';
3
- import { computed } from '@ember/object';
4
- import { Adapter, BuildURLMixin } from '../adapter.js';
5
- import { b as serializeIntoHash, d as determineBodyPromise, g as getFetchFunction, s as serializeQueryParams, p as parseResponseHeaders } from "../serialize-into-hash-DPZYoF-i.js";
6
- import { InvalidError, ServerError, ConflictError, NotFoundError, ForbiddenError, UnauthorizedError, AdapterError, TimeoutError, AbortError } from './error.js';
7
- import { macroCondition, getGlobalConfig } from '@embroider/macros';
8
- import { d as decorateMethodV2 } from "../runtime-BPCpkOf1-BKOwiRJp.js";
9
-
10
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
11
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
12
- /* eslint-disable @typescript-eslint/no-unsafe-return */
13
-
1
+ import { n as decorateMethodV2 } from "../runtime--fcdnjmJ-DMTJ0Kb3.js";
2
+ import { n as BuildURLMixin, t as Adapter } from "../adapter-eYo2pIuM.js";
3
+ import { AbortError, AdapterError, ConflictError, ForbiddenError, InvalidError, NotFoundError, ServerError, TimeoutError, UnauthorizedError } from "./error.js";
4
+ import { a as determineBodyPromise, i as serializeQueryParams, n as getFetchFunction, o as parseResponseHeaders, t as serializeIntoHash } from "../-private-DQ6Iap2t.js";
5
+ import { getOwner } from "@ember/application";
6
+ import { warn } from "@ember/debug";
7
+ import { getGlobalConfig, macroCondition } from "@embroider/macros";
8
+ import { computed } from "@ember/object";
9
+
10
+ //#region src/adapter/rest.ts
11
+ /**
12
+ * The query params built by {@link RESTAdapter.buildQuery | buildQuery} for a
13
+ * `findAll`/`findRecord` request.
14
+ */
15
+ /**
16
+ * The options passed to the native `fetch` API by {@link RESTAdapter._fetchRequest | _fetchRequest}.
17
+ */
18
+ /**
19
+ * The options passed to jQuery's `$.ajax` by {@link RESTAdapter._ajaxRequest | _ajaxRequest}.
20
+ */
21
+ /**
22
+ * A minimal description of an in-flight request, used for building
23
+ * error messages when a request fails.
24
+ */
14
25
  const AdapterWithBuildURLMixin = Adapter.extend(BuildURLMixin);
15
-
16
26
  /**
17
- * :::danger
18
- ⚠️ **This is LEGACY documentation** for a feature that is no longer encouraged to be used.
19
- If starting a new app or thinking of implementing a new adapter, consider writing a
20
- {@link Handler} instead to be used with the {@link RequestManager}
21
- :::
22
-
23
- The REST adapter allows your store to communicate with an HTTP server by
24
- transmitting JSON via XHR.
25
-
26
- This adapter is designed around the idea that the JSON exchanged with
27
- the server should be conventional. It builds URLs in a manner that follows
28
- the structure of most common REST-style web services.
29
-
30
- ## Success and failure
31
-
32
- The REST adapter will consider a success any response with a status code
33
- of the 2xx family ("Success"), as well as 304 ("Not Modified"). Any other
34
- status code will be considered a failure.
35
-
36
- On success, the request promise will be resolved with the full response
37
- payload.
38
-
39
- Failed responses with status code 422 ("Unprocessable Entity") will be
40
- considered "invalid". The response will be discarded, except for the
41
- `errors` key. The request promise will be rejected with a `InvalidError`.
42
- This error object will encapsulate the saved `errors` value.
43
-
44
- Any other status codes will be treated as an "adapter error". The request
45
- promise will be rejected, similarly to the "invalid" case, but with
46
- an instance of `AdapterError` instead.
47
-
48
- ## JSON Structure
49
-
50
- The REST adapter expects the JSON returned from your server to follow
51
- these conventions.
52
-
53
- ### Object Root
54
-
55
- The JSON payload should be an object that contains the record inside a
56
- root property. For example, in response to a `GET` request for
57
- `/posts/1`, the JSON should look like this:
58
-
59
- ```js
60
- {
61
- "posts": {
62
- "id": 1,
63
- "title": "I'm Running to Reform the W3C",
64
- "author": "Yehuda Katz"
65
- }
66
- }
67
- ```
68
-
69
- Similarly, in response to a `GET` request for `/posts`, the JSON should
70
- look like this:
71
-
72
- ```js
73
- {
74
- "posts": [
75
- {
76
- "id": 1,
77
- "title": "I'm Running to Reform the W3C",
78
- "author": "Yehuda Katz"
79
- },
80
- {
81
- "id": 2,
82
- "title": "Rails is omakase",
83
- "author": "D2H"
84
- }
85
- ]
86
- }
87
- ```
88
-
89
- Note that the object root can be pluralized for both a single-object response
90
- and an array response: the REST adapter is not strict on this. Further, if the
91
- HTTP server responds to a `GET` request to `/posts/1` (e.g. the response to a
92
- `findRecord` query) with more than one object in the array, WarpDrive will
93
- only display the object with the matching ID.
94
-
95
- ### Conventional Names
96
-
97
- Attribute names in your JSON payload should be the camelCased versions of
98
- the attributes in your Ember.js models.
99
-
100
- For example, if you have a `Person` model:
101
-
102
- ```js [app/models/person.js]
103
- import { Model, attr } from '@warp-drive/legacy/model';
104
-
105
- export default Model.extend({
106
- firstName: attr('string'),
107
- lastName: attr('string'),
108
- occupation: attr('string')
109
- });
110
- ```
111
-
112
- The JSON returned should look like this:
113
-
114
- ```js
115
- {
116
- "people": {
117
- "id": 5,
118
- "firstName": "Zaphod",
119
- "lastName": "Beeblebrox",
120
- "occupation": "President"
121
- }
122
- }
123
- ```
124
-
125
- #### Relationships
126
-
127
- Relationships are usually represented by ids to the record in the
128
- relationship. The related records can then be sideloaded in the
129
- response under a key for the type.
130
-
131
- ```js
132
- {
133
- "posts": {
134
- "id": 5,
135
- "title": "I'm Running to Reform the W3C",
136
- "author": "Yehuda Katz",
137
- "comments": [1, 2]
138
- },
139
- "comments": [{
140
- "id": 1,
141
- "author": "User 1",
142
- "message": "First!",
143
- }, {
144
- "id": 2,
145
- "author": "User 2",
146
- "message": "Good Luck!",
147
- }]
148
- }
149
- ```
150
-
151
- If the records in the relationship are not known when the response
152
- is serialized it's also possible to represent the relationship as a
153
- URL using the `links` key in the response. WarpDrive will fetch
154
- this URL to resolve the relationship when it is accessed for the
155
- first time.
27
+ * :::danger
28
+ ⚠️ **This is LEGACY documentation** for a feature that is no longer encouraged to be used.
29
+ If starting a new app or thinking of implementing a new adapter, consider writing a
30
+ {@link Handler} instead to be used with the {@link RequestManager}
31
+ :::
156
32
 
157
- ```js
158
- {
159
- "posts": {
160
- "id": 5,
161
- "title": "I'm Running to Reform the W3C",
162
- "author": "Yehuda Katz",
163
- "links": {
164
- "comments": "/posts/5/comments"
165
- }
166
- }
167
- }
168
- ```
33
+ The REST adapter allows your store to communicate with an HTTP server by
34
+ transmitting JSON via XHR.
169
35
 
170
- ### Errors
36
+ This adapter is designed around the idea that the JSON exchanged with
37
+ the server should be conventional. It builds URLs in a manner that follows
38
+ the structure of most common REST-style web services.
171
39
 
172
- If a response is considered a failure, the JSON payload is expected to include
173
- a top-level key `errors`, detailing any specific issues. For example:
40
+ ## Success and failure
174
41
 
175
- ```js
176
- {
177
- "errors": {
178
- "msg": "Something went wrong"
179
- }
180
- }
181
- ```
42
+ The REST adapter will consider a success any response with a status code
43
+ of the 2xx family ("Success"), as well as 304 ("Not Modified"). Any other
44
+ status code will be considered a failure.
182
45
 
183
- This adapter does not make any assumptions as to the format of the `errors`
184
- object. It will simply be passed along as is, wrapped in an instance
185
- of `InvalidError` or `AdapterError`. The serializer can interpret it
186
- afterwards.
46
+ On success, the request promise will be resolved with the full response
47
+ payload.
187
48
 
188
- ## Customization
49
+ Failed responses with status code 422 ("Unprocessable Entity") will be
50
+ considered "invalid". The response will be discarded, except for the
51
+ `errors` key. The request promise will be rejected with a `InvalidError`.
52
+ This error object will encapsulate the saved `errors` value.
189
53
 
190
- ### Endpoint path customization
54
+ Any other status codes will be treated as an "adapter error". The request
55
+ promise will be rejected, similarly to the "invalid" case, but with
56
+ an instance of `AdapterError` instead.
191
57
 
192
- Endpoint paths can be prefixed with a `namespace` by setting the namespace
193
- property on the adapter:
58
+ ## JSON Structure
194
59
 
195
- ```js [app/adapters/application.js]
196
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
60
+ The REST adapter expects the JSON returned from your server to follow
61
+ these conventions.
197
62
 
198
- export default class ApplicationAdapter extends RESTAdapter {
199
- namespace = 'api/1';
200
- }
201
- ```
202
- Requests for the `Person` model would now target `/api/1/people/1`.
63
+ ### Object Root
203
64
 
204
- ### Host customization
65
+ The JSON payload should be an object that contains the record inside a
66
+ root property. For example, in response to a `GET` request for
67
+ `/posts/1`, the JSON should look like this:
205
68
 
206
- An adapter can target other hosts by setting the `host` property.
207
-
208
- ```js [app/adapters/application.js]
209
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
210
-
211
- export default class ApplicationAdapter extends RESTAdapter {
212
- host = 'https://api.example.com';
213
- }
214
- ```
215
-
216
- ### Headers customization
217
-
218
- Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary
219
- headers can be set as key/value pairs on the `RESTAdapter`'s `headers`
220
- object and WarpDrive will send them along with each ajax request.
221
-
222
-
223
- ```js [app/adapters/application.js]
224
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
225
-
226
- export default class ApplicationAdapter extends RESTAdapter {
227
- get headers() {
228
- return {
229
- 'API_KEY': 'secret key',
230
- 'ANOTHER_HEADER': 'Some header value'
231
- };
232
- }
233
- }
234
- ```
235
-
236
- @public
237
- */
238
- class RESTAdapter extends AdapterWithBuildURLMixin {
239
- /**
240
- This property allows ajax to still be used instead when `false`.
241
- @default true
242
- @public
243
- */
244
- useFetch = true;
245
- _defaultContentType = 'application/json; charset=utf-8';
246
- get fastboot() {
247
- // Avoid computed property override deprecation in fastboot as suggested by:
248
- // https://deprecations.emberjs.com/v3.x/#toc_computed-property-override
249
- const fastboot = this._fastboot;
250
- if (fastboot) {
251
- return fastboot;
252
- }
253
- return this._fastboot = getOwner(this).lookup('service:fastboot');
254
- }
255
- static {
256
- decorateMethodV2(this.prototype, "fastboot", [computed()]);
257
- }
258
- set fastboot(value) {
259
- this._fastboot = value;
260
- }
261
-
262
- /**
263
- By default, the RESTAdapter will send the query params sorted alphabetically to the
264
- server.
265
- For example:
266
- ```js
267
- store.query('posts', { sort: 'price', category: 'pets' });
268
- ```
269
- will generate a requests like this `/posts?category=pets&sort=price`, even if the
270
- parameters were specified in a different order.
271
- That way the generated URL will be deterministic and that simplifies caching mechanisms
272
- in the backend.
273
- Setting `sortQueryParams` to a falsey value will respect the original order.
274
- In case you want to sort the query parameters with a different criteria, set
275
- `sortQueryParams` to your custom sort function.
276
- ```js [app/adapters/application.js]
277
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
278
- export default class ApplicationAdapter extends RESTAdapter {
279
- sortQueryParams(params) {
280
- let sortedKeys = Object.keys(params).sort().reverse();
281
- let len = sortedKeys.length, newParams = {};
282
- for (let i = 0; i < len; i++) {
283
- newParams[sortedKeys[i]] = params[sortedKeys[i]];
284
- }
285
- return newParams;
286
- }
287
- }
288
- ```
289
- @public
290
- */
291
- sortQueryParams(obj) {
292
- const keys = Object.keys(obj);
293
- const len = keys.length;
294
- if (len < 2) {
295
- return obj;
296
- }
297
- const newQueryParams = {};
298
- const sortedKeys = keys.sort();
299
- for (let i = 0; i < len; i++) {
300
- newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]];
301
- }
302
- return newQueryParams;
303
- }
304
-
305
- /**
306
- By default the RESTAdapter will send each find request coming from a `store.find`
307
- or from accessing a relationship separately to the server. If your server supports passing
308
- ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests
309
- within a single runloop.
310
- For example, if you have an initial payload of:
311
- ```javascript
312
- {
313
- post: {
314
- id: 1,
315
- comments: [1, 2]
316
- }
317
- }
318
- ```
319
- By default calling `post.comments` will trigger the following requests(assuming the
320
- comments haven't been loaded before):
321
- ```
322
- GET /comments/1
323
- GET /comments/2
324
- ```
325
- If you set coalesceFindRequests to `true` it will instead trigger the following request:
326
- ```
327
- GET /comments?ids[]=1&ids[]=2
328
- ```
329
- Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo`
330
- relationships accessed within the same runloop. If you set `coalesceFindRequests: true`
331
- ```javascript
332
- store.findRecord('comment', 1);
333
- store.findRecord('comment', 2);
334
- ```
335
- will also send a request to: `GET /comments?ids[]=1&ids[]=2`
336
- Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app
337
- `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work.
338
- @public
339
- */
340
- get coalesceFindRequests() {
341
- const coalesceFindRequests = this._coalesceFindRequests;
342
- if (typeof coalesceFindRequests === 'boolean') {
343
- return coalesceFindRequests;
344
- }
345
- return this._coalesceFindRequests = false;
346
- }
347
- set coalesceFindRequests(value) {
348
- this._coalesceFindRequests = value;
349
- }
350
-
351
- /**
352
- Endpoint paths can be prefixed with a `namespace` by setting the namespace
353
- property on the adapter:
354
- ```js [app/adapters/application.js]
355
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
356
- export default class ApplicationAdapter extends RESTAdapter {
357
- namespace = 'api/1';
358
- }
359
- ```
360
- Requests for the `Post` model would now target `/api/1/post/`.
361
- @public
362
- */
363
-
364
- /**
365
- An adapter can target other hosts by setting the `host` property.
366
- ```js [app/adapters/application.js]
367
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
368
- export default class ApplicationAdapter extends RESTAdapter {
369
- host = 'https://api.example.com';
370
- }
371
- ```
372
- Requests for the `Post` model would now target `https://api.example.com/post/`.
373
- @public
374
- */
69
+ ```js
70
+ {
71
+ "posts": {
72
+ "id": 1,
73
+ "title": "I'm Running to Reform the W3C",
74
+ "author": "Yehuda Katz"
75
+ }
76
+ }
77
+ ```
78
+
79
+ Similarly, in response to a `GET` request for `/posts`, the JSON should
80
+ look like this:
81
+
82
+ ```js
83
+ {
84
+ "posts": [
85
+ {
86
+ "id": 1,
87
+ "title": "I'm Running to Reform the W3C",
88
+ "author": "Yehuda Katz"
89
+ },
90
+ {
91
+ "id": 2,
92
+ "title": "Rails is omakase",
93
+ "author": "D2H"
94
+ }
95
+ ]
96
+ }
97
+ ```
375
98
 
376
- /**
377
- Some APIs require HTTP headers, e.g. to provide an API
378
- key. Arbitrary headers can be set as key/value pairs on the
379
- `RESTAdapter`'s `headers` object and WarpDrive will send them
380
- along with each ajax request..
381
- ```js [app/adapters/application.js]
382
- import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
383
- export default class ApplicationAdapter extends RESTAdapter {
384
- get headers() {
385
- return {
386
- 'API_KEY': 'secret key',
387
- 'ANOTHER_HEADER': 'Some header value'
388
- };
389
- }
390
- }
391
- ```
392
- @public
393
- */
99
+ Note that the object root can be pluralized for both a single-object response
100
+ and an array response: the REST adapter is not strict on this. Further, if the
101
+ HTTP server responds to a `GET` request to `/posts/1` (e.g. the response to a
102
+ `findRecord` query) with more than one object in the array, WarpDrive will
103
+ only display the object with the matching ID.
394
104
 
395
- /**
396
- Called by the store in order to fetch the JSON for a given
397
- type and ID.
398
- The `findRecord` method makes an Ajax request to a URL computed by
399
- `buildURL`, and returns a promise for the resulting payload.
400
- This method performs an HTTP `GET` request with the id provided as part of the query string.
401
- @since 1.13.0
402
- @public
403
- */
404
- findRecord(store, type, id, snapshot) {
405
- const url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
406
- const query = this.buildQuery(snapshot);
407
- return this.ajax(url, 'GET', {
408
- data: query
409
- });
410
- }
105
+ ### Conventional Names
411
106
 
412
- /**
413
- Called by the store in order to fetch a JSON array for all
414
- of the records for a given type.
415
- The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
416
- promise for the resulting payload.
417
- @public
418
- */
419
- findAll(store, type, neverUsed, snapshotRecordArray) {
420
- const query = this.buildQuery(snapshotRecordArray);
421
- const url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll');
422
- return this.ajax(url, 'GET', {
423
- data: query
424
- });
425
- }
107
+ Attribute names in your JSON payload should be the camelCased versions of
108
+ the attributes in your Ember.js models.
426
109
 
427
- /**
428
- Called by the store in order to fetch a JSON array for
429
- the records that match a particular query.
430
- The `query` method makes an Ajax (HTTP GET) request to a URL
431
- computed by `buildURL`, and returns a promise for the resulting
432
- payload.
433
- The `query` argument is a simple JavaScript object that will be passed directly
434
- to the server as parameters.
435
- @public
436
- */
437
- query(store, type, query) {
438
- const url = this.buildURL(type.modelName, null, null, 'query', query);
439
- if (this.sortQueryParams) {
440
- query = this.sortQueryParams(query);
441
- }
442
- return this.ajax(url, 'GET', {
443
- data: query
444
- });
445
- }
110
+ For example, if you have a `Person` model:
446
111
 
447
- /**
448
- Called by the store in order to fetch a JSON object for
449
- the record that matches a particular query.
450
- The `queryRecord` method makes an Ajax (HTTP GET) request to a URL
451
- computed by `buildURL`, and returns a promise for the resulting
452
- payload.
453
- The `query` argument is a simple JavaScript object that will be passed directly
454
- to the server as parameters.
455
- @since 1.13.0
456
- @public
457
- */
458
- queryRecord(store, type, query, adapterOptions) {
459
- const url = this.buildURL(type.modelName, null, null, 'queryRecord', query);
460
- if (this.sortQueryParams) {
461
- query = this.sortQueryParams(query);
462
- }
463
- return this.ajax(url, 'GET', {
464
- data: query
465
- });
466
- }
112
+ ```js [app/models/person.js]
113
+ import { Model, attr } from '@warp-drive/legacy/model';
467
114
 
468
- /**
469
- Called by the store in order to fetch several records together if `coalesceFindRequests` is true
470
- For example, if the original payload looks like:
471
- ```js
472
- {
473
- "id": 1,
474
- "title": "Rails is omakase",
475
- "comments": [ 1, 2, 3 ]
476
- }
477
- ```
478
- The IDs will be passed as a URL-encoded Array of IDs, in this form:
479
- ```
480
- ids[]=1&ids[]=2&ids[]=3
481
- ```
482
- Many servers, such as Rails and PHP, will automatically convert this URL-encoded array
483
- into an Array for you on the server-side. If you want to encode the
484
- IDs, differently, just override this (one-line) method.
485
- The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
486
- promise for the resulting payload.
487
- @public
488
- */
489
- findMany(store, type, ids, snapshots) {
490
- const url = this.buildURL(type.modelName, ids, snapshots, 'findMany');
491
- return this.ajax(url, 'GET', {
492
- data: {
493
- ids: ids
494
- }
495
- });
496
- }
115
+ export default Model.extend({
116
+ firstName: attr('string'),
117
+ lastName: attr('string'),
118
+ occupation: attr('string')
119
+ });
120
+ ```
497
121
 
498
- /**
499
- Called by the store in order to fetch a JSON array for
500
- the unloaded records in a has-many relationship that were originally
501
- specified as a URL (inside of `links`).
502
- For example, if your original payload looks like this:
503
- ```js
504
- {
505
- "post": {
506
- "id": 1,
507
- "title": "Rails is omakase",
508
- "links": { "comments": "/posts/1/comments" }
509
- }
510
- }
511
- ```
512
- This method will be called with the parent record and `/posts/1/comments`.
513
- The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL.
514
- The format of your `links` value will influence the final request URL via the `urlPrefix` method:
515
- * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation.
516
- * Links beginning with a single `/` will have the current adapter's `host` value prepended to it.
517
- * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`.
518
- @public
519
- */
520
- findHasMany(store, snapshot, url, relationship) {
521
- const id = snapshot.id;
522
- const type = snapshot.modelName;
523
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
524
- if (!test) {
525
- throw new Error(`Attempted to fetch the hasMany relationship for ${type}, but the record has no id`);
526
- }
527
- })(typeof id === 'string' && id.length > 0) : {};
528
- url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany'));
529
- return this.ajax(url, 'GET');
530
- }
122
+ The JSON returned should look like this:
531
123
 
532
- /**
533
- Called by the store in order to fetch the JSON for the unloaded record in a
534
- belongs-to relationship that was originally specified as a URL (inside of
535
- `links`).
536
- For example, if your original payload looks like this:
537
- ```js
538
- {
539
- "person": {
540
- "id": 1,
541
- "name": "Tom Dale",
542
- "links": { "group": "/people/1/group" }
543
- }
544
- }
545
- ```
546
- This method will be called with the parent record and `/people/1/group`.
547
- The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL.
548
- The format of your `links` value will influence the final request URL via the `urlPrefix` method:
549
- * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation.
550
- * Links beginning with a single `/` will have the current adapter's `host` value prepended to it.
551
- * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`.
552
- @public
553
- */
554
- findBelongsTo(store, snapshot, url, relationship) {
555
- const id = snapshot.id;
556
- const type = snapshot.modelName;
557
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
558
- if (!test) {
559
- throw new Error(`Attempted to fetch the belongsTo relationship for ${type}, but the record has no id`);
560
- }
561
- })(typeof id === 'string' && id.length > 0) : {};
562
- url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo'));
563
- return this.ajax(url, 'GET');
564
- }
124
+ ```js
125
+ {
126
+ "people": {
127
+ "id": 5,
128
+ "firstName": "Zaphod",
129
+ "lastName": "Beeblebrox",
130
+ "occupation": "President"
131
+ }
132
+ }
133
+ ```
134
+
135
+ #### Relationships
136
+
137
+ Relationships are usually represented by ids to the record in the
138
+ relationship. The related records can then be sideloaded in the
139
+ response under a key for the type.
140
+
141
+ ```js
142
+ {
143
+ "posts": {
144
+ "id": 5,
145
+ "title": "I'm Running to Reform the W3C",
146
+ "author": "Yehuda Katz",
147
+ "comments": [1, 2]
148
+ },
149
+ "comments": [{
150
+ "id": 1,
151
+ "author": "User 1",
152
+ "message": "First!",
153
+ }, {
154
+ "id": 2,
155
+ "author": "User 2",
156
+ "message": "Good Luck!",
157
+ }]
158
+ }
159
+ ```
160
+
161
+ If the records in the relationship are not known when the response
162
+ is serialized it's also possible to represent the relationship as a
163
+ URL using the `links` key in the response. WarpDrive will fetch
164
+ this URL to resolve the relationship when it is accessed for the
165
+ first time.
166
+
167
+ ```js
168
+ {
169
+ "posts": {
170
+ "id": 5,
171
+ "title": "I'm Running to Reform the W3C",
172
+ "author": "Yehuda Katz",
173
+ "links": {
174
+ "comments": "/posts/5/comments"
175
+ }
176
+ }
177
+ }
178
+ ```
565
179
 
566
- /**
567
- Called by the store when a newly created record is
568
- saved via the `save` method on a model record instance.
569
- The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request
570
- to a URL computed by `buildURL`.
571
- See `serialize` for information on how to customize the serialized form
572
- of a record.
573
- @public
574
- */
575
- createRecord(store, type, snapshot) {
576
- const url = this.buildURL(type.modelName, null, snapshot, 'createRecord');
577
- const data = serializeIntoHash(store, type, snapshot);
578
- return this.ajax(url, 'POST', {
579
- data
580
- });
581
- }
180
+ ### Errors
582
181
 
583
- /**
584
- Called by the store when an existing record is saved
585
- via the `save` method on a model record instance.
586
- The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request
587
- to a URL computed by `buildURL`.
588
- See `serialize` for information on how to customize the serialized form
589
- of a record.
590
- @public
591
- */
592
- updateRecord(store, schema, snapshot) {
593
- const data = serializeIntoHash(store, schema, snapshot, {});
594
- const type = snapshot.modelName;
595
- const id = snapshot.id;
596
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
597
- if (!test) {
598
- throw new Error(`Attempted to update the ${type} record, but the record has no id`);
599
- }
600
- })(typeof id === 'string' && id.length > 0) : {};
601
- const url = this.buildURL(type, id, snapshot, 'updateRecord');
602
- return this.ajax(url, 'PUT', {
603
- data
604
- });
605
- }
182
+ If a response is considered a failure, the JSON payload is expected to include
183
+ a top-level key `errors`, detailing any specific issues. For example:
606
184
 
607
- /**
608
- Called by the store when a record is deleted.
609
- The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`.
610
- @public
611
- */
612
- deleteRecord(store, schema, snapshot) {
613
- const type = snapshot.modelName;
614
- const id = snapshot.id;
615
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
616
- if (!test) {
617
- throw new Error(`Attempted to delete the ${type} record, but the record has no id`);
618
- }
619
- })(typeof id === 'string' && id.length > 0) : {};
620
- return this.ajax(this.buildURL(type, id, snapshot, 'deleteRecord'), 'DELETE');
621
- }
185
+ ```js
186
+ {
187
+ "errors": {
188
+ "msg": "Something went wrong"
189
+ }
190
+ }
191
+ ```
622
192
 
623
- /**
624
- @private
625
- */
626
- _stripIDFromURL(store, snapshot) {
627
- const type = snapshot.modelName;
628
- const id = snapshot.id;
629
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
630
- if (!test) {
631
- throw new Error(`Attempted to strip the url from the ${type} record for coalescing, but the record has no id`);
632
- }
633
- })(typeof id === 'string' && id.length > 0) : {};
634
- const url = this.buildURL(type, id, snapshot);
635
- const expandedURL = url.split('/');
636
- // Case when the url is of the format ...something/:id
637
- // We are decodeURIComponent-ing the lastSegment because if it represents
638
- // the id, it has been encodeURIComponent-ified within `buildURL`. If we
639
- // don't do this, then records with id having special characters are not
640
- // coalesced correctly (see GH #4190 for the reported bug)
641
- const lastSegment = expandedURL[expandedURL.length - 1];
642
- if (decodeURIComponent(lastSegment) === id) {
643
- expandedURL[expandedURL.length - 1] = '';
644
- } else if (id && endsWith(lastSegment, '?id=' + id)) {
645
- //Case when the url is of the format ...something?id=:id
646
- expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1);
647
- }
648
- return expandedURL.join('/');
649
- }
193
+ This adapter does not make any assumptions as to the format of the `errors`
194
+ object. It will simply be passed along as is, wrapped in an instance
195
+ of `InvalidError` or `AdapterError`. The serializer can interpret it
196
+ afterwards.
650
197
 
651
- // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
652
- maxURLLength = 2048;
198
+ ## Customization
653
199
 
654
- /**
655
- Organize records into groups, each of which is to be passed to separate
656
- calls to `findMany`.
657
- This implementation groups together records that have the same base URL but
658
- differing ids. For example `/comments/1` and `/comments/2` will be grouped together
659
- because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2`
660
- It also supports urls where ids are passed as a query param, such as `/comments?id=1`
661
- but not those where there is more than 1 query param such as `/comments?id=2&name=David`
662
- Currently only the query param of `id` is supported. If you need to support others, please
663
- override this or the `_stripIDFromURL` method.
664
- It does not group records that have differing base urls, such as for example: `/posts/1/comments/2`
665
- and `/posts/2/comments/3`
666
- @public
667
- @return an array of arrays of records, each of which is to be
668
- loaded separately by `findMany`.
669
- */
670
- groupRecordsForFindMany(store, snapshots) {
671
- const groups = new Map();
672
- const maxURLLength = this.maxURLLength;
673
- snapshots.forEach(snapshot => {
674
- const baseUrl = this._stripIDFromURL(store, snapshot);
675
- if (!groups.has(baseUrl)) {
676
- groups.set(baseUrl, []);
677
- }
678
- groups.get(baseUrl).push(snapshot);
679
- });
680
- const groupsArray = [];
681
- groups.forEach((group, key) => {
682
- const paramNameLength = '&ids%5B%5D='.length;
683
- const splitGroups = splitGroupToFitInUrl(store, this, group, maxURLLength, paramNameLength);
684
- splitGroups.forEach(splitGroup => groupsArray.push(splitGroup));
685
- });
686
- return groupsArray;
687
- }
200
+ ### Endpoint path customization
688
201
 
689
- /**
690
- Takes an ajax response, and returns the json payload or an error.
691
- By default this hook just returns the json payload passed to it.
692
- You might want to override it in two cases:
693
- 1. Your API might return useful results in the response headers.
694
- Response headers are passed in as the second argument.
695
- 2. Your API might return errors as successful responses with status code
696
- 200 and an Errors text or object. You can return a `InvalidError` or a
697
- `AdapterError` (or a sub class) from this hook and it will automatically
698
- reject the promise and put your record into the invalid or error state.
699
- Returning a `InvalidError` from this method will cause the
700
- record to transition into the `invalid` state and make the
701
- `errors` object available on the record. When returning an
702
- `InvalidError` the store will attempt to normalize the error data
703
- returned from the server using the serializer's `extractErrors`
704
- method.
705
- @since 1.13.0
706
- @public
707
- */
708
- handleResponse(status, headers, payload, requestData) {
709
- if (this.isSuccess(status, headers, payload)) {
710
- return payload;
711
- } else if (this.isInvalid(status, headers, payload)) {
712
- // @ts-expect-error needs cast to ApiError
713
- return new InvalidError(typeof payload === 'object' && 'errors' in payload ? payload.errors : undefined);
714
- }
715
- const errors = this.normalizeErrorResponse(status, headers, payload);
716
- const detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData);
717
- switch (status) {
718
- case 401:
719
- return new UnauthorizedError(errors, detailedMessage);
720
- case 403:
721
- return new ForbiddenError(errors, detailedMessage);
722
- case 404:
723
- return new NotFoundError(errors, detailedMessage);
724
- case 409:
725
- return new ConflictError(errors, detailedMessage);
726
- default:
727
- if (status >= 500) {
728
- return new ServerError(errors, detailedMessage);
729
- }
730
- }
731
- return new AdapterError(errors, detailedMessage);
732
- }
202
+ Endpoint paths can be prefixed with a `namespace` by setting the namespace
203
+ property on the adapter:
733
204
 
734
- /**
735
- Default `handleResponse` implementation uses this hook to decide if the
736
- response is a success.
737
- @since 1.13.0
738
- @public
739
- */
740
- isSuccess(status, _headers, _payload) {
741
- return status >= 200 && status < 300 || status === 304;
742
- }
205
+ ```js [app/adapters/application.js]
206
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
743
207
 
744
- /**
745
- Default `handleResponse` implementation uses this hook to decide if the
746
- response is an invalid error.
747
- @since 1.13.0
748
- @public
749
- */
750
- isInvalid(status, _headers, _payload) {
751
- return status === 422;
752
- }
208
+ export default class ApplicationAdapter extends RESTAdapter {
209
+ namespace = 'api/1';
210
+ }
211
+ ```
212
+ Requests for the `Person` model would now target `/api/1/people/1`.
753
213
 
754
- /**
755
- Takes a URL, an HTTP method and a hash of data, and makes an
756
- HTTP request.
757
- When the server responds with a payload, WarpDrive will call into `extractSingle`
758
- or `extractArray` (depending on whether the original query was for one record or
759
- many records).
760
- By default, `ajax` method has the following behavior:
761
- * It sets the response `dataType` to `"json"`
762
- * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be
763
- `application/json; charset=utf-8`
764
- * If the HTTP method is not `"GET"`, it stringifies the data passed in. The
765
- data is the serialized record in the case of a save.
766
- * Registers success and failure handlers.
767
- @private
768
- */
769
- async ajax(url, type, options = {}) {
770
- const requestData = {
771
- url: url,
772
- method: type
773
- };
774
- if (this.useFetch) {
775
- // @ts-expect-error poorly typed
776
- const hash = this.ajaxOptions(url, type, options);
777
- const response = await this._fetchRequest(hash);
778
- const payload = await determineBodyPromise(response, requestData);
779
- if (response.ok && !(payload instanceof Error)) {
780
- return fetchSuccessHandler(this, payload, response, requestData);
781
- } else {
782
- // eslint-disable-next-line @typescript-eslint/only-throw-error
783
- throw fetchErrorHandler(this, payload, response, null, requestData);
784
- }
785
- } else {
786
- return execjQAjax(this, requestData, options);
787
- }
788
- }
214
+ ### Host customization
789
215
 
790
- /**
791
- @private
792
- @param options jQuery ajax options to be used for the ajax request
793
- */
794
- _ajaxRequest(options) {
795
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
796
- if (!test) {
797
- throw new Error('You must install jQuery globally when `useFetch` is false');
798
- }
799
- })(typeof jQuery !== 'undefined') : {};
800
- void jQuery.ajax(options);
801
- }
802
- /**
803
- @private
804
- */
805
- _fetchRequest(options) {
806
- const fetchFunction = getFetchFunction();
807
- return fetchFunction(options.url, options);
808
- }
809
- /**
810
- @private
811
- */
812
- _ajax(options) {
813
- if (this.useFetch) {
814
- void this._fetchRequest(options);
815
- } else {
816
- this._ajaxRequest(options);
817
- }
818
- }
216
+ An adapter can target other hosts by setting the `host` property.
819
217
 
820
- /**
821
- @private
822
- */
823
- ajaxOptions(url, method, options) {
824
- let reqOptions = Object.assign({
825
- url,
826
- method,
827
- type: method
828
- }, options);
829
- if (this.headers !== undefined) {
830
- // @ts-expect-error poorly typed
831
- reqOptions.headers = {
832
- ...this.headers,
833
- ...reqOptions.headers
834
- };
835
- } else if (!options.headers) {
836
- reqOptions.headers = {};
837
- }
218
+ ```js [app/adapters/application.js]
219
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
838
220
 
839
- // @ts-expect-error poorly typed
840
- const contentType = reqOptions.contentType || this._defaultContentType;
841
- if (this.useFetch) {
842
- // @ts-expect-error poorly typed
843
- if (reqOptions.data && reqOptions.type !== 'GET' && reqOptions.headers) {
844
- if (!reqOptions.headers['Content-Type'] && !reqOptions.headers['content-type']) {
845
- reqOptions.headers['content-type'] = contentType;
846
- }
847
- }
848
- // @ts-expect-error poorly typed
849
- reqOptions = fetchOptions(reqOptions);
850
- } else {
851
- // GET requests without a body should not have a content-type header
852
- // and may be unexpected by a server
853
- // @ts-expect-error poorly typed
854
- if (reqOptions.data && reqOptions.type !== 'GET') {
855
- reqOptions = {
856
- ...reqOptions,
857
- contentType
858
- };
859
- }
860
- // @ts-expect-error poorly typed
861
- reqOptions = ajaxOptions(reqOptions, this);
862
- }
863
- reqOptions.url = this._ajaxURL(reqOptions.url);
864
- return reqOptions;
865
- }
221
+ export default class ApplicationAdapter extends RESTAdapter {
222
+ host = 'https://api.example.com';
223
+ }
224
+ ```
866
225
 
867
- /**
868
- * @private
869
- */
870
- _ajaxURL(url) {
871
- if (this.fastboot?.isFastBoot) {
872
- const httpRegex = /^https?:\/\//;
873
- const protocolRelativeRegex = /^\/\//;
874
- const protocol = this.fastboot.request.protocol;
875
- const host = this.fastboot.request.host;
876
- if (protocolRelativeRegex.test(url)) {
877
- return `${protocol}${url}`;
878
- } else if (!httpRegex.test(url)) {
879
- try {
880
- return `${protocol}//${host}${url}`;
881
- } catch (fbError) {
882
- throw new Error('You are using WarpDrive with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: ' + fbError.message);
883
- }
884
- }
885
- }
886
- return url;
887
- }
226
+ ### Headers customization
888
227
 
889
- /**
890
- @private
891
- */
892
- parseErrorResponse(responseText) {
893
- let json = responseText;
894
- try {
895
- json = JSON.parse(responseText);
896
- } catch {
897
- // ignored
898
- }
899
- return json;
900
- }
228
+ Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary
229
+ headers can be set as key/value pairs on the `RESTAdapter`'s `headers`
230
+ object and WarpDrive will send them along with each ajax request.
901
231
 
902
- /**
903
- @private
904
- @return errors payload
905
- */
906
- normalizeErrorResponse(status, _headers, payload) {
907
- if (payload && typeof payload === 'object' && 'errors' in payload && Array.isArray(payload.errors)) {
908
- return payload.errors;
909
- } else {
910
- return [{
911
- status: `${status}`,
912
- // Set to a string per the JSON API spec: https://jsonapi.org/format/#errors
913
- title: 'The backend responded with an error',
914
- // Detail is intended to be a string, but backends be non-compliant.
915
- // stringifying gives the user a more friendly error in this situation, whereas
916
- // they'd instead receive [object Object].
917
- // JSON.stringify will convert *anything* to a string without erroring.
918
- detail: typeof payload === 'string' ? payload : JSON.stringify(payload)
919
- }];
920
- }
921
- }
922
232
 
923
- /**
924
- Generates a detailed ("friendly") error message, with plenty
925
- of information for debugging (good luck!)
926
- @private
927
- @return detailed error message
928
- */
929
- generatedDetailedMessage(status, headers, payload, requestData) {
930
- let shortenedPayload;
931
- const payloadContentType = headers['content-type'] || 'Empty Content-Type';
932
- if (payloadContentType === 'text/html' && typeof payload === 'string' && payload.length > 250) {
933
- shortenedPayload = '[Omitted Lengthy HTML]';
934
- } else if (typeof payload === 'object' && payload !== null) {
935
- shortenedPayload = JSON.stringify(payload, null, 2);
936
- } else {
937
- shortenedPayload = payload;
938
- }
939
- const requestDescription = requestData.method + ' ' + requestData.url;
940
- const payloadDescription = 'Payload (' + payloadContentType + ')';
941
- return ['Ember Data Request ' + requestDescription + ' returned a ' + status, payloadDescription, shortenedPayload].join('\n');
942
- }
233
+ ```js [app/adapters/application.js]
234
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
943
235
 
944
- /**
945
- Used by `findAll` and `findRecord` to build the query's `data` hash
946
- supplied to the ajax method.
947
- @since 2.5.0
948
- @public
949
- */
950
- buildQuery(snapshot) {
951
- const query = {};
952
- if (snapshot) {
953
- const {
954
- include
955
- } = snapshot;
956
- if (include) {
957
- // note: if user passed in an array, this will serialize like `?include[]=foo&include[]=bar`
958
- // but if user passed in a string, this will serialize like `?include=foo,bar`
959
- // users that want consistent behavior should override this method
960
- query.include = include;
961
- }
962
- }
963
- return query;
964
- }
236
+ export default class ApplicationAdapter extends RESTAdapter {
237
+ get headers() {
238
+ return {
239
+ 'API_KEY': 'secret key',
240
+ 'ANOTHER_HEADER': 'Some header value'
241
+ };
965
242
  }
243
+ }
244
+ ```
966
245
 
967
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
968
-
246
+ @public
247
+ */
248
+ var RESTAdapter = class extends AdapterWithBuildURLMixin {
249
+ /**
250
+ * @private
251
+ */
252
+ /**
253
+ * @private
254
+ */
255
+ /**
256
+ * See "Host customization" above.
257
+ */
258
+ /**
259
+ * See "Namespace customization" above.
260
+ */
261
+ /**
262
+ This property allows ajax to still be used instead when `false`.
263
+ @default true
264
+ @public
265
+ */
266
+ useFetch = true;
267
+ /**
268
+ * The `Content-Type` header used when serializing request bodies
269
+ * that don't otherwise specify one.
270
+ */
271
+ _defaultContentType = "application/json; charset=utf-8";
272
+ /**
273
+ * The FastBoot service instance, if running in a FastBoot environment.
274
+ * Lazily looked up on first access.
275
+ */
276
+ get fastboot() {
277
+ const fastboot = this._fastboot;
278
+ if (fastboot) return fastboot;
279
+ return this._fastboot = getOwner(this).lookup("service:fastboot");
280
+ }
281
+ /**
282
+ * Sets the FastBoot service instance to use.
283
+ */
284
+ static {
285
+ decorateMethodV2(this.prototype, "fastboot", [computed()]);
286
+ }
287
+ set fastboot(value) {
288
+ this._fastboot = value;
289
+ }
290
+ /**
291
+ By default, the RESTAdapter will send the query params sorted alphabetically to the
292
+ server.
293
+ For example:
294
+ ```js
295
+ store.query('posts', { sort: 'price', category: 'pets' });
296
+ ```
297
+ will generate a requests like this `/posts?category=pets&sort=price`, even if the
298
+ parameters were specified in a different order.
299
+ That way the generated URL will be deterministic and that simplifies caching mechanisms
300
+ in the backend.
301
+ Setting `sortQueryParams` to a falsey value will respect the original order.
302
+ In case you want to sort the query parameters with a different criteria, set
303
+ `sortQueryParams` to your custom sort function.
304
+ ```js [app/adapters/application.js]
305
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
306
+ export default class ApplicationAdapter extends RESTAdapter {
307
+ sortQueryParams(params) {
308
+ let sortedKeys = Object.keys(params).sort().reverse();
309
+ let len = sortedKeys.length, newParams = {};
310
+ for (let i = 0; i < len; i++) {
311
+ newParams[sortedKeys[i]] = params[sortedKeys[i]];
312
+ }
313
+ return newParams;
314
+ }
315
+ }
316
+ ```
317
+ @public
318
+ */
319
+ sortQueryParams(obj) {
320
+ const keys = Object.keys(obj);
321
+ const len = keys.length;
322
+ if (len < 2) return obj;
323
+ const newQueryParams = {};
324
+ const sortedKeys = keys.sort();
325
+ for (let i = 0; i < len; i++) newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]];
326
+ return newQueryParams;
327
+ }
328
+ /**
329
+ By default the RESTAdapter will send each find request coming from a `store.find`
330
+ or from accessing a relationship separately to the server. If your server supports passing
331
+ ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests
332
+ within a single runloop.
333
+ For example, if you have an initial payload of:
334
+ ```javascript
335
+ {
336
+ post: {
337
+ id: 1,
338
+ comments: [1, 2]
339
+ }
340
+ }
341
+ ```
342
+ By default calling `post.comments` will trigger the following requests(assuming the
343
+ comments haven't been loaded before):
344
+ ```
345
+ GET /comments/1
346
+ GET /comments/2
347
+ ```
348
+ If you set coalesceFindRequests to `true` it will instead trigger the following request:
349
+ ```
350
+ GET /comments?ids[]=1&ids[]=2
351
+ ```
352
+ Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo`
353
+ relationships accessed within the same runloop. If you set `coalesceFindRequests: true`
354
+ ```javascript
355
+ store.findRecord('comment', 1);
356
+ store.findRecord('comment', 2);
357
+ ```
358
+ will also send a request to: `GET /comments?ids[]=1&ids[]=2`
359
+ Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app
360
+ `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work.
361
+ @public
362
+ */
363
+ get coalesceFindRequests() {
364
+ const coalesceFindRequests = this._coalesceFindRequests;
365
+ if (typeof coalesceFindRequests === "boolean") return coalesceFindRequests;
366
+ return this._coalesceFindRequests = false;
367
+ }
368
+ set coalesceFindRequests(value) {
369
+ this._coalesceFindRequests = value;
370
+ }
371
+ /**
372
+ Endpoint paths can be prefixed with a `namespace` by setting the namespace
373
+ property on the adapter:
374
+ ```js [app/adapters/application.js]
375
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
376
+ export default class ApplicationAdapter extends RESTAdapter {
377
+ namespace = 'api/1';
378
+ }
379
+ ```
380
+ Requests for the `Post` model would now target `/api/1/post/`.
381
+ @public
382
+ */
383
+ /**
384
+ An adapter can target other hosts by setting the `host` property.
385
+ ```js [app/adapters/application.js]
386
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
387
+ export default class ApplicationAdapter extends RESTAdapter {
388
+ host = 'https://api.example.com';
389
+ }
390
+ ```
391
+ Requests for the `Post` model would now target `https://api.example.com/post/`.
392
+ @public
393
+ */
394
+ /**
395
+ Some APIs require HTTP headers, e.g. to provide an API
396
+ key. Arbitrary headers can be set as key/value pairs on the
397
+ `RESTAdapter`'s `headers` object and WarpDrive will send them
398
+ along with each ajax request..
399
+ ```js [app/adapters/application.js]
400
+ import { RESTAdapter } from '@warp-drive/legacy/adapter/rest';
401
+ export default class ApplicationAdapter extends RESTAdapter {
402
+ get headers() {
403
+ return {
404
+ 'API_KEY': 'secret key',
405
+ 'ANOTHER_HEADER': 'Some header value'
406
+ };
407
+ }
408
+ }
409
+ ```
410
+ @public
411
+ */
412
+ /**
413
+ Called by the store in order to fetch the JSON for a given
414
+ type and ID.
415
+ The `findRecord` method makes an Ajax request to a URL computed by
416
+ `buildURL`, and returns a promise for the resulting payload.
417
+ This method performs an HTTP `GET` request with the id provided as part of the query string.
418
+ @since 1.13.0
419
+ @public
420
+ */
421
+ findRecord(store, type, id, snapshot) {
422
+ const url = this.buildURL(type.modelName, id, snapshot, "findRecord");
423
+ const query = this.buildQuery(snapshot);
424
+ return this.ajax(url, "GET", { data: query });
425
+ }
426
+ /**
427
+ Called by the store in order to fetch a JSON array for all
428
+ of the records for a given type.
429
+ The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
430
+ promise for the resulting payload.
431
+ @public
432
+ */
433
+ findAll(store, type, neverUsed, snapshotRecordArray) {
434
+ const query = this.buildQuery(snapshotRecordArray);
435
+ const url = this.buildURL(type.modelName, null, snapshotRecordArray, "findAll");
436
+ return this.ajax(url, "GET", { data: query });
437
+ }
438
+ /**
439
+ Called by the store in order to fetch a JSON array for
440
+ the records that match a particular query.
441
+ The `query` method makes an Ajax (HTTP GET) request to a URL
442
+ computed by `buildURL`, and returns a promise for the resulting
443
+ payload.
444
+ The `query` argument is a simple JavaScript object that will be passed directly
445
+ to the server as parameters.
446
+ @public
447
+ */
448
+ query(store, type, query) {
449
+ const url = this.buildURL(type.modelName, null, null, "query", query);
450
+ if (this.sortQueryParams) query = this.sortQueryParams(query);
451
+ return this.ajax(url, "GET", { data: query });
452
+ }
453
+ /**
454
+ Called by the store in order to fetch a JSON object for
455
+ the record that matches a particular query.
456
+ The `queryRecord` method makes an Ajax (HTTP GET) request to a URL
457
+ computed by `buildURL`, and returns a promise for the resulting
458
+ payload.
459
+ The `query` argument is a simple JavaScript object that will be passed directly
460
+ to the server as parameters.
461
+ @since 1.13.0
462
+ @public
463
+ */
464
+ queryRecord(store, type, query, adapterOptions) {
465
+ const url = this.buildURL(type.modelName, null, null, "queryRecord", query);
466
+ if (this.sortQueryParams) query = this.sortQueryParams(query);
467
+ return this.ajax(url, "GET", { data: query });
468
+ }
469
+ /**
470
+ Called by the store in order to fetch several records together if `coalesceFindRequests` is true
471
+ For example, if the original payload looks like:
472
+ ```js
473
+ {
474
+ "id": 1,
475
+ "title": "Rails is omakase",
476
+ "comments": [ 1, 2, 3 ]
477
+ }
478
+ ```
479
+ The IDs will be passed as a URL-encoded Array of IDs, in this form:
480
+ ```
481
+ ids[]=1&ids[]=2&ids[]=3
482
+ ```
483
+ Many servers, such as Rails and PHP, will automatically convert this URL-encoded array
484
+ into an Array for you on the server-side. If you want to encode the
485
+ IDs, differently, just override this (one-line) method.
486
+ The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
487
+ promise for the resulting payload.
488
+ @public
489
+ */
490
+ findMany(store, type, ids, snapshots) {
491
+ const url = this.buildURL(type.modelName, ids, snapshots, "findMany");
492
+ return this.ajax(url, "GET", { data: { ids } });
493
+ }
494
+ /**
495
+ Called by the store in order to fetch a JSON array for
496
+ the unloaded records in a has-many relationship that were originally
497
+ specified as a URL (inside of `links`).
498
+ For example, if your original payload looks like this:
499
+ ```js
500
+ {
501
+ "post": {
502
+ "id": 1,
503
+ "title": "Rails is omakase",
504
+ "links": { "comments": "/posts/1/comments" }
505
+ }
506
+ }
507
+ ```
508
+ This method will be called with the parent record and `/posts/1/comments`.
509
+ The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL.
510
+ The format of your `links` value will influence the final request URL via the `urlPrefix` method:
511
+ * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation.
512
+ * Links beginning with a single `/` will have the current adapter's `host` value prepended to it.
513
+ * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`.
514
+ @public
515
+ */
516
+ findHasMany(store, snapshot, url, relationship) {
517
+ const id = snapshot.id;
518
+ const type = snapshot.modelName;
519
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) && ((test) => {
520
+ if (!test) throw new Error(`Attempted to fetch the hasMany relationship for ${type}, but the record has no id`);
521
+ })(typeof id === "string" && id.length > 0);
522
+ url = this.urlPrefix(url, this.buildURL(type, id, snapshot, "findHasMany"));
523
+ return this.ajax(url, "GET");
524
+ }
525
+ /**
526
+ Called by the store in order to fetch the JSON for the unloaded record in a
527
+ belongs-to relationship that was originally specified as a URL (inside of
528
+ `links`).
529
+ For example, if your original payload looks like this:
530
+ ```js
531
+ {
532
+ "person": {
533
+ "id": 1,
534
+ "name": "Tom Dale",
535
+ "links": { "group": "/people/1/group" }
536
+ }
537
+ }
538
+ ```
539
+ This method will be called with the parent record and `/people/1/group`.
540
+ The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL.
541
+ The format of your `links` value will influence the final request URL via the `urlPrefix` method:
542
+ * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation.
543
+ * Links beginning with a single `/` will have the current adapter's `host` value prepended to it.
544
+ * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`.
545
+ @public
546
+ */
547
+ findBelongsTo(store, snapshot, url, relationship) {
548
+ const id = snapshot.id;
549
+ const type = snapshot.modelName;
550
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) && ((test) => {
551
+ if (!test) throw new Error(`Attempted to fetch the belongsTo relationship for ${type}, but the record has no id`);
552
+ })(typeof id === "string" && id.length > 0);
553
+ url = this.urlPrefix(url, this.buildURL(type, id, snapshot, "findBelongsTo"));
554
+ return this.ajax(url, "GET");
555
+ }
556
+ /**
557
+ Called by the store when a newly created record is
558
+ saved via the `save` method on a model record instance.
559
+ The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request
560
+ to a URL computed by `buildURL`.
561
+ See `serialize` for information on how to customize the serialized form
562
+ of a record.
563
+ @public
564
+ */
565
+ createRecord(store, type, snapshot) {
566
+ const url = this.buildURL(type.modelName, null, snapshot, "createRecord");
567
+ const data = serializeIntoHash(store, type, snapshot);
568
+ return this.ajax(url, "POST", { data });
569
+ }
570
+ /**
571
+ Called by the store when an existing record is saved
572
+ via the `save` method on a model record instance.
573
+ The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request
574
+ to a URL computed by `buildURL`.
575
+ See `serialize` for information on how to customize the serialized form
576
+ of a record.
577
+ @public
578
+ */
579
+ updateRecord(store, schema, snapshot) {
580
+ const data = serializeIntoHash(store, schema, snapshot, {});
581
+ const type = snapshot.modelName;
582
+ const id = snapshot.id;
583
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) && ((test) => {
584
+ if (!test) throw new Error(`Attempted to update the ${type} record, but the record has no id`);
585
+ })(typeof id === "string" && id.length > 0);
586
+ const url = this.buildURL(type, id, snapshot, "updateRecord");
587
+ return this.ajax(url, "PUT", { data });
588
+ }
589
+ /**
590
+ Called by the store when a record is deleted.
591
+ The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`.
592
+ @public
593
+ */
594
+ deleteRecord(store, schema, snapshot) {
595
+ const type = snapshot.modelName;
596
+ const id = snapshot.id;
597
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) && ((test) => {
598
+ if (!test) throw new Error(`Attempted to delete the ${type} record, but the record has no id`);
599
+ })(typeof id === "string" && id.length > 0);
600
+ return this.ajax(this.buildURL(type, id, snapshot, "deleteRecord"), "DELETE");
601
+ }
602
+ /**
603
+ @private
604
+ */
605
+ _stripIDFromURL(store, snapshot) {
606
+ const type = snapshot.modelName;
607
+ const id = snapshot.id;
608
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) && ((test) => {
609
+ if (!test) throw new Error(`Attempted to strip the url from the ${type} record for coalescing, but the record has no id`);
610
+ })(typeof id === "string" && id.length > 0);
611
+ const expandedURL = this.buildURL(type, id, snapshot).split("/");
612
+ const lastSegment = expandedURL[expandedURL.length - 1];
613
+ if (decodeURIComponent(lastSegment) === id) expandedURL[expandedURL.length - 1] = "";
614
+ else if (id && endsWith(lastSegment, "?id=" + id)) expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1);
615
+ return expandedURL.join("/");
616
+ }
617
+ /**
618
+ * The maximum URL length to allow when coalescing `findRecord` requests
619
+ * into a single `findMany` request via {@link RESTAdapter.groupRecordsForFindMany | groupRecordsForFindMany}.
620
+ * Requests that would exceed this length are split into multiple groups.
621
+ *
622
+ * See http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
623
+ */
624
+ maxURLLength = 2048;
625
+ /**
626
+ Organize records into groups, each of which is to be passed to separate
627
+ calls to `findMany`.
628
+ This implementation groups together records that have the same base URL but
629
+ differing ids. For example `/comments/1` and `/comments/2` will be grouped together
630
+ because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2`
631
+ It also supports urls where ids are passed as a query param, such as `/comments?id=1`
632
+ but not those where there is more than 1 query param such as `/comments?id=2&name=David`
633
+ Currently only the query param of `id` is supported. If you need to support others, please
634
+ override this or the `_stripIDFromURL` method.
635
+ It does not group records that have differing base urls, such as for example: `/posts/1/comments/2`
636
+ and `/posts/2/comments/3`
637
+ @public
638
+ @return an array of arrays of records, each of which is to be
639
+ loaded separately by `findMany`.
640
+ */
641
+ groupRecordsForFindMany(store, snapshots) {
642
+ const groups = /* @__PURE__ */ new Map();
643
+ const maxURLLength = this.maxURLLength;
644
+ snapshots.forEach((snapshot) => {
645
+ const baseUrl = this._stripIDFromURL(store, snapshot);
646
+ if (!groups.has(baseUrl)) groups.set(baseUrl, []);
647
+ groups.get(baseUrl).push(snapshot);
648
+ });
649
+ const groupsArray = [];
650
+ groups.forEach((group, key) => {
651
+ splitGroupToFitInUrl(store, this, group, maxURLLength, 11).forEach((splitGroup) => groupsArray.push(splitGroup));
652
+ });
653
+ return groupsArray;
654
+ }
655
+ /**
656
+ Takes an ajax response, and returns the json payload or an error.
657
+ By default this hook just returns the json payload passed to it.
658
+ You might want to override it in two cases:
659
+ 1. Your API might return useful results in the response headers.
660
+ Response headers are passed in as the second argument.
661
+ 2. Your API might return errors as successful responses with status code
662
+ 200 and an Errors text or object. You can return a `InvalidError` or a
663
+ `AdapterError` (or a sub class) from this hook and it will automatically
664
+ reject the promise and put your record into the invalid or error state.
665
+ Returning a `InvalidError` from this method will cause the
666
+ record to transition into the `invalid` state and make the
667
+ `errors` object available on the record. When returning an
668
+ `InvalidError` the store will attempt to normalize the error data
669
+ returned from the server using the serializer's `extractErrors`
670
+ method.
671
+ @since 1.13.0
672
+ @public
673
+ */
674
+ handleResponse(status, headers, payload, requestData) {
675
+ if (this.isSuccess(status, headers, payload)) return payload;
676
+ else if (this.isInvalid(status, headers, payload)) {
677
+ const errorPayload = payload ?? {};
678
+ return new InvalidError(typeof errorPayload === "object" && "errors" in errorPayload ? errorPayload.errors : void 0);
679
+ }
680
+ const errors = this.normalizeErrorResponse(status, headers, payload);
681
+ const detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData);
682
+ switch (status) {
683
+ case 401: return new UnauthorizedError(errors, detailedMessage);
684
+ case 403: return new ForbiddenError(errors, detailedMessage);
685
+ case 404: return new NotFoundError(errors, detailedMessage);
686
+ case 409: return new ConflictError(errors, detailedMessage);
687
+ default: if (status >= 500) return new ServerError(errors, detailedMessage);
688
+ }
689
+ return new AdapterError(errors, detailedMessage);
690
+ }
691
+ /**
692
+ Default `handleResponse` implementation uses this hook to decide if the
693
+ response is a success.
694
+ @since 1.13.0
695
+ @public
696
+ */
697
+ isSuccess(status, _headers, _payload) {
698
+ return status >= 200 && status < 300 || status === 304;
699
+ }
700
+ /**
701
+ Default `handleResponse` implementation uses this hook to decide if the
702
+ response is an invalid error.
703
+ @since 1.13.0
704
+ @public
705
+ */
706
+ isInvalid(status, _headers, _payload) {
707
+ return status === 422;
708
+ }
709
+ /**
710
+ Takes a URL, an HTTP method and a hash of data, and makes an
711
+ HTTP request.
712
+ When the server responds with a payload, WarpDrive will call into `extractSingle`
713
+ or `extractArray` (depending on whether the original query was for one record or
714
+ many records).
715
+ By default, `ajax` method has the following behavior:
716
+ * It sets the response `dataType` to `"json"`
717
+ * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be
718
+ `application/json; charset=utf-8`
719
+ * If the HTTP method is not `"GET"`, it stringifies the data passed in. The
720
+ data is the serialized record in the case of a save.
721
+ * Registers success and failure handlers.
722
+ @private
723
+ */
724
+ async ajax(url, type, options = {}) {
725
+ const requestData = {
726
+ url,
727
+ method: type
728
+ };
729
+ if (this.useFetch) {
730
+ const hash = this.ajaxOptions(url, type, options);
731
+ const response = await this._fetchRequest(hash);
732
+ const payload = await determineBodyPromise(response, requestData);
733
+ if (response.ok && !(payload instanceof Error)) return fetchSuccessHandler(this, payload, response, requestData);
734
+ else throw fetchErrorHandler(this, payload, response, null, requestData);
735
+ } else return execjQAjax(this, requestData, options);
736
+ }
737
+ /**
738
+ @private
739
+ @param options jQuery ajax options to be used for the ajax request
740
+ */
741
+ _ajaxRequest(options) {
742
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) && ((test) => {
743
+ if (!test) throw new Error("You must install jQuery globally when `useFetch` is false");
744
+ })(typeof jQuery !== "undefined");
745
+ jQuery.ajax(options);
746
+ }
747
+ /**
748
+ @private
749
+ */
750
+ _fetchRequest(options) {
751
+ return getFetchFunction()(options.url, options);
752
+ }
753
+ /**
754
+ @private
755
+ */
756
+ _ajax(options) {
757
+ if (this.useFetch) this._fetchRequest(options);
758
+ else this._ajaxRequest(options);
759
+ }
760
+ /**
761
+ @private
762
+ */
763
+ ajaxOptions(url, method, options) {
764
+ let reqOptions = Object.assign({
765
+ url,
766
+ method,
767
+ type: method
768
+ }, options);
769
+ if (this.headers !== void 0) reqOptions.headers = {
770
+ ...this.headers,
771
+ ...reqOptions.headers
772
+ };
773
+ else if (!options.headers) reqOptions.headers = {};
774
+ const contentType = reqOptions.contentType || this._defaultContentType;
775
+ if (this.useFetch) {
776
+ if (reqOptions.data && reqOptions.type !== "GET" && reqOptions.headers) {
777
+ if (!reqOptions.headers["Content-Type"] && !reqOptions.headers["content-type"]) reqOptions.headers["content-type"] = contentType;
778
+ }
779
+ reqOptions = fetchOptions(reqOptions, this);
780
+ } else {
781
+ if (reqOptions.data && reqOptions.type !== "GET") reqOptions = {
782
+ ...reqOptions,
783
+ contentType
784
+ };
785
+ reqOptions = ajaxOptions(reqOptions, this);
786
+ }
787
+ reqOptions.url = this._ajaxURL(reqOptions.url);
788
+ return reqOptions;
789
+ }
790
+ /**
791
+ * @private
792
+ */
793
+ _ajaxURL(url) {
794
+ if (this.fastboot?.isFastBoot) {
795
+ const httpRegex = /^https?:\/\//;
796
+ const protocolRelativeRegex = /^\/\//;
797
+ const protocol = this.fastboot.request.protocol;
798
+ const host = this.fastboot.request.host;
799
+ if (protocolRelativeRegex.test(url)) return `${protocol}${url}`;
800
+ else if (!httpRegex.test(url)) try {
801
+ return `${protocol}//${host}${url}`;
802
+ } catch (fbError) {
803
+ throw new Error("You are using WarpDrive with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: " + fbError.message, { cause: fbError });
804
+ }
805
+ }
806
+ return url;
807
+ }
808
+ /**
809
+ @private
810
+ */
811
+ parseErrorResponse(responseText) {
812
+ let json = responseText;
813
+ try {
814
+ json = JSON.parse(responseText);
815
+ } catch {}
816
+ return json;
817
+ }
818
+ /**
819
+ @private
820
+ @return errors payload
821
+ */
822
+ normalizeErrorResponse(status, _headers, payload) {
823
+ if (payload && typeof payload === "object" && "errors" in payload && Array.isArray(payload.errors)) return payload.errors;
824
+ else return [{
825
+ status: `${status}`,
826
+ title: "The backend responded with an error",
827
+ detail: typeof payload === "string" ? payload : JSON.stringify(payload)
828
+ }];
829
+ }
830
+ /**
831
+ Generates a detailed ("friendly") error message, with plenty
832
+ of information for debugging (good luck!)
833
+ @private
834
+ @return detailed error message
835
+ */
836
+ generatedDetailedMessage(status, headers, payload, requestData) {
837
+ let shortenedPayload;
838
+ const payloadContentType = headers["content-type"] || "Empty Content-Type";
839
+ if (payloadContentType === "text/html" && typeof payload === "string" && payload.length > 250) shortenedPayload = "[Omitted Lengthy HTML]";
840
+ else if (typeof payload === "object" && payload !== null) shortenedPayload = JSON.stringify(payload, null, 2);
841
+ else shortenedPayload = payload;
842
+ const requestDescription = requestData.method + " " + requestData.url;
843
+ const payloadDescription = "Payload (" + payloadContentType + ")";
844
+ return [
845
+ "Ember Data Request " + requestDescription + " returned a " + status,
846
+ payloadDescription,
847
+ shortenedPayload
848
+ ].join("\n");
849
+ }
850
+ /**
851
+ Used by `findAll` and `findRecord` to build the query's `data` hash
852
+ supplied to the ajax method.
853
+ @since 2.5.0
854
+ @public
855
+ */
856
+ buildQuery(snapshot) {
857
+ const query = {};
858
+ if (snapshot) {
859
+ const { include } = snapshot;
860
+ if (include) query.include = include;
861
+ }
862
+ return query;
863
+ }
864
+ };
969
865
  function ajaxSuccess(adapter, payload, requestData, responseData) {
970
- let response;
971
- try {
972
- response = adapter.handleResponse(responseData.status, responseData.headers, payload, requestData);
973
- } catch (error) {
974
- // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
975
- return Promise.reject(error);
976
- }
977
- if (response && response.isAdapterError) {
978
- // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
979
- return Promise.reject(response);
980
- } else {
981
- return response;
982
- }
866
+ let response;
867
+ try {
868
+ response = adapter.handleResponse(responseData.status, responseData.headers, payload, requestData);
869
+ } catch (error) {
870
+ return Promise.reject(error);
871
+ }
872
+ if (response && response.isAdapterError) return Promise.reject(response);
873
+ else return response;
983
874
  }
984
875
  function ajaxError(adapter, payload, requestData, responseData) {
985
- let error;
986
- if (responseData.errorThrown instanceof Error && payload !== '') {
987
- error = responseData.errorThrown;
988
- } else if (responseData.textStatus === 'timeout') {
989
- error = new TimeoutError();
990
- } else if (responseData.textStatus === 'abort' || responseData.status === 0) {
991
- error = handleAbort(requestData, responseData);
992
- } else {
993
- try {
994
- error = adapter.handleResponse(responseData.status, responseData.headers, payload || responseData.errorThrown, requestData);
995
- } catch (e) {
996
- error = e;
997
- }
998
- }
999
- return error;
876
+ let error;
877
+ if (responseData.errorThrown instanceof Error && payload !== "") error = responseData.errorThrown;
878
+ else if (responseData.textStatus === "timeout") error = new TimeoutError();
879
+ else if (responseData.textStatus === "abort" || responseData.status === 0) error = handleAbort(requestData, responseData);
880
+ else try {
881
+ error = adapter.handleResponse(responseData.status, responseData.headers, payload || responseData.errorThrown, requestData);
882
+ } catch (e) {
883
+ error = e;
884
+ }
885
+ return error;
1000
886
  }
1001
-
1002
- // Adapter abort error to include any relevent info, e.g. request/response:
1003
887
  function handleAbort(requestData, responseData) {
1004
- const {
1005
- method,
1006
- url,
1007
- errorThrown
1008
- } = requestData;
1009
- const {
1010
- status
1011
- } = responseData;
1012
- const msg = `Request failed: ${method} ${url} ${String(errorThrown ?? '')}`;
1013
- const errors = [{
1014
- title: 'Adapter Error',
1015
- detail: msg.trim(),
1016
- status
1017
- }];
1018
- return new AbortError(errors);
888
+ const { method, url, errorThrown } = requestData;
889
+ const { status } = responseData;
890
+ const errors = [{
891
+ title: "Adapter Error",
892
+ detail: `Request failed: ${method} ${url} ${String(errorThrown ?? "")}`.trim(),
893
+ status
894
+ }];
895
+ return new AbortError(errors);
1019
896
  }
1020
-
1021
- //From http://stackoverflow.com/questions/280634/endswith-in-javascript
1022
897
  function endsWith(string, suffix) {
1023
- if (typeof String.prototype.endsWith !== 'function') {
1024
- return string.includes(suffix, string.length - suffix.length);
1025
- } else {
1026
- return string.endsWith(suffix);
1027
- }
898
+ if (typeof String.prototype.endsWith !== "function") return string.includes(suffix, string.length - suffix.length);
899
+ else return string.endsWith(suffix);
1028
900
  }
1029
901
  function fetchSuccessHandler(adapter, payload, response, requestData) {
1030
- const responseData = fetchResponseData(response);
1031
- return ajaxSuccess(adapter, payload, requestData, responseData);
902
+ return ajaxSuccess(adapter, payload, requestData, fetchResponseData(response));
1032
903
  }
1033
904
  function fetchErrorHandler(adapter, payload, response, errorThrown, requestData) {
1034
- const responseData = fetchResponseData(response);
1035
- if (responseData.status === 200 && payload instanceof Error) {
1036
- responseData.errorThrown = payload;
1037
- // @ts-expect-error poorly typed
1038
- payload = responseData.errorThrown.payload;
1039
- } else {
1040
- responseData.errorThrown = errorThrown;
1041
- if (typeof payload === 'string') {
1042
- payload = adapter.parseErrorResponse(payload);
1043
- }
1044
- }
1045
- return ajaxError(adapter, payload, requestData, responseData);
905
+ const responseData = fetchResponseData(response);
906
+ if (responseData.status === 200 && payload instanceof Error) {
907
+ responseData.errorThrown = payload;
908
+ payload = responseData.errorThrown.payload;
909
+ } else {
910
+ responseData.errorThrown = errorThrown;
911
+ if (typeof payload === "string") payload = adapter.parseErrorResponse(payload);
912
+ }
913
+ return ajaxError(adapter, payload, requestData, responseData);
1046
914
  }
1047
915
  function ajaxSuccessHandler(adapter, payload, jqXHR, requestData) {
1048
- const responseData = ajaxResponseData(jqXHR);
1049
- return ajaxSuccess(adapter, payload, requestData, responseData);
916
+ return ajaxSuccess(adapter, payload, requestData, ajaxResponseData(jqXHR));
1050
917
  }
1051
918
  function ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData) {
1052
- const responseData = ajaxResponseData(jqXHR);
1053
- responseData.errorThrown = errorThrown;
1054
- const payload = adapter.parseErrorResponse(jqXHR.responseText);
1055
- if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
1056
- const message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`;
1057
- const validJSONString = !(responseData.textStatus === 'parsererror' && payload === '');
1058
- warn(message, validJSONString, {
1059
- id: 'ds.adapter.returned-empty-string-as-JSON'
1060
- });
1061
- }
1062
- return ajaxError(adapter, payload, requestData, responseData);
919
+ const responseData = ajaxResponseData(jqXHR);
920
+ responseData.errorThrown = errorThrown;
921
+ const payload = adapter.parseErrorResponse(jqXHR.responseText);
922
+ if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
923
+ const message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`;
924
+ const validJSONString = !(responseData.textStatus === "parsererror" && payload === "");
925
+ warn(message, validJSONString, { id: "ds.adapter.returned-empty-string-as-JSON" });
926
+ }
927
+ return ajaxError(adapter, payload, requestData, responseData);
1063
928
  }
1064
929
  function fetchResponseData(response) {
1065
- return {
1066
- status: response.status,
1067
- textStatus: response.statusText,
1068
- headers: headersToObject(response.headers)
1069
- };
930
+ return {
931
+ status: response.status,
932
+ textStatus: response.statusText,
933
+ headers: headersToObject(response.headers)
934
+ };
1070
935
  }
1071
936
  function ajaxResponseData(jqXHR) {
1072
- return {
1073
- status: jqXHR.status,
1074
- textStatus: jqXHR.statusText,
1075
- headers: parseResponseHeaders(jqXHR.getAllResponseHeaders())
1076
- };
937
+ return {
938
+ status: jqXHR.status,
939
+ textStatus: jqXHR.statusText,
940
+ headers: parseResponseHeaders(jqXHR.getAllResponseHeaders())
941
+ };
1077
942
  }
1078
943
  function headersToObject(headers) {
1079
- const headersObject = {};
1080
- if (headers) {
1081
- headers.forEach((value, key) => headersObject[key] = value);
1082
- }
1083
- return headersObject;
944
+ const headersObject = {};
945
+ if (headers) headers.forEach((value, key) => headersObject[key] = value);
946
+ return headersObject;
1084
947
  }
1085
-
1086
948
  /**
1087
- * Helper function that translates the options passed to `jQuery.ajax` into a format that `fetch` expects.
1088
- *
1089
- * @private
1090
- */
949
+ * Helper function that translates the options passed to `jQuery.ajax` into a format that `fetch` expects.
950
+ *
951
+ * @private
952
+ */
1091
953
  function fetchOptions(options, adapter) {
1092
- options.credentials = options.credentials || 'same-origin';
1093
- if (options.data) {
1094
- // GET and HEAD requests can't have a `body`
1095
- if (options.method === 'GET' || options.method === 'HEAD') {
1096
- // If no options are passed, WarpDrive sets `data` to an empty object, which we test for.
1097
- if (Object.keys(options.data).length && options.url) {
1098
- // Test if there are already query params in the url (mimics jQuey.ajax).
1099
- const queryParamDelimiter = options.url.includes('?') ? '&' : '?';
1100
- options.url += `${queryParamDelimiter}${serializeQueryParams(options.data)}`;
1101
- }
1102
- } else {
1103
- // NOTE: a request's body cannot be an object, so we stringify it if it is.
1104
- // JSON.stringify removes keys with values of `undefined` (mimics jQuery.ajax).
1105
- // If the data is not a POJO (it's a String, FormData, etc), we just set it.
1106
- // If the data is a string, we assume it's a stringified object.
1107
-
1108
- /* We check for Objects this way because we want the logic inside the consequent to run
1109
- * if `options.data` is a POJO, not if it is a data structure whose `typeof` returns "object"
1110
- * when it's not (Array, FormData, etc). The reason we don't use `options.data.constructor`
1111
- * to check is in case `data` is an object with no prototype (e.g. created with null).
1112
- */
1113
- if (Object.prototype.toString.call(options.data) === '[object Object]') {
1114
- options.body = JSON.stringify(options.data);
1115
- } else {
1116
- // @ts-expect-error poorly typed
1117
- options.body = options.data;
1118
- }
1119
- }
1120
- }
1121
- return options;
954
+ options.credentials = options.credentials || "same-origin";
955
+ if (options.data) {
956
+ if (options.method === "GET" || options.method === "HEAD") {
957
+ if (Object.keys(options.data).length && options.url) {
958
+ const queryParamDelimiter = options.url.includes("?") ? "&" : "?";
959
+ options.url += `${queryParamDelimiter}${serializeQueryParams(options.data)}`;
960
+ }
961
+ } else if (Object.prototype.toString.call(options.data) === "[object Object]") options.body = JSON.stringify(options.data);
962
+ else options.body = options.data;
963
+ }
964
+ return options;
1122
965
  }
1123
966
  function ajaxOptions(options, adapter) {
1124
- options.dataType = 'json';
1125
- options.context = adapter;
1126
- if (options.data && options.type !== 'GET') {
1127
- options.data = JSON.stringify(options.data);
1128
- }
1129
- options.beforeSend = function (xhr) {
1130
- if (options.headers) {
1131
- Object.keys(options.headers).forEach(key => {
1132
- const headerValue = options.headers && options.headers[key];
1133
- const isString = value => typeof value === 'string';
1134
- if (isString(headerValue)) {
1135
- xhr.setRequestHeader(key, headerValue);
1136
- }
1137
- });
1138
- }
1139
- };
1140
- return options;
967
+ options.dataType = "json";
968
+ options.context = adapter;
969
+ if (options.data && options.type !== "GET") options.data = JSON.stringify(options.data);
970
+ options.beforeSend = function(xhr) {
971
+ if (options.headers) Object.keys(options.headers).forEach((key) => {
972
+ const headerValue = options.headers && options.headers[key];
973
+ const isString = (value) => typeof value === "string";
974
+ if (isString(headerValue)) xhr.setRequestHeader(key, headerValue);
975
+ });
976
+ };
977
+ return options;
1141
978
  }
1142
979
  function execjQAjax(adapter, requestData, options) {
1143
- const hash = adapter.ajaxOptions(requestData.url, requestData.method, options);
1144
- return new Promise((resolve, reject) => {
1145
- hash.success = function (payload, textStatus, jqXHR) {
1146
- const response = ajaxSuccessHandler(adapter, payload, jqXHR, requestData);
1147
- resolve(response);
1148
- };
1149
- hash.error = function (jqXHR, textStatus, errorThrown) {
1150
- const error = ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData);
1151
- // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
1152
- reject(error);
1153
- };
1154
- adapter._ajax(hash);
1155
- });
980
+ const hash = adapter.ajaxOptions(requestData.url, requestData.method, options);
981
+ return new Promise((resolve, reject) => {
982
+ hash.success = function(payload, textStatus, jqXHR) {
983
+ resolve(ajaxSuccessHandler(adapter, payload, jqXHR, requestData));
984
+ };
985
+ hash.error = function(jqXHR, textStatus, errorThrown) {
986
+ reject(ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData));
987
+ };
988
+ adapter._ajax(hash);
989
+ });
1156
990
  }
1157
991
  function splitGroupToFitInUrl(store, adapter, group, maxURLLength, paramNameLength) {
1158
- let idsSize = 0;
1159
- const baseUrl = adapter._stripIDFromURL(store, group[0]);
1160
- const splitGroups = [[]];
1161
- group.forEach(snapshot => {
1162
- const additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength;
1163
- if (baseUrl.length + idsSize + additionalLength >= maxURLLength) {
1164
- idsSize = 0;
1165
- splitGroups.push([]);
1166
- }
1167
- idsSize += additionalLength;
1168
- const lastGroupIndex = splitGroups.length - 1;
1169
- splitGroups[lastGroupIndex].push(snapshot);
1170
- });
1171
- return splitGroups;
992
+ let idsSize = 0;
993
+ const baseUrl = adapter._stripIDFromURL(store, group[0]);
994
+ const splitGroups = [[]];
995
+ group.forEach((snapshot) => {
996
+ const additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength;
997
+ if (baseUrl.length + idsSize + additionalLength >= maxURLLength) {
998
+ idsSize = 0;
999
+ splitGroups.push([]);
1000
+ }
1001
+ idsSize += additionalLength;
1002
+ const lastGroupIndex = splitGroups.length - 1;
1003
+ splitGroups[lastGroupIndex].push(snapshot);
1004
+ });
1005
+ return splitGroups;
1172
1006
  }
1173
- export { RESTAdapter, fetchOptions };
1007
+
1008
+ //#endregion
1009
+ export { RESTAdapter, fetchOptions };
1010
+ //# sourceMappingURL=rest.js.map