@warp-drive/legacy 5.9.0-alpha.2 → 5.9.0-alpha.21

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 (162) hide show
  1. package/README.md +6 -0
  2. package/declarations/adapter/-private/build-url-mixin.d.ts +156 -0
  3. package/declarations/adapter/error.d.ts +385 -169
  4. package/declarations/adapter/json-api.d.ts +12 -1
  5. package/declarations/adapter/rest.d.ts +74 -0
  6. package/declarations/adapter.d.ts +6 -0
  7. package/declarations/compat/builders/find-all.d.ts +0 -1
  8. package/declarations/compat/extensions.d.ts +40 -0
  9. package/declarations/compat/legacy-network-handler/legacy-network-handler.d.ts +7 -0
  10. package/declarations/compat/legacy-network-handler/minimum-adapter-interface.d.ts +4 -0
  11. package/declarations/compat/legacy-network-handler/minimum-serializer-interface.d.ts +7 -0
  12. package/declarations/compat/utils.d.ts +11 -0
  13. package/declarations/compat.d.ts +32 -0
  14. package/declarations/index.d.ts +142 -0
  15. package/declarations/model/-private/attr.d.ts +21 -0
  16. package/declarations/model/-private/belongs-to.d.ts +21 -0
  17. package/declarations/model/-private/hooks.d.ts +26 -0
  18. package/declarations/model/-private/model.d.ts +55 -4
  19. package/declarations/model/-private/promise-many-array.d.ts +25 -1
  20. package/declarations/model/-private/schema-provider.d.ts +11 -1
  21. package/declarations/model/migration-support.d.ts +31 -5
  22. package/declarations/model-fragments/extensions/fragment-array.d.ts +38 -0
  23. package/declarations/model-fragments/extensions/fragment.d.ts +35 -0
  24. package/declarations/model-fragments/hooks/model-for.d.ts +7 -0
  25. package/declarations/model-fragments/index.d.ts +8 -0
  26. package/declarations/model-fragments/instance-initializers/fragment-extensions.d.ts +6 -0
  27. package/declarations/model-fragments/utilities/with-array-defaults.d.ts +30 -0
  28. package/declarations/model-fragments/utilities/with-fragment-array-defaults.d.ts +18 -0
  29. package/declarations/model-fragments/utilities/with-fragment-defaults.d.ts +15 -0
  30. package/declarations/model-fragments/utilities/with-legacy.d.ts +8 -0
  31. package/declarations/serializer/-private/transforms/boolean.d.ts +13 -0
  32. package/declarations/serializer/-private/transforms/date.d.ts +15 -1
  33. package/declarations/serializer/-private/transforms/number.d.ts +14 -1
  34. package/declarations/serializer/-private/transforms/string.d.ts +14 -1
  35. package/declarations/serializer/-private/utils.d.ts +24 -0
  36. package/declarations/serializer/json-api.d.ts +1 -1
  37. package/declarations/serializer.d.ts +4 -6
  38. package/declarations/store/-private.d.ts +2 -2
  39. package/declarations/store.d.ts +7 -0
  40. package/dist/adapter/error.js +386 -241
  41. package/dist/adapter/json-api.js +12 -0
  42. package/dist/adapter/rest.js +39 -3
  43. package/dist/adapter.js +23 -26
  44. package/dist/compat/builders.js +0 -1
  45. package/dist/compat/extensions.js +80 -3
  46. package/dist/compat/utils.js +14 -0
  47. package/dist/compat.js +17 -0
  48. package/dist/{errors-Cz5KrzBk.js → errors-DZKA206g.js} +24 -1
  49. package/dist/{hooks-D6diaM34.js → hooks-BvOqJBei.js} +33 -2
  50. package/dist/index.js +168 -13
  51. package/dist/{json-ChdEfB0X.js → json-DU8m1pGf.js} +83 -6
  52. package/dist/model/-private.js +1 -1
  53. package/dist/model/migration-support.js +15 -2
  54. package/dist/{unpkg/dev-deprecated/model-for-CqXsIKws.js → model-for-CXkJw59V.js} +77 -1
  55. package/dist/model-fragments.js +18 -2
  56. package/dist/model.js +12 -8
  57. package/dist/{schema-provider-DJCV_6AF.js → schema-provider-DtPOp0d7.js} +93 -6
  58. package/dist/serializer/json-api.js +8 -3
  59. package/dist/serializer/json.js +1 -1
  60. package/dist/serializer/rest.js +3 -4
  61. package/dist/serializer/transform.js +51 -3
  62. package/dist/serializer.js +4 -7
  63. package/dist/store.js +13 -7
  64. package/dist/unpkg/dev/adapter/error.js +386 -241
  65. package/dist/unpkg/dev/adapter/json-api.js +13 -1
  66. package/dist/unpkg/dev/adapter/rest.js +39 -3
  67. package/dist/unpkg/dev/adapter.js +23 -26
  68. package/dist/unpkg/dev/compat/builders.js +0 -1
  69. package/dist/unpkg/dev/compat/extensions.js +80 -3
  70. package/dist/unpkg/dev/compat/utils.js +14 -0
  71. package/dist/unpkg/dev/compat.js +34 -1
  72. package/dist/unpkg/dev/{errors-DmGGJr3T.js → errors-DngRU-If.js} +24 -1
  73. package/dist/unpkg/dev/{hooks-CkYiE6Ud.js → hooks-UuiLxWxS.js} +33 -2
  74. package/dist/unpkg/dev/index.js +171 -13
  75. package/dist/unpkg/dev/json-K2Y9z6MN.js +1333 -0
  76. package/dist/unpkg/dev/model/-private.js +1 -1
  77. package/dist/unpkg/dev/model/migration-support.js +16 -2
  78. package/dist/unpkg/{prod-deprecated/model-for-CqXsIKws.js → dev/model-for-CXkJw59V.js} +77 -1
  79. package/dist/unpkg/dev/model-fragments.js +18 -2
  80. package/dist/unpkg/dev/model.js +12 -8
  81. package/dist/unpkg/dev/{schema-provider-DDVYxmUV.js → schema-provider-0D7f-QOn.js} +92 -6
  82. package/dist/unpkg/dev/serializer/json-api.js +9 -4
  83. package/dist/unpkg/dev/serializer/json.js +1 -1
  84. package/dist/unpkg/dev/serializer/rest.js +3 -4
  85. package/dist/unpkg/dev/serializer/transform.js +51 -3
  86. package/dist/unpkg/dev/serializer.js +4 -7
  87. package/dist/unpkg/dev/store.js +21 -7
  88. package/dist/unpkg/dev-deprecated/adapter/error.js +386 -241
  89. package/dist/unpkg/dev-deprecated/adapter/json-api.js +13 -1
  90. package/dist/unpkg/dev-deprecated/adapter/rest.js +39 -3
  91. package/dist/unpkg/dev-deprecated/adapter.js +23 -26
  92. package/dist/unpkg/dev-deprecated/compat/builders.js +0 -1
  93. package/dist/unpkg/dev-deprecated/compat/extensions.js +80 -3
  94. package/dist/unpkg/dev-deprecated/compat/utils.js +14 -0
  95. package/dist/unpkg/dev-deprecated/compat.js +34 -1
  96. package/dist/unpkg/dev-deprecated/{errors-Spt6ubMd.js → errors-Bzidntpi.js} +24 -1
  97. package/dist/unpkg/dev-deprecated/{hooks-DOXegvhL.js → hooks-DVXhMW14.js} +33 -2
  98. package/dist/unpkg/dev-deprecated/index.js +171 -13
  99. package/dist/unpkg/{prod-deprecated/json-BWrZ5546.js → dev-deprecated/json-K2Y9z6MN.js} +96 -6
  100. package/dist/unpkg/dev-deprecated/model/-private.js +1 -1
  101. package/dist/unpkg/dev-deprecated/model/migration-support.js +16 -2
  102. package/dist/unpkg/{dev/model-for-CqXsIKws.js → dev-deprecated/model-for-CXkJw59V.js} +77 -1
  103. package/dist/unpkg/dev-deprecated/model-fragments.js +18 -2
  104. package/dist/unpkg/dev-deprecated/model.js +12 -8
  105. package/dist/unpkg/dev-deprecated/{schema-provider-BP6_8N-V.js → schema-provider-ZwO5_fZw.js} +84 -3
  106. package/dist/unpkg/dev-deprecated/serializer/json-api.js +9 -4
  107. package/dist/unpkg/dev-deprecated/serializer/json.js +1 -1
  108. package/dist/unpkg/dev-deprecated/serializer/rest.js +3 -4
  109. package/dist/unpkg/dev-deprecated/serializer/transform.js +51 -3
  110. package/dist/unpkg/dev-deprecated/serializer.js +4 -7
  111. package/dist/unpkg/dev-deprecated/store.js +21 -7
  112. package/dist/unpkg/prod/adapter/error.js +386 -241
  113. package/dist/unpkg/prod/adapter/json-api.js +13 -1
  114. package/dist/unpkg/prod/adapter/rest.js +39 -3
  115. package/dist/unpkg/prod/adapter.js +23 -26
  116. package/dist/unpkg/prod/compat/builders.js +0 -1
  117. package/dist/unpkg/prod/compat/extensions.js +70 -3
  118. package/dist/unpkg/prod/compat/utils.js +14 -0
  119. package/dist/unpkg/prod/compat.js +17 -0
  120. package/dist/unpkg/prod/{errors-BGVFCBmi.js → errors-B-PWeYlW.js} +24 -1
  121. package/dist/unpkg/prod/{hooks-BztVA_x0.js → hooks-Bx-zBziU.js} +32 -1
  122. package/dist/unpkg/prod/index.js +171 -5
  123. package/dist/unpkg/{dev/json-Cu1LNgmQ.js → prod/json-Qewu-UN9.js} +63 -19
  124. package/dist/unpkg/prod/model/-private.js +1 -1
  125. package/dist/unpkg/prod/model/migration-support.js +16 -2
  126. package/dist/unpkg/prod/model-for-CXkJw59V.js +297 -0
  127. package/dist/unpkg/prod/model-fragments.js +18 -2
  128. package/dist/unpkg/prod/model.js +12 -8
  129. package/dist/unpkg/prod/{schema-provider-DJtD_8jZ.js → schema-provider-BgRqk8i9.js} +96 -6
  130. package/dist/unpkg/prod/serializer/json-api.js +9 -4
  131. package/dist/unpkg/prod/serializer/json.js +1 -1
  132. package/dist/unpkg/prod/serializer/rest.js +3 -4
  133. package/dist/unpkg/prod/serializer/transform.js +51 -3
  134. package/dist/unpkg/prod/serializer.js +4 -7
  135. package/dist/unpkg/prod/store.js +21 -7
  136. package/dist/unpkg/prod-deprecated/adapter/error.js +386 -241
  137. package/dist/unpkg/prod-deprecated/adapter/json-api.js +13 -1
  138. package/dist/unpkg/prod-deprecated/adapter/rest.js +39 -3
  139. package/dist/unpkg/prod-deprecated/adapter.js +23 -26
  140. package/dist/unpkg/prod-deprecated/compat/builders.js +0 -1
  141. package/dist/unpkg/prod-deprecated/compat/extensions.js +70 -3
  142. package/dist/unpkg/prod-deprecated/compat/utils.js +14 -0
  143. package/dist/unpkg/prod-deprecated/compat.js +17 -0
  144. package/dist/unpkg/prod-deprecated/{errors-CdDaK81x.js → errors-Dl2J9d1D.js} +24 -1
  145. package/dist/unpkg/prod-deprecated/{hooks-yId87yyG.js → hooks-Cm60wWTf.js} +32 -1
  146. package/dist/unpkg/prod-deprecated/index.js +171 -5
  147. package/dist/unpkg/{dev-deprecated/json-Cu1LNgmQ.js → prod-deprecated/json-Qewu-UN9.js} +63 -19
  148. package/dist/unpkg/prod-deprecated/model/-private.js +1 -1
  149. package/dist/unpkg/prod-deprecated/model/migration-support.js +16 -2
  150. package/dist/{model-for-CqXsIKws.js → unpkg/prod-deprecated/model-for-CXkJw59V.js} +77 -1
  151. package/dist/unpkg/prod-deprecated/model-fragments.js +18 -2
  152. package/dist/unpkg/prod-deprecated/model.js +12 -8
  153. package/dist/unpkg/prod-deprecated/{schema-provider-CjX55uSY.js → schema-provider-Dh6tRqVI.js} +79 -3
  154. package/dist/unpkg/prod-deprecated/serializer/json-api.js +9 -4
  155. package/dist/unpkg/prod-deprecated/serializer/json.js +1 -1
  156. package/dist/unpkg/prod-deprecated/serializer/rest.js +3 -4
  157. package/dist/unpkg/prod-deprecated/serializer/transform.js +51 -3
  158. package/dist/unpkg/prod-deprecated/serializer.js +4 -7
  159. package/dist/unpkg/prod-deprecated/store.js +21 -7
  160. package/package.json +8 -8
  161. package/dist/unpkg/prod/json-BWrZ5546.js +0 -1243
  162. package/dist/unpkg/prod/model-for-CqXsIKws.js +0 -221
