@warp-drive/core 5.9.0-alpha.17 → 5.9.0-alpha.19
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.
- package/declarations/graph/-private/-state.d.ts +1 -0
- package/declarations/index.d.ts +10 -1
- package/declarations/reactive/-private/default-mode.d.ts +22 -9
- package/declarations/reactive/-private/kind/belongs-to-field.d.ts +3 -0
- package/declarations/types/runtime.d.ts +16 -0
- package/declarations/types/schema/fields.d.ts +40 -12
- package/dist/graph/-private.js +67 -52
- package/dist/{index-CFwnjldF.js → index-LI2ckwf9.js} +332 -10
- package/dist/index.js +1 -1
- package/dist/reactive.js +1 -1
- package/dist/store/-private.js +1 -1
- package/dist/types/-private.js +1 -1
- package/dist/types/runtime.js +20 -1
- package/dist/unpkg/dev/graph/-private.js +67 -52
- package/dist/unpkg/dev/{index-BZRBBa34.js → index-DU_HLpg-.js} +332 -10
- package/dist/unpkg/dev/index.js +1 -1
- package/dist/unpkg/dev/reactive.js +1 -1
- package/dist/unpkg/dev/store/-private.js +2 -2
- package/dist/unpkg/dev/types/-private.js +1 -1
- package/dist/unpkg/dev/types/runtime.js +20 -1
- package/dist/unpkg/dev-deprecated/graph/-private.js +67 -52
- package/dist/unpkg/dev-deprecated/{index-Bu52tQ9I.js → index-BYFUHVPd.js} +332 -10
- package/dist/unpkg/dev-deprecated/index.js +1 -1
- package/dist/unpkg/dev-deprecated/reactive.js +1 -1
- package/dist/unpkg/dev-deprecated/store/-private.js +1 -1
- package/dist/unpkg/dev-deprecated/types/-private.js +1 -1
- package/dist/unpkg/dev-deprecated/types/runtime.js +20 -1
- package/dist/unpkg/prod/{-leaked-BHLmJyaw.js → -leaked-DgjQ5X55.js} +2 -2
- package/dist/unpkg/prod/configure.js +1 -1
- package/dist/unpkg/prod/graph/-private.js +17 -25
- package/dist/unpkg/prod/{schema-BdC3DirM.js → index-C-AhVafS.js} +2383 -73
- package/dist/unpkg/prod/index.js +5 -483
- package/dist/unpkg/prod/{promise-cache-DIT8Ypjq.js → promise-cache-DUblkX-U.js} +1 -1
- package/dist/unpkg/prod/reactive.js +3 -29
- package/dist/unpkg/prod/{request-BrJSCG6r.js → request-eb7Zm-oS.js} +1 -1
- package/dist/unpkg/prod/request.js +2 -2
- package/dist/unpkg/prod/signals/-leaked.js +1 -1
- package/dist/unpkg/prod/store/-private.js +2 -3
- package/dist/unpkg/prod/types/-private.js +1 -1
- package/dist/unpkg/prod/types/runtime.js +20 -1
- package/dist/unpkg/prod-deprecated/{-leaked-D_5Yrs5c.js → -leaked-BNVttukY.js} +1 -1
- package/dist/unpkg/prod-deprecated/configure.js +1 -1
- package/dist/unpkg/prod-deprecated/graph/-private.js +17 -25
- package/dist/unpkg/prod-deprecated/{schema-h0nuUTCj.js → index-CplZl2hv.js} +1035 -7
- package/dist/unpkg/prod-deprecated/index.js +5 -483
- package/dist/unpkg/prod-deprecated/{promise-cache-DIT8Ypjq.js → promise-cache-DUblkX-U.js} +1 -1
- package/dist/unpkg/prod-deprecated/reactive.js +2 -3
- package/dist/unpkg/prod-deprecated/{request-BrJSCG6r.js → request-eb7Zm-oS.js} +1 -1
- package/dist/unpkg/prod-deprecated/request.js +2 -2
- package/dist/unpkg/prod-deprecated/signals/-leaked.js +1 -1
- package/dist/unpkg/prod-deprecated/store/-private.js +1 -2
- package/dist/unpkg/prod-deprecated/types/-private.js +1 -1
- package/dist/unpkg/prod-deprecated/types/runtime.js +20 -1
- package/package.json +3 -3
- package/dist/unpkg/prod/handler-BJogFbfS.js +0 -1619
- package/dist/unpkg/prod-deprecated/handler-kGR8zguj.js +0 -334
- package/dist/unpkg/prod-deprecated/hooks-wJdveHPi.js +0 -26
|
@@ -2,6 +2,7 @@ import { d as defineGate, w as withSignalStore, n as notifyInternalSignal, p as
|
|
|
2
2
|
import { EnableHydration, SkipCache, STRUCTURED } from './types/request.js';
|
|
3
3
|
import { D as Destroy, a as Context, S as SOURCE, C as Checkout, b as Commit } from "./-private-3C1OkYtZ.js";
|
|
4
4
|
import { isResourceSchema } from './types/schema/fields.js';
|
|
5
|
+
import { setLogging, getRuntimeConfig, setIsMaybeMirage } from './types/runtime.js';
|
|
5
6
|
import { a as cloneResponseProperties, I as IS_CACHE_HANDLER, b as assertValidRequest, e as executeNextHandler, d as getRequestResult, u as upgradePromise, s as setPromiseResult, f as clearRequestResult } from "./future-DUuPqyLj.js";
|
|
6
7
|
import { getOrSetGlobal, peekTransient, setTransient, peekUniversalTransient, setUniversalTransient } from './types/-private.js';
|
|
7
8
|
import { DefaultCachePolicy } from './store.js';
|
|
@@ -9,7 +10,6 @@ import { withBrand } from './request.js';
|
|
|
9
10
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_KEY_TYPE, DEBUG_CLIENT_ORIGINATED } from './types/identifier.js';
|
|
10
11
|
import { dasherize } from './utils/string.js';
|
|
11
12
|
import { g as getGlobalConfig } from "./runtime-DfhJzpZH.js";
|
|
12
|
-
import { setLogging, getRuntimeConfig } from './types/runtime.js';
|
|
13
13
|
import { RecordStore, Type } from './types/symbols.js';
|
|
14
14
|
import * as _importSync20 from '@ember/object';
|
|
15
15
|
function urlFromLink(link) {
|
|
@@ -7248,11 +7248,32 @@ function getBelongsToField(context) {
|
|
|
7248
7248
|
}
|
|
7249
7249
|
function setBelongsToField(context) {
|
|
7250
7250
|
const {
|
|
7251
|
+
field,
|
|
7252
|
+
resourceKey,
|
|
7251
7253
|
store
|
|
7252
7254
|
} = context;
|
|
7253
7255
|
const {
|
|
7254
|
-
schema
|
|
7256
|
+
schema,
|
|
7257
|
+
cache
|
|
7255
7258
|
} = store;
|
|
7259
|
+
|
|
7260
|
+
/**
|
|
7261
|
+
* We currently only allow editing sync belongsTo relationships
|
|
7262
|
+
* in PolarisMode
|
|
7263
|
+
*/
|
|
7264
|
+
const isValidPolarisConfig = field.options.linksMode && !field.options.async;
|
|
7265
|
+
if (!context.legacy && isValidPolarisConfig) {
|
|
7266
|
+
const name = context.path.at(-1);
|
|
7267
|
+
cache.mutate({
|
|
7268
|
+
op: 'replaceRelatedRecord',
|
|
7269
|
+
record: resourceKey,
|
|
7270
|
+
field: name,
|
|
7271
|
+
value: getResourceKey(context.value)
|
|
7272
|
+
},
|
|
7273
|
+
// @ts-expect-error
|
|
7274
|
+
true);
|
|
7275
|
+
return true;
|
|
7276
|
+
}
|
|
7256
7277
|
(test => {
|
|
7257
7278
|
if (!test) {
|
|
7258
7279
|
throw new Error(`Can only mutate belongsTo fields when the resource is in legacy mode`);
|
|
@@ -7261,6 +7282,12 @@ function setBelongsToField(context) {
|
|
|
7261
7282
|
schema._kind('@legacy', 'belongsTo').set(store, context.record, context.resourceKey, context.field, context.value);
|
|
7262
7283
|
return true;
|
|
7263
7284
|
}
|
|
7285
|
+
function getResourceKey(record) {
|
|
7286
|
+
if (!record) {
|
|
7287
|
+
return null;
|
|
7288
|
+
}
|
|
7289
|
+
return recordIdentifierFor(record);
|
|
7290
|
+
}
|
|
7264
7291
|
function getCollectionField(context) {
|
|
7265
7292
|
entangleSignal(context.signals, context.record, context.path.at(-1), null);
|
|
7266
7293
|
(test => {
|
|
@@ -7993,6 +8020,17 @@ function setSchemaObjectField(context) {
|
|
|
7993
8020
|
// }
|
|
7994
8021
|
return true;
|
|
7995
8022
|
}
|
|
8023
|
+
|
|
8024
|
+
/**
|
|
8025
|
+
* A ReactiveResource context object passed to
|
|
8026
|
+
* the get/set functions of a field kind implementation.
|
|
8027
|
+
*
|
|
8028
|
+
* This provides all the necessary information for
|
|
8029
|
+
* the field kind to perform its operations.
|
|
8030
|
+
*
|
|
8031
|
+
* @internal
|
|
8032
|
+
*/
|
|
8033
|
+
|
|
7996
8034
|
const DefaultMode = {
|
|
7997
8035
|
'@hash': {
|
|
7998
8036
|
get: getHashField,
|
|
@@ -8288,6 +8326,9 @@ class ReactiveResource {
|
|
|
8288
8326
|
if (prop === Destroy || prop === Checkout) {
|
|
8289
8327
|
return true;
|
|
8290
8328
|
}
|
|
8329
|
+
if (prop === identityField?.name) {
|
|
8330
|
+
return true;
|
|
8331
|
+
}
|
|
8291
8332
|
return fields.has(prop);
|
|
8292
8333
|
},
|
|
8293
8334
|
getOwnPropertyDescriptor(target, prop) {
|
|
@@ -8786,6 +8827,14 @@ const TypeField = {
|
|
|
8786
8827
|
key: 'type'
|
|
8787
8828
|
}
|
|
8788
8829
|
};
|
|
8830
|
+
const IdentifierField = {
|
|
8831
|
+
type: '@identity',
|
|
8832
|
+
name: '$key',
|
|
8833
|
+
kind: 'derived',
|
|
8834
|
+
options: {
|
|
8835
|
+
key: '^'
|
|
8836
|
+
}
|
|
8837
|
+
};
|
|
8789
8838
|
const DefaultIdentityField = {
|
|
8790
8839
|
name: 'id',
|
|
8791
8840
|
kind: '@id'
|
|
@@ -8974,6 +9023,7 @@ function withDefaults(schema) {
|
|
|
8974
9023
|
// we add TypeField to the beginning so that it will
|
|
8975
9024
|
// appear right next to the identity field
|
|
8976
9025
|
schema.fields.unshift(TypeField);
|
|
9026
|
+
schema.fields.unshift(IdentifierField);
|
|
8977
9027
|
schema.fields.push(ConstructorField);
|
|
8978
9028
|
return schema;
|
|
8979
9029
|
}
|
|
@@ -9029,6 +9079,90 @@ function registerDerivations(schema) {
|
|
|
9029
9079
|
schema.registerDerivation(fromIdentity);
|
|
9030
9080
|
schema.registerDerivation(_constructor);
|
|
9031
9081
|
}
|
|
9082
|
+
|
|
9083
|
+
/**
|
|
9084
|
+
* A relationship field capable of declaring `options.as`, marking it as a
|
|
9085
|
+
* concrete implementation of an abstract polymorphic type.
|
|
9086
|
+
*/
|
|
9087
|
+
|
|
9088
|
+
/**
|
|
9089
|
+
* A relationship field contributed to an abstract type's schema, along with
|
|
9090
|
+
* the name of the type that contributed it (either a concrete implementer,
|
|
9091
|
+
* via `options.as`, or the abstract type's own schema), for use in assertion
|
|
9092
|
+
* messages when two contributions disagree on shape.
|
|
9093
|
+
*/
|
|
9094
|
+
|
|
9095
|
+
/**
|
|
9096
|
+
* Reduces a field to a plain object with a fixed key order, covering every
|
|
9097
|
+
* option any relationship-implementer field can declare, so two fields can
|
|
9098
|
+
* be compared for exact equality via `JSON.stringify` regardless of the key
|
|
9099
|
+
* order the schema author happened to write them in.
|
|
9100
|
+
*
|
|
9101
|
+
* `options.as` is included and is *not* special-cased: every contributor to
|
|
9102
|
+
* a given field name on an abstract type - including the abstract type's
|
|
9103
|
+
* own schema, if it has one - is expected to declare `as` equal to that
|
|
9104
|
+
* abstract type's own name. This is redundant/self-referential for the
|
|
9105
|
+
* abstract type's own schema, but required for consistency: relationship
|
|
9106
|
+
* resolution elsewhere (e.g. `inverse` name-matching) does not itself
|
|
9107
|
+
* validate `as`, so a field with a missing or incorrect `as` can otherwise
|
|
9108
|
+
* be silently pulled into a relationship it never declared it implements.
|
|
9109
|
+
*/
|
|
9110
|
+
function comparableAbstractFieldShape(field) {
|
|
9111
|
+
const {
|
|
9112
|
+
kind,
|
|
9113
|
+
name,
|
|
9114
|
+
type,
|
|
9115
|
+
sourceKey,
|
|
9116
|
+
options
|
|
9117
|
+
} = field;
|
|
9118
|
+
return {
|
|
9119
|
+
kind,
|
|
9120
|
+
name,
|
|
9121
|
+
type,
|
|
9122
|
+
sourceKey,
|
|
9123
|
+
options: {
|
|
9124
|
+
as: options?.as,
|
|
9125
|
+
async: options?.async,
|
|
9126
|
+
inverse: options?.inverse,
|
|
9127
|
+
polymorphic: options?.polymorphic,
|
|
9128
|
+
linksMode: options?.linksMode,
|
|
9129
|
+
resetOnRemoteUpdate: options?.resetOnRemoteUpdate,
|
|
9130
|
+
arrayExtensions: options?.arrayExtensions
|
|
9131
|
+
}
|
|
9132
|
+
};
|
|
9133
|
+
}
|
|
9134
|
+
|
|
9135
|
+
/**
|
|
9136
|
+
* Asserts that two contributions to the same field name on an abstract
|
|
9137
|
+
* polymorphic type - whether from two different concrete implementers, or
|
|
9138
|
+
* from an implementer and the abstract type's own schema - declare an
|
|
9139
|
+
* identical shape: `kind`, `type`, and every option, including `as` (which
|
|
9140
|
+
* every contributor, the abstract type's own schema included, must declare
|
|
9141
|
+
* equal to `abstractType`). A mismatch here (e.g. one implementer's field
|
|
9142
|
+
* being a `hasMany` while another's is a `belongsTo`, the two disagreeing on
|
|
9143
|
+
* `inverse`/`async`/`polymorphic`, or one omitting or misdeclaring `as`)
|
|
9144
|
+
* cannot be resolved by picking one side arbitrarily, since that would
|
|
9145
|
+
* silently leave whichever side lost the mismatch pointing at a relationship
|
|
9146
|
+
* whose true shape differs from what its own schema declared.
|
|
9147
|
+
*/
|
|
9148
|
+
function assertConsistentAbstractFieldShape(abstractType, fieldName, existing, incoming) {
|
|
9149
|
+
// This function exists solely to support the `assert()` call below - there
|
|
9150
|
+
// is no other work here with an effect in production. Since `assert()`'s
|
|
9151
|
+
// own babel-macro stripping only removes the call expression itself, not
|
|
9152
|
+
// the (comparatively expensive, involving `JSON.stringify`) computation of
|
|
9153
|
+
// its arguments, guard the whole body so none of it survives in production
|
|
9154
|
+
// builds, matching how `assertPolymorphicType`/`assertInheritedSchema` and
|
|
9155
|
+
// their call sites are gated in `assert-polymorphic-type.ts`.
|
|
9156
|
+
{
|
|
9157
|
+
const existingShape = comparableAbstractFieldShape(existing.field);
|
|
9158
|
+
const incomingShape = comparableAbstractFieldShape(incoming.field);
|
|
9159
|
+
(test => {
|
|
9160
|
+
if (!test) {
|
|
9161
|
+
throw new Error(`Expected the relationship '${fieldName}' on the abstract polymorphic type '${abstractType}' to be declared identically everywhere it is implemented (including 'options.as', which every contributor - the abstract type's own schema included - must declare equal to '${abstractType}'), but '${existing.source}' declares it as:\n\n${JSON.stringify(existingShape, null, 2)}\n\nwhile '${incoming.source}' declares it as:\n\n${JSON.stringify(incomingShape, null, 2)}\n\nAll concrete implementers of an abstract type - and the abstract type's own schema, if it has one - must declare an identical shape for any relationship field they share.`);
|
|
9162
|
+
}
|
|
9163
|
+
})(JSON.stringify(existingShape) === JSON.stringify(incomingShape));
|
|
9164
|
+
}
|
|
9165
|
+
}
|
|
9032
9166
|
/**
|
|
9033
9167
|
* Wraps a derivation in a new function with Derivation signature but that looks
|
|
9034
9168
|
* up the value in the cache before recomputing.
|
|
@@ -9068,6 +9202,18 @@ class SchemaService {
|
|
|
9068
9202
|
|
|
9069
9203
|
/** @internal */
|
|
9070
9204
|
|
|
9205
|
+
/**
|
|
9206
|
+
* Tracks, per abstract type, the relationship fields that concrete
|
|
9207
|
+
* implementers have contributed via `options.as`, along with the type
|
|
9208
|
+
* that contributed each one (for assertion messages). This is
|
|
9209
|
+
* independent of whatever schema (synthesized or user-registered)
|
|
9210
|
+
* currently occupies `_schemas` for that type, so that these fields
|
|
9211
|
+
* survive regardless of the order in which the abstract type's
|
|
9212
|
+
* implementers and its own (optional) concrete schema are registered.
|
|
9213
|
+
*
|
|
9214
|
+
* @internal
|
|
9215
|
+
*/
|
|
9216
|
+
|
|
9071
9217
|
/** @internal */
|
|
9072
9218
|
|
|
9073
9219
|
/** @internal */
|
|
@@ -9079,6 +9225,7 @@ class SchemaService {
|
|
|
9079
9225
|
this._derivations = new Map();
|
|
9080
9226
|
this._traits = new Map();
|
|
9081
9227
|
this._modes = new Map();
|
|
9228
|
+
this._abstractImplementerFields = new Map();
|
|
9082
9229
|
this._extensions = {
|
|
9083
9230
|
object: new Map(),
|
|
9084
9231
|
array: new Map()
|
|
@@ -9174,6 +9321,7 @@ class SchemaService {
|
|
|
9174
9321
|
const fields = new Map();
|
|
9175
9322
|
const relationships = {};
|
|
9176
9323
|
const attributes = {};
|
|
9324
|
+
const abstractImplementations = [];
|
|
9177
9325
|
for (const field of schema.fields) {
|
|
9178
9326
|
(test => {
|
|
9179
9327
|
if (!test) {
|
|
@@ -9187,6 +9335,31 @@ class SchemaService {
|
|
|
9187
9335
|
attributes[field.name] = field;
|
|
9188
9336
|
} else if (field.kind === 'belongsTo' || field.kind === 'hasMany') {
|
|
9189
9337
|
relationships[field.name] = field;
|
|
9338
|
+
if (field.options?.as) {
|
|
9339
|
+
abstractImplementations.push(field);
|
|
9340
|
+
}
|
|
9341
|
+
}
|
|
9342
|
+
}
|
|
9343
|
+
|
|
9344
|
+
// This type may already be known as an abstract polymorphic type,
|
|
9345
|
+
// implemented by other concrete types via `options.as`, from before it
|
|
9346
|
+
// ever had a schema of its own (see `_registerAbstractTypeImplementation`).
|
|
9347
|
+
// Carry those previously-contributed fields forward so that registering
|
|
9348
|
+
// a "real" schema for the type - whenever that happens to occur - never
|
|
9349
|
+
// erases the relationships its implementers depend on.
|
|
9350
|
+
const implementerFields = this._abstractImplementerFields.get(schema.type);
|
|
9351
|
+
if (implementerFields) {
|
|
9352
|
+
for (const [name, contribution] of implementerFields) {
|
|
9353
|
+
const ownField = fields.get(name);
|
|
9354
|
+
if (!ownField) {
|
|
9355
|
+
fields.set(name, contribution.field);
|
|
9356
|
+
relationships[name] = contribution.field;
|
|
9357
|
+
} else {
|
|
9358
|
+
assertConsistentAbstractFieldShape(schema.type, name, contribution, {
|
|
9359
|
+
field: ownField,
|
|
9360
|
+
source: schema.type
|
|
9361
|
+
});
|
|
9362
|
+
}
|
|
9190
9363
|
}
|
|
9191
9364
|
}
|
|
9192
9365
|
const cacheFields = null;
|
|
@@ -9205,6 +9378,101 @@ class SchemaService {
|
|
|
9205
9378
|
internalSchema.cacheFields = getCacheFields(internalSchema);
|
|
9206
9379
|
}
|
|
9207
9380
|
this._schemas.set(schema.type, internalSchema);
|
|
9381
|
+
|
|
9382
|
+
// A relationship field's `as` option marks it as a valid concrete
|
|
9383
|
+
// implementer of an abstract polymorphic type (e.g. `as: 'commentable'`).
|
|
9384
|
+
// That abstract type may never be given its own schema by the user - it
|
|
9385
|
+
// may exist only to be implemented by concrete types like this one - or
|
|
9386
|
+
// it may already have (or later receive) a schema of its own, e.g. if it
|
|
9387
|
+
// turns out to also be a real, directly-resolvable resource. Either way,
|
|
9388
|
+
// ensure it has a schema with this field present, so that it behaves
|
|
9389
|
+
// like any other registered resource (`hasResource`, `fields`, etc.)
|
|
9390
|
+
// instead of requiring special-casing wherever abstract relationship
|
|
9391
|
+
// types are resolved.
|
|
9392
|
+
for (const field of abstractImplementations) {
|
|
9393
|
+
this._registerAbstractTypeImplementation(field, schema.type);
|
|
9394
|
+
}
|
|
9395
|
+
}
|
|
9396
|
+
|
|
9397
|
+
/** @internal */
|
|
9398
|
+
_registerAbstractTypeImplementation(field, implementer) {
|
|
9399
|
+
const abstractType = field.options.as;
|
|
9400
|
+
let implementerFields = this._abstractImplementerFields.get(abstractType);
|
|
9401
|
+
if (!implementerFields) {
|
|
9402
|
+
implementerFields = new Map();
|
|
9403
|
+
this._abstractImplementerFields.set(abstractType, implementerFields);
|
|
9404
|
+
}
|
|
9405
|
+
|
|
9406
|
+
// Unlike the original approach this replaced, `as` is *not* stripped here:
|
|
9407
|
+
// the field as synthesized onto the abstract type's own schema keeps
|
|
9408
|
+
// `options.as === abstractType`, redundant/self-referential as that is.
|
|
9409
|
+
// This keeps every contributor - implementers and the abstract type's
|
|
9410
|
+
// own schema alike - declaring the same thing, which is what
|
|
9411
|
+
// `assertConsistentAbstractFieldShape` checks, and it is also what lets
|
|
9412
|
+
// `assertPolymorphicType` (which reads a field's declared `as` off
|
|
9413
|
+
// whatever `schema.fields()` serves for its type) correctly permit the
|
|
9414
|
+
// abstract type itself to be pushed directly into this relationship.
|
|
9415
|
+
const abstractField = {
|
|
9416
|
+
...field
|
|
9417
|
+
};
|
|
9418
|
+
const contribution = {
|
|
9419
|
+
field: abstractField,
|
|
9420
|
+
source: implementer
|
|
9421
|
+
};
|
|
9422
|
+
|
|
9423
|
+
// all concrete implementations of an abstract type are required to
|
|
9424
|
+
// share the same shape for the field that implements it, so the first
|
|
9425
|
+
// one registered is as good a canonical source as any - but a later,
|
|
9426
|
+
// differently-shaped one is almost certainly a mistake rather than an
|
|
9427
|
+
// intentional override, so we catch it rather than silently ignoring it.
|
|
9428
|
+
const existingImplementer = implementerFields.get(field.name);
|
|
9429
|
+
if (existingImplementer) {
|
|
9430
|
+
{
|
|
9431
|
+
assertConsistentAbstractFieldShape(abstractType, field.name, existingImplementer, contribution);
|
|
9432
|
+
}
|
|
9433
|
+
return;
|
|
9434
|
+
}
|
|
9435
|
+
implementerFields.set(field.name, contribution);
|
|
9436
|
+
let abstractSchema = this._schemas.get(abstractType);
|
|
9437
|
+
if (!abstractSchema) {
|
|
9438
|
+
abstractSchema = {
|
|
9439
|
+
original: {
|
|
9440
|
+
legacy: true,
|
|
9441
|
+
identity: {
|
|
9442
|
+
kind: '@id',
|
|
9443
|
+
name: 'id'
|
|
9444
|
+
},
|
|
9445
|
+
type: abstractType,
|
|
9446
|
+
fields: []
|
|
9447
|
+
},
|
|
9448
|
+
finalized: true,
|
|
9449
|
+
fields: new Map(),
|
|
9450
|
+
cacheFields: new Map(),
|
|
9451
|
+
relationships: {},
|
|
9452
|
+
attributes: {},
|
|
9453
|
+
traits: new Set()
|
|
9454
|
+
};
|
|
9455
|
+
this._schemas.set(abstractType, abstractSchema);
|
|
9456
|
+
}
|
|
9457
|
+
const existingAbstractField = abstractSchema.fields.get(field.name);
|
|
9458
|
+
if (existingAbstractField) {
|
|
9459
|
+
{
|
|
9460
|
+
assertConsistentAbstractFieldShape(abstractType, field.name, {
|
|
9461
|
+
field: existingAbstractField,
|
|
9462
|
+
source: abstractType
|
|
9463
|
+
}, contribution);
|
|
9464
|
+
}
|
|
9465
|
+
return;
|
|
9466
|
+
}
|
|
9467
|
+
abstractSchema.fields.set(field.name, abstractField);
|
|
9468
|
+
abstractSchema.relationships[field.name] = abstractField;
|
|
9469
|
+
|
|
9470
|
+
// If the schema is mid-finalization (traits pending), finalizeResource
|
|
9471
|
+
// will recompute cacheFields from the current `fields` map anyway; avoid
|
|
9472
|
+
// doing so prematurely from a partially-resolved set of fields.
|
|
9473
|
+
if (abstractSchema.finalized) {
|
|
9474
|
+
abstractSchema.cacheFields = getCacheFields(abstractSchema);
|
|
9475
|
+
}
|
|
9208
9476
|
}
|
|
9209
9477
|
|
|
9210
9478
|
/**
|
|
@@ -9490,9 +9758,33 @@ function cloneResponse(response, overrides) {
|
|
|
9490
9758
|
const props = cloneResponseProperties(response);
|
|
9491
9759
|
return new Response(response.body, Object.assign(props, overrides));
|
|
9492
9760
|
}
|
|
9761
|
+
function withDateHeader(response) {
|
|
9762
|
+
const headers = new Headers(response.headers);
|
|
9763
|
+
headers.set('date', new Date().toUTCString());
|
|
9764
|
+
return cloneResponse(response, {
|
|
9765
|
+
headers
|
|
9766
|
+
});
|
|
9767
|
+
}
|
|
9768
|
+
|
|
9769
|
+
// Detects Mirage (or another Pretender-based fetch mock), whose `Response`
|
|
9770
|
+
// may (unlike a spec-compliant `fetch()`, whose Response headers are always
|
|
9771
|
+
// immutable) allow header mutation and may not support streaming reads.
|
|
9772
|
+
//
|
|
9773
|
+
// This is inherently a heuristic - many legitimate tools (APM/monitoring
|
|
9774
|
+
// agents, browser extensions, polyfills) also patch `window.fetch`, and can
|
|
9775
|
+
// produce false positives. `setWarpDriveIsMaybeMirage(value)` lets an app
|
|
9776
|
+
// declare the answer explicitly (`true` or `false`), overriding the
|
|
9777
|
+
// heuristic in either direction; leave it unset to keep the default
|
|
9778
|
+
// detection. See https://github.com/warp-drive-data/warp-drive/issues/10535
|
|
9493
9779
|
let IS_MAYBE_MIRAGE = () => false;
|
|
9494
9780
|
{
|
|
9495
|
-
IS_MAYBE_MIRAGE = () =>
|
|
9781
|
+
IS_MAYBE_MIRAGE = () => {
|
|
9782
|
+
const override = getRuntimeConfig().mirage;
|
|
9783
|
+
if (override !== undefined) {
|
|
9784
|
+
return override;
|
|
9785
|
+
}
|
|
9786
|
+
return Boolean(typeof window !== 'undefined' && (window.server?.pretender || window.fetch.toString().replace(/\s+/g, '') !== 'function fetch() { [native code] }'.replace(/\s+/g, '')));
|
|
9787
|
+
};
|
|
9496
9788
|
}
|
|
9497
9789
|
const MUTATION_OPS = new Set(['updateRecord', 'createRecord', 'deleteRecord']);
|
|
9498
9790
|
const ERROR_STATUS_CODE_FOR = new Map([[400, 'Bad Request'], [401, 'Unauthorized'], [402, 'Payment Required'], [403, 'Forbidden'], [404, 'Not Found'], [405, 'Method Not Allowed'], [406, 'Not Acceptable'], [407, 'Proxy Authentication Required'], [408, 'Request Timeout'], [409, 'Conflict'], [410, 'Gone'], [411, 'Length Required'], [412, 'Precondition Failed'], [413, 'Payload Too Large'], [414, 'URI Too Long'], [415, 'Unsupported Media Type'], [416, 'Range Not Satisfiable'], [417, 'Expectation Failed'], [419, 'Page Expired'], [420, 'Enhance Your Calm'], [421, 'Misdirected Request'], [422, 'Unprocessable Entity'], [423, 'Locked'], [424, 'Failed Dependency'], [425, 'Too Early'], [426, 'Upgrade Required'], [428, 'Precondition Required'], [429, 'Too Many Requests'], [430, 'Request Header Fields Too Large'], [431, 'Request Header Fields Too Large'], [450, 'Blocked By Windows Parental Controls'], [451, 'Unavailable For Legal Reasons'], [500, 'Internal Server Error'], [501, 'Not Implemented'], [502, 'Bad Gateway'], [503, 'Service Unavailable'], [504, 'Gateway Timeout'], [505, 'HTTP Version Not Supported'], [506, 'Variant Also Negotiates'], [507, 'Insufficient Storage'], [508, 'Loop Detected'], [509, 'Bandwidth Limit Exceeded'], [510, 'Not Extended'], [511, 'Network Authentication Required']]);
|
|
@@ -9544,13 +9836,15 @@ const Fetch = {
|
|
|
9544
9836
|
const isMutationOp = Boolean(op && MUTATION_OPS.has(op));
|
|
9545
9837
|
if (!isError && !isMutationOp && response.status !== 204 && !response.headers.has('date')) {
|
|
9546
9838
|
if (IS_MAYBE_MIRAGE()) {
|
|
9547
|
-
|
|
9839
|
+
try {
|
|
9840
|
+
response.headers.set('date', new Date().toUTCString());
|
|
9841
|
+
} catch {
|
|
9842
|
+
// IS_MAYBE_MIRAGE() was a false positive, or the mock's headers
|
|
9843
|
+
// are (correctly) immutable - fall back to cloning.
|
|
9844
|
+
response = withDateHeader(response);
|
|
9845
|
+
}
|
|
9548
9846
|
} else {
|
|
9549
|
-
|
|
9550
|
-
headers.set('date', new Date().toUTCString());
|
|
9551
|
-
response = cloneResponse(response, {
|
|
9552
|
-
headers
|
|
9553
|
-
});
|
|
9847
|
+
response = withDateHeader(response);
|
|
9554
9848
|
}
|
|
9555
9849
|
}
|
|
9556
9850
|
context.setResponse(response);
|
|
@@ -9945,6 +10239,12 @@ class RequestManager {
|
|
|
9945
10239
|
globalThis.getWarpDriveRuntimeConfig = getRuntimeConfig;
|
|
9946
10240
|
}
|
|
9947
10241
|
|
|
10242
|
+
// Mirage (or another Pretender-based fetch mock) may be used outside of a
|
|
10243
|
+
// `TESTING` build (e.g. `ember serve` in dev mode), so this override is
|
|
10244
|
+
// exposed unconditionally rather than gated to the `TESTING` env.
|
|
10245
|
+
// @ts-expect-error adding to globalThis
|
|
10246
|
+
globalThis.setWarpDriveIsMaybeMirage = setIsMaybeMirage;
|
|
10247
|
+
|
|
9948
10248
|
/**
|
|
9949
10249
|
* Options for setting up a Store instance with `useRecommendedStore`.
|
|
9950
10250
|
*/
|
|
@@ -9965,7 +10265,29 @@ class RequestManager {
|
|
|
9965
10265
|
*/
|
|
9966
10266
|
function useRecommendedStore(options, StoreKlass = Store) {
|
|
9967
10267
|
return class AppStore extends StoreKlass {
|
|
9968
|
-
|
|
10268
|
+
constructor(createArgs) {
|
|
10269
|
+
super(createArgs);
|
|
10270
|
+
// installed via defineProperty (rather than a class field/accessor) so that
|
|
10271
|
+
// this lazy override of the inherited `requestManager` field does not
|
|
10272
|
+
// conflict with the documented pattern of assigning it directly on
|
|
10273
|
+
// consumer-authored Store subclasses. The setter preserves the ability
|
|
10274
|
+
// to replace `requestManager` outright after construction.
|
|
10275
|
+
let requestManager;
|
|
10276
|
+
Object.defineProperty(this, 'requestManager', {
|
|
10277
|
+
configurable: true,
|
|
10278
|
+
enumerable: true,
|
|
10279
|
+
get: () => {
|
|
10280
|
+
if (!requestManager) {
|
|
10281
|
+
const handlers = typeof options.handlers === 'function' ? options.handlers(this) : options.handlers ?? [];
|
|
10282
|
+
requestManager = new RequestManager().use([...handlers, Fetch]).useCache(CacheHandler);
|
|
10283
|
+
}
|
|
10284
|
+
return requestManager;
|
|
10285
|
+
},
|
|
10286
|
+
set: value => {
|
|
10287
|
+
requestManager = value;
|
|
10288
|
+
}
|
|
10289
|
+
});
|
|
10290
|
+
}
|
|
9969
10291
|
lifetimes = options.policy ?? new DefaultCachePolicy({
|
|
9970
10292
|
apiCacheHardExpires: 15 * 60 * 1000,
|
|
9971
10293
|
// 15 minutes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CacheHandler, F as Fetch, z as RequestManager, S as Store, r as cacheKeyFor, r as recordIdentifierFor, E as setIdentifierForgetMethod, B as setIdentifierGenerationMethod, G as setIdentifierResetMethod, D as setIdentifierUpdateMethod, H as setKeyInfoForResource, s as storeFor, A as useRecommendedStore } from "./index-
|
|
1
|
+
export { C as CacheHandler, F as Fetch, z as RequestManager, S as Store, r as cacheKeyFor, r as recordIdentifierFor, E as setIdentifierForgetMethod, B as setIdentifierGenerationMethod, G as setIdentifierResetMethod, D as setIdentifierUpdateMethod, H as setKeyInfoForResource, s as storeFor, A as useRecommendedStore } from "./index-BYFUHVPd.js";
|
|
2
2
|
import "./-private-3C1OkYtZ.js";
|
|
3
3
|
import "./-leaked-C40gfiH-.js";
|
|
4
4
|
import './store.js';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { u as SchemaService, p as checkout, y as commit, v as fromIdentity, q as instantiateRecord, x as registerDerivations, t as teardownRecord, w as withDefaults } from "./index-
|
|
1
|
+
export { u as SchemaService, p as checkout, y as commit, v as fromIdentity, q as instantiateRecord, x as registerDerivations, t as teardownRecord, w as withDefaults } from "./index-BYFUHVPd.js";
|
|
2
2
|
export { C as Checkout } from "./-private-3C1OkYtZ.js";
|
|
3
3
|
export { c as createRequestSubscription, a as getPromiseState, g as getRequestState } from "./-leaked-C40gfiH-.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as CacheHandler, R as RecordArrayManager, S as Store, k as StoreMap, _ as _clearCaches, n as _deprecatingNormalize, h as assertPrivateCapabilities, d as assertPrivateStore, b as coerceId, c as constructResource, l as createLegacyManyArray, e as ensureStringId, f as fastPush, g as isPrivateStore, a as isRequestKey, i as isResourceKey, m as log, o as logGroup, r as recordIdentifierFor, j as setRecordIdentifier, s as storeFor } from "../index-
|
|
1
|
+
export { C as CacheHandler, R as RecordArrayManager, S as Store, k as StoreMap, _ as _clearCaches, n as _deprecatingNormalize, h as assertPrivateCapabilities, d as assertPrivateStore, b as coerceId, c as constructResource, l as createLegacyManyArray, e as ensureStringId, f as fastPush, g as isPrivateStore, a as isRequestKey, i as isResourceKey, m as log, o as logGroup, r as recordIdentifierFor, j as setRecordIdentifier, s as storeFor } from "../index-BYFUHVPd.js";
|
|
@@ -31,4 +31,23 @@ function setLogging(config) {
|
|
|
31
31
|
Object.assign(RuntimeConfig.debug, config);
|
|
32
32
|
storage?.setItem('WarpDriveRuntimeConfig', JSON.stringify(RuntimeConfig));
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Explicitly declares whether requests may be served by Mirage (or another
|
|
37
|
+
* Pretender-based fetch mock) instead of a native `fetch` implementation.
|
|
38
|
+
*
|
|
39
|
+
* The `Fetch` request handler otherwise infers this via a heuristic (the
|
|
40
|
+
* presence of `window.server.pretender`, or `window.fetch` appearing to be
|
|
41
|
+
* patched), which can be wrong in either direction: some Mirage setups don't
|
|
42
|
+
* expose `window.server`, while some unrelated tools (APM agents, browser
|
|
43
|
+
* extensions) also patch `fetch`. Call this to override that heuristic:
|
|
44
|
+
* `true` to force Mirage-compatible behavior on, `false` to force it off.
|
|
45
|
+
*
|
|
46
|
+
* globalThis.setWarpDriveIsMaybeMirage(true);
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
function setIsMaybeMirage(value) {
|
|
50
|
+
RuntimeConfig.mirage = value;
|
|
51
|
+
storage?.setItem('WarpDriveRuntimeConfig', JSON.stringify(RuntimeConfig));
|
|
52
|
+
}
|
|
53
|
+
export { getRuntimeConfig, setIsMaybeMirage, setLogging };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { peekTransient, getOrSetGlobal, setTransient } from './types/-private.js';
|
|
2
|
-
import {
|
|
2
|
+
import { g as getPromiseResult, a as setPromiseResult } from "./promise-cache-DUblkX-U.js";
|
|
3
3
|
|
|
4
4
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5
5
|
|
|
@@ -1673,4 +1673,4 @@ function getPromiseState(promise) {
|
|
|
1673
1673
|
}
|
|
1674
1674
|
return state;
|
|
1675
1675
|
}
|
|
1676
|
-
export { ARRAY_SIGNAL as A, DISPOSE as D, OBJECT_SIGNAL as O, Signals as S,
|
|
1676
|
+
export { ARRAY_SIGNAL as A, DISPOSE as D, OBJECT_SIGNAL as O, Signals as S, willSyncFlushWatchers as a, createInternalSignal as b, consumeInternalSignal as c, defineGate as d, createSignalDescriptor as e, defineSignal as f, getOrCreateInternalSignal as g, entangleSignal as h, entangleInitiallyStaleSignal as i, createInternalMemo as j, createRequestSubscription as k, getRequestState as l, getPromiseState as m, notifyInternalSignal as n, defineNonEnumerableSignal as o, peekInternalSignal as p, makeInitializer as q, signal as r, setupSignals as s, waitFor as t, gate as u, memoized as v, withSignalStore as w };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { s as setupSignals } from "./-leaked-
|
|
1
|
+
export { s as setupSignals } from "./-leaked-DgjQ5X55.js";
|
|
2
2
|
import './types/-private.js';
|
|
@@ -789,8 +789,10 @@ function replaceRelatedRecord(graph, op, isRemote = false) {
|
|
|
789
789
|
if (op.value === existingState) {
|
|
790
790
|
// if we were empty before but now know we are empty this needs to be true
|
|
791
791
|
state.hasReceivedData = true;
|
|
792
|
+
|
|
792
793
|
// if this is a remote update we still sync
|
|
793
794
|
if (isRemote) {
|
|
795
|
+
state.hasReceivedRemoteData = true;
|
|
794
796
|
const {
|
|
795
797
|
localState
|
|
796
798
|
} = relationship;
|
|
@@ -813,6 +815,15 @@ function replaceRelatedRecord(graph, op, isRemote = false) {
|
|
|
813
815
|
// update value to the new value
|
|
814
816
|
relationship[prop] = op.value;
|
|
815
817
|
state.hasReceivedData = true;
|
|
818
|
+
/**
|
|
819
|
+
* Local mutations never give us additional information about
|
|
820
|
+
* whether the relationship has received *remote* data. This is
|
|
821
|
+
* what `getRemoteRelationship` relies on to avoid reflecting
|
|
822
|
+
* local-only edits.
|
|
823
|
+
*/
|
|
824
|
+
if (isRemote) {
|
|
825
|
+
state.hasReceivedRemoteData = true;
|
|
826
|
+
}
|
|
816
827
|
state.isEmpty = op.value === null;
|
|
817
828
|
state.isStale = false;
|
|
818
829
|
state.hasFailedLoadAttempt = false;
|
|
@@ -1206,6 +1217,7 @@ function rollbackRelationship(graph, key, field, relationship) {
|
|
|
1206
1217
|
function createState() {
|
|
1207
1218
|
return {
|
|
1208
1219
|
hasReceivedData: false,
|
|
1220
|
+
hasReceivedRemoteData: false,
|
|
1209
1221
|
isEmpty: true,
|
|
1210
1222
|
isStale: false,
|
|
1211
1223
|
hasFailedLoadAttempt: false,
|
|
@@ -1310,13 +1322,10 @@ function legacyGetResourceRelationshipData(source, getRemoteState) {
|
|
|
1310
1322
|
source.accessed = true;
|
|
1311
1323
|
let data;
|
|
1312
1324
|
const payload = {};
|
|
1313
|
-
if (getRemoteState && source.remoteState) {
|
|
1314
|
-
data = source.remoteState;
|
|
1315
|
-
} else if (!getRemoteState && source.localState) {
|
|
1316
|
-
data = source.localState;
|
|
1317
|
-
}
|
|
1318
|
-
if ((getRemoteState && source.remoteState === null || source.localState === null) && source.state.hasReceivedData) {
|
|
1319
|
-
data = null;
|
|
1325
|
+
if (getRemoteState && (source.remoteState || source.state.hasReceivedRemoteData)) {
|
|
1326
|
+
data = source.remoteState ?? null;
|
|
1327
|
+
} else if (!getRemoteState && (source.localState || source.state.hasReceivedData)) {
|
|
1328
|
+
data = source.localState ?? null;
|
|
1320
1329
|
}
|
|
1321
1330
|
if (source.links) {
|
|
1322
1331
|
payload.links = source.links;
|
|
@@ -1493,7 +1502,6 @@ function updateRelationshipOperation(graph, op) {
|
|
|
1493
1502
|
const relationship = graph.get(op.record, op.field);
|
|
1494
1503
|
const {
|
|
1495
1504
|
definition,
|
|
1496
|
-
state,
|
|
1497
1505
|
identifier
|
|
1498
1506
|
} = relationship;
|
|
1499
1507
|
const {
|
|
@@ -1528,23 +1536,6 @@ function updateRelationshipOperation(graph, op) {
|
|
|
1528
1536
|
value: payload.data ? graph.store.cacheKeyManager.upgradeIdentifier(payload.data) : null
|
|
1529
1537
|
}, true);
|
|
1530
1538
|
}
|
|
1531
|
-
} else if (definition.isAsync === false && !state.hasReceivedData) {
|
|
1532
|
-
hasRelationshipDataProperty = true;
|
|
1533
|
-
if (isCollection) {
|
|
1534
|
-
graph.update({
|
|
1535
|
-
op: 'replaceRelatedRecords',
|
|
1536
|
-
record: identifier,
|
|
1537
|
-
field: op.field,
|
|
1538
|
-
value: []
|
|
1539
|
-
}, true);
|
|
1540
|
-
} else {
|
|
1541
|
-
graph.update({
|
|
1542
|
-
op: 'replaceRelatedRecord',
|
|
1543
|
-
record: identifier,
|
|
1544
|
-
field: op.field,
|
|
1545
|
-
value: null
|
|
1546
|
-
}, true);
|
|
1547
|
-
}
|
|
1548
1539
|
}
|
|
1549
1540
|
if (payload.links) {
|
|
1550
1541
|
const originalLinks = relationship.links;
|
|
@@ -1579,6 +1570,7 @@ function updateRelationshipOperation(graph, op) {
|
|
|
1579
1570
|
// we don't need to notify here as the update op we pushed in above will notify once
|
|
1580
1571
|
// membership is in the correct state.
|
|
1581
1572
|
relationship.state.hasReceivedData = true;
|
|
1573
|
+
relationship.state.hasReceivedRemoteData = true;
|
|
1582
1574
|
relationship.state.isStale = false;
|
|
1583
1575
|
relationship.state.hasDematerializedInverse = false;
|
|
1584
1576
|
relationship.state.isEmpty = relationshipIsEmpty;
|