@warp-drive/core 5.7.0-alpha.4 → 5.7.0-alpha.5

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.
@@ -20,17 +20,19 @@ export interface BaseContext {
20
20
  export interface ResourceContext extends BaseContext {
21
21
  path: null;
22
22
  field: null;
23
+ value: null;
23
24
  }
24
25
  export interface ObjectContext extends BaseContext {
25
26
  path: string[];
26
27
  field: SchemaObjectField | SchemaArrayField;
28
+ value: string;
27
29
  }
28
30
  export interface KindContext<T extends FieldSchema | IdentityField | HashField> extends BaseContext {
29
31
  path: string[];
30
32
  field: T;
33
+ value: unknown;
31
34
  record: ReactiveResource;
32
35
  signals: SignalStore;
33
- value: unknown;
34
36
  }
35
37
  export interface KindImpl<T extends FieldSchema | IdentityField | HashField> {
36
38
  /**
@@ -1,9 +1,4 @@
1
- import type { RelatedCollection as ManyArray } from "../../../store/-private.js";
2
- import type { ArrayField, FieldSchema, SchemaArrayField } from "../../../types/schema/fields.js";
1
+ import type { ArrayField, SchemaArrayField } from "../../../types/schema/fields.js";
3
2
  import type { KindContext } from "../default-mode.js";
4
- import { ManagedArray } from "../fields/managed-array.js";
5
- import type { ReactiveResource } from "../record.js";
6
- export declare const ManagedArrayMap: Map<ReactiveResource, Map<string, ManagedArray | ManyArray>>;
7
- export declare function peekManagedArray(record: ReactiveResource, field: FieldSchema): ManyArray | ManagedArray | undefined;
8
3
  export declare function getArrayField(context: KindContext<ArrayField | SchemaArrayField>): unknown;
9
- export declare function setArrayField(context: KindContext<ArrayField | SchemaArrayField>): boolean;
4
+ export declare function setArrayField(context: KindContext<ArrayField>): boolean;
@@ -271,7 +271,7 @@ export declare class SchemaService implements SchemaServiceInterface {
271
271
  CAUTION_MEGA_DANGER_ZONE_resourceExtensions(resource: StableRecordIdentifier | {
272
272
  type: string;
273
273
  }): null | ProcessedExtension["features"];
274
- CAUTION_MEGA_DANGER_ZONE_objectExtensions(field: ExtensibleField): null | ProcessedExtension["features"];
274
+ CAUTION_MEGA_DANGER_ZONE_objectExtensions(field: ExtensibleField, resolvedType: string | null): null | ProcessedExtension["features"];
275
275
  CAUTION_MEGA_DANGER_ZONE_arrayExtensions(field: ExtensibleField): null | ProcessedExtension["features"];
276
276
  CAUTION_MEGA_DANGER_ZONE_hasExtension(ext: {
277
277
  kind: "object" | "array";
@@ -2,3 +2,4 @@ export { instantiateRecord, teardownRecord } from "./reactive/-private/hooks.js"
2
2
  export { type CAUTION_MEGA_DANGER_ZONE_Extension, type ProcessedExtension, type ExtensionDef, type Transformation, SchemaService, withDefaults, fromIdentity, registerDerivations } from "./reactive/-private/schema.js";
3
3
  export { type ReactiveResource } from "./reactive/-private/record.js";
4
4
  export { Checkout } from "./reactive/-private/symbols.js";
5
+ export { type ReactiveDocument } from "./reactive/-private/document.js";
@@ -358,7 +358,7 @@ export interface SchemaService {
358
358
  *
359
359
  * @public
360
360
  */
361
- CAUTION_MEGA_DANGER_ZONE_objectExtensions?(field: ExtensibleField): null | ProcessedExtension["features"];
361
+ CAUTION_MEGA_DANGER_ZONE_objectExtensions?(field: ExtensibleField, resolvedType: string | null): null | ProcessedExtension["features"];
362
362
  /**
363
363
  * Retrieve the extension map for an array field
364
364
  *
@@ -294,7 +294,7 @@ export interface IdentityField {
294
294
  * perform those itself.
295
295
  *
296
296
  * A schema-array can declare its "key" value to be `@hash` if
297
- * a schema-object has such a field.
297
+ * the schema-objects it contains have such a field.
298
298
  *
299
299
  * Only one hash field is permittable per schema-object, and
300
300
  * it should be placed in the `ResourceSchema`'s `@id` field
@@ -476,11 +476,13 @@ export interface ObjectField {
476
476
  /**
477
477
  * Represents a field whose value is an object
478
478
  * with a well-defined structure described by
479
- * a non-resource schema.
479
+ * a schema-object (a non-resource schema).
480
480
  *
481
481
  * If the object's structure is not well-defined,
482
482
  * use 'object' instead.
483
483
  *
484
+ * By default, a SchemaObject within
485
+ *
484
486
  * @public
485
487
  */
486
488
  export interface SchemaObjectField {
@@ -520,12 +522,19 @@ export interface SchemaObjectField {
520
522
  */
521
523
  sourceKey?: string;
522
524
  /**
525
+ * If the field is not polymorphic:
526
+ *
523
527
  * The name of the ObjectSchema that describes the
524
528
  * structure of the object.
525
529
  *
530
+ * If the field is polymorphic:
531
+ *
532
+ * The name of the hashFn to use to extract
533
+ * the type from the contained value or null.
534
+ *
526
535
  * @public
527
536
  */
528
- type: string;
537
+ type: string | null;
529
538
  /**
530
539
  * Options for configuring the behavior of the
531
540
  * SchemaObject.
@@ -562,7 +571,15 @@ export interface SchemaObjectField {
562
571
  * If the SchemaObject is Polymorphic, the key on the raw cache data to use
563
572
  * as the "resource-type" value for the schema-object.
564
573
  *
565
- * Defaults to "type".
574
+ * The default is `'type'`.
575
+ *
576
+ * Valid options are:
577
+ *
578
+ * - `'@hash'` : will lookup the `@hash` function specified by
579
+ * SchemaObjectField.type and use it to calculate the type for each value.
580
+ * - \<field-name> (string) : the name of a field to use as the key, only GenericFields (kind `field`)
581
+ * Are valid field names for this purpose. The cache state without transforms applied will be
582
+ * used when comparing values.
566
583
  *
567
584
  * @public
568
585
  */
@@ -694,12 +711,19 @@ export interface SchemaArrayField {
694
711
  */
695
712
  sourceKey?: string;
696
713
  /**
714
+ * If the SchemaArray is not polymorphic:
715
+ *
697
716
  * The name of the ObjectSchema that describes the
698
717
  * structure of the objects in the array.
699
718
  *
719
+ * If the SchemaArray is polymorphic:
720
+ *
721
+ * The name of the hashFn to use to extract
722
+ * the type from contained members or null.
723
+ *
700
724
  * @public
701
725
  */
702
- type: string;
726
+ type: string | null;
703
727
  /**
704
728
  * Options for configuring the behavior of the
705
729
  * SchemaArray.
@@ -713,13 +737,13 @@ export interface SchemaArrayField {
713
737
  *
714
738
  * Valid options are:
715
739
  *
716
- * - `'@identity'` (default) : the cached object's referential identity will be used.
740
+ * - `'@identity'`(default) : the cached object's referential identity will be used.
717
741
  * This may result in significant instability when resource data is updated from the API
718
742
  * - `'@index'` : the cached object's index in the array will be used.
719
743
  * This is only a good choice for arrays that rarely if ever change membership
720
744
  * - `'@hash'` : will lookup the `@hash` function supplied in the ResourceSchema for
721
745
  * The contained schema-object and use the computed result to determine and compare identity.
722
- * - \<field-name> (string) : the name of a field to use as the key, only GenericFields (kind `field`)
746
+ * - \<field-name> (string) : the name of a field to use as the key, only GenericFields (kind `field`)
723
747
  * Are valid field names for this purpose. The cache state without transforms applied will be
724
748
  * used when comparing values. The field value should be unique enough to guarantee two schema-objects
725
749
  * of the same type will not collide.
@@ -791,8 +815,15 @@ export interface SchemaArrayField {
791
815
  * If the SchemaArray is Polymorphic, the key on the raw cache data to use
792
816
  * as the "resource-type" value for the schema-object.
793
817
  *
794
- * Defaults to "type".
818
+ * The default is `'type'`.
795
819
  *
820
+ * Valid options are:
821
+ *
822
+ * - `'@hash'` : will lookup the `@hash` function specified by
823
+ * SchemaArrayField.type and use it to calculate the type for each value.
824
+ * - \<field-name> (string) : the name of a field to use as the key, only GenericFields (kind `field`)
825
+ * Are valid field names for this purpose. The cache state without transforms applied will be
826
+ * used when comparing values.
796
827
  */
797
828
  type?: string;
798
829
  };
@@ -1,5 +1,5 @@
1
1
  import { deprecate, warn } from '@ember/debug';
2
- import { p as peekCache } from "../request-state-Bj0zUw2r.js";
2
+ import { p as peekCache } from "../request-state-CeN66aML.js";
3
3
  import '../types/request.js';
4
4
  import { macroCondition, getGlobalConfig } from '@embroider/macros';
5
5
  import '../utils/string.js';
@@ -1,4 +1,4 @@
1
- import { K as ReactiveDocument } from "./request-state-Bj0zUw2r.js";
1
+ import { K as ReactiveDocument } from "./request-state-CeN66aML.js";
2
2
  import { SkipCache, EnableHydration } from './types/request.js';
3
3
  import { macroCondition, getGlobalConfig } from '@embroider/macros';
4
4
  const MUTATION_OPS = new Set(['createRecord', 'updateRecord', 'deleteRecord']);
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ import { a as cloneResponseProperties, I as IS_CACHE_HANDLER, b as assertValidRe
3
3
  import { macroCondition, getGlobalConfig } from '@embroider/macros';
4
4
  import { w as waitFor } from "./configure-B48bFHOl.js";
5
5
  import { peekUniversalTransient, setUniversalTransient } from './types/-private.js';
6
- export { S as Store, r as recordIdentifierFor, O as setIdentifierForgetMethod, L as setIdentifierGenerationMethod, P as setIdentifierResetMethod, N as setIdentifierUpdateMethod, Q as setKeyInfoForResource, s as storeFor } from "./request-state-Bj0zUw2r.js";
7
- export { C as CacheHandler } from "./handler-Gm-q2q05.js";
6
+ export { S as Store, r as recordIdentifierFor, O as setIdentifierForgetMethod, L as setIdentifierGenerationMethod, P as setIdentifierResetMethod, N as setIdentifierUpdateMethod, Q as setKeyInfoForResource, s as storeFor } from "./request-state-CeN66aML.js";
7
+ export { C as CacheHandler } from "./handler-SdXlte1w.js";
8
8
  import '@ember/debug';
9
9
  import './utils/string.js';
10
10
 
package/dist/reactive.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { isResourceSchema } from './types/schema/fields.js';
2
- import { F as withSignalStore, T as isExtensionProp, U as performExtensionSet, H as consumeInternalSignal, V as performArrayExtensionGet, x as entangleSignal, d as SOURCE$1, f as fastPush, l as RelatedCollection, J as getOrCreateInternalSignal, G as notifyInternalSignal, W as performObjectExtensionGet, y as defineSignal, B as Signals, h as setRecordIdentifier, r as recordIdentifierFor } from "./request-state-Bj0zUw2r.js";
2
+ import { F as withSignalStore, T as isExtensionProp, U as performExtensionSet, H as consumeInternalSignal, V as performArrayExtensionGet, x as entangleSignal, E as peekInternalSignal, d as SOURCE$1, f as fastPush, l as RelatedCollection, J as getOrCreateInternalSignal, G as notifyInternalSignal, W as performObjectExtensionGet, y as defineSignal, B as Signals, h as setRecordIdentifier, r as recordIdentifierFor } from "./request-state-CeN66aML.js";
3
3
  import { EnableHydration, STRUCTURED } from './types/request.js';
4
4
  import { macroCondition, getGlobalConfig } from '@embroider/macros';
5
5
  import { warn, deprecate } from '@ember/debug';
6
6
  import './utils/string.js';
7
7
  import { A as ARRAY_SIGNAL, O as OBJECT_SIGNAL, c as createMemo } from "./configure-B48bFHOl.js";
8
8
  import { RecordStore, Type } from './types/symbols.js';
9
+ import { S as SOURCE, E as Editable, L as Legacy, D as Destroy, I as Identifier, P as Parent, a as EmbeddedPath, C as Checkout, b as EmbeddedField } from "./symbols-SIstXMLI.js";
9
10
  import { getOrSetGlobal } from './types/-private.js';
10
- import { S as SOURCE, E as Editable, L as Legacy, I as Identifier, P as Parent, a as EmbeddedPath, D as Destroy, C as Checkout, b as EmbeddedField } from "./symbols-SIstXMLI.js";
11
11
  import './index.js';
12
12
  function getAliasField(context) {
13
13
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
@@ -78,6 +78,9 @@ class ManagedArray {
78
78
  this[Legacy] = context.legacy;
79
79
  const schema = context.store.schema;
80
80
  const cache = context.store.cache;
81
+ const {
82
+ field
83
+ } = context;
81
84
  const signals = withSignalStore(this);
82
85
  let _SIGNAL = null;
83
86
  const boundFns = new Map();
@@ -85,8 +88,9 @@ class ManagedArray {
85
88
  this.path = context.path;
86
89
  this.owner = owner;
87
90
  let transaction = false;
88
- const mode = context.field.options?.key ?? '@identity';
89
- const RefStorage = mode === '@identity' ? WeakMap :
91
+ const KeyMode = field.options?.key ?? '@identity';
92
+ // listener.
93
+ const RefStorage = KeyMode === '@identity' ? WeakMap :
90
94
  // CAUTION CAUTION CAUTION
91
95
  // this is a pile of lies
92
96
  // the Map is Map<string, WeakRef<ReactiveResource>>
@@ -94,8 +98,8 @@ class ManagedArray {
94
98
  // internal to a method like ours without us duplicating the code
95
99
  // into two separate methods.
96
100
  Map;
97
- const ManagedRecordRefs = context.field.kind === 'schema-array' ? new RefStorage() : null;
98
- const extensions = context.legacy ? schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions(context.field) : null;
101
+ const ManagedRecordRefs = field.kind === 'schema-array' ? new RefStorage() : null;
102
+ const extensions = context.legacy ? schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions(field) : null;
99
103
  const proxy = new Proxy(this[SOURCE], {
100
104
  get(target, prop, receiver) {
101
105
  if (prop === ARRAY_SIGNAL) {
@@ -121,14 +125,72 @@ class ManagedArray {
121
125
  }
122
126
  if (prop === '[]') return consumeInternalSignal(_SIGNAL), receiver;
123
127
  if (index !== null) {
124
- let val;
125
- if (mode === '@hash') {
126
- val = target[index];
128
+ if (!transaction) {
129
+ consumeInternalSignal(_SIGNAL);
130
+ }
131
+ const rawValue = target[index];
132
+ if (field.kind === 'array') {
133
+ if (field.type) {
134
+ const transform = schema.transformation(field);
135
+ return transform.hydrate(rawValue, field.options ?? null, self.owner);
136
+ }
137
+ return rawValue;
138
+ }
139
+
140
+ /**
141
+ * When the array is polymorphic, we need to determine the real type
142
+ * in order to apply the correct identity as schema-object identity
143
+ * is only required to be unique by type
144
+ */
145
+ let objectType;
146
+ if (field.options?.polymorphic) {
147
+ const typePath = field.options.type ?? 'type';
148
+ // if we are polymorphic, then context.field.options.type will
149
+ // either specify a path on the rawValue to use as the type, defaulting to "type" or
150
+ // the special string "@hash" which tells us to treat field.type as a hashFn name with which
151
+ // to calc the type.
152
+ if (typePath === '@hash') {
153
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
154
+ if (!test) {
155
+ throw new Error(`Expected the field to define a hashFn as its type`);
156
+ }
157
+ })(field.type) : {};
158
+ const hashFn = schema.hashFn({
159
+ type: field.type
160
+ });
161
+ // TODO consider if there are better options and name args we could provide.
162
+ objectType = hashFn(rawValue, null, null);
163
+ } else {
164
+ objectType = rawValue[typePath];
165
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
166
+ if (!test) {
167
+ throw new Error(`Expected the type path for the field to be a value on the raw object`);
168
+ }
169
+ })(typePath && objectType && typeof objectType === 'string') : {};
170
+ }
171
+ } else {
172
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
173
+ if (!test) {
174
+ throw new Error(`A non-polymorphic SchemaArrayField must provide a SchemaObject type in its definition`);
175
+ }
176
+ })(field.type) : {};
177
+ objectType = field.type;
178
+ }
179
+
180
+ /**
181
+ * When KeyMode=@hash the ReactiveResource is keyed into
182
+ * ManagedRecordRefs by the return value of @hash on the rawValue.
183
+ *
184
+ * This means that we could find a way to only recompute the identity
185
+ * when ARRAY_SIGNAL is dirty if hash performance becomes a bottleneck.
186
+ */
187
+ let schemaObjectKeyValue;
188
+ if (KeyMode === '@hash') {
127
189
  const hashField = schema.resource({
128
- type: context.field.type
190
+ type: objectType
129
191
  }).identity;
130
192
  const hashFn = schema.hashFn(hashField);
131
- val = hashFn(val, null, null);
193
+ schemaObjectKeyValue = hashFn(rawValue, hashField.options ?? null, hashField.name);
132
194
  } else {
133
195
  // if mode is not @identity or @index, then access the key path.
134
196
  // we should assert that `mode` is a string
@@ -136,74 +198,78 @@ class ManagedArray {
136
198
  // and, we likely should lookup the associated field and throw an error IF
137
199
  // the given field does not exist OR
138
200
  // the field is anything other than a GenericField or LegacyAttributeField.
139
- if (mode !== '@identity' && mode !== '@index') {
140
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
141
- if (!test) {
142
- throw new Error('mode must be a string');
143
- }
144
- })(typeof mode === 'string') : {};
145
- const modeField = schema.resource({
146
- type: context.field.type
147
- }).fields.find(f => f.name === mode);
148
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
149
- if (!test) {
150
- throw new Error('field must exist in schema');
151
- }
152
- })(modeField) : {};
153
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
154
- if (!test) {
155
- throw new Error('field must be a GenericField or LegacyAttributeField');
156
- }
157
- })(modeField.kind === 'field' || modeField.kind === 'attribute') : {};
158
- }
159
- val = mode === '@identity' ? target[index] : mode === '@index' ? '@index' : target[index][mode];
160
- }
161
- if (context.field.kind === 'schema-array') {
162
- if (!transaction) {
163
- consumeInternalSignal(_SIGNAL);
164
- }
165
- if (val) {
166
- const recordRef = ManagedRecordRefs.get(val);
167
- let record = recordRef?.deref();
168
- if (!record) {
169
- const recordPath = context.path.slice();
170
- // this is a dirty lie since path is string[] but really we
171
- // should change the types for paths to `Array<string | number>`
172
- // TODO we should allow the schema for the field to define a "key"
173
- // for stability. Default should be `@identity` which means that
174
- // same object reference from cache should result in same ReactiveResource
175
- // embedded object.
176
- recordPath.push(index);
177
- record = new ReactiveResource({
178
- store: context.store,
179
- resourceKey: context.resourceKey,
180
- modeName: context.modeName,
181
- legacy: context.legacy,
182
- editable: context.editable,
183
- path: recordPath,
184
- field: context.field
185
- });
186
-
187
- // if mode is not @identity or @index, then access the key path now
188
- // to determine the key value.
189
- // chris says we can implement this as a special kind `@hash` which
190
- // would be a function that only has access to the cache value and not
191
- // the record itself, so derivation is possible but intentionally limited
192
- // and non-reactive?
193
- ManagedRecordRefs.set(val, new WeakRef(record));
201
+ if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
202
+ const isPathKeyMode = KeyMode !== '@identity' && KeyMode !== '@index';
203
+ if (isPathKeyMode) {
204
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
205
+ if (!test) {
206
+ throw new Error('mode must be a string');
207
+ }
208
+ })(typeof KeyMode === 'string' && KeyMode !== '') : {};
209
+ const modeField = schema.fields({
210
+ type: objectType
211
+ }).get(KeyMode);
212
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
213
+ if (!test) {
214
+ throw new Error('field must exist in schema');
215
+ }
216
+ })(modeField) : {};
217
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
218
+ if (!test) {
219
+ throw new Error('field must be a GenericField or LegacyAttributeField');
220
+ }
221
+ })(modeField.kind === 'field' || modeField.kind === 'attribute') : {};
194
222
  }
195
- return record;
196
223
  }