@@ -7,11 +7,11 @@ import '@ember/object';
7
7
  import '@warp-drive/core/types/symbols';
8
8
  import '@warp-drive/utilities/string';
9
9
  import '@warp-drive/core/store/-private';
10
- import "./errors-Spt6ubMd.js";
11
- import "./schema-provider-BP6_8N-V.js";
12
- import { i as instantiateRecord, t as teardownRecord, m as modelFor } from "./hooks-DOXegvhL.js";
10
+ import "./errors-Bzidntpi.js";
11
+ import "./schema-provider-ZwO5_fZw.js";
12
+ import { i as instantiateRecord, t as teardownRecord, m as modelFor } from "./hooks-DVXhMW14.js";
13
13
  import { registerDerivations as registerDerivations$1, DelegatingSchemaService } from './model/migration-support.js';
14
- import { F as FragmentExtension, a as FragmentArrayExtension, f as fragmentsModelFor } from "./model-for-CqXsIKws.js";
14
+ import { F as FragmentExtension, a as FragmentArrayExtension, f as fragmentsModelFor } from "./model-for-CXkJw59V.js";
15
15
  import { restoreDeprecatedStoreBehaviors } from './store.js';
16
16
 
17
17
  /**
@@ -19,10 +19,153 @@ import { restoreDeprecatedStoreBehaviors } from './store.js';
19
19
  * @mergeModuleWith <project>
20
20
  */
21
21
 
22
+ /**
23
+ * Setup options for a legacy store configured to use `Model` with `linksMode`
24
+ * enabled, meaning no legacy adapter/serializer request infrastructure is required.
25
+ *
26
+ * @public
27
+ */
28
+
29
+ /**
30
+ * Setup options for a legacy store configured to use `Model` along with the
31
+ * legacy adapter/serializer network layer, but without the deprecated
32
+ * `store.findRecord`/`findAll`/`query`/etc. request methods.
33
+ *
34
+ * @public
35
+ */
36
+
37
+ /**
38
+ * Setup options for a legacy store configured to use `Model` along with the
39
+ * legacy adapter/serializer network layer and the deprecated
40
+ * `store.findRecord`/`findAll`/`query`/etc. request methods.
41
+ *
42
+ * @public
43
+ */
44
+
22
45
  //export type ConfiguredStore<T = unknown> = typeof Store;
23
46
 
47
+ /**
48
+ * The available options when setting up the legacy store,
49
+ * one of:
50
+ *
51
+ * - {@link LegacyModelStoreSetupOptions}
52
+ * - {@link LegacyModelAndNetworkStoreSetupOptions}
53
+ * - {@link LegacyModelAndNetworkAndRequestStoreSetupOptions}
54
+ */
55
+
24
56
  /**
25
57
  * Use the legacy store with the given options.
58
+ *
59
+ * See {@link LegacyStoreSetupOptions} for details on the available options.
60
+ *
61
+ * ```ts
62
+ * import { useLegacyStore } from '@warp-drive/legacy';
63
+ * import { JSONAPICache } from '@warp-drive/json-api';
64
+ *
65
+ * export default useLegacyStore({
66
+ * linksMode: false,
67
+ * legacyRequests: true,
68
+ * cache: JSONAPICache,
69
+ * schemas: [],
70
+ * });
71
+ * ```
72
+ *
73
+ * ### Adding Stateful Handlers
74
+ *
75
+ * A request {@link Handler} is sometimes more than a plain object or class
76
+ * with a `request` method — it may need access to a stateful dependency such
77
+ * as an Ember service (an auth token, a feature-flags service, an i18n
78
+ * helper, etc.).
79
+ *
80
+ * A plain class handler that only relies on Ember's `@service` decorator will
81
+ * not work here on its own: the handler is never instantiated *through*
82
+ * Ember's container (it's just `new`'d up), so it has no owner and its
83
+ * `@service` injections would fail to resolve.
84
+ *
85
+ * Instead, give `handlers` a function. It receives the {@link Store} instance
86
+ * being configured, which by the time the function runs already has an owner
87
+ * assigned. Use `getOwner`/`setOwner` from `@ember/owner` to transfer that
88
+ * owner onto your handler instance before returning it, exactly as you would
89
+ * when constructing any other DI-aware object outside of the container:
90
+ *
91
+ * ```ts
92
+ * import { getOwner, setOwner } from '@ember/owner';
93
+ * import { service } from '@ember/service';
94
+ * import { useLegacyStore } from '@warp-drive/legacy';
95
+ * import type { NextFn } from '@warp-drive/core/request';
96
+ * import type { RequestContext } from '@warp-drive/core/types/request';
97
+ * import { JSONAPICache } from '@warp-drive/json-api';
98
+ *
99
+ * class AuthHandler {
100
+ * @service session;
101
+ *
102
+ * request<T>(context: RequestContext, next: NextFn<T>) {
103
+ * const headers = new Headers(context.request.headers);
104
+ * headers.append('Authorization', `Bearer ${this.session.accessToken}`);
105
+ * return next(Object.assign({}, context.request, { headers }));
106
+ * }
107
+ * }
108
+ *
109
+ * export default useLegacyStore({
110
+ * linksMode: false,
111
+ * legacyRequests: true,
112
+ * cache: JSONAPICache,
113
+ * handlers: (store) => {
114
+ * const authHandler = new AuthHandler();
115
+ * setOwner(authHandler, getOwner(store)!);
116
+ * return [authHandler];
117
+ * },
118
+ * });
119
+ * ```
120
+ *
121
+ * The `handlers` function is invoked lazily and only once per store instance,
122
+ * the first time `store.requestManager` is accessed, so it is safe to do
123
+ * owner-dependent setup like this inside of it.
124
+ *
125
+ * ### Accessing the Store from a Handler's Context
126
+ *
127
+ * If a handler only needs to read something *off of the store itself*
128
+ * (its cache, or a property/service you've attached to a custom store
129
+ * subclass) rather than an unrelated Ember service, there is a second,
130
+ * simpler option that requires no DI/`setOwner` wiring at all.
131
+ *
132
+ * Every request issued via {@link Store.request | store.request(...)}
133
+ * automatically carries the originating store along as
134
+ * {@link RequestInfo.store | context.request.store}. Any handler — a plain
135
+ * object, a function-built handler, or a class — can read it directly,
136
+ * without needing the `handlers` callback form shown above:
137
+ *
138
+ * ```ts
139
+ * import { useLegacyStore } from '@warp-drive/legacy';
140
+ * import type { NextFn } from '@warp-drive/core/request';
141
+ * import type { RequestContext } from '@warp-drive/core/types/request';
142
+ * import { JSONAPICache } from '@warp-drive/json-api';
143
+ *
144
+ * const LoggingHandler = {
145
+ * request<T>(context: RequestContext, next: NextFn<T>) {
146
+ * // only present when the request was made via `store.request(...)`
147
+ * const store = context.request.store;
148
+ * if (store) {
149
+ * console.log(`[${store.constructor.name}] ${context.request.url ?? ''}`);
150
+ * }
151
+ * return next(context.request);
152
+ * },
153
+ * };
154
+ *
155
+ * export default useLegacyStore({
156
+ * linksMode: false,
157
+ * legacyRequests: true,
158
+ * cache: JSONAPICache,
159
+ * handlers: [LoggingHandler],
160
+ * });
161
+ * ```
162
+ *
163
+ * The trade-off versus the `getOwner`/`setOwner` pattern above is that
164
+ * `context.request.store` is only populated for requests issued via
165
+ * `store.request(...)`; a request made directly against a
166
+ * {@link RequestManager} won't have it set unless the caller supplies it
167
+ * explicitly, so a handler relying on it should treat it as optional (as
168
+ * `LoggingHandler` does above).
26
169
  */
27
170
 
28
171
  function useLegacyStore(options, StoreKlass = Store) {
@@ -34,7 +177,30 @@ function useLegacyStore(options, StoreKlass = Store) {
34
177
  // we extend the store to ensure we don't leak our prototype overrides to other stores below.
35
178
  class BaseKlass extends StoreKlass {}
36
179
  class LegacyConfiguredStore extends BaseKlass {
37
- requestManager = new RequestManager().use([options.linksMode ? null : LegacyNetworkHandler, ...(options.handlers ?? []), Fetch].filter(Boolean)).useCache(CacheHandler);
180
+ constructor(createArgs) {
181
+ super(createArgs);
182
+ // installed via defineProperty (rather than a class field/accessor) so that
183
+ // this lazy override of the inherited `requestManager` field does not
184
+ // conflict with the documented pattern of assigning it directly on
185
+ // consumer-authored Store subclasses. The setter preserves the ability
186
+ // to replace `requestManager` outright after construction.
187
+ let requestManager;
188
+ Object.defineProperty(this, 'requestManager', {
189
+ configurable: true,
190
+ enumerable: true,
191
+ get: () => {
192
+ if (!requestManager) {
193
+ const handlersOption = options.handlers;
194
+ const handlers = typeof handlersOption === 'function' ? handlersOption(this) : handlersOption ?? [];
195
+ requestManager = new RequestManager().use([options.linksMode ? null : LegacyNetworkHandler, ...handlers, Fetch].filter(Boolean)).useCache(CacheHandler);
196
+ }
197
+ return requestManager;
198
+ },
199
+ set: value => {
200
+ requestManager = value;
201
+ }
202
+ });
203
+ }
38
204
  lifetimes = options.policy ?? new DefaultCachePolicy({
39
205
  apiCacheHardExpires: 15 * 60 * 1000,
40
206
  // 15 minutes
@@ -114,14 +280,6 @@ function useLegacyStore(options, StoreKlass = Store) {
114
280
  }
115
281
  modelFor(type) {
116
282
  assertType(this.schema, type);
117
- // TODO I'm not sure this is right
118
- (test => {
119
- if (!test) {
120
- throw new Error(`modelFor should only be used to lookup legacy models when in linksMode: false`);
121
- }
122
- })(!options.linksMode || !this.schema.isDelegated({
123
- type
124
- }));
125
283
  const klass =
126
284
  // prefer real models if present
127
285
  modelFor.call(this, type) || (
@@ -13,6 +13,78 @@ function coerceId(id) {
13
13
  }
14
14
  }
15
15
 
16
+ /**
17
+ Given the name of a relationship on a resource `type`, determines the
18
+ inverse relationship field (if any) using only the schema service.
19
+
20
+ Unlike `Model.inverseFor`, this does not require `type` to be backed by
21
+ a `Model` class, so it works for both `Model`-based and schema-only
22
+ (e.g. `withDefaults` migration-support) resources.
23
+
24
+ @private
25
+ */
26
+ function inverseForRelationship(store, type, name) {
27
+ const relationship = store.schema.fields({
28
+ type
29
+ }).get(name);
30
+ (test => {
31
+ if (!test) {
32
+ throw new Error(`No relationship named '${name}' on '${type}' exists.`);
33
+ }
34
+ })(relationship);
35
+ const {
36
+ options
37
+ } = relationship;
38
+ (test => {
39
+ if (!test) {
40
+ throw new Error(`Expected the relationship ${name} on ${type} to define an inverse.`);
41
+ }
42
+ })(options.inverse === null || typeof options.inverse === 'string' && options.inverse.length > 0);
43
+ if (options.inverse === null) {
44
+ return null;
45
+ }
46
+ const schemaExists = store.schema.hasResource(relationship);
47
+ (test => {
48
+ if (!test) {
49
+ throw new Error(`No associated schema found for '${relationship.type}' while calculating the inverse of ${name} on ${type}`);
50
+ }
51
+ })(schemaExists);
52
+ if (!schemaExists) {
53
+ return null;
54
+ }
55
+ const inverseField = store.schema.fields(relationship).get(options.inverse);
56
+ (test => {
57
+ if (!test) {
58
+ throw new Error(`No inverse relationship found for '${name}' on '${type}'`);
59
+ }
60
+ })(inverseField && (inverseField.kind === 'belongsTo' || inverseField.kind === 'hasMany'));
61
+ return inverseField ?? null;
62
+ }
63
+
64
+ /**
65
+ Given a relationship field on a resource `type`, determines the
66
+ cardinality of the relationship using only the schema service.
67
+
68
+ Unlike `Model.determineRelationshipType`, this does not require `type`
69
+ to be backed by a `Model` class, so it works for both `Model`-based and
70
+ schema-only (e.g. `withDefaults` migration-support) resources.
71
+
72
+ @private
73
+ */
74
+ function determineRelationshipType(store, type, knownSide) {
75
+ const knownKind = knownSide.kind;
76
+ const inverse = inverseForRelationship(store, type, knownSide.name);
77
+ if (!inverse) {
78
+ return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone';
79
+ }
80
+ const otherKind = inverse.kind;
81
+ if (otherKind === 'belongsTo') {
82
+ return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne';
83
+ } else {
84
+ return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany';
85
+ }
86
+ }
87
+
16
88
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
17
89
  /* eslint-disable @typescript-eslint/no-unsafe-call */
18
90
  /* eslint-disable @typescript-eslint/no-unsafe-return */
@@ -381,6 +453,11 @@ const JSONSerializer = Serializer.extend({
381
453
  };
382
454
  const meta = this.extractMeta(store, primaryModelClass, payload);
383
455
  if (meta) {
456
+ (test => {
457
+ if (!test) {
458
+ throw new Error('The `meta` returned from `extractMeta` has to be an object, not "' + typeof meta + '".');
459
+ }
460
+ })(typeof meta === 'object');
384
461
  // @ts-expect-error untyped
385
462
  documentHash.meta = meta;
386
463
  }
@@ -686,6 +763,9 @@ const JSONSerializer = Serializer.extend({
686
763
  @private
687
764
  */
688
765
  _getMappedKey(key, modelClass) {
766
+ console.warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', modelClass.attributes.has(key) || modelClass.relationshipsByName.has(key), {
767
+ id: 'ds.serializer.no-mapped-attrs-key'
768
+ }); // @ts-expect-error attrs is dynamically injected
689
769
  const attrs = this.attrs;
690
770
  let mappedKey;
691
771
  if (attrs && attrs[key]) {
@@ -733,9 +813,7 @@ const JSONSerializer = Serializer.extend({
733
813
  */
734
814
  shouldSerializeHasMany(snapshot, key, relationship) {
735
815
  // @ts-expect-error store is dynamically injected
736
- const schema = this.store.modelFor(snapshot.modelName);
737
- // @ts-expect-error store is dynamically injected
738
- const relationshipType = schema.determineRelationshipType(relationship, this.store);
816
+ const relationshipType = determineRelationshipType(this.store, snapshot.modelName, relationship);
739
817
  if (this._mustSerialize(key)) {
740
818
  return true;
741
819
  }
@@ -774,8 +852,15 @@ const JSONSerializer = Serializer.extend({
774
852
  `serialize` takes an options hash with a single option:
775
853
  `includeId`. If this option is `true`, `serialize` will,
776
854
  by default include the ID in the JSON object it builds.
777
- The adapter passes in `includeId: true` when serializing
778
- a record for `createRecord`, but not for `updateRecord`.
855
+ Whether `includeId` is `true` or `false` depends on the
856
+ adapter and the operation being performed, since it is the
857
+ adapter that invokes `serialize` and decides which options
858
+ to pass. For instance, `RESTAdapter` passes `includeId: true`
859
+ when serializing a record for `createRecord`, but not for
860
+ `updateRecord`, while `JSONAPIAdapter` passes `includeId: true`
861
+ for both `createRecord` and `updateRecord`. Refer to the
862
+ documentation for the adapter and serializer pairing you are
863
+ using for specifics.
779
864
  ## Customization
780
865
  Your server may expect a different JSON format than the
781
866
  built-in serialization format.
@@ -1237,7 +1322,12 @@ const JSONSerializer = Serializer.extend({
1237
1322
  */
1238
1323
  transformFor(attributeType, skipAssertion) {
1239
1324
  const transform = getOwner(this).lookup(`transform:${attributeType}`);
1325
+ (test => {
1326
+ if (!test) {
1327
+ throw new Error(`Unable to find the transform for \`attr('${attributeType}')\``);
1328
+ }
1329
+ })(skipAssertion || !!transform);
1240
1330
  return transform;
1241
1331
  }
1242
1332
  });
1243
- export { JSONSerializer as J, coerceId as c };
1333
+ export { JSONSerializer as J, coerceId as c, inverseForRelationship as i };
@@ -1 +1 @@
1
- export { E as Errors, L as LEGACY_SUPPORT, P as PromiseBelongsTo, a as PromiseManyArray, l as lookupLegacySupport } from "../errors-Spt6ubMd.js";
1
+ export { E as Errors, L as LEGACY_SUPPORT, P as PromiseBelongsTo, a as PromiseManyArray, l as lookupLegacySupport } from "../errors-Bzidntpi.js";
@@ -4,8 +4,8 @@ import { notifyInternalSignal } from '@warp-drive/core/signals/-leaked';
4
4
  import { assertPrivateStore } from '@warp-drive/core/store/-private';
5
5
  import { getOrSetGlobal } from '@warp-drive/core/types/-private';
6
6
  import { Type } from '@warp-drive/core/types/symbols';
7
- import { l as lookupLegacySupport, E as Errors } from "../errors-Spt6ubMd.js";
8
- import { b as buildSchema, u as unloadRecord, s as serialize, _ as _save, a as save, r as rollbackAttributes, c as _reload, d as reload, h as hasMany, e as _destroyRecord, f as destroyRecord, i as deleteRecord, R as RecordState, j as changedAttributes, k as belongsTo, l as createSnapshot } from "../schema-provider-BP6_8N-V.js";
7
+ import { l as lookupLegacySupport, E as Errors } from "../errors-Bzidntpi.js";
8
+ import { b as buildSchema, u as unloadRecord, s as serialize, _ as _save, a as save, r as rollbackAttributes, c as _reload, d as reload, h as hasMany, e as _destroyRecord, f as destroyRecord, i as deleteRecord, R as RecordState, j as changedAttributes, k as belongsTo, l as createSnapshot } from "../schema-provider-ZwO5_fZw.js";
9
9
 
10
10
  /**
11
11
  * This module provides support for migrating away from @warp-drive/legacy/model
@@ -27,6 +27,12 @@ import { b as buildSchema, u as unloadRecord, s as serialize, _ as _save, a as s
27
27
  * @module
28
28
  */
29
29
 
30
+ /**
31
+ * Adds the `Model`-style `belongsTo`/`hasMany` reference methods to a
32
+ * {@link TypedRecordInstance}, for use when migrating a resource from
33
+ * `Model` to a schema-based record while preserving these APIs.
34
+ */
35
+
30
36
  // 'isDestroying', 'isDestroyed'
31
37
  const LegacyFields = ['_createSnapshot', 'adapterError', 'belongsTo', 'changedAttributes', 'constructor', 'currentState', 'deleteRecord', 'destroyRecord', 'dirtyType', 'errors', 'hasDirtyAttributes', 'hasMany', 'isDeleted', 'isEmpty', 'isError', 'isLoaded', 'isLoading', 'isNew', 'isSaving', 'isValid', 'reload', 'rollbackAttributes', 'save', 'serialize', 'unloadRecord'];
32
38
 
@@ -423,6 +429,9 @@ function registerDerivations(schema) {
423
429
  * @public
424
430
  */
425
431
 
432
+ /**
433
+ * See the {@link DelegatingSchemaService | class documentation above} for usage.
434
+ */
426
435
  class DelegatingSchemaService {
427
436
  /** @internal */
428
437
  _preferred;
@@ -432,6 +441,11 @@ class DelegatingSchemaService {
432
441
  this._preferred = schema;
433
442
  this._secondary = buildSchema(store);
434
443
  }
444
+
445
+ /**
446
+ * Whether the given resource's schema is being served by the fallback
447
+ * (legacy Model-derived) schema service rather than the primary one.
448
+ */
435
449
  isDelegated(resource) {
436
450
  return !this._preferred.hasResource(resource) && this._secondary.hasResource(resource);
437
451
  }
@@ -1,6 +1,11 @@
1
1
  import { tracked, cached } from '@glimmer/tracking';
2
2
  import { Context } from '@warp-drive/core/reactive/-private';
3
3
  import { a as decorateFieldV2, i as initializeDeferredDecorator, d as decorateMethodV2 } from "./runtime-BPCpkOf1-BKOwiRJp.js";
4
+
5
+ /**
6
+ * The features added to an object resource by {@link FragmentExtension}, providing
7
+ * a subset of the legacy `ModelFragments` fragment API for migrated resources.
8
+ */
4
9
  class Fragment {
5
10
  static {
6
11
  decorateFieldV2(this.prototype, "isDestroying", [tracked], function () {
@@ -8,12 +13,21 @@ class Fragment {
8
13
  });
9
14
  }
10
15
  #isDestroying = (initializeDeferredDecorator(this, "isDestroying"), void 0); // We might want to check the parent values once we move this code to warp-drive.
16
+ /**
17
+ * Whether this fragment is in the process of being destroyed.
18
+ */
11
19
  static {
12
20
  decorateFieldV2(this.prototype, "isDestroyed", [tracked], function () {
13
21
  return false;
14
22
  });
15
23
  }
16
24
  #isDestroyed = (initializeDeferredDecorator(this, "isDestroyed"), void 0);
25
+ /**
26
+ * Whether this fragment has been destroyed.
27
+ */
28
+ /**
29
+ * Whether this fragment (or the attribute it is rooted at) has uncommitted changes.
30
+ */
17
31
  get hasDirtyAttributes() {
18
32
  const {
19
33
  path,
@@ -27,18 +41,30 @@ class Fragment {
27
41
  }
28
42
  return false;
29
43
  }
44
+
45
+ /**
46
+ * Always `true`. Used to distinguish fragments from other resources.
47
+ */
30
48
  static {
31
49
  decorateMethodV2(this.prototype, "hasDirtyAttributes", [cached]);
32
50
  }
33
51
  get isFragment() {
34
52
  return true;
35
53
  }
54
+
55
+ /**
56
+ * The resource type of this fragment, if known.
57
+ */
36
58
  get $type() {
37
59
  const {
38
60
  field
39
61
  } = this[Context];
40
62
  return field?.type;
41
63
  }
64
+
65
+ /**
66
+ * Reverts this fragment's attribute back to its last known remote value.
67
+ */
42
68
  rollbackAttributes() {
43
69
  const {
44
70
  path,
@@ -51,11 +77,21 @@ class Fragment {
51
77
  }
52
78
  }
53
79
  }
80
+
81
+ /**
82
+ * A schema extension that adds the {@link Fragment} API to migrated
83
+ * `ModelFragments` object resources.
84
+ */
54
85
  const FragmentExtension = {
55
86
  kind: 'object',
56
87
  name: 'fragment',
57
88
  features: Fragment
58
89
  };
90
+
91
+ /**
92
+ * The features added to an array resource by {@link FragmentArrayExtension}, providing
93
+ * a subset of the legacy `ModelFragments` fragment-array API for migrated resources.
94
+ */
59
95
  class FragmentArray {
60
96
  static {
61
97
  decorateFieldV2(this.prototype, "isDestroying", [tracked], function () {
@@ -63,18 +99,29 @@ class FragmentArray {
63
99
  });
64
100
  }
65
101
  #isDestroying = (initializeDeferredDecorator(this, "isDestroying"), void 0); // We might want to check the parent values once we move this code to warp-drive.
102
+ /**
103
+ * Whether this fragment array is in the process of being destroyed.
104
+ */
66
105
  static {
67
106
  decorateFieldV2(this.prototype, "isDestroyed", [tracked], function () {
68
107
  return false;
69
108
  });
70
109
  }
71
110
  #isDestroyed = (initializeDeferredDecorator(this, "isDestroyed"), void 0);
111
+ /**
112
+ * Whether this fragment array has been destroyed.
113
+ */
114
+ /**
115
+ * Whether this fragment array (or any of its members) has uncommitted changes.
116
+ */
72
117
  get hasDirtyAttributes() {
118
+ const array = this;
119
+ const context = array[Context];
73
120
  const {
74
121
  path,
75
122
  resourceKey,
76
123
  store
77
- } = this[Context];
124
+ } = context;
78
125
  const record = store.peekRecord(resourceKey);
79
126
  if (record.hasDirtyAttributes && path) {
80
127
  const root = path.at(0);
@@ -82,6 +129,10 @@ class FragmentArray {
82
129
  }
83
130
  return false;
84
131
  }
132
+
133
+ /**
134
+ * Adds an existing fragment to this array, if one was given.
135
+ */
85
136
  static {
86
137
  decorateMethodV2(this.prototype, "hasDirtyAttributes", [cached]);
87
138
  }
@@ -91,12 +142,20 @@ class FragmentArray {
91
142
  }
92
143
  return this.addObject(fragment);
93
144
  }
145
+
146
+ /**
147
+ * Appends a new fragment to the end of this array, if one was given.
148
+ */
94
149
  createFragment(fragment) {
95
150
  if (!fragment) {
96
151
  return;
97
152
  }
98
153
  return this.pushObject(fragment);
99
154
  }
155
+
156
+ /**
157
+ * Removes the given fragment from this array, if present.
158
+ */
100
159
  removeFragment(fragment) {
101
160
  if (!fragment) {
102
161
  return;
@@ -106,6 +165,10 @@ class FragmentArray {
106
165
  this.splice(index, 1);
107
166
  }
108
167
  }
168
+
169
+ /**
170
+ * Reverts each member fragment's attribute back to its last known remote value.
171
+ */
109
172
  rollbackAttributes() {
110
173
  for (const fragment of this) {
111
174
  // @ts-expect-error TODO: fix these types
@@ -113,6 +176,11 @@ class FragmentArray {
113
176
  }
114
177
  }
115
178
  }
179
+
180
+ /**
181
+ * A schema extension that adds the {@link FragmentArray} API to migrated
182
+ * `ModelFragments` array resources.
183
+ */
116
184
  const FragmentArrayExtension = {
117
185
  kind: 'array',
118
186
  name: 'fragment-array',
@@ -217,5 +285,13 @@ class ShimModelClass {
217
285
  function fragmentsModelFor(modelName) {
218
286
  return getShimClass(this, modelName);
219
287
  }
288
+
289
+ /**
290
+ * The `modelFor` fallback used to construct a `ShimModelClass` schema for a
291
+ * type when ModelFragments support is enabled and no real `Model` subclass
292
+ * is registered for that type.
293
+ *
294
+ * @public
295
+ */
220
296
  const modelFor = fragmentsModelFor;
221
297
  export { FragmentExtension as F, FragmentArrayExtension as a, FragmentArray as b, Fragment as c, fragmentsModelFor as f, modelFor as m };
@@ -1,7 +1,7 @@
1
1
  import { pluralize, singularize } from '@warp-drive/utilities/string';
2
2
  import { withDefaults } from './model/migration-support.js';
3
- import { F as FragmentExtension, a as FragmentArrayExtension } from "./model-for-CqXsIKws.js";
4
- export { c as Fragment, b as FragmentArray, m as modelFor } from "./model-for-CqXsIKws.js";
3
+ import { F as FragmentExtension, a as FragmentArrayExtension } from "./model-for-CXkJw59V.js";
4
+ export { c as Fragment, b as FragmentArray, m as modelFor } from "./model-for-CXkJw59V.js";
5
5
 
6
6
  /**
7
7
  * Used as a helper to setup the relevant parts of an array
@@ -62,6 +62,15 @@ function withFragmentArrayDefaults(fragmentArrayType, fragmentArrayName) {
62
62
  }
63
63
  };
64
64
  }
65
+
66
+ /**
67
+ * Used as a helper to setup the relevant parts of a legacy resource schema
68
+ * migrated from `Model`, applying the `ember-object` and `fragment` object
69
+ * extensions and a default `@id` identity field.
70
+ *
71
+ * @param schema the partial legacy resource schema to complete
72
+ * @returns the completed resource schema
73
+ */
65
74
  function withLegacy(schema) {
66
75
  return withDefaults({
67
76
  ...schema,
@@ -72,6 +81,13 @@ function withLegacy(schema) {
72
81
  objectExtensions: ['ember-object', 'fragment']
73
82
  });
74
83
  }
84
+
85
+ /**
86
+ * Registers the {@link FragmentExtension}/{@link FragmentArrayExtension} schema
87
+ * extensions on the given `SchemaService`, enabling ModelFragments migration support.
88
+ *
89
+ * @public
90
+ */
75
91
  function registerFragmentExtensions(schema) {
76
92
  schema.CAUTION_MEGA_DANGER_ZONE_registerExtension?.(FragmentExtension);
77
93
  schema.CAUTION_MEGA_DANGER_ZONE_registerExtension?.(FragmentArrayExtension);