@plasius/economy 0.6.0 → 0.8.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 +85 -0
- package/dist/index.cjs +1619 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +417 -2
- package/dist/index.d.ts +417 -2
- package/dist/index.js +1588 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ADMIN_TOKEN_ANOMALY_BASELINE_DAYS: () => ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
24
|
+
ADMIN_TOKEN_DEFAULT_WINDOW_DAYS: () => ADMIN_TOKEN_DEFAULT_WINDOW_DAYS,
|
|
25
|
+
ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS: () => ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS,
|
|
26
|
+
ADMIN_TOKEN_MAXIMUM_PAGE_SIZE: () => ADMIN_TOKEN_MAXIMUM_PAGE_SIZE,
|
|
27
|
+
ADMIN_TOKEN_MAXIMUM_TREND_POINTS: () => ADMIN_TOKEN_MAXIMUM_TREND_POINTS,
|
|
28
|
+
ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS: () => ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS,
|
|
29
|
+
ADMIN_TOKEN_MINIMUM_COHORT_SIZE: () => ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
23
30
|
BASELINE_GBP_CATALOG_VERSION: () => BASELINE_GBP_CATALOG_VERSION,
|
|
24
31
|
BASELINE_GBP_REFERENCE_RATE: () => BASELINE_GBP_REFERENCE_RATE,
|
|
25
32
|
BASELINE_GBP_TOKEN_PACKS: () => BASELINE_GBP_TOKEN_PACKS,
|
|
@@ -47,6 +54,19 @@ __export(index_exports, {
|
|
|
47
54
|
applyWalletBalanceDelta: () => applyWalletBalanceDelta,
|
|
48
55
|
applyWalletLifetimeDeltas: () => applyWalletLifetimeDeltas,
|
|
49
56
|
assertActivityEntry: () => assertActivityEntry,
|
|
57
|
+
assertAdminTokenActivityCursorBinding: () => assertAdminTokenActivityCursorBinding,
|
|
58
|
+
assertAdminTokenActivityEntry: () => assertAdminTokenActivityEntry,
|
|
59
|
+
assertAdminTokenActivityPage: () => assertAdminTokenActivityPage,
|
|
60
|
+
assertAdminTokenActivityPageForRequest: () => assertAdminTokenActivityPageForRequest,
|
|
61
|
+
assertAdminTokenActivityPageRequest: () => assertAdminTokenActivityPageRequest,
|
|
62
|
+
assertAdminTokenEconomySummary: () => assertAdminTokenEconomySummary,
|
|
63
|
+
assertAdminTokenTrendRequest: () => assertAdminTokenTrendRequest,
|
|
64
|
+
assertAdminTokenTrendResult: () => assertAdminTokenTrendResult,
|
|
65
|
+
assertAdminTokenTrendResultForRequest: () => assertAdminTokenTrendResultForRequest,
|
|
66
|
+
assertAdminTokenWalletBalanceCursorBinding: () => assertAdminTokenWalletBalanceCursorBinding,
|
|
67
|
+
assertAdminTokenWalletBalancePage: () => assertAdminTokenWalletBalancePage,
|
|
68
|
+
assertAdminTokenWalletBalancePageForRequest: () => assertAdminTokenWalletBalancePageForRequest,
|
|
69
|
+
assertAdminTokenWalletBalancePageRequest: () => assertAdminTokenWalletBalancePageRequest,
|
|
50
70
|
assertAuditedEconomyCommandEnvelope: () => assertAuditedEconomyCommandEnvelope,
|
|
51
71
|
assertBalancedTransaction: () => assertBalancedTransaction,
|
|
52
72
|
assertDeterministicWalletBalanceSummary: () => assertDeterministicWalletBalanceSummary,
|
|
@@ -100,6 +120,10 @@ __export(index_exports, {
|
|
|
100
120
|
assertModuleSpendQuote: () => assertModuleSpendQuote,
|
|
101
121
|
assertNonNegativeAccounts: () => assertNonNegativeAccounts,
|
|
102
122
|
assertOpenPurchaseIntent: () => assertOpenPurchaseIntent,
|
|
123
|
+
assertOperatorAdjustmentDecision: () => assertOperatorAdjustmentDecision,
|
|
124
|
+
assertOperatorAdjustmentExecution: () => assertOperatorAdjustmentExecution,
|
|
125
|
+
assertOperatorAdjustmentPreview: () => assertOperatorAdjustmentPreview,
|
|
126
|
+
assertOperatorAdjustmentProposal: () => assertOperatorAdjustmentProposal,
|
|
103
127
|
assertPaidLotLifecycle: () => assertPaidLotLifecycle,
|
|
104
128
|
assertPaidLotLifecycleEvent: () => assertPaidLotLifecycleEvent,
|
|
105
129
|
assertPaidLotPurchaseProvenance: () => assertPaidLotPurchaseProvenance,
|
|
@@ -163,11 +187,18 @@ __export(index_exports, {
|
|
|
163
187
|
canonicalEconomyRegionalEvidenceReceiptBodyPayload: () => canonicalEconomyRegionalEvidenceReceiptBodyPayload,
|
|
164
188
|
canonicalEconomyRegionalEvidenceReceiptPayload: () => canonicalEconomyRegionalEvidenceReceiptPayload,
|
|
165
189
|
canonicalEconomyRegionalEvidenceReceiptSigningPayload: () => canonicalEconomyRegionalEvidenceReceiptSigningPayload,
|
|
190
|
+
canonicalOperatorAdjustmentDecisionPayload: () => canonicalOperatorAdjustmentDecisionPayload,
|
|
191
|
+
canonicalOperatorAdjustmentExecutionPayload: () => canonicalOperatorAdjustmentExecutionPayload,
|
|
192
|
+
canonicalOperatorAdjustmentPreviewPayload: () => canonicalOperatorAdjustmentPreviewPayload,
|
|
193
|
+
canonicalOperatorAdjustmentProposalPayload: () => canonicalOperatorAdjustmentProposalPayload,
|
|
166
194
|
canonicalPersonalWalletInitializationCommandPayload: () => canonicalPersonalWalletInitializationCommandPayload,
|
|
167
195
|
canonicalPersonalWalletInitializationOutboxPayload: () => canonicalPersonalWalletInitializationOutboxPayload,
|
|
168
196
|
canonicalTransactionPayload: () => canonicalTransactionPayload,
|
|
169
197
|
closeModuleAllowance: () => closeModuleAllowance,
|
|
170
198
|
convertRewardPayout: () => convertRewardPayout,
|
|
199
|
+
createAdminTokenAnomalyIndicator: () => createAdminTokenAnomalyIndicator,
|
|
200
|
+
createAdminTokenAnomalyUnavailable: () => createAdminTokenAnomalyUnavailable,
|
|
201
|
+
createDefaultAdminTokenReportingWindow: () => createDefaultAdminTokenReportingWindow,
|
|
171
202
|
createEarlyBackerRetentionFromPaidLot: () => createEarlyBackerRetentionFromPaidLot,
|
|
172
203
|
createEconomyPortableCustomerReceipt: () => createEconomyPortableCustomerReceipt,
|
|
173
204
|
createEconomyRecoveryAcceptanceEnvelope: () => createEconomyRecoveryAcceptanceEnvelope,
|
|
@@ -728,6 +759,1155 @@ function mapBitLabsConversionState(state) {
|
|
|
728
759
|
return transition;
|
|
729
760
|
}
|
|
730
761
|
|
|
762
|
+
// src/admin-reporting.ts
|
|
763
|
+
var ADMIN_TOKEN_DEFAULT_WINDOW_DAYS = 30;
|
|
764
|
+
var ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS = 365;
|
|
765
|
+
var ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS = 31;
|
|
766
|
+
var ADMIN_TOKEN_MAXIMUM_PAGE_SIZE = 100;
|
|
767
|
+
var ADMIN_TOKEN_MAXIMUM_TREND_POINTS = ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS * 24 * 5;
|
|
768
|
+
var ADMIN_TOKEN_MINIMUM_COHORT_SIZE = 5;
|
|
769
|
+
var ADMIN_TOKEN_ANOMALY_BASELINE_DAYS = 28;
|
|
770
|
+
var DAY_MILLISECONDS = 864e5;
|
|
771
|
+
var HOUR_MILLISECONDS = 36e5;
|
|
772
|
+
var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
773
|
+
"acquisition",
|
|
774
|
+
"spend",
|
|
775
|
+
"reversal",
|
|
776
|
+
"hold",
|
|
777
|
+
"failure"
|
|
778
|
+
]);
|
|
779
|
+
var ACTIVITY_STATUSES = /* @__PURE__ */ new Set([
|
|
780
|
+
"pending",
|
|
781
|
+
"held",
|
|
782
|
+
"settled",
|
|
783
|
+
"reversed",
|
|
784
|
+
"failed"
|
|
785
|
+
]);
|
|
786
|
+
var ACTIVITY_SOURCES = /* @__PURE__ */ new Set([
|
|
787
|
+
"paid-purchase",
|
|
788
|
+
"subscription",
|
|
789
|
+
"rewarded-activity",
|
|
790
|
+
"gameplay",
|
|
791
|
+
"system-adjustment",
|
|
792
|
+
"unknown"
|
|
793
|
+
]);
|
|
794
|
+
var SAFE_LABELS = /* @__PURE__ */ new Set([
|
|
795
|
+
"token-acquisition",
|
|
796
|
+
"token-spend",
|
|
797
|
+
"token-reversal",
|
|
798
|
+
"token-hold",
|
|
799
|
+
"token-activity-failed",
|
|
800
|
+
"token-system-adjustment",
|
|
801
|
+
"token-activity-unclassified"
|
|
802
|
+
]);
|
|
803
|
+
var SAFE_LABELS_BY_ACTIVITY_TYPE = {
|
|
804
|
+
acquisition: /* @__PURE__ */ new Set([
|
|
805
|
+
"token-acquisition",
|
|
806
|
+
"token-system-adjustment",
|
|
807
|
+
"token-activity-unclassified"
|
|
808
|
+
]),
|
|
809
|
+
spend: /* @__PURE__ */ new Set([
|
|
810
|
+
"token-spend",
|
|
811
|
+
"token-system-adjustment",
|
|
812
|
+
"token-activity-unclassified"
|
|
813
|
+
]),
|
|
814
|
+
reversal: /* @__PURE__ */ new Set([
|
|
815
|
+
"token-reversal",
|
|
816
|
+
"token-system-adjustment",
|
|
817
|
+
"token-activity-unclassified"
|
|
818
|
+
]),
|
|
819
|
+
hold: /* @__PURE__ */ new Set([
|
|
820
|
+
"token-hold",
|
|
821
|
+
"token-system-adjustment",
|
|
822
|
+
"token-activity-unclassified"
|
|
823
|
+
]),
|
|
824
|
+
failure: /* @__PURE__ */ new Set([
|
|
825
|
+
"token-activity-failed",
|
|
826
|
+
"token-activity-unclassified"
|
|
827
|
+
])
|
|
828
|
+
};
|
|
829
|
+
var ACTIVITY_SORTS = /* @__PURE__ */ new Set([
|
|
830
|
+
"occurred-at-desc",
|
|
831
|
+
"amount-absolute-desc"
|
|
832
|
+
]);
|
|
833
|
+
var PSEUDONYM_AUDIENCES = /* @__PURE__ */ new Set([
|
|
834
|
+
"admin-token-activity",
|
|
835
|
+
"mcp-token-activity"
|
|
836
|
+
]);
|
|
837
|
+
var BALANCE_PSEUDONYM_AUDIENCES = /* @__PURE__ */ new Set([
|
|
838
|
+
"admin-token-balances",
|
|
839
|
+
"mcp-token-balances"
|
|
840
|
+
]);
|
|
841
|
+
var WALLET_COMPONENTS = /* @__PURE__ */ new Set([
|
|
842
|
+
"household",
|
|
843
|
+
"personal",
|
|
844
|
+
"gameplay-allocation"
|
|
845
|
+
]);
|
|
846
|
+
var WALLET_STATUSES = /* @__PURE__ */ new Set([
|
|
847
|
+
"active",
|
|
848
|
+
"closed"
|
|
849
|
+
]);
|
|
850
|
+
var WALLET_BALANCE_SORTS = /* @__PURE__ */ new Set([
|
|
851
|
+
"available-desc",
|
|
852
|
+
"updated-at-desc"
|
|
853
|
+
]);
|
|
854
|
+
var TREND_GRANULARITIES = /* @__PURE__ */ new Set([
|
|
855
|
+
"hour",
|
|
856
|
+
"day"
|
|
857
|
+
]);
|
|
858
|
+
var ALIAS = /^[A-Za-z0-9_-]{16,96}$/u;
|
|
859
|
+
var OPAQUE_CURSOR = /^c1\.[A-Za-z0-9_-]{32,480}$/u;
|
|
860
|
+
var PSEUDONYM_VERSION = /^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/u;
|
|
861
|
+
var EXACT_STATISTIC_INTEGER = /^(?:0|-?[1-9][0-9]*)$/u;
|
|
862
|
+
var POSITIVE_UNSIGNED_INTEGER = /^[1-9][0-9]*$/u;
|
|
863
|
+
var MAXIMUM_STATISTIC_HALF_SUBUNITS = (TOKEN_SUBUNITS_MAX - TOKEN_SUBUNITS_MIN) * 2n;
|
|
864
|
+
var ANOMALY_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
865
|
+
"insufficient-history",
|
|
866
|
+
"privacy-suppressed-baseline"
|
|
867
|
+
]);
|
|
868
|
+
function assertPlainObject(value, label) {
|
|
869
|
+
economyAssert(
|
|
870
|
+
typeof value === "object" && value !== null && !Array.isArray(value),
|
|
871
|
+
"INVALID_CONTRACT",
|
|
872
|
+
`${label} must be an object`
|
|
873
|
+
);
|
|
874
|
+
const prototype = Object.getPrototypeOf(value);
|
|
875
|
+
economyAssert(
|
|
876
|
+
(prototype === Object.prototype || prototype === null) && !Reflect.has(value, "toJSON"),
|
|
877
|
+
"INVALID_CONTRACT",
|
|
878
|
+
`${label} must be a plain data object without serialization hooks`
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
function assertExactKeys(value, allowedKeys, label) {
|
|
882
|
+
assertPlainObject(value, label);
|
|
883
|
+
const allowed = new Set(allowedKeys);
|
|
884
|
+
const keys = Reflect.ownKeys(value);
|
|
885
|
+
economyAssert(
|
|
886
|
+
allowedKeys.every(
|
|
887
|
+
(key) => !Reflect.has(value, key) || Object.hasOwn(value, key)
|
|
888
|
+
) && keys.every((key) => {
|
|
889
|
+
if (typeof key !== "string" || !allowed.has(key)) {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
893
|
+
return descriptor !== void 0 && descriptor.enumerable && "value" in descriptor;
|
|
894
|
+
}),
|
|
895
|
+
"INVALID_CONTRACT",
|
|
896
|
+
`${label} contains an unsupported, identifying, or non-data property`
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
function assertAlias(value, label) {
|
|
900
|
+
economyAssert(
|
|
901
|
+
typeof value === "string" && ALIAS.test(value),
|
|
902
|
+
"INVALID_CONTRACT",
|
|
903
|
+
`${label} must be an opaque pseudonymous alias`
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
function assertOpaqueCursor(value) {
|
|
907
|
+
economyAssert(
|
|
908
|
+
typeof value === "string" && OPAQUE_CURSOR.test(value),
|
|
909
|
+
"INVALID_CONTRACT",
|
|
910
|
+
"Admin Token cursor must be a bounded confidentiality-protected opaque value"
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
function assertUniqueValues(values, allowed, label) {
|
|
914
|
+
economyAssert(
|
|
915
|
+
Array.isArray(values),
|
|
916
|
+
"INVALID_CONTRACT",
|
|
917
|
+
`${label} must be a list`
|
|
918
|
+
);
|
|
919
|
+
const unique = new Set(values);
|
|
920
|
+
economyAssert(
|
|
921
|
+
values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
|
|
922
|
+
"INVALID_CONTRACT",
|
|
923
|
+
`${label} must contain unique supported values`
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
function absolute(value) {
|
|
927
|
+
return value < 0n ? -value : value;
|
|
928
|
+
}
|
|
929
|
+
function compareTextDescending(left, right) {
|
|
930
|
+
if (left === right) {
|
|
931
|
+
return 0;
|
|
932
|
+
}
|
|
933
|
+
return left > right ? -1 : 1;
|
|
934
|
+
}
|
|
935
|
+
function assertReportingWindow(window, maximumDays = ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS) {
|
|
936
|
+
assertExactKeys(
|
|
937
|
+
window,
|
|
938
|
+
["fromInclusive", "toExclusive"],
|
|
939
|
+
"Admin Token reporting window"
|
|
940
|
+
);
|
|
941
|
+
const from = parseIsoTimestamp(window.fromInclusive);
|
|
942
|
+
const to = parseIsoTimestamp(window.toExclusive);
|
|
943
|
+
economyAssert(
|
|
944
|
+
from < to && to - from <= maximumDays * DAY_MILLISECONDS,
|
|
945
|
+
"INVALID_TIME_WINDOW",
|
|
946
|
+
`Admin Token reporting window must be positive and no longer than ${maximumDays} days`
|
|
947
|
+
);
|
|
948
|
+
return { from, to };
|
|
949
|
+
}
|
|
950
|
+
function createDefaultAdminTokenReportingWindow(asOf) {
|
|
951
|
+
const to = parseIsoTimestamp(asOf);
|
|
952
|
+
return {
|
|
953
|
+
fromInclusive: new Date(
|
|
954
|
+
to - ADMIN_TOKEN_DEFAULT_WINDOW_DAYS * DAY_MILLISECONDS
|
|
955
|
+
).toISOString(),
|
|
956
|
+
toExclusive: new Date(to).toISOString()
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
function assertNonNegativeTokenAmounts(amounts, label) {
|
|
960
|
+
economyAssert(
|
|
961
|
+
amounts.every((amount) => parseTokenSubunits(amount) >= 0n),
|
|
962
|
+
"INVALID_AMOUNT",
|
|
963
|
+
`${label} cannot contain a negative amount`
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
function assertPositiveAuthoritySequence(sequence, label) {
|
|
967
|
+
economyAssert(
|
|
968
|
+
typeof sequence === "string" && POSITIVE_UNSIGNED_INTEGER.test(sequence),
|
|
969
|
+
"INVALID_CONTRACT",
|
|
970
|
+
`${label} must be a canonical positive integer`
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
function assertAdminTokenEconomySummary(summary) {
|
|
974
|
+
assertExactKeys(
|
|
975
|
+
summary,
|
|
976
|
+
[
|
|
977
|
+
"schemaVersion",
|
|
978
|
+
"generatedAt",
|
|
979
|
+
"projectionAsOf",
|
|
980
|
+
"authoritySequence",
|
|
981
|
+
"walletCount",
|
|
982
|
+
"activeWalletCount",
|
|
983
|
+
"balances",
|
|
984
|
+
"lifetime",
|
|
985
|
+
"rawIdentifiersIncluded"
|
|
986
|
+
],
|
|
987
|
+
"Admin Token economy summary"
|
|
988
|
+
);
|
|
989
|
+
assertExactKeys(
|
|
990
|
+
summary.balances,
|
|
991
|
+
["schemaVersion", "available", "reserved", "held", "rewardProgress"],
|
|
992
|
+
"Admin Token aggregate balances"
|
|
993
|
+
);
|
|
994
|
+
assertExactKeys(
|
|
995
|
+
summary.lifetime,
|
|
996
|
+
[
|
|
997
|
+
"schemaVersion",
|
|
998
|
+
"bought",
|
|
999
|
+
"earned",
|
|
1000
|
+
"allocated",
|
|
1001
|
+
"reclaimed",
|
|
1002
|
+
"spent",
|
|
1003
|
+
"reversed"
|
|
1004
|
+
],
|
|
1005
|
+
"Admin Token aggregate lifetime"
|
|
1006
|
+
);
|
|
1007
|
+
economyAssert(
|
|
1008
|
+
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,
|
|
1009
|
+
"INVALID_CONTRACT",
|
|
1010
|
+
"Admin Token economy summary metadata is invalid"
|
|
1011
|
+
);
|
|
1012
|
+
const generatedAt = parseIsoTimestamp(summary.generatedAt);
|
|
1013
|
+
const projectionAsOf = parseIsoTimestamp(summary.projectionAsOf);
|
|
1014
|
+
economyAssert(
|
|
1015
|
+
projectionAsOf <= generatedAt,
|
|
1016
|
+
"INVALID_TIME_WINDOW",
|
|
1017
|
+
"Admin Token projection cannot be newer than its generated result"
|
|
1018
|
+
);
|
|
1019
|
+
assertPositiveAuthoritySequence(
|
|
1020
|
+
summary.authoritySequence,
|
|
1021
|
+
"Admin Token summary authority sequence"
|
|
1022
|
+
);
|
|
1023
|
+
assertNonNegativeTokenAmounts(
|
|
1024
|
+
[
|
|
1025
|
+
summary.balances.available,
|
|
1026
|
+
summary.balances.reserved,
|
|
1027
|
+
summary.balances.held,
|
|
1028
|
+
summary.balances.rewardProgress,
|
|
1029
|
+
summary.lifetime.bought,
|
|
1030
|
+
summary.lifetime.earned,
|
|
1031
|
+
summary.lifetime.allocated,
|
|
1032
|
+
summary.lifetime.reclaimed,
|
|
1033
|
+
summary.lifetime.spent,
|
|
1034
|
+
summary.lifetime.reversed
|
|
1035
|
+
],
|
|
1036
|
+
"Admin Token economy summary"
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
function assertAdminTokenWalletBalanceFilter(filter) {
|
|
1040
|
+
assertExactKeys(
|
|
1041
|
+
filter,
|
|
1042
|
+
["components", "statuses", "subjectAlias"],
|
|
1043
|
+
"Admin Token wallet balance filter"
|
|
1044
|
+
);
|
|
1045
|
+
if (filter.components !== void 0) {
|
|
1046
|
+
assertUniqueValues(
|
|
1047
|
+
filter.components,
|
|
1048
|
+
WALLET_COMPONENTS,
|
|
1049
|
+
"Admin Token wallet components"
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
if (filter.statuses !== void 0) {
|
|
1053
|
+
assertUniqueValues(
|
|
1054
|
+
filter.statuses,
|
|
1055
|
+
WALLET_STATUSES,
|
|
1056
|
+
"Admin Token wallet statuses"
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
if (filter.subjectAlias !== void 0) {
|
|
1060
|
+
assertAlias(filter.subjectAlias, "Wallet subject alias filter");
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
function sameWalletBalanceFilter(left, right) {
|
|
1064
|
+
if (left === void 0 || right === void 0) {
|
|
1065
|
+
return left === right;
|
|
1066
|
+
}
|
|
1067
|
+
return sameOptionalValues(left.components, right.components) && sameOptionalValues(left.statuses, right.statuses) && left.subjectAlias === right.subjectAlias;
|
|
1068
|
+
}
|
|
1069
|
+
function assertAdminTokenWalletBalanceCursorBinding(binding) {
|
|
1070
|
+
assertExactKeys(
|
|
1071
|
+
binding,
|
|
1072
|
+
[
|
|
1073
|
+
"schemaVersion",
|
|
1074
|
+
"sort",
|
|
1075
|
+
"filter",
|
|
1076
|
+
"audience",
|
|
1077
|
+
"pseudonymVersion"
|
|
1078
|
+
],
|
|
1079
|
+
"Admin Token wallet balance cursor binding"
|
|
1080
|
+
);
|
|
1081
|
+
economyAssert(
|
|
1082
|
+
binding.schemaVersion === ECONOMY_CONTRACT_VERSION && WALLET_BALANCE_SORTS.has(binding.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(binding.audience) && PSEUDONYM_VERSION.test(binding.pseudonymVersion),
|
|
1083
|
+
"INVALID_CONTRACT",
|
|
1084
|
+
"Unsupported Admin Token wallet balance cursor binding"
|
|
1085
|
+
);
|
|
1086
|
+
if (binding.filter !== void 0) {
|
|
1087
|
+
assertAdminTokenWalletBalanceFilter(binding.filter);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
function assertAdminTokenWalletBalancePageRequest(request) {
|
|
1091
|
+
assertExactKeys(
|
|
1092
|
+
request,
|
|
1093
|
+
[
|
|
1094
|
+
"schemaVersion",
|
|
1095
|
+
"limit",
|
|
1096
|
+
"cursor",
|
|
1097
|
+
"cursorBinding",
|
|
1098
|
+
"sort",
|
|
1099
|
+
"filter",
|
|
1100
|
+
"audience",
|
|
1101
|
+
"pseudonymVersion"
|
|
1102
|
+
],
|
|
1103
|
+
"Admin Token wallet balance request"
|
|
1104
|
+
);
|
|
1105
|
+
economyAssert(
|
|
1106
|
+
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),
|
|
1107
|
+
"INVALID_CONTRACT",
|
|
1108
|
+
"Unsupported or unbounded Admin Token wallet balance request"
|
|
1109
|
+
);
|
|
1110
|
+
if (request.filter !== void 0) {
|
|
1111
|
+
assertAdminTokenWalletBalanceFilter(request.filter);
|
|
1112
|
+
}
|
|
1113
|
+
economyAssert(
|
|
1114
|
+
request.cursor === void 0 === (request.cursorBinding === void 0),
|
|
1115
|
+
"INVALID_CONTRACT",
|
|
1116
|
+
"Admin Token wallet balance cursor and binding must be provided together"
|
|
1117
|
+
);
|
|
1118
|
+
if (request.cursor === void 0 || request.cursorBinding === void 0) {
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
assertOpaqueCursor(request.cursor);
|
|
1122
|
+
assertAdminTokenWalletBalanceCursorBinding(request.cursorBinding);
|
|
1123
|
+
economyAssert(
|
|
1124
|
+
request.cursorBinding.sort === request.sort && request.cursorBinding.audience === request.audience && request.cursorBinding.pseudonymVersion === request.pseudonymVersion && sameWalletBalanceFilter(request.cursorBinding.filter, request.filter),
|
|
1125
|
+
"INVALID_CONTRACT",
|
|
1126
|
+
"Admin Token wallet balance cursor is not bound to the normalized query"
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
function assertAdminTokenWalletBalanceEntry(entry) {
|
|
1130
|
+
assertExactKeys(
|
|
1131
|
+
entry,
|
|
1132
|
+
[
|
|
1133
|
+
"schemaVersion",
|
|
1134
|
+
"walletAlias",
|
|
1135
|
+
"subjectAlias",
|
|
1136
|
+
"component",
|
|
1137
|
+
"status",
|
|
1138
|
+
"available",
|
|
1139
|
+
"reserved",
|
|
1140
|
+
"held",
|
|
1141
|
+
"rewardProgress",
|
|
1142
|
+
"updatedAt",
|
|
1143
|
+
"authoritySequence"
|
|
1144
|
+
],
|
|
1145
|
+
"Admin Token wallet balance entry"
|
|
1146
|
+
);
|
|
1147
|
+
economyAssert(
|
|
1148
|
+
entry.schemaVersion === ECONOMY_CONTRACT_VERSION && WALLET_COMPONENTS.has(entry.component) && WALLET_STATUSES.has(entry.status),
|
|
1149
|
+
"INVALID_CONTRACT",
|
|
1150
|
+
"Unsupported Admin Token wallet balance entry"
|
|
1151
|
+
);
|
|
1152
|
+
assertAlias(entry.walletAlias, "Wallet alias");
|
|
1153
|
+
assertAlias(entry.subjectAlias, "Wallet subject alias");
|
|
1154
|
+
economyAssert(
|
|
1155
|
+
entry.walletAlias !== entry.subjectAlias,
|
|
1156
|
+
"INVALID_CONTRACT",
|
|
1157
|
+
"Wallet and subject aliases must use separate pseudonym domains"
|
|
1158
|
+
);
|
|
1159
|
+
assertNonNegativeTokenAmounts(
|
|
1160
|
+
[entry.available, entry.reserved, entry.held, entry.rewardProgress],
|
|
1161
|
+
"Admin Token wallet balance entry"
|
|
1162
|
+
);
|
|
1163
|
+
parseIsoTimestamp(entry.updatedAt);
|
|
1164
|
+
assertPositiveAuthoritySequence(
|
|
1165
|
+
entry.authoritySequence,
|
|
1166
|
+
"Admin Token wallet balance authority sequence"
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
function compareWalletBalanceEntries(left, right, sort) {
|
|
1170
|
+
if (sort === "available-desc") {
|
|
1171
|
+
const leftAvailable = parseTokenSubunits(left.available);
|
|
1172
|
+
const rightAvailable = parseTokenSubunits(right.available);
|
|
1173
|
+
if (leftAvailable !== rightAvailable) {
|
|
1174
|
+
return leftAvailable > rightAvailable ? -1 : 1;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const leftUpdatedAt = parseIsoTimestamp(left.updatedAt);
|
|
1178
|
+
const rightUpdatedAt = parseIsoTimestamp(right.updatedAt);
|
|
1179
|
+
if (leftUpdatedAt !== rightUpdatedAt) {
|
|
1180
|
+
return leftUpdatedAt > rightUpdatedAt ? -1 : 1;
|
|
1181
|
+
}
|
|
1182
|
+
return compareTextDescending(left.walletAlias, right.walletAlias);
|
|
1183
|
+
}
|
|
1184
|
+
function assertAdminTokenWalletBalancePage(page) {
|
|
1185
|
+
assertExactKeys(
|
|
1186
|
+
page,
|
|
1187
|
+
["schemaVersion", "entries", "hasMore", "nextCursor", "metadata"],
|
|
1188
|
+
"Admin Token wallet balance page"
|
|
1189
|
+
);
|
|
1190
|
+
assertExactKeys(
|
|
1191
|
+
page.metadata,
|
|
1192
|
+
[
|
|
1193
|
+
"schemaVersion",
|
|
1194
|
+
"generatedAt",
|
|
1195
|
+
"sort",
|
|
1196
|
+
"filter",
|
|
1197
|
+
"pageLimit",
|
|
1198
|
+
"audience",
|
|
1199
|
+
"pseudonymVersion",
|
|
1200
|
+
"rawIdentifiersIncluded"
|
|
1201
|
+
],
|
|
1202
|
+
"Admin Token wallet balance metadata"
|
|
1203
|
+
);
|
|
1204
|
+
economyAssert(
|
|
1205
|
+
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),
|
|
1206
|
+
"INVALID_CONTRACT",
|
|
1207
|
+
"Unsupported or unbounded Admin Token wallet balance page"
|
|
1208
|
+
);
|
|
1209
|
+
if (page.metadata.filter !== void 0) {
|
|
1210
|
+
assertAdminTokenWalletBalanceFilter(page.metadata.filter);
|
|
1211
|
+
}
|
|
1212
|
+
parseIsoTimestamp(page.metadata.generatedAt);
|
|
1213
|
+
if (page.nextCursor !== void 0) {
|
|
1214
|
+
assertOpaqueCursor(page.nextCursor);
|
|
1215
|
+
}
|
|
1216
|
+
const walletAliases = /* @__PURE__ */ new Set();
|
|
1217
|
+
let previous;
|
|
1218
|
+
for (const entry of page.entries) {
|
|
1219
|
+
assertAdminTokenWalletBalanceEntry(entry);
|
|
1220
|
+
const filter = page.metadata.filter;
|
|
1221
|
+
economyAssert(
|
|
1222
|
+
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),
|
|
1223
|
+
"INVALID_CONTRACT",
|
|
1224
|
+
"Admin Token wallet balance result contains an unrequested row"
|
|
1225
|
+
);
|
|
1226
|
+
economyAssert(
|
|
1227
|
+
!walletAliases.has(entry.walletAlias),
|
|
1228
|
+
"DUPLICATE_IDENTIFIER",
|
|
1229
|
+
"Admin Token wallet balance page cannot repeat a wallet alias"
|
|
1230
|
+
);
|
|
1231
|
+
walletAliases.add(entry.walletAlias);
|
|
1232
|
+
if (previous !== void 0) {
|
|
1233
|
+
economyAssert(
|
|
1234
|
+
compareWalletBalanceEntries(previous, entry, page.metadata.sort) < 0,
|
|
1235
|
+
"INVALID_CONTRACT",
|
|
1236
|
+
"Admin Token wallet balance page does not use its declared stable sort"
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
previous = entry;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function assertAdminTokenWalletBalancePageForRequest(page, request) {
|
|
1243
|
+
assertAdminTokenWalletBalancePageRequest(request);
|
|
1244
|
+
assertAdminTokenWalletBalancePage(page);
|
|
1245
|
+
economyAssert(
|
|
1246
|
+
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,
|
|
1247
|
+
"INVALID_CONTRACT",
|
|
1248
|
+
"Admin Token wallet balance result does not match its normalized request"
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
function assertAdminTokenActivityEntry(entry) {
|
|
1252
|
+
assertExactKeys(
|
|
1253
|
+
entry,
|
|
1254
|
+
[
|
|
1255
|
+
"schemaVersion",
|
|
1256
|
+
"occurredAt",
|
|
1257
|
+
"activityType",
|
|
1258
|
+
"status",
|
|
1259
|
+
"source",
|
|
1260
|
+
"amount",
|
|
1261
|
+
"safeLabel",
|
|
1262
|
+
"rowAlias",
|
|
1263
|
+
"subjectAlias"
|
|
1264
|
+
],
|
|
1265
|
+
"Admin Token activity entry"
|
|
1266
|
+
);
|
|
1267
|
+
economyAssert(
|
|
1268
|
+
entry.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_TYPES.has(entry.activityType) && ACTIVITY_STATUSES.has(entry.status) && ACTIVITY_SOURCES.has(entry.source),
|
|
1269
|
+
"INVALID_CONTRACT",
|
|
1270
|
+
"Unsupported Admin Token activity contract"
|
|
1271
|
+
);
|
|
1272
|
+
parseIsoTimestamp(entry.occurredAt);
|
|
1273
|
+
const amount = parseTokenSubunits(entry.amount);
|
|
1274
|
+
economyAssert(
|
|
1275
|
+
(amount !== 0n || entry.activityType === "failure") && (entry.activityType !== "acquisition" || amount > 0n) && (entry.activityType !== "spend" || amount < 0n),
|
|
1276
|
+
"INVALID_AMOUNT",
|
|
1277
|
+
"Admin Token activity amount has an invalid sign or zero value"
|
|
1278
|
+
);
|
|
1279
|
+
economyAssert(
|
|
1280
|
+
entry.activityType === "failure" === (entry.status === "failed"),
|
|
1281
|
+
"INVALID_CONTRACT",
|
|
1282
|
+
"Failed rows must use the failure activity type"
|
|
1283
|
+
);
|
|
1284
|
+
economyAssert(
|
|
1285
|
+
SAFE_LABELS.has(entry.safeLabel) && SAFE_LABELS_BY_ACTIVITY_TYPE[entry.activityType]?.has(entry.safeLabel) === true,
|
|
1286
|
+
"INVALID_CONTRACT",
|
|
1287
|
+
"Admin Token activity label must use the approved non-identifying allowlist"
|
|
1288
|
+
);
|
|
1289
|
+
assertAlias(entry.rowAlias, "Row alias");
|
|
1290
|
+
assertAlias(entry.subjectAlias, "Subject alias");
|
|
1291
|
+
economyAssert(
|
|
1292
|
+
entry.rowAlias !== entry.subjectAlias,
|
|
1293
|
+
"INVALID_CONTRACT",
|
|
1294
|
+
"Row and subject aliases must use separate pseudonym domains"
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
function assertAdminTokenActivityFilter(filter) {
|
|
1298
|
+
assertExactKeys(
|
|
1299
|
+
filter,
|
|
1300
|
+
[
|
|
1301
|
+
"activityTypes",
|
|
1302
|
+
"statuses",
|
|
1303
|
+
"sources",
|
|
1304
|
+
"subjectAlias"
|
|
1305
|
+
],
|
|
1306
|
+
"Admin Token activity filter"
|
|
1307
|
+
);
|
|
1308
|
+
if (filter.activityTypes !== void 0) {
|
|
1309
|
+
assertUniqueValues(
|
|
1310
|
+
filter.activityTypes,
|
|
1311
|
+
ACTIVITY_TYPES,
|
|
1312
|
+
"Admin Token activity types"
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
if (filter.statuses !== void 0) {
|
|
1316
|
+
assertUniqueValues(
|
|
1317
|
+
filter.statuses,
|
|
1318
|
+
ACTIVITY_STATUSES,
|
|
1319
|
+
"Admin Token activity statuses"
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
if (filter.sources !== void 0) {
|
|
1323
|
+
assertUniqueValues(
|
|
1324
|
+
filter.sources,
|
|
1325
|
+
ACTIVITY_SOURCES,
|
|
1326
|
+
"Admin Token activity sources"
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
if (filter.subjectAlias !== void 0) {
|
|
1330
|
+
assertAlias(filter.subjectAlias, "Subject alias filter");
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
function sameOptionalValues(left, right) {
|
|
1334
|
+
if (left === void 0 || right === void 0) {
|
|
1335
|
+
return left === right;
|
|
1336
|
+
}
|
|
1337
|
+
return left.length === right.length && left.every((value) => right.includes(value));
|
|
1338
|
+
}
|
|
1339
|
+
function sameActivityFilter(left, right) {
|
|
1340
|
+
if (left === void 0 || right === void 0) {
|
|
1341
|
+
return left === right;
|
|
1342
|
+
}
|
|
1343
|
+
return sameOptionalValues(left.activityTypes, right.activityTypes) && sameOptionalValues(left.statuses, right.statuses) && sameOptionalValues(left.sources, right.sources) && left.subjectAlias === right.subjectAlias;
|
|
1344
|
+
}
|
|
1345
|
+
function assertAdminTokenActivityCursorBinding(binding) {
|
|
1346
|
+
assertExactKeys(
|
|
1347
|
+
binding,
|
|
1348
|
+
[
|
|
1349
|
+
"schemaVersion",
|
|
1350
|
+
"sort",
|
|
1351
|
+
"window",
|
|
1352
|
+
"filter",
|
|
1353
|
+
"audience",
|
|
1354
|
+
"pseudonymVersion"
|
|
1355
|
+
],
|
|
1356
|
+
"Admin Token activity cursor binding"
|
|
1357
|
+
);
|
|
1358
|
+
economyAssert(
|
|
1359
|
+
binding.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_SORTS.has(binding.sort) && PSEUDONYM_AUDIENCES.has(binding.audience) && PSEUDONYM_VERSION.test(binding.pseudonymVersion),
|
|
1360
|
+
"INVALID_CONTRACT",
|
|
1361
|
+
"Unsupported Admin Token activity cursor binding"
|
|
1362
|
+
);
|
|
1363
|
+
assertReportingWindow(binding.window);
|
|
1364
|
+
if (binding.filter !== void 0) {
|
|
1365
|
+
assertAdminTokenActivityFilter(binding.filter);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
function assertAdminTokenActivityPageRequest(request) {
|
|
1369
|
+
assertExactKeys(
|
|
1370
|
+
request,
|
|
1371
|
+
[
|
|
1372
|
+
"schemaVersion",
|
|
1373
|
+
"limit",
|
|
1374
|
+
"cursor",
|
|
1375
|
+
"cursorBinding",
|
|
1376
|
+
"sort",
|
|
1377
|
+
"window",
|
|
1378
|
+
"filter",
|
|
1379
|
+
"audience",
|
|
1380
|
+
"pseudonymVersion"
|
|
1381
|
+
],
|
|
1382
|
+
"Admin Token activity request"
|
|
1383
|
+
);
|
|
1384
|
+
economyAssert(
|
|
1385
|
+
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),
|
|
1386
|
+
"INVALID_CONTRACT",
|
|
1387
|
+
"Unsupported or unbounded Admin Token activity request"
|
|
1388
|
+
);
|
|
1389
|
+
assertReportingWindow(request.window);
|
|
1390
|
+
if (request.filter !== void 0) {
|
|
1391
|
+
assertAdminTokenActivityFilter(request.filter);
|
|
1392
|
+
}
|
|
1393
|
+
economyAssert(
|
|
1394
|
+
request.cursor === void 0 === (request.cursorBinding === void 0),
|
|
1395
|
+
"INVALID_CONTRACT",
|
|
1396
|
+
"Admin Token activity cursor and trusted binding must be provided together"
|
|
1397
|
+
);
|
|
1398
|
+
if (request.cursor === void 0 || request.cursorBinding === void 0) {
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
assertOpaqueCursor(request.cursor);
|
|
1402
|
+
assertAdminTokenActivityCursorBinding(request.cursorBinding);
|
|
1403
|
+
economyAssert(
|
|
1404
|
+
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),
|
|
1405
|
+
"INVALID_CONTRACT",
|
|
1406
|
+
"Admin Token cursor is not bound to the normalized query"
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
function compareActivityEntries(left, right, sort) {
|
|
1410
|
+
if (sort === "amount-absolute-desc") {
|
|
1411
|
+
const leftAmount = absolute(parseTokenSubunits(left.amount));
|
|
1412
|
+
const rightAmount = absolute(parseTokenSubunits(right.amount));
|
|
1413
|
+
if (leftAmount !== rightAmount) {
|
|
1414
|
+
return leftAmount > rightAmount ? -1 : 1;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
const leftTime = parseIsoTimestamp(left.occurredAt);
|
|
1418
|
+
const rightTime = parseIsoTimestamp(right.occurredAt);
|
|
1419
|
+
if (leftTime !== rightTime) {
|
|
1420
|
+
return leftTime > rightTime ? -1 : 1;
|
|
1421
|
+
}
|
|
1422
|
+
return compareTextDescending(left.rowAlias, right.rowAlias);
|
|
1423
|
+
}
|
|
1424
|
+
function assertAdminTokenActivityPage(page) {
|
|
1425
|
+
assertExactKeys(
|
|
1426
|
+
page,
|
|
1427
|
+
["schemaVersion", "entries", "hasMore", "nextCursor", "metadata"],
|
|
1428
|
+
"Admin Token activity page"
|
|
1429
|
+
);
|
|
1430
|
+
assertExactKeys(
|
|
1431
|
+
page.metadata,
|
|
1432
|
+
[
|
|
1433
|
+
"schemaVersion",
|
|
1434
|
+
"generatedAt",
|
|
1435
|
+
"fromInclusive",
|
|
1436
|
+
"toExclusive",
|
|
1437
|
+
"sort",
|
|
1438
|
+
"filter",
|
|
1439
|
+
"pageLimit",
|
|
1440
|
+
"audience",
|
|
1441
|
+
"pseudonymVersion",
|
|
1442
|
+
"rawIdentifiersIncluded"
|
|
1443
|
+
],
|
|
1444
|
+
"Admin Token activity metadata"
|
|
1445
|
+
);
|
|
1446
|
+
economyAssert(
|
|
1447
|
+
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,
|
|
1448
|
+
"INVALID_CONTRACT",
|
|
1449
|
+
"Unsupported Admin Token activity result metadata"
|
|
1450
|
+
);
|
|
1451
|
+
const window = assertReportingWindow({
|
|
1452
|
+
fromInclusive: page.metadata.fromInclusive,
|
|
1453
|
+
toExclusive: page.metadata.toExclusive
|
|
1454
|
+
});
|
|
1455
|
+
if (page.metadata.filter !== void 0) {
|
|
1456
|
+
assertAdminTokenActivityFilter(page.metadata.filter);
|
|
1457
|
+
}
|
|
1458
|
+
parseIsoTimestamp(page.metadata.generatedAt);
|
|
1459
|
+
economyAssert(
|
|
1460
|
+
Array.isArray(page.entries) && page.entries.length <= page.metadata.pageLimit && page.hasMore === (page.nextCursor !== void 0) && (!page.hasMore || page.entries.length > 0),
|
|
1461
|
+
"INVALID_CONTRACT",
|
|
1462
|
+
"Admin Token activity page is unbounded or has inconsistent pagination"
|
|
1463
|
+
);
|
|
1464
|
+
if (page.nextCursor !== void 0) {
|
|
1465
|
+
assertOpaqueCursor(page.nextCursor);
|
|
1466
|
+
}
|
|
1467
|
+
const rowAliases = /* @__PURE__ */ new Set();
|
|
1468
|
+
let previous;
|
|
1469
|
+
for (const entry of page.entries) {
|
|
1470
|
+
assertAdminTokenActivityEntry(entry);
|
|
1471
|
+
const occurredAt = parseIsoTimestamp(entry.occurredAt);
|
|
1472
|
+
economyAssert(
|
|
1473
|
+
occurredAt >= window.from && occurredAt < window.to,
|
|
1474
|
+
"INVALID_TIME_WINDOW",
|
|
1475
|
+
"Admin Token activity falls outside the declared result window"
|
|
1476
|
+
);
|
|
1477
|
+
const filter = page.metadata.filter;
|
|
1478
|
+
economyAssert(
|
|
1479
|
+
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),
|
|
1480
|
+
"INVALID_CONTRACT",
|
|
1481
|
+
"Admin Token activity result contains a row outside its metadata filters"
|
|
1482
|
+
);
|
|
1483
|
+
economyAssert(
|
|
1484
|
+
!rowAliases.has(entry.rowAlias),
|
|
1485
|
+
"DUPLICATE_IDENTIFIER",
|
|
1486
|
+
"Admin Token activity page cannot repeat a row alias"
|
|
1487
|
+
);
|
|
1488
|
+
rowAliases.add(entry.rowAlias);
|
|
1489
|
+
if (previous !== void 0) {
|
|
1490
|
+
economyAssert(
|
|
1491
|
+
compareActivityEntries(previous, entry, page.metadata.sort) < 0,
|
|
1492
|
+
"INVALID_CONTRACT",
|
|
1493
|
+
"Admin Token activity page does not use its declared stable sort"
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
previous = entry;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
function assertAdminTokenActivityPageForRequest(page, request) {
|
|
1500
|
+
assertAdminTokenActivityPageRequest(request);
|
|
1501
|
+
assertAdminTokenActivityPage(page);
|
|
1502
|
+
economyAssert(
|
|
1503
|
+
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,
|
|
1504
|
+
"INVALID_CONTRACT",
|
|
1505
|
+
"Admin Token activity result metadata does not match its normalized request"
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
function assertAdminTokenTrendRequest(request) {
|
|
1509
|
+
assertExactKeys(
|
|
1510
|
+
request,
|
|
1511
|
+
["schemaVersion", "window", "granularity", "activityTypes"],
|
|
1512
|
+
"Admin Token trend request"
|
|
1513
|
+
);
|
|
1514
|
+
economyAssert(
|
|
1515
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && TREND_GRANULARITIES.has(request.granularity),
|
|
1516
|
+
"INVALID_CONTRACT",
|
|
1517
|
+
"Unsupported Admin Token trend request"
|
|
1518
|
+
);
|
|
1519
|
+
assertReportingWindow(
|
|
1520
|
+
request.window,
|
|
1521
|
+
request.granularity === "hour" ? ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS : ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS
|
|
1522
|
+
);
|
|
1523
|
+
if (request.activityTypes !== void 0) {
|
|
1524
|
+
assertUniqueValues(
|
|
1525
|
+
request.activityTypes,
|
|
1526
|
+
ACTIVITY_TYPES,
|
|
1527
|
+
"Admin Token trend activity types"
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
function medianHalfSubunits(values) {
|
|
1532
|
+
const ordered = [...values].sort(
|
|
1533
|
+
(left, right) => left === right ? 0 : left < right ? -1 : 1
|
|
1534
|
+
);
|
|
1535
|
+
const lower = ordered[Math.floor((ordered.length - 1) / 2)];
|
|
1536
|
+
const upper = ordered[Math.floor(ordered.length / 2)];
|
|
1537
|
+
economyAssert(
|
|
1538
|
+
lower !== void 0 && upper !== void 0,
|
|
1539
|
+
"INVALID_CONTRACT",
|
|
1540
|
+
"Median requires at least one value"
|
|
1541
|
+
);
|
|
1542
|
+
const sum = lower + upper;
|
|
1543
|
+
economyAssert(
|
|
1544
|
+
sum % 2n === 0n,
|
|
1545
|
+
"INVALID_AMOUNT",
|
|
1546
|
+
"Median cannot be represented in exact half TokenSubunits"
|
|
1547
|
+
);
|
|
1548
|
+
return sum / 2n;
|
|
1549
|
+
}
|
|
1550
|
+
function serializeExactStatistic(halfSubunits) {
|
|
1551
|
+
economyAssert(
|
|
1552
|
+
absolute(halfSubunits) <= MAXIMUM_STATISTIC_HALF_SUBUNITS,
|
|
1553
|
+
"AMOUNT_OUT_OF_RANGE",
|
|
1554
|
+
"Admin Token statistic exceeds its exact bounded representation"
|
|
1555
|
+
);
|
|
1556
|
+
if (halfSubunits % 2n === 0n) {
|
|
1557
|
+
return {
|
|
1558
|
+
numerator: (halfSubunits / 2n).toString(10),
|
|
1559
|
+
denominator: 1
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
return {
|
|
1563
|
+
numerator: halfSubunits.toString(10),
|
|
1564
|
+
denominator: 2
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
function parseExactStatistic(value, label) {
|
|
1568
|
+
assertExactKeys(value, ["numerator", "denominator"], label);
|
|
1569
|
+
economyAssert(
|
|
1570
|
+
typeof value.numerator === "string" && value.numerator.length <= 22 && EXACT_STATISTIC_INTEGER.test(value.numerator) && (value.denominator === 1 || value.denominator === 2),
|
|
1571
|
+
"INVALID_AMOUNT",
|
|
1572
|
+
`${label} must be an exact bounded rational TokenSubunit value`
|
|
1573
|
+
);
|
|
1574
|
+
const numerator = BigInt(value.numerator);
|
|
1575
|
+
economyAssert(
|
|
1576
|
+
value.denominator === 1 || numerator % 2n !== 0n,
|
|
1577
|
+
"INVALID_AMOUNT",
|
|
1578
|
+
`${label} must use a reduced exact representation`
|
|
1579
|
+
);
|
|
1580
|
+
const halfSubunits = numerator * BigInt(2 / value.denominator);
|
|
1581
|
+
economyAssert(
|
|
1582
|
+
absolute(halfSubunits) <= MAXIMUM_STATISTIC_HALF_SUBUNITS,
|
|
1583
|
+
"AMOUNT_OUT_OF_RANGE",
|
|
1584
|
+
`${label} exceeds its exact bounded representation`
|
|
1585
|
+
);
|
|
1586
|
+
return halfSubunits;
|
|
1587
|
+
}
|
|
1588
|
+
function classifyAnomaly(options) {
|
|
1589
|
+
if (options.absoluteDeltaHalfSubunits < options.minimumAbsoluteDeltaHalfSubunits) {
|
|
1590
|
+
return {
|
|
1591
|
+
status: "normal",
|
|
1592
|
+
explanationCode: "below-absolute-minimum"
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
if (options.medianAbsoluteDeviationHalfSubunits === 0n) {
|
|
1596
|
+
return options.absoluteDeltaHalfSubunits > 0n ? {
|
|
1597
|
+
status: "irregular-spike",
|
|
1598
|
+
explanationCode: "zero-mad-absolute-threshold-exceeded"
|
|
1599
|
+
} : {
|
|
1600
|
+
status: "normal",
|
|
1601
|
+
explanationCode: "within-baseline-variation"
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
const exceedsBaseline = options.absoluteDeltaHalfSubunits * 1000n >= options.medianAbsoluteDeviationHalfSubunits * BigInt(options.madMultiplierMilli);
|
|
1605
|
+
return exceedsBaseline ? {
|
|
1606
|
+
status: "irregular-spike",
|
|
1607
|
+
explanationCode: "median-mad-and-absolute-threshold-exceeded"
|
|
1608
|
+
} : {
|
|
1609
|
+
status: "normal",
|
|
1610
|
+
explanationCode: "within-baseline-variation"
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
function createAdminTokenAnomalyIndicator(input) {
|
|
1614
|
+
assertExactKeys(
|
|
1615
|
+
input,
|
|
1616
|
+
[
|
|
1617
|
+
"observedAmount",
|
|
1618
|
+
"baselineSamples",
|
|
1619
|
+
"minimumAbsoluteDelta",
|
|
1620
|
+
"madMultiplierMilli"
|
|
1621
|
+
],
|
|
1622
|
+
"Admin Token anomaly input"
|
|
1623
|
+
);
|
|
1624
|
+
economyAssert(
|
|
1625
|
+
Array.isArray(input.baselineSamples) && input.baselineSamples.length === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && Number.isSafeInteger(input.madMultiplierMilli) && input.madMultiplierMilli >= 1 && input.madMultiplierMilli <= 1e6,
|
|
1626
|
+
"INVALID_CONTRACT",
|
|
1627
|
+
"Admin Token anomaly input requires 28 baselines and a bounded fixed-point multiplier"
|
|
1628
|
+
);
|
|
1629
|
+
const observed = parseTokenSubunits(input.observedAmount);
|
|
1630
|
+
const baseline = input.baselineSamples.map((sample) => {
|
|
1631
|
+
assertExactKeys(
|
|
1632
|
+
sample,
|
|
1633
|
+
["amount", "distinctSubjects"],
|
|
1634
|
+
"Admin Token anomaly baseline sample"
|
|
1635
|
+
);
|
|
1636
|
+
economyAssert(
|
|
1637
|
+
Number.isSafeInteger(sample.distinctSubjects) && sample.distinctSubjects >= ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
1638
|
+
"INVALID_CONTRACT",
|
|
1639
|
+
"Admin Token anomaly baselines must exclude privacy-suppressed cohorts"
|
|
1640
|
+
);
|
|
1641
|
+
return parseTokenSubunits(sample.amount);
|
|
1642
|
+
});
|
|
1643
|
+
const minimum = parseTokenSubunits(input.minimumAbsoluteDelta);
|
|
1644
|
+
economyAssert(
|
|
1645
|
+
minimum > 0n,
|
|
1646
|
+
"INVALID_AMOUNT",
|
|
1647
|
+
"Admin Token anomaly absolute minimum must be positive"
|
|
1648
|
+
);
|
|
1649
|
+
const baselineHalfSubunits = baseline.map((amount) => amount * 2n);
|
|
1650
|
+
const medianHalf = medianHalfSubunits(baselineHalfSubunits);
|
|
1651
|
+
const medianAbsoluteDeviationHalf = medianHalfSubunits(
|
|
1652
|
+
baselineHalfSubunits.map((amount) => absolute(amount - medianHalf))
|
|
1653
|
+
);
|
|
1654
|
+
const deviationHalf = observed * 2n - medianHalf;
|
|
1655
|
+
const classification = classifyAnomaly({
|
|
1656
|
+
absoluteDeltaHalfSubunits: absolute(deviationHalf),
|
|
1657
|
+
medianAbsoluteDeviationHalfSubunits: medianAbsoluteDeviationHalf,
|
|
1658
|
+
minimumAbsoluteDeltaHalfSubunits: minimum * 2n,
|
|
1659
|
+
madMultiplierMilli: input.madMultiplierMilli
|
|
1660
|
+
});
|
|
1661
|
+
return {
|
|
1662
|
+
method: "same-window-median-mad-v1",
|
|
1663
|
+
...classification,
|
|
1664
|
+
baselineWindowCount: ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1665
|
+
medianAmount: serializeExactStatistic(medianHalf),
|
|
1666
|
+
medianAbsoluteDeviation: serializeExactStatistic(medianAbsoluteDeviationHalf),
|
|
1667
|
+
minimumAbsoluteDelta: input.minimumAbsoluteDelta,
|
|
1668
|
+
deviationFromMedian: serializeExactStatistic(deviationHalf),
|
|
1669
|
+
madMultiplierMilli: input.madMultiplierMilli
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
function createAdminTokenAnomalyUnavailable(input) {
|
|
1673
|
+
assertExactKeys(
|
|
1674
|
+
input,
|
|
1675
|
+
["reason", "eligibleBaselineWindowCount"],
|
|
1676
|
+
"Unavailable Admin Token anomaly input"
|
|
1677
|
+
);
|
|
1678
|
+
economyAssert(
|
|
1679
|
+
ANOMALY_UNAVAILABLE_REASONS.has(input.reason) && Number.isSafeInteger(input.eligibleBaselineWindowCount) && input.eligibleBaselineWindowCount >= 0 && input.eligibleBaselineWindowCount < ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1680
|
+
"INVALID_CONTRACT",
|
|
1681
|
+
"Unavailable Admin Token anomaly requires a bounded reason and eligible baseline count"
|
|
1682
|
+
);
|
|
1683
|
+
return {
|
|
1684
|
+
method: "same-window-median-mad-v1",
|
|
1685
|
+
status: "unavailable",
|
|
1686
|
+
reason: input.reason,
|
|
1687
|
+
eligibleBaselineWindowCount: input.eligibleBaselineWindowCount,
|
|
1688
|
+
requiredBaselineWindowCount: ADMIN_TOKEN_ANOMALY_BASELINE_DAYS
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
function assertAdminTokenAnomalyIndicator(anomaly, observedAmount) {
|
|
1692
|
+
assertExactKeys(
|
|
1693
|
+
anomaly,
|
|
1694
|
+
[
|
|
1695
|
+
"method",
|
|
1696
|
+
"status",
|
|
1697
|
+
"baselineWindowCount",
|
|
1698
|
+
"medianAmount",
|
|
1699
|
+
"medianAbsoluteDeviation",
|
|
1700
|
+
"minimumAbsoluteDelta",
|
|
1701
|
+
"deviationFromMedian",
|
|
1702
|
+
"madMultiplierMilli",
|
|
1703
|
+
"explanationCode"
|
|
1704
|
+
],
|
|
1705
|
+
"Admin Token anomaly indicator"
|
|
1706
|
+
);
|
|
1707
|
+
const observed = parseTokenSubunits(observedAmount);
|
|
1708
|
+
const medianHalf = parseExactStatistic(
|
|
1709
|
+
anomaly.medianAmount,
|
|
1710
|
+
"Admin Token anomaly median"
|
|
1711
|
+
);
|
|
1712
|
+
const madHalf = parseExactStatistic(
|
|
1713
|
+
anomaly.medianAbsoluteDeviation,
|
|
1714
|
+
"Admin Token anomaly median absolute deviation"
|
|
1715
|
+
);
|
|
1716
|
+
const minimum = parseTokenSubunits(anomaly.minimumAbsoluteDelta);
|
|
1717
|
+
const deviationHalf = parseExactStatistic(
|
|
1718
|
+
anomaly.deviationFromMedian,
|
|
1719
|
+
"Admin Token anomaly deviation"
|
|
1720
|
+
);
|
|
1721
|
+
economyAssert(
|
|
1722
|
+
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,
|
|
1723
|
+
"INVALID_CONTRACT",
|
|
1724
|
+
"Admin Token anomaly arithmetic or method is invalid"
|
|
1725
|
+
);
|
|
1726
|
+
const expected = classifyAnomaly({
|
|
1727
|
+
absoluteDeltaHalfSubunits: absolute(deviationHalf),
|
|
1728
|
+
medianAbsoluteDeviationHalfSubunits: madHalf,
|
|
1729
|
+
minimumAbsoluteDeltaHalfSubunits: minimum * 2n,
|
|
1730
|
+
madMultiplierMilli: anomaly.madMultiplierMilli
|
|
1731
|
+
});
|
|
1732
|
+
economyAssert(
|
|
1733
|
+
anomaly.status === expected.status && anomaly.explanationCode === expected.explanationCode,
|
|
1734
|
+
"INVALID_CONTRACT",
|
|
1735
|
+
"Admin Token anomaly classification is inconsistent with its explanation"
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
function assertAdminTokenAnomalyUnavailable(anomaly) {
|
|
1739
|
+
assertExactKeys(
|
|
1740
|
+
anomaly,
|
|
1741
|
+
[
|
|
1742
|
+
"method",
|
|
1743
|
+
"status",
|
|
1744
|
+
"reason",
|
|
1745
|
+
"eligibleBaselineWindowCount",
|
|
1746
|
+
"requiredBaselineWindowCount"
|
|
1747
|
+
],
|
|
1748
|
+
"Unavailable Admin Token anomaly"
|
|
1749
|
+
);
|
|
1750
|
+
economyAssert(
|
|
1751
|
+
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,
|
|
1752
|
+
"INVALID_CONTRACT",
|
|
1753
|
+
"Unavailable Admin Token anomaly metadata is invalid"
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
function assertTrendBucketAlignment(start, end, granularity) {
|
|
1757
|
+
const expectedDuration = granularity === "hour" ? HOUR_MILLISECONDS : DAY_MILLISECONDS;
|
|
1758
|
+
const date = new Date(start);
|
|
1759
|
+
const aligned = date.getUTCMinutes() === 0 && date.getUTCSeconds() === 0 && date.getUTCMilliseconds() === 0 && (granularity === "hour" || date.getUTCHours() === 0);
|
|
1760
|
+
economyAssert(
|
|
1761
|
+
aligned && end - start === expectedDuration,
|
|
1762
|
+
"INVALID_TIME_WINDOW",
|
|
1763
|
+
"Admin Token trend bucket is not aligned to its declared granularity"
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
function assertTrendAggregate(aggregate) {
|
|
1767
|
+
assertPlainObject(aggregate, "Admin Token trend aggregate");
|
|
1768
|
+
if (aggregate.visibility === "suppressed") {
|
|
1769
|
+
assertExactKeys(
|
|
1770
|
+
aggregate,
|
|
1771
|
+
["visibility", "reason", "threshold"],
|
|
1772
|
+
"Suppressed Admin Token trend aggregate"
|
|
1773
|
+
);
|
|
1774
|
+
economyAssert(
|
|
1775
|
+
aggregate.reason === "cohort-below-minimum" && aggregate.threshold === ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
1776
|
+
"INVALID_CONTRACT",
|
|
1777
|
+
"Suppressed Admin Token trend aggregate has invalid privacy metadata"
|
|
1778
|
+
);
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
assertExactKeys(
|
|
1782
|
+
aggregate,
|
|
1783
|
+
[
|
|
1784
|
+
"visibility",
|
|
1785
|
+
"distinctSubjects",
|
|
1786
|
+
"activityCount",
|
|
1787
|
+
"signedAmount"
|
|
1788
|
+
],
|
|
1789
|
+
"Reported Admin Token trend aggregate"
|
|
1790
|
+
);
|
|
1791
|
+
parseTokenSubunits(aggregate.signedAmount);
|
|
1792
|
+
economyAssert(
|
|
1793
|
+
aggregate.visibility === "reported" && Number.isSafeInteger(aggregate.distinctSubjects) && aggregate.distinctSubjects >= ADMIN_TOKEN_MINIMUM_COHORT_SIZE && Number.isSafeInteger(aggregate.activityCount) && aggregate.activityCount >= aggregate.distinctSubjects,
|
|
1794
|
+
"INVALID_CONTRACT",
|
|
1795
|
+
"Reported Admin Token trend aggregate is invalid or below the privacy threshold"
|
|
1796
|
+
);
|
|
1797
|
+
}
|
|
1798
|
+
function assertAdminTokenTrendResult(result) {
|
|
1799
|
+
assertExactKeys(
|
|
1800
|
+
result,
|
|
1801
|
+
["schemaVersion", "series", "metadata"],
|
|
1802
|
+
"Admin Token trend result"
|
|
1803
|
+
);
|
|
1804
|
+
assertExactKeys(
|
|
1805
|
+
result.metadata,
|
|
1806
|
+
[
|
|
1807
|
+
"schemaVersion",
|
|
1808
|
+
"generatedAt",
|
|
1809
|
+
"fromInclusive",
|
|
1810
|
+
"toExclusive",
|
|
1811
|
+
"granularity",
|
|
1812
|
+
"activityTypes",
|
|
1813
|
+
"minimumCohortSize",
|
|
1814
|
+
"anomalyBaselineDays",
|
|
1815
|
+
"rawIdentifiersIncluded"
|
|
1816
|
+
],
|
|
1817
|
+
"Admin Token trend metadata"
|
|
1818
|
+
);
|
|
1819
|
+
economyAssert(
|
|
1820
|
+
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,
|
|
1821
|
+
"INVALID_CONTRACT",
|
|
1822
|
+
"Unsupported or unbounded Admin Token trend result"
|
|
1823
|
+
);
|
|
1824
|
+
assertUniqueValues(
|
|
1825
|
+
result.metadata.activityTypes,
|
|
1826
|
+
ACTIVITY_TYPES,
|
|
1827
|
+
"Admin Token trend result activity types"
|
|
1828
|
+
);
|
|
1829
|
+
const window = assertReportingWindow(
|
|
1830
|
+
{
|
|
1831
|
+
fromInclusive: result.metadata.fromInclusive,
|
|
1832
|
+
toExclusive: result.metadata.toExclusive
|
|
1833
|
+
},
|
|
1834
|
+
result.metadata.granularity === "hour" ? ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS : ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS
|
|
1835
|
+
);
|
|
1836
|
+
parseIsoTimestamp(result.metadata.generatedAt);
|
|
1837
|
+
const pointKeys = /* @__PURE__ */ new Set();
|
|
1838
|
+
let previousKey;
|
|
1839
|
+
for (const point of result.series) {
|
|
1840
|
+
assertExactKeys(
|
|
1841
|
+
point,
|
|
1842
|
+
[
|
|
1843
|
+
"schemaVersion",
|
|
1844
|
+
"bucketStart",
|
|
1845
|
+
"bucketEnd",
|
|
1846
|
+
"activityType",
|
|
1847
|
+
"aggregate",
|
|
1848
|
+
"anomaly"
|
|
1849
|
+
],
|
|
1850
|
+
"Admin Token trend point"
|
|
1851
|
+
);
|
|
1852
|
+
economyAssert(
|
|
1853
|
+
point.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_TYPES.has(point.activityType) && result.metadata.activityTypes.includes(point.activityType),
|
|
1854
|
+
"INVALID_CONTRACT",
|
|
1855
|
+
"Unsupported Admin Token trend point"
|
|
1856
|
+
);
|
|
1857
|
+
const start = parseIsoTimestamp(point.bucketStart);
|
|
1858
|
+
const end = parseIsoTimestamp(point.bucketEnd);
|
|
1859
|
+
economyAssert(
|
|
1860
|
+
start >= window.from && end <= window.to,
|
|
1861
|
+
"INVALID_TIME_WINDOW",
|
|
1862
|
+
"Admin Token trend bucket falls outside the declared result window"
|
|
1863
|
+
);
|
|
1864
|
+
assertTrendBucketAlignment(start, end, result.metadata.granularity);
|
|
1865
|
+
assertTrendAggregate(point.aggregate);
|
|
1866
|
+
if (point.aggregate.visibility === "suppressed") {
|
|
1867
|
+
economyAssert(
|
|
1868
|
+
point.anomaly === void 0,
|
|
1869
|
+
"INVALID_CONTRACT",
|
|
1870
|
+
"Suppressed Admin Token cohorts cannot include anomaly details"
|
|
1871
|
+
);
|
|
1872
|
+
} else {
|
|
1873
|
+
economyAssert(
|
|
1874
|
+
point.anomaly !== void 0,
|
|
1875
|
+
"INVALID_CONTRACT",
|
|
1876
|
+
"Reported Admin Token cohorts require an anomaly result"
|
|
1877
|
+
);
|
|
1878
|
+
if (point.anomaly.status === "unavailable") {
|
|
1879
|
+
assertAdminTokenAnomalyUnavailable(point.anomaly);
|
|
1880
|
+
} else {
|
|
1881
|
+
assertAdminTokenAnomalyIndicator(
|
|
1882
|
+
point.anomaly,
|
|
1883
|
+
point.aggregate.signedAmount
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
const key = `${point.bucketStart}\0${point.activityType}`;
|
|
1888
|
+
economyAssert(
|
|
1889
|
+
!pointKeys.has(key) && (previousKey === void 0 || previousKey < key),
|
|
1890
|
+
"DUPLICATE_IDENTIFIER",
|
|
1891
|
+
"Admin Token trend points must be unique and stably ordered"
|
|
1892
|
+
);
|
|
1893
|
+
pointKeys.add(key);
|
|
1894
|
+
previousKey = key;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
function assertAdminTokenTrendResultForRequest(result, request) {
|
|
1898
|
+
assertAdminTokenTrendRequest(request);
|
|
1899
|
+
assertAdminTokenTrendResult(result);
|
|
1900
|
+
const requestedActivityTypes = request.activityTypes ?? [...ACTIVITY_TYPES];
|
|
1901
|
+
economyAssert(
|
|
1902
|
+
result.metadata.fromInclusive === request.window.fromInclusive && result.metadata.toExclusive === request.window.toExclusive && result.metadata.granularity === request.granularity && sameOptionalValues(
|
|
1903
|
+
result.metadata.activityTypes,
|
|
1904
|
+
requestedActivityTypes
|
|
1905
|
+
),
|
|
1906
|
+
"INVALID_CONTRACT",
|
|
1907
|
+
"Admin Token trend result metadata does not match its normalized request"
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
731
1911
|
// src/allocations.ts
|
|
732
1912
|
function assertWholePositive(amount, label) {
|
|
733
1913
|
const parsed = parseTokenSubunits(amount);
|
|
@@ -1064,7 +2244,7 @@ var COMMAND_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
1064
2244
|
"acceptedRegion",
|
|
1065
2245
|
"writerFencingToken"
|
|
1066
2246
|
]);
|
|
1067
|
-
function
|
|
2247
|
+
function assertExactKeys2(value, allowedKeys, label) {
|
|
1068
2248
|
economyAssert(
|
|
1069
2249
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
1070
2250
|
"INVALID_CONTRACT",
|
|
@@ -1108,7 +2288,7 @@ function assertRelationshipContext(relationshipId, authorizationVersion) {
|
|
|
1108
2288
|
);
|
|
1109
2289
|
}
|
|
1110
2290
|
function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
|
|
1111
|
-
|
|
2291
|
+
assertExactKeys2(
|
|
1112
2292
|
fingerprint,
|
|
1113
2293
|
/* @__PURE__ */ new Set([
|
|
1114
2294
|
"schemaVersion",
|
|
@@ -1133,7 +2313,7 @@ function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
|
|
|
1133
2313
|
);
|
|
1134
2314
|
}
|
|
1135
2315
|
function assertEconomyAuthorizationEvidence(evidence) {
|
|
1136
|
-
|
|
2316
|
+
assertExactKeys2(
|
|
1137
2317
|
evidence,
|
|
1138
2318
|
/* @__PURE__ */ new Set([
|
|
1139
2319
|
"schemaVersion",
|
|
@@ -1170,7 +2350,7 @@ function assertEconomyAuthorizationEvidence(evidence) {
|
|
|
1170
2350
|
);
|
|
1171
2351
|
}
|
|
1172
2352
|
function assertCausationReference(causation) {
|
|
1173
|
-
|
|
2353
|
+
assertExactKeys2(
|
|
1174
2354
|
causation,
|
|
1175
2355
|
/* @__PURE__ */ new Set(["schemaVersion", "kind", "causationId"]),
|
|
1176
2356
|
"Economy causation reference"
|
|
@@ -1225,7 +2405,7 @@ function assertCommandSourcePrincipal(envelope) {
|
|
|
1225
2405
|
}
|
|
1226
2406
|
}
|
|
1227
2407
|
function assertAuditedEconomyCommandEnvelope(envelope) {
|
|
1228
|
-
|
|
2408
|
+
assertExactKeys2(
|
|
1229
2409
|
envelope,
|
|
1230
2410
|
COMMAND_ENVELOPE_KEYS,
|
|
1231
2411
|
"Audited economy command envelope"
|
|
@@ -1291,7 +2471,7 @@ function assertAuditedEconomyCommandEnvelope(envelope) {
|
|
|
1291
2471
|
);
|
|
1292
2472
|
}
|
|
1293
2473
|
function assertEconomyProviderEvidenceHash(evidence) {
|
|
1294
|
-
|
|
2474
|
+
assertExactKeys2(
|
|
1295
2475
|
evidence,
|
|
1296
2476
|
/* @__PURE__ */ new Set([
|
|
1297
2477
|
"schemaVersion",
|
|
@@ -1362,7 +2542,7 @@ function assertEconomyProviderEvidenceHash(evidence) {
|
|
|
1362
2542
|
}
|
|
1363
2543
|
}
|
|
1364
2544
|
function assertEconomyEncryptedOperationalHandleBinding(binding) {
|
|
1365
|
-
|
|
2545
|
+
assertExactKeys2(
|
|
1366
2546
|
binding,
|
|
1367
2547
|
/* @__PURE__ */ new Set([
|
|
1368
2548
|
"schemaVersion",
|
|
@@ -1397,7 +2577,7 @@ function assertEconomyEncryptedOperationalHandleBinding(binding) {
|
|
|
1397
2577
|
parseIsoTimestamp(binding.createdAt);
|
|
1398
2578
|
}
|
|
1399
2579
|
function assertEvidenceRecordReference(reference) {
|
|
1400
|
-
|
|
2580
|
+
assertExactKeys2(
|
|
1401
2581
|
reference,
|
|
1402
2582
|
/* @__PURE__ */ new Set(["schemaVersion", "recordId", "contentHash"]),
|
|
1403
2583
|
"Evidence record reference"
|
|
@@ -1428,7 +2608,7 @@ function assertUniqueSortedReferences(references, label) {
|
|
|
1428
2608
|
}
|
|
1429
2609
|
}
|
|
1430
2610
|
function assertEconomyProviderEvidenceManifest(manifest) {
|
|
1431
|
-
|
|
2611
|
+
assertExactKeys2(
|
|
1432
2612
|
manifest,
|
|
1433
2613
|
/* @__PURE__ */ new Set([
|
|
1434
2614
|
"schemaVersion",
|
|
@@ -1470,7 +2650,7 @@ function assertEconomyProviderEvidenceManifest(manifest) {
|
|
|
1470
2650
|
parseIsoTimestamp(manifest.createdAt);
|
|
1471
2651
|
}
|
|
1472
2652
|
function assertEconomyAcceptedCommandReceipt(receipt) {
|
|
1473
|
-
|
|
2653
|
+
assertExactKeys2(
|
|
1474
2654
|
receipt,
|
|
1475
2655
|
/* @__PURE__ */ new Set([
|
|
1476
2656
|
"schemaVersion",
|
|
@@ -1494,7 +2674,7 @@ function assertEconomyAcceptedCommandReceipt(receipt) {
|
|
|
1494
2674
|
parseIsoTimestamp(receipt.acceptedAt);
|
|
1495
2675
|
}
|
|
1496
2676
|
function assertEconomyCommandResultReceipt(receipt) {
|
|
1497
|
-
|
|
2677
|
+
assertExactKeys2(
|
|
1498
2678
|
receipt,
|
|
1499
2679
|
/* @__PURE__ */ new Set([
|
|
1500
2680
|
"schemaVersion",
|
|
@@ -1551,7 +2731,7 @@ function assertEconomyCommandResultReceipt(receipt) {
|
|
|
1551
2731
|
}
|
|
1552
2732
|
}
|
|
1553
2733
|
function assertEconomyAuditedIdempotencyScope(scope) {
|
|
1554
|
-
|
|
2734
|
+
assertExactKeys2(
|
|
1555
2735
|
scope,
|
|
1556
2736
|
/* @__PURE__ */ new Set([
|
|
1557
2737
|
"schemaVersion",
|
|
@@ -1582,7 +2762,7 @@ function assertEconomyAuditedIdempotencyScope(scope) {
|
|
|
1582
2762
|
);
|
|
1583
2763
|
}
|
|
1584
2764
|
function assertEconomyAuditedIdempotencyResult(result) {
|
|
1585
|
-
|
|
2765
|
+
assertExactKeys2(
|
|
1586
2766
|
result,
|
|
1587
2767
|
/* @__PURE__ */ new Set([
|
|
1588
2768
|
"schemaVersion",
|
|
@@ -1873,7 +3053,7 @@ var MANIFEST_KEYS = /* @__PURE__ */ new Set([
|
|
|
1873
3053
|
"recordReferences",
|
|
1874
3054
|
"committedAt"
|
|
1875
3055
|
]);
|
|
1876
|
-
function
|
|
3056
|
+
function assertExactKeys3(value, allowedKeys, label) {
|
|
1877
3057
|
economyAssert(
|
|
1878
3058
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
1879
3059
|
"INVALID_CONTRACT",
|
|
@@ -1911,7 +3091,7 @@ function referenceOrder(left, right) {
|
|
|
1911
3091
|
return byKind === 0 ? compareUnicodeCodeUnits(left.recordId, right.recordId) : byKind;
|
|
1912
3092
|
}
|
|
1913
3093
|
function assertEconomyAuthorityRecordReference(reference) {
|
|
1914
|
-
|
|
3094
|
+
assertExactKeys3(
|
|
1915
3095
|
reference,
|
|
1916
3096
|
/* @__PURE__ */ new Set([
|
|
1917
3097
|
"schemaVersion",
|
|
@@ -2075,7 +3255,7 @@ function assertCommitAllowedInState(manifest) {
|
|
|
2075
3255
|
}
|
|
2076
3256
|
}
|
|
2077
3257
|
function assertEconomyAuthorityCommitManifest(manifest) {
|
|
2078
|
-
|
|
3258
|
+
assertExactKeys3(manifest, MANIFEST_KEYS, "Authority commit manifest");
|
|
2079
3259
|
economyAssert(
|
|
2080
3260
|
manifest.schemaVersion === ECONOMY_CONTRACT_VERSION && COMMIT_KINDS.has(manifest.commitKind) && AUTHORITY_STATES.has(manifest.authorityStateBefore) && AUTHORITY_STATES.has(manifest.authorityStateAfter),
|
|
2081
3261
|
"INVALID_CONTRACT",
|
|
@@ -2122,7 +3302,7 @@ function assertEconomyAuthorityCommitManifest(manifest) {
|
|
|
2122
3302
|
parseIsoTimestamp(manifest.committedAt);
|
|
2123
3303
|
}
|
|
2124
3304
|
function assertEconomyAuthorityHead(head) {
|
|
2125
|
-
|
|
3305
|
+
assertExactKeys3(head, HEAD_KEYS, "Economy authority head");
|
|
2126
3306
|
economyAssert(
|
|
2127
3307
|
head.schemaVersion === ECONOMY_CONTRACT_VERSION && AUTHORITY_STATES.has(head.state),
|
|
2128
3308
|
"INVALID_CONTRACT",
|
|
@@ -2181,7 +3361,7 @@ function advanceEconomyAuthorityHead(head, manifest, manifestCanonicalHash) {
|
|
|
2181
3361
|
};
|
|
2182
3362
|
}
|
|
2183
3363
|
function assertEconomyIntegrityVerificationReceipt(receipt) {
|
|
2184
|
-
|
|
3364
|
+
assertExactKeys3(
|
|
2185
3365
|
receipt,
|
|
2186
3366
|
/* @__PURE__ */ new Set([
|
|
2187
3367
|
"schemaVersion",
|
|
@@ -2327,7 +3507,7 @@ function assertEconomyIntegrityVerificationReceipt(receipt) {
|
|
|
2327
3507
|
parseIsoTimestamp(receipt.verifiedAt);
|
|
2328
3508
|
}
|
|
2329
3509
|
function assertEconomyIntegrityAnchorManifest(manifest) {
|
|
2330
|
-
|
|
3510
|
+
assertExactKeys3(
|
|
2331
3511
|
manifest,
|
|
2332
3512
|
/* @__PURE__ */ new Set([
|
|
2333
3513
|
"schemaVersion",
|
|
@@ -2489,7 +3669,7 @@ function sortEconomyAuthorityRecordReferences(references) {
|
|
|
2489
3669
|
}
|
|
2490
3670
|
|
|
2491
3671
|
// src/ledger.ts
|
|
2492
|
-
var
|
|
3672
|
+
var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
|
|
2493
3673
|
"purchase",
|
|
2494
3674
|
"subscription",
|
|
2495
3675
|
"rewarded-ad",
|
|
@@ -2506,14 +3686,14 @@ var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
|
2506
3686
|
"event",
|
|
2507
3687
|
"competition"
|
|
2508
3688
|
]);
|
|
2509
|
-
var
|
|
3689
|
+
var ACTIVITY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
2510
3690
|
"pending",
|
|
2511
3691
|
"held",
|
|
2512
3692
|
"settled",
|
|
2513
3693
|
"reversed",
|
|
2514
3694
|
"failed"
|
|
2515
3695
|
]);
|
|
2516
|
-
var
|
|
3696
|
+
var ACTIVITY_SOURCES2 = /* @__PURE__ */ new Set([
|
|
2517
3697
|
"shopify",
|
|
2518
3698
|
"ayet",
|
|
2519
3699
|
"bitlabs",
|
|
@@ -2543,7 +3723,7 @@ function assertActivityEntry(entry) {
|
|
|
2543
3723
|
);
|
|
2544
3724
|
assertEconomyIdentifier(entry.transactionId, "transactionId");
|
|
2545
3725
|
economyAssert(
|
|
2546
|
-
|
|
3726
|
+
ACTIVITY_TYPES2.has(entry.activityType) && ACTIVITY_STATUSES2.has(entry.status) && ACTIVITY_SOURCES2.has(entry.source),
|
|
2547
3727
|
"INVALID_CONTRACT",
|
|
2548
3728
|
"Activity type, status, or source is unsupported"
|
|
2549
3729
|
);
|
|
@@ -2581,7 +3761,7 @@ function assertBalancedTransaction(transaction) {
|
|
|
2581
3761
|
assertEconomyIdentifier(transaction.transactionId, "transactionId");
|
|
2582
3762
|
assertEconomyIdentifier(transaction.idempotencyKey, "idempotencyKey");
|
|
2583
3763
|
economyAssert(
|
|
2584
|
-
|
|
3764
|
+
ACTIVITY_TYPES2.has(transaction.activityType) && ACTIVITY_STATUSES2.has(transaction.status),
|
|
2585
3765
|
"INVALID_CONTRACT",
|
|
2586
3766
|
"Transaction activity type or status is unsupported"
|
|
2587
3767
|
);
|
|
@@ -4546,6 +5726,341 @@ function assertDistinctAdjustmentApproval(request) {
|
|
|
4546
5726
|
}
|
|
4547
5727
|
}
|
|
4548
5728
|
|
|
5729
|
+
// src/operator-adjustments.ts
|
|
5730
|
+
var PREVIEW_KEYS = /* @__PURE__ */ new Set([
|
|
5731
|
+
"schemaVersion",
|
|
5732
|
+
"previewId",
|
|
5733
|
+
"adjustmentId",
|
|
5734
|
+
"operation",
|
|
5735
|
+
"targetAccountId",
|
|
5736
|
+
"targetComponent",
|
|
5737
|
+
"targetWalletId",
|
|
5738
|
+
"targetLedgerAccountId",
|
|
5739
|
+
"offsetLedgerAccountId",
|
|
5740
|
+
"sourceLotId",
|
|
5741
|
+
"amount",
|
|
5742
|
+
"reasonCode",
|
|
5743
|
+
"ticketReferenceHash",
|
|
5744
|
+
"transferPolicy",
|
|
5745
|
+
"refundPolicy",
|
|
5746
|
+
"originalSourceLotId",
|
|
5747
|
+
"originalTransactionId",
|
|
5748
|
+
"preparedAt",
|
|
5749
|
+
"expiresAt"
|
|
5750
|
+
]);
|
|
5751
|
+
var DECISION_KEYS = /* @__PURE__ */ new Set([
|
|
5752
|
+
"schemaVersion",
|
|
5753
|
+
"decisionId",
|
|
5754
|
+
"adjustmentId",
|
|
5755
|
+
"proposalId",
|
|
5756
|
+
"proposalHash",
|
|
5757
|
+
"previewHash",
|
|
5758
|
+
"decision",
|
|
5759
|
+
"proposedByAccountId",
|
|
5760
|
+
"decidedByAccountId",
|
|
5761
|
+
"proposedAt",
|
|
5762
|
+
"decidedAt"
|
|
5763
|
+
]);
|
|
5764
|
+
var PROPOSAL_KEYS = /* @__PURE__ */ new Set([
|
|
5765
|
+
"schemaVersion",
|
|
5766
|
+
"proposalId",
|
|
5767
|
+
"adjustmentId",
|
|
5768
|
+
"previewHash",
|
|
5769
|
+
"status",
|
|
5770
|
+
"proposedByAccountId",
|
|
5771
|
+
"proposedAt",
|
|
5772
|
+
"expiresAt"
|
|
5773
|
+
]);
|
|
5774
|
+
var EXECUTION_KEYS = /* @__PURE__ */ new Set([
|
|
5775
|
+
"schemaVersion",
|
|
5776
|
+
"executionId",
|
|
5777
|
+
"adjustmentId",
|
|
5778
|
+
"previewHash",
|
|
5779
|
+
"proposalHash",
|
|
5780
|
+
"decisionHash",
|
|
5781
|
+
"sourceLotId",
|
|
5782
|
+
"transactionId",
|
|
5783
|
+
"resultReceiptId",
|
|
5784
|
+
"executedAt"
|
|
5785
|
+
]);
|
|
5786
|
+
var OPERATIONS = /* @__PURE__ */ new Set([
|
|
5787
|
+
"credit",
|
|
5788
|
+
"reverse-credit"
|
|
5789
|
+
]);
|
|
5790
|
+
var TARGET_COMPONENTS = /* @__PURE__ */ new Set([
|
|
5791
|
+
"personal",
|
|
5792
|
+
"household-treasury"
|
|
5793
|
+
]);
|
|
5794
|
+
var TRANSFER_POLICIES = /* @__PURE__ */ new Set([
|
|
5795
|
+
"household-allocatable",
|
|
5796
|
+
"same-user-only",
|
|
5797
|
+
"non-transferable"
|
|
5798
|
+
]);
|
|
5799
|
+
var DECISIONS = /* @__PURE__ */ new Set([
|
|
5800
|
+
"approve",
|
|
5801
|
+
"reject"
|
|
5802
|
+
]);
|
|
5803
|
+
function assertExactKeys4(value, allowed, label) {
|
|
5804
|
+
economyAssert(
|
|
5805
|
+
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
5806
|
+
"INVALID_CONTRACT",
|
|
5807
|
+
`${label} must be an object`
|
|
5808
|
+
);
|
|
5809
|
+
economyAssert(
|
|
5810
|
+
Object.keys(value).every((key) => allowed.has(key)),
|
|
5811
|
+
"INVALID_CONTRACT",
|
|
5812
|
+
`${label} contains an unsupported field`
|
|
5813
|
+
);
|
|
5814
|
+
}
|
|
5815
|
+
function assertCanonicalHash6(value, label) {
|
|
5816
|
+
economyAssert(
|
|
5817
|
+
/^sha256:[a-f0-9]{64}$/u.test(value),
|
|
5818
|
+
"INVALID_CONTRACT",
|
|
5819
|
+
`${label} must be a canonical SHA-256 reference`
|
|
5820
|
+
);
|
|
5821
|
+
}
|
|
5822
|
+
function assertReasonCode(reasonCode) {
|
|
5823
|
+
economyAssert(
|
|
5824
|
+
/^[A-Z][A-Z0-9_]{2,95}$/u.test(reasonCode),
|
|
5825
|
+
"INVALID_CONTRACT",
|
|
5826
|
+
"Adjustment reasonCode must be a bounded uppercase identifier"
|
|
5827
|
+
);
|
|
5828
|
+
}
|
|
5829
|
+
function assertOperatorAdjustmentPreview(preview) {
|
|
5830
|
+
assertExactKeys4(preview, PREVIEW_KEYS, "Operator adjustment preview");
|
|
5831
|
+
economyAssert(
|
|
5832
|
+
preview.schemaVersion === ECONOMY_CONTRACT_VERSION && OPERATIONS.has(preview.operation) && TARGET_COMPONENTS.has(preview.targetComponent) && TRANSFER_POLICIES.has(preview.transferPolicy) && preview.refundPolicy === "not-refundable",
|
|
5833
|
+
"INVALID_CONTRACT",
|
|
5834
|
+
"Unsupported operator adjustment preview"
|
|
5835
|
+
);
|
|
5836
|
+
assertEconomyIdentifier(preview.previewId, "previewId");
|
|
5837
|
+
assertEconomyIdentifier(preview.adjustmentId, "adjustmentId");
|
|
5838
|
+
assertEconomyIdentifier(preview.targetAccountId, "targetAccountId");
|
|
5839
|
+
assertEconomyIdentifier(preview.targetWalletId, "targetWalletId");
|
|
5840
|
+
assertEconomyIdentifier(
|
|
5841
|
+
preview.targetLedgerAccountId,
|
|
5842
|
+
"targetLedgerAccountId"
|
|
5843
|
+
);
|
|
5844
|
+
assertEconomyIdentifier(
|
|
5845
|
+
preview.offsetLedgerAccountId,
|
|
5846
|
+
"offsetLedgerAccountId"
|
|
5847
|
+
);
|
|
5848
|
+
assertEconomyIdentifier(preview.sourceLotId, "sourceLotId");
|
|
5849
|
+
economyAssert(
|
|
5850
|
+
parseTokenSubunits(preview.amount) > 0n,
|
|
5851
|
+
"INVALID_AMOUNT",
|
|
5852
|
+
"Operator adjustment amount must be positive"
|
|
5853
|
+
);
|
|
5854
|
+
assertReasonCode(preview.reasonCode);
|
|
5855
|
+
assertCanonicalHash6(preview.ticketReferenceHash, "ticketReferenceHash");
|
|
5856
|
+
const preparedAt = parseIsoTimestamp(preview.preparedAt);
|
|
5857
|
+
const expiresAt = parseIsoTimestamp(preview.expiresAt);
|
|
5858
|
+
economyAssert(
|
|
5859
|
+
expiresAt > preparedAt,
|
|
5860
|
+
"INVALID_TIME_WINDOW",
|
|
5861
|
+
"Operator adjustment preview must expire after preparation"
|
|
5862
|
+
);
|
|
5863
|
+
if (preview.operation === "credit") {
|
|
5864
|
+
economyAssert(
|
|
5865
|
+
preview.originalSourceLotId === void 0 && preview.originalTransactionId === void 0,
|
|
5866
|
+
"INVALID_CONTRACT",
|
|
5867
|
+
"A credit preview cannot bind an original transaction"
|
|
5868
|
+
);
|
|
5869
|
+
return;
|
|
5870
|
+
}
|
|
5871
|
+
economyAssert(
|
|
5872
|
+
preview.originalSourceLotId !== void 0 && preview.originalTransactionId !== void 0,
|
|
5873
|
+
"INVALID_CONTRACT",
|
|
5874
|
+
"A reversal preview must bind the original lot and transaction"
|
|
5875
|
+
);
|
|
5876
|
+
assertEconomyIdentifier(preview.originalSourceLotId, "originalSourceLotId");
|
|
5877
|
+
assertEconomyIdentifier(
|
|
5878
|
+
preview.originalTransactionId,
|
|
5879
|
+
"originalTransactionId"
|
|
5880
|
+
);
|
|
5881
|
+
}
|
|
5882
|
+
function canonicalOperatorAdjustmentPreviewPayload(preview) {
|
|
5883
|
+
assertOperatorAdjustmentPreview(preview);
|
|
5884
|
+
return JSON.stringify({
|
|
5885
|
+
schemaVersion: preview.schemaVersion,
|
|
5886
|
+
previewId: preview.previewId,
|
|
5887
|
+
adjustmentId: preview.adjustmentId,
|
|
5888
|
+
operation: preview.operation,
|
|
5889
|
+
targetAccountId: preview.targetAccountId,
|
|
5890
|
+
targetComponent: preview.targetComponent,
|
|
5891
|
+
targetWalletId: preview.targetWalletId,
|
|
5892
|
+
targetLedgerAccountId: preview.targetLedgerAccountId,
|
|
5893
|
+
offsetLedgerAccountId: preview.offsetLedgerAccountId,
|
|
5894
|
+
sourceLotId: preview.sourceLotId,
|
|
5895
|
+
amount: preview.amount,
|
|
5896
|
+
reasonCode: preview.reasonCode,
|
|
5897
|
+
ticketReferenceHash: preview.ticketReferenceHash,
|
|
5898
|
+
transferPolicy: preview.transferPolicy,
|
|
5899
|
+
refundPolicy: preview.refundPolicy,
|
|
5900
|
+
...preview.originalSourceLotId === void 0 ? {} : { originalSourceLotId: preview.originalSourceLotId },
|
|
5901
|
+
...preview.originalTransactionId === void 0 ? {} : { originalTransactionId: preview.originalTransactionId },
|
|
5902
|
+
preparedAt: preview.preparedAt,
|
|
5903
|
+
expiresAt: preview.expiresAt
|
|
5904
|
+
});
|
|
5905
|
+
}
|
|
5906
|
+
function assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash) {
|
|
5907
|
+
assertOperatorAdjustmentPreview(preview);
|
|
5908
|
+
assertCanonicalHash6(expectedPreviewHash, "expectedPreviewHash");
|
|
5909
|
+
assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
|
|
5910
|
+
economyAssert(
|
|
5911
|
+
proposal.schemaVersion === ECONOMY_CONTRACT_VERSION && proposal.status === "pending-approval",
|
|
5912
|
+
"INVALID_CONTRACT",
|
|
5913
|
+
"Unsupported operator adjustment proposal"
|
|
5914
|
+
);
|
|
5915
|
+
assertEconomyIdentifier(proposal.proposalId, "proposalId");
|
|
5916
|
+
assertEconomyIdentifier(proposal.adjustmentId, "adjustmentId");
|
|
5917
|
+
assertCanonicalHash6(proposal.previewHash, "previewHash");
|
|
5918
|
+
assertEconomyIdentifier(
|
|
5919
|
+
proposal.proposedByAccountId,
|
|
5920
|
+
"proposedByAccountId"
|
|
5921
|
+
);
|
|
5922
|
+
economyAssert(
|
|
5923
|
+
proposal.adjustmentId === preview.adjustmentId && proposal.previewHash === expectedPreviewHash,
|
|
5924
|
+
"ADJUSTMENT_PREVIEW_MISMATCH",
|
|
5925
|
+
"Operator adjustment proposal does not match its preview"
|
|
5926
|
+
);
|
|
5927
|
+
const proposedAt = parseIsoTimestamp(proposal.proposedAt);
|
|
5928
|
+
const expiresAt = parseIsoTimestamp(proposal.expiresAt);
|
|
5929
|
+
economyAssert(
|
|
5930
|
+
proposedAt >= parseIsoTimestamp(preview.preparedAt) && expiresAt === parseIsoTimestamp(preview.expiresAt) && expiresAt > proposedAt,
|
|
5931
|
+
"INVALID_TIME_WINDOW",
|
|
5932
|
+
"Operator adjustment proposal times are inconsistent"
|
|
5933
|
+
);
|
|
5934
|
+
}
|
|
5935
|
+
function canonicalOperatorAdjustmentProposalPayload(proposal) {
|
|
5936
|
+
assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
|
|
5937
|
+
return JSON.stringify({
|
|
5938
|
+
schemaVersion: proposal.schemaVersion,
|
|
5939
|
+
proposalId: proposal.proposalId,
|
|
5940
|
+
adjustmentId: proposal.adjustmentId,
|
|
5941
|
+
previewHash: proposal.previewHash,
|
|
5942
|
+
status: proposal.status,
|
|
5943
|
+
proposedByAccountId: proposal.proposedByAccountId,
|
|
5944
|
+
proposedAt: proposal.proposedAt,
|
|
5945
|
+
expiresAt: proposal.expiresAt
|
|
5946
|
+
});
|
|
5947
|
+
}
|
|
5948
|
+
function assertOperatorAdjustmentDecision(decision, proposal, preview, expectedPreviewHash, expectedProposalHash) {
|
|
5949
|
+
assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash);
|
|
5950
|
+
assertCanonicalHash6(expectedProposalHash, "expectedProposalHash");
|
|
5951
|
+
assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
|
|
5952
|
+
economyAssert(
|
|
5953
|
+
decision.schemaVersion === ECONOMY_CONTRACT_VERSION && DECISIONS.has(decision.decision),
|
|
5954
|
+
"INVALID_CONTRACT",
|
|
5955
|
+
"Unsupported operator adjustment decision"
|
|
5956
|
+
);
|
|
5957
|
+
assertEconomyIdentifier(decision.decisionId, "decisionId");
|
|
5958
|
+
assertEconomyIdentifier(decision.adjustmentId, "adjustmentId");
|
|
5959
|
+
assertEconomyIdentifier(decision.proposalId, "proposalId");
|
|
5960
|
+
assertCanonicalHash6(decision.proposalHash, "proposalHash");
|
|
5961
|
+
assertCanonicalHash6(decision.previewHash, "previewHash");
|
|
5962
|
+
assertEconomyIdentifier(
|
|
5963
|
+
decision.proposedByAccountId,
|
|
5964
|
+
"proposedByAccountId"
|
|
5965
|
+
);
|
|
5966
|
+
assertEconomyIdentifier(
|
|
5967
|
+
decision.decidedByAccountId,
|
|
5968
|
+
"decidedByAccountId"
|
|
5969
|
+
);
|
|
5970
|
+
economyAssert(
|
|
5971
|
+
decision.proposedByAccountId !== decision.decidedByAccountId,
|
|
5972
|
+
"ADJUSTMENT_SELF_APPROVAL",
|
|
5973
|
+
"Operator adjustment approval requires a distinct operator"
|
|
5974
|
+
);
|
|
5975
|
+
economyAssert(
|
|
5976
|
+
decision.adjustmentId === preview.adjustmentId && decision.proposalId === proposal.proposalId && decision.proposalHash === expectedProposalHash && decision.previewHash === expectedPreviewHash,
|
|
5977
|
+
"ADJUSTMENT_PREVIEW_MISMATCH",
|
|
5978
|
+
"Operator adjustment decision does not match its preview"
|
|
5979
|
+
);
|
|
5980
|
+
const proposedAt = parseIsoTimestamp(decision.proposedAt);
|
|
5981
|
+
const decidedAt = parseIsoTimestamp(decision.decidedAt);
|
|
5982
|
+
economyAssert(
|
|
5983
|
+
decision.proposedByAccountId === proposal.proposedByAccountId && proposedAt === parseIsoTimestamp(proposal.proposedAt) && decidedAt >= proposedAt,
|
|
5984
|
+
"INVALID_TIME_WINDOW",
|
|
5985
|
+
"Operator adjustment decision times are inconsistent"
|
|
5986
|
+
);
|
|
5987
|
+
economyAssert(
|
|
5988
|
+
decidedAt <= parseIsoTimestamp(preview.expiresAt),
|
|
5989
|
+
"ADJUSTMENT_EXPIRED",
|
|
5990
|
+
"Operator adjustment preview has expired"
|
|
5991
|
+
);
|
|
5992
|
+
}
|
|
5993
|
+
function canonicalOperatorAdjustmentDecisionPayload(decision) {
|
|
5994
|
+
assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
|
|
5995
|
+
return JSON.stringify({
|
|
5996
|
+
schemaVersion: decision.schemaVersion,
|
|
5997
|
+
decisionId: decision.decisionId,
|
|
5998
|
+
adjustmentId: decision.adjustmentId,
|
|
5999
|
+
proposalId: decision.proposalId,
|
|
6000
|
+
proposalHash: decision.proposalHash,
|
|
6001
|
+
previewHash: decision.previewHash,
|
|
6002
|
+
decision: decision.decision,
|
|
6003
|
+
proposedByAccountId: decision.proposedByAccountId,
|
|
6004
|
+
decidedByAccountId: decision.decidedByAccountId,
|
|
6005
|
+
proposedAt: decision.proposedAt,
|
|
6006
|
+
decidedAt: decision.decidedAt
|
|
6007
|
+
});
|
|
6008
|
+
}
|
|
6009
|
+
function assertOperatorAdjustmentExecution(execution, preview, proposal, decision, expectedPreviewHash, expectedProposalHash, expectedDecisionHash) {
|
|
6010
|
+
assertOperatorAdjustmentDecision(
|
|
6011
|
+
decision,
|
|
6012
|
+
proposal,
|
|
6013
|
+
preview,
|
|
6014
|
+
expectedPreviewHash,
|
|
6015
|
+
expectedProposalHash
|
|
6016
|
+
);
|
|
6017
|
+
assertCanonicalHash6(expectedDecisionHash, "expectedDecisionHash");
|
|
6018
|
+
assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
|
|
6019
|
+
economyAssert(
|
|
6020
|
+
execution.schemaVersion === ECONOMY_CONTRACT_VERSION,
|
|
6021
|
+
"INVALID_CONTRACT",
|
|
6022
|
+
"Unsupported operator adjustment execution"
|
|
6023
|
+
);
|
|
6024
|
+
assertEconomyIdentifier(execution.executionId, "executionId");
|
|
6025
|
+
assertEconomyIdentifier(execution.adjustmentId, "adjustmentId");
|
|
6026
|
+
assertCanonicalHash6(execution.previewHash, "previewHash");
|
|
6027
|
+
assertCanonicalHash6(execution.proposalHash, "proposalHash");
|
|
6028
|
+
assertCanonicalHash6(execution.decisionHash, "decisionHash");
|
|
6029
|
+
assertEconomyIdentifier(execution.sourceLotId, "sourceLotId");
|
|
6030
|
+
assertEconomyIdentifier(execution.transactionId, "transactionId");
|
|
6031
|
+
assertEconomyIdentifier(execution.resultReceiptId, "resultReceiptId");
|
|
6032
|
+
economyAssert(
|
|
6033
|
+
decision.decision === "approve",
|
|
6034
|
+
"ADJUSTMENT_NOT_APPROVED",
|
|
6035
|
+
"Only an approved adjustment may execute"
|
|
6036
|
+
);
|
|
6037
|
+
economyAssert(
|
|
6038
|
+
execution.adjustmentId === preview.adjustmentId && execution.previewHash === expectedPreviewHash && execution.proposalHash === expectedProposalHash && execution.decisionHash === expectedDecisionHash && execution.sourceLotId === preview.sourceLotId,
|
|
6039
|
+
"ADJUSTMENT_PREVIEW_MISMATCH",
|
|
6040
|
+
"Operator adjustment execution does not match its approval plan"
|
|
6041
|
+
);
|
|
6042
|
+
economyAssert(
|
|
6043
|
+
parseIsoTimestamp(execution.executedAt) >= parseIsoTimestamp(decision.decidedAt),
|
|
6044
|
+
"INVALID_TIME_WINDOW",
|
|
6045
|
+
"Operator adjustment execution predates its decision"
|
|
6046
|
+
);
|
|
6047
|
+
}
|
|
6048
|
+
function canonicalOperatorAdjustmentExecutionPayload(execution) {
|
|
6049
|
+
assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
|
|
6050
|
+
return JSON.stringify({
|
|
6051
|
+
schemaVersion: execution.schemaVersion,
|
|
6052
|
+
executionId: execution.executionId,
|
|
6053
|
+
adjustmentId: execution.adjustmentId,
|
|
6054
|
+
previewHash: execution.previewHash,
|
|
6055
|
+
proposalHash: execution.proposalHash,
|
|
6056
|
+
decisionHash: execution.decisionHash,
|
|
6057
|
+
sourceLotId: execution.sourceLotId,
|
|
6058
|
+
transactionId: execution.transactionId,
|
|
6059
|
+
resultReceiptId: execution.resultReceiptId,
|
|
6060
|
+
executedAt: execution.executedAt
|
|
6061
|
+
});
|
|
6062
|
+
}
|
|
6063
|
+
|
|
4549
6064
|
// src/paid-lots.ts
|
|
4550
6065
|
var ZERO_ARITHMETIC = Object.freeze({
|
|
4551
6066
|
retainedDelta: serializeTokenSubunits(0n),
|
|
@@ -5576,7 +7091,7 @@ function createProjectionSnapshot(transactions, rebuiltAt) {
|
|
|
5576
7091
|
}
|
|
5577
7092
|
|
|
5578
7093
|
// src/ports/query.ts
|
|
5579
|
-
var
|
|
7094
|
+
var ACTIVITY_TYPES3 = /* @__PURE__ */ new Set([
|
|
5580
7095
|
"purchase",
|
|
5581
7096
|
"subscription",
|
|
5582
7097
|
"rewarded-ad",
|
|
@@ -5593,14 +7108,14 @@ var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
|
|
|
5593
7108
|
"event",
|
|
5594
7109
|
"competition"
|
|
5595
7110
|
]);
|
|
5596
|
-
var
|
|
7111
|
+
var ACTIVITY_STATUSES3 = /* @__PURE__ */ new Set([
|
|
5597
7112
|
"pending",
|
|
5598
7113
|
"held",
|
|
5599
7114
|
"settled",
|
|
5600
7115
|
"reversed",
|
|
5601
7116
|
"failed"
|
|
5602
7117
|
]);
|
|
5603
|
-
var
|
|
7118
|
+
var ACTIVITY_SOURCES3 = /* @__PURE__ */ new Set([
|
|
5604
7119
|
"shopify",
|
|
5605
7120
|
"ayet",
|
|
5606
7121
|
"bitlabs",
|
|
@@ -5628,14 +7143,14 @@ function assertSafeDisplayString(value, label) {
|
|
|
5628
7143
|
`${label} must be bounded and safe for display`
|
|
5629
7144
|
);
|
|
5630
7145
|
}
|
|
5631
|
-
function
|
|
7146
|
+
function assertOpaqueCursor2(value) {
|
|
5632
7147
|
economyAssert(
|
|
5633
7148
|
typeof value === "string" && value.length > 0 && value.length <= 512 && !hasControlCharacters2(value),
|
|
5634
7149
|
"INVALID_CONTRACT",
|
|
5635
7150
|
"Activity cursor must be a bounded opaque value"
|
|
5636
7151
|
);
|
|
5637
7152
|
}
|
|
5638
|
-
function
|
|
7153
|
+
function assertUniqueValues2(values, allowed, label) {
|
|
5639
7154
|
const unique = new Set(values);
|
|
5640
7155
|
economyAssert(
|
|
5641
7156
|
values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
|
|
@@ -5898,7 +7413,7 @@ function assertWalletActivityEntry(entry) {
|
|
|
5898
7413
|
assertEconomyIdentifier(entry.activityId, "activityId");
|
|
5899
7414
|
assertEconomyIdentifier(entry.walletId, "walletId");
|
|
5900
7415
|
economyAssert(
|
|
5901
|
-
|
|
7416
|
+
ACTIVITY_TYPES3.has(entry.activityType) && ACTIVITY_STATUSES3.has(entry.status) && ACTIVITY_SOURCES3.has(entry.source),
|
|
5902
7417
|
"INVALID_CONTRACT",
|
|
5903
7418
|
"Wallet activity type, status, or source is unsupported"
|
|
5904
7419
|
);
|
|
@@ -5946,20 +7461,20 @@ function assertWalletActivityPageRequest(request) {
|
|
|
5946
7461
|
"Activity page limit must be between one and 100"
|
|
5947
7462
|
);
|
|
5948
7463
|
if (request.cursor !== void 0) {
|
|
5949
|
-
|
|
7464
|
+
assertOpaqueCursor2(request.cursor);
|
|
5950
7465
|
}
|
|
5951
7466
|
const filter = request.filter;
|
|
5952
7467
|
if (filter === void 0) {
|
|
5953
7468
|
return;
|
|
5954
7469
|
}
|
|
5955
7470
|
if (filter.activityTypes !== void 0) {
|
|
5956
|
-
|
|
7471
|
+
assertUniqueValues2(filter.activityTypes, ACTIVITY_TYPES3, "Activity types");
|
|
5957
7472
|
}
|
|
5958
7473
|
if (filter.statuses !== void 0) {
|
|
5959
|
-
|
|
7474
|
+
assertUniqueValues2(filter.statuses, ACTIVITY_STATUSES3, "Activity statuses");
|
|
5960
7475
|
}
|
|
5961
7476
|
if (filter.sources !== void 0) {
|
|
5962
|
-
|
|
7477
|
+
assertUniqueValues2(filter.sources, ACTIVITY_SOURCES3, "Activity sources");
|
|
5963
7478
|
}
|
|
5964
7479
|
if (filter.beneficiaryAccountId !== void 0) {
|
|
5965
7480
|
assertEconomyIdentifier(
|
|
@@ -5992,7 +7507,7 @@ function assertWalletActivityPage(page) {
|
|
|
5992
7507
|
"Activity pages are bounded and cannot advertise more rows from an empty page"
|
|
5993
7508
|
);
|
|
5994
7509
|
if (page.nextCursor !== void 0) {
|
|
5995
|
-
|
|
7510
|
+
assertOpaqueCursor2(page.nextCursor);
|
|
5996
7511
|
}
|
|
5997
7512
|
const activityIds = /* @__PURE__ */ new Set();
|
|
5998
7513
|
let previous;
|
|
@@ -6974,7 +8489,7 @@ var RESULT_OUTCOMES = /* @__PURE__ */ new Set([
|
|
|
6974
8489
|
"failed",
|
|
6975
8490
|
"no-op"
|
|
6976
8491
|
]);
|
|
6977
|
-
var
|
|
8492
|
+
var ACTIVITY_TYPES4 = /* @__PURE__ */ new Set([
|
|
6978
8493
|
"purchase",
|
|
6979
8494
|
"subscription",
|
|
6980
8495
|
"rewarded-ad",
|
|
@@ -7086,7 +8601,7 @@ var PORTABLE_KEYS = /* @__PURE__ */ new Set([
|
|
|
7086
8601
|
"signature",
|
|
7087
8602
|
...PORTABLE_BODY_KEYS
|
|
7088
8603
|
]);
|
|
7089
|
-
function
|
|
8604
|
+
function assertExactKeys5(value, allowedKeys, label) {
|
|
7090
8605
|
economyAssert(
|
|
7091
8606
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
7092
8607
|
"INVALID_CONTRACT",
|
|
@@ -7098,7 +8613,7 @@ function assertExactKeys3(value, allowedKeys, label) {
|
|
|
7098
8613
|
`${label} contains an unsupported field`
|
|
7099
8614
|
);
|
|
7100
8615
|
}
|
|
7101
|
-
function
|
|
8616
|
+
function assertCanonicalHash7(value, label) {
|
|
7102
8617
|
economyAssert(
|
|
7103
8618
|
typeof value === "string" && CANONICAL_HASH.test(value),
|
|
7104
8619
|
"INVALID_CONTRACT",
|
|
@@ -7107,7 +8622,7 @@ function assertCanonicalHash6(value, label) {
|
|
|
7107
8622
|
}
|
|
7108
8623
|
function canonicalHash(payload, hashCanonicalPayload2, label) {
|
|
7109
8624
|
const value = hashCanonicalPayload2(payload);
|
|
7110
|
-
|
|
8625
|
+
assertCanonicalHash7(value, label);
|
|
7111
8626
|
return value;
|
|
7112
8627
|
}
|
|
7113
8628
|
function assertUnsignedInteger(value, label) {
|
|
@@ -7175,7 +8690,7 @@ function canonicalSignatureMetadata(signature) {
|
|
|
7175
8690
|
};
|
|
7176
8691
|
}
|
|
7177
8692
|
function assertEconomySealedRecoveryPayload(payload) {
|
|
7178
|
-
|
|
8693
|
+
assertExactKeys5(
|
|
7179
8694
|
payload,
|
|
7180
8695
|
/* @__PURE__ */ new Set([
|
|
7181
8696
|
"schemaVersion",
|
|
@@ -7205,17 +8720,17 @@ function assertEconomySealedRecoveryPayload(payload) {
|
|
|
7205
8720
|
22,
|
|
7206
8721
|
22
|
|
7207
8722
|
);
|
|
7208
|
-
|
|
8723
|
+
assertCanonicalHash7(
|
|
7209
8724
|
payload.plaintextContentHash,
|
|
7210
8725
|
"Recovery plaintext-content hash"
|
|
7211
8726
|
);
|
|
7212
|
-
|
|
8727
|
+
assertCanonicalHash7(
|
|
7213
8728
|
payload.encryptionContextHash,
|
|
7214
8729
|
"Recovery encryption-context hash"
|
|
7215
8730
|
);
|
|
7216
8731
|
}
|
|
7217
8732
|
function assertAcceptanceBody(body) {
|
|
7218
|
-
|
|
8733
|
+
assertExactKeys5(
|
|
7219
8734
|
body,
|
|
7220
8735
|
"acceptanceEnvelopeId" in body ? ACCEPTANCE_KEYS : ACCEPTANCE_BODY_KEYS,
|
|
7221
8736
|
"Recovery acceptance body"
|
|
@@ -7234,9 +8749,9 @@ function assertAcceptanceBody(body) {
|
|
|
7234
8749
|
body.idempotencyFingerprint,
|
|
7235
8750
|
"economy.idempotency-key.v1"
|
|
7236
8751
|
);
|
|
7237
|
-
|
|
8752
|
+
assertCanonicalHash7(body.commandEnvelopeHash, "Command-envelope hash");
|
|
7238
8753
|
assertEconomyIdentifier(body.acceptedReceiptId, "acceptedReceiptId");
|
|
7239
|
-
|
|
8754
|
+
assertCanonicalHash7(body.acceptedReceiptHash, "Accepted-receipt hash");
|
|
7240
8755
|
assertEconomySealedRecoveryPayload(body.sealedPayload);
|
|
7241
8756
|
const preparedAt = parseIsoTimestamp(body.preparedAt);
|
|
7242
8757
|
const acceptedAt = parseIsoTimestamp(body.acceptedAt);
|
|
@@ -7284,7 +8799,7 @@ function createEconomyRecoveryAcceptanceEnvelope(body, hashCanonicalPayload2) {
|
|
|
7284
8799
|
};
|
|
7285
8800
|
}
|
|
7286
8801
|
function assertEconomyRecoveryAcceptanceEnvelope(envelope, hashCanonicalPayload2) {
|
|
7287
|
-
|
|
8802
|
+
assertExactKeys5(envelope, ACCEPTANCE_KEYS, "Recovery acceptance envelope");
|
|
7288
8803
|
assertAcceptanceBody(envelope);
|
|
7289
8804
|
assertEconomyIdentifier(
|
|
7290
8805
|
envelope.acceptanceEnvelopeId,
|
|
@@ -7325,7 +8840,7 @@ function canonicalEconomyRecoveryAcceptanceEnvelopePayload(envelope, hashCanonic
|
|
|
7325
8840
|
});
|
|
7326
8841
|
}
|
|
7327
8842
|
function assertCommittedResultBody(body) {
|
|
7328
|
-
|
|
8843
|
+
assertExactKeys5(
|
|
7329
8844
|
body,
|
|
7330
8845
|
"committedResultId" in body ? COMMITTED_RESULT_KEYS : COMMITTED_RESULT_BODY_KEYS,
|
|
7331
8846
|
"Recovery committed-result body"
|
|
@@ -7353,7 +8868,7 @@ function assertCommittedResultBody(body) {
|
|
|
7353
8868
|
[body.authorityCommitHash, "Authority-commit hash"],
|
|
7354
8869
|
[body.authorityHeadHashAfter, "Authority-head hash"]
|
|
7355
8870
|
]) {
|
|
7356
|
-
|
|
8871
|
+
assertCanonicalHash7(value, label);
|
|
7357
8872
|
}
|
|
7358
8873
|
economyAssert(
|
|
7359
8874
|
RESULT_OUTCOMES.has(body.outcome),
|
|
@@ -7376,7 +8891,7 @@ function assertCommittedResultBody(body) {
|
|
|
7376
8891
|
assertEconomyIdentifier(body.transactionId, "transactionId");
|
|
7377
8892
|
}
|
|
7378
8893
|
if (body.transactionCanonicalHash !== void 0) {
|
|
7379
|
-
|
|
8894
|
+
assertCanonicalHash7(
|
|
7380
8895
|
body.transactionCanonicalHash,
|
|
7381
8896
|
"Transaction canonical hash"
|
|
7382
8897
|
);
|
|
@@ -7419,7 +8934,7 @@ function createEconomyRecoveryCommittedResult(body, hashCanonicalPayload2) {
|
|
|
7419
8934
|
};
|
|
7420
8935
|
}
|
|
7421
8936
|
function assertEconomyRecoveryCommittedResult(result, hashCanonicalPayload2) {
|
|
7422
|
-
|
|
8937
|
+
assertExactKeys5(
|
|
7423
8938
|
result,
|
|
7424
8939
|
COMMITTED_RESULT_KEYS,
|
|
7425
8940
|
"Recovery committed result"
|
|
@@ -7478,7 +8993,7 @@ function assertEconomyRecoveryResultLink(acceptance, result, hashCanonicalPayloa
|
|
|
7478
8993
|
);
|
|
7479
8994
|
}
|
|
7480
8995
|
function assertEconomyEvidenceSignatureMetadata(signature) {
|
|
7481
|
-
|
|
8996
|
+
assertExactKeys5(
|
|
7482
8997
|
signature,
|
|
7483
8998
|
/* @__PURE__ */ new Set([
|
|
7484
8999
|
"schemaVersion",
|
|
@@ -7498,7 +9013,7 @@ function assertEconomyEvidenceSignatureMetadata(signature) {
|
|
|
7498
9013
|
parseIsoTimestamp(signature.signedAt);
|
|
7499
9014
|
}
|
|
7500
9015
|
function assertEconomyEvidenceSignature(signature) {
|
|
7501
|
-
|
|
9016
|
+
assertExactKeys5(
|
|
7502
9017
|
signature,
|
|
7503
9018
|
/* @__PURE__ */ new Set([
|
|
7504
9019
|
"schemaVersion",
|
|
@@ -7520,7 +9035,7 @@ function assertEconomyEvidenceSignature(signature) {
|
|
|
7520
9035
|
assertBase64url(signature.value, "Evidence signature value", 32, 2048);
|
|
7521
9036
|
}
|
|
7522
9037
|
function assertRegionalEvidenceBody(body) {
|
|
7523
|
-
|
|
9038
|
+
assertExactKeys5(
|
|
7524
9039
|
body,
|
|
7525
9040
|
"evidenceReceiptId" in body ? REGIONAL_KEYS : REGIONAL_BODY_KEYS,
|
|
7526
9041
|
"Regional evidence-receipt body"
|
|
@@ -7552,7 +9067,7 @@ function assertRegionalEvidenceBody(body) {
|
|
|
7552
9067
|
"INVALID_CONTRACT",
|
|
7553
9068
|
"Unsupported recovery record kind"
|
|
7554
9069
|
);
|
|
7555
|
-
|
|
9070
|
+
assertCanonicalHash7(
|
|
7556
9071
|
body.recoveryRecordContentHash,
|
|
7557
9072
|
"Recovery-record content hash"
|
|
7558
9073
|
);
|
|
@@ -7568,7 +9083,7 @@ function assertRegionalEvidenceBody(body) {
|
|
|
7568
9083
|
"INVALID_CONTRACT",
|
|
7569
9084
|
"Non-genesis regional evidence receipt requires a previous hash"
|
|
7570
9085
|
);
|
|
7571
|
-
|
|
9086
|
+
assertCanonicalHash7(
|
|
7572
9087
|
body.previousReceiptHash,
|
|
7573
9088
|
"Previous evidence-receipt hash"
|
|
7574
9089
|
);
|
|
@@ -7612,7 +9127,7 @@ function createEconomyRegionalEvidenceReceipt(body, signature, hashCanonicalPayl
|
|
|
7612
9127
|
};
|
|
7613
9128
|
}
|
|
7614
9129
|
function assertEconomyRegionalEvidenceReceipt(receipt, hashCanonicalPayload2) {
|
|
7615
|
-
|
|
9130
|
+
assertExactKeys5(receipt, REGIONAL_KEYS, "Regional evidence receipt");
|
|
7616
9131
|
assertRegionalEvidenceBody(receipt);
|
|
7617
9132
|
assertEconomyIdentifier(receipt.evidenceReceiptId, "evidenceReceiptId");
|
|
7618
9133
|
assertEconomyEvidenceSignature(receipt.signature);
|
|
@@ -7743,7 +9258,7 @@ function assertEconomyRegionalEvidenceChain(receipts, expectedPreviousReceiptHas
|
|
|
7743
9258
|
"INVALID_CONTRACT",
|
|
7744
9259
|
"Partial evidence chain requires its trusted preceding hash"
|
|
7745
9260
|
);
|
|
7746
|
-
|
|
9261
|
+
assertCanonicalHash7(
|
|
7747
9262
|
expectedPreviousReceiptHash,
|
|
7748
9263
|
"Expected preceding evidence-receipt hash"
|
|
7749
9264
|
);
|
|
@@ -7814,7 +9329,7 @@ function assertEconomyRegionalEvidenceEquality(receipts, expectedRegions, hashCa
|
|
|
7814
9329
|
);
|
|
7815
9330
|
}
|
|
7816
9331
|
function assertEconomyMerkleInclusionProof(proof) {
|
|
7817
|
-
|
|
9332
|
+
assertExactKeys5(
|
|
7818
9333
|
proof,
|
|
7819
9334
|
/* @__PURE__ */ new Set([
|
|
7820
9335
|
"schemaVersion",
|
|
@@ -7835,8 +9350,8 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7835
9350
|
"Unsupported Merkle inclusion proof"
|
|
7836
9351
|
);
|
|
7837
9352
|
assertEconomyIdentifier(proof.anchorId, "anchorId");
|
|
7838
|
-
|
|
7839
|
-
|
|
9353
|
+
assertCanonicalHash7(proof.anchorManifestHash, "Anchor-manifest hash");
|
|
9354
|
+
assertCanonicalHash7(proof.leafHash, "Merkle leaf hash");
|
|
7840
9355
|
assertUnsignedInteger(proof.leafIndex, "Merkle leaf index");
|
|
7841
9356
|
assertUnsignedInteger(proof.leafCount, "Merkle leaf count");
|
|
7842
9357
|
economyAssert(
|
|
@@ -7845,7 +9360,7 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7845
9360
|
"Merkle leaf position is outside its bounded tree"
|
|
7846
9361
|
);
|
|
7847
9362
|
for (const step of proof.siblings) {
|
|
7848
|
-
|
|
9363
|
+
assertExactKeys5(
|
|
7849
9364
|
step,
|
|
7850
9365
|
/* @__PURE__ */ new Set(["schemaVersion", "side", "hash"]),
|
|
7851
9366
|
"Merkle proof step"
|
|
@@ -7855,7 +9370,7 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7855
9370
|
"INVALID_CONTRACT",
|
|
7856
9371
|
"Unsupported Merkle proof step"
|
|
7857
9372
|
);
|
|
7858
|
-
|
|
9373
|
+
assertCanonicalHash7(step.hash, "Merkle sibling hash");
|
|
7859
9374
|
}
|
|
7860
9375
|
}
|
|
7861
9376
|
function canonicalMerkleProof(proof) {
|
|
@@ -7934,7 +9449,7 @@ function assertEconomyMerkleInclusion(proof, anchor, hashCanonicalPayload2) {
|
|
|
7934
9449
|
);
|
|
7935
9450
|
}
|
|
7936
9451
|
function assertPortableEvidenceReference(reference) {
|
|
7937
|
-
|
|
9452
|
+
assertExactKeys5(
|
|
7938
9453
|
reference,
|
|
7939
9454
|
/* @__PURE__ */ new Set([
|
|
7940
9455
|
"schemaVersion",
|
|
@@ -7954,7 +9469,7 @@ function assertPortableEvidenceReference(reference) {
|
|
|
7954
9469
|
reference.evidenceReceiptId,
|
|
7955
9470
|
"evidenceReceiptId"
|
|
7956
9471
|
);
|
|
7957
|
-
|
|
9472
|
+
assertCanonicalHash7(
|
|
7958
9473
|
reference.evidenceReceiptHash,
|
|
7959
9474
|
"Evidence-receipt hash"
|
|
7960
9475
|
);
|
|
@@ -7971,7 +9486,7 @@ function canonicalPortableEvidenceReference(reference) {
|
|
|
7971
9486
|
};
|
|
7972
9487
|
}
|
|
7973
9488
|
function assertPortableBody(body) {
|
|
7974
|
-
|
|
9489
|
+
assertExactKeys5(
|
|
7975
9490
|
body,
|
|
7976
9491
|
"portableReceiptId" in body ? PORTABLE_KEYS : PORTABLE_BODY_KEYS,
|
|
7977
9492
|
"Portable customer-receipt body"
|
|
@@ -7995,7 +9510,7 @@ function assertPortableBody(body) {
|
|
|
7995
9510
|
assertEconomyIdentifier(value, label);
|
|
7996
9511
|
}
|
|
7997
9512
|
economyAssert(
|
|
7998
|
-
|
|
9513
|
+
ACTIVITY_TYPES4.has(body.activityType) && (body.direction === "credit" || body.direction === "debit"),
|
|
7999
9514
|
"INVALID_CONTRACT",
|
|
8000
9515
|
"Portable customer receipt has an unsupported activity or direction"
|
|
8001
9516
|
);
|
|
@@ -8010,7 +9525,7 @@ function assertPortableBody(body) {
|
|
|
8010
9525
|
[body.committedResultContentHash, "Committed-result content hash"],
|
|
8011
9526
|
[body.authorityCommitHash, "Authority-commit hash"]
|
|
8012
9527
|
]) {
|
|
8013
|
-
|
|
9528
|
+
assertCanonicalHash7(value, label);
|
|
8014
9529
|
}
|
|
8015
9530
|
assertUnsignedInteger(body.authoritySequence, "Authority sequence");
|
|
8016
9531
|
economyAssert(
|
|
@@ -8095,7 +9610,7 @@ function createEconomyPortableCustomerReceipt(body, signature, hashCanonicalPayl
|
|
|
8095
9610
|
};
|
|
8096
9611
|
}
|
|
8097
9612
|
function assertEconomyPortableCustomerReceipt(receipt, hashCanonicalPayload2) {
|
|
8098
|
-
|
|
9613
|
+
assertExactKeys5(receipt, PORTABLE_KEYS, "Portable customer receipt");
|
|
8099
9614
|
assertPortableBody(receipt);
|
|
8100
9615
|
assertEconomyIdentifier(receipt.portableReceiptId, "portableReceiptId");
|
|
8101
9616
|
assertEconomyEvidenceSignature(receipt.signature);
|
|
@@ -8395,7 +9910,7 @@ var DOCUMENT_ID_KEYS = /* @__PURE__ */ new Set([
|
|
|
8395
9910
|
"lifetimeProjectionId",
|
|
8396
9911
|
"outboxEventId"
|
|
8397
9912
|
]);
|
|
8398
|
-
function
|
|
9913
|
+
function assertExactKeys6(value, allowed, label) {
|
|
8399
9914
|
economyAssert(
|
|
8400
9915
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
8401
9916
|
"INVALID_CONTRACT",
|
|
@@ -8435,7 +9950,7 @@ function createPersonalWalletInitializationDocumentIds(subjectAccountId, hash) {
|
|
|
8435
9950
|
};
|
|
8436
9951
|
}
|
|
8437
9952
|
function assertPersonalWalletInitializationCommand(command) {
|
|
8438
|
-
|
|
9953
|
+
assertExactKeys6(command, COMMAND_KEYS, "Wallet initialization command");
|
|
8439
9954
|
economyAssert(
|
|
8440
9955
|
command.schemaVersion === ECONOMY_CONTRACT_VERSION && command.commandType === "initialize-wallet" && command.walletKind === "personal",
|
|
8441
9956
|
"INVALID_CONTRACT",
|
|
@@ -8459,7 +9974,7 @@ function canonicalPersonalWalletInitializationCommandPayload(command) {
|
|
|
8459
9974
|
});
|
|
8460
9975
|
}
|
|
8461
9976
|
function assertPersonalWalletInitializationOutboxIntent(intent) {
|
|
8462
|
-
|
|
9977
|
+
assertExactKeys6(intent, OUTBOX_KEYS, "Wallet initialization outbox intent");
|
|
8463
9978
|
economyAssert(
|
|
8464
9979
|
intent.schemaVersion === ECONOMY_CONTRACT_VERSION && intent.eventType === "wallet.initialized.v1",
|
|
8465
9980
|
"INVALID_CONTRACT",
|
|
@@ -8559,8 +10074,8 @@ function createPersonalWalletInitializationState(input, hash) {
|
|
|
8559
10074
|
return state;
|
|
8560
10075
|
}
|
|
8561
10076
|
function assertPersonalWalletInitializationState(state) {
|
|
8562
|
-
|
|
8563
|
-
|
|
10077
|
+
assertExactKeys6(state, STATE_KEYS, "Wallet initialization state");
|
|
10078
|
+
assertExactKeys6(
|
|
8564
10079
|
state.documentIds,
|
|
8565
10080
|
DOCUMENT_ID_KEYS,
|
|
8566
10081
|
"Wallet initialization document IDs"
|
|
@@ -8592,6 +10107,13 @@ function assertPersonalWalletInitializationState(state) {
|
|
|
8592
10107
|
}
|
|
8593
10108
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8594
10109
|
0 && (module.exports = {
|
|
10110
|
+
ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
10111
|
+
ADMIN_TOKEN_DEFAULT_WINDOW_DAYS,
|
|
10112
|
+
ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS,
|
|
10113
|
+
ADMIN_TOKEN_MAXIMUM_PAGE_SIZE,
|
|
10114
|
+
ADMIN_TOKEN_MAXIMUM_TREND_POINTS,
|
|
10115
|
+
ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS,
|
|
10116
|
+
ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
8595
10117
|
BASELINE_GBP_CATALOG_VERSION,
|
|
8596
10118
|
BASELINE_GBP_REFERENCE_RATE,
|
|
8597
10119
|
BASELINE_GBP_TOKEN_PACKS,
|
|
@@ -8619,6 +10141,19 @@ function assertPersonalWalletInitializationState(state) {
|
|
|
8619
10141
|
applyWalletBalanceDelta,
|
|
8620
10142
|
applyWalletLifetimeDeltas,
|
|
8621
10143
|
assertActivityEntry,
|
|
10144
|
+
assertAdminTokenActivityCursorBinding,
|
|
10145
|
+
assertAdminTokenActivityEntry,
|
|
10146
|
+
assertAdminTokenActivityPage,
|
|
10147
|
+
assertAdminTokenActivityPageForRequest,
|
|
10148
|
+
assertAdminTokenActivityPageRequest,
|
|
10149
|
+
assertAdminTokenEconomySummary,
|
|
10150
|
+
assertAdminTokenTrendRequest,
|
|
10151
|
+
assertAdminTokenTrendResult,
|
|
10152
|
+
assertAdminTokenTrendResultForRequest,
|
|
10153
|
+
assertAdminTokenWalletBalanceCursorBinding,
|
|
10154
|
+
assertAdminTokenWalletBalancePage,
|
|
10155
|
+
assertAdminTokenWalletBalancePageForRequest,
|
|
10156
|
+
assertAdminTokenWalletBalancePageRequest,
|
|
8622
10157
|
assertAuditedEconomyCommandEnvelope,
|
|
8623
10158
|
assertBalancedTransaction,
|
|
8624
10159
|
assertDeterministicWalletBalanceSummary,
|
|
@@ -8672,6 +10207,10 @@ function assertPersonalWalletInitializationState(state) {
|
|
|
8672
10207
|
assertModuleSpendQuote,
|
|
8673
10208
|
assertNonNegativeAccounts,
|
|
8674
10209
|
assertOpenPurchaseIntent,
|
|
10210
|
+
assertOperatorAdjustmentDecision,
|
|
10211
|
+
assertOperatorAdjustmentExecution,
|
|
10212
|
+
assertOperatorAdjustmentPreview,
|
|
10213
|
+
assertOperatorAdjustmentProposal,
|
|
8675
10214
|
assertPaidLotLifecycle,
|
|
8676
10215
|
assertPaidLotLifecycleEvent,
|
|
8677
10216
|
assertPaidLotPurchaseProvenance,
|
|
@@ -8735,11 +10274,18 @@ function assertPersonalWalletInitializationState(state) {
|
|
|
8735
10274
|
canonicalEconomyRegionalEvidenceReceiptBodyPayload,
|
|
8736
10275
|
canonicalEconomyRegionalEvidenceReceiptPayload,
|
|
8737
10276
|
canonicalEconomyRegionalEvidenceReceiptSigningPayload,
|
|
10277
|
+
canonicalOperatorAdjustmentDecisionPayload,
|
|
10278
|
+
canonicalOperatorAdjustmentExecutionPayload,
|
|
10279
|
+
canonicalOperatorAdjustmentPreviewPayload,
|
|
10280
|
+
canonicalOperatorAdjustmentProposalPayload,
|
|
8738
10281
|
canonicalPersonalWalletInitializationCommandPayload,
|
|
8739
10282
|
canonicalPersonalWalletInitializationOutboxPayload,
|
|
8740
10283
|
canonicalTransactionPayload,
|
|
8741
10284
|
closeModuleAllowance,
|
|
8742
10285
|
convertRewardPayout,
|
|
10286
|
+
createAdminTokenAnomalyIndicator,
|
|
10287
|
+
createAdminTokenAnomalyUnavailable,
|
|
10288
|
+
createDefaultAdminTokenReportingWindow,
|
|
8743
10289
|
createEarlyBackerRetentionFromPaidLot,
|
|
8744
10290
|
createEconomyPortableCustomerReceipt,
|
|
8745
10291
|
createEconomyRecoveryAcceptanceEnvelope,
|