@agentplat/mesh-protocol 0.3.0-alpha.1 → 0.3.0-alpha.2
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 +294 -1
- package/dist/contracts.d.ts +335 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1654 -16
- package/dist/validation.js.map +1 -1
- package/fixtures/v0/README.md +6 -2
- package/fixtures/v0/capability-advertise.json +35 -0
- package/fixtures/v0/capability-withdraw.json +26 -0
- package/fixtures/v0/lease-certificate.json +29 -0
- package/fixtures/v0/lease-renew.json +41 -0
- package/fixtures/v0/lease-takeover-proposal.json +46 -0
- package/fixtures/v0/lease-vote.json +28 -0
- package/fixtures/v0/objective-announce.json +43 -0
- package/fixtures/v0/objective-cancel.json +28 -0
- package/fixtures/v0/objective-revise.json +44 -0
- package/fixtures/v0/peer-card.json +31 -0
- package/fixtures/v0/peer-goodbye.json +26 -0
- package/fixtures/v0/work-accept.json +38 -0
- package/fixtures/v0/work-award.json +46 -0
- package/fixtures/v0/work-bid.json +46 -0
- package/fixtures/v0/work-cancel.json +40 -0
- package/fixtures/v0/work-checkpoint.json +42 -0
- package/fixtures/v0/work-decline.json +38 -0
- package/fixtures/v0/work-offer.json +39 -0
- package/fixtures/v0/work-progress.json +41 -0
- package/fixtures/v0/work-release.json +41 -0
- package/fixtures/v0/work-result.json +42 -0
- package/package.json +1 -1
package/dist/validation.js
CHANGED
|
@@ -6,6 +6,42 @@ const base64UrlPattern = /^[A-Za-z0-9_-]+$/;
|
|
|
6
6
|
const rfc3339Pattern = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?(Z|([+-])(\d{2}):(\d{2}))$/;
|
|
7
7
|
const base64UrlAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
8
8
|
const maximumIssuePathLength = 256;
|
|
9
|
+
const maximumDomainStringBytes = 4_096;
|
|
10
|
+
const maximumProtocolVersions = 8;
|
|
11
|
+
const maximumTransportHints = 8;
|
|
12
|
+
const maximumTransportHintBytes = 2_048;
|
|
13
|
+
const maximumTransportHintsBytes = 8_192;
|
|
14
|
+
const maximumCapabilityIds = 32;
|
|
15
|
+
const maximumMediaTypes = 16;
|
|
16
|
+
const maximumMediaTypeBytes = 128;
|
|
17
|
+
const maximumAttributes = 32;
|
|
18
|
+
const maximumAttributeKeyBytes = 128;
|
|
19
|
+
const maximumAttributeValueBytes = 1_024;
|
|
20
|
+
const maximumAttributesBytes = 16_384;
|
|
21
|
+
const maximumVersionBytes = 128;
|
|
22
|
+
const maximumAdvertisementValidityMs = 24 * 60 * 60 * 1_000;
|
|
23
|
+
const maximumObjectiveValidityMs = 30 * 24 * 60 * 60 * 1_000;
|
|
24
|
+
const maximumObjectiveTextBytes = 4_096;
|
|
25
|
+
const maximumSuccessCriteria = 32;
|
|
26
|
+
const maximumSuccessCriteriaBytes = 16_384;
|
|
27
|
+
const maximumPermittedCapabilityKeys = 32;
|
|
28
|
+
const maximumRecoveryWitnesses = 32;
|
|
29
|
+
const minimumRecoveryWitnesses = 3;
|
|
30
|
+
const maximumAuthorizedObservers = 32;
|
|
31
|
+
const maximumObjectiveWorkItems = 1_000_000;
|
|
32
|
+
const maximumBidWindowMs = 60 * 60 * 1_000;
|
|
33
|
+
const maximumAcceptanceWindowMs = 15 * 60 * 1_000;
|
|
34
|
+
const maximumLeaseDurationMs = 24 * 60 * 60 * 1_000;
|
|
35
|
+
const maximumRecoveryGraceMs = 60 * 60 * 1_000;
|
|
36
|
+
const maximumLeaseRenewals = 100;
|
|
37
|
+
const maximumWorkCapabilityKeys = 32;
|
|
38
|
+
const maximumWorkTextBytes = 4_096;
|
|
39
|
+
const maximumWorkListItems = 32;
|
|
40
|
+
const maximumWorkListBytes = 16_384;
|
|
41
|
+
const maximumCapacityReservationUnits = 1_000_000;
|
|
42
|
+
const maximumWorkBidWindowMs = 60 * 60 * 1_000;
|
|
43
|
+
const maximumWorkDeadlineMs = 30 * 24 * 60 * 60 * 1_000;
|
|
44
|
+
const maximumWorkExecutionLifetimeMs = 5 * 60 * 1_000;
|
|
9
45
|
const knownMessageTypes = new Set(MESH_MESSAGE_TYPES);
|
|
10
46
|
const knownTopics = new Set(MESH_AUDIENCE_TOPICS);
|
|
11
47
|
const utf8Encoder = new TextEncoder();
|
|
@@ -71,7 +107,7 @@ export function compareMeshTimestamps(left, right) {
|
|
|
71
107
|
}
|
|
72
108
|
}
|
|
73
109
|
/**
|
|
74
|
-
* Parses and statically validates one complete
|
|
110
|
+
* Parses and statically validates one complete implemented Mesh envelope.
|
|
75
111
|
* This stage does not verify the payload digest or proof.
|
|
76
112
|
*/
|
|
77
113
|
export function parseSignedMeshEnvelope(input, options = {}) {
|
|
@@ -222,7 +258,7 @@ function validateEnvelope(input, limits) {
|
|
|
222
258
|
if (!knownMessageTypes.has(type)) {
|
|
223
259
|
fail('unsupported_message_type', '$["type"]');
|
|
224
260
|
}
|
|
225
|
-
if (!
|
|
261
|
+
if (!isImplementedMessageType(type)) {
|
|
226
262
|
fail('unsupported_message_type', '$["type"]');
|
|
227
263
|
}
|
|
228
264
|
const sender = validateSender(envelope.sender, limits);
|
|
@@ -251,7 +287,7 @@ function validateEnvelope(input, limits) {
|
|
|
251
287
|
if (payload.type !== type) {
|
|
252
288
|
fail('type_payload_mismatch', '$["payload"]["type"]');
|
|
253
289
|
}
|
|
254
|
-
validateMessageSpecificEnvelope(type, audience, objectiveId, causationId);
|
|
290
|
+
validateMessageSpecificEnvelope(type, sender, audience, objectiveId, causationId, payload, sentAt, expiresAt);
|
|
255
291
|
return {
|
|
256
292
|
protocol: MESH_PROTOCOL,
|
|
257
293
|
wireVersion: MESH_WIRE_VERSION,
|
|
@@ -310,6 +346,46 @@ function validatePayload(type, input, limits) {
|
|
|
310
346
|
};
|
|
311
347
|
return result;
|
|
312
348
|
}
|
|
349
|
+
if (type === 'peer.card') {
|
|
350
|
+
const payload = assertClosedRecord(input, [
|
|
351
|
+
'capabilityIds',
|
|
352
|
+
'cardRevision',
|
|
353
|
+
'instanceId',
|
|
354
|
+
'peerCardId',
|
|
355
|
+
'protocolVersions',
|
|
356
|
+
'subjectPeerId',
|
|
357
|
+
'transportHints',
|
|
358
|
+
'type',
|
|
359
|
+
'validFrom',
|
|
360
|
+
'validUntil',
|
|
361
|
+
], ['previousPeerCardId'], '$["payload"]', 'invalid_payload');
|
|
362
|
+
const peerCardId = assertIdentifier(payload.peerCardId, '$["payload"]["peerCardId"]', limits);
|
|
363
|
+
const cardRevision = assertPositiveSafeInteger(payload.cardRevision, '$["payload"]["cardRevision"]', 'invalid_payload');
|
|
364
|
+
const previousPeerCardId = payload.previousPeerCardId === undefined
|
|
365
|
+
? undefined
|
|
366
|
+
: assertIdentifier(payload.previousPeerCardId, '$["payload"]["previousPeerCardId"]', limits);
|
|
367
|
+
validateRevisionPredecessor(cardRevision, previousPeerCardId, '$["payload"]["previousPeerCardId"]');
|
|
368
|
+
if (previousPeerCardId === peerCardId) {
|
|
369
|
+
fail('invalid_payload', '$["payload"]["previousPeerCardId"]');
|
|
370
|
+
}
|
|
371
|
+
const validFrom = assertRfc3339PayloadTimestamp(payload.validFrom, '$["payload"]["validFrom"]');
|
|
372
|
+
const validUntil = assertRfc3339PayloadTimestamp(payload.validUntil, '$["payload"]["validUntil"]');
|
|
373
|
+
assertBoundedValidity(validFrom.instant, validUntil.instant);
|
|
374
|
+
const result = {
|
|
375
|
+
type: assertPayloadType(payload.type, type),
|
|
376
|
+
peerCardId,
|
|
377
|
+
cardRevision,
|
|
378
|
+
subjectPeerId: assertIdentifier(payload.subjectPeerId, '$["payload"]["subjectPeerId"]', limits),
|
|
379
|
+
instanceId: assertIdentifier(payload.instanceId, '$["payload"]["instanceId"]', limits),
|
|
380
|
+
protocolVersions: validateProtocolVersions(payload.protocolVersions),
|
|
381
|
+
transportHints: validateBoundedStringArray(payload.transportHints, '$["payload"]["transportHints"]', maximumTransportHints, maximumTransportHintBytes, maximumTransportHintsBytes, true),
|
|
382
|
+
capabilityIds: validateIdentifierArray(payload.capabilityIds, '$["payload"]["capabilityIds"]', maximumCapabilityIds, limits),
|
|
383
|
+
validFrom: validFrom.text,
|
|
384
|
+
validUntil: validUntil.text,
|
|
385
|
+
...(previousPeerCardId === undefined ? {} : { previousPeerCardId }),
|
|
386
|
+
};
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
313
389
|
if (type === 'peer.ping') {
|
|
314
390
|
const payload = assertClosedRecord(input, ['type'], [], '$["payload"]', 'invalid_payload');
|
|
315
391
|
const result = {
|
|
@@ -317,11 +393,1040 @@ function validatePayload(type, input, limits) {
|
|
|
317
393
|
};
|
|
318
394
|
return result;
|
|
319
395
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
396
|
+
if (type === 'peer.ping_ack') {
|
|
397
|
+
const payload = assertClosedRecord(input, ['type'], [], '$["payload"]', 'invalid_payload');
|
|
398
|
+
const result = {
|
|
399
|
+
type: assertPayloadType(payload.type, type),
|
|
400
|
+
};
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
if (type === 'peer.goodbye') {
|
|
404
|
+
const payload = assertClosedRecord(input, ['cardRevision', 'instanceId', 'peerCardId', 'type'], [], '$["payload"]', 'invalid_payload');
|
|
405
|
+
const result = {
|
|
406
|
+
type: assertPayloadType(payload.type, type),
|
|
407
|
+
peerCardId: assertIdentifier(payload.peerCardId, '$["payload"]["peerCardId"]', limits),
|
|
408
|
+
cardRevision: assertPositiveSafeInteger(payload.cardRevision, '$["payload"]["cardRevision"]', 'invalid_payload'),
|
|
409
|
+
instanceId: assertIdentifier(payload.instanceId, '$["payload"]["instanceId"]', limits),
|
|
410
|
+
};
|
|
411
|
+
return result;
|
|
412
|
+
}
|
|
413
|
+
if (type === 'capability.advertise') {
|
|
414
|
+
const payload = assertClosedRecord(input, [
|
|
415
|
+
'advertisementId',
|
|
416
|
+
'attributes',
|
|
417
|
+
'capabilityId',
|
|
418
|
+
'capabilityKey',
|
|
419
|
+
'capabilityRevision',
|
|
420
|
+
'inputMediaTypes',
|
|
421
|
+
'outputMediaTypes',
|
|
422
|
+
'ownerPeerId',
|
|
423
|
+
'type',
|
|
424
|
+
'validFrom',
|
|
425
|
+
'validUntil',
|
|
426
|
+
'version',
|
|
427
|
+
], [
|
|
428
|
+
'maximumConcurrency',
|
|
429
|
+
'maximumPayloadBytes',
|
|
430
|
+
'previousAdvertisementId',
|
|
431
|
+
'variant',
|
|
432
|
+
], '$["payload"]', 'invalid_payload');
|
|
433
|
+
const advertisementId = assertIdentifier(payload.advertisementId, '$["payload"]["advertisementId"]', limits);
|
|
434
|
+
const capabilityRevision = assertPositiveSafeInteger(payload.capabilityRevision, '$["payload"]["capabilityRevision"]', 'invalid_payload');
|
|
435
|
+
const previousAdvertisementId = payload.previousAdvertisementId === undefined
|
|
436
|
+
? undefined
|
|
437
|
+
: assertIdentifier(payload.previousAdvertisementId, '$["payload"]["previousAdvertisementId"]', limits);
|
|
438
|
+
validateRevisionPredecessor(capabilityRevision, previousAdvertisementId, '$["payload"]["previousAdvertisementId"]');
|
|
439
|
+
if (previousAdvertisementId === advertisementId) {
|
|
440
|
+
fail('invalid_payload', '$["payload"]["previousAdvertisementId"]');
|
|
441
|
+
}
|
|
442
|
+
const validFrom = assertRfc3339PayloadTimestamp(payload.validFrom, '$["payload"]["validFrom"]');
|
|
443
|
+
const validUntil = assertRfc3339PayloadTimestamp(payload.validUntil, '$["payload"]["validUntil"]');
|
|
444
|
+
assertBoundedValidity(validFrom.instant, validUntil.instant);
|
|
445
|
+
const result = {
|
|
446
|
+
type: assertPayloadType(payload.type, type),
|
|
447
|
+
advertisementId,
|
|
448
|
+
capabilityId: assertIdentifier(payload.capabilityId, '$["payload"]["capabilityId"]', limits),
|
|
449
|
+
capabilityRevision,
|
|
450
|
+
ownerPeerId: assertIdentifier(payload.ownerPeerId, '$["payload"]["ownerPeerId"]', limits),
|
|
451
|
+
capabilityKey: assertBoundedString(payload.capabilityKey, '$["payload"]["capabilityKey"]', maximumDomainStringBytes),
|
|
452
|
+
version: assertBoundedString(payload.version, '$["payload"]["version"]', maximumVersionBytes),
|
|
453
|
+
...(payload.variant === undefined
|
|
454
|
+
? {}
|
|
455
|
+
: {
|
|
456
|
+
variant: assertBoundedString(payload.variant, '$["payload"]["variant"]', maximumVersionBytes),
|
|
457
|
+
}),
|
|
458
|
+
inputMediaTypes: validateBoundedStringArray(payload.inputMediaTypes, '$["payload"]["inputMediaTypes"]', maximumMediaTypes, maximumMediaTypeBytes, undefined, true),
|
|
459
|
+
outputMediaTypes: validateBoundedStringArray(payload.outputMediaTypes, '$["payload"]["outputMediaTypes"]', maximumMediaTypes, maximumMediaTypeBytes, undefined, true),
|
|
460
|
+
attributes: validateAttributes(payload.attributes),
|
|
461
|
+
validFrom: validFrom.text,
|
|
462
|
+
validUntil: validUntil.text,
|
|
463
|
+
...(payload.maximumConcurrency === undefined
|
|
464
|
+
? {}
|
|
465
|
+
: {
|
|
466
|
+
maximumConcurrency: assertPositiveSafeInteger(payload.maximumConcurrency, '$["payload"]["maximumConcurrency"]', 'invalid_payload'),
|
|
467
|
+
}),
|
|
468
|
+
...(payload.maximumPayloadBytes === undefined
|
|
469
|
+
? {}
|
|
470
|
+
: {
|
|
471
|
+
maximumPayloadBytes: assertPositiveSafeInteger(payload.maximumPayloadBytes, '$["payload"]["maximumPayloadBytes"]', 'invalid_payload'),
|
|
472
|
+
}),
|
|
473
|
+
...(previousAdvertisementId === undefined
|
|
474
|
+
? {}
|
|
475
|
+
: { previousAdvertisementId }),
|
|
476
|
+
};
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
if (type === 'capability.withdraw') {
|
|
480
|
+
const payload = assertClosedRecord(input, ['advertisementId', 'capabilityId', 'capabilityRevision', 'type'], [], '$["payload"]', 'invalid_payload');
|
|
481
|
+
const result = {
|
|
482
|
+
type: assertPayloadType(payload.type, type),
|
|
483
|
+
capabilityId: assertIdentifier(payload.capabilityId, '$["payload"]["capabilityId"]', limits),
|
|
484
|
+
capabilityRevision: assertPositiveSafeInteger(payload.capabilityRevision, '$["payload"]["capabilityRevision"]', 'invalid_payload'),
|
|
485
|
+
advertisementId: assertIdentifier(payload.advertisementId, '$["payload"]["advertisementId"]', limits),
|
|
486
|
+
};
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
if (type === 'objective.announce') {
|
|
490
|
+
const document = validateObjectiveDocument(input, type, limits);
|
|
491
|
+
if (document.objectiveRevision !== 1) {
|
|
492
|
+
fail('invalid_payload', '$["payload"]["objectiveRevision"]');
|
|
493
|
+
}
|
|
494
|
+
const result = {
|
|
495
|
+
type,
|
|
496
|
+
...document,
|
|
497
|
+
};
|
|
498
|
+
return result;
|
|
499
|
+
}
|
|
500
|
+
if (type === 'objective.revise') {
|
|
501
|
+
const document = validateObjectiveDocument(input, type, limits);
|
|
502
|
+
if (document.objectiveRevision < 2) {
|
|
503
|
+
fail('invalid_payload', '$["payload"]["objectiveRevision"]');
|
|
504
|
+
}
|
|
505
|
+
const payload = input;
|
|
506
|
+
const previousObjectiveDocumentId = assertIdentifier(payload.previousObjectiveDocumentId, '$["payload"]["previousObjectiveDocumentId"]', limits);
|
|
507
|
+
if (previousObjectiveDocumentId === document.objectiveDocumentId) {
|
|
508
|
+
fail('invalid_payload', '$["payload"]["previousObjectiveDocumentId"]');
|
|
509
|
+
}
|
|
510
|
+
const result = {
|
|
511
|
+
type,
|
|
512
|
+
...document,
|
|
513
|
+
previousObjectiveDocumentId,
|
|
514
|
+
};
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
if (type === 'objective.cancel') {
|
|
518
|
+
const payload = assertClosedRecord(input, [
|
|
519
|
+
'cancellationId',
|
|
520
|
+
'objectiveDocumentId',
|
|
521
|
+
'objectiveId',
|
|
522
|
+
'objectiveRevision',
|
|
523
|
+
'type',
|
|
524
|
+
], [], '$["payload"]', 'invalid_payload');
|
|
525
|
+
const result = {
|
|
526
|
+
type: assertPayloadType(payload.type, type),
|
|
527
|
+
cancellationId: assertIdentifier(payload.cancellationId, '$["payload"]["cancellationId"]', limits),
|
|
528
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
529
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
530
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
531
|
+
};
|
|
532
|
+
return result;
|
|
533
|
+
}
|
|
534
|
+
if (type === 'work.offer') {
|
|
535
|
+
return validateWorkOffer(input, limits);
|
|
536
|
+
}
|
|
537
|
+
if (type === 'work.bid') {
|
|
538
|
+
return validateWorkBid(input, limits);
|
|
539
|
+
}
|
|
540
|
+
if (type === 'work.award') {
|
|
541
|
+
return validateWorkAward(input, limits);
|
|
542
|
+
}
|
|
543
|
+
if (type === 'work.accept') {
|
|
544
|
+
return validateWorkAccept(input, limits);
|
|
545
|
+
}
|
|
546
|
+
if (type === 'work.decline') {
|
|
547
|
+
return validateWorkDecline(input, limits);
|
|
548
|
+
}
|
|
549
|
+
if (type === 'work.progress') {
|
|
550
|
+
return validateWorkProgress(input, limits);
|
|
551
|
+
}
|
|
552
|
+
if (type === 'work.checkpoint') {
|
|
553
|
+
return validateWorkCheckpoint(input, limits);
|
|
554
|
+
}
|
|
555
|
+
if (type === 'work.result') {
|
|
556
|
+
return validateWorkResult(input, limits);
|
|
557
|
+
}
|
|
558
|
+
if (type === 'work.release') {
|
|
559
|
+
return validateWorkRelease(input, limits);
|
|
560
|
+
}
|
|
561
|
+
if (type === 'work.cancel') {
|
|
562
|
+
return validateWorkCancel(input, limits);
|
|
563
|
+
}
|
|
564
|
+
if (type === 'lease.renew') {
|
|
565
|
+
return validateLeaseRenew(input, limits);
|
|
566
|
+
}
|
|
567
|
+
if (type === 'lease.takeover_proposal') {
|
|
568
|
+
return validateLeaseTakeoverProposal(input, limits);
|
|
569
|
+
}
|
|
570
|
+
if (type === 'lease.vote') {
|
|
571
|
+
return validateLeaseVote(input, limits);
|
|
572
|
+
}
|
|
573
|
+
if (type === 'lease.certificate') {
|
|
574
|
+
return validateLeaseCertificate(input, limits);
|
|
575
|
+
}
|
|
576
|
+
return fail('unsupported_message_type', '$["type"]');
|
|
577
|
+
}
|
|
578
|
+
function validateWorkOffer(input, limits) {
|
|
579
|
+
const payload = assertClosedRecord(input, [
|
|
580
|
+
'bidDeadline',
|
|
581
|
+
'budgetReservationUnits',
|
|
582
|
+
'completionCriteria',
|
|
583
|
+
'matchingAttributes',
|
|
584
|
+
'objectiveDocumentId',
|
|
585
|
+
'objectiveId',
|
|
586
|
+
'objectiveRevision',
|
|
587
|
+
'offerAttempt',
|
|
588
|
+
'offerId',
|
|
589
|
+
'ownerEpoch',
|
|
590
|
+
'ownerPeerId',
|
|
591
|
+
'requiredCapabilityKeys',
|
|
592
|
+
'type',
|
|
593
|
+
'workDeadline',
|
|
594
|
+
'workItemId',
|
|
595
|
+
'workItemRevision',
|
|
596
|
+
], ['inputReference', 'inputSummary', 'previousOfferId'], '$["payload"]', 'invalid_payload');
|
|
597
|
+
assertPayloadType(payload.type, 'work.offer');
|
|
598
|
+
const hasInputSummary = payload.inputSummary !== undefined;
|
|
599
|
+
const hasInputReference = payload.inputReference !== undefined;
|
|
600
|
+
if (hasInputSummary === hasInputReference) {
|
|
601
|
+
fail('invalid_payload', '$["payload"]');
|
|
602
|
+
}
|
|
603
|
+
const inputSummary = hasInputSummary
|
|
604
|
+
? assertBoundedString(payload.inputSummary, '$["payload"]["inputSummary"]', maximumWorkTextBytes)
|
|
605
|
+
: undefined;
|
|
606
|
+
const inputReference = hasInputReference
|
|
607
|
+
? assertBoundedString(payload.inputReference, '$["payload"]["inputReference"]', maximumWorkTextBytes)
|
|
608
|
+
: undefined;
|
|
609
|
+
const offerId = assertIdentifier(payload.offerId, '$["payload"]["offerId"]', limits);
|
|
610
|
+
const offerAttempt = assertPositiveSafeInteger(payload.offerAttempt, '$["payload"]["offerAttempt"]', 'invalid_payload');
|
|
611
|
+
const previousOfferId = payload.previousOfferId === undefined
|
|
612
|
+
? undefined
|
|
613
|
+
: assertIdentifier(payload.previousOfferId, '$["payload"]["previousOfferId"]', limits);
|
|
614
|
+
validateRevisionPredecessor(offerAttempt, previousOfferId, '$["payload"]["previousOfferId"]');
|
|
615
|
+
if (previousOfferId === offerId) {
|
|
616
|
+
fail('invalid_payload', '$["payload"]["previousOfferId"]');
|
|
617
|
+
}
|
|
618
|
+
const requiredCapabilityKeys = validateBoundedStringArray(payload.requiredCapabilityKeys, '$["payload"]["requiredCapabilityKeys"]', maximumWorkCapabilityKeys, maximumWorkTextBytes, undefined, true);
|
|
619
|
+
if (requiredCapabilityKeys.length === 0) {
|
|
620
|
+
fail('invalid_payload', '$["payload"]["requiredCapabilityKeys"]');
|
|
621
|
+
}
|
|
622
|
+
const completionCriteria = validateBoundedStringArray(payload.completionCriteria, '$["payload"]["completionCriteria"]', maximumWorkListItems, maximumWorkTextBytes, maximumWorkListBytes);
|
|
623
|
+
if (completionCriteria.length === 0) {
|
|
624
|
+
fail('invalid_payload', '$["payload"]["completionCriteria"]');
|
|
625
|
+
}
|
|
626
|
+
const ownerEpoch = assertPositiveSafeInteger(payload.ownerEpoch, '$["payload"]["ownerEpoch"]', 'invalid_payload');
|
|
627
|
+
if (ownerEpoch !== 1) {
|
|
628
|
+
fail('invalid_payload', '$["payload"]["ownerEpoch"]');
|
|
629
|
+
}
|
|
630
|
+
const bidDeadline = assertRfc3339PayloadTimestamp(payload.bidDeadline, '$["payload"]["bidDeadline"]').text;
|
|
631
|
+
const workDeadline = assertRfc3339PayloadTimestamp(payload.workDeadline, '$["payload"]["workDeadline"]').text;
|
|
632
|
+
const fields = {
|
|
633
|
+
offerId,
|
|
634
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
635
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
636
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
637
|
+
workItemId: assertIdentifier(payload.workItemId, '$["payload"]["workItemId"]', limits),
|
|
638
|
+
workItemRevision: assertPositiveSafeInteger(payload.workItemRevision, '$["payload"]["workItemRevision"]', 'invalid_payload'),
|
|
639
|
+
ownerPeerId: assertIdentifier(payload.ownerPeerId, '$["payload"]["ownerPeerId"]', limits),
|
|
640
|
+
ownerEpoch,
|
|
641
|
+
offerAttempt,
|
|
642
|
+
...(previousOfferId === undefined ? {} : { previousOfferId }),
|
|
643
|
+
requiredCapabilityKeys,
|
|
644
|
+
matchingAttributes: validateAttributes(payload.matchingAttributes, '$["payload"]["matchingAttributes"]'),
|
|
645
|
+
completionCriteria,
|
|
646
|
+
budgetReservationUnits: assertNonnegativeSafeInteger(payload.budgetReservationUnits, '$["payload"]["budgetReservationUnits"]'),
|
|
647
|
+
bidDeadline,
|
|
648
|
+
workDeadline,
|
|
323
649
|
};
|
|
324
|
-
|
|
650
|
+
if (inputSummary !== undefined) {
|
|
651
|
+
const offerInput = { inputSummary };
|
|
652
|
+
return { type: 'work.offer', ...fields, ...offerInput };
|
|
653
|
+
}
|
|
654
|
+
if (inputReference === undefined) {
|
|
655
|
+
return fail('invalid_payload', '$["payload"]');
|
|
656
|
+
}
|
|
657
|
+
const offerInput = { inputReference };
|
|
658
|
+
return { type: 'work.offer', ...fields, ...offerInput };
|
|
659
|
+
}
|
|
660
|
+
function validateWorkBid(input, limits) {
|
|
661
|
+
const payload = assertClosedRecord(input, [
|
|
662
|
+
'advertisementId',
|
|
663
|
+
'assumptions',
|
|
664
|
+
'bidDeadline',
|
|
665
|
+
'bidExpiresAt',
|
|
666
|
+
'bidId',
|
|
667
|
+
'bidRevision',
|
|
668
|
+
'bidderPeerId',
|
|
669
|
+
'budgetUnits',
|
|
670
|
+
'capabilityId',
|
|
671
|
+
'capabilityRevision',
|
|
672
|
+
'capacityReservationUnits',
|
|
673
|
+
'expectedCompletionAt',
|
|
674
|
+
'objectiveDocumentId',
|
|
675
|
+
'objectiveId',
|
|
676
|
+
'objectiveRevision',
|
|
677
|
+
'offerAttempt',
|
|
678
|
+
'offerId',
|
|
679
|
+
'ownerEpoch',
|
|
680
|
+
'ownerPeerId',
|
|
681
|
+
'type',
|
|
682
|
+
'workDeadline',
|
|
683
|
+
'workItemId',
|
|
684
|
+
'workItemRevision',
|
|
685
|
+
], ['previousBidId'], '$["payload"]', 'invalid_payload');
|
|
686
|
+
const bidId = assertIdentifier(payload.bidId, '$["payload"]["bidId"]', limits);
|
|
687
|
+
const bidRevision = assertPositiveSafeInteger(payload.bidRevision, '$["payload"]["bidRevision"]', 'invalid_payload');
|
|
688
|
+
const previousBidId = payload.previousBidId === undefined
|
|
689
|
+
? undefined
|
|
690
|
+
: assertIdentifier(payload.previousBidId, '$["payload"]["previousBidId"]', limits);
|
|
691
|
+
validateRevisionPredecessor(bidRevision, previousBidId, '$["payload"]["previousBidId"]');
|
|
692
|
+
if (previousBidId === bidId) {
|
|
693
|
+
fail('invalid_payload', '$["payload"]["previousBidId"]');
|
|
694
|
+
}
|
|
695
|
+
const ownerEpoch = assertPositiveSafeInteger(payload.ownerEpoch, '$["payload"]["ownerEpoch"]', 'invalid_payload');
|
|
696
|
+
if (ownerEpoch !== 1) {
|
|
697
|
+
fail('invalid_payload', '$["payload"]["ownerEpoch"]');
|
|
698
|
+
}
|
|
699
|
+
return {
|
|
700
|
+
type: assertPayloadType(payload.type, 'work.bid'),
|
|
701
|
+
bidId,
|
|
702
|
+
bidRevision,
|
|
703
|
+
...(previousBidId === undefined ? {} : { previousBidId }),
|
|
704
|
+
offerId: assertIdentifier(payload.offerId, '$["payload"]["offerId"]', limits),
|
|
705
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
706
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
707
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
708
|
+
workItemId: assertIdentifier(payload.workItemId, '$["payload"]["workItemId"]', limits),
|
|
709
|
+
workItemRevision: assertPositiveSafeInteger(payload.workItemRevision, '$["payload"]["workItemRevision"]', 'invalid_payload'),
|
|
710
|
+
ownerPeerId: assertIdentifier(payload.ownerPeerId, '$["payload"]["ownerPeerId"]', limits),
|
|
711
|
+
ownerEpoch,
|
|
712
|
+
offerAttempt: assertPositiveSafeInteger(payload.offerAttempt, '$["payload"]["offerAttempt"]', 'invalid_payload'),
|
|
713
|
+
bidderPeerId: assertIdentifier(payload.bidderPeerId, '$["payload"]["bidderPeerId"]', limits),
|
|
714
|
+
advertisementId: assertIdentifier(payload.advertisementId, '$["payload"]["advertisementId"]', limits),
|
|
715
|
+
capabilityId: assertIdentifier(payload.capabilityId, '$["payload"]["capabilityId"]', limits),
|
|
716
|
+
capabilityRevision: assertPositiveSafeInteger(payload.capabilityRevision, '$["payload"]["capabilityRevision"]', 'invalid_payload'),
|
|
717
|
+
capacityReservationUnits: assertBoundedPositiveSafeInteger(payload.capacityReservationUnits, '$["payload"]["capacityReservationUnits"]', maximumCapacityReservationUnits),
|
|
718
|
+
budgetUnits: assertNonnegativeSafeInteger(payload.budgetUnits, '$["payload"]["budgetUnits"]'),
|
|
719
|
+
bidDeadline: assertRfc3339PayloadTimestamp(payload.bidDeadline, '$["payload"]["bidDeadline"]').text,
|
|
720
|
+
workDeadline: assertRfc3339PayloadTimestamp(payload.workDeadline, '$["payload"]["workDeadline"]').text,
|
|
721
|
+
expectedCompletionAt: assertRfc3339PayloadTimestamp(payload.expectedCompletionAt, '$["payload"]["expectedCompletionAt"]').text,
|
|
722
|
+
bidExpiresAt: assertRfc3339PayloadTimestamp(payload.bidExpiresAt, '$["payload"]["bidExpiresAt"]').text,
|
|
723
|
+
assumptions: validateBoundedStringArray(payload.assumptions, '$["payload"]["assumptions"]', maximumWorkListItems, maximumWorkTextBytes, maximumWorkListBytes),
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function validateWorkAward(input, limits) {
|
|
727
|
+
const payload = assertClosedRecord(input, [
|
|
728
|
+
'acceptanceDeadline',
|
|
729
|
+
'assigneePeerId',
|
|
730
|
+
'assignmentAuthorityId',
|
|
731
|
+
'assignmentEpoch',
|
|
732
|
+
'authorityKind',
|
|
733
|
+
'awardId',
|
|
734
|
+
'bidId',
|
|
735
|
+
'bidRevision',
|
|
736
|
+
'budgetReservationUnits',
|
|
737
|
+
'fencingToken',
|
|
738
|
+
'leaseExpiresAt',
|
|
739
|
+
'leaseStartsAt',
|
|
740
|
+
'objectiveDocumentId',
|
|
741
|
+
'objectiveId',
|
|
742
|
+
'objectiveRevision',
|
|
743
|
+
'offerAttempt',
|
|
744
|
+
'offerId',
|
|
745
|
+
'ownerEpoch',
|
|
746
|
+
'ownerPeerId',
|
|
747
|
+
'type',
|
|
748
|
+
'workDeadline',
|
|
749
|
+
'workItemId',
|
|
750
|
+
'workItemRevision',
|
|
751
|
+
], ['recoveryCertificateId', 'resumeCheckpointId'], '$["payload"]', 'invalid_payload');
|
|
752
|
+
assertPayloadType(payload.type, 'work.award');
|
|
753
|
+
const authorityKind = assertString(payload.authorityKind, '$["payload"]["authorityKind"]', 'invalid_payload');
|
|
754
|
+
if (authorityKind !== 'award' && authorityKind !== 'recovery_certificate') {
|
|
755
|
+
fail('invalid_payload', '$["payload"]["authorityKind"]');
|
|
756
|
+
}
|
|
757
|
+
const awardId = assertIdentifier(payload.awardId, '$["payload"]["awardId"]', limits);
|
|
758
|
+
const assignmentEpoch = assertPositiveSafeInteger(payload.assignmentEpoch, '$["payload"]["assignmentEpoch"]', 'invalid_payload');
|
|
759
|
+
const assignmentAuthorityId = assertIdentifier(payload.assignmentAuthorityId, '$["payload"]["assignmentAuthorityId"]', limits);
|
|
760
|
+
const fencingToken = assertIdentifier(payload.fencingToken, '$["payload"]["fencingToken"]', limits);
|
|
761
|
+
if (assignmentAuthorityId !== fencingToken) {
|
|
762
|
+
fail('invalid_payload', '$["payload"]["fencingToken"]');
|
|
763
|
+
}
|
|
764
|
+
const ownerEpoch = assertPositiveSafeInteger(payload.ownerEpoch, '$["payload"]["ownerEpoch"]', 'invalid_payload');
|
|
765
|
+
if (ownerEpoch !== 1) {
|
|
766
|
+
fail('invalid_payload', '$["payload"]["ownerEpoch"]');
|
|
767
|
+
}
|
|
768
|
+
const fields = {
|
|
769
|
+
type: 'work.award',
|
|
770
|
+
awardId,
|
|
771
|
+
offerId: assertIdentifier(payload.offerId, '$["payload"]["offerId"]', limits),
|
|
772
|
+
bidId: assertIdentifier(payload.bidId, '$["payload"]["bidId"]', limits),
|
|
773
|
+
bidRevision: assertPositiveSafeInteger(payload.bidRevision, '$["payload"]["bidRevision"]', 'invalid_payload'),
|
|
774
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
775
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
776
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
777
|
+
workItemId: assertIdentifier(payload.workItemId, '$["payload"]["workItemId"]', limits),
|
|
778
|
+
workItemRevision: assertPositiveSafeInteger(payload.workItemRevision, '$["payload"]["workItemRevision"]', 'invalid_payload'),
|
|
779
|
+
ownerPeerId: assertIdentifier(payload.ownerPeerId, '$["payload"]["ownerPeerId"]', limits),
|
|
780
|
+
ownerEpoch,
|
|
781
|
+
offerAttempt: assertPositiveSafeInteger(payload.offerAttempt, '$["payload"]["offerAttempt"]', 'invalid_payload'),
|
|
782
|
+
assigneePeerId: assertIdentifier(payload.assigneePeerId, '$["payload"]["assigneePeerId"]', limits),
|
|
783
|
+
assignmentEpoch,
|
|
784
|
+
assignmentAuthorityId,
|
|
785
|
+
fencingToken,
|
|
786
|
+
budgetReservationUnits: assertNonnegativeSafeInteger(payload.budgetReservationUnits, '$["payload"]["budgetReservationUnits"]'),
|
|
787
|
+
workDeadline: assertRfc3339PayloadTimestamp(payload.workDeadline, '$["payload"]["workDeadline"]').text,
|
|
788
|
+
leaseStartsAt: assertRfc3339PayloadTimestamp(payload.leaseStartsAt, '$["payload"]["leaseStartsAt"]').text,
|
|
789
|
+
leaseExpiresAt: assertRfc3339PayloadTimestamp(payload.leaseExpiresAt, '$["payload"]["leaseExpiresAt"]').text,
|
|
790
|
+
acceptanceDeadline: assertRfc3339PayloadTimestamp(payload.acceptanceDeadline, '$["payload"]["acceptanceDeadline"]').text,
|
|
791
|
+
};
|
|
792
|
+
if (authorityKind === 'award') {
|
|
793
|
+
if (payload.recoveryCertificateId !== undefined ||
|
|
794
|
+
payload.resumeCheckpointId !== undefined) {
|
|
795
|
+
fail('invalid_payload', '$["payload"]');
|
|
796
|
+
}
|
|
797
|
+
if (assignmentAuthorityId !== awardId) {
|
|
798
|
+
fail('invalid_payload', '$["payload"]["assignmentAuthorityId"]');
|
|
799
|
+
}
|
|
800
|
+
return { ...fields, authorityKind };
|
|
801
|
+
}
|
|
802
|
+
if (assignmentEpoch < 2) {
|
|
803
|
+
fail('invalid_payload', '$["payload"]["assignmentEpoch"]');
|
|
804
|
+
}
|
|
805
|
+
const recoveryCertificateId = assertIdentifier(payload.recoveryCertificateId, '$["payload"]["recoveryCertificateId"]', limits);
|
|
806
|
+
if (assignmentAuthorityId !== recoveryCertificateId) {
|
|
807
|
+
fail('invalid_payload', '$["payload"]["assignmentAuthorityId"]');
|
|
808
|
+
}
|
|
809
|
+
const resumeCheckpointId = payload.resumeCheckpointId === undefined
|
|
810
|
+
? undefined
|
|
811
|
+
: assertIdentifier(payload.resumeCheckpointId, '$["payload"]["resumeCheckpointId"]', limits);
|
|
812
|
+
return {
|
|
813
|
+
...fields,
|
|
814
|
+
authorityKind,
|
|
815
|
+
recoveryCertificateId,
|
|
816
|
+
...(resumeCheckpointId === undefined ? {} : { resumeCheckpointId }),
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
function validateWorkAccept(input, limits) {
|
|
820
|
+
const payload = validateWorkAssignmentResponse(input, 'work.accept', 'acceptanceId', limits);
|
|
821
|
+
return {
|
|
822
|
+
type: 'work.accept',
|
|
823
|
+
acceptanceId: payload.responseId,
|
|
824
|
+
...payload.fields,
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
function validateWorkDecline(input, limits) {
|
|
828
|
+
const payload = validateWorkAssignmentResponse(input, 'work.decline', 'declineId', limits);
|
|
829
|
+
return {
|
|
830
|
+
type: 'work.decline',
|
|
831
|
+
declineId: payload.responseId,
|
|
832
|
+
...payload.fields,
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
function validateWorkProgress(input, limits) {
|
|
836
|
+
const payload = assertClosedRecord(input, [
|
|
837
|
+
'acceptanceId',
|
|
838
|
+
'assigneePeerId',
|
|
839
|
+
'assignmentAuthorityId',
|
|
840
|
+
'assignmentEpoch',
|
|
841
|
+
'awardId',
|
|
842
|
+
'fencingToken',
|
|
843
|
+
'leaseExpiresAt',
|
|
844
|
+
'objectiveDocumentId',
|
|
845
|
+
'objectiveId',
|
|
846
|
+
'objectiveRevision',
|
|
847
|
+
'ownerEpoch',
|
|
848
|
+
'ownerPeerId',
|
|
849
|
+
'progressId',
|
|
850
|
+
'progressSequence',
|
|
851
|
+
'progressSummary',
|
|
852
|
+
'type',
|
|
853
|
+
'workItemId',
|
|
854
|
+
'workItemRevision',
|
|
855
|
+
], ['checkpointId'], '$["payload"]', 'invalid_payload');
|
|
856
|
+
assertPayloadType(payload.type, 'work.progress');
|
|
857
|
+
const checkpointId = payload.checkpointId === undefined
|
|
858
|
+
? undefined
|
|
859
|
+
: assertIdentifier(payload.checkpointId, '$["payload"]["checkpointId"]', limits);
|
|
860
|
+
return {
|
|
861
|
+
type: 'work.progress',
|
|
862
|
+
...validateWorkExecutionAuthorityFields(payload, limits),
|
|
863
|
+
progressId: assertIdentifier(payload.progressId, '$["payload"]["progressId"]', limits),
|
|
864
|
+
progressSequence: assertPositiveSafeInteger(payload.progressSequence, '$["payload"]["progressSequence"]', 'invalid_payload'),
|
|
865
|
+
progressSummary: assertBoundedString(payload.progressSummary, '$["payload"]["progressSummary"]', maximumWorkTextBytes),
|
|
866
|
+
...(checkpointId === undefined ? {} : { checkpointId }),
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
function validateWorkCheckpoint(input, limits) {
|
|
870
|
+
const payload = assertClosedRecord(input, [
|
|
871
|
+
'acceptanceId',
|
|
872
|
+
'assigneePeerId',
|
|
873
|
+
'assignmentAuthorityId',
|
|
874
|
+
'assignmentEpoch',
|
|
875
|
+
'awardId',
|
|
876
|
+
'checkpointDigest',
|
|
877
|
+
'checkpointId',
|
|
878
|
+
'checkpointSequence',
|
|
879
|
+
'fencingToken',
|
|
880
|
+
'leaseExpiresAt',
|
|
881
|
+
'objectiveDocumentId',
|
|
882
|
+
'objectiveId',
|
|
883
|
+
'objectiveRevision',
|
|
884
|
+
'ownerEpoch',
|
|
885
|
+
'ownerPeerId',
|
|
886
|
+
'type',
|
|
887
|
+
'workItemId',
|
|
888
|
+
'workItemRevision',
|
|
889
|
+
], ['checkpointReference', 'checkpointSummary', 'previousCheckpointId'], '$["payload"]', 'invalid_payload');
|
|
890
|
+
assertPayloadType(payload.type, 'work.checkpoint');
|
|
891
|
+
const checkpointId = assertIdentifier(payload.checkpointId, '$["payload"]["checkpointId"]', limits);
|
|
892
|
+
const checkpointSequence = assertPositiveSafeInteger(payload.checkpointSequence, '$["payload"]["checkpointSequence"]', 'invalid_payload');
|
|
893
|
+
const previousCheckpointId = payload.previousCheckpointId === undefined
|
|
894
|
+
? undefined
|
|
895
|
+
: assertIdentifier(payload.previousCheckpointId, '$["payload"]["previousCheckpointId"]', limits);
|
|
896
|
+
validateRevisionPredecessor(checkpointSequence, previousCheckpointId, '$["payload"]["previousCheckpointId"]');
|
|
897
|
+
if (previousCheckpointId === checkpointId) {
|
|
898
|
+
fail('invalid_payload', '$["payload"]["previousCheckpointId"]');
|
|
899
|
+
}
|
|
900
|
+
return {
|
|
901
|
+
type: 'work.checkpoint',
|
|
902
|
+
...validateWorkExecutionAuthorityFields(payload, limits),
|
|
903
|
+
...validateWorkCheckpointContent(payload, limits),
|
|
904
|
+
checkpointId,
|
|
905
|
+
checkpointSequence,
|
|
906
|
+
...(previousCheckpointId === undefined ? {} : { previousCheckpointId }),
|
|
907
|
+
checkpointDigest: assertContentDigest(payload.checkpointDigest, '$["payload"]["checkpointDigest"]'),
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
function validateWorkResult(input, limits) {
|
|
911
|
+
const payload = assertClosedRecord(input, [
|
|
912
|
+
'acceptanceId',
|
|
913
|
+
'assigneePeerId',
|
|
914
|
+
'assignmentAuthorityId',
|
|
915
|
+
'assignmentEpoch',
|
|
916
|
+
'awardId',
|
|
917
|
+
'fencingToken',
|
|
918
|
+
'leaseExpiresAt',
|
|
919
|
+
'objectiveDocumentId',
|
|
920
|
+
'objectiveId',
|
|
921
|
+
'objectiveRevision',
|
|
922
|
+
'ownerEpoch',
|
|
923
|
+
'ownerPeerId',
|
|
924
|
+
'resultDigest',
|
|
925
|
+
'resultId',
|
|
926
|
+
'type',
|
|
927
|
+
'workItemId',
|
|
928
|
+
'workItemRevision',
|
|
929
|
+
], ['checkpointId', 'resultReference', 'resultSummary'], '$["payload"]', 'invalid_payload');
|
|
930
|
+
assertPayloadType(payload.type, 'work.result');
|
|
931
|
+
const checkpointId = payload.checkpointId === undefined
|
|
932
|
+
? undefined
|
|
933
|
+
: assertIdentifier(payload.checkpointId, '$["payload"]["checkpointId"]', limits);
|
|
934
|
+
return {
|
|
935
|
+
type: 'work.result',
|
|
936
|
+
...validateWorkExecutionAuthorityFields(payload, limits),
|
|
937
|
+
...validateWorkResultContent(payload, limits),
|
|
938
|
+
resultId: assertIdentifier(payload.resultId, '$["payload"]["resultId"]', limits),
|
|
939
|
+
resultDigest: assertContentDigest(payload.resultDigest, '$["payload"]["resultDigest"]'),
|
|
940
|
+
...(checkpointId === undefined ? {} : { checkpointId }),
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
function validateWorkRelease(input, limits) {
|
|
944
|
+
const payload = assertClosedRecord(input, [
|
|
945
|
+
'acceptanceId',
|
|
946
|
+
'assigneePeerId',
|
|
947
|
+
'assignmentAuthorityId',
|
|
948
|
+
'assignmentEpoch',
|
|
949
|
+
'awardId',
|
|
950
|
+
'fencingToken',
|
|
951
|
+
'leaseExpiresAt',
|
|
952
|
+
'objectiveDocumentId',
|
|
953
|
+
'objectiveId',
|
|
954
|
+
'objectiveRevision',
|
|
955
|
+
'ownerEpoch',
|
|
956
|
+
'ownerPeerId',
|
|
957
|
+
'releaseAuthority',
|
|
958
|
+
'releaseDisposition',
|
|
959
|
+
'releaseId',
|
|
960
|
+
'type',
|
|
961
|
+
'workItemId',
|
|
962
|
+
'workItemRevision',
|
|
963
|
+
], [], '$["payload"]', 'invalid_payload');
|
|
964
|
+
assertPayloadType(payload.type, 'work.release');
|
|
965
|
+
const releaseAuthority = assertString(payload.releaseAuthority, '$["payload"]["releaseAuthority"]', 'invalid_payload');
|
|
966
|
+
if (releaseAuthority !== 'owner' && releaseAuthority !== 'assignee') {
|
|
967
|
+
fail('invalid_payload', '$["payload"]["releaseAuthority"]');
|
|
968
|
+
}
|
|
969
|
+
const releaseDisposition = assertString(payload.releaseDisposition, '$["payload"]["releaseDisposition"]', 'invalid_payload');
|
|
970
|
+
if (releaseDisposition !== 'reoffer' && releaseDisposition !== 'close') {
|
|
971
|
+
fail('invalid_payload', '$["payload"]["releaseDisposition"]');
|
|
972
|
+
}
|
|
973
|
+
return {
|
|
974
|
+
type: 'work.release',
|
|
975
|
+
...validateWorkExecutionAuthorityFields(payload, limits),
|
|
976
|
+
releaseId: assertIdentifier(payload.releaseId, '$["payload"]["releaseId"]', limits),
|
|
977
|
+
releaseAuthority,
|
|
978
|
+
releaseDisposition,
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
function validateWorkCancel(input, limits) {
|
|
982
|
+
const payload = assertClosedRecord(input, [
|
|
983
|
+
'assigneePeerId',
|
|
984
|
+
'assignmentAuthorityId',
|
|
985
|
+
'assignmentEpoch',
|
|
986
|
+
'assignmentState',
|
|
987
|
+
'awardId',
|
|
988
|
+
'cancellationId',
|
|
989
|
+
'fencingToken',
|
|
990
|
+
'leaseExpiresAt',
|
|
991
|
+
'objectiveDocumentId',
|
|
992
|
+
'objectiveId',
|
|
993
|
+
'objectiveRevision',
|
|
994
|
+
'ownerEpoch',
|
|
995
|
+
'ownerPeerId',
|
|
996
|
+
'type',
|
|
997
|
+
'workItemId',
|
|
998
|
+
'workItemRevision',
|
|
999
|
+
], ['acceptanceId'], '$["payload"]', 'invalid_payload');
|
|
1000
|
+
assertPayloadType(payload.type, 'work.cancel');
|
|
1001
|
+
const fields = validateWorkAssignmentAuthorityFields(payload, limits);
|
|
1002
|
+
const cancellationId = assertIdentifier(payload.cancellationId, '$["payload"]["cancellationId"]', limits);
|
|
1003
|
+
const assignmentState = assertString(payload.assignmentState, '$["payload"]["assignmentState"]', 'invalid_payload');
|
|
1004
|
+
if (assignmentState === 'award_pending') {
|
|
1005
|
+
if (Object.hasOwn(payload, 'acceptanceId')) {
|
|
1006
|
+
fail('invalid_payload', '$["payload"]["acceptanceId"]');
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
type: 'work.cancel',
|
|
1010
|
+
...fields,
|
|
1011
|
+
cancellationId,
|
|
1012
|
+
assignmentState,
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (assignmentState === 'active') {
|
|
1016
|
+
return {
|
|
1017
|
+
type: 'work.cancel',
|
|
1018
|
+
...fields,
|
|
1019
|
+
cancellationId,
|
|
1020
|
+
assignmentState,
|
|
1021
|
+
acceptanceId: assertIdentifier(payload.acceptanceId, '$["payload"]["acceptanceId"]', limits),
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
return fail('invalid_payload', '$["payload"]["assignmentState"]');
|
|
1025
|
+
}
|
|
1026
|
+
function validateLeaseRenew(input, limits) {
|
|
1027
|
+
const payload = assertClosedRecord(input, [
|
|
1028
|
+
'acceptanceId',
|
|
1029
|
+
'assigneePeerId',
|
|
1030
|
+
'assignmentAuthorityId',
|
|
1031
|
+
'assignmentEpoch',
|
|
1032
|
+
'awardId',
|
|
1033
|
+
'fencingToken',
|
|
1034
|
+
'leaseExpiresAt',
|
|
1035
|
+
'leaseRenewalId',
|
|
1036
|
+
'leaseRenewalSequence',
|
|
1037
|
+
'objectiveDocumentId',
|
|
1038
|
+
'objectiveId',
|
|
1039
|
+
'objectiveRevision',
|
|
1040
|
+
'ownerEpoch',
|
|
1041
|
+
'ownerPeerId',
|
|
1042
|
+
'renewedLeaseExpiresAt',
|
|
1043
|
+
'type',
|
|
1044
|
+
'workItemId',
|
|
1045
|
+
'workItemRevision',
|
|
1046
|
+
], ['previousLeaseRenewalId'], '$["payload"]', 'invalid_payload');
|
|
1047
|
+
assertPayloadType(payload.type, 'lease.renew');
|
|
1048
|
+
const fields = validateWorkExecutionAuthorityFields(payload, limits);
|
|
1049
|
+
const leaseRenewalId = assertIdentifier(payload.leaseRenewalId, '$["payload"]["leaseRenewalId"]', limits);
|
|
1050
|
+
const leaseRenewalSequence = assertPositiveSafeInteger(payload.leaseRenewalSequence, '$["payload"]["leaseRenewalSequence"]', 'invalid_payload');
|
|
1051
|
+
if (leaseRenewalSequence > maximumLeaseRenewals) {
|
|
1052
|
+
fail('invalid_payload', '$["payload"]["leaseRenewalSequence"]');
|
|
1053
|
+
}
|
|
1054
|
+
const previousLeaseRenewalId = payload.previousLeaseRenewalId === undefined
|
|
1055
|
+
? undefined
|
|
1056
|
+
: assertIdentifier(payload.previousLeaseRenewalId, '$["payload"]["previousLeaseRenewalId"]', limits);
|
|
1057
|
+
validateRevisionPredecessor(leaseRenewalSequence, previousLeaseRenewalId, '$["payload"]["previousLeaseRenewalId"]');
|
|
1058
|
+
if (previousLeaseRenewalId === leaseRenewalId) {
|
|
1059
|
+
fail('invalid_payload', '$["payload"]["previousLeaseRenewalId"]');
|
|
1060
|
+
}
|
|
1061
|
+
const renewedLeaseExpiresAt = assertRfc3339PayloadTimestamp(payload.renewedLeaseExpiresAt, '$["payload"]["renewedLeaseExpiresAt"]');
|
|
1062
|
+
const currentLeaseExpiresAt = parseRfc3339(fields.leaseExpiresAt, '$["payload"]["leaseExpiresAt"]');
|
|
1063
|
+
if (renewedLeaseExpiresAt.instant <= currentLeaseExpiresAt) {
|
|
1064
|
+
fail('invalid_payload', '$["payload"]["renewedLeaseExpiresAt"]');
|
|
1065
|
+
}
|
|
1066
|
+
if (renewedLeaseExpiresAt.instant - currentLeaseExpiresAt >
|
|
1067
|
+
BigInt(maximumLeaseDurationMs) * 1000000n) {
|
|
1068
|
+
fail('invalid_payload', '$["payload"]["renewedLeaseExpiresAt"]');
|
|
1069
|
+
}
|
|
1070
|
+
return {
|
|
1071
|
+
type: 'lease.renew',
|
|
1072
|
+
...fields,
|
|
1073
|
+
leaseRenewalId,
|
|
1074
|
+
leaseRenewalSequence,
|
|
1075
|
+
...(previousLeaseRenewalId === undefined ? {} : { previousLeaseRenewalId }),
|
|
1076
|
+
renewedLeaseExpiresAt: renewedLeaseExpiresAt.text,
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function validateLeaseTakeoverProposal(input, limits) {
|
|
1080
|
+
const payload = assertClosedRecord(input, [
|
|
1081
|
+
'acceptanceId',
|
|
1082
|
+
'assigneePeerId',
|
|
1083
|
+
'assignmentAuthorityId',
|
|
1084
|
+
'assignmentEpoch',
|
|
1085
|
+
'awardId',
|
|
1086
|
+
'fencingToken',
|
|
1087
|
+
'leaseExpiresAt',
|
|
1088
|
+
'leaseRenewalSequence',
|
|
1089
|
+
'objectiveDocumentId',
|
|
1090
|
+
'objectiveId',
|
|
1091
|
+
'objectiveRevision',
|
|
1092
|
+
'ownerEpoch',
|
|
1093
|
+
'ownerPeerId',
|
|
1094
|
+
'proposalAuthority',
|
|
1095
|
+
'proposedAssigneePeerId',
|
|
1096
|
+
'proposedAssignmentEpoch',
|
|
1097
|
+
'proposerPeerId',
|
|
1098
|
+
'takeoverProposalId',
|
|
1099
|
+
'type',
|
|
1100
|
+
'workItemId',
|
|
1101
|
+
'workItemRevision',
|
|
1102
|
+
], ['candidateConsentProposalId', 'latestLeaseRenewalId'], '$["payload"]', 'invalid_payload');
|
|
1103
|
+
assertPayloadType(payload.type, 'lease.takeover_proposal');
|
|
1104
|
+
const fields = validateWorkExecutionAuthorityFields(payload, limits);
|
|
1105
|
+
const takeoverProposalId = assertIdentifier(payload.takeoverProposalId, '$["payload"]["takeoverProposalId"]', limits);
|
|
1106
|
+
const proposerPeerId = assertIdentifier(payload.proposerPeerId, '$["payload"]["proposerPeerId"]', limits);
|
|
1107
|
+
const proposedAssigneePeerId = assertIdentifier(payload.proposedAssigneePeerId, '$["payload"]["proposedAssigneePeerId"]', limits);
|
|
1108
|
+
if (proposedAssigneePeerId === fields.assigneePeerId) {
|
|
1109
|
+
fail('invalid_payload', '$["payload"]["proposedAssigneePeerId"]');
|
|
1110
|
+
}
|
|
1111
|
+
const proposalAuthority = assertString(payload.proposalAuthority, '$["payload"]["proposalAuthority"]', 'invalid_payload');
|
|
1112
|
+
if (proposalAuthority !== 'candidate' && proposalAuthority !== 'witness') {
|
|
1113
|
+
fail('invalid_payload', '$["payload"]["proposalAuthority"]');
|
|
1114
|
+
}
|
|
1115
|
+
if (proposalAuthority === 'candidate' &&
|
|
1116
|
+
proposerPeerId !== proposedAssigneePeerId) {
|
|
1117
|
+
fail('invalid_payload', '$["payload"]["proposedAssigneePeerId"]');
|
|
1118
|
+
}
|
|
1119
|
+
if (proposalAuthority === 'witness' &&
|
|
1120
|
+
proposerPeerId === proposedAssigneePeerId) {
|
|
1121
|
+
fail('invalid_payload', '$["payload"]["proposalAuthority"]');
|
|
1122
|
+
}
|
|
1123
|
+
if (proposalAuthority === 'candidate' &&
|
|
1124
|
+
Object.hasOwn(payload, 'candidateConsentProposalId')) {
|
|
1125
|
+
fail('invalid_payload', '$["payload"]["candidateConsentProposalId"]');
|
|
1126
|
+
}
|
|
1127
|
+
const proposedAssignmentEpoch = assertPositiveSafeInteger(payload.proposedAssignmentEpoch, '$["payload"]["proposedAssignmentEpoch"]', 'invalid_payload');
|
|
1128
|
+
if (proposedAssignmentEpoch !== fields.assignmentEpoch + 1) {
|
|
1129
|
+
fail('invalid_payload', '$["payload"]["proposedAssignmentEpoch"]');
|
|
1130
|
+
}
|
|
1131
|
+
const leaseRenewalSequence = assertNonnegativeSafeInteger(payload.leaseRenewalSequence, '$["payload"]["leaseRenewalSequence"]');
|
|
1132
|
+
if (leaseRenewalSequence > maximumLeaseRenewals) {
|
|
1133
|
+
fail('invalid_payload', '$["payload"]["leaseRenewalSequence"]');
|
|
1134
|
+
}
|
|
1135
|
+
const latestLeaseRenewalId = leaseRenewalSequence === 0
|
|
1136
|
+
? undefined
|
|
1137
|
+
: assertIdentifier(payload.latestLeaseRenewalId, '$["payload"]["latestLeaseRenewalId"]', limits);
|
|
1138
|
+
if (leaseRenewalSequence === 0) {
|
|
1139
|
+
if (Object.hasOwn(payload, 'latestLeaseRenewalId')) {
|
|
1140
|
+
fail('invalid_payload', '$["payload"]["latestLeaseRenewalId"]');
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
const proposalFields = {
|
|
1144
|
+
type: 'lease.takeover_proposal',
|
|
1145
|
+
...fields,
|
|
1146
|
+
takeoverProposalId,
|
|
1147
|
+
proposerPeerId,
|
|
1148
|
+
proposedAssigneePeerId,
|
|
1149
|
+
proposedAssignmentEpoch,
|
|
1150
|
+
leaseRenewalSequence,
|
|
1151
|
+
...(latestLeaseRenewalId === undefined ? {} : { latestLeaseRenewalId }),
|
|
1152
|
+
};
|
|
1153
|
+
if (proposalAuthority === 'candidate') {
|
|
1154
|
+
return {
|
|
1155
|
+
...proposalFields,
|
|
1156
|
+
proposalAuthority,
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
return {
|
|
1160
|
+
...proposalFields,
|
|
1161
|
+
proposalAuthority,
|
|
1162
|
+
candidateConsentProposalId: assertIdentifier(payload.candidateConsentProposalId, '$["payload"]["candidateConsentProposalId"]', limits),
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
function validateLeaseVote(input, limits) {
|
|
1166
|
+
const payload = assertClosedRecord(input, [
|
|
1167
|
+
'leaseVoteId',
|
|
1168
|
+
'objectiveId',
|
|
1169
|
+
'takeoverProposalId',
|
|
1170
|
+
'type',
|
|
1171
|
+
'witnessPeerId',
|
|
1172
|
+
], [], '$["payload"]', 'invalid_payload');
|
|
1173
|
+
return {
|
|
1174
|
+
type: assertPayloadType(payload.type, 'lease.vote'),
|
|
1175
|
+
leaseVoteId: assertIdentifier(payload.leaseVoteId, '$["payload"]["leaseVoteId"]', limits),
|
|
1176
|
+
takeoverProposalId: assertIdentifier(payload.takeoverProposalId, '$["payload"]["takeoverProposalId"]', limits),
|
|
1177
|
+
witnessPeerId: assertIdentifier(payload.witnessPeerId, '$["payload"]["witnessPeerId"]', limits),
|
|
1178
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
function validateLeaseCertificate(input, limits) {
|
|
1182
|
+
const payload = assertClosedRecord(input, [
|
|
1183
|
+
'certificateAssemblerPeerId',
|
|
1184
|
+
'certificateId',
|
|
1185
|
+
'leaseVoteIds',
|
|
1186
|
+
'objectiveId',
|
|
1187
|
+
'takeoverProposalId',
|
|
1188
|
+
'type',
|
|
1189
|
+
], [], '$["payload"]', 'invalid_payload');
|
|
1190
|
+
const leaseVoteIds = validateIdentifierArray(payload.leaseVoteIds, '$["payload"]["leaseVoteIds"]', maximumRecoveryWitnesses, limits);
|
|
1191
|
+
if (leaseVoteIds.length < 2) {
|
|
1192
|
+
fail('invalid_payload', '$["payload"]["leaseVoteIds"]');
|
|
1193
|
+
}
|
|
1194
|
+
return {
|
|
1195
|
+
type: assertPayloadType(payload.type, 'lease.certificate'),
|
|
1196
|
+
certificateId: assertIdentifier(payload.certificateId, '$["payload"]["certificateId"]', limits),
|
|
1197
|
+
certificateAssemblerPeerId: assertIdentifier(payload.certificateAssemblerPeerId, '$["payload"]["certificateAssemblerPeerId"]', limits),
|
|
1198
|
+
takeoverProposalId: assertIdentifier(payload.takeoverProposalId, '$["payload"]["takeoverProposalId"]', limits),
|
|
1199
|
+
leaseVoteIds,
|
|
1200
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
function validateWorkExecutionAuthorityFields(payload, limits) {
|
|
1204
|
+
return {
|
|
1205
|
+
...validateWorkAssignmentAuthorityFields(payload, limits),
|
|
1206
|
+
acceptanceId: assertIdentifier(payload.acceptanceId, '$["payload"]["acceptanceId"]', limits),
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
function validateWorkAssignmentAuthorityFields(payload, limits) {
|
|
1210
|
+
const ownerEpoch = assertPositiveSafeInteger(payload.ownerEpoch, '$["payload"]["ownerEpoch"]', 'invalid_payload');
|
|
1211
|
+
if (ownerEpoch !== 1) {
|
|
1212
|
+
fail('invalid_payload', '$["payload"]["ownerEpoch"]');
|
|
1213
|
+
}
|
|
1214
|
+
const assignmentAuthorityId = assertIdentifier(payload.assignmentAuthorityId, '$["payload"]["assignmentAuthorityId"]', limits);
|
|
1215
|
+
const fencingToken = assertIdentifier(payload.fencingToken, '$["payload"]["fencingToken"]', limits);
|
|
1216
|
+
if (assignmentAuthorityId !== fencingToken) {
|
|
1217
|
+
fail('invalid_payload', '$["payload"]["fencingToken"]');
|
|
1218
|
+
}
|
|
1219
|
+
return {
|
|
1220
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
1221
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
1222
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
1223
|
+
workItemId: assertIdentifier(payload.workItemId, '$["payload"]["workItemId"]', limits),
|
|
1224
|
+
workItemRevision: assertPositiveSafeInteger(payload.workItemRevision, '$["payload"]["workItemRevision"]', 'invalid_payload'),
|
|
1225
|
+
ownerPeerId: assertIdentifier(payload.ownerPeerId, '$["payload"]["ownerPeerId"]', limits),
|
|
1226
|
+
ownerEpoch,
|
|
1227
|
+
assigneePeerId: assertIdentifier(payload.assigneePeerId, '$["payload"]["assigneePeerId"]', limits),
|
|
1228
|
+
awardId: assertIdentifier(payload.awardId, '$["payload"]["awardId"]', limits),
|
|
1229
|
+
assignmentEpoch: assertPositiveSafeInteger(payload.assignmentEpoch, '$["payload"]["assignmentEpoch"]', 'invalid_payload'),
|
|
1230
|
+
assignmentAuthorityId,
|
|
1231
|
+
fencingToken,
|
|
1232
|
+
leaseExpiresAt: assertRfc3339PayloadTimestamp(payload.leaseExpiresAt, '$["payload"]["leaseExpiresAt"]').text,
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
function validateWorkCheckpointContent(payload, limits) {
|
|
1236
|
+
const hasSummary = payload.checkpointSummary !== undefined;
|
|
1237
|
+
const hasReference = payload.checkpointReference !== undefined;
|
|
1238
|
+
if (hasSummary === hasReference) {
|
|
1239
|
+
fail('invalid_payload', '$["payload"]');
|
|
1240
|
+
}
|
|
1241
|
+
if (hasSummary) {
|
|
1242
|
+
return {
|
|
1243
|
+
checkpointSummary: assertBoundedString(payload.checkpointSummary, '$["payload"]["checkpointSummary"]', maximumWorkTextBytes),
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
return {
|
|
1247
|
+
checkpointReference: assertBoundedString(payload.checkpointReference, '$["payload"]["checkpointReference"]', maximumWorkTextBytes),
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
function validateWorkResultContent(payload, limits) {
|
|
1251
|
+
const hasSummary = payload.resultSummary !== undefined;
|
|
1252
|
+
const hasReference = payload.resultReference !== undefined;
|
|
1253
|
+
if (hasSummary === hasReference) {
|
|
1254
|
+
fail('invalid_payload', '$["payload"]');
|
|
1255
|
+
}
|
|
1256
|
+
if (hasSummary) {
|
|
1257
|
+
return {
|
|
1258
|
+
resultSummary: assertBoundedString(payload.resultSummary, '$["payload"]["resultSummary"]', maximumWorkTextBytes),
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
return {
|
|
1262
|
+
resultReference: assertBoundedString(payload.resultReference, '$["payload"]["resultReference"]', maximumWorkTextBytes),
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function validateWorkAssignmentResponse(input, type, responseIdKey, limits) {
|
|
1266
|
+
const payload = assertClosedRecord(input, [
|
|
1267
|
+
'acceptanceDeadline',
|
|
1268
|
+
'assigneePeerId',
|
|
1269
|
+
'assignmentAuthorityId',
|
|
1270
|
+
'assignmentEpoch',
|
|
1271
|
+
'awardId',
|
|
1272
|
+
'fencingToken',
|
|
1273
|
+
'objectiveDocumentId',
|
|
1274
|
+
'objectiveId',
|
|
1275
|
+
'objectiveRevision',
|
|
1276
|
+
'ownerEpoch',
|
|
1277
|
+
'ownerPeerId',
|
|
1278
|
+
responseIdKey,
|
|
1279
|
+
'type',
|
|
1280
|
+
'workItemId',
|
|
1281
|
+
'workItemRevision',
|
|
1282
|
+
], [], '$["payload"]', 'invalid_payload');
|
|
1283
|
+
assertPayloadType(payload.type, type);
|
|
1284
|
+
const assignmentAuthorityId = assertIdentifier(payload.assignmentAuthorityId, '$["payload"]["assignmentAuthorityId"]', limits);
|
|
1285
|
+
const fencingToken = assertIdentifier(payload.fencingToken, '$["payload"]["fencingToken"]', limits);
|
|
1286
|
+
if (assignmentAuthorityId !== fencingToken) {
|
|
1287
|
+
fail('invalid_payload', '$["payload"]["fencingToken"]');
|
|
1288
|
+
}
|
|
1289
|
+
const ownerEpoch = assertPositiveSafeInteger(payload.ownerEpoch, '$["payload"]["ownerEpoch"]', 'invalid_payload');
|
|
1290
|
+
if (ownerEpoch !== 1) {
|
|
1291
|
+
fail('invalid_payload', '$["payload"]["ownerEpoch"]');
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1294
|
+
responseId: assertIdentifier(payload[responseIdKey], `$["payload"]["${responseIdKey}"]`, limits),
|
|
1295
|
+
fields: {
|
|
1296
|
+
awardId: assertIdentifier(payload.awardId, '$["payload"]["awardId"]', limits),
|
|
1297
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
1298
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
1299
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
1300
|
+
workItemId: assertIdentifier(payload.workItemId, '$["payload"]["workItemId"]', limits),
|
|
1301
|
+
workItemRevision: assertPositiveSafeInteger(payload.workItemRevision, '$["payload"]["workItemRevision"]', 'invalid_payload'),
|
|
1302
|
+
ownerPeerId: assertIdentifier(payload.ownerPeerId, '$["payload"]["ownerPeerId"]', limits),
|
|
1303
|
+
ownerEpoch,
|
|
1304
|
+
assigneePeerId: assertIdentifier(payload.assigneePeerId, '$["payload"]["assigneePeerId"]', limits),
|
|
1305
|
+
assignmentEpoch: assertPositiveSafeInteger(payload.assignmentEpoch, '$["payload"]["assignmentEpoch"]', 'invalid_payload'),
|
|
1306
|
+
assignmentAuthorityId,
|
|
1307
|
+
fencingToken,
|
|
1308
|
+
acceptanceDeadline: assertRfc3339PayloadTimestamp(payload.acceptanceDeadline, '$["payload"]["acceptanceDeadline"]').text,
|
|
1309
|
+
},
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
function validateObjectiveDocument(input, type, limits) {
|
|
1313
|
+
const requiredKeys = [
|
|
1314
|
+
'acceptanceWindowMs',
|
|
1315
|
+
'bidWindowMs',
|
|
1316
|
+
'issuerPeerId',
|
|
1317
|
+
'maximumBudgetUnits',
|
|
1318
|
+
'maximumConcurrentAssignments',
|
|
1319
|
+
'maximumLeaseDurationMs',
|
|
1320
|
+
'maximumLeaseRenewals',
|
|
1321
|
+
'maximumWorkItems',
|
|
1322
|
+
'objectiveDocumentId',
|
|
1323
|
+
'objectiveId',
|
|
1324
|
+
'objectiveRevision',
|
|
1325
|
+
'permittedCapabilityKeys',
|
|
1326
|
+
'recoveryGraceMs',
|
|
1327
|
+
'recoveryWitnessPeerIds',
|
|
1328
|
+
'recoveryWitnessThreshold',
|
|
1329
|
+
'successCriteria',
|
|
1330
|
+
'type',
|
|
1331
|
+
'validFrom',
|
|
1332
|
+
'validUntil',
|
|
1333
|
+
];
|
|
1334
|
+
if (type === 'objective.revise') {
|
|
1335
|
+
requiredKeys.push('previousObjectiveDocumentId');
|
|
1336
|
+
}
|
|
1337
|
+
const payload = assertClosedRecord(input, requiredKeys, ['authorizedObserverPeerIds', 'contentReference', 'summary'], '$["payload"]', 'invalid_payload');
|
|
1338
|
+
assertPayloadType(payload.type, type);
|
|
1339
|
+
const hasSummary = payload.summary !== undefined;
|
|
1340
|
+
const hasContentReference = payload.contentReference !== undefined;
|
|
1341
|
+
if (hasSummary === hasContentReference) {
|
|
1342
|
+
fail('invalid_payload', '$["payload"]');
|
|
1343
|
+
}
|
|
1344
|
+
const summary = hasSummary
|
|
1345
|
+
? assertBoundedString(payload.summary, '$["payload"]["summary"]', maximumObjectiveTextBytes)
|
|
1346
|
+
: undefined;
|
|
1347
|
+
const contentReference = hasContentReference
|
|
1348
|
+
? assertBoundedString(payload.contentReference, '$["payload"]["contentReference"]', maximumObjectiveTextBytes)
|
|
1349
|
+
: undefined;
|
|
1350
|
+
const successCriteria = validateBoundedStringArray(payload.successCriteria, '$["payload"]["successCriteria"]', maximumSuccessCriteria, maximumObjectiveTextBytes, maximumSuccessCriteriaBytes);
|
|
1351
|
+
if (successCriteria.length === 0) {
|
|
1352
|
+
fail('invalid_payload', '$["payload"]["successCriteria"]');
|
|
1353
|
+
}
|
|
1354
|
+
const permittedCapabilityKeys = validateBoundedStringArray(payload.permittedCapabilityKeys, '$["payload"]["permittedCapabilityKeys"]', maximumPermittedCapabilityKeys, maximumObjectiveTextBytes, undefined, true);
|
|
1355
|
+
if (permittedCapabilityKeys.length === 0) {
|
|
1356
|
+
fail('invalid_payload', '$["payload"]["permittedCapabilityKeys"]');
|
|
1357
|
+
}
|
|
1358
|
+
const recoveryWitnessPeerIds = validateIdentifierArray(payload.recoveryWitnessPeerIds, '$["payload"]["recoveryWitnessPeerIds"]', maximumRecoveryWitnesses, limits);
|
|
1359
|
+
if (recoveryWitnessPeerIds.length < minimumRecoveryWitnesses) {
|
|
1360
|
+
fail('invalid_payload', '$["payload"]["recoveryWitnessPeerIds"]');
|
|
1361
|
+
}
|
|
1362
|
+
const recoveryWitnessThreshold = assertPositiveSafeInteger(payload.recoveryWitnessThreshold, '$["payload"]["recoveryWitnessThreshold"]', 'invalid_payload');
|
|
1363
|
+
if (recoveryWitnessThreshold > recoveryWitnessPeerIds.length ||
|
|
1364
|
+
recoveryWitnessThreshold <= recoveryWitnessPeerIds.length / 2) {
|
|
1365
|
+
fail('invalid_payload', '$["payload"]["recoveryWitnessThreshold"]');
|
|
1366
|
+
}
|
|
1367
|
+
const authorizedObserverPeerIds = payload.authorizedObserverPeerIds === undefined
|
|
1368
|
+
? undefined
|
|
1369
|
+
: validateIdentifierArray(payload.authorizedObserverPeerIds, '$["payload"]["authorizedObserverPeerIds"]', maximumAuthorizedObservers, limits);
|
|
1370
|
+
const maximumWorkItems = assertPositiveSafeInteger(payload.maximumWorkItems, '$["payload"]["maximumWorkItems"]', 'invalid_payload');
|
|
1371
|
+
if (maximumWorkItems > maximumObjectiveWorkItems) {
|
|
1372
|
+
fail('invalid_payload', '$["payload"]["maximumWorkItems"]');
|
|
1373
|
+
}
|
|
1374
|
+
const maximumConcurrentAssignments = assertPositiveSafeInteger(payload.maximumConcurrentAssignments, '$["payload"]["maximumConcurrentAssignments"]', 'invalid_payload');
|
|
1375
|
+
if (maximumConcurrentAssignments > maximumWorkItems) {
|
|
1376
|
+
fail('invalid_payload', '$["payload"]["maximumConcurrentAssignments"]');
|
|
1377
|
+
}
|
|
1378
|
+
const maximumBudgetUnits = assertNonnegativeSafeInteger(payload.maximumBudgetUnits, '$["payload"]["maximumBudgetUnits"]');
|
|
1379
|
+
const bidWindowMs = assertBoundedPositiveSafeInteger(payload.bidWindowMs, '$["payload"]["bidWindowMs"]', maximumBidWindowMs);
|
|
1380
|
+
const acceptanceWindowMs = assertBoundedPositiveSafeInteger(payload.acceptanceWindowMs, '$["payload"]["acceptanceWindowMs"]', maximumAcceptanceWindowMs);
|
|
1381
|
+
const maximumLeaseDuration = assertBoundedPositiveSafeInteger(payload.maximumLeaseDurationMs, '$["payload"]["maximumLeaseDurationMs"]', maximumLeaseDurationMs);
|
|
1382
|
+
const recoveryGraceMs = assertBoundedPositiveSafeInteger(payload.recoveryGraceMs, '$["payload"]["recoveryGraceMs"]', maximumRecoveryGraceMs);
|
|
1383
|
+
const maximumLeaseRenewalsValue = assertNonnegativeSafeInteger(payload.maximumLeaseRenewals, '$["payload"]["maximumLeaseRenewals"]');
|
|
1384
|
+
if (maximumLeaseRenewalsValue > maximumLeaseRenewals) {
|
|
1385
|
+
fail('invalid_payload', '$["payload"]["maximumLeaseRenewals"]');
|
|
1386
|
+
}
|
|
1387
|
+
const validFrom = assertRfc3339PayloadTimestamp(payload.validFrom, '$["payload"]["validFrom"]');
|
|
1388
|
+
const validUntil = assertRfc3339PayloadTimestamp(payload.validUntil, '$["payload"]["validUntil"]');
|
|
1389
|
+
const validityDuration = assertObjectiveValidity(validFrom.instant, validUntil.instant);
|
|
1390
|
+
for (const [path, timer] of [
|
|
1391
|
+
['$["payload"]["bidWindowMs"]', bidWindowMs],
|
|
1392
|
+
['$["payload"]["acceptanceWindowMs"]', acceptanceWindowMs],
|
|
1393
|
+
['$["payload"]["maximumLeaseDurationMs"]', maximumLeaseDuration],
|
|
1394
|
+
['$["payload"]["recoveryGraceMs"]', recoveryGraceMs],
|
|
1395
|
+
]) {
|
|
1396
|
+
if (BigInt(timer) * 1000000n > validityDuration) {
|
|
1397
|
+
fail('invalid_payload', path);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
const fields = {
|
|
1401
|
+
objectiveDocumentId: assertIdentifier(payload.objectiveDocumentId, '$["payload"]["objectiveDocumentId"]', limits),
|
|
1402
|
+
objectiveId: assertIdentifier(payload.objectiveId, '$["payload"]["objectiveId"]', limits),
|
|
1403
|
+
objectiveRevision: assertPositiveSafeInteger(payload.objectiveRevision, '$["payload"]["objectiveRevision"]', 'invalid_payload'),
|
|
1404
|
+
issuerPeerId: assertIdentifier(payload.issuerPeerId, '$["payload"]["issuerPeerId"]', limits),
|
|
1405
|
+
successCriteria,
|
|
1406
|
+
permittedCapabilityKeys,
|
|
1407
|
+
maximumWorkItems,
|
|
1408
|
+
maximumConcurrentAssignments,
|
|
1409
|
+
maximumBudgetUnits,
|
|
1410
|
+
bidWindowMs,
|
|
1411
|
+
acceptanceWindowMs,
|
|
1412
|
+
maximumLeaseDurationMs: maximumLeaseDuration,
|
|
1413
|
+
recoveryGraceMs,
|
|
1414
|
+
maximumLeaseRenewals: maximumLeaseRenewalsValue,
|
|
1415
|
+
recoveryWitnessPeerIds,
|
|
1416
|
+
recoveryWitnessThreshold,
|
|
1417
|
+
validFrom: validFrom.text,
|
|
1418
|
+
validUntil: validUntil.text,
|
|
1419
|
+
...(authorizedObserverPeerIds === undefined
|
|
1420
|
+
? {}
|
|
1421
|
+
: { authorizedObserverPeerIds }),
|
|
1422
|
+
};
|
|
1423
|
+
if (summary !== undefined) {
|
|
1424
|
+
return { ...fields, summary };
|
|
1425
|
+
}
|
|
1426
|
+
if (contentReference === undefined) {
|
|
1427
|
+
return fail('invalid_payload', '$["payload"]');
|
|
1428
|
+
}
|
|
1429
|
+
return { ...fields, contentReference };
|
|
325
1430
|
}
|
|
326
1431
|
function validateProof(input, limits) {
|
|
327
1432
|
const proof = assertClosedRecord(input, ['algorithm', 'keyId', 'value'], [], '$["proof"]', 'invalid_proof');
|
|
@@ -371,28 +1476,517 @@ function validateCriticalExtensions(input, extensions, limits) {
|
|
|
371
1476
|
}
|
|
372
1477
|
return result;
|
|
373
1478
|
}
|
|
374
|
-
function validateMessageSpecificEnvelope(type, audience, objectiveId, causationId) {
|
|
375
|
-
if (type === 'peer.
|
|
1479
|
+
function validateMessageSpecificEnvelope(type, sender, audience, objectiveId, causationId, payload, sentAt, expiresAt) {
|
|
1480
|
+
if (payload.type === 'peer.card') {
|
|
1481
|
+
if (payload.subjectPeerId !== sender.peerId) {
|
|
1482
|
+
fail('invalid_payload', '$["payload"]["subjectPeerId"]');
|
|
1483
|
+
}
|
|
1484
|
+
if (payload.instanceId !== sender.instanceId) {
|
|
1485
|
+
fail('invalid_payload', '$["payload"]["instanceId"]');
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
else if (payload.type === 'peer.goodbye' &&
|
|
1489
|
+
payload.instanceId !== sender.instanceId) {
|
|
1490
|
+
fail('invalid_payload', '$["payload"]["instanceId"]');
|
|
1491
|
+
}
|
|
1492
|
+
else if (payload.type === 'capability.advertise' &&
|
|
1493
|
+
payload.ownerPeerId !== sender.peerId) {
|
|
1494
|
+
fail('invalid_payload', '$["payload"]["ownerPeerId"]');
|
|
1495
|
+
}
|
|
1496
|
+
else if ((payload.type === 'objective.announce' ||
|
|
1497
|
+
payload.type === 'objective.revise') &&
|
|
1498
|
+
payload.issuerPeerId !== sender.peerId) {
|
|
1499
|
+
fail('invalid_payload', '$["payload"]["issuerPeerId"]');
|
|
1500
|
+
}
|
|
1501
|
+
else if (payload.type === 'work.offer' &&
|
|
1502
|
+
payload.ownerPeerId !== sender.peerId) {
|
|
1503
|
+
fail('invalid_payload', '$["payload"]["ownerPeerId"]');
|
|
1504
|
+
}
|
|
1505
|
+
else if (payload.type === 'work.bid' &&
|
|
1506
|
+
payload.bidderPeerId !== sender.peerId) {
|
|
1507
|
+
fail('invalid_payload', '$["payload"]["bidderPeerId"]');
|
|
1508
|
+
}
|
|
1509
|
+
else if (payload.type === 'work.award' &&
|
|
1510
|
+
payload.ownerPeerId !== sender.peerId) {
|
|
1511
|
+
fail('invalid_payload', '$["payload"]["ownerPeerId"]');
|
|
1512
|
+
}
|
|
1513
|
+
else if ((payload.type === 'work.accept' ||
|
|
1514
|
+
payload.type === 'work.decline' ||
|
|
1515
|
+
payload.type === 'work.progress' ||
|
|
1516
|
+
payload.type === 'work.checkpoint' ||
|
|
1517
|
+
payload.type === 'work.result' ||
|
|
1518
|
+
payload.type === 'lease.renew') &&
|
|
1519
|
+
payload.assigneePeerId !== sender.peerId) {
|
|
1520
|
+
fail('invalid_payload', '$["payload"]["assigneePeerId"]');
|
|
1521
|
+
}
|
|
1522
|
+
else if (payload.type === 'work.release') {
|
|
1523
|
+
if (payload.releaseAuthority === 'owner' &&
|
|
1524
|
+
payload.ownerPeerId !== sender.peerId) {
|
|
1525
|
+
fail('invalid_payload', '$["payload"]["ownerPeerId"]');
|
|
1526
|
+
}
|
|
1527
|
+
if (payload.releaseAuthority === 'assignee' &&
|
|
1528
|
+
payload.assigneePeerId !== sender.peerId) {
|
|
1529
|
+
fail('invalid_payload', '$["payload"]["assigneePeerId"]');
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
else if (payload.type === 'work.cancel' &&
|
|
1533
|
+
payload.ownerPeerId !== sender.peerId) {
|
|
1534
|
+
fail('invalid_payload', '$["payload"]["ownerPeerId"]');
|
|
1535
|
+
}
|
|
1536
|
+
else if (payload.type === 'lease.takeover_proposal' &&
|
|
1537
|
+
payload.proposerPeerId !== sender.peerId) {
|
|
1538
|
+
fail('invalid_payload', '$["payload"]["proposerPeerId"]');
|
|
1539
|
+
}
|
|
1540
|
+
else if (payload.type === 'lease.vote' &&
|
|
1541
|
+
payload.witnessPeerId !== sender.peerId) {
|
|
1542
|
+
fail('invalid_payload', '$["payload"]["witnessPeerId"]');
|
|
1543
|
+
}
|
|
1544
|
+
else if (payload.type === 'lease.certificate' &&
|
|
1545
|
+
payload.certificateAssemblerPeerId !== sender.peerId) {
|
|
1546
|
+
fail('invalid_payload', '$["payload"]["certificateAssemblerPeerId"]');
|
|
1547
|
+
}
|
|
1548
|
+
if (type === 'peer.hello' ||
|
|
1549
|
+
type === 'peer.card' ||
|
|
1550
|
+
type === 'peer.goodbye') {
|
|
376
1551
|
if (audience.kind === 'mesh' && audience.topic !== 'membership') {
|
|
377
1552
|
fail('invalid_audience', '$["audience"]["topic"]');
|
|
378
1553
|
}
|
|
379
|
-
return;
|
|
380
1554
|
}
|
|
381
|
-
if (
|
|
1555
|
+
else if (type === 'capability.advertise' ||
|
|
1556
|
+
type === 'capability.withdraw') {
|
|
1557
|
+
if (audience.kind === 'mesh' && audience.topic !== 'capability') {
|
|
1558
|
+
fail('invalid_audience', '$["audience"]["topic"]');
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
else if (type === 'objective.announce' ||
|
|
1562
|
+
type === 'objective.revise' ||
|
|
1563
|
+
type === 'objective.cancel') {
|
|
1564
|
+
if (audience.kind === 'mesh' && audience.topic !== 'objective') {
|
|
1565
|
+
fail('invalid_audience', '$["audience"]["topic"]');
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
else if (type === 'work.offer') {
|
|
1569
|
+
if (audience.kind === 'mesh' && audience.topic !== 'work') {
|
|
1570
|
+
fail('invalid_audience', '$["audience"]["topic"]');
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
else if (type === 'work.bid') {
|
|
1574
|
+
if (audience.kind !== 'peer') {
|
|
1575
|
+
fail('invalid_audience', '$["audience"]');
|
|
1576
|
+
}
|
|
1577
|
+
if (audience.peerId !== payload.ownerPeerId) {
|
|
1578
|
+
fail('invalid_audience', '$["audience"]["peerId"]');
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
else if (type === 'work.award' ||
|
|
1582
|
+
type === 'work.accept' ||
|
|
1583
|
+
type === 'work.decline' ||
|
|
1584
|
+
type === 'work.progress' ||
|
|
1585
|
+
type === 'work.checkpoint' ||
|
|
1586
|
+
type === 'work.result' ||
|
|
1587
|
+
type === 'work.release' ||
|
|
1588
|
+
type === 'work.cancel' ||
|
|
1589
|
+
type === 'lease.renew' ||
|
|
1590
|
+
type === 'lease.takeover_proposal' ||
|
|
1591
|
+
type === 'lease.vote' ||
|
|
1592
|
+
type === 'lease.certificate') {
|
|
1593
|
+
if (audience.kind !== 'peer') {
|
|
1594
|
+
fail('invalid_audience', '$["audience"]');
|
|
1595
|
+
}
|
|
1596
|
+
if (type === 'work.decline' &&
|
|
1597
|
+
audience.peerId !== payload.ownerPeerId) {
|
|
1598
|
+
fail('invalid_audience', '$["audience"]["peerId"]');
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
else if (audience.kind !== 'peer') {
|
|
382
1602
|
fail('invalid_audience', '$["audience"]');
|
|
383
1603
|
}
|
|
384
|
-
if (
|
|
1604
|
+
if (type !== 'peer.hello' &&
|
|
1605
|
+
type.startsWith('peer.') &&
|
|
1606
|
+
objectiveId !== undefined) {
|
|
385
1607
|
fail('invalid_payload', '$["objectiveId"]');
|
|
386
1608
|
}
|
|
387
|
-
if (type === 'peer.ping_ack'
|
|
1609
|
+
if (type === 'peer.ping_ack' ||
|
|
1610
|
+
type === 'peer.goodbye' ||
|
|
1611
|
+
type === 'capability.withdraw' ||
|
|
1612
|
+
type === 'objective.cancel') {
|
|
1613
|
+
if (causationId === undefined) {
|
|
1614
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
else if (type === 'peer.card' || type === 'capability.advertise') {
|
|
1618
|
+
const revision = payload.type === 'peer.card'
|
|
1619
|
+
? payload.cardRevision
|
|
1620
|
+
: payload.capabilityRevision;
|
|
1621
|
+
if (revision === 1 && causationId !== undefined) {
|
|
1622
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1623
|
+
}
|
|
1624
|
+
if (revision > 1 && causationId === undefined) {
|
|
1625
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
else if (type === 'objective.announce') {
|
|
1629
|
+
if (causationId !== undefined) {
|
|
1630
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
else if (type === 'objective.revise' && causationId === undefined) {
|
|
1634
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1635
|
+
}
|
|
1636
|
+
else if (type === 'work.offer') {
|
|
1637
|
+
const offer = payload;
|
|
1638
|
+
if (offer.offerAttempt === 1 && causationId !== undefined) {
|
|
1639
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1640
|
+
}
|
|
1641
|
+
if (offer.offerAttempt > 1 && causationId === undefined) {
|
|
1642
|
+
fail('invalid_payload', '$["causationId"]');
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
else if ((type === 'work.bid' ||
|
|
1646
|
+
type === 'work.award' ||
|
|
1647
|
+
type === 'work.accept' ||
|
|
1648
|
+
type === 'work.decline' ||
|
|
1649
|
+
type === 'work.progress' ||
|
|
1650
|
+
type === 'work.checkpoint' ||
|
|
1651
|
+
type === 'work.result' ||
|
|
1652
|
+
type === 'work.release' ||
|
|
1653
|
+
type === 'work.cancel' ||
|
|
1654
|
+
type === 'lease.renew' ||
|
|
1655
|
+
type === 'lease.takeover_proposal' ||
|
|
1656
|
+
type === 'lease.vote' ||
|
|
1657
|
+
type === 'lease.certificate') &&
|
|
1658
|
+
causationId === undefined) {
|
|
388
1659
|
fail('invalid_payload', '$["causationId"]');
|
|
389
1660
|
}
|
|
1661
|
+
if (type === 'objective.announce' ||
|
|
1662
|
+
type === 'objective.revise' ||
|
|
1663
|
+
type === 'objective.cancel' ||
|
|
1664
|
+
type === 'work.offer' ||
|
|
1665
|
+
type === 'work.bid' ||
|
|
1666
|
+
type === 'work.award' ||
|
|
1667
|
+
type === 'work.accept' ||
|
|
1668
|
+
type === 'work.decline' ||
|
|
1669
|
+
type === 'work.progress' ||
|
|
1670
|
+
type === 'work.checkpoint' ||
|
|
1671
|
+
type === 'work.result' ||
|
|
1672
|
+
type === 'work.release' ||
|
|
1673
|
+
type === 'work.cancel' ||
|
|
1674
|
+
type === 'lease.renew' ||
|
|
1675
|
+
type === 'lease.takeover_proposal' ||
|
|
1676
|
+
type === 'lease.vote' ||
|
|
1677
|
+
type === 'lease.certificate') {
|
|
1678
|
+
if (objectiveId === undefined ||
|
|
1679
|
+
objectiveId !==
|
|
1680
|
+
payload.objectiveId) {
|
|
1681
|
+
fail('invalid_payload', '$["objectiveId"]');
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
if (payload.type === 'work.offer') {
|
|
1685
|
+
validateWorkOfferTimes(payload, sentAt, expiresAt);
|
|
1686
|
+
}
|
|
1687
|
+
else if (payload.type === 'work.bid') {
|
|
1688
|
+
validateWorkBidTimes(payload, sentAt, expiresAt);
|
|
1689
|
+
}
|
|
1690
|
+
else if (payload.type === 'work.award') {
|
|
1691
|
+
validateWorkAwardTimes(payload, sentAt, expiresAt);
|
|
1692
|
+
}
|
|
1693
|
+
else if (payload.type === 'work.accept' ||
|
|
1694
|
+
payload.type === 'work.decline') {
|
|
1695
|
+
validateWorkAssignmentResponseTimes(payload, sentAt, expiresAt);
|
|
1696
|
+
}
|
|
1697
|
+
else if (payload.type === 'work.progress' ||
|
|
1698
|
+
payload.type === 'work.checkpoint' ||
|
|
1699
|
+
payload.type === 'work.result' ||
|
|
1700
|
+
payload.type === 'lease.renew') {
|
|
1701
|
+
validateWorkExecutionTimes(payload, sentAt, expiresAt);
|
|
1702
|
+
}
|
|
1703
|
+
else if (payload.type === 'work.release' &&
|
|
1704
|
+
payload.releaseAuthority === 'assignee') {
|
|
1705
|
+
validateWorkExecutionTimes(payload, sentAt, expiresAt);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
function validateWorkOfferTimes(payload, sentAt, expiresAt) {
|
|
1709
|
+
const bidDeadline = parseRfc3339(payload.bidDeadline, '$["payload"]["bidDeadline"]');
|
|
1710
|
+
const workDeadline = parseRfc3339(payload.workDeadline, '$["payload"]["workDeadline"]');
|
|
1711
|
+
if (bidDeadline <= sentAt) {
|
|
1712
|
+
fail('invalid_payload', '$["payload"]["bidDeadline"]');
|
|
1713
|
+
}
|
|
1714
|
+
if (workDeadline <= bidDeadline) {
|
|
1715
|
+
fail('invalid_payload', '$["payload"]["workDeadline"]');
|
|
1716
|
+
}
|
|
1717
|
+
if (bidDeadline - sentAt > BigInt(maximumWorkBidWindowMs) * 1000000n) {
|
|
1718
|
+
fail('invalid_payload', '$["payload"]["bidDeadline"]');
|
|
1719
|
+
}
|
|
1720
|
+
if (workDeadline - sentAt > BigInt(maximumWorkDeadlineMs) * 1000000n) {
|
|
1721
|
+
fail('invalid_payload', '$["payload"]["workDeadline"]');
|
|
1722
|
+
}
|
|
1723
|
+
if (expiresAt > bidDeadline) {
|
|
1724
|
+
fail('invalid_lifetime', '$["expiresAt"]');
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
function validateWorkBidTimes(payload, sentAt, expiresAt) {
|
|
1728
|
+
const bidExpiresAt = parseRfc3339(payload.bidExpiresAt, '$["payload"]["bidExpiresAt"]');
|
|
1729
|
+
const bidDeadline = parseRfc3339(payload.bidDeadline, '$["payload"]["bidDeadline"]');
|
|
1730
|
+
const expectedCompletionAt = parseRfc3339(payload.expectedCompletionAt, '$["payload"]["expectedCompletionAt"]');
|
|
1731
|
+
const workDeadline = parseRfc3339(payload.workDeadline, '$["payload"]["workDeadline"]');
|
|
1732
|
+
if (bidExpiresAt <= sentAt) {
|
|
1733
|
+
fail('invalid_payload', '$["payload"]["bidExpiresAt"]');
|
|
1734
|
+
}
|
|
1735
|
+
if (bidExpiresAt > bidDeadline) {
|
|
1736
|
+
fail('invalid_payload', '$["payload"]["bidExpiresAt"]');
|
|
1737
|
+
}
|
|
1738
|
+
if (bidDeadline >= expectedCompletionAt) {
|
|
1739
|
+
fail('invalid_payload', '$["payload"]["expectedCompletionAt"]');
|
|
1740
|
+
}
|
|
1741
|
+
if (expectedCompletionAt > workDeadline) {
|
|
1742
|
+
fail('invalid_payload', '$["payload"]["expectedCompletionAt"]');
|
|
1743
|
+
}
|
|
1744
|
+
if (bidDeadline - sentAt > BigInt(maximumWorkBidWindowMs) * 1000000n) {
|
|
1745
|
+
fail('invalid_payload', '$["payload"]["bidDeadline"]');
|
|
1746
|
+
}
|
|
1747
|
+
if (workDeadline - sentAt > BigInt(maximumWorkDeadlineMs) * 1000000n) {
|
|
1748
|
+
fail('invalid_payload', '$["payload"]["workDeadline"]');
|
|
1749
|
+
}
|
|
1750
|
+
if (expiresAt > bidExpiresAt) {
|
|
1751
|
+
fail('invalid_lifetime', '$["expiresAt"]');
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
function validateWorkAwardTimes(payload, sentAt, expiresAt) {
|
|
1755
|
+
const leaseStartsAt = parseRfc3339(payload.leaseStartsAt, '$["payload"]["leaseStartsAt"]');
|
|
1756
|
+
const acceptanceDeadline = parseRfc3339(payload.acceptanceDeadline, '$["payload"]["acceptanceDeadline"]');
|
|
1757
|
+
const leaseExpiresAt = parseRfc3339(payload.leaseExpiresAt, '$["payload"]["leaseExpiresAt"]');
|
|
1758
|
+
const workDeadline = parseRfc3339(payload.workDeadline, '$["payload"]["workDeadline"]');
|
|
1759
|
+
if (leaseStartsAt < sentAt) {
|
|
1760
|
+
fail('invalid_payload', '$["payload"]["leaseStartsAt"]');
|
|
1761
|
+
}
|
|
1762
|
+
if (acceptanceDeadline <= leaseStartsAt) {
|
|
1763
|
+
fail('invalid_payload', '$["payload"]["acceptanceDeadline"]');
|
|
1764
|
+
}
|
|
1765
|
+
if (leaseExpiresAt < acceptanceDeadline) {
|
|
1766
|
+
fail('invalid_payload', '$["payload"]["leaseExpiresAt"]');
|
|
1767
|
+
}
|
|
1768
|
+
if (workDeadline < leaseExpiresAt) {
|
|
1769
|
+
fail('invalid_payload', '$["payload"]["workDeadline"]');
|
|
1770
|
+
}
|
|
1771
|
+
if (acceptanceDeadline - sentAt >
|
|
1772
|
+
BigInt(maximumAcceptanceWindowMs) * 1000000n) {
|
|
1773
|
+
fail('invalid_payload', '$["payload"]["acceptanceDeadline"]');
|
|
1774
|
+
}
|
|
1775
|
+
if (leaseExpiresAt - leaseStartsAt >
|
|
1776
|
+
BigInt(maximumLeaseDurationMs) * 1000000n) {
|
|
1777
|
+
fail('invalid_payload', '$["payload"]["leaseExpiresAt"]');
|
|
1778
|
+
}
|
|
1779
|
+
if (workDeadline - sentAt > BigInt(maximumWorkDeadlineMs) * 1000000n) {
|
|
1780
|
+
fail('invalid_payload', '$["payload"]["workDeadline"]');
|
|
1781
|
+
}
|
|
1782
|
+
if (expiresAt > acceptanceDeadline) {
|
|
1783
|
+
fail('invalid_lifetime', '$["expiresAt"]');
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
function validateWorkAssignmentResponseTimes(payload, sentAt, expiresAt) {
|
|
1787
|
+
const acceptanceDeadline = parseRfc3339(payload.acceptanceDeadline, '$["payload"]["acceptanceDeadline"]');
|
|
1788
|
+
if (sentAt >= acceptanceDeadline) {
|
|
1789
|
+
fail('invalid_payload', '$["payload"]["acceptanceDeadline"]');
|
|
1790
|
+
}
|
|
1791
|
+
if (expiresAt > acceptanceDeadline) {
|
|
1792
|
+
fail('invalid_lifetime', '$["expiresAt"]');
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
function validateWorkExecutionTimes(payload, sentAt, expiresAt) {
|
|
1796
|
+
const leaseExpiresAt = parseRfc3339(payload.leaseExpiresAt, '$["payload"]["leaseExpiresAt"]');
|
|
1797
|
+
if (sentAt >= leaseExpiresAt) {
|
|
1798
|
+
fail('invalid_payload', '$["payload"]["leaseExpiresAt"]');
|
|
1799
|
+
}
|
|
1800
|
+
if (expiresAt > leaseExpiresAt) {
|
|
1801
|
+
fail('invalid_lifetime', '$["expiresAt"]');
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
function validateRevisionPredecessor(revision, predecessor, path) {
|
|
1805
|
+
if (revision === 1 && predecessor !== undefined) {
|
|
1806
|
+
fail('invalid_payload', path);
|
|
1807
|
+
}
|
|
1808
|
+
if (revision > 1 && predecessor === undefined) {
|
|
1809
|
+
fail('invalid_payload', path);
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
function assertBoundedValidity(validFrom, validUntil) {
|
|
1813
|
+
if (validUntil <= validFrom) {
|
|
1814
|
+
fail('invalid_payload', '$["payload"]["validUntil"]');
|
|
1815
|
+
}
|
|
1816
|
+
if (validUntil - validFrom >
|
|
1817
|
+
BigInt(maximumAdvertisementValidityMs) * 1000000n) {
|
|
1818
|
+
fail('invalid_payload', '$["payload"]["validUntil"]');
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
function assertObjectiveValidity(validFrom, validUntil) {
|
|
1822
|
+
if (validUntil <= validFrom) {
|
|
1823
|
+
fail('invalid_payload', '$["payload"]["validUntil"]');
|
|
1824
|
+
}
|
|
1825
|
+
const duration = validUntil - validFrom;
|
|
1826
|
+
if (duration > BigInt(maximumObjectiveValidityMs) * 1000000n) {
|
|
1827
|
+
fail('invalid_payload', '$["payload"]["validUntil"]');
|
|
1828
|
+
}
|
|
1829
|
+
return duration;
|
|
1830
|
+
}
|
|
1831
|
+
function assertRfc3339PayloadTimestamp(input, path) {
|
|
1832
|
+
const text = assertString(input, path, 'invalid_payload');
|
|
1833
|
+
try {
|
|
1834
|
+
return { text, instant: parseRfc3339(text, path) };
|
|
1835
|
+
}
|
|
1836
|
+
catch (error) {
|
|
1837
|
+
if (error instanceof ValidationFailure) {
|
|
1838
|
+
fail('invalid_payload', path);
|
|
1839
|
+
}
|
|
1840
|
+
throw error;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
function validateProtocolVersions(input) {
|
|
1844
|
+
const path = '$["payload"]["protocolVersions"]';
|
|
1845
|
+
if (!Array.isArray(input) ||
|
|
1846
|
+
input.length === 0 ||
|
|
1847
|
+
input.length > maximumProtocolVersions) {
|
|
1848
|
+
fail('invalid_payload', path);
|
|
1849
|
+
}
|
|
1850
|
+
let previous;
|
|
1851
|
+
let includesCurrentWireVersion = false;
|
|
1852
|
+
const result = [];
|
|
1853
|
+
for (const [index, value] of input.entries()) {
|
|
1854
|
+
if (typeof value !== 'number' ||
|
|
1855
|
+
!Number.isSafeInteger(value) ||
|
|
1856
|
+
value < 0 ||
|
|
1857
|
+
(previous !== undefined && value <= previous)) {
|
|
1858
|
+
fail('invalid_payload', `${path}[${index}]`);
|
|
1859
|
+
}
|
|
1860
|
+
if (value === MESH_WIRE_VERSION)
|
|
1861
|
+
includesCurrentWireVersion = true;
|
|
1862
|
+
previous = value;
|
|
1863
|
+
result.push(value);
|
|
1864
|
+
}
|
|
1865
|
+
if (!includesCurrentWireVersion) {
|
|
1866
|
+
fail('invalid_payload', path);
|
|
1867
|
+
}
|
|
1868
|
+
return result;
|
|
1869
|
+
}
|
|
1870
|
+
function validateIdentifierArray(input, path, maximumItems, limits) {
|
|
1871
|
+
if (!Array.isArray(input) || input.length > maximumItems) {
|
|
1872
|
+
fail('invalid_payload', path);
|
|
1873
|
+
}
|
|
1874
|
+
let previous;
|
|
1875
|
+
const result = [];
|
|
1876
|
+
for (const [index, value] of input.entries()) {
|
|
1877
|
+
const itemPath = `${path}[${index}]`;
|
|
1878
|
+
const identifier = assertIdentifier(value, itemPath, limits);
|
|
1879
|
+
if (previous !== undefined &&
|
|
1880
|
+
compareUtf16CodeUnits(identifier, previous) !== 1) {
|
|
1881
|
+
fail('invalid_payload', itemPath);
|
|
1882
|
+
}
|
|
1883
|
+
previous = identifier;
|
|
1884
|
+
result.push(identifier);
|
|
1885
|
+
}
|
|
1886
|
+
return result;
|
|
1887
|
+
}
|
|
1888
|
+
function validateBoundedStringArray(input, path, maximumItems, maximumItemBytes, maximumAggregateBytes, sortedUnique = false) {
|
|
1889
|
+
if (!Array.isArray(input) || input.length > maximumItems) {
|
|
1890
|
+
fail('invalid_payload', path);
|
|
1891
|
+
}
|
|
1892
|
+
let aggregateBytes = 0;
|
|
1893
|
+
let previous;
|
|
1894
|
+
const result = [];
|
|
1895
|
+
for (const [index, value] of input.entries()) {
|
|
1896
|
+
const itemPath = `${path}[${index}]`;
|
|
1897
|
+
const item = assertBoundedString(value, itemPath, maximumItemBytes);
|
|
1898
|
+
if (sortedUnique &&
|
|
1899
|
+
previous !== undefined &&
|
|
1900
|
+
compareUtf16CodeUnits(item, previous) !== 1) {
|
|
1901
|
+
fail('invalid_payload', itemPath);
|
|
1902
|
+
}
|
|
1903
|
+
aggregateBytes += utf8Encoder.encode(item).byteLength;
|
|
1904
|
+
if (maximumAggregateBytes !== undefined &&
|
|
1905
|
+
aggregateBytes > maximumAggregateBytes) {
|
|
1906
|
+
fail('invalid_payload', path);
|
|
1907
|
+
}
|
|
1908
|
+
previous = item;
|
|
1909
|
+
result.push(item);
|
|
1910
|
+
}
|
|
1911
|
+
return result;
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Compares raw UTF-16 code units lexicographically, matching JavaScript string
|
|
1915
|
+
* relational ordering and the property-name ordering used by JCS/RFC 8785.
|
|
1916
|
+
*/
|
|
1917
|
+
function compareUtf16CodeUnits(left, right) {
|
|
1918
|
+
const sharedLength = Math.min(left.length, right.length);
|
|
1919
|
+
for (let index = 0; index < sharedLength; index += 1) {
|
|
1920
|
+
const leftCodeUnit = left.charCodeAt(index);
|
|
1921
|
+
const rightCodeUnit = right.charCodeAt(index);
|
|
1922
|
+
if (leftCodeUnit < rightCodeUnit)
|
|
1923
|
+
return -1;
|
|
1924
|
+
if (leftCodeUnit > rightCodeUnit)
|
|
1925
|
+
return 1;
|
|
1926
|
+
}
|
|
1927
|
+
if (left.length < right.length)
|
|
1928
|
+
return -1;
|
|
1929
|
+
if (left.length > right.length)
|
|
1930
|
+
return 1;
|
|
1931
|
+
return 0;
|
|
1932
|
+
}
|
|
1933
|
+
function validateAttributes(input, path = '$["payload"]["attributes"]') {
|
|
1934
|
+
const attributes = assertRecord(input, path, 'invalid_payload');
|
|
1935
|
+
const keys = Object.keys(attributes);
|
|
1936
|
+
if (keys.length > maximumAttributes) {
|
|
1937
|
+
fail('invalid_payload', path);
|
|
1938
|
+
}
|
|
1939
|
+
let aggregateBytes = 0;
|
|
1940
|
+
const result = {};
|
|
1941
|
+
for (const key of keys) {
|
|
1942
|
+
const keyPath = `${path}[${JSON.stringify(key)}]`;
|
|
1943
|
+
if (key.length === 0 ||
|
|
1944
|
+
utf8Encoder.encode(key).byteLength > maximumAttributeKeyBytes) {
|
|
1945
|
+
fail('invalid_payload', keyPath);
|
|
1946
|
+
}
|
|
1947
|
+
const value = assertBoundedString(attributes[key], keyPath, maximumAttributeValueBytes);
|
|
1948
|
+
aggregateBytes +=
|
|
1949
|
+
utf8Encoder.encode(key).byteLength + utf8Encoder.encode(value).byteLength;
|
|
1950
|
+
if (aggregateBytes > maximumAttributesBytes) {
|
|
1951
|
+
fail('invalid_payload', path);
|
|
1952
|
+
}
|
|
1953
|
+
Object.defineProperty(result, key, {
|
|
1954
|
+
value,
|
|
1955
|
+
enumerable: true,
|
|
1956
|
+
configurable: true,
|
|
1957
|
+
writable: true,
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
return result;
|
|
1961
|
+
}
|
|
1962
|
+
function assertBoundedString(input, path, maximumBytes) {
|
|
1963
|
+
const value = assertString(input, path, 'invalid_payload');
|
|
1964
|
+
if (value.length === 0 ||
|
|
1965
|
+
utf8Encoder.encode(value).byteLength > maximumBytes) {
|
|
1966
|
+
fail('invalid_payload', path);
|
|
1967
|
+
}
|
|
1968
|
+
return value;
|
|
390
1969
|
}
|
|
391
1970
|
function validateLifetime(type, sentAt, expiresAt, limits) {
|
|
392
1971
|
if (expiresAt <= sentAt) {
|
|
393
1972
|
fail('invalid_lifetime', '$["expiresAt"]');
|
|
394
1973
|
}
|
|
395
|
-
const messageMaximum = type === 'peer.
|
|
1974
|
+
const messageMaximum = type === 'peer.ping' || type === 'peer.ping_ack'
|
|
1975
|
+
? 30_000
|
|
1976
|
+
: type === 'peer.goodbye' ||
|
|
1977
|
+
type === 'lease.takeover_proposal' ||
|
|
1978
|
+
type === 'lease.vote' ||
|
|
1979
|
+
type === 'lease.certificate'
|
|
1980
|
+
? 60_000
|
|
1981
|
+
: type === 'objective.announce' || type === 'objective.revise'
|
|
1982
|
+
? 5 * 60_000
|
|
1983
|
+
: type === 'work.progress' ||
|
|
1984
|
+
type === 'work.checkpoint' ||
|
|
1985
|
+
type === 'work.result'
|
|
1986
|
+
? maximumWorkExecutionLifetimeMs
|
|
1987
|
+
: type === 'lease.renew'
|
|
1988
|
+
? 30_000
|
|
1989
|
+
: 120_000;
|
|
396
1990
|
const maximum = Math.min(limits.maximumLifetimeMs, messageMaximum);
|
|
397
1991
|
if (expiresAt - sentAt > BigInt(maximum) * 1000000n) {
|
|
398
1992
|
fail('invalid_lifetime', '$["expiresAt"]');
|
|
@@ -415,6 +2009,14 @@ function assertPayloadHash(input, path) {
|
|
|
415
2009
|
}
|
|
416
2010
|
return value;
|
|
417
2011
|
}
|
|
2012
|
+
function assertContentDigest(input, path) {
|
|
2013
|
+
const value = assertString(input, path, 'invalid_payload');
|
|
2014
|
+
if (!value.startsWith('sha256:') ||
|
|
2015
|
+
!isCanonicalBase64Url(value.slice('sha256:'.length), 32)) {
|
|
2016
|
+
fail('invalid_payload', path);
|
|
2017
|
+
}
|
|
2018
|
+
return value;
|
|
2019
|
+
}
|
|
418
2020
|
function assertMessageId(input, path) {
|
|
419
2021
|
const value = assertString(input, path, 'invalid_message_id');
|
|
420
2022
|
if (!isCanonicalBase64Url(value, 16)) {
|
|
@@ -435,6 +2037,19 @@ function assertPositiveSafeInteger(input, path, code = 'invalid_sequence') {
|
|
|
435
2037
|
}
|
|
436
2038
|
return input;
|
|
437
2039
|
}
|
|
2040
|
+
function assertNonnegativeSafeInteger(input, path) {
|
|
2041
|
+
if (typeof input !== 'number' || !Number.isSafeInteger(input) || input < 0) {
|
|
2042
|
+
fail('invalid_payload', path);
|
|
2043
|
+
}
|
|
2044
|
+
return input;
|
|
2045
|
+
}
|
|
2046
|
+
function assertBoundedPositiveSafeInteger(input, path, maximum) {
|
|
2047
|
+
const value = assertPositiveSafeInteger(input, path, 'invalid_payload');
|
|
2048
|
+
if (value > maximum) {
|
|
2049
|
+
fail('invalid_payload', path);
|
|
2050
|
+
}
|
|
2051
|
+
return value;
|
|
2052
|
+
}
|
|
438
2053
|
function assertString(input, path, code = 'invalid_payload') {
|
|
439
2054
|
if (typeof input !== 'string')
|
|
440
2055
|
fail(code, path);
|
|
@@ -535,8 +2150,31 @@ function isCanonicalBase64Url(value, expectedBytes) {
|
|
|
535
2150
|
const unusedBits = 6 - significantBits;
|
|
536
2151
|
return (finalIndex & ((1 << unusedBits) - 1)) === 0;
|
|
537
2152
|
}
|
|
538
|
-
function
|
|
539
|
-
return (value === 'peer.hello' ||
|
|
2153
|
+
function isImplementedMessageType(value) {
|
|
2154
|
+
return (value === 'peer.hello' ||
|
|
2155
|
+
value === 'peer.card' ||
|
|
2156
|
+
value === 'peer.ping' ||
|
|
2157
|
+
value === 'peer.ping_ack' ||
|
|
2158
|
+
value === 'peer.goodbye' ||
|
|
2159
|
+
value === 'capability.advertise' ||
|
|
2160
|
+
value === 'capability.withdraw' ||
|
|
2161
|
+
value === 'objective.announce' ||
|
|
2162
|
+
value === 'objective.revise' ||
|
|
2163
|
+
value === 'objective.cancel' ||
|
|
2164
|
+
value === 'work.offer' ||
|
|
2165
|
+
value === 'work.bid' ||
|
|
2166
|
+
value === 'work.award' ||
|
|
2167
|
+
value === 'work.accept' ||
|
|
2168
|
+
value === 'work.decline' ||
|
|
2169
|
+
value === 'work.progress' ||
|
|
2170
|
+
value === 'work.checkpoint' ||
|
|
2171
|
+
value === 'work.result' ||
|
|
2172
|
+
value === 'work.release' ||
|
|
2173
|
+
value === 'work.cancel' ||
|
|
2174
|
+
value === 'lease.renew' ||
|
|
2175
|
+
value === 'lease.takeover_proposal' ||
|
|
2176
|
+
value === 'lease.vote' ||
|
|
2177
|
+
value === 'lease.certificate');
|
|
540
2178
|
}
|
|
541
2179
|
function canonicalizeMeshJsonInternal(input, options) {
|
|
542
2180
|
const limits = resolveLimits(options.limits);
|