@plasius/economy 0.7.0 → 0.9.0
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 +68 -0
- package/dist/index.cjs +1263 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +325 -2
- package/dist/index.d.ts +325 -2
- package/dist/index.js +1240 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -501,6 +501,1155 @@ function mapBitLabsConversionState(state) {
|
|
|
501
501
|
return transition;
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
// src/admin-reporting.ts
|
|
505
|
+
var ADMIN_TOKEN_DEFAULT_WINDOW_DAYS = 30;
|
|
506
|
+
var ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS = 365;
|
|
507
|
+
var ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS = 31;
|
|
508
|
+
var ADMIN_TOKEN_MAXIMUM_PAGE_SIZE = 100;
|
|
509
|
+
var ADMIN_TOKEN_MAXIMUM_TREND_POINTS = ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS * 24 * 5;
|
|
510
|
+
var ADMIN_TOKEN_MINIMUM_COHORT_SIZE = 5;
|
|
511
|
+
var ADMIN_TOKEN_ANOMALY_BASELINE_DAYS = 28;
|
|
512
|
+
var DAY_MILLISECONDS = 864e5;
|
|
513
|
+
var HOUR_MILLISECONDS = 36e5;
|
|
514
|
+
var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
515
|
+
"acquisition",
|
|
516
|
+
"spend",
|
|
517
|
+
"reversal",
|
|
518
|
+
"hold",
|
|
519
|
+
"failure"
|
|
520
|
+
]);
|
|
521
|
+
var ACTIVITY_STATUSES = /* @__PURE__ */ new Set([
|
|
522
|
+
"pending",
|
|
523
|
+
"held",
|
|
524
|
+
"settled",
|
|
525
|
+
"reversed",
|
|
526
|
+
"failed"
|
|
527
|
+
]);
|
|
528
|
+
var ACTIVITY_SOURCES = /* @__PURE__ */ new Set([
|
|
529
|
+
"paid-purchase",
|
|
530
|
+
"subscription",
|
|
531
|
+
"rewarded-activity",
|
|
532
|
+
"gameplay",
|
|
533
|
+
"system-adjustment",
|
|
534
|
+
"unknown"
|
|
535
|
+
]);
|
|
536
|
+
var SAFE_LABELS = /* @__PURE__ */ new Set([
|
|
537
|
+
"token-acquisition",
|
|
538
|
+
"token-spend",
|
|
539
|
+
"token-reversal",
|
|
540
|
+
"token-hold",
|
|
541
|
+
"token-activity-failed",
|
|
542
|
+
"token-system-adjustment",
|
|
543
|
+
"token-activity-unclassified"
|
|
544
|
+
]);
|
|
545
|
+
var SAFE_LABELS_BY_ACTIVITY_TYPE = {
|
|
546
|
+
acquisition: /* @__PURE__ */ new Set([
|
|
547
|
+
"token-acquisition",
|
|
548
|
+
"token-system-adjustment",
|
|
549
|
+
"token-activity-unclassified"
|
|
550
|
+
]),
|
|
551
|
+
spend: /* @__PURE__ */ new Set([
|
|
552
|
+
"token-spend",
|
|
553
|
+
"token-system-adjustment",
|
|
554
|
+
"token-activity-unclassified"
|
|
555
|
+
]),
|
|
556
|
+
reversal: /* @__PURE__ */ new Set([
|
|
557
|
+
"token-reversal",
|
|
558
|
+
"token-system-adjustment",
|
|
559
|
+
"token-activity-unclassified"
|
|
560
|
+
]),
|
|
561
|
+
hold: /* @__PURE__ */ new Set([
|
|
562
|
+
"token-hold",
|
|
563
|
+
"token-system-adjustment",
|
|
564
|
+
"token-activity-unclassified"
|
|
565
|
+
]),
|
|
566
|
+
failure: /* @__PURE__ */ new Set([
|
|
567
|
+
"token-activity-failed",
|
|
568
|
+
"token-activity-unclassified"
|
|
569
|
+
])
|
|
570
|
+
};
|
|
571
|
+
var ACTIVITY_SORTS = /* @__PURE__ */ new Set([
|
|
572
|
+
"occurred-at-desc",
|
|
573
|
+
"amount-absolute-desc"
|
|
574
|
+
]);
|
|
575
|
+
var PSEUDONYM_AUDIENCES = /* @__PURE__ */ new Set([
|
|
576
|
+
"admin-token-activity",
|
|
577
|
+
"mcp-token-activity"
|
|
578
|
+
]);
|
|
579
|
+
var BALANCE_PSEUDONYM_AUDIENCES = /* @__PURE__ */ new Set([
|
|
580
|
+
"admin-token-balances",
|
|
581
|
+
"mcp-token-balances"
|
|
582
|
+
]);
|
|
583
|
+
var WALLET_COMPONENTS = /* @__PURE__ */ new Set([
|
|
584
|
+
"household",
|
|
585
|
+
"personal",
|
|
586
|
+
"gameplay-allocation"
|
|
587
|
+
]);
|
|
588
|
+
var WALLET_STATUSES = /* @__PURE__ */ new Set([
|
|
589
|
+
"active",
|
|
590
|
+
"closed"
|
|
591
|
+
]);
|
|
592
|
+
var WALLET_BALANCE_SORTS = /* @__PURE__ */ new Set([
|
|
593
|
+
"available-desc",
|
|
594
|
+
"updated-at-desc"
|
|
595
|
+
]);
|
|
596
|
+
var TREND_GRANULARITIES = /* @__PURE__ */ new Set([
|
|
597
|
+
"hour",
|
|
598
|
+
"day"
|
|
599
|
+
]);
|
|
600
|
+
var ALIAS = /^[A-Za-z0-9_-]{16,96}$/u;
|
|
601
|
+
var OPAQUE_CURSOR = /^c1\.[A-Za-z0-9_-]{32,480}$/u;
|
|
602
|
+
var PSEUDONYM_VERSION = /^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/u;
|
|
603
|
+
var EXACT_STATISTIC_INTEGER = /^(?:0|-?[1-9][0-9]*)$/u;
|
|
604
|
+
var POSITIVE_UNSIGNED_INTEGER = /^[1-9][0-9]*$/u;
|
|
605
|
+
var MAXIMUM_STATISTIC_HALF_SUBUNITS = (TOKEN_SUBUNITS_MAX - TOKEN_SUBUNITS_MIN) * 2n;
|
|
606
|
+
var ANOMALY_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
607
|
+
"insufficient-history",
|
|
608
|
+
"privacy-suppressed-baseline"
|
|
609
|
+
]);
|
|
610
|
+
function assertPlainObject(value, label) {
|
|
611
|
+
economyAssert(
|
|
612
|
+
typeof value === "object" && value !== null && !Array.isArray(value),
|
|
613
|
+
"INVALID_CONTRACT",
|
|
614
|
+
`${label} must be an object`
|
|
615
|
+
);
|
|
616
|
+
const prototype = Object.getPrototypeOf(value);
|
|
617
|
+
economyAssert(
|
|
618
|
+
(prototype === Object.prototype || prototype === null) && !Reflect.has(value, "toJSON"),
|
|
619
|
+
"INVALID_CONTRACT",
|
|
620
|
+
`${label} must be a plain data object without serialization hooks`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function assertExactKeys(value, allowedKeys, label) {
|
|
624
|
+
assertPlainObject(value, label);
|
|
625
|
+
const allowed = new Set(allowedKeys);
|
|
626
|
+
const keys = Reflect.ownKeys(value);
|
|
627
|
+
economyAssert(
|
|
628
|
+
allowedKeys.every(
|
|
629
|
+
(key) => !Reflect.has(value, key) || Object.hasOwn(value, key)
|
|
630
|
+
) && keys.every((key) => {
|
|
631
|
+
if (typeof key !== "string" || !allowed.has(key)) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
635
|
+
return descriptor !== void 0 && descriptor.enumerable && "value" in descriptor;
|
|
636
|
+
}),
|
|
637
|
+
"INVALID_CONTRACT",
|
|
638
|
+
`${label} contains an unsupported, identifying, or non-data property`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
function assertAlias(value, label) {
|
|
642
|
+
economyAssert(
|
|
643
|
+
typeof value === "string" && ALIAS.test(value),
|
|
644
|
+
"INVALID_CONTRACT",
|
|
645
|
+
`${label} must be an opaque pseudonymous alias`
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
function assertOpaqueCursor(value) {
|
|
649
|
+
economyAssert(
|
|
650
|
+
typeof value === "string" && OPAQUE_CURSOR.test(value),
|
|
651
|
+
"INVALID_CONTRACT",
|
|
652
|
+
"Admin Token cursor must be a bounded confidentiality-protected opaque value"
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
function assertUniqueValues(values, allowed, label) {
|
|
656
|
+
economyAssert(
|
|
657
|
+
Array.isArray(values),
|
|
658
|
+
"INVALID_CONTRACT",
|
|
659
|
+
`${label} must be a list`
|
|
660
|
+
);
|
|
661
|
+
const unique = new Set(values);
|
|
662
|
+
economyAssert(
|
|
663
|
+
values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
|
|
664
|
+
"INVALID_CONTRACT",
|
|
665
|
+
`${label} must contain unique supported values`
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
function absolute(value) {
|
|
669
|
+
return value < 0n ? -value : value;
|
|
670
|
+
}
|
|
671
|
+
function compareTextDescending(left, right) {
|
|
672
|
+
if (left === right) {
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
675
|
+
return left > right ? -1 : 1;
|
|
676
|
+
}
|
|
677
|
+
function assertReportingWindow(window, maximumDays = ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS) {
|
|
678
|
+
assertExactKeys(
|
|
679
|
+
window,
|
|
680
|
+
["fromInclusive", "toExclusive"],
|
|
681
|
+
"Admin Token reporting window"
|
|
682
|
+
);
|
|
683
|
+
const from = parseIsoTimestamp(window.fromInclusive);
|
|
684
|
+
const to = parseIsoTimestamp(window.toExclusive);
|
|
685
|
+
economyAssert(
|
|
686
|
+
from < to && to - from <= maximumDays * DAY_MILLISECONDS,
|
|
687
|
+
"INVALID_TIME_WINDOW",
|
|
688
|
+
`Admin Token reporting window must be positive and no longer than ${maximumDays} days`
|
|
689
|
+
);
|
|
690
|
+
return { from, to };
|
|
691
|
+
}
|
|
692
|
+
function createDefaultAdminTokenReportingWindow(asOf) {
|
|
693
|
+
const to = parseIsoTimestamp(asOf);
|
|
694
|
+
return {
|
|
695
|
+
fromInclusive: new Date(
|
|
696
|
+
to - ADMIN_TOKEN_DEFAULT_WINDOW_DAYS * DAY_MILLISECONDS
|
|
697
|
+
).toISOString(),
|
|
698
|
+
toExclusive: new Date(to).toISOString()
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
function assertNonNegativeTokenAmounts(amounts, label) {
|
|
702
|
+
economyAssert(
|
|
703
|
+
amounts.every((amount) => parseTokenSubunits(amount) >= 0n),
|
|
704
|
+
"INVALID_AMOUNT",
|
|
705
|
+
`${label} cannot contain a negative amount`
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
function assertPositiveAuthoritySequence(sequence, label) {
|
|
709
|
+
economyAssert(
|
|
710
|
+
typeof sequence === "string" && POSITIVE_UNSIGNED_INTEGER.test(sequence),
|
|
711
|
+
"INVALID_CONTRACT",
|
|
712
|
+
`${label} must be a canonical positive integer`
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
function assertAdminTokenEconomySummary(summary) {
|
|
716
|
+
assertExactKeys(
|
|
717
|
+
summary,
|
|
718
|
+
[
|
|
719
|
+
"schemaVersion",
|
|
720
|
+
"generatedAt",
|
|
721
|
+
"projectionAsOf",
|
|
722
|
+
"authoritySequence",
|
|
723
|
+
"walletCount",
|
|
724
|
+
"activeWalletCount",
|
|
725
|
+
"balances",
|
|
726
|
+
"lifetime",
|
|
727
|
+
"rawIdentifiersIncluded"
|
|
728
|
+
],
|
|
729
|
+
"Admin Token economy summary"
|
|
730
|
+
);
|
|
731
|
+
assertExactKeys(
|
|
732
|
+
summary.balances,
|
|
733
|
+
["schemaVersion", "available", "reserved", "held", "rewardProgress"],
|
|
734
|
+
"Admin Token aggregate balances"
|
|
735
|
+
);
|
|
736
|
+
assertExactKeys(
|
|
737
|
+
summary.lifetime,
|
|
738
|
+
[
|
|
739
|
+
"schemaVersion",
|
|
740
|
+
"bought",
|
|
741
|
+
"earned",
|
|
742
|
+
"allocated",
|
|
743
|
+
"reclaimed",
|
|
744
|
+
"spent",
|
|
745
|
+
"reversed"
|
|
746
|
+
],
|
|
747
|
+
"Admin Token aggregate lifetime"
|
|
748
|
+
);
|
|
749
|
+
economyAssert(
|
|
750
|
+
summary.schemaVersion === ECONOMY_CONTRACT_VERSION && summary.balances.schemaVersion === ECONOMY_CONTRACT_VERSION && summary.lifetime.schemaVersion === ECONOMY_CONTRACT_VERSION && summary.rawIdentifiersIncluded === false && Number.isSafeInteger(summary.walletCount) && summary.walletCount >= 0 && Number.isSafeInteger(summary.activeWalletCount) && summary.activeWalletCount >= 0 && summary.activeWalletCount <= summary.walletCount,
|
|
751
|
+
"INVALID_CONTRACT",
|
|
752
|
+
"Admin Token economy summary metadata is invalid"
|
|
753
|
+
);
|
|
754
|
+
const generatedAt = parseIsoTimestamp(summary.generatedAt);
|
|
755
|
+
const projectionAsOf = parseIsoTimestamp(summary.projectionAsOf);
|
|
756
|
+
economyAssert(
|
|
757
|
+
projectionAsOf <= generatedAt,
|
|
758
|
+
"INVALID_TIME_WINDOW",
|
|
759
|
+
"Admin Token projection cannot be newer than its generated result"
|
|
760
|
+
);
|
|
761
|
+
assertPositiveAuthoritySequence(
|
|
762
|
+
summary.authoritySequence,
|
|
763
|
+
"Admin Token summary authority sequence"
|
|
764
|
+
);
|
|
765
|
+
assertNonNegativeTokenAmounts(
|
|
766
|
+
[
|
|
767
|
+
summary.balances.available,
|
|
768
|
+
summary.balances.reserved,
|
|
769
|
+
summary.balances.held,
|
|
770
|
+
summary.balances.rewardProgress,
|
|
771
|
+
summary.lifetime.bought,
|
|
772
|
+
summary.lifetime.earned,
|
|
773
|
+
summary.lifetime.allocated,
|
|
774
|
+
summary.lifetime.reclaimed,
|
|
775
|
+
summary.lifetime.spent,
|
|
776
|
+
summary.lifetime.reversed
|
|
777
|
+
],
|
|
778
|
+
"Admin Token economy summary"
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
function assertAdminTokenWalletBalanceFilter(filter) {
|
|
782
|
+
assertExactKeys(
|
|
783
|
+
filter,
|
|
784
|
+
["components", "statuses", "subjectAlias"],
|
|
785
|
+
"Admin Token wallet balance filter"
|
|
786
|
+
);
|
|
787
|
+
if (filter.components !== void 0) {
|
|
788
|
+
assertUniqueValues(
|
|
789
|
+
filter.components,
|
|
790
|
+
WALLET_COMPONENTS,
|
|
791
|
+
"Admin Token wallet components"
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
if (filter.statuses !== void 0) {
|
|
795
|
+
assertUniqueValues(
|
|
796
|
+
filter.statuses,
|
|
797
|
+
WALLET_STATUSES,
|
|
798
|
+
"Admin Token wallet statuses"
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
if (filter.subjectAlias !== void 0) {
|
|
802
|
+
assertAlias(filter.subjectAlias, "Wallet subject alias filter");
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
function sameWalletBalanceFilter(left, right) {
|
|
806
|
+
if (left === void 0 || right === void 0) {
|
|
807
|
+
return left === right;
|
|
808
|
+
}
|
|
809
|
+
return sameOptionalValues(left.components, right.components) && sameOptionalValues(left.statuses, right.statuses) && left.subjectAlias === right.subjectAlias;
|
|
810
|
+
}
|
|
811
|
+
function assertAdminTokenWalletBalanceCursorBinding(binding) {
|
|
812
|
+
assertExactKeys(
|
|
813
|
+
binding,
|
|
814
|
+
[
|
|
815
|
+
"schemaVersion",
|
|
816
|
+
"sort",
|
|
817
|
+
"filter",
|
|
818
|
+
"audience",
|
|
819
|
+
"pseudonymVersion"
|
|
820
|
+
],
|
|
821
|
+
"Admin Token wallet balance cursor binding"
|
|
822
|
+
);
|
|
823
|
+
economyAssert(
|
|
824
|
+
binding.schemaVersion === ECONOMY_CONTRACT_VERSION && WALLET_BALANCE_SORTS.has(binding.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(binding.audience) && PSEUDONYM_VERSION.test(binding.pseudonymVersion),
|
|
825
|
+
"INVALID_CONTRACT",
|
|
826
|
+
"Unsupported Admin Token wallet balance cursor binding"
|
|
827
|
+
);
|
|
828
|
+
if (binding.filter !== void 0) {
|
|
829
|
+
assertAdminTokenWalletBalanceFilter(binding.filter);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function assertAdminTokenWalletBalancePageRequest(request) {
|
|
833
|
+
assertExactKeys(
|
|
834
|
+
request,
|
|
835
|
+
[
|
|
836
|
+
"schemaVersion",
|
|
837
|
+
"limit",
|
|
838
|
+
"cursor",
|
|
839
|
+
"cursorBinding",
|
|
840
|
+
"sort",
|
|
841
|
+
"filter",
|
|
842
|
+
"audience",
|
|
843
|
+
"pseudonymVersion"
|
|
844
|
+
],
|
|
845
|
+
"Admin Token wallet balance request"
|
|
846
|
+
);
|
|
847
|
+
economyAssert(
|
|
848
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && Number.isSafeInteger(request.limit) && request.limit >= 1 && request.limit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE && WALLET_BALANCE_SORTS.has(request.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(request.audience) && PSEUDONYM_VERSION.test(request.pseudonymVersion),
|
|
849
|
+
"INVALID_CONTRACT",
|
|
850
|
+
"Unsupported or unbounded Admin Token wallet balance request"
|
|
851
|
+
);
|
|
852
|
+
if (request.filter !== void 0) {
|
|
853
|
+
assertAdminTokenWalletBalanceFilter(request.filter);
|
|
854
|
+
}
|
|
855
|
+
economyAssert(
|
|
856
|
+
request.cursor === void 0 === (request.cursorBinding === void 0),
|
|
857
|
+
"INVALID_CONTRACT",
|
|
858
|
+
"Admin Token wallet balance cursor and binding must be provided together"
|
|
859
|
+
);
|
|
860
|
+
if (request.cursor === void 0 || request.cursorBinding === void 0) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
assertOpaqueCursor(request.cursor);
|
|
864
|
+
assertAdminTokenWalletBalanceCursorBinding(request.cursorBinding);
|
|
865
|
+
economyAssert(
|
|
866
|
+
request.cursorBinding.sort === request.sort && request.cursorBinding.audience === request.audience && request.cursorBinding.pseudonymVersion === request.pseudonymVersion && sameWalletBalanceFilter(request.cursorBinding.filter, request.filter),
|
|
867
|
+
"INVALID_CONTRACT",
|
|
868
|
+
"Admin Token wallet balance cursor is not bound to the normalized query"
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
function assertAdminTokenWalletBalanceEntry(entry) {
|
|
872
|
+
assertExactKeys(
|
|
873
|
+
entry,
|
|
874
|
+
[
|
|
875
|
+
"schemaVersion",
|
|
876
|
+
"walletAlias",
|
|
877
|
+
"subjectAlias",
|
|
878
|
+
"component",
|
|
879
|
+
"status",
|
|
880
|
+
"available",
|
|
881
|
+
"reserved",
|
|
882
|
+
"held",
|
|
883
|
+
"rewardProgress",
|
|
884
|
+
"updatedAt",
|
|
885
|
+
"authoritySequence"
|
|
886
|
+
],
|
|
887
|
+
"Admin Token wallet balance entry"
|
|
888
|
+
);
|
|
889
|
+
economyAssert(
|
|
890
|
+
entry.schemaVersion === ECONOMY_CONTRACT_VERSION && WALLET_COMPONENTS.has(entry.component) && WALLET_STATUSES.has(entry.status),
|
|
891
|
+
"INVALID_CONTRACT",
|
|
892
|
+
"Unsupported Admin Token wallet balance entry"
|
|
893
|
+
);
|
|
894
|
+
assertAlias(entry.walletAlias, "Wallet alias");
|
|
895
|
+
assertAlias(entry.subjectAlias, "Wallet subject alias");
|
|
896
|
+
economyAssert(
|
|
897
|
+
entry.walletAlias !== entry.subjectAlias,
|
|
898
|
+
"INVALID_CONTRACT",
|
|
899
|
+
"Wallet and subject aliases must use separate pseudonym domains"
|
|
900
|
+
);
|
|
901
|
+
assertNonNegativeTokenAmounts(
|
|
902
|
+
[entry.available, entry.reserved, entry.held, entry.rewardProgress],
|
|
903
|
+
"Admin Token wallet balance entry"
|
|
904
|
+
);
|
|
905
|
+
parseIsoTimestamp(entry.updatedAt);
|
|
906
|
+
assertPositiveAuthoritySequence(
|
|
907
|
+
entry.authoritySequence,
|
|
908
|
+
"Admin Token wallet balance authority sequence"
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
function compareWalletBalanceEntries(left, right, sort) {
|
|
912
|
+
if (sort === "available-desc") {
|
|
913
|
+
const leftAvailable = parseTokenSubunits(left.available);
|
|
914
|
+
const rightAvailable = parseTokenSubunits(right.available);
|
|
915
|
+
if (leftAvailable !== rightAvailable) {
|
|
916
|
+
return leftAvailable > rightAvailable ? -1 : 1;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
const leftUpdatedAt = parseIsoTimestamp(left.updatedAt);
|
|
920
|
+
const rightUpdatedAt = parseIsoTimestamp(right.updatedAt);
|
|
921
|
+
if (leftUpdatedAt !== rightUpdatedAt) {
|
|
922
|
+
return leftUpdatedAt > rightUpdatedAt ? -1 : 1;
|
|
923
|
+
}
|
|
924
|
+
return compareTextDescending(left.walletAlias, right.walletAlias);
|
|
925
|
+
}
|
|
926
|
+
function assertAdminTokenWalletBalancePage(page) {
|
|
927
|
+
assertExactKeys(
|
|
928
|
+
page,
|
|
929
|
+
["schemaVersion", "entries", "hasMore", "nextCursor", "metadata"],
|
|
930
|
+
"Admin Token wallet balance page"
|
|
931
|
+
);
|
|
932
|
+
assertExactKeys(
|
|
933
|
+
page.metadata,
|
|
934
|
+
[
|
|
935
|
+
"schemaVersion",
|
|
936
|
+
"generatedAt",
|
|
937
|
+
"sort",
|
|
938
|
+
"filter",
|
|
939
|
+
"pageLimit",
|
|
940
|
+
"audience",
|
|
941
|
+
"pseudonymVersion",
|
|
942
|
+
"rawIdentifiersIncluded"
|
|
943
|
+
],
|
|
944
|
+
"Admin Token wallet balance metadata"
|
|
945
|
+
);
|
|
946
|
+
economyAssert(
|
|
947
|
+
page.schemaVersion === ECONOMY_CONTRACT_VERSION && page.metadata.schemaVersion === ECONOMY_CONTRACT_VERSION && typeof page.hasMore === "boolean" && page.metadata.rawIdentifiersIncluded === false && WALLET_BALANCE_SORTS.has(page.metadata.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(page.metadata.audience) && PSEUDONYM_VERSION.test(page.metadata.pseudonymVersion) && Number.isSafeInteger(page.metadata.pageLimit) && page.metadata.pageLimit >= 1 && page.metadata.pageLimit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE && Array.isArray(page.entries) && page.entries.length <= page.metadata.pageLimit && page.hasMore === (page.nextCursor !== void 0) && (!page.hasMore || page.entries.length > 0),
|
|
948
|
+
"INVALID_CONTRACT",
|
|
949
|
+
"Unsupported or unbounded Admin Token wallet balance page"
|
|
950
|
+
);
|
|
951
|
+
if (page.metadata.filter !== void 0) {
|
|
952
|
+
assertAdminTokenWalletBalanceFilter(page.metadata.filter);
|
|
953
|
+
}
|
|
954
|
+
parseIsoTimestamp(page.metadata.generatedAt);
|
|
955
|
+
if (page.nextCursor !== void 0) {
|
|
956
|
+
assertOpaqueCursor(page.nextCursor);
|
|
957
|
+
}
|
|
958
|
+
const walletAliases = /* @__PURE__ */ new Set();
|
|
959
|
+
let previous;
|
|
960
|
+
for (const entry of page.entries) {
|
|
961
|
+
assertAdminTokenWalletBalanceEntry(entry);
|
|
962
|
+
const filter = page.metadata.filter;
|
|
963
|
+
economyAssert(
|
|
964
|
+
filter === void 0 || (filter.components === void 0 || filter.components.includes(entry.component)) && (filter.statuses === void 0 || filter.statuses.includes(entry.status)) && (filter.subjectAlias === void 0 || filter.subjectAlias === entry.subjectAlias),
|
|
965
|
+
"INVALID_CONTRACT",
|
|
966
|
+
"Admin Token wallet balance result contains an unrequested row"
|
|
967
|
+
);
|
|
968
|
+
economyAssert(
|
|
969
|
+
!walletAliases.has(entry.walletAlias),
|
|
970
|
+
"DUPLICATE_IDENTIFIER",
|
|
971
|
+
"Admin Token wallet balance page cannot repeat a wallet alias"
|
|
972
|
+
);
|
|
973
|
+
walletAliases.add(entry.walletAlias);
|
|
974
|
+
if (previous !== void 0) {
|
|
975
|
+
economyAssert(
|
|
976
|
+
compareWalletBalanceEntries(previous, entry, page.metadata.sort) < 0,
|
|
977
|
+
"INVALID_CONTRACT",
|
|
978
|
+
"Admin Token wallet balance page does not use its declared stable sort"
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
previous = entry;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function assertAdminTokenWalletBalancePageForRequest(page, request) {
|
|
985
|
+
assertAdminTokenWalletBalancePageRequest(request);
|
|
986
|
+
assertAdminTokenWalletBalancePage(page);
|
|
987
|
+
economyAssert(
|
|
988
|
+
page.metadata.sort === request.sort && sameWalletBalanceFilter(page.metadata.filter, request.filter) && page.metadata.pageLimit === request.limit && page.metadata.audience === request.audience && page.metadata.pseudonymVersion === request.pseudonymVersion,
|
|
989
|
+
"INVALID_CONTRACT",
|
|
990
|
+
"Admin Token wallet balance result does not match its normalized request"
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
function assertAdminTokenActivityEntry(entry) {
|
|
994
|
+
assertExactKeys(
|
|
995
|
+
entry,
|
|
996
|
+
[
|
|
997
|
+
"schemaVersion",
|
|
998
|
+
"occurredAt",
|
|
999
|
+
"activityType",
|
|
1000
|
+
"status",
|
|
1001
|
+
"source",
|
|
1002
|
+
"amount",
|
|
1003
|
+
"safeLabel",
|
|
1004
|
+
"rowAlias",
|
|
1005
|
+
"subjectAlias"
|
|
1006
|
+
],
|
|
1007
|
+
"Admin Token activity entry"
|
|
1008
|
+
);
|
|
1009
|
+
economyAssert(
|
|
1010
|
+
entry.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_TYPES.has(entry.activityType) && ACTIVITY_STATUSES.has(entry.status) && ACTIVITY_SOURCES.has(entry.source),
|
|
1011
|
+
"INVALID_CONTRACT",
|
|
1012
|
+
"Unsupported Admin Token activity contract"
|
|
1013
|
+
);
|
|
1014
|
+
parseIsoTimestamp(entry.occurredAt);
|
|
1015
|
+
const amount = parseTokenSubunits(entry.amount);
|
|
1016
|
+
economyAssert(
|
|
1017
|
+
(amount !== 0n || entry.activityType === "failure") && (entry.activityType !== "acquisition" || amount > 0n) && (entry.activityType !== "spend" || amount < 0n),
|
|
1018
|
+
"INVALID_AMOUNT",
|
|
1019
|
+
"Admin Token activity amount has an invalid sign or zero value"
|
|
1020
|
+
);
|
|
1021
|
+
economyAssert(
|
|
1022
|
+
entry.activityType === "failure" === (entry.status === "failed"),
|
|
1023
|
+
"INVALID_CONTRACT",
|
|
1024
|
+
"Failed rows must use the failure activity type"
|
|
1025
|
+
);
|
|
1026
|
+
economyAssert(
|
|
1027
|
+
SAFE_LABELS.has(entry.safeLabel) && SAFE_LABELS_BY_ACTIVITY_TYPE[entry.activityType]?.has(entry.safeLabel) === true,
|
|
1028
|
+
"INVALID_CONTRACT",
|
|
1029
|
+
"Admin Token activity label must use the approved non-identifying allowlist"
|
|
1030
|
+
);
|
|
1031
|
+
assertAlias(entry.rowAlias, "Row alias");
|
|
1032
|
+
assertAlias(entry.subjectAlias, "Subject alias");
|
|
1033
|
+
economyAssert(
|
|
1034
|
+
entry.rowAlias !== entry.subjectAlias,
|
|
1035
|
+
"INVALID_CONTRACT",
|
|
1036
|
+
"Row and subject aliases must use separate pseudonym domains"
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
function assertAdminTokenActivityFilter(filter) {
|
|
1040
|
+
assertExactKeys(
|
|
1041
|
+
filter,
|
|
1042
|
+
[
|
|
1043
|
+
"activityTypes",
|
|
1044
|
+
"statuses",
|
|
1045
|
+
"sources",
|
|
1046
|
+
"subjectAlias"
|
|
1047
|
+
],
|
|
1048
|
+
"Admin Token activity filter"
|
|
1049
|
+
);
|
|
1050
|
+
if (filter.activityTypes !== void 0) {
|
|
1051
|
+
assertUniqueValues(
|
|
1052
|
+
filter.activityTypes,
|
|
1053
|
+
ACTIVITY_TYPES,
|
|
1054
|
+
"Admin Token activity types"
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
if (filter.statuses !== void 0) {
|
|
1058
|
+
assertUniqueValues(
|
|
1059
|
+
filter.statuses,
|
|
1060
|
+
ACTIVITY_STATUSES,
|
|
1061
|
+
"Admin Token activity statuses"
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
if (filter.sources !== void 0) {
|
|
1065
|
+
assertUniqueValues(
|
|
1066
|
+
filter.sources,
|
|
1067
|
+
ACTIVITY_SOURCES,
|
|
1068
|
+
"Admin Token activity sources"
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
if (filter.subjectAlias !== void 0) {
|
|
1072
|
+
assertAlias(filter.subjectAlias, "Subject alias filter");
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
function sameOptionalValues(left, right) {
|
|
1076
|
+
if (left === void 0 || right === void 0) {
|
|
1077
|
+
return left === right;
|
|
1078
|
+
}
|
|
1079
|
+
return left.length === right.length && left.every((value) => right.includes(value));
|
|
1080
|
+
}
|
|
1081
|
+
function sameActivityFilter(left, right) {
|
|
1082
|
+
if (left === void 0 || right === void 0) {
|
|
1083
|
+
return left === right;
|
|
1084
|
+
}
|
|
1085
|
+
return sameOptionalValues(left.activityTypes, right.activityTypes) && sameOptionalValues(left.statuses, right.statuses) && sameOptionalValues(left.sources, right.sources) && left.subjectAlias === right.subjectAlias;
|
|
1086
|
+
}
|
|
1087
|
+
function assertAdminTokenActivityCursorBinding(binding) {
|
|
1088
|
+
assertExactKeys(
|
|
1089
|
+
binding,
|
|
1090
|
+
[
|
|
1091
|
+
"schemaVersion",
|
|
1092
|
+
"sort",
|
|
1093
|
+
"window",
|
|
1094
|
+
"filter",
|
|
1095
|
+
"audience",
|
|
1096
|
+
"pseudonymVersion"
|
|
1097
|
+
],
|
|
1098
|
+
"Admin Token activity cursor binding"
|
|
1099
|
+
);
|
|
1100
|
+
economyAssert(
|
|
1101
|
+
binding.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_SORTS.has(binding.sort) && PSEUDONYM_AUDIENCES.has(binding.audience) && PSEUDONYM_VERSION.test(binding.pseudonymVersion),
|
|
1102
|
+
"INVALID_CONTRACT",
|
|
1103
|
+
"Unsupported Admin Token activity cursor binding"
|
|
1104
|
+
);
|
|
1105
|
+
assertReportingWindow(binding.window);
|
|
1106
|
+
if (binding.filter !== void 0) {
|
|
1107
|
+
assertAdminTokenActivityFilter(binding.filter);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
function assertAdminTokenActivityPageRequest(request) {
|
|
1111
|
+
assertExactKeys(
|
|
1112
|
+
request,
|
|
1113
|
+
[
|
|
1114
|
+
"schemaVersion",
|
|
1115
|
+
"limit",
|
|
1116
|
+
"cursor",
|
|
1117
|
+
"cursorBinding",
|
|
1118
|
+
"sort",
|
|
1119
|
+
"window",
|
|
1120
|
+
"filter",
|
|
1121
|
+
"audience",
|
|
1122
|
+
"pseudonymVersion"
|
|
1123
|
+
],
|
|
1124
|
+
"Admin Token activity request"
|
|
1125
|
+
);
|
|
1126
|
+
economyAssert(
|
|
1127
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && Number.isSafeInteger(request.limit) && request.limit >= 1 && request.limit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE && ACTIVITY_SORTS.has(request.sort) && PSEUDONYM_AUDIENCES.has(request.audience) && PSEUDONYM_VERSION.test(request.pseudonymVersion),
|
|
1128
|
+
"INVALID_CONTRACT",
|
|
1129
|
+
"Unsupported or unbounded Admin Token activity request"
|
|
1130
|
+
);
|
|
1131
|
+
assertReportingWindow(request.window);
|
|
1132
|
+
if (request.filter !== void 0) {
|
|
1133
|
+
assertAdminTokenActivityFilter(request.filter);
|
|
1134
|
+
}
|
|
1135
|
+
economyAssert(
|
|
1136
|
+
request.cursor === void 0 === (request.cursorBinding === void 0),
|
|
1137
|
+
"INVALID_CONTRACT",
|
|
1138
|
+
"Admin Token activity cursor and trusted binding must be provided together"
|
|
1139
|
+
);
|
|
1140
|
+
if (request.cursor === void 0 || request.cursorBinding === void 0) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
assertOpaqueCursor(request.cursor);
|
|
1144
|
+
assertAdminTokenActivityCursorBinding(request.cursorBinding);
|
|
1145
|
+
economyAssert(
|
|
1146
|
+
request.cursorBinding.sort === request.sort && request.cursorBinding.window.fromInclusive === request.window.fromInclusive && request.cursorBinding.window.toExclusive === request.window.toExclusive && request.cursorBinding.audience === request.audience && request.cursorBinding.pseudonymVersion === request.pseudonymVersion && sameActivityFilter(request.cursorBinding.filter, request.filter),
|
|
1147
|
+
"INVALID_CONTRACT",
|
|
1148
|
+
"Admin Token cursor is not bound to the normalized query"
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
function compareActivityEntries(left, right, sort) {
|
|
1152
|
+
if (sort === "amount-absolute-desc") {
|
|
1153
|
+
const leftAmount = absolute(parseTokenSubunits(left.amount));
|
|
1154
|
+
const rightAmount = absolute(parseTokenSubunits(right.amount));
|
|
1155
|
+
if (leftAmount !== rightAmount) {
|
|
1156
|
+
return leftAmount > rightAmount ? -1 : 1;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
const leftTime = parseIsoTimestamp(left.occurredAt);
|
|
1160
|
+
const rightTime = parseIsoTimestamp(right.occurredAt);
|
|
1161
|
+
if (leftTime !== rightTime) {
|
|
1162
|
+
return leftTime > rightTime ? -1 : 1;
|
|
1163
|
+
}
|
|
1164
|
+
return compareTextDescending(left.rowAlias, right.rowAlias);
|
|
1165
|
+
}
|
|
1166
|
+
function assertAdminTokenActivityPage(page) {
|
|
1167
|
+
assertExactKeys(
|
|
1168
|
+
page,
|
|
1169
|
+
["schemaVersion", "entries", "hasMore", "nextCursor", "metadata"],
|
|
1170
|
+
"Admin Token activity page"
|
|
1171
|
+
);
|
|
1172
|
+
assertExactKeys(
|
|
1173
|
+
page.metadata,
|
|
1174
|
+
[
|
|
1175
|
+
"schemaVersion",
|
|
1176
|
+
"generatedAt",
|
|
1177
|
+
"fromInclusive",
|
|
1178
|
+
"toExclusive",
|
|
1179
|
+
"sort",
|
|
1180
|
+
"filter",
|
|
1181
|
+
"pageLimit",
|
|
1182
|
+
"audience",
|
|
1183
|
+
"pseudonymVersion",
|
|
1184
|
+
"rawIdentifiersIncluded"
|
|
1185
|
+
],
|
|
1186
|
+
"Admin Token activity metadata"
|
|
1187
|
+
);
|
|
1188
|
+
economyAssert(
|
|
1189
|
+
page.schemaVersion === ECONOMY_CONTRACT_VERSION && page.metadata.schemaVersion === ECONOMY_CONTRACT_VERSION && typeof page.hasMore === "boolean" && page.metadata.rawIdentifiersIncluded === false && ACTIVITY_SORTS.has(page.metadata.sort) && PSEUDONYM_AUDIENCES.has(page.metadata.audience) && PSEUDONYM_VERSION.test(page.metadata.pseudonymVersion) && Number.isSafeInteger(page.metadata.pageLimit) && page.metadata.pageLimit >= 1 && page.metadata.pageLimit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE,
|
|
1190
|
+
"INVALID_CONTRACT",
|
|
1191
|
+
"Unsupported Admin Token activity result metadata"
|
|
1192
|
+
);
|
|
1193
|
+
const window = assertReportingWindow({
|
|
1194
|
+
fromInclusive: page.metadata.fromInclusive,
|
|
1195
|
+
toExclusive: page.metadata.toExclusive
|
|
1196
|
+
});
|
|
1197
|
+
if (page.metadata.filter !== void 0) {
|
|
1198
|
+
assertAdminTokenActivityFilter(page.metadata.filter);
|
|
1199
|
+
}
|
|
1200
|
+
parseIsoTimestamp(page.metadata.generatedAt);
|
|
1201
|
+
economyAssert(
|
|
1202
|
+
Array.isArray(page.entries) && page.entries.length <= page.metadata.pageLimit && page.hasMore === (page.nextCursor !== void 0) && (!page.hasMore || page.entries.length > 0),
|
|
1203
|
+
"INVALID_CONTRACT",
|
|
1204
|
+
"Admin Token activity page is unbounded or has inconsistent pagination"
|
|
1205
|
+
);
|
|
1206
|
+
if (page.nextCursor !== void 0) {
|
|
1207
|
+
assertOpaqueCursor(page.nextCursor);
|
|
1208
|
+
}
|
|
1209
|
+
const rowAliases = /* @__PURE__ */ new Set();
|
|
1210
|
+
let previous;
|
|
1211
|
+
for (const entry of page.entries) {
|
|
1212
|
+
assertAdminTokenActivityEntry(entry);
|
|
1213
|
+
const occurredAt = parseIsoTimestamp(entry.occurredAt);
|
|
1214
|
+
economyAssert(
|
|
1215
|
+
occurredAt >= window.from && occurredAt < window.to,
|
|
1216
|
+
"INVALID_TIME_WINDOW",
|
|
1217
|
+
"Admin Token activity falls outside the declared result window"
|
|
1218
|
+
);
|
|
1219
|
+
const filter = page.metadata.filter;
|
|
1220
|
+
economyAssert(
|
|
1221
|
+
filter === void 0 || (filter.activityTypes === void 0 || filter.activityTypes.includes(entry.activityType)) && (filter.statuses === void 0 || filter.statuses.includes(entry.status)) && (filter.sources === void 0 || filter.sources.includes(entry.source)) && (filter.subjectAlias === void 0 || filter.subjectAlias === entry.subjectAlias),
|
|
1222
|
+
"INVALID_CONTRACT",
|
|
1223
|
+
"Admin Token activity result contains a row outside its metadata filters"
|
|
1224
|
+
);
|
|
1225
|
+
economyAssert(
|
|
1226
|
+
!rowAliases.has(entry.rowAlias),
|
|
1227
|
+
"DUPLICATE_IDENTIFIER",
|
|
1228
|
+
"Admin Token activity page cannot repeat a row alias"
|
|
1229
|
+
);
|
|
1230
|
+
rowAliases.add(entry.rowAlias);
|
|
1231
|
+
if (previous !== void 0) {
|
|
1232
|
+
economyAssert(
|
|
1233
|
+
compareActivityEntries(previous, entry, page.metadata.sort) < 0,
|
|
1234
|
+
"INVALID_CONTRACT",
|
|
1235
|
+
"Admin Token activity page does not use its declared stable sort"
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
previous = entry;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
function assertAdminTokenActivityPageForRequest(page, request) {
|
|
1242
|
+
assertAdminTokenActivityPageRequest(request);
|
|
1243
|
+
assertAdminTokenActivityPage(page);
|
|
1244
|
+
economyAssert(
|
|
1245
|
+
page.metadata.fromInclusive === request.window.fromInclusive && page.metadata.toExclusive === request.window.toExclusive && page.metadata.sort === request.sort && sameActivityFilter(page.metadata.filter, request.filter) && page.metadata.pageLimit === request.limit && page.metadata.audience === request.audience && page.metadata.pseudonymVersion === request.pseudonymVersion,
|
|
1246
|
+
"INVALID_CONTRACT",
|
|
1247
|
+
"Admin Token activity result metadata does not match its normalized request"
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function assertAdminTokenTrendRequest(request) {
|
|
1251
|
+
assertExactKeys(
|
|
1252
|
+
request,
|
|
1253
|
+
["schemaVersion", "window", "granularity", "activityTypes"],
|
|
1254
|
+
"Admin Token trend request"
|
|
1255
|
+
);
|
|
1256
|
+
economyAssert(
|
|
1257
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && TREND_GRANULARITIES.has(request.granularity),
|
|
1258
|
+
"INVALID_CONTRACT",
|
|
1259
|
+
"Unsupported Admin Token trend request"
|
|
1260
|
+
);
|
|
1261
|
+
assertReportingWindow(
|
|
1262
|
+
request.window,
|
|
1263
|
+
request.granularity === "hour" ? ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS : ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS
|
|
1264
|
+
);
|
|
1265
|
+
if (request.activityTypes !== void 0) {
|
|
1266
|
+
assertUniqueValues(
|
|
1267
|
+
request.activityTypes,
|
|
1268
|
+
ACTIVITY_TYPES,
|
|
1269
|
+
"Admin Token trend activity types"
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
function medianHalfSubunits(values) {
|
|
1274
|
+
const ordered = [...values].sort(
|
|
1275
|
+
(left, right) => left === right ? 0 : left < right ? -1 : 1
|
|
1276
|
+
);
|
|
1277
|
+
const lower = ordered[Math.floor((ordered.length - 1) / 2)];
|
|
1278
|
+
const upper = ordered[Math.floor(ordered.length / 2)];
|
|
1279
|
+
economyAssert(
|
|
1280
|
+
lower !== void 0 && upper !== void 0,
|
|
1281
|
+
"INVALID_CONTRACT",
|
|
1282
|
+
"Median requires at least one value"
|
|
1283
|
+
);
|
|
1284
|
+
const sum = lower + upper;
|
|
1285
|
+
economyAssert(
|
|
1286
|
+
sum % 2n === 0n,
|
|
1287
|
+
"INVALID_AMOUNT",
|
|
1288
|
+
"Median cannot be represented in exact half TokenSubunits"
|
|
1289
|
+
);
|
|
1290
|
+
return sum / 2n;
|
|
1291
|
+
}
|
|
1292
|
+
function serializeExactStatistic(halfSubunits) {
|
|
1293
|
+
economyAssert(
|
|
1294
|
+
absolute(halfSubunits) <= MAXIMUM_STATISTIC_HALF_SUBUNITS,
|
|
1295
|
+
"AMOUNT_OUT_OF_RANGE",
|
|
1296
|
+
"Admin Token statistic exceeds its exact bounded representation"
|
|
1297
|
+
);
|
|
1298
|
+
if (halfSubunits % 2n === 0n) {
|
|
1299
|
+
return {
|
|
1300
|
+
numerator: (halfSubunits / 2n).toString(10),
|
|
1301
|
+
denominator: 1
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
numerator: halfSubunits.toString(10),
|
|
1306
|
+
denominator: 2
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
function parseExactStatistic(value, label) {
|
|
1310
|
+
assertExactKeys(value, ["numerator", "denominator"], label);
|
|
1311
|
+
economyAssert(
|
|
1312
|
+
typeof value.numerator === "string" && value.numerator.length <= 22 && EXACT_STATISTIC_INTEGER.test(value.numerator) && (value.denominator === 1 || value.denominator === 2),
|
|
1313
|
+
"INVALID_AMOUNT",
|
|
1314
|
+
`${label} must be an exact bounded rational TokenSubunit value`
|
|
1315
|
+
);
|
|
1316
|
+
const numerator = BigInt(value.numerator);
|
|
1317
|
+
economyAssert(
|
|
1318
|
+
value.denominator === 1 || numerator % 2n !== 0n,
|
|
1319
|
+
"INVALID_AMOUNT",
|
|
1320
|
+
`${label} must use a reduced exact representation`
|
|
1321
|
+
);
|
|
1322
|
+
const halfSubunits = numerator * BigInt(2 / value.denominator);
|
|
1323
|
+
economyAssert(
|
|
1324
|
+
absolute(halfSubunits) <= MAXIMUM_STATISTIC_HALF_SUBUNITS,
|
|
1325
|
+
"AMOUNT_OUT_OF_RANGE",
|
|
1326
|
+
`${label} exceeds its exact bounded representation`
|
|
1327
|
+
);
|
|
1328
|
+
return halfSubunits;
|
|
1329
|
+
}
|
|
1330
|
+
function classifyAnomaly(options) {
|
|
1331
|
+
if (options.absoluteDeltaHalfSubunits < options.minimumAbsoluteDeltaHalfSubunits) {
|
|
1332
|
+
return {
|
|
1333
|
+
status: "normal",
|
|
1334
|
+
explanationCode: "below-absolute-minimum"
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
if (options.medianAbsoluteDeviationHalfSubunits === 0n) {
|
|
1338
|
+
return options.absoluteDeltaHalfSubunits > 0n ? {
|
|
1339
|
+
status: "irregular-spike",
|
|
1340
|
+
explanationCode: "zero-mad-absolute-threshold-exceeded"
|
|
1341
|
+
} : {
|
|
1342
|
+
status: "normal",
|
|
1343
|
+
explanationCode: "within-baseline-variation"
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
const exceedsBaseline = options.absoluteDeltaHalfSubunits * 1000n >= options.medianAbsoluteDeviationHalfSubunits * BigInt(options.madMultiplierMilli);
|
|
1347
|
+
return exceedsBaseline ? {
|
|
1348
|
+
status: "irregular-spike",
|
|
1349
|
+
explanationCode: "median-mad-and-absolute-threshold-exceeded"
|
|
1350
|
+
} : {
|
|
1351
|
+
status: "normal",
|
|
1352
|
+
explanationCode: "within-baseline-variation"
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
function createAdminTokenAnomalyIndicator(input) {
|
|
1356
|
+
assertExactKeys(
|
|
1357
|
+
input,
|
|
1358
|
+
[
|
|
1359
|
+
"observedAmount",
|
|
1360
|
+
"baselineSamples",
|
|
1361
|
+
"minimumAbsoluteDelta",
|
|
1362
|
+
"madMultiplierMilli"
|
|
1363
|
+
],
|
|
1364
|
+
"Admin Token anomaly input"
|
|
1365
|
+
);
|
|
1366
|
+
economyAssert(
|
|
1367
|
+
Array.isArray(input.baselineSamples) && input.baselineSamples.length === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && Number.isSafeInteger(input.madMultiplierMilli) && input.madMultiplierMilli >= 1 && input.madMultiplierMilli <= 1e6,
|
|
1368
|
+
"INVALID_CONTRACT",
|
|
1369
|
+
"Admin Token anomaly input requires 28 baselines and a bounded fixed-point multiplier"
|
|
1370
|
+
);
|
|
1371
|
+
const observed = parseTokenSubunits(input.observedAmount);
|
|
1372
|
+
const baseline = input.baselineSamples.map((sample) => {
|
|
1373
|
+
assertExactKeys(
|
|
1374
|
+
sample,
|
|
1375
|
+
["amount", "distinctSubjects"],
|
|
1376
|
+
"Admin Token anomaly baseline sample"
|
|
1377
|
+
);
|
|
1378
|
+
economyAssert(
|
|
1379
|
+
Number.isSafeInteger(sample.distinctSubjects) && sample.distinctSubjects >= ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
1380
|
+
"INVALID_CONTRACT",
|
|
1381
|
+
"Admin Token anomaly baselines must exclude privacy-suppressed cohorts"
|
|
1382
|
+
);
|
|
1383
|
+
return parseTokenSubunits(sample.amount);
|
|
1384
|
+
});
|
|
1385
|
+
const minimum = parseTokenSubunits(input.minimumAbsoluteDelta);
|
|
1386
|
+
economyAssert(
|
|
1387
|
+
minimum > 0n,
|
|
1388
|
+
"INVALID_AMOUNT",
|
|
1389
|
+
"Admin Token anomaly absolute minimum must be positive"
|
|
1390
|
+
);
|
|
1391
|
+
const baselineHalfSubunits = baseline.map((amount) => amount * 2n);
|
|
1392
|
+
const medianHalf = medianHalfSubunits(baselineHalfSubunits);
|
|
1393
|
+
const medianAbsoluteDeviationHalf = medianHalfSubunits(
|
|
1394
|
+
baselineHalfSubunits.map((amount) => absolute(amount - medianHalf))
|
|
1395
|
+
);
|
|
1396
|
+
const deviationHalf = observed * 2n - medianHalf;
|
|
1397
|
+
const classification = classifyAnomaly({
|
|
1398
|
+
absoluteDeltaHalfSubunits: absolute(deviationHalf),
|
|
1399
|
+
medianAbsoluteDeviationHalfSubunits: medianAbsoluteDeviationHalf,
|
|
1400
|
+
minimumAbsoluteDeltaHalfSubunits: minimum * 2n,
|
|
1401
|
+
madMultiplierMilli: input.madMultiplierMilli
|
|
1402
|
+
});
|
|
1403
|
+
return {
|
|
1404
|
+
method: "same-window-median-mad-v1",
|
|
1405
|
+
...classification,
|
|
1406
|
+
baselineWindowCount: ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1407
|
+
medianAmount: serializeExactStatistic(medianHalf),
|
|
1408
|
+
medianAbsoluteDeviation: serializeExactStatistic(medianAbsoluteDeviationHalf),
|
|
1409
|
+
minimumAbsoluteDelta: input.minimumAbsoluteDelta,
|
|
1410
|
+
deviationFromMedian: serializeExactStatistic(deviationHalf),
|
|
1411
|
+
madMultiplierMilli: input.madMultiplierMilli
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
function createAdminTokenAnomalyUnavailable(input) {
|
|
1415
|
+
assertExactKeys(
|
|
1416
|
+
input,
|
|
1417
|
+
["reason", "eligibleBaselineWindowCount"],
|
|
1418
|
+
"Unavailable Admin Token anomaly input"
|
|
1419
|
+
);
|
|
1420
|
+
economyAssert(
|
|
1421
|
+
ANOMALY_UNAVAILABLE_REASONS.has(input.reason) && Number.isSafeInteger(input.eligibleBaselineWindowCount) && input.eligibleBaselineWindowCount >= 0 && input.eligibleBaselineWindowCount < ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1422
|
+
"INVALID_CONTRACT",
|
|
1423
|
+
"Unavailable Admin Token anomaly requires a bounded reason and eligible baseline count"
|
|
1424
|
+
);
|
|
1425
|
+
return {
|
|
1426
|
+
method: "same-window-median-mad-v1",
|
|
1427
|
+
status: "unavailable",
|
|
1428
|
+
reason: input.reason,
|
|
1429
|
+
eligibleBaselineWindowCount: input.eligibleBaselineWindowCount,
|
|
1430
|
+
requiredBaselineWindowCount: ADMIN_TOKEN_ANOMALY_BASELINE_DAYS
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
function assertAdminTokenAnomalyIndicator(anomaly, observedAmount) {
|
|
1434
|
+
assertExactKeys(
|
|
1435
|
+
anomaly,
|
|
1436
|
+
[
|
|
1437
|
+
"method",
|
|
1438
|
+
"status",
|
|
1439
|
+
"baselineWindowCount",
|
|
1440
|
+
"medianAmount",
|
|
1441
|
+
"medianAbsoluteDeviation",
|
|
1442
|
+
"minimumAbsoluteDelta",
|
|
1443
|
+
"deviationFromMedian",
|
|
1444
|
+
"madMultiplierMilli",
|
|
1445
|
+
"explanationCode"
|
|
1446
|
+
],
|
|
1447
|
+
"Admin Token anomaly indicator"
|
|
1448
|
+
);
|
|
1449
|
+
const observed = parseTokenSubunits(observedAmount);
|
|
1450
|
+
const medianHalf = parseExactStatistic(
|
|
1451
|
+
anomaly.medianAmount,
|
|
1452
|
+
"Admin Token anomaly median"
|
|
1453
|
+
);
|
|
1454
|
+
const madHalf = parseExactStatistic(
|
|
1455
|
+
anomaly.medianAbsoluteDeviation,
|
|
1456
|
+
"Admin Token anomaly median absolute deviation"
|
|
1457
|
+
);
|
|
1458
|
+
const minimum = parseTokenSubunits(anomaly.minimumAbsoluteDelta);
|
|
1459
|
+
const deviationHalf = parseExactStatistic(
|
|
1460
|
+
anomaly.deviationFromMedian,
|
|
1461
|
+
"Admin Token anomaly deviation"
|
|
1462
|
+
);
|
|
1463
|
+
economyAssert(
|
|
1464
|
+
anomaly.method === "same-window-median-mad-v1" && anomaly.baselineWindowCount === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && medianHalf >= TOKEN_SUBUNITS_MIN * 2n && medianHalf <= TOKEN_SUBUNITS_MAX * 2n && madHalf >= 0n && minimum > 0n && Number.isSafeInteger(anomaly.madMultiplierMilli) && anomaly.madMultiplierMilli >= 1 && anomaly.madMultiplierMilli <= 1e6 && deviationHalf === observed * 2n - medianHalf,
|
|
1465
|
+
"INVALID_CONTRACT",
|
|
1466
|
+
"Admin Token anomaly arithmetic or method is invalid"
|
|
1467
|
+
);
|
|
1468
|
+
const expected = classifyAnomaly({
|
|
1469
|
+
absoluteDeltaHalfSubunits: absolute(deviationHalf),
|
|
1470
|
+
medianAbsoluteDeviationHalfSubunits: madHalf,
|
|
1471
|
+
minimumAbsoluteDeltaHalfSubunits: minimum * 2n,
|
|
1472
|
+
madMultiplierMilli: anomaly.madMultiplierMilli
|
|
1473
|
+
});
|
|
1474
|
+
economyAssert(
|
|
1475
|
+
anomaly.status === expected.status && anomaly.explanationCode === expected.explanationCode,
|
|
1476
|
+
"INVALID_CONTRACT",
|
|
1477
|
+
"Admin Token anomaly classification is inconsistent with its explanation"
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
function assertAdminTokenAnomalyUnavailable(anomaly) {
|
|
1481
|
+
assertExactKeys(
|
|
1482
|
+
anomaly,
|
|
1483
|
+
[
|
|
1484
|
+
"method",
|
|
1485
|
+
"status",
|
|
1486
|
+
"reason",
|
|
1487
|
+
"eligibleBaselineWindowCount",
|
|
1488
|
+
"requiredBaselineWindowCount"
|
|
1489
|
+
],
|
|
1490
|
+
"Unavailable Admin Token anomaly"
|
|
1491
|
+
);
|
|
1492
|
+
economyAssert(
|
|
1493
|
+
anomaly.method === "same-window-median-mad-v1" && anomaly.status === "unavailable" && ANOMALY_UNAVAILABLE_REASONS.has(anomaly.reason) && Number.isSafeInteger(anomaly.eligibleBaselineWindowCount) && anomaly.eligibleBaselineWindowCount >= 0 && anomaly.eligibleBaselineWindowCount < ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && anomaly.requiredBaselineWindowCount === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1494
|
+
"INVALID_CONTRACT",
|
|
1495
|
+
"Unavailable Admin Token anomaly metadata is invalid"
|
|
1496
|
+
);
|
|
1497
|
+
}
|
|
1498
|
+
function assertTrendBucketAlignment(start, end, granularity) {
|
|
1499
|
+
const expectedDuration = granularity === "hour" ? HOUR_MILLISECONDS : DAY_MILLISECONDS;
|
|
1500
|
+
const date = new Date(start);
|
|
1501
|
+
const aligned = date.getUTCMinutes() === 0 && date.getUTCSeconds() === 0 && date.getUTCMilliseconds() === 0 && (granularity === "hour" || date.getUTCHours() === 0);
|
|
1502
|
+
economyAssert(
|
|
1503
|
+
aligned && end - start === expectedDuration,
|
|
1504
|
+
"INVALID_TIME_WINDOW",
|
|
1505
|
+
"Admin Token trend bucket is not aligned to its declared granularity"
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
function assertTrendAggregate(aggregate) {
|
|
1509
|
+
assertPlainObject(aggregate, "Admin Token trend aggregate");
|
|
1510
|
+
if (aggregate.visibility === "suppressed") {
|
|
1511
|
+
assertExactKeys(
|
|
1512
|
+
aggregate,
|
|
1513
|
+
["visibility", "reason", "threshold"],
|
|
1514
|
+
"Suppressed Admin Token trend aggregate"
|
|
1515
|
+
);
|
|
1516
|
+
economyAssert(
|
|
1517
|
+
aggregate.reason === "cohort-below-minimum" && aggregate.threshold === ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
1518
|
+
"INVALID_CONTRACT",
|
|
1519
|
+
"Suppressed Admin Token trend aggregate has invalid privacy metadata"
|
|
1520
|
+
);
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
assertExactKeys(
|
|
1524
|
+
aggregate,
|
|
1525
|
+
[
|
|
1526
|
+
"visibility",
|
|
1527
|
+
"distinctSubjects",
|
|
1528
|
+
"activityCount",
|
|
1529
|
+
"signedAmount"
|
|
1530
|
+
],
|
|
1531
|
+
"Reported Admin Token trend aggregate"
|
|
1532
|
+
);
|
|
1533
|
+
parseTokenSubunits(aggregate.signedAmount);
|
|
1534
|
+
economyAssert(
|
|
1535
|
+
aggregate.visibility === "reported" && Number.isSafeInteger(aggregate.distinctSubjects) && aggregate.distinctSubjects >= ADMIN_TOKEN_MINIMUM_COHORT_SIZE && Number.isSafeInteger(aggregate.activityCount) && aggregate.activityCount >= aggregate.distinctSubjects,
|
|
1536
|
+
"INVALID_CONTRACT",
|
|
1537
|
+
"Reported Admin Token trend aggregate is invalid or below the privacy threshold"
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
function assertAdminTokenTrendResult(result) {
|
|
1541
|
+
assertExactKeys(
|
|
1542
|
+
result,
|
|
1543
|
+
["schemaVersion", "series", "metadata"],
|
|
1544
|
+
"Admin Token trend result"
|
|
1545
|
+
);
|
|
1546
|
+
assertExactKeys(
|
|
1547
|
+
result.metadata,
|
|
1548
|
+
[
|
|
1549
|
+
"schemaVersion",
|
|
1550
|
+
"generatedAt",
|
|
1551
|
+
"fromInclusive",
|
|
1552
|
+
"toExclusive",
|
|
1553
|
+
"granularity",
|
|
1554
|
+
"activityTypes",
|
|
1555
|
+
"minimumCohortSize",
|
|
1556
|
+
"anomalyBaselineDays",
|
|
1557
|
+
"rawIdentifiersIncluded"
|
|
1558
|
+
],
|
|
1559
|
+
"Admin Token trend metadata"
|
|
1560
|
+
);
|
|
1561
|
+
economyAssert(
|
|
1562
|
+
result.schemaVersion === ECONOMY_CONTRACT_VERSION && result.metadata.schemaVersion === ECONOMY_CONTRACT_VERSION && TREND_GRANULARITIES.has(result.metadata.granularity) && result.metadata.minimumCohortSize === ADMIN_TOKEN_MINIMUM_COHORT_SIZE && result.metadata.anomalyBaselineDays === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && result.metadata.rawIdentifiersIncluded === false && Array.isArray(result.series) && result.series.length <= ADMIN_TOKEN_MAXIMUM_TREND_POINTS,
|
|
1563
|
+
"INVALID_CONTRACT",
|
|
1564
|
+
"Unsupported or unbounded Admin Token trend result"
|
|
1565
|
+
);
|
|
1566
|
+
assertUniqueValues(
|
|
1567
|
+
result.metadata.activityTypes,
|
|
1568
|
+
ACTIVITY_TYPES,
|
|
1569
|
+
"Admin Token trend result activity types"
|
|
1570
|
+
);
|
|
1571
|
+
const window = assertReportingWindow(
|
|
1572
|
+
{
|
|
1573
|
+
fromInclusive: result.metadata.fromInclusive,
|
|
1574
|
+
toExclusive: result.metadata.toExclusive
|
|
1575
|
+
},
|
|
1576
|
+
result.metadata.granularity === "hour" ? ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS : ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS
|
|
1577
|
+
);
|
|
1578
|
+
parseIsoTimestamp(result.metadata.generatedAt);
|
|
1579
|
+
const pointKeys = /* @__PURE__ */ new Set();
|
|
1580
|
+
let previousKey;
|
|
1581
|
+
for (const point of result.series) {
|
|
1582
|
+
assertExactKeys(
|
|
1583
|
+
point,
|
|
1584
|
+
[
|
|
1585
|
+
"schemaVersion",
|
|
1586
|
+
"bucketStart",
|
|
1587
|
+
"bucketEnd",
|
|
1588
|
+
"activityType",
|
|
1589
|
+
"aggregate",
|
|
1590
|
+
"anomaly"
|
|
1591
|
+
],
|
|
1592
|
+
"Admin Token trend point"
|
|
1593
|
+
);
|
|
1594
|
+
economyAssert(
|
|
1595
|
+
point.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_TYPES.has(point.activityType) && result.metadata.activityTypes.includes(point.activityType),
|
|
1596
|
+
"INVALID_CONTRACT",
|
|
1597
|
+
"Unsupported Admin Token trend point"
|
|
1598
|
+
);
|
|
1599
|
+
const start = parseIsoTimestamp(point.bucketStart);
|
|
1600
|
+
const end = parseIsoTimestamp(point.bucketEnd);
|
|
1601
|
+
economyAssert(
|
|
1602
|
+
start >= window.from && end <= window.to,
|
|
1603
|
+
"INVALID_TIME_WINDOW",
|
|
1604
|
+
"Admin Token trend bucket falls outside the declared result window"
|
|
1605
|
+
);
|
|
1606
|
+
assertTrendBucketAlignment(start, end, result.metadata.granularity);
|
|
1607
|
+
assertTrendAggregate(point.aggregate);
|
|
1608
|
+
if (point.aggregate.visibility === "suppressed") {
|
|
1609
|
+
economyAssert(
|
|
1610
|
+
point.anomaly === void 0,
|
|
1611
|
+
"INVALID_CONTRACT",
|
|
1612
|
+
"Suppressed Admin Token cohorts cannot include anomaly details"
|
|
1613
|
+
);
|
|
1614
|
+
} else {
|
|
1615
|
+
economyAssert(
|
|
1616
|
+
point.anomaly !== void 0,
|
|
1617
|
+
"INVALID_CONTRACT",
|
|
1618
|
+
"Reported Admin Token cohorts require an anomaly result"
|
|
1619
|
+
);
|
|
1620
|
+
if (point.anomaly.status === "unavailable") {
|
|
1621
|
+
assertAdminTokenAnomalyUnavailable(point.anomaly);
|
|
1622
|
+
} else {
|
|
1623
|
+
assertAdminTokenAnomalyIndicator(
|
|
1624
|
+
point.anomaly,
|
|
1625
|
+
point.aggregate.signedAmount
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
const key = `${point.bucketStart}\0${point.activityType}`;
|
|
1630
|
+
economyAssert(
|
|
1631
|
+
!pointKeys.has(key) && (previousKey === void 0 || previousKey < key),
|
|
1632
|
+
"DUPLICATE_IDENTIFIER",
|
|
1633
|
+
"Admin Token trend points must be unique and stably ordered"
|
|
1634
|
+
);
|
|
1635
|
+
pointKeys.add(key);
|
|
1636
|
+
previousKey = key;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
function assertAdminTokenTrendResultForRequest(result, request) {
|
|
1640
|
+
assertAdminTokenTrendRequest(request);
|
|
1641
|
+
assertAdminTokenTrendResult(result);
|
|
1642
|
+
const requestedActivityTypes = request.activityTypes ?? [...ACTIVITY_TYPES];
|
|
1643
|
+
economyAssert(
|
|
1644
|
+
result.metadata.fromInclusive === request.window.fromInclusive && result.metadata.toExclusive === request.window.toExclusive && result.metadata.granularity === request.granularity && sameOptionalValues(
|
|
1645
|
+
result.metadata.activityTypes,
|
|
1646
|
+
requestedActivityTypes
|
|
1647
|
+
),
|
|
1648
|
+
"INVALID_CONTRACT",
|
|
1649
|
+
"Admin Token trend result metadata does not match its normalized request"
|
|
1650
|
+
);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
504
1653
|
// src/allocations.ts
|
|
505
1654
|
function assertWholePositive(amount, label) {
|
|
506
1655
|
const parsed = parseTokenSubunits(amount);
|
|
@@ -746,7 +1895,8 @@ var COMMAND_TYPES = /* @__PURE__ */ new Set([
|
|
|
746
1895
|
"chargeback",
|
|
747
1896
|
"reverse",
|
|
748
1897
|
"adjust",
|
|
749
|
-
"initialize-wallet"
|
|
1898
|
+
"initialize-wallet",
|
|
1899
|
+
"initialize-admin-reporting"
|
|
750
1900
|
]);
|
|
751
1901
|
var COMMAND_SOURCES = /* @__PURE__ */ new Set([
|
|
752
1902
|
"browser",
|
|
@@ -810,6 +1960,7 @@ var SOURCE_COMMAND_TYPES = {
|
|
|
810
1960
|
system: /* @__PURE__ */ new Set([
|
|
811
1961
|
"credit-event",
|
|
812
1962
|
"credit-competition",
|
|
1963
|
+
"initialize-admin-reporting",
|
|
813
1964
|
"hold",
|
|
814
1965
|
"release-hold",
|
|
815
1966
|
"reverse"
|
|
@@ -837,7 +1988,7 @@ var COMMAND_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
837
1988
|
"acceptedRegion",
|
|
838
1989
|
"writerFencingToken"
|
|
839
1990
|
]);
|
|
840
|
-
function
|
|
1991
|
+
function assertExactKeys2(value, allowedKeys, label) {
|
|
841
1992
|
economyAssert(
|
|
842
1993
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
843
1994
|
"INVALID_CONTRACT",
|
|
@@ -881,7 +2032,7 @@ function assertRelationshipContext(relationshipId, authorizationVersion) {
|
|
|
881
2032
|
);
|
|
882
2033
|
}
|
|
883
2034
|
function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
|
|
884
|
-
|
|
2035
|
+
assertExactKeys2(
|
|
885
2036
|
fingerprint,
|
|
886
2037
|
/* @__PURE__ */ new Set([
|
|
887
2038
|
"schemaVersion",
|
|
@@ -906,7 +2057,7 @@ function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
|
|
|
906
2057
|
);
|
|
907
2058
|
}
|
|
908
2059
|
function assertEconomyAuthorizationEvidence(evidence) {
|
|
909
|
-
|
|
2060
|
+
assertExactKeys2(
|
|
910
2061
|
evidence,
|
|
911
2062
|
/* @__PURE__ */ new Set([
|
|
912
2063
|
"schemaVersion",
|
|
@@ -943,7 +2094,7 @@ function assertEconomyAuthorizationEvidence(evidence) {
|
|
|
943
2094
|
);
|
|
944
2095
|
}
|
|
945
2096
|
function assertCausationReference(causation) {
|
|
946
|
-
|
|
2097
|
+
assertExactKeys2(
|
|
947
2098
|
causation,
|
|
948
2099
|
/* @__PURE__ */ new Set(["schemaVersion", "kind", "causationId"]),
|
|
949
2100
|
"Economy causation reference"
|
|
@@ -998,7 +2149,7 @@ function assertCommandSourcePrincipal(envelope) {
|
|
|
998
2149
|
}
|
|
999
2150
|
}
|
|
1000
2151
|
function assertAuditedEconomyCommandEnvelope(envelope) {
|
|
1001
|
-
|
|
2152
|
+
assertExactKeys2(
|
|
1002
2153
|
envelope,
|
|
1003
2154
|
COMMAND_ENVELOPE_KEYS,
|
|
1004
2155
|
"Audited economy command envelope"
|
|
@@ -1064,7 +2215,7 @@ function assertAuditedEconomyCommandEnvelope(envelope) {
|
|
|
1064
2215
|
);
|
|
1065
2216
|
}
|
|
1066
2217
|
function assertEconomyProviderEvidenceHash(evidence) {
|
|
1067
|
-
|
|
2218
|
+
assertExactKeys2(
|
|
1068
2219
|
evidence,
|
|
1069
2220
|
/* @__PURE__ */ new Set([
|
|
1070
2221
|
"schemaVersion",
|
|
@@ -1135,7 +2286,7 @@ function assertEconomyProviderEvidenceHash(evidence) {
|
|
|
1135
2286
|
}
|
|
1136
2287
|
}
|
|
1137
2288
|
function assertEconomyEncryptedOperationalHandleBinding(binding) {
|
|
1138
|
-
|
|
2289
|
+
assertExactKeys2(
|
|
1139
2290
|
binding,
|
|
1140
2291
|
/* @__PURE__ */ new Set([
|
|
1141
2292
|
"schemaVersion",
|
|
@@ -1170,7 +2321,7 @@ function assertEconomyEncryptedOperationalHandleBinding(binding) {
|
|
|
1170
2321
|
parseIsoTimestamp(binding.createdAt);
|
|
1171
2322
|
}
|
|
1172
2323
|
function assertEvidenceRecordReference(reference) {
|
|
1173
|
-
|
|
2324
|
+
assertExactKeys2(
|
|
1174
2325
|
reference,
|
|
1175
2326
|
/* @__PURE__ */ new Set(["schemaVersion", "recordId", "contentHash"]),
|
|
1176
2327
|
"Evidence record reference"
|
|
@@ -1201,7 +2352,7 @@ function assertUniqueSortedReferences(references, label) {
|
|
|
1201
2352
|
}
|
|
1202
2353
|
}
|
|
1203
2354
|
function assertEconomyProviderEvidenceManifest(manifest) {
|
|
1204
|
-
|
|
2355
|
+
assertExactKeys2(
|
|
1205
2356
|
manifest,
|
|
1206
2357
|
/* @__PURE__ */ new Set([
|
|
1207
2358
|
"schemaVersion",
|
|
@@ -1243,7 +2394,7 @@ function assertEconomyProviderEvidenceManifest(manifest) {
|
|
|
1243
2394
|
parseIsoTimestamp(manifest.createdAt);
|
|
1244
2395
|
}
|
|
1245
2396
|
function assertEconomyAcceptedCommandReceipt(receipt) {
|
|
1246
|
-
|
|
2397
|
+
assertExactKeys2(
|
|
1247
2398
|
receipt,
|
|
1248
2399
|
/* @__PURE__ */ new Set([
|
|
1249
2400
|
"schemaVersion",
|
|
@@ -1267,7 +2418,7 @@ function assertEconomyAcceptedCommandReceipt(receipt) {
|
|
|
1267
2418
|
parseIsoTimestamp(receipt.acceptedAt);
|
|
1268
2419
|
}
|
|
1269
2420
|
function assertEconomyCommandResultReceipt(receipt) {
|
|
1270
|
-
|
|
2421
|
+
assertExactKeys2(
|
|
1271
2422
|
receipt,
|
|
1272
2423
|
/* @__PURE__ */ new Set([
|
|
1273
2424
|
"schemaVersion",
|
|
@@ -1324,7 +2475,7 @@ function assertEconomyCommandResultReceipt(receipt) {
|
|
|
1324
2475
|
}
|
|
1325
2476
|
}
|
|
1326
2477
|
function assertEconomyAuditedIdempotencyScope(scope) {
|
|
1327
|
-
|
|
2478
|
+
assertExactKeys2(
|
|
1328
2479
|
scope,
|
|
1329
2480
|
/* @__PURE__ */ new Set([
|
|
1330
2481
|
"schemaVersion",
|
|
@@ -1355,7 +2506,7 @@ function assertEconomyAuditedIdempotencyScope(scope) {
|
|
|
1355
2506
|
);
|
|
1356
2507
|
}
|
|
1357
2508
|
function assertEconomyAuditedIdempotencyResult(result) {
|
|
1358
|
-
|
|
2509
|
+
assertExactKeys2(
|
|
1359
2510
|
result,
|
|
1360
2511
|
/* @__PURE__ */ new Set([
|
|
1361
2512
|
"schemaVersion",
|
|
@@ -1646,7 +2797,7 @@ var MANIFEST_KEYS = /* @__PURE__ */ new Set([
|
|
|
1646
2797
|
"recordReferences",
|
|
1647
2798
|
"committedAt"
|
|
1648
2799
|
]);
|
|
1649
|
-
function
|
|
2800
|
+
function assertExactKeys3(value, allowedKeys, label) {
|
|
1650
2801
|
economyAssert(
|
|
1651
2802
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
1652
2803
|
"INVALID_CONTRACT",
|
|
@@ -1684,7 +2835,7 @@ function referenceOrder(left, right) {
|
|
|
1684
2835
|
return byKind === 0 ? compareUnicodeCodeUnits(left.recordId, right.recordId) : byKind;
|
|
1685
2836
|
}
|
|
1686
2837
|
function assertEconomyAuthorityRecordReference(reference) {
|
|
1687
|
-
|
|
2838
|
+
assertExactKeys3(
|
|
1688
2839
|
reference,
|
|
1689
2840
|
/* @__PURE__ */ new Set([
|
|
1690
2841
|
"schemaVersion",
|
|
@@ -1848,7 +2999,7 @@ function assertCommitAllowedInState(manifest) {
|
|
|
1848
2999
|
}
|
|
1849
3000
|
}
|
|
1850
3001
|
function assertEconomyAuthorityCommitManifest(manifest) {
|
|
1851
|
-
|
|
3002
|
+
assertExactKeys3(manifest, MANIFEST_KEYS, "Authority commit manifest");
|
|
1852
3003
|
economyAssert(
|
|
1853
3004
|
manifest.schemaVersion === ECONOMY_CONTRACT_VERSION && COMMIT_KINDS.has(manifest.commitKind) && AUTHORITY_STATES.has(manifest.authorityStateBefore) && AUTHORITY_STATES.has(manifest.authorityStateAfter),
|
|
1854
3005
|
"INVALID_CONTRACT",
|
|
@@ -1895,7 +3046,7 @@ function assertEconomyAuthorityCommitManifest(manifest) {
|
|
|
1895
3046
|
parseIsoTimestamp(manifest.committedAt);
|
|
1896
3047
|
}
|
|
1897
3048
|
function assertEconomyAuthorityHead(head) {
|
|
1898
|
-
|
|
3049
|
+
assertExactKeys3(head, HEAD_KEYS, "Economy authority head");
|
|
1899
3050
|
economyAssert(
|
|
1900
3051
|
head.schemaVersion === ECONOMY_CONTRACT_VERSION && AUTHORITY_STATES.has(head.state),
|
|
1901
3052
|
"INVALID_CONTRACT",
|
|
@@ -1954,7 +3105,7 @@ function advanceEconomyAuthorityHead(head, manifest, manifestCanonicalHash) {
|
|
|
1954
3105
|
};
|
|
1955
3106
|
}
|
|
1956
3107
|
function assertEconomyIntegrityVerificationReceipt(receipt) {
|
|
1957
|
-
|
|
3108
|
+
assertExactKeys3(
|
|
1958
3109
|
receipt,
|
|
1959
3110
|
/* @__PURE__ */ new Set([
|
|
1960
3111
|
"schemaVersion",
|
|
@@ -2100,7 +3251,7 @@ function assertEconomyIntegrityVerificationReceipt(receipt) {
|
|
|
2100
3251
|
parseIsoTimestamp(receipt.verifiedAt);
|
|
2101
3252
|
}
|
|
2102
3253
|
function assertEconomyIntegrityAnchorManifest(manifest) {
|
|
2103
|
-
|
|
3254
|
+
assertExactKeys3(
|
|
2104
3255
|
manifest,
|
|
2105
3256
|
/* @__PURE__ */ new Set([
|
|
2106
3257
|
"schemaVersion",
|
|
@@ -2262,7 +3413,7 @@ function sortEconomyAuthorityRecordReferences(references) {
|
|
|
2262
3413
|
}
|
|
2263
3414
|
|
|
2264
3415
|
// src/ledger.ts
|
|
2265
|
-
var
|
|
3416
|
+
var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
|
|
2266
3417
|
"purchase",
|
|
2267
3418
|
"subscription",
|
|
2268
3419
|
"rewarded-ad",
|
|
@@ -2279,14 +3430,14 @@ var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
|
2279
3430
|
"event",
|
|
2280
3431
|
"competition"
|
|
2281
3432
|
]);
|
|
2282
|
-
var
|
|
3433
|
+
var ACTIVITY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
2283
3434
|
"pending",
|
|
2284
3435
|
"held",
|
|
2285
3436
|
"settled",
|
|
2286
3437
|
"reversed",
|
|
2287
3438
|
"failed"
|
|
2288
3439
|
]);
|
|
2289
|
-
var
|
|
3440
|
+
var ACTIVITY_SOURCES2 = /* @__PURE__ */ new Set([
|
|
2290
3441
|
"shopify",
|
|
2291
3442
|
"ayet",
|
|
2292
3443
|
"bitlabs",
|
|
@@ -2316,7 +3467,7 @@ function assertActivityEntry(entry) {
|
|
|
2316
3467
|
);
|
|
2317
3468
|
assertEconomyIdentifier(entry.transactionId, "transactionId");
|
|
2318
3469
|
economyAssert(
|
|
2319
|
-
|
|
3470
|
+
ACTIVITY_TYPES2.has(entry.activityType) && ACTIVITY_STATUSES2.has(entry.status) && ACTIVITY_SOURCES2.has(entry.source),
|
|
2320
3471
|
"INVALID_CONTRACT",
|
|
2321
3472
|
"Activity type, status, or source is unsupported"
|
|
2322
3473
|
);
|
|
@@ -2354,7 +3505,7 @@ function assertBalancedTransaction(transaction) {
|
|
|
2354
3505
|
assertEconomyIdentifier(transaction.transactionId, "transactionId");
|
|
2355
3506
|
assertEconomyIdentifier(transaction.idempotencyKey, "idempotencyKey");
|
|
2356
3507
|
economyAssert(
|
|
2357
|
-
|
|
3508
|
+
ACTIVITY_TYPES2.has(transaction.activityType) && ACTIVITY_STATUSES2.has(transaction.status),
|
|
2358
3509
|
"INVALID_CONTRACT",
|
|
2359
3510
|
"Transaction activity type or status is unsupported"
|
|
2360
3511
|
);
|
|
@@ -4393,7 +5544,7 @@ var DECISIONS = /* @__PURE__ */ new Set([
|
|
|
4393
5544
|
"approve",
|
|
4394
5545
|
"reject"
|
|
4395
5546
|
]);
|
|
4396
|
-
function
|
|
5547
|
+
function assertExactKeys4(value, allowed, label) {
|
|
4397
5548
|
economyAssert(
|
|
4398
5549
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
4399
5550
|
"INVALID_CONTRACT",
|
|
@@ -4420,7 +5571,7 @@ function assertReasonCode(reasonCode) {
|
|
|
4420
5571
|
);
|
|
4421
5572
|
}
|
|
4422
5573
|
function assertOperatorAdjustmentPreview(preview) {
|
|
4423
|
-
|
|
5574
|
+
assertExactKeys4(preview, PREVIEW_KEYS, "Operator adjustment preview");
|
|
4424
5575
|
economyAssert(
|
|
4425
5576
|
preview.schemaVersion === ECONOMY_CONTRACT_VERSION && OPERATIONS.has(preview.operation) && TARGET_COMPONENTS.has(preview.targetComponent) && TRANSFER_POLICIES.has(preview.transferPolicy) && preview.refundPolicy === "not-refundable",
|
|
4426
5577
|
"INVALID_CONTRACT",
|
|
@@ -4499,7 +5650,7 @@ function canonicalOperatorAdjustmentPreviewPayload(preview) {
|
|
|
4499
5650
|
function assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash) {
|
|
4500
5651
|
assertOperatorAdjustmentPreview(preview);
|
|
4501
5652
|
assertCanonicalHash6(expectedPreviewHash, "expectedPreviewHash");
|
|
4502
|
-
|
|
5653
|
+
assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
|
|
4503
5654
|
economyAssert(
|
|
4504
5655
|
proposal.schemaVersion === ECONOMY_CONTRACT_VERSION && proposal.status === "pending-approval",
|
|
4505
5656
|
"INVALID_CONTRACT",
|
|
@@ -4526,7 +5677,7 @@ function assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash
|
|
|
4526
5677
|
);
|
|
4527
5678
|
}
|
|
4528
5679
|
function canonicalOperatorAdjustmentProposalPayload(proposal) {
|
|
4529
|
-
|
|
5680
|
+
assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
|
|
4530
5681
|
return JSON.stringify({
|
|
4531
5682
|
schemaVersion: proposal.schemaVersion,
|
|
4532
5683
|
proposalId: proposal.proposalId,
|
|
@@ -4541,7 +5692,7 @@ function canonicalOperatorAdjustmentProposalPayload(proposal) {
|
|
|
4541
5692
|
function assertOperatorAdjustmentDecision(decision, proposal, preview, expectedPreviewHash, expectedProposalHash) {
|
|
4542
5693
|
assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash);
|
|
4543
5694
|
assertCanonicalHash6(expectedProposalHash, "expectedProposalHash");
|
|
4544
|
-
|
|
5695
|
+
assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
|
|
4545
5696
|
economyAssert(
|
|
4546
5697
|
decision.schemaVersion === ECONOMY_CONTRACT_VERSION && DECISIONS.has(decision.decision),
|
|
4547
5698
|
"INVALID_CONTRACT",
|
|
@@ -4584,7 +5735,7 @@ function assertOperatorAdjustmentDecision(decision, proposal, preview, expectedP
|
|
|
4584
5735
|
);
|
|
4585
5736
|
}
|
|
4586
5737
|
function canonicalOperatorAdjustmentDecisionPayload(decision) {
|
|
4587
|
-
|
|
5738
|
+
assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
|
|
4588
5739
|
return JSON.stringify({
|
|
4589
5740
|
schemaVersion: decision.schemaVersion,
|
|
4590
5741
|
decisionId: decision.decisionId,
|
|
@@ -4608,7 +5759,7 @@ function assertOperatorAdjustmentExecution(execution, preview, proposal, decisio
|
|
|
4608
5759
|
expectedProposalHash
|
|
4609
5760
|
);
|
|
4610
5761
|
assertCanonicalHash6(expectedDecisionHash, "expectedDecisionHash");
|
|
4611
|
-
|
|
5762
|
+
assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
|
|
4612
5763
|
economyAssert(
|
|
4613
5764
|
execution.schemaVersion === ECONOMY_CONTRACT_VERSION,
|
|
4614
5765
|
"INVALID_CONTRACT",
|
|
@@ -4639,7 +5790,7 @@ function assertOperatorAdjustmentExecution(execution, preview, proposal, decisio
|
|
|
4639
5790
|
);
|
|
4640
5791
|
}
|
|
4641
5792
|
function canonicalOperatorAdjustmentExecutionPayload(execution) {
|
|
4642
|
-
|
|
5793
|
+
assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
|
|
4643
5794
|
return JSON.stringify({
|
|
4644
5795
|
schemaVersion: execution.schemaVersion,
|
|
4645
5796
|
executionId: execution.executionId,
|
|
@@ -5684,7 +6835,7 @@ function createProjectionSnapshot(transactions, rebuiltAt) {
|
|
|
5684
6835
|
}
|
|
5685
6836
|
|
|
5686
6837
|
// src/ports/query.ts
|
|
5687
|
-
var
|
|
6838
|
+
var ACTIVITY_TYPES3 = /* @__PURE__ */ new Set([
|
|
5688
6839
|
"purchase",
|
|
5689
6840
|
"subscription",
|
|
5690
6841
|
"rewarded-ad",
|
|
@@ -5701,14 +6852,14 @@ var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
|
|
|
5701
6852
|
"event",
|
|
5702
6853
|
"competition"
|
|
5703
6854
|
]);
|
|
5704
|
-
var
|
|
6855
|
+
var ACTIVITY_STATUSES3 = /* @__PURE__ */ new Set([
|
|
5705
6856
|
"pending",
|
|
5706
6857
|
"held",
|
|
5707
6858
|
"settled",
|
|
5708
6859
|
"reversed",
|
|
5709
6860
|
"failed"
|
|
5710
6861
|
]);
|
|
5711
|
-
var
|
|
6862
|
+
var ACTIVITY_SOURCES3 = /* @__PURE__ */ new Set([
|
|
5712
6863
|
"shopify",
|
|
5713
6864
|
"ayet",
|
|
5714
6865
|
"bitlabs",
|
|
@@ -5736,14 +6887,14 @@ function assertSafeDisplayString(value, label) {
|
|
|
5736
6887
|
`${label} must be bounded and safe for display`
|
|
5737
6888
|
);
|
|
5738
6889
|
}
|
|
5739
|
-
function
|
|
6890
|
+
function assertOpaqueCursor2(value) {
|
|
5740
6891
|
economyAssert(
|
|
5741
6892
|
typeof value === "string" && value.length > 0 && value.length <= 512 && !hasControlCharacters2(value),
|
|
5742
6893
|
"INVALID_CONTRACT",
|
|
5743
6894
|
"Activity cursor must be a bounded opaque value"
|
|
5744
6895
|
);
|
|
5745
6896
|
}
|
|
5746
|
-
function
|
|
6897
|
+
function assertUniqueValues2(values, allowed, label) {
|
|
5747
6898
|
const unique = new Set(values);
|
|
5748
6899
|
economyAssert(
|
|
5749
6900
|
values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
|
|
@@ -6006,7 +7157,7 @@ function assertWalletActivityEntry(entry) {
|
|
|
6006
7157
|
assertEconomyIdentifier(entry.activityId, "activityId");
|
|
6007
7158
|
assertEconomyIdentifier(entry.walletId, "walletId");
|
|
6008
7159
|
economyAssert(
|
|
6009
|
-
|
|
7160
|
+
ACTIVITY_TYPES3.has(entry.activityType) && ACTIVITY_STATUSES3.has(entry.status) && ACTIVITY_SOURCES3.has(entry.source),
|
|
6010
7161
|
"INVALID_CONTRACT",
|
|
6011
7162
|
"Wallet activity type, status, or source is unsupported"
|
|
6012
7163
|
);
|
|
@@ -6054,20 +7205,20 @@ function assertWalletActivityPageRequest(request) {
|
|
|
6054
7205
|
"Activity page limit must be between one and 100"
|
|
6055
7206
|
);
|
|
6056
7207
|
if (request.cursor !== void 0) {
|
|
6057
|
-
|
|
7208
|
+
assertOpaqueCursor2(request.cursor);
|
|
6058
7209
|
}
|
|
6059
7210
|
const filter = request.filter;
|
|
6060
7211
|
if (filter === void 0) {
|
|
6061
7212
|
return;
|
|
6062
7213
|
}
|
|
6063
7214
|
if (filter.activityTypes !== void 0) {
|
|
6064
|
-
|
|
7215
|
+
assertUniqueValues2(filter.activityTypes, ACTIVITY_TYPES3, "Activity types");
|
|
6065
7216
|
}
|
|
6066
7217
|
if (filter.statuses !== void 0) {
|
|
6067
|
-
|
|
7218
|
+
assertUniqueValues2(filter.statuses, ACTIVITY_STATUSES3, "Activity statuses");
|
|
6068
7219
|
}
|
|
6069
7220
|
if (filter.sources !== void 0) {
|
|
6070
|
-
|
|
7221
|
+
assertUniqueValues2(filter.sources, ACTIVITY_SOURCES3, "Activity sources");
|
|
6071
7222
|
}
|
|
6072
7223
|
if (filter.beneficiaryAccountId !== void 0) {
|
|
6073
7224
|
assertEconomyIdentifier(
|
|
@@ -6100,7 +7251,7 @@ function assertWalletActivityPage(page) {
|
|
|
6100
7251
|
"Activity pages are bounded and cannot advertise more rows from an empty page"
|
|
6101
7252
|
);
|
|
6102
7253
|
if (page.nextCursor !== void 0) {
|
|
6103
|
-
|
|
7254
|
+
assertOpaqueCursor2(page.nextCursor);
|
|
6104
7255
|
}
|
|
6105
7256
|
const activityIds = /* @__PURE__ */ new Set();
|
|
6106
7257
|
let previous;
|
|
@@ -7082,7 +8233,7 @@ var RESULT_OUTCOMES = /* @__PURE__ */ new Set([
|
|
|
7082
8233
|
"failed",
|
|
7083
8234
|
"no-op"
|
|
7084
8235
|
]);
|
|
7085
|
-
var
|
|
8236
|
+
var ACTIVITY_TYPES4 = /* @__PURE__ */ new Set([
|
|
7086
8237
|
"purchase",
|
|
7087
8238
|
"subscription",
|
|
7088
8239
|
"rewarded-ad",
|
|
@@ -7194,7 +8345,7 @@ var PORTABLE_KEYS = /* @__PURE__ */ new Set([
|
|
|
7194
8345
|
"signature",
|
|
7195
8346
|
...PORTABLE_BODY_KEYS
|
|
7196
8347
|
]);
|
|
7197
|
-
function
|
|
8348
|
+
function assertExactKeys5(value, allowedKeys, label) {
|
|
7198
8349
|
economyAssert(
|
|
7199
8350
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
7200
8351
|
"INVALID_CONTRACT",
|
|
@@ -7283,7 +8434,7 @@ function canonicalSignatureMetadata(signature) {
|
|
|
7283
8434
|
};
|
|
7284
8435
|
}
|
|
7285
8436
|
function assertEconomySealedRecoveryPayload(payload) {
|
|
7286
|
-
|
|
8437
|
+
assertExactKeys5(
|
|
7287
8438
|
payload,
|
|
7288
8439
|
/* @__PURE__ */ new Set([
|
|
7289
8440
|
"schemaVersion",
|
|
@@ -7323,7 +8474,7 @@ function assertEconomySealedRecoveryPayload(payload) {
|
|
|
7323
8474
|
);
|
|
7324
8475
|
}
|
|
7325
8476
|
function assertAcceptanceBody(body) {
|
|
7326
|
-
|
|
8477
|
+
assertExactKeys5(
|
|
7327
8478
|
body,
|
|
7328
8479
|
"acceptanceEnvelopeId" in body ? ACCEPTANCE_KEYS : ACCEPTANCE_BODY_KEYS,
|
|
7329
8480
|
"Recovery acceptance body"
|
|
@@ -7392,7 +8543,7 @@ function createEconomyRecoveryAcceptanceEnvelope(body, hashCanonicalPayload2) {
|
|
|
7392
8543
|
};
|
|
7393
8544
|
}
|
|
7394
8545
|
function assertEconomyRecoveryAcceptanceEnvelope(envelope, hashCanonicalPayload2) {
|
|
7395
|
-
|
|
8546
|
+
assertExactKeys5(envelope, ACCEPTANCE_KEYS, "Recovery acceptance envelope");
|
|
7396
8547
|
assertAcceptanceBody(envelope);
|
|
7397
8548
|
assertEconomyIdentifier(
|
|
7398
8549
|
envelope.acceptanceEnvelopeId,
|
|
@@ -7433,7 +8584,7 @@ function canonicalEconomyRecoveryAcceptanceEnvelopePayload(envelope, hashCanonic
|
|
|
7433
8584
|
});
|
|
7434
8585
|
}
|
|
7435
8586
|
function assertCommittedResultBody(body) {
|
|
7436
|
-
|
|
8587
|
+
assertExactKeys5(
|
|
7437
8588
|
body,
|
|
7438
8589
|
"committedResultId" in body ? COMMITTED_RESULT_KEYS : COMMITTED_RESULT_BODY_KEYS,
|
|
7439
8590
|
"Recovery committed-result body"
|
|
@@ -7527,7 +8678,7 @@ function createEconomyRecoveryCommittedResult(body, hashCanonicalPayload2) {
|
|
|
7527
8678
|
};
|
|
7528
8679
|
}
|
|
7529
8680
|
function assertEconomyRecoveryCommittedResult(result, hashCanonicalPayload2) {
|
|
7530
|
-
|
|
8681
|
+
assertExactKeys5(
|
|
7531
8682
|
result,
|
|
7532
8683
|
COMMITTED_RESULT_KEYS,
|
|
7533
8684
|
"Recovery committed result"
|
|
@@ -7586,7 +8737,7 @@ function assertEconomyRecoveryResultLink(acceptance, result, hashCanonicalPayloa
|
|
|
7586
8737
|
);
|
|
7587
8738
|
}
|
|
7588
8739
|
function assertEconomyEvidenceSignatureMetadata(signature) {
|
|
7589
|
-
|
|
8740
|
+
assertExactKeys5(
|
|
7590
8741
|
signature,
|
|
7591
8742
|
/* @__PURE__ */ new Set([
|
|
7592
8743
|
"schemaVersion",
|
|
@@ -7606,7 +8757,7 @@ function assertEconomyEvidenceSignatureMetadata(signature) {
|
|
|
7606
8757
|
parseIsoTimestamp(signature.signedAt);
|
|
7607
8758
|
}
|
|
7608
8759
|
function assertEconomyEvidenceSignature(signature) {
|
|
7609
|
-
|
|
8760
|
+
assertExactKeys5(
|
|
7610
8761
|
signature,
|
|
7611
8762
|
/* @__PURE__ */ new Set([
|
|
7612
8763
|
"schemaVersion",
|
|
@@ -7628,7 +8779,7 @@ function assertEconomyEvidenceSignature(signature) {
|
|
|
7628
8779
|
assertBase64url(signature.value, "Evidence signature value", 32, 2048);
|
|
7629
8780
|
}
|
|
7630
8781
|
function assertRegionalEvidenceBody(body) {
|
|
7631
|
-
|
|
8782
|
+
assertExactKeys5(
|
|
7632
8783
|
body,
|
|
7633
8784
|
"evidenceReceiptId" in body ? REGIONAL_KEYS : REGIONAL_BODY_KEYS,
|
|
7634
8785
|
"Regional evidence-receipt body"
|
|
@@ -7720,7 +8871,7 @@ function createEconomyRegionalEvidenceReceipt(body, signature, hashCanonicalPayl
|
|
|
7720
8871
|
};
|
|
7721
8872
|
}
|
|
7722
8873
|
function assertEconomyRegionalEvidenceReceipt(receipt, hashCanonicalPayload2) {
|
|
7723
|
-
|
|
8874
|
+
assertExactKeys5(receipt, REGIONAL_KEYS, "Regional evidence receipt");
|
|
7724
8875
|
assertRegionalEvidenceBody(receipt);
|
|
7725
8876
|
assertEconomyIdentifier(receipt.evidenceReceiptId, "evidenceReceiptId");
|
|
7726
8877
|
assertEconomyEvidenceSignature(receipt.signature);
|
|
@@ -7922,7 +9073,7 @@ function assertEconomyRegionalEvidenceEquality(receipts, expectedRegions, hashCa
|
|
|
7922
9073
|
);
|
|
7923
9074
|
}
|
|
7924
9075
|
function assertEconomyMerkleInclusionProof(proof) {
|
|
7925
|
-
|
|
9076
|
+
assertExactKeys5(
|
|
7926
9077
|
proof,
|
|
7927
9078
|
/* @__PURE__ */ new Set([
|
|
7928
9079
|
"schemaVersion",
|
|
@@ -7953,7 +9104,7 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7953
9104
|
"Merkle leaf position is outside its bounded tree"
|
|
7954
9105
|
);
|
|
7955
9106
|
for (const step of proof.siblings) {
|
|
7956
|
-
|
|
9107
|
+
assertExactKeys5(
|
|
7957
9108
|
step,
|
|
7958
9109
|
/* @__PURE__ */ new Set(["schemaVersion", "side", "hash"]),
|
|
7959
9110
|
"Merkle proof step"
|
|
@@ -8042,7 +9193,7 @@ function assertEconomyMerkleInclusion(proof, anchor, hashCanonicalPayload2) {
|
|
|
8042
9193
|
);
|
|
8043
9194
|
}
|
|
8044
9195
|
function assertPortableEvidenceReference(reference) {
|
|
8045
|
-
|
|
9196
|
+
assertExactKeys5(
|
|
8046
9197
|
reference,
|
|
8047
9198
|
/* @__PURE__ */ new Set([
|
|
8048
9199
|
"schemaVersion",
|
|
@@ -8079,7 +9230,7 @@ function canonicalPortableEvidenceReference(reference) {
|
|
|
8079
9230
|
};
|
|
8080
9231
|
}
|
|
8081
9232
|
function assertPortableBody(body) {
|
|
8082
|
-
|
|
9233
|
+
assertExactKeys5(
|
|
8083
9234
|
body,
|
|
8084
9235
|
"portableReceiptId" in body ? PORTABLE_KEYS : PORTABLE_BODY_KEYS,
|
|
8085
9236
|
"Portable customer-receipt body"
|
|
@@ -8103,7 +9254,7 @@ function assertPortableBody(body) {
|
|
|
8103
9254
|
assertEconomyIdentifier(value, label);
|
|
8104
9255
|
}
|
|
8105
9256
|
economyAssert(
|
|
8106
|
-
|
|
9257
|
+
ACTIVITY_TYPES4.has(body.activityType) && (body.direction === "credit" || body.direction === "debit"),
|
|
8107
9258
|
"INVALID_CONTRACT",
|
|
8108
9259
|
"Portable customer receipt has an unsupported activity or direction"
|
|
8109
9260
|
);
|
|
@@ -8203,7 +9354,7 @@ function createEconomyPortableCustomerReceipt(body, signature, hashCanonicalPayl
|
|
|
8203
9354
|
};
|
|
8204
9355
|
}
|
|
8205
9356
|
function assertEconomyPortableCustomerReceipt(receipt, hashCanonicalPayload2) {
|
|
8206
|
-
|
|
9357
|
+
assertExactKeys5(receipt, PORTABLE_KEYS, "Portable customer receipt");
|
|
8207
9358
|
assertPortableBody(receipt);
|
|
8208
9359
|
assertEconomyIdentifier(receipt.portableReceiptId, "portableReceiptId");
|
|
8209
9360
|
assertEconomyEvidenceSignature(receipt.signature);
|
|
@@ -8503,7 +9654,7 @@ var DOCUMENT_ID_KEYS = /* @__PURE__ */ new Set([
|
|
|
8503
9654
|
"lifetimeProjectionId",
|
|
8504
9655
|
"outboxEventId"
|
|
8505
9656
|
]);
|
|
8506
|
-
function
|
|
9657
|
+
function assertExactKeys6(value, allowed, label) {
|
|
8507
9658
|
economyAssert(
|
|
8508
9659
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
8509
9660
|
"INVALID_CONTRACT",
|
|
@@ -8543,7 +9694,7 @@ function createPersonalWalletInitializationDocumentIds(subjectAccountId, hash) {
|
|
|
8543
9694
|
};
|
|
8544
9695
|
}
|
|
8545
9696
|
function assertPersonalWalletInitializationCommand(command) {
|
|
8546
|
-
|
|
9697
|
+
assertExactKeys6(command, COMMAND_KEYS, "Wallet initialization command");
|
|
8547
9698
|
economyAssert(
|
|
8548
9699
|
command.schemaVersion === ECONOMY_CONTRACT_VERSION && command.commandType === "initialize-wallet" && command.walletKind === "personal",
|
|
8549
9700
|
"INVALID_CONTRACT",
|
|
@@ -8567,7 +9718,7 @@ function canonicalPersonalWalletInitializationCommandPayload(command) {
|
|
|
8567
9718
|
});
|
|
8568
9719
|
}
|
|
8569
9720
|
function assertPersonalWalletInitializationOutboxIntent(intent) {
|
|
8570
|
-
|
|
9721
|
+
assertExactKeys6(intent, OUTBOX_KEYS, "Wallet initialization outbox intent");
|
|
8571
9722
|
economyAssert(
|
|
8572
9723
|
intent.schemaVersion === ECONOMY_CONTRACT_VERSION && intent.eventType === "wallet.initialized.v1",
|
|
8573
9724
|
"INVALID_CONTRACT",
|
|
@@ -8667,8 +9818,8 @@ function createPersonalWalletInitializationState(input, hash) {
|
|
|
8667
9818
|
return state;
|
|
8668
9819
|
}
|
|
8669
9820
|
function assertPersonalWalletInitializationState(state) {
|
|
8670
|
-
|
|
8671
|
-
|
|
9821
|
+
assertExactKeys6(state, STATE_KEYS, "Wallet initialization state");
|
|
9822
|
+
assertExactKeys6(
|
|
8672
9823
|
state.documentIds,
|
|
8673
9824
|
DOCUMENT_ID_KEYS,
|
|
8674
9825
|
"Wallet initialization document IDs"
|
|
@@ -8699,6 +9850,13 @@ function assertPersonalWalletInitializationState(state) {
|
|
|
8699
9850
|
);
|
|
8700
9851
|
}
|
|
8701
9852
|
export {
|
|
9853
|
+
ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
9854
|
+
ADMIN_TOKEN_DEFAULT_WINDOW_DAYS,
|
|
9855
|
+
ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS,
|
|
9856
|
+
ADMIN_TOKEN_MAXIMUM_PAGE_SIZE,
|
|
9857
|
+
ADMIN_TOKEN_MAXIMUM_TREND_POINTS,
|
|
9858
|
+
ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS,
|
|
9859
|
+
ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
8702
9860
|
BASELINE_GBP_CATALOG_VERSION,
|
|
8703
9861
|
BASELINE_GBP_REFERENCE_RATE,
|
|
8704
9862
|
BASELINE_GBP_TOKEN_PACKS,
|
|
@@ -8726,6 +9884,19 @@ export {
|
|
|
8726
9884
|
applyWalletBalanceDelta,
|
|
8727
9885
|
applyWalletLifetimeDeltas,
|
|
8728
9886
|
assertActivityEntry,
|
|
9887
|
+
assertAdminTokenActivityCursorBinding,
|
|
9888
|
+
assertAdminTokenActivityEntry,
|
|
9889
|
+
assertAdminTokenActivityPage,
|
|
9890
|
+
assertAdminTokenActivityPageForRequest,
|
|
9891
|
+
assertAdminTokenActivityPageRequest,
|
|
9892
|
+
assertAdminTokenEconomySummary,
|
|
9893
|
+
assertAdminTokenTrendRequest,
|
|
9894
|
+
assertAdminTokenTrendResult,
|
|
9895
|
+
assertAdminTokenTrendResultForRequest,
|
|
9896
|
+
assertAdminTokenWalletBalanceCursorBinding,
|
|
9897
|
+
assertAdminTokenWalletBalancePage,
|
|
9898
|
+
assertAdminTokenWalletBalancePageForRequest,
|
|
9899
|
+
assertAdminTokenWalletBalancePageRequest,
|
|
8729
9900
|
assertAuditedEconomyCommandEnvelope,
|
|
8730
9901
|
assertBalancedTransaction,
|
|
8731
9902
|
assertDeterministicWalletBalanceSummary,
|
|
@@ -8855,6 +10026,9 @@ export {
|
|
|
8855
10026
|
canonicalTransactionPayload,
|
|
8856
10027
|
closeModuleAllowance,
|
|
8857
10028
|
convertRewardPayout,
|
|
10029
|
+
createAdminTokenAnomalyIndicator,
|
|
10030
|
+
createAdminTokenAnomalyUnavailable,
|
|
10031
|
+
createDefaultAdminTokenReportingWindow,
|
|
8858
10032
|
createEarlyBackerRetentionFromPaidLot,
|
|
8859
10033
|
createEconomyPortableCustomerReceipt,
|
|
8860
10034
|
createEconomyRecoveryAcceptanceEnvelope,
|