@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
|
@@ -4,13 +4,13 @@ import { EnableHydration, SkipCache, STRUCTURED } from './types/request.js';
|
|
|
4
4
|
import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from '@embroider/macros';
|
|
5
5
|
import { D as Destroy, a as Context, S as SOURCE, C as Checkout, b as Commit } from "./symbols-3C1OkYtZ.js";
|
|
6
6
|
import { isResourceSchema } from './types/schema/fields.js';
|
|
7
|
+
import { setLogging, getRuntimeConfig, setIsMaybeMirage } from './types/runtime.js';
|
|
7
8
|
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-CPfkKOvf.js";
|
|
8
9
|
import { getOrSetGlobal, peekTransient, setTransient, peekUniversalTransient, setUniversalTransient } from './types/-private.js';
|
|
9
10
|
import { D as DefaultCachePolicy } from "./default-cache-policy-D7_u4YRH.js";
|
|
10
11
|
import { withBrand } from './request.js';
|
|
11
12
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_KEY_TYPE, DEBUG_CLIENT_ORIGINATED } from './types/identifier.js';
|
|
12
13
|
import { dasherize } from './utils/string.js';
|
|
13
|
-
import { setLogging, getRuntimeConfig } from './types/runtime.js';
|
|
14
14
|
import { RecordStore, Type } from './types/symbols.js';
|
|
15
15
|
function urlFromLink(link) {
|
|
16
16
|
if (typeof link === 'string') return link;
|
|
@@ -7281,11 +7281,32 @@ function getBelongsToField(context) {
|
|
|
7281
7281
|
}
|
|
7282
7282
|
function setBelongsToField(context) {
|
|
7283
7283
|
const {
|
|
7284
|
+
field,
|
|
7285
|
+
resourceKey,
|
|
7284
7286
|
store
|
|
7285
7287
|
} = context;
|
|
7286
7288
|
const {
|
|
7287
|
-
schema
|
|
7289
|
+
schema,
|
|
7290
|
+
cache
|
|
7288
7291
|
} = store;
|
|
7292
|
+
|
|
7293
|
+
/**
|
|
7294
|
+
* We currently only allow editing sync belongsTo relationships
|
|
7295
|
+
* in PolarisMode
|
|
7296
|
+
*/
|
|
7297
|
+
const isValidPolarisConfig = field.options.linksMode && !field.options.async;
|
|
7298
|
+
if (!context.legacy && isValidPolarisConfig) {
|
|
7299
|
+
const name = context.path.at(-1);
|
|
7300
|
+
cache.mutate({
|
|
7301
|
+
op: 'replaceRelatedRecord',
|
|
7302
|
+
record: resourceKey,
|
|
7303
|
+
field: name,
|
|
7304
|
+
value: getResourceKey(context.value)
|
|
7305
|
+
},
|
|
7306
|
+
// @ts-expect-error
|
|
7307
|
+
true);
|
|
7308
|
+
return true;
|
|
7309
|
+
}
|
|
7289
7310
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
7290
7311
|
if (!test) {
|
|
7291
7312
|
throw new Error(`Can only mutate belongsTo fields when the resource is in legacy mode`);
|
|
@@ -7294,6 +7315,12 @@ function setBelongsToField(context) {
|
|
|
7294
7315
|
schema._kind('@legacy', 'belongsTo').set(store, context.record, context.resourceKey, context.field, context.value);
|
|
7295
7316
|
return true;
|
|
7296
7317
|
}
|
|
7318
|
+
function getResourceKey(record) {
|
|
7319
|
+
if (!record) {
|
|
7320
|
+
return null;
|
|
7321
|
+
}
|
|
7322
|
+
return recordIdentifierFor(record);
|
|
7323
|
+
}
|
|
7297
7324
|
function getCollectionField(context) {
|
|
7298
7325
|
entangleSignal(context.signals, context.record, context.path.at(-1), null);
|
|
7299
7326
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
@@ -8029,6 +8056,17 @@ function setSchemaObjectField(context) {
|
|
|
8029
8056
|
// }
|
|
8030
8057
|
return true;
|
|
8031
8058
|
}
|
|
8059
|
+
|
|
8060
|
+
/**
|
|
8061
|
+
* A ReactiveResource context object passed to
|
|
8062
|
+
* the get/set functions of a field kind implementation.
|
|
8063
|
+
*
|
|
8064
|
+
* This provides all the necessary information for
|
|
8065
|
+
* the field kind to perform its operations.
|
|
8066
|
+
*
|
|
8067
|
+
* @internal
|
|
8068
|
+
*/
|
|
8069
|
+
|
|
8032
8070
|
const DefaultMode = {
|
|
8033
8071
|
'@hash': {
|
|
8034
8072
|
get: getHashField,
|
|
@@ -8324,6 +8362,9 @@ class ReactiveResource {
|
|
|
8324
8362
|
if (prop === Destroy || prop === Checkout) {
|
|
8325
8363
|
return true;
|
|
8326
8364
|
}
|
|
8365
|
+
if (prop === identityField?.name) {
|
|
8366
|
+
return true;
|
|
8367
|
+
}
|
|
8327
8368
|
return fields.has(prop);
|
|
8328
8369
|
},
|
|
8329
8370
|
getOwnPropertyDescriptor(target, prop) {
|
|
@@ -8822,6 +8863,14 @@ const TypeField = {
|
|
|
8822
8863
|
key: 'type'
|
|
8823
8864
|
}
|
|
8824
8865
|
};
|
|
8866
|
+
const IdentifierField = {
|
|
8867
|
+
type: '@identity',
|
|
8868
|
+
name: '$key',
|
|
8869
|
+
kind: 'derived',
|
|
8870
|
+
options: {
|
|
8871
|
+
key: '^'
|
|
8872
|
+
}
|
|
8873
|
+
};
|
|
8825
8874
|
const DefaultIdentityField = {
|
|
8826
8875
|
name: 'id',
|
|
8827
8876
|
kind: '@id'
|
|
@@ -9010,6 +9059,7 @@ function withDefaults(schema) {
|
|
|
9010
9059
|
// we add TypeField to the beginning so that it will
|
|
9011
9060
|
// appear right next to the identity field
|
|
9012
9061
|
schema.fields.unshift(TypeField);
|
|
9062
|
+
schema.fields.unshift(IdentifierField);
|
|
9013
9063
|
schema.fields.push(ConstructorField);
|
|
9014
9064
|
return schema;
|
|
9015
9065
|
}
|
|
@@ -9065,6 +9115,90 @@ function registerDerivations(schema) {
|
|
|
9065
9115
|
schema.registerDerivation(fromIdentity);
|
|
9066
9116
|
schema.registerDerivation(_constructor);
|
|
9067
9117
|
}
|
|
9118
|
+
|
|
9119
|
+
/**
|
|
9120
|
+
* A relationship field capable of declaring `options.as`, marking it as a
|
|
9121
|
+
* concrete implementation of an abstract polymorphic type.
|
|
9122
|
+
*/
|
|
9123
|
+
|
|
9124
|
+
/**
|
|
9125
|
+
* A relationship field contributed to an abstract type's schema, along with
|
|
9126
|
+
* the name of the type that contributed it (either a concrete implementer,
|
|
9127
|
+
* via `options.as`, or the abstract type's own schema), for use in assertion
|
|
9128
|
+
* messages when two contributions disagree on shape.
|
|
9129
|
+
*/
|
|
9130
|
+
|
|
9131
|
+
/**
|
|
9132
|
+
* Reduces a field to a plain object with a fixed key order, covering every
|
|
9133
|
+
* option any relationship-implementer field can declare, so two fields can
|
|
9134
|
+
* be compared for exact equality via `JSON.stringify` regardless of the key
|
|
9135
|
+
* order the schema author happened to write them in.
|
|
9136
|
+
*
|
|
9137
|
+
* `options.as` is included and is *not* special-cased: every contributor to
|
|
9138
|
+
* a given field name on an abstract type - including the abstract type's
|
|
9139
|
+
* own schema, if it has one - is expected to declare `as` equal to that
|
|
9140
|
+
* abstract type's own name. This is redundant/self-referential for the
|
|
9141
|
+
* abstract type's own schema, but required for consistency: relationship
|
|
9142
|
+
* resolution elsewhere (e.g. `inverse` name-matching) does not itself
|
|
9143
|
+
* validate `as`, so a field with a missing or incorrect `as` can otherwise
|
|
9144
|
+
* be silently pulled into a relationship it never declared it implements.
|
|
9145
|
+
*/
|
|
9146
|
+
function comparableAbstractFieldShape(field) {
|
|
9147
|
+
const {
|
|
9148
|
+
kind,
|
|
9149
|
+
name,
|
|
9150
|
+
type,
|
|
9151
|
+
sourceKey,
|
|
9152
|
+
options
|
|
9153
|
+
} = field;
|
|
9154
|
+
return {
|
|
9155
|
+
kind,
|
|
9156
|
+
name,
|
|
9157
|
+
type,
|
|
9158
|
+
sourceKey,
|
|
9159
|
+
options: {
|
|
9160
|
+
as: options?.as,
|
|
9161
|
+
async: options?.async,
|
|
9162
|
+
inverse: options?.inverse,
|
|
9163
|
+
polymorphic: options?.polymorphic,
|
|
9164
|
+
linksMode: options?.linksMode,
|
|
9165
|
+
resetOnRemoteUpdate: options?.resetOnRemoteUpdate,
|
|
9166
|
+
arrayExtensions: options?.arrayExtensions
|
|
9167
|
+
}
|
|
9168
|
+
};
|
|
9169
|
+
}
|
|
9170
|
+
|
|
9171
|
+
/**
|
|
9172
|
+
* Asserts that two contributions to the same field name on an abstract
|
|
9173
|
+
* polymorphic type - whether from two different concrete implementers, or
|
|
9174
|
+
* from an implementer and the abstract type's own schema - declare an
|
|
9175
|
+
* identical shape: `kind`, `type`, and every option, including `as` (which
|
|
9176
|
+
* every contributor, the abstract type's own schema included, must declare
|
|
9177
|
+
* equal to `abstractType`). A mismatch here (e.g. one implementer's field
|
|
9178
|
+
* being a `hasMany` while another's is a `belongsTo`, the two disagreeing on
|
|
9179
|
+
* `inverse`/`async`/`polymorphic`, or one omitting or misdeclaring `as`)
|
|
9180
|
+
* cannot be resolved by picking one side arbitrarily, since that would
|
|
9181
|
+
* silently leave whichever side lost the mismatch pointing at a relationship
|
|
9182
|
+
* whose true shape differs from what its own schema declared.
|
|
9183
|
+
*/
|
|
9184
|
+
function assertConsistentAbstractFieldShape(abstractType, fieldName, existing, incoming) {
|
|
9185
|
+
// This function exists solely to support the `assert()` call below - there
|
|
9186
|
+
// is no other work here with an effect in production. Since `assert()`'s
|
|
9187
|
+
// own babel-macro stripping only removes the call expression itself, not
|
|
9188
|
+
// the (comparatively expensive, involving `JSON.stringify`) computation of
|
|
9189
|
+
// its arguments, guard the whole body so none of it survives in production
|
|
9190
|
+
// builds, matching how `assertPolymorphicType`/`assertInheritedSchema` and
|
|
9191
|
+
// their call sites are gated in `assert-polymorphic-type.ts`.
|
|
9192
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
9193
|
+
const existingShape = comparableAbstractFieldShape(existing.field);
|
|
9194
|
+
const incomingShape = comparableAbstractFieldShape(incoming.field);
|
|
9195
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
9196
|
+
if (!test) {
|
|
9197
|
+
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.`);
|
|
9198
|
+
}
|
|
9199
|
+
})(JSON.stringify(existingShape) === JSON.stringify(incomingShape)) : {};
|
|
9200
|
+
}
|
|
9201
|
+
}
|
|
9068
9202
|
/**
|
|
9069
9203
|
* Wraps a derivation in a new function with Derivation signature but that looks
|
|
9070
9204
|
* up the value in the cache before recomputing.
|
|
@@ -9104,6 +9238,18 @@ class SchemaService {
|
|
|
9104
9238
|
|
|
9105
9239
|
/** @internal */
|
|
9106
9240
|
|
|
9241
|
+
/**
|
|
9242
|
+
* Tracks, per abstract type, the relationship fields that concrete
|
|
9243
|
+
* implementers have contributed via `options.as`, along with the type
|
|
9244
|
+
* that contributed each one (for assertion messages). This is
|
|
9245
|
+
* independent of whatever schema (synthesized or user-registered)
|
|
9246
|
+
* currently occupies `_schemas` for that type, so that these fields
|
|
9247
|
+
* survive regardless of the order in which the abstract type's
|
|
9248
|
+
* implementers and its own (optional) concrete schema are registered.
|
|
9249
|
+
*
|
|
9250
|
+
* @internal
|
|
9251
|
+
*/
|
|
9252
|
+
|
|
9107
9253
|
/** @internal */
|
|
9108
9254
|
|
|
9109
9255
|
/** @internal */
|
|
@@ -9115,6 +9261,7 @@ class SchemaService {
|
|
|
9115
9261
|
this._derivations = new Map();
|
|
9116
9262
|
this._traits = new Map();
|
|
9117
9263
|
this._modes = new Map();
|
|
9264
|
+
this._abstractImplementerFields = new Map();
|
|
9118
9265
|
this._extensions = {
|
|
9119
9266
|
object: new Map(),
|
|
9120
9267
|
array: new Map()
|
|
@@ -9210,6 +9357,7 @@ class SchemaService {
|
|
|
9210
9357
|
const fields = new Map();
|
|
9211
9358
|
const relationships = {};
|
|
9212
9359
|
const attributes = {};
|
|
9360
|
+
const abstractImplementations = [];
|
|
9213
9361
|
for (const field of schema.fields) {
|
|
9214
9362
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
9215
9363
|
if (!test) {
|
|
@@ -9223,6 +9371,31 @@ class SchemaService {
|
|
|
9223
9371
|
attributes[field.name] = field;
|
|
9224
9372
|
} else if (field.kind === 'belongsTo' || field.kind === 'hasMany') {
|
|
9225
9373
|
relationships[field.name] = field;
|
|
9374
|
+
if (field.options?.as) {
|
|
9375
|
+
abstractImplementations.push(field);
|
|
9376
|
+
}
|
|
9377
|
+
}
|
|
9378
|
+
}
|
|
9379
|
+
|
|
9380
|
+
// This type may already be known as an abstract polymorphic type,
|
|
9381
|
+
// implemented by other concrete types via `options.as`, from before it
|
|
9382
|
+
// ever had a schema of its own (see `_registerAbstractTypeImplementation`).
|
|
9383
|
+
// Carry those previously-contributed fields forward so that registering
|
|
9384
|
+
// a "real" schema for the type - whenever that happens to occur - never
|
|
9385
|
+
// erases the relationships its implementers depend on.
|
|
9386
|
+
const implementerFields = this._abstractImplementerFields.get(schema.type);
|
|
9387
|
+
if (implementerFields) {
|
|
9388
|
+
for (const [name, contribution] of implementerFields) {
|
|
9389
|
+
const ownField = fields.get(name);
|
|
9390
|
+
if (!ownField) {
|
|
9391
|
+
fields.set(name, contribution.field);
|
|
9392
|
+
relationships[name] = contribution.field;
|
|
9393
|
+
} else if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
9394
|
+
assertConsistentAbstractFieldShape(schema.type, name, contribution, {
|
|
9395
|
+
field: ownField,
|
|
9396
|
+
source: schema.type
|
|
9397
|
+
});
|
|
9398
|
+
}
|
|
9226
9399
|
}
|
|
9227
9400
|
}
|
|
9228
9401
|
const cacheFields = null;
|
|
@@ -9241,6 +9414,101 @@ class SchemaService {
|
|
|
9241
9414
|
internalSchema.cacheFields = getCacheFields(internalSchema);
|
|
9242
9415
|
}
|
|
9243
9416
|
this._schemas.set(schema.type, internalSchema);
|
|
9417
|
+
|
|
9418
|
+
// A relationship field's `as` option marks it as a valid concrete
|
|
9419
|
+
// implementer of an abstract polymorphic type (e.g. `as: 'commentable'`).
|
|
9420
|
+
// That abstract type may never be given its own schema by the user - it
|
|
9421
|
+
// may exist only to be implemented by concrete types like this one - or
|
|
9422
|
+
// it may already have (or later receive) a schema of its own, e.g. if it
|
|
9423
|
+
// turns out to also be a real, directly-resolvable resource. Either way,
|
|
9424
|
+
// ensure it has a schema with this field present, so that it behaves
|
|
9425
|
+
// like any other registered resource (`hasResource`, `fields`, etc.)
|
|
9426
|
+
// instead of requiring special-casing wherever abstract relationship
|
|
9427
|
+
// types are resolved.
|
|
9428
|
+
for (const field of abstractImplementations) {
|
|
9429
|
+
this._registerAbstractTypeImplementation(field, schema.type);
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
|
|
9433
|
+
/** @internal */
|
|
9434
|
+
_registerAbstractTypeImplementation(field, implementer) {
|
|
9435
|
+
const abstractType = field.options.as;
|
|
9436
|
+
let implementerFields = this._abstractImplementerFields.get(abstractType);
|
|
9437
|
+
if (!implementerFields) {
|
|
9438
|
+
implementerFields = new Map();
|
|
9439
|
+
this._abstractImplementerFields.set(abstractType, implementerFields);
|
|
9440
|
+
}
|
|
9441
|
+
|
|
9442
|
+
// Unlike the original approach this replaced, `as` is *not* stripped here:
|
|
9443
|
+
// the field as synthesized onto the abstract type's own schema keeps
|
|
9444
|
+
// `options.as === abstractType`, redundant/self-referential as that is.
|
|
9445
|
+
// This keeps every contributor - implementers and the abstract type's
|
|
9446
|
+
// own schema alike - declaring the same thing, which is what
|
|
9447
|
+
// `assertConsistentAbstractFieldShape` checks, and it is also what lets
|
|
9448
|
+
// `assertPolymorphicType` (which reads a field's declared `as` off
|
|
9449
|
+
// whatever `schema.fields()` serves for its type) correctly permit the
|
|
9450
|
+
// abstract type itself to be pushed directly into this relationship.
|
|
9451
|
+
const abstractField = {
|
|
9452
|
+
...field
|
|
9453
|
+
};
|
|
9454
|
+
const contribution = {
|
|
9455
|
+
field: abstractField,
|
|
9456
|
+
source: implementer
|
|
9457
|
+
};
|
|
9458
|
+
|
|
9459
|
+
// all concrete implementations of an abstract type are required to
|
|
9460
|
+
// share the same shape for the field that implements it, so the first
|
|
9461
|
+
// one registered is as good a canonical source as any - but a later,
|
|
9462
|
+
// differently-shaped one is almost certainly a mistake rather than an
|
|
9463
|
+
// intentional override, so we catch it rather than silently ignoring it.
|
|
9464
|
+
const existingImplementer = implementerFields.get(field.name);
|
|
9465
|
+
if (existingImplementer) {
|
|
9466
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
9467
|
+
assertConsistentAbstractFieldShape(abstractType, field.name, existingImplementer, contribution);
|
|
9468
|
+
}
|
|
9469
|
+
return;
|
|
9470
|
+
}
|
|
9471
|
+
implementerFields.set(field.name, contribution);
|
|
9472
|
+
let abstractSchema = this._schemas.get(abstractType);
|
|
9473
|
+
if (!abstractSchema) {
|
|
9474
|
+
abstractSchema = {
|
|
9475
|
+
original: {
|
|
9476
|
+
legacy: true,
|
|
9477
|
+
identity: {
|
|
9478
|
+
kind: '@id',
|
|
9479
|
+
name: 'id'
|
|
9480
|
+
},
|
|
9481
|
+
type: abstractType,
|
|
9482
|
+
fields: []
|
|
9483
|
+
},
|
|
9484
|
+
finalized: true,
|
|
9485
|
+
fields: new Map(),
|
|
9486
|
+
cacheFields: new Map(),
|
|
9487
|
+
relationships: {},
|
|
9488
|
+
attributes: {},
|
|
9489
|
+
traits: new Set()
|
|
9490
|
+
};
|
|
9491
|
+
this._schemas.set(abstractType, abstractSchema);
|
|
9492
|
+
}
|
|
9493
|
+
const existingAbstractField = abstractSchema.fields.get(field.name);
|
|
9494
|
+
if (existingAbstractField) {
|
|
9495
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
9496
|
+
assertConsistentAbstractFieldShape(abstractType, field.name, {
|
|
9497
|
+
field: existingAbstractField,
|
|
9498
|
+
source: abstractType
|
|
9499
|
+
}, contribution);
|
|
9500
|
+
}
|
|
9501
|
+
return;
|
|
9502
|
+
}
|
|
9503
|
+
abstractSchema.fields.set(field.name, abstractField);
|
|
9504
|
+
abstractSchema.relationships[field.name] = abstractField;
|
|
9505
|
+
|
|
9506
|
+
// If the schema is mid-finalization (traits pending), finalizeResource
|
|
9507
|
+
// will recompute cacheFields from the current `fields` map anyway; avoid
|
|
9508
|
+
// doing so prematurely from a partially-resolved set of fields.
|
|
9509
|
+
if (abstractSchema.finalized) {
|
|
9510
|
+
abstractSchema.cacheFields = getCacheFields(abstractSchema);
|
|
9511
|
+
}
|
|
9244
9512
|
}
|
|
9245
9513
|
|
|
9246
9514
|
/**
|
|
@@ -9556,9 +9824,33 @@ function cloneResponse(response, overrides) {
|
|
|
9556
9824
|
const props = cloneResponseProperties(response);
|
|
9557
9825
|
return new Response(response.body, Object.assign(props, overrides));
|
|
9558
9826
|
}
|
|
9827
|
+
function withDateHeader(response) {
|
|
9828
|
+
const headers = new Headers(response.headers);
|
|
9829
|
+
headers.set('date', new Date().toUTCString());
|
|
9830
|
+
return cloneResponse(response, {
|
|
9831
|
+
headers
|
|
9832
|
+
});
|
|
9833
|
+
}
|
|
9834
|
+
|
|
9835
|
+
// Detects Mirage (or another Pretender-based fetch mock), whose `Response`
|
|
9836
|
+
// may (unlike a spec-compliant `fetch()`, whose Response headers are always
|
|
9837
|
+
// immutable) allow header mutation and may not support streaming reads.
|
|
9838
|
+
//
|
|
9839
|
+
// This is inherently a heuristic - many legitimate tools (APM/monitoring
|
|
9840
|
+
// agents, browser extensions, polyfills) also patch `window.fetch`, and can
|
|
9841
|
+
// produce false positives. `setWarpDriveIsMaybeMirage(value)` lets an app
|
|
9842
|
+
// declare the answer explicitly (`true` or `false`), overriding the
|
|
9843
|
+
// heuristic in either direction; leave it unset to keep the default
|
|
9844
|
+
// detection. See https://github.com/warp-drive-data/warp-drive/issues/10535
|
|
9559
9845
|
let IS_MAYBE_MIRAGE = () => false;
|
|
9560
9846
|
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
9561
|
-
IS_MAYBE_MIRAGE = () =>
|
|
9847
|
+
IS_MAYBE_MIRAGE = () => {
|
|
9848
|
+
const override = getRuntimeConfig().mirage;
|
|
9849
|
+
if (override !== undefined) {
|
|
9850
|
+
return override;
|
|
9851
|
+
}
|
|
9852
|
+
return Boolean(typeof window !== 'undefined' && (window.server?.pretender || window.fetch.toString().replace(/\s+/g, '') !== 'function fetch() { [native code] }'.replace(/\s+/g, '')));
|
|
9853
|
+
};
|
|
9562
9854
|
}
|
|
9563
9855
|
const MUTATION_OPS = new Set(['updateRecord', 'createRecord', 'deleteRecord']);
|
|
9564
9856
|
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']]);
|
|
@@ -9610,13 +9902,15 @@ const Fetch = {
|
|
|
9610
9902
|
const isMutationOp = Boolean(op && MUTATION_OPS.has(op));
|
|
9611
9903
|
if (!isError && !isMutationOp && response.status !== 204 && !response.headers.has('date')) {
|
|
9612
9904
|
if (IS_MAYBE_MIRAGE()) {
|
|
9613
|
-
|
|
9905
|
+
try {
|
|
9906
|
+
response.headers.set('date', new Date().toUTCString());
|
|
9907
|
+
} catch {
|
|
9908
|
+
// IS_MAYBE_MIRAGE() was a false positive, or the mock's headers
|
|
9909
|
+
// are (correctly) immutable - fall back to cloning.
|
|
9910
|
+
response = withDateHeader(response);
|
|
9911
|
+
}
|
|
9614
9912
|
} else {
|
|
9615
|
-
|
|
9616
|
-
headers.set('date', new Date().toUTCString());
|
|
9617
|
-
response = cloneResponse(response, {
|
|
9618
|
-
headers
|
|
9619
|
-
});
|
|
9913
|
+
response = withDateHeader(response);
|
|
9620
9914
|
}
|
|
9621
9915
|
}
|
|
9622
9916
|
context.setResponse(response);
|
|
@@ -9920,6 +10214,12 @@ if (macroCondition(getGlobalConfig().WarpDrive.env.TESTING)) {
|
|
|
9920
10214
|
globalThis.getWarpDriveRuntimeConfig = getRuntimeConfig;
|
|
9921
10215
|
}
|
|
9922
10216
|
|
|
10217
|
+
// Mirage (or another Pretender-based fetch mock) may be used outside of a
|
|
10218
|
+
// `TESTING` build (e.g. `ember serve` in dev mode), so this override is
|
|
10219
|
+
// exposed unconditionally rather than gated to the `TESTING` env.
|
|
10220
|
+
// @ts-expect-error adding to globalThis
|
|
10221
|
+
globalThis.setWarpDriveIsMaybeMirage = setIsMaybeMirage;
|
|
10222
|
+
|
|
9923
10223
|
/**
|
|
9924
10224
|
* Options for setting up a Store instance with `useRecommendedStore`.
|
|
9925
10225
|
*/
|
|
@@ -9940,7 +10240,29 @@ if (macroCondition(getGlobalConfig().WarpDrive.env.TESTING)) {
|
|
|
9940
10240
|
*/
|
|
9941
10241
|
function useRecommendedStore(options, StoreKlass = Store) {
|
|
9942
10242
|
return class AppStore extends StoreKlass {
|
|
9943
|
-
|
|
10243
|
+
constructor(createArgs) {
|
|
10244
|
+
super(createArgs);
|
|
10245
|
+
// installed via defineProperty (rather than a class field/accessor) so that
|
|
10246
|
+
// this lazy override of the inherited `requestManager` field does not
|
|
10247
|
+
// conflict with the documented pattern of assigning it directly on
|
|
10248
|
+
// consumer-authored Store subclasses. The setter preserves the ability
|
|
10249
|
+
// to replace `requestManager` outright after construction.
|
|
10250
|
+
let requestManager;
|
|
10251
|
+
Object.defineProperty(this, 'requestManager', {
|
|
10252
|
+
configurable: true,
|
|
10253
|
+
enumerable: true,
|
|
10254
|
+
get: () => {
|
|
10255
|
+
if (!requestManager) {
|
|
10256
|
+
const handlers = typeof options.handlers === 'function' ? options.handlers(this) : options.handlers ?? [];
|
|
10257
|
+
requestManager = new RequestManager().use([...handlers, Fetch]).useCache(CacheHandler);
|
|
10258
|
+
}
|
|
10259
|
+
return requestManager;
|
|
10260
|
+
},
|
|
10261
|
+
set: value => {
|
|
10262
|
+
requestManager = value;
|
|
10263
|
+
}
|
|
10264
|
+
});
|
|
10265
|
+
}
|
|
9944
10266
|
lifetimes = options.policy ?? new DefaultCachePolicy({
|
|
9945
10267
|
apiCacheHardExpires: 15 * 60 * 1000,
|
|
9946
10268
|
// 15 minutes
|
package/dist/index.js
CHANGED
|
@@ -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-LI2ckwf9.js";
|
|
2
2
|
import "./symbols-3C1OkYtZ.js";
|
|
3
3
|
import "./configure-BMxnD2RJ.js";
|
|
4
4
|
import '@embroider/macros';
|
package/dist/reactive.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-LI2ckwf9.js";
|
|
2
2
|
export { C as Checkout } from "./symbols-3C1OkYtZ.js";
|
|
3
3
|
export { h as createRequestSubscription, j as getPromiseState, i as getRequestState } from "./configure-BMxnD2RJ.js";
|
|
4
4
|
import '@embroider/macros';
|
package/dist/store/-private.js
CHANGED
|
@@ -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-LI2ckwf9.js";
|
package/dist/types/-private.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { macroCondition, getGlobalConfig } from '@embroider/macros';
|
|
2
2
|
const name = "@warp-drive/core";
|
|
3
|
-
const version = "5.9.0-alpha.
|
|
3
|
+
const version = "5.9.0-alpha.19";
|
|
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
|
package/dist/types/runtime.js
CHANGED
|
@@ -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 };
|