197
- return val;
224
+ schemaObjectKeyValue = KeyMode === '@identity' ? rawValue : KeyMode === '@index' ? index : rawValue[KeyMode];
198
225
  }
199
- if (!transaction) {
200
- consumeInternalSignal(_SIGNAL);
226
+ if (!schemaObjectKeyValue) {
227
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
228
+ {
229
+ throw new Error(`Unexpected out of bounds access on SchemaArray`);
230
+ }
231
+ })() : {};
232
+ return undefined;
201
233
  }
202
- if (context.field.type) {
203
- const transform = schema.transformation(context.field);
204
- return transform.hydrate(val, context.field.options ?? null, self.owner);
234
+ const recordRef = ManagedRecordRefs.get(schemaObjectKeyValue);
235
+ const record = recordRef?.value.deref();
236
+
237
+ // confirm the type and key still match
238
+ if (record && recordRef.type === objectType && recordRef.identity === schemaObjectKeyValue) {
239
+ if (recordRef.index !== index) {
240
+ recordRef.index = index;
241
+ recordRef.context.path[recordRef.context.path.length - 1] = index;
242
+ }
243
+ return record;
244
+ } else if (record) {
245
+ // TODO schedule idle once we can
246
+ void Promise.resolve().then(() => {
247
+ record[Destroy]();
248
+ });
205
249
  }
206
- return val;
250
+ const recordPath = context.path.slice();
251
+ // this is a dirty lie since path is string[] but really we
252
+ // should change the types for paths to `Array<string | number>`
253
+ recordPath.push(index);
254
+ const objectContext = {
255
+ store: context.store,
256
+ resourceKey: context.resourceKey,
257
+ modeName: context.modeName,
258
+ legacy: context.legacy,
259
+ editable: context.editable,
260
+ path: recordPath,
261
+ field: field,
262
+ value: objectType
263
+ };
264
+ const schemaObject = new ReactiveResource(objectContext);
265
+ ManagedRecordRefs.set(schemaObjectKeyValue, {
266
+ type: objectType,
267
+ identity: schemaObjectKeyValue,
268
+ index,
269
+ context: objectContext,
270
+ value: new WeakRef(schemaObject)
271
+ });
272
+ return schemaObject;
207
273
  }
208
274
  if (isArrayGetter(prop)) {
209
275
  let fn = boundFns.get(prop);
@@ -274,18 +340,18 @@ class ManagedArray {
274
340
  }
275
341
  const reflect = Reflect.set(target, prop, value, receiver);
276
342
  if (reflect) {
277
- if (!context.field.type) {
343
+ if (!field.type) {
278
344
  cache.setAttr(context.resourceKey, context.path, self[SOURCE]);
279
345
  _SIGNAL.isStale = true;
280
346
  return true;
281
347
  }
282
348
  let rawValue = self[SOURCE];
283
- if (context.field.kind !== 'schema-array') {
284
- const transform = schema.transformation(context.field);
349
+ if (field.kind !== 'schema-array') {
350
+ const transform = schema.transformation(field);
285
351
  if (!transform) {
286
- throw new Error(`No '${context.field.type}' transform defined for use by ${context.resourceKey.type}.${String(prop)}`);
352
+ throw new Error(`No '${field.type}' transform defined for use by ${context.resourceKey.type}.${String(prop)}`);
287
353
  }
288
- rawValue = self[SOURCE].map(item => transform.serialize(item, context.field.options ?? null, self.owner));
354
+ rawValue = self[SOURCE].map(item => transform.serialize(item, field.options ?? null, self.owner));
289
355
  }
290
356
  cache.setAttr(context.resourceKey, context.path, rawValue);
291
357
  _SIGNAL.isStale = true;
@@ -324,29 +390,17 @@ const desc = {
324
390
  };
325
391
  // compat(desc);
326
392
  Object.defineProperty(ManagedArray.prototype, '[]', desc);
327
- const ManagedArrayMap = getOrSetGlobal('ManagedArrayMap', new Map());
328
- function peekManagedArray(record, field) {
329
- const managedArrayMapForRecord = ManagedArrayMap.get(record);
330
- if (managedArrayMapForRecord) {
331
- return managedArrayMapForRecord.get(field.name);
332
- }
333
- }
334
393
  function getArrayField(context) {
335
- entangleSignal(context.signals, context.record, context.path.at(-1), null);
394
+ const signal = entangleSignal(context.signals, context.record, context.path.at(-1), null);
336
395
  // the thing we hand out needs to know its owner and path in a private manner
337
396
  // its "address" is the parent identifier (identifier) + field name (field.name)
338
397
  // in the nested object case field name here is the full dot path from root resource to this value
339
398
  // its "key" is the field on the parent record
340
399
  // its "owner" is the parent record
341
400
  const {
342
- field,
343
401
  record
344
402
  } = context;
345
- const managedArrayMapForRecord = ManagedArrayMap.get(record);
346
- let managedArray;
347
- if (managedArrayMapForRecord) {
348
- managedArray = managedArrayMapForRecord.get(field.name);
349
- }
403
+ let managedArray = signal.value;
350
404
  if (managedArray) {
351
405
  return managedArray;
352
406
  } else {
@@ -363,11 +417,7 @@ function getArrayField(context) {
363
417
  return null;
364
418
  }
365
419
  managedArray = new ManagedArray(context, record, rawValue);
366
- if (!managedArrayMapForRecord) {
367
- ManagedArrayMap.set(record, new Map([[field.name, managedArray]]));
368
- } else {
369
- managedArrayMapForRecord.set(field.name, managedArray);
370
- }
420
+ signal.value = managedArray;
371
421
  }
372
422
  return managedArray;
373
423
  }
@@ -381,27 +431,11 @@ function setArrayField(context) {
381
431
  cache,
382
432
  schema
383
433
  } = context.store;
384
- if (!field.type) {
385
- cache.setAttr(context.resourceKey, context.path, value?.slice());
386
- const peeked = peekManagedArray(record, field);
387
- if (peeked) {
388
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
389
- if (!test) {
390
- throw new Error(`Expected the peekManagedArray for ${field.kind} to return a ManagedArray`);
391
- }
392
- })(ARRAY_SIGNAL in peeked) : {};
393
- const arrSignal = peeked[ARRAY_SIGNAL];
394
- arrSignal.isStale = true;
395
- }
396
- if (!Array.isArray(value)) {
397
- ManagedArrayMap.delete(record);
398
- }
399
- return true;
400
- }
401
- const transform = schema.transformation(field);
402
- const rawValue = value.map(item => transform.serialize(item, field.options ?? null, record));
434
+ const fieldSignal = peekInternalSignal(context.signals, context.path.at(-1));
435
+ const peeked = fieldSignal?.value;
436
+ const transform = field.type ? schema.transformation(field) : null;
437
+ const rawValue = field.type ? value.map(item => transform.serialize(item, field.options ?? null, record)) : value?.slice();
403
438
  cache.setAttr(context.resourceKey, context.path, rawValue);
404
- const peeked = peekManagedArray(record, field);
405
439
  if (peeked) {
406
440
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
407
441
  if (!test) {
@@ -410,6 +444,10 @@ function setArrayField(context) {
410
444
  })(ARRAY_SIGNAL in peeked) : {};
411
445
  const arrSignal = peeked[ARRAY_SIGNAL];
412
446
  arrSignal.isStale = true;
447
+ // TODO run array destroy?
448
+ }
449
+ if (!Array.isArray(rawValue) && fieldSignal) {
450
+ fieldSignal.value = null;
413
451
  }
414
452
  return true;
415
453
  }
@@ -619,7 +657,7 @@ function extractCacheOptions(options) {
619
657
  return cacheOptions;
620
658
  }
621
659
  function getHasManyField(context) {
622
- entangleSignal(context.signals, context.record, context.path.at(-1), null);
660
+ const signal = entangleSignal(context.signals, context.record, context.path.at(-1), null);
623
661
  const {
624
662
  store,
625
663
  field
@@ -634,52 +672,43 @@ function getHasManyField(context) {
634
672
  // its "key" is the field on the parent record
635
673
  // its "owner" is the parent record
636
674
 
637
- const managedArrayMapForRecord = ManagedArrayMap.get(record);
638
- let managedArray;
639
- if (managedArrayMapForRecord) {
640
- managedArray = managedArrayMapForRecord.get(getFieldCacheKeyStrict(field));
675
+ const cached = signal.value;
676
+ if (cached) {
677
+ return cached;
641
678
  }
642
- if (managedArray) {
643
- return managedArray;
644
- } else {
645
- const {
646
- editable,
647
- resourceKey
648
- } = context;
649
- const {
650
- cache
651
- } = store;
652
- const rawValue = cache.getRelationship(resourceKey, getFieldCacheKeyStrict(field));
653
- if (!rawValue) {
654
- return null;
655
- }
656
- managedArray = new RelatedCollection({
657
- store,
658
- type: field.type,
659
- identifier: resourceKey,
660
- cache,
661
- field: context.legacy ? field : undefined,
662
- // we divorce the reference here because ManyArray mutates the target directly
663
- // before sending the mutation op to the cache. We may be able to avoid this in the future
664
- identifiers: rawValue.data?.slice(),
665
- key: field.name,
666
- meta: rawValue.meta || null,
667
- links: rawValue.links || null,
668
- isPolymorphic: field.options.polymorphic ?? false,
669
- isAsync: field.options.async ?? false,
670
- // TODO: Grab the proper value
671
- _inverseIsAsync: false,
672
- // @ts-expect-error Typescript doesn't have a way for us to thread the generic backwards so it infers unknown instead of T
673
- manager: new ManyArrayManager(record, editable),
674
- isLoaded: true,
675
- allowMutation: editable
676
- });
677
- if (!managedArrayMapForRecord) {
678
- ManagedArrayMap.set(record, new Map([[field.name, managedArray]]));
679
- } else {
680
- managedArrayMapForRecord.set(field.name, managedArray);
681
- }
679
+ const {
680
+ editable,
681
+ resourceKey
682
+ } = context;
683
+ const {
684
+ cache
685
+ } = store;
686
+ const rawValue = cache.getRelationship(resourceKey, getFieldCacheKeyStrict(field));
687
+ if (!rawValue) {
688
+ return null;
682
689
  }
690
+ const managedArray = new RelatedCollection({
691
+ store,
692
+ type: field.type,
693
+ identifier: resourceKey,
694
+ cache,
695
+ field: context.legacy ? field : undefined,
696
+ // we divorce the reference here because ManyArray mutates the target directly
697
+ // before sending the mutation op to the cache. We may be able to avoid this in the future
698
+ identifiers: rawValue.data?.slice(),
699
+ key: field.name,
700
+ meta: rawValue.meta || null,
701
+ links: rawValue.links || null,
702
+ isPolymorphic: field.options.polymorphic ?? false,
703
+ isAsync: field.options.async ?? false,
704
+ // TODO: Grab the proper value
705
+ _inverseIsAsync: false,
706
+ // @ts-expect-error Typescript doesn't have a way for us to thread the generic backwards so it infers unknown instead of T
707
+ manager: new ManyArrayManager(record, editable),
708
+ isLoaded: true,
709
+ allowMutation: editable
710
+ });
711
+ signal.value = managedArray;
683
712
  return managedArray;
684
713
  }
685
714
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
@@ -807,7 +836,7 @@ class ManagedObject {
807
836
  } = context.store;
808
837
 
809
838
  // prettier-ignore
810
- const extensions = !context.legacy ? null : schema.CAUTION_MEGA_DANGER_ZONE_objectExtensions(field);
839
+ const extensions = !context.legacy ? null : schema.CAUTION_MEGA_DANGER_ZONE_objectExtensions(field, null);
811
840
  const proxy = new Proxy(this[SOURCE], {
812
841
  ownKeys() {
813
842
  return Object.keys(self[SOURCE]);
@@ -1070,11 +1099,9 @@ function setResourceField(context) {
1070
1099
  }
1071
1100
  function setSchemaArrayField(context) {
1072
1101
  const arrayValue = context.value?.slice();
1073
- if (!Array.isArray(arrayValue)) {
1074
- ManagedArrayMap.delete(context.record);
1075
- }
1102
+ const fieldSignal = peekInternalSignal(context.signals, context.path.at(-1));
1103
+ const peeked = fieldSignal?.value;
1076
1104
  context.store.cache.setAttr(context.resourceKey, context.path, arrayValue);
1077
- const peeked = peekManagedArray(context.record, context.field);
1078
1105
  if (peeked) {
1079
1106
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1080
1107
  if (!test) {
@@ -1083,50 +1110,104 @@ function setSchemaArrayField(context) {
1083
1110
  })(ARRAY_SIGNAL in peeked) : {};
1084
1111
  const arrSignal = peeked[ARRAY_SIGNAL];
1085
1112
  arrSignal.isStale = true;
1113
+ if (!Array.isArray(arrayValue)) {
1114
+ fieldSignal.value = null;
1115
+ }
1086
1116
  }
1087
1117
  return true;
1088
1118
  }
1089
1119
  function getSchemaObjectField(context) {
1090
- entangleSignal(context.signals, context.record, context.path.at(-1), null);
1120
+ const signal = entangleSignal(context.signals, context.record, context.path.at(-1), null);
1091
1121
  const {
1092
- record,
1093
- field
1122
+ store,
1123
+ resourceKey,
1124
+ path
1094
1125
  } = context;
1095
- const schemaObjectMapForRecord = ManagedObjectMap.get(record);
1096
- let schemaObject;
1097
- if (schemaObjectMapForRecord) {
1098
- schemaObject = schemaObjectMapForRecord.get(field.name);
1099
- }
1100
- if (schemaObject) {
1101
- return schemaObject;
1102
- } else {
1103
- const {
1104
- store,
1105
- resourceKey,
1106
- path
1107
- } = context;
1108
- const {
1109
- cache
1110
- } = store;
1111
- const rawValue = context.editable ? cache.getAttr(resourceKey, path) : cache.getRemoteAttr(resourceKey, path);
1112
- if (!rawValue) {
1113
- return null;
1126
+ const {
1127
+ cache
1128
+ } = store;
1129
+ const rawValue = context.editable ? cache.getAttr(resourceKey, path) : cache.getRemoteAttr(resourceKey, path);
1130
+ if (!rawValue) {
1131
+ if (signal.value) {
1132
+ const value = signal.value;
1133
+ // TODO if we had idle scheduling this should be done there.
1134
+ void Promise.resolve().then(() => {
1135
+ value.value[Destroy]();
1136
+ });
1137
+ signal.value = null;
1114
1138
  }
1115
- schemaObject = new ReactiveResource({
1116
- store: context.store,
1117
- resourceKey: context.resourceKey,
1118
- modeName: context.modeName,
1119
- legacy: context.legacy,
1120
- editable: context.editable,
1121
- path: context.path,
1122
- field: context.field
1123
- });
1139
+ return null;
1124
1140
  }
1125
- if (!schemaObjectMapForRecord) {
1126
- ManagedObjectMap.set(record, new Map([[field.name, schemaObject]]));
1141
+ const {
1142
+ field
1143
+ } = context;
1144
+ const {
1145
+ schema
1146
+ } = store;
1147
+ let objectType;
1148
+ if (field.options?.polymorphic) {
1149
+ const typePath = field.options.type ?? 'type';
1150
+ // if we are polymorphic, then context.field.options.type will
1151
+ // either specify a path on the rawValue to use as the type, defaulting to "type" or
1152
+ // the special string "@hash" which tells us to treat field.type as a hashFn name with which
1153
+ // to calc the type.
1154
+ if (typePath === '@hash') {
1155
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1156
+ if (!test) {
1157
+ throw new Error(`Expected the field to define a hashFn as its type`);
1158
+ }
1159
+ })(field.type) : {};
1160
+ const hashFn = schema.hashFn({
1161
+ type: field.type
1162
+ });
1163
+ // TODO consider if there are better options and name args we could provide.
1164
+ objectType = hashFn(rawValue, null, null);
1165
+ } else {
1166
+ objectType = rawValue[typePath];
1167
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1168
+ if (!test) {
1169
+ throw new Error(`Expected the type path for the field to be a value on the raw object`);
1170
+ }
1171
+ })(typePath && objectType && typeof objectType === 'string') : {};
1172
+ }
1127
1173
  } else {
1128
- schemaObjectMapForRecord.set(field.name, schemaObject);
1174
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1175
+ if (!test) {
1176
+ throw new Error(`A non-polymorphic SchemaObjectField must provide a SchemaObject type in its definition`);
1177
+ }
1178
+ })(field.type) : {};
1179
+ objectType = field.type;
1180
+ }
1181
+ const hashField = schema.resource({
1182
+ type: objectType
1183
+ }).identity;
1184
+ const identity = hashField ? schema.hashFn(hashField)(rawValue, hashField.options ?? null, hashField.name) : field.name;
1185
+ const cachedSchemaObject = signal.value;
1186
+ if (cachedSchemaObject) {
1187
+ if (cachedSchemaObject.type === objectType && cachedSchemaObject.identity === identity) {
1188
+ return cachedSchemaObject.value;
1189
+ } else {
1190
+ // TODO if we had idle scheduling this should be done there.
1191
+ void Promise.resolve().then(() => {
1192
+ cachedSchemaObject.value[Destroy]();
1193
+ });
1194
+ }
1129
1195
  }
1196
+ const schemaObject = new ReactiveResource({
1197
+ store: context.store,
1198
+ resourceKey: context.resourceKey,
1199
+ modeName: context.modeName,
1200
+ legacy: context.legacy,
1201
+ editable: context.editable,
1202
+ path: context.path,
1203
+ field: context.field,
1204
+ value: objectType
1205
+ });
1206
+ signal.value = {
1207
+ type: objectType,
1208
+ identity: identity,
1209
+ value: schemaObject
1210
+ };
1130
1211
  return schemaObject;
1131
1212
  }
1132
1213
  function setSchemaObjectField(context) {
@@ -1309,17 +1390,26 @@ class ReactiveResource {
1309
1390
  this[Identifier] = identifier;
1310
1391
  }
1311
1392
  const IS_EDITABLE = this[Editable] = context.editable ?? false;
1312
- this[Legacy] = context.legacy ?? false;
1313
1393
  const schema = store.schema;
1314
- const ResourceSchema = schema.resource(isEmbedded ? embeddedField : identifier);
1394
+ this[Legacy] = context.legacy ?? false;
1395
+ const objectType = isEmbedded ? context.value : identifier.type;
1396
+ const ResourceSchema = schema.resource(isEmbedded ? {
1397
+ type: objectType
1398
+ } : identifier);
1315
1399
  const identityField = ResourceSchema.identity;
1316
1400
  const BoundFns = new Map();
1317
1401
 
1318
1402
  // prettier-ignore
1319
- const extensions = !context.legacy ? null : isEmbedded ? schema.CAUTION_MEGA_DANGER_ZONE_objectExtensions(embeddedField) : schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(identifier);
1403
+ const extensions = !context.legacy ? null : isEmbedded ? schema.CAUTION_MEGA_DANGER_ZONE_objectExtensions(embeddedField, objectType) : schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(identifier);
1320
1404
  this[EmbeddedField] = embeddedField;
1321
1405
  this[EmbeddedPath] = embeddedPath;
1322
- const fields = isEmbedded ? schema.fields(embeddedField) : schema.fields(identifier);
1406
+ const fields = isEmbedded ? schema.fields({
1407
+ type: objectType
1408
+ }) : schema.fields(identifier);
1409
+ const method = typeof schema.cacheFields === 'function' ? 'cacheFields' : 'fields';
1410
+ const cacheFields = isEmbedded ? schema[method]({
1411
+ type: objectType
1412
+ }) : schema[method](identifier);
1323
1413
  const signals = withSignalStore(this);
1324
1414
  const proxy = new Proxy(this, {
1325
1415
  ownKeys() {
@@ -1684,9 +1774,9 @@ class ReactiveResource {
1684
1774
  if (signal) {
1685
1775
  notifyInternalSignal(signal);
1686
1776
  }
1687
- const field = fields.get(key);
1777
+ const field = cacheFields.get(key);
1688
1778
  if (field?.kind === 'array' || field?.kind === 'schema-array') {
1689
- const peeked = peekManagedArray(proxy, field);
1779
+ const peeked = signal?.value;
1690
1780
  if (peeked) {
1691
1781
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1692
1782
  if (!test) {
@@ -1712,7 +1802,7 @@ class ReactiveResource {
1712
1802
  if (Array.isArray(key)) ;else {
1713
1803
  if (isEmbedded) return; // base paths never apply to embedded records
1714
1804
 
1715
- const field = fields.get(key);
1805
+ const field = cacheFields.get(key);
1716
1806
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1717
1807
  if (!test) {
1718
1808
  throw new Error(`Expected relationship ${key} to be the name of a field`);
@@ -1728,9 +1818,12 @@ class ReactiveResource {
1728
1818
  // FIXME
1729
1819
  } else if (field.kind === 'resource') ;else if (field.kind === 'hasMany') {
1730
1820
  if (field.options.linksMode) {
1731
- const peeked = peekManagedArray(proxy, field);
1732
- if (peeked) {
1733
- notifyInternalSignal(peeked[ARRAY_SIGNAL]);
1821
+ const signal = signals.get(key);
1822
+ if (signal) {
1823
+ const peeked = signal.value;
1824
+ if (peeked) {
1825
+ notifyInternalSignal(peeked[ARRAY_SIGNAL]);
1826
+ }
1734
1827
  }
1735
1828
  return;
1736
1829
  }
@@ -1801,8 +1894,9 @@ function _CHECKOUT(record) {
1801
1894
  modeName: legacy ? 'legacy' : 'polaris',
1802
1895
  legacy: legacy,
1803
1896
  editable: true,
1804
- path: embeddedPath,
1805
- field: embeddedType
1897
+ path: null,
1898
+ field: null,
1899
+ value: null
1806
1900
  });
1807
1901
  setRecordIdentifier(editableRecord, recordIdentifierFor(record));
1808
1902
  return Promise.resolve(editableRecord);
@@ -1815,6 +1909,9 @@ function _DESTROY(record) {
1815
1909
  record.isDestroyed = true;
1816
1910
  }
1817
1911
  record[RecordStore].notifications.unsubscribe(record.___notifications);
1912
+
1913
+ // FIXME we need a way to also unsubscribe all SchemaObjects when the primary
1914
+ // resource is destroyed.
1818
1915
  }
1819
1916
  function assertNeverField(identifier, field, path) {
1820
1917
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
@@ -1841,7 +1938,8 @@ function instantiateRecord(store, identifier, createArgs) {
1841
1938
  legacy: legacy,
1842
1939
  editable: editable,
1843
1940
  path: null,
1844
- field: null
1941
+ field: null,
1942
+ value: null
1845
1943
  });
1846
1944
  if (createArgs) {
1847
1945
  Object.assign(record, createArgs);
@@ -1978,7 +2076,7 @@ function getExt(extCache, type, extName) {
1978
2076
  function hasObjectSchema(field) {
1979
2077
  return 'kind' in field && (field.kind === 'schema-array' || field.kind === 'schema-object');
1980
2078
  }
1981
- function processExtensions(schema, field, scenario) {
2079
+ function processExtensions(schema, field, scenario, resolvedType) {
1982
2080
  // if we're looking up extensions for a resource, there is no
1983
2081
  // merging required so if we have no objectExtensions
1984
2082
  // we are done.
@@ -2005,12 +2103,16 @@ function processExtensions(schema, field, scenario) {
2005
2103
  if (!hasObjectSchema(field)) {
2006
2104
  return null;
2007
2105
  }
2008
- return schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(field);
2106
+ return schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(resolvedType ? {
2107
+ type: resolvedType
2108
+ } : field);
2009
2109
  }
2010
2110
 
2011
2111
  // if we have made it here, we have extensions, lets check if there's
2012
2112
  // a cached version we can use
2013
- const baseExtensions = scenario === 'resource' && hasObjectSchema(field) ? schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(field) : scenario === 'object' && hasObjectSchema(field) ? schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(field) : null;
2113
+ const baseExtensions = scenario === 'resource' && hasObjectSchema(field) ? schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(field) : scenario === 'object' && hasObjectSchema(field) ? schema.CAUTION_MEGA_DANGER_ZONE_resourceExtensions(resolvedType ? {
2114
+ type: resolvedType
2115
+ } : field) : null;
2014
2116
  if (!baseExtensions && extensions.length === 1) {
2015
2117
  const value = getExt(extCache, type, extensions[0]);
2016
2118
  fieldCache[type].set(field, value);
@@ -2339,13 +2441,13 @@ class SchemaService {
2339
2441
  }
2340
2442
  CAUTION_MEGA_DANGER_ZONE_resourceExtensions(resource) {
2341
2443
  const schema = this.resource(resource);
2342
- return processExtensions(this, schema, 'resource');
2444
+ return processExtensions(this, schema, 'resource', null);
2343
2445
  }
2344
- CAUTION_MEGA_DANGER_ZONE_objectExtensions(field) {
2345
- return processExtensions(this, field, 'object');
2446
+ CAUTION_MEGA_DANGER_ZONE_objectExtensions(field, resolvedType) {
2447
+ return processExtensions(this, field, 'object', resolvedType);
2346
2448
  }
2347
2449
  CAUTION_MEGA_DANGER_ZONE_arrayExtensions(field) {
2348
- return processExtensions(this, field, 'array');
2450
+ return processExtensions(this, field, 'array', null);
2349
2451
  }
2350
2452
  CAUTION_MEGA_DANGER_ZONE_hasExtension(ext) {
2351
2453
  return this._extensions[ext.kind].has(ext.name);
@@ -3481,7 +3481,7 @@ function extractIdentifierFromRecord$2(record) {
3481
3481
  return recordIdentifierFor(record);
3482
3482
  }
3483
3483
  const FAKE_ARR = getOrSetGlobal('FAKE_ARR', {});
3484
- const SLICE_BATCH_SIZE = 1200;
3484
+ const SLICE_BATCH_SIZE = 4761;
3485
3485
  /**
3486
3486
  * This is a clever optimization.
3487
3487
  *
@@ -3521,15 +3521,12 @@ const SLICE_BATCH_SIZE = 1200;
3521
3521
  * @param source the items to push into target
3522
3522
  */
3523
3523
  function fastPush(target, source) {
3524
- let startLength = 0;
3525
- const newLength = source.length;
3526
- while (newLength - startLength > SLICE_BATCH_SIZE) {
3527
- // eslint-disable-next-line prefer-spread
3528
- target.push.apply(target, source.slice(startLength, startLength + SLICE_BATCH_SIZE));
3529
- startLength += SLICE_BATCH_SIZE;
3524
+ let batch;
3525
+ while (source.length > SLICE_BATCH_SIZE) {
3526
+ batch = source.splice(0, SLICE_BATCH_SIZE);
3527
+ target.push(...batch);
3530
3528
  }
3531
- // eslint-disable-next-line prefer-spread
3532
- target.push.apply(target, source.slice(startLength));
3529
+ target.push(...source);
3533
3530
  }
3534
3531
  /**
3535
3532
  @class RecordArrayManager
@@ -5078,7 +5075,7 @@ class Store extends BaseClass {
5078
5075
  if (!cache) {
5079
5076
  cache = this._instanceCache.cache = this.createCache(this._instanceCache._storeWrapper);
5080
5077
  if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
5081
- cache = new CacheManager(cache);
5078
+ cache = this._instanceCache.cache = new CacheManager(cache);
5082
5079
  }
5083
5080
  }
5084
5081
  return cache;
@@ -1,3 +1,3 @@
1
- export { C as CollectionRecordArray, D as DISPOSE, I as LiveArray, M as MUTATE, R as RecordArrayManager, l as RelatedCollection, d as SOURCE, B as Signals, S as Store, j as StoreMap, _ as _clearCaches, n as _deprecatingNormalize, b as coerceId, c as constructResource, H as consumeInternalSignal, t as createRequestSubscription, z as defineGate, A as defineNonEnumerableSignal, y as defineSignal, e as ensureStringId, x as entangleSignal, f as fastPush, w as gate, J as getOrCreateInternalSignal, q as getPromiseState, u as getRequestState, a as isDocumentIdentifier, i as isStableIdentifier, m as log, o as logGroup, v as memoized, G as notifyInternalSignal, p as peekCache, E as peekInternalSignal, r as recordIdentifierFor, g as removeRecordDataFor, k as setCacheFor, h as setRecordIdentifier, s as storeFor, F as withSignalStore } from "../request-state-Bj0zUw2r.js";
2
- export { C as CacheHandler } from "../handler-Gm-q2q05.js";
1
+ export { C as CollectionRecordArray, D as DISPOSE, I as LiveArray, M as MUTATE, R as RecordArrayManager, l as RelatedCollection, d as SOURCE, B as Signals, S as Store, j as StoreMap, _ as _clearCaches, n as _deprecatingNormalize, b as coerceId, c as constructResource, H as consumeInternalSignal, t as createRequestSubscription, z as defineGate, A as defineNonEnumerableSignal, y as defineSignal, e as ensureStringId, x as entangleSignal, f as fastPush, w as gate, J as getOrCreateInternalSignal, q as getPromiseState, u as getRequestState, a as isDocumentIdentifier, i as isStableIdentifier, m as log, o as logGroup, v as memoized, G as notifyInternalSignal, p as peekCache, E as peekInternalSignal, r as recordIdentifierFor, g as removeRecordDataFor, k as setCacheFor, h as setRecordIdentifier, s as storeFor, F as withSignalStore } from "../request-state-CeN66aML.js";
2
+ export { C as CacheHandler } from "../handler-SdXlte1w.js";
3
3
  export { A as ARRAY_SIGNAL, O as OBJECT_SIGNAL, c as createMemo, w as waitFor } from "../configure-B48bFHOl.js";
@@ -1,6 +1,6 @@
1
1
  import { macroCondition, getGlobalConfig } from '@embroider/macros';
2
2
  const name = "@warp-drive/core";
3
- const version = "5.7.0-alpha.4";
3
+ const version = "5.7.0-alpha.5";
4
4
 
5
5
  // in testing mode, we utilize globals to ensure only one copy exists of
6
6
  // these maps, due to bugs in ember-auto-import
@@ -134,7 +134,7 @@
134
134
  * perform those itself.
135
135
  *
136
136
  * A schema-array can declare its "key" value to be `@hash` if
137
- * a schema-object has such a field.
137
+ * the schema-objects it contains have such a field.
138
138
  *
139
139
  * Only one hash field is permittable per schema-object, and
140
140
  * it should be placed in the `ResourceSchema`'s `@id` field
@@ -188,11 +188,13 @@
188
188
  /**
189
189
  * Represents a field whose value is an object
190
190
  * with a well-defined structure described by
191
- * a non-resource schema.
191
+ * a schema-object (a non-resource schema).
192
192
  *
193
193
  * If the object's structure is not well-defined,
194
194
  * use 'object' instead.
195
195
  *
196
+ * By default, a SchemaObject within
197
+ *
196
198
  * @public
197
199
  */
198
200
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warp-drive/core",
3
- "version": "5.7.0-alpha.4",
3
+ "version": "5.7.0-alpha.5",
4
4
  "description": "Core package for WarpDrive | All the Universal Basics",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -37,13 +37,13 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@embroider/macros": "^1.16.12",
40
- "@warp-drive/build-config": "5.7.0-alpha.4"
40
+ "@warp-drive/build-config": "5.7.0-alpha.5"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@babel/core": "^7.26.10",
44
44
  "@babel/plugin-transform-typescript": "^7.27.0",
45
45
  "@babel/preset-typescript": "^7.27.0",
46
- "@warp-drive/internal-config": "5.7.0-alpha.4",
46
+ "@warp-drive/internal-config": "5.7.0-alpha.5",
47
47
  "decorator-transforms": "^2.3.0",
48
48
  "ember-source": "~6.3.0",
49
49
  "expect-type": "^1.2.1",