@agentplat/mesh 0.3.0-beta.2 → 0.3.0-beta.4
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/README.md +133 -4
- package/dist/adaptive-overlay-contracts.d.ts +149 -0
- package/dist/adaptive-overlay-contracts.d.ts.map +1 -0
- package/dist/adaptive-overlay-contracts.js +3 -0
- package/dist/adaptive-overlay-contracts.js.map +1 -0
- package/dist/adaptive-overlay-runtime.d.ts +67 -0
- package/dist/adaptive-overlay-runtime.d.ts.map +1 -0
- package/dist/adaptive-overlay-runtime.js +427 -0
- package/dist/adaptive-overlay-runtime.js.map +1 -0
- package/dist/adaptive-overlay-validation.d.ts +19 -0
- package/dist/adaptive-overlay-validation.d.ts.map +1 -0
- package/dist/adaptive-overlay-validation.js +326 -0
- package/dist/adaptive-overlay-validation.js.map +1 -0
- package/dist/adaptive-overlay.d.ts +4 -0
- package/dist/adaptive-overlay.d.ts.map +1 -0
- package/dist/adaptive-overlay.js +4 -0
- package/dist/adaptive-overlay.js.map +1 -0
- package/dist/authenticated-overlay-transport.d.ts +227 -0
- package/dist/authenticated-overlay-transport.d.ts.map +1 -0
- package/dist/authenticated-overlay-transport.js +702 -0
- package/dist/authenticated-overlay-transport.js.map +1 -0
- package/dist/authority-continuity-contracts.d.ts +249 -0
- package/dist/authority-continuity-contracts.d.ts.map +1 -0
- package/dist/authority-continuity-contracts.js +11 -0
- package/dist/authority-continuity-contracts.js.map +1 -0
- package/dist/authority-continuity.d.ts +43 -0
- package/dist/authority-continuity.d.ts.map +1 -0
- package/dist/authority-continuity.js +1338 -0
- package/dist/authority-continuity.js.map +1 -0
- package/dist/continuity.d.ts +3 -0
- package/dist/continuity.d.ts.map +1 -0
- package/dist/continuity.js +3 -0
- package/dist/continuity.js.map +1 -0
- package/dist/coordination-allocation-contracts.d.ts +6 -0
- package/dist/coordination-allocation-contracts.d.ts.map +1 -1
- package/dist/coordination-allocation-state.d.ts.map +1 -1
- package/dist/coordination-allocation-state.js +37 -7
- package/dist/coordination-allocation-state.js.map +1 -1
- package/dist/coordination-allocation.d.ts +1 -1
- package/dist/coordination-allocation.d.ts.map +1 -1
- package/dist/coordination-allocation.js +92 -11
- package/dist/coordination-allocation.js.map +1 -1
- package/dist/coordination-discovery-state.d.ts.map +1 -1
- package/dist/coordination-discovery-state.js +5 -3
- package/dist/coordination-discovery-state.js.map +1 -1
- package/dist/coordination-recovery.js +5 -1
- package/dist/coordination-recovery.js.map +1 -1
- package/dist/durability.d.ts +22 -0
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +22 -0
- package/dist/durability.js.map +1 -1
- package/dist/overlay-transport.d.ts +7 -0
- package/dist/overlay-transport.d.ts.map +1 -0
- package/dist/overlay-transport.js +7 -0
- package/dist/overlay-transport.js.map +1 -0
- package/dist/overlay.d.ts +9 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +9 -0
- package/dist/overlay.js.map +1 -0
- package/dist/sparse-overlay-contracts.d.ts +91 -0
- package/dist/sparse-overlay-contracts.d.ts.map +1 -0
- package/dist/sparse-overlay-contracts.js +2 -0
- package/dist/sparse-overlay-contracts.js.map +1 -0
- package/dist/sparse-overlay-durability.d.ts +23 -0
- package/dist/sparse-overlay-durability.d.ts.map +1 -0
- package/dist/sparse-overlay-durability.js +97 -0
- package/dist/sparse-overlay-durability.js.map +1 -0
- package/dist/sparse-overlay-runtime-contracts.d.ts +158 -0
- package/dist/sparse-overlay-runtime-contracts.d.ts.map +1 -0
- package/dist/sparse-overlay-runtime-contracts.js +2 -0
- package/dist/sparse-overlay-runtime-contracts.js.map +1 -0
- package/dist/sparse-overlay-runtime.d.ts +48 -0
- package/dist/sparse-overlay-runtime.d.ts.map +1 -0
- package/dist/sparse-overlay-runtime.js +763 -0
- package/dist/sparse-overlay-runtime.js.map +1 -0
- package/dist/sparse-overlay-transport-contracts.d.ts +183 -0
- package/dist/sparse-overlay-transport-contracts.d.ts.map +1 -0
- package/dist/sparse-overlay-transport-contracts.js +2 -0
- package/dist/sparse-overlay-transport-contracts.js.map +1 -0
- package/dist/sparse-overlay-transport-durability.d.ts +19 -0
- package/dist/sparse-overlay-transport-durability.d.ts.map +1 -0
- package/dist/sparse-overlay-transport-durability.js +91 -0
- package/dist/sparse-overlay-transport-durability.js.map +1 -0
- package/dist/sparse-overlay-transport.d.ts +97 -0
- package/dist/sparse-overlay-transport.d.ts.map +1 -0
- package/dist/sparse-overlay-transport.js +888 -0
- package/dist/sparse-overlay-transport.js.map +1 -0
- package/dist/sparse-overlay.d.ts +74 -0
- package/dist/sparse-overlay.d.ts.map +1 -0
- package/dist/sparse-overlay.js +817 -0
- package/dist/sparse-overlay.js.map +1 -0
- package/fixtures/beta1/manifest.json +4 -4
- package/fixtures/beta1/states/discovery-v1.json +3 -3
- package/fixtures/beta1/states/discovery-v2.json +3 -3
- package/package.json +20 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MeshAllocationBidSelection, MeshAllocationCommand, MeshAllocationDecision, MeshAllocationRuntimeState, MeshAllocationSelectionInput, MeshAllocationTimerDecision, MeshAllocationTimerInput, MeshVerifiedAllocationRequest } from "./coordination-allocation-contracts.js";
|
|
2
2
|
/** Commits a prepared local offer or award; signing and delivery stay outside. */
|
|
3
|
-
export declare function evaluateMeshAllocationCommand(state: MeshAllocationRuntimeState, command: MeshAllocationCommand, verifiedAt: string, receivedAt: number): MeshAllocationDecision;
|
|
3
|
+
export declare function evaluateMeshAllocationCommand(state: MeshAllocationRuntimeState, command: MeshAllocationCommand, verifiedAt: string, receivedAt: number, supportedCriticalExtensions?: readonly string[], eligibleRecipientPeerIds?: readonly string[]): MeshAllocationDecision;
|
|
4
4
|
/** Evaluates a verified direct bid at the local offer owner. */
|
|
5
5
|
export declare function evaluateVerifiedMeshAllocationEnvelope(state: MeshAllocationRuntimeState, request: MeshVerifiedAllocationRequest): MeshAllocationDecision;
|
|
6
6
|
/** Selects a currently valid bid deterministically while the window is open. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordination-allocation.d.ts","sourceRoot":"","sources":["../src/coordination-allocation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"coordination-allocation.d.ts","sourceRoot":"","sources":["../src/coordination-allocation.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAIV,0BAA0B,EAC1B,qBAAqB,EACrB,sBAAsB,EAGtB,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,EASxB,6BAA6B,EAE9B,MAAM,wCAAwC,CAAC;AAsChD,kFAAkF;AAClF,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,0BAA0B,EACjC,OAAO,EAAE,qBAAqB,EAC9B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,2BAA2B,GAAE,SAAS,MAAM,EAAO,EACnD,wBAAwB,CAAC,EAAE,SAAS,MAAM,EAAE,GAC3C,sBAAsB,CAkWxB;AAghCD,gEAAgE;AAChE,wBAAgB,sCAAsC,CACpD,KAAK,EAAE,0BAA0B,EACjC,OAAO,EAAE,6BAA6B,GACrC,sBAAsB,CA6PxB;AA03BD,gFAAgF;AAChF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,0BAA0B,EACjC,KAAK,EAAE,4BAA4B,GAClC,0BAA0B,CAwF5B;AAED,6DAA6D;AAC7D,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,0BAA0B,EACjC,KAAK,EAAE,wBAAwB,EAC/B,WAAW,EAAE,MAAM,GAClB,2BAA2B,CAqJ7B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canonicalizeMeshPayload, compareMeshTimestamps, validateMeshEnvelopeContext, validateSignedMeshEnvelope, } from "@agentplat/mesh-protocol";
|
|
1
|
+
import { DEFAULT_MESH_PROTOCOL_LIMITS, canonicalizeMeshPayload, compareMeshTimestamps, validateMeshEnvelopeContext, validateSignedMeshEnvelope, } from "@agentplat/mesh-protocol";
|
|
2
2
|
import { createMeshAllocationRuntimeState, meshAllocationRetainsMessageId, meshAssignmentFenceKey, restoreMeshAllocationState, } from "./coordination-allocation-state.js";
|
|
3
3
|
import { matchMeshDiscoveryCapabilities } from "./coordination-discovery.js";
|
|
4
4
|
import { evaluateMeshExecutionCommand, evaluateVerifiedMeshExecutionEnvelope, } from "./coordination-execution.js";
|
|
@@ -10,8 +10,10 @@ import { sha256Base64Url } from "./sha256.js";
|
|
|
10
10
|
import { assertMeshLogicalTime, createFrozenRecord, recordEntries, } from "./state.js";
|
|
11
11
|
const utf8Encoder = new TextEncoder();
|
|
12
12
|
/** Commits a prepared local offer or award; signing and delivery stay outside. */
|
|
13
|
-
export function evaluateMeshAllocationCommand(state, command, verifiedAt, receivedAt) {
|
|
13
|
+
export function evaluateMeshAllocationCommand(state, command, verifiedAt, receivedAt, supportedCriticalExtensions = [], eligibleRecipientPeerIds) {
|
|
14
14
|
assertRuntime(state, receivedAt);
|
|
15
|
+
assertSupportedCriticalExtensions(supportedCriticalExtensions);
|
|
16
|
+
assertEligibleRecipientPeerIds(eligibleRecipientPeerIds, state.allocation.limits.maximumRecipientsPerOffer, supportedCriticalExtensions.length > 0);
|
|
15
17
|
if (!command ||
|
|
16
18
|
![
|
|
17
19
|
"allocation.offer",
|
|
@@ -81,7 +83,7 @@ export function evaluateMeshAllocationCommand(state, command, verifiedAt, receiv
|
|
|
81
83
|
.filter((offer) => offer.objectiveId === work.objectiveId &&
|
|
82
84
|
offer.work.workItemId === work.workItemId)
|
|
83
85
|
.sort((a, b) => a.offerAttempt - b.offerAttempt);
|
|
84
|
-
const prepared = validatePrepared(command.recipients, state, work, verifiedAt, receivedAt, priorOffers.at(-1));
|
|
86
|
+
const prepared = validatePrepared(command.recipients, state, work, verifiedAt, receivedAt, priorOffers.at(-1), supportedCriticalExtensions, eligibleRecipientPeerIds);
|
|
85
87
|
if ("code" in prepared)
|
|
86
88
|
return reject(state, prepared.code);
|
|
87
89
|
const { payload, entries, bidDeadlineAt } = prepared;
|
|
@@ -155,6 +157,13 @@ export function evaluateMeshAllocationCommand(state, command, verifiedAt, receiv
|
|
|
155
157
|
bidDeadlineTimerGeneration: generation,
|
|
156
158
|
createdAt: receivedAt,
|
|
157
159
|
validityVerifiedAt: verifiedAt,
|
|
160
|
+
...(supportedCriticalExtensions.length === 0
|
|
161
|
+
? {}
|
|
162
|
+
: {
|
|
163
|
+
supportedCriticalExtensions: Object.freeze([
|
|
164
|
+
...supportedCriticalExtensions,
|
|
165
|
+
]),
|
|
166
|
+
}),
|
|
158
167
|
reservationId,
|
|
159
168
|
recipientOffers: createFrozenRecord(entries.map(({ recipientPeerId, preparedAt, envelope }) => [
|
|
160
169
|
recipientPeerId,
|
|
@@ -275,8 +284,10 @@ export function evaluateMeshAllocationCommand(state, command, verifiedAt, receiv
|
|
|
275
284
|
});
|
|
276
285
|
}
|
|
277
286
|
function evaluateAwardCommand(state, command, verifiedAt, receivedAt) {
|
|
278
|
-
|
|
279
|
-
|
|
287
|
+
const commandKeys = Object.keys(command).sort().join(",");
|
|
288
|
+
if ((commandKeys !== "bidId,bidRevision,kind,offerId,recipient" &&
|
|
289
|
+
commandKeys !==
|
|
290
|
+
"bidId,bidRevision,excludedBidderPeerIds,kind,offerId,recipient") ||
|
|
280
291
|
!command.recipient ||
|
|
281
292
|
Object.keys(command.recipient).sort().join(",") !==
|
|
282
293
|
"envelope,preparedAt,recipientPeerId")
|
|
@@ -292,6 +303,9 @@ function evaluateAwardCommand(state, command, verifiedAt, receivedAt) {
|
|
|
292
303
|
const selected = selectMeshAllocationBid(state, {
|
|
293
304
|
offerId: offer.offerId,
|
|
294
305
|
evaluatedAt: receivedAt,
|
|
306
|
+
...(command.excludedBidderPeerIds === undefined
|
|
307
|
+
? {}
|
|
308
|
+
: { excludedBidderPeerIds: command.excludedBidderPeerIds }),
|
|
295
309
|
});
|
|
296
310
|
if (selected.reason !== "selected" ||
|
|
297
311
|
!selected.bid ||
|
|
@@ -1942,12 +1956,21 @@ function isWitnessCopy(state, request) {
|
|
|
1942
1956
|
}
|
|
1943
1957
|
/** Selects a currently valid bid deterministically while the window is open. */
|
|
1944
1958
|
export function selectMeshAllocationBid(state, input) {
|
|
1959
|
+
const inputKeys = input && typeof input === "object"
|
|
1960
|
+
? Object.keys(input).sort().join(",")
|
|
1961
|
+
: "";
|
|
1962
|
+
const excludedBidderPeerIds = input?.excludedBidderPeerIds ?? [];
|
|
1945
1963
|
if (!input ||
|
|
1946
1964
|
typeof input !== "object" ||
|
|
1947
|
-
|
|
1965
|
+
(inputKeys !== "evaluatedAt,offerId" &&
|
|
1966
|
+
inputKeys !== "evaluatedAt,excludedBidderPeerIds,offerId") ||
|
|
1948
1967
|
typeof input.offerId !== "string" ||
|
|
1949
1968
|
!Number.isSafeInteger(input.evaluatedAt) ||
|
|
1950
|
-
input.evaluatedAt < 0
|
|
1969
|
+
input.evaluatedAt < 0 ||
|
|
1970
|
+
!Array.isArray(excludedBidderPeerIds) ||
|
|
1971
|
+
excludedBidderPeerIds.length > 256 ||
|
|
1972
|
+
new Set(excludedBidderPeerIds).size !== excludedBidderPeerIds.length ||
|
|
1973
|
+
excludedBidderPeerIds.some((peerId) => typeof peerId !== "string" || peerId.length === 0))
|
|
1951
1974
|
throw new TypeError("Invalid Mesh allocation selection input");
|
|
1952
1975
|
assertRuntime(state, input.evaluatedAt);
|
|
1953
1976
|
const offer = state.allocation.localOffers[input.offerId];
|
|
@@ -1976,6 +1999,8 @@ export function selectMeshAllocationBid(state, input) {
|
|
|
1976
1999
|
const eligible = Object.values(state.allocation.bidHeads).filter((bid) => {
|
|
1977
2000
|
if (bid.offerId !== input.offerId)
|
|
1978
2001
|
return false;
|
|
2002
|
+
if (excludedBidderPeerIds.includes(bid.bidderPeerId))
|
|
2003
|
+
return false;
|
|
1979
2004
|
const evidence = state.allocation.acceptedBidEvidence[bid.bidId];
|
|
1980
2005
|
if (!evidence)
|
|
1981
2006
|
return false;
|
|
@@ -2317,7 +2342,7 @@ function evaluateAcceptanceDeadline(state, timer, logicalTime) {
|
|
|
2317
2342
|
state: createMeshAllocationRuntimeState(coordination, Object.freeze({ ...state.discovery, lastLogicalTime: logicalTime }), objectives, allocation),
|
|
2318
2343
|
});
|
|
2319
2344
|
}
|
|
2320
|
-
function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previousOffer) {
|
|
2345
|
+
function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previousOffer, supportedCriticalExtensions = [], eligibleRecipientPeerIds) {
|
|
2321
2346
|
if (!Array.isArray(recipients) ||
|
|
2322
2347
|
!recipients.length ||
|
|
2323
2348
|
recipients.length > state.allocation.limits.maximumRecipientsPerOffer)
|
|
@@ -2327,6 +2352,13 @@ function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previ
|
|
|
2327
2352
|
if (!parsed?.ok || parsed.value.payload.type !== "work.offer")
|
|
2328
2353
|
return { code: "offer_invalid" };
|
|
2329
2354
|
const payload = parsed.value.payload;
|
|
2355
|
+
const firstEnvelope = parsed.value;
|
|
2356
|
+
const priorEnvelope = previousOffer
|
|
2357
|
+
? Object.values(previousOffer.recipientOffers)[0]?.envelope
|
|
2358
|
+
: undefined;
|
|
2359
|
+
if (priorEnvelope !== undefined &&
|
|
2360
|
+
!preservesCriticalSemantics(firstEnvelope, priorEnvelope))
|
|
2361
|
+
return { code: "offer_invalid" };
|
|
2330
2362
|
const bidDeadlineAt = logicalDeadline(payload.bidDeadline, verifiedAt, receivedAt);
|
|
2331
2363
|
if (bidDeadlineAt === undefined)
|
|
2332
2364
|
return { code: "offer_invalid" };
|
|
@@ -2335,10 +2367,15 @@ function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previ
|
|
|
2335
2367
|
attributes: work.matchingAttributes,
|
|
2336
2368
|
fanout: Math.min(state.allocation.limits.maximumRecipientsPerOffer, state.discovery.limits.maximumFanout),
|
|
2337
2369
|
}, receivedAt).matches.map((match) => match.peerId);
|
|
2370
|
+
const constrainedMatches = eligibleRecipientPeerIds === undefined
|
|
2371
|
+
? matches
|
|
2372
|
+
: matches.filter((peerId) => eligibleRecipientPeerIds.includes(peerId));
|
|
2338
2373
|
const ids = recipients.map((item) => item.recipientPeerId);
|
|
2339
|
-
if (
|
|
2340
|
-
|
|
2341
|
-
ids.
|
|
2374
|
+
if ((eligibleRecipientPeerIds !== undefined &&
|
|
2375
|
+
eligibleRecipientPeerIds.some((peerId) => !matches.includes(peerId))) ||
|
|
2376
|
+
new Set(ids).size !== ids.length ||
|
|
2377
|
+
ids.length !== constrainedMatches.length ||
|
|
2378
|
+
ids.some((id, index) => id !== constrainedMatches[index]))
|
|
2342
2379
|
return { code: "offer_invalid" };
|
|
2343
2380
|
const entries = [];
|
|
2344
2381
|
const retainedMessageIds = new Set([
|
|
@@ -2353,6 +2390,7 @@ function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previ
|
|
|
2353
2390
|
meshId: state.allocation.identity.meshId,
|
|
2354
2391
|
peerId: item.recipientPeerId,
|
|
2355
2392
|
receivedAt: verifiedAt,
|
|
2393
|
+
supportedCriticalExtensions,
|
|
2356
2394
|
});
|
|
2357
2395
|
if (!result.ok ||
|
|
2358
2396
|
result.value.payload.type !== "work.offer" ||
|
|
@@ -2367,6 +2405,7 @@ function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previ
|
|
|
2367
2405
|
: result.value.causationId !==
|
|
2368
2406
|
previousOffer?.recipientOffers[item.recipientPeerId]?.messageId) ||
|
|
2369
2407
|
!samePayload(result.value.payload, payload) ||
|
|
2408
|
+
!sameCriticalSemantics(result.value, firstEnvelope) ||
|
|
2370
2409
|
!canonicalDigest(result.value))
|
|
2371
2410
|
return { code: "offer_invalid" };
|
|
2372
2411
|
if (retainedMessageIds.has(result.value.messageId) ||
|
|
@@ -2381,6 +2420,48 @@ function validatePrepared(recipients, state, work, verifiedAt, receivedAt, previ
|
|
|
2381
2420
|
}
|
|
2382
2421
|
return { payload, entries: Object.freeze(entries), bidDeadlineAt };
|
|
2383
2422
|
}
|
|
2423
|
+
function assertSupportedCriticalExtensions(value) {
|
|
2424
|
+
const descriptors = Array.isArray(value)
|
|
2425
|
+
? Object.getOwnPropertyDescriptors(value)
|
|
2426
|
+
: undefined;
|
|
2427
|
+
if (!Array.isArray(value) ||
|
|
2428
|
+
value.length > DEFAULT_MESH_PROTOCOL_LIMITS.maximumCriticalExtensions ||
|
|
2429
|
+
Reflect.ownKeys(value).length !== value.length + 1 ||
|
|
2430
|
+
Object.values(descriptors ?? {}).some((descriptor) => "get" in descriptor || "set" in descriptor))
|
|
2431
|
+
throw new TypeError("Invalid Mesh supported critical extensions");
|
|
2432
|
+
const seen = new Set();
|
|
2433
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
2434
|
+
if (!Object.prototype.hasOwnProperty.call(value, index))
|
|
2435
|
+
throw new TypeError("Invalid Mesh supported critical extensions");
|
|
2436
|
+
const extension = value[index];
|
|
2437
|
+
if (typeof extension !== "string" ||
|
|
2438
|
+
extension.length < 1 ||
|
|
2439
|
+
seen.has(extension))
|
|
2440
|
+
throw new TypeError("Invalid Mesh supported critical extensions");
|
|
2441
|
+
seen.add(extension);
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
function assertEligibleRecipientPeerIds(value, maximumRecipients, criticalExtensionEnabled) {
|
|
2445
|
+
if (value === undefined)
|
|
2446
|
+
return;
|
|
2447
|
+
if (!criticalExtensionEnabled ||
|
|
2448
|
+
!Array.isArray(value) ||
|
|
2449
|
+
value.length < 1 ||
|
|
2450
|
+
value.length > maximumRecipients ||
|
|
2451
|
+
new Set(value).size !== value.length ||
|
|
2452
|
+
value.some((peerId) => typeof peerId !== "string" || peerId.length < 1))
|
|
2453
|
+
throw new TypeError("Invalid Mesh eligible recipient peer IDs");
|
|
2454
|
+
}
|
|
2455
|
+
function sameCriticalSemantics(left, right) {
|
|
2456
|
+
if (!sameData(left.criticalExtensions ?? [], right.criticalExtensions ?? []))
|
|
2457
|
+
return false;
|
|
2458
|
+
return (left.criticalExtensions ?? []).every((key) => sameData(left.extensions?.[key], right.extensions?.[key]));
|
|
2459
|
+
}
|
|
2460
|
+
function preservesCriticalSemantics(current, previous) {
|
|
2461
|
+
const currentCritical = new Set(current.criticalExtensions ?? []);
|
|
2462
|
+
return (previous.criticalExtensions ?? []).every((key) => currentCritical.has(key) &&
|
|
2463
|
+
sameData(current.extensions?.[key], previous.extensions?.[key]));
|
|
2464
|
+
}
|
|
2384
2465
|
function validateContext(state, request) {
|
|
2385
2466
|
if (!request ||
|
|
2386
2467
|
typeof request !== "object" ||
|