@plasius/economy 0.7.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/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,
@@ -176,6 +196,9 @@ __export(index_exports, {
176
196
  canonicalTransactionPayload: () => canonicalTransactionPayload,
177
197
  closeModuleAllowance: () => closeModuleAllowance,
178
198
  convertRewardPayout: () => convertRewardPayout,
199
+ createAdminTokenAnomalyIndicator: () => createAdminTokenAnomalyIndicator,
200
+ createAdminTokenAnomalyUnavailable: () => createAdminTokenAnomalyUnavailable,
201
+ createDefaultAdminTokenReportingWindow: () => createDefaultAdminTokenReportingWindow,
179
202
  createEarlyBackerRetentionFromPaidLot: () => createEarlyBackerRetentionFromPaidLot,
180
203
  createEconomyPortableCustomerReceipt: () => createEconomyPortableCustomerReceipt,
181
204
  createEconomyRecoveryAcceptanceEnvelope: () => createEconomyRecoveryAcceptanceEnvelope,
@@ -736,6 +759,1155 @@ function mapBitLabsConversionState(state) {
736
759
  return transition;
737
760
  }
738
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
+
739
1911
  // src/allocations.ts
740
1912
  function assertWholePositive(amount, label) {
741
1913
  const parsed = parseTokenSubunits(amount);
@@ -1072,7 +2244,7 @@ var COMMAND_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
1072
2244
  "acceptedRegion",
1073
2245
  "writerFencingToken"
1074
2246
  ]);
1075
- function assertExactKeys(value, allowedKeys, label) {
2247
+ function assertExactKeys2(value, allowedKeys, label) {
1076
2248
  economyAssert(
1077
2249
  value !== null && typeof value === "object" && !Array.isArray(value),
1078
2250
  "INVALID_CONTRACT",
@@ -1116,7 +2288,7 @@ function assertRelationshipContext(relationshipId, authorizationVersion) {
1116
2288
  );
1117
2289
  }
1118
2290
  function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
1119
- assertExactKeys(
2291
+ assertExactKeys2(
1120
2292
  fingerprint,
1121
2293
  /* @__PURE__ */ new Set([
1122
2294
  "schemaVersion",
@@ -1141,7 +2313,7 @@ function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
1141
2313
  );
1142
2314
  }
1143
2315
  function assertEconomyAuthorizationEvidence(evidence) {
1144
- assertExactKeys(
2316
+ assertExactKeys2(
1145
2317
  evidence,
1146
2318
  /* @__PURE__ */ new Set([
1147
2319
  "schemaVersion",
@@ -1178,7 +2350,7 @@ function assertEconomyAuthorizationEvidence(evidence) {
1178
2350
  );
1179
2351
  }
1180
2352
  function assertCausationReference(causation) {
1181
- assertExactKeys(
2353
+ assertExactKeys2(
1182
2354
  causation,
1183
2355
  /* @__PURE__ */ new Set(["schemaVersion", "kind", "causationId"]),
1184
2356
  "Economy causation reference"
@@ -1233,7 +2405,7 @@ function assertCommandSourcePrincipal(envelope) {
1233
2405
  }
1234
2406
  }
1235
2407
  function assertAuditedEconomyCommandEnvelope(envelope) {
1236
- assertExactKeys(
2408
+ assertExactKeys2(
1237
2409
  envelope,
1238
2410
  COMMAND_ENVELOPE_KEYS,
1239
2411
  "Audited economy command envelope"
@@ -1299,7 +2471,7 @@ function assertAuditedEconomyCommandEnvelope(envelope) {
1299
2471
  );
1300
2472
  }
1301
2473
  function assertEconomyProviderEvidenceHash(evidence) {
1302
- assertExactKeys(
2474
+ assertExactKeys2(
1303
2475
  evidence,
1304
2476
  /* @__PURE__ */ new Set([
1305
2477
  "schemaVersion",
@@ -1370,7 +2542,7 @@ function assertEconomyProviderEvidenceHash(evidence) {
1370
2542
  }
1371
2543
  }
1372
2544
  function assertEconomyEncryptedOperationalHandleBinding(binding) {
1373
- assertExactKeys(
2545
+ assertExactKeys2(
1374
2546
  binding,
1375
2547
  /* @__PURE__ */ new Set([
1376
2548
  "schemaVersion",
@@ -1405,7 +2577,7 @@ function assertEconomyEncryptedOperationalHandleBinding(binding) {
1405
2577
  parseIsoTimestamp(binding.createdAt);
1406
2578
  }
1407
2579
  function assertEvidenceRecordReference(reference) {
1408
- assertExactKeys(
2580
+ assertExactKeys2(
1409
2581
  reference,
1410
2582
  /* @__PURE__ */ new Set(["schemaVersion", "recordId", "contentHash"]),
1411
2583
  "Evidence record reference"
@@ -1436,7 +2608,7 @@ function assertUniqueSortedReferences(references, label) {
1436
2608
  }
1437
2609
  }
1438
2610
  function assertEconomyProviderEvidenceManifest(manifest) {
1439
- assertExactKeys(
2611
+ assertExactKeys2(
1440
2612
  manifest,
1441
2613
  /* @__PURE__ */ new Set([
1442
2614
  "schemaVersion",
@@ -1478,7 +2650,7 @@ function assertEconomyProviderEvidenceManifest(manifest) {
1478
2650
  parseIsoTimestamp(manifest.createdAt);
1479
2651
  }
1480
2652
  function assertEconomyAcceptedCommandReceipt(receipt) {
1481
- assertExactKeys(
2653
+ assertExactKeys2(
1482
2654
  receipt,
1483
2655
  /* @__PURE__ */ new Set([
1484
2656
  "schemaVersion",
@@ -1502,7 +2674,7 @@ function assertEconomyAcceptedCommandReceipt(receipt) {
1502
2674
  parseIsoTimestamp(receipt.acceptedAt);
1503
2675
  }
1504
2676
  function assertEconomyCommandResultReceipt(receipt) {
1505
- assertExactKeys(
2677
+ assertExactKeys2(
1506
2678
  receipt,
1507
2679
  /* @__PURE__ */ new Set([
1508
2680
  "schemaVersion",
@@ -1559,7 +2731,7 @@ function assertEconomyCommandResultReceipt(receipt) {
1559
2731
  }
1560
2732
  }
1561
2733
  function assertEconomyAuditedIdempotencyScope(scope) {
1562
- assertExactKeys(
2734
+ assertExactKeys2(
1563
2735
  scope,
1564
2736
  /* @__PURE__ */ new Set([
1565
2737
  "schemaVersion",
@@ -1590,7 +2762,7 @@ function assertEconomyAuditedIdempotencyScope(scope) {
1590
2762
  );
1591
2763
  }
1592
2764
  function assertEconomyAuditedIdempotencyResult(result) {
1593
- assertExactKeys(
2765
+ assertExactKeys2(
1594
2766
  result,
1595
2767
  /* @__PURE__ */ new Set([
1596
2768
  "schemaVersion",
@@ -1881,7 +3053,7 @@ var MANIFEST_KEYS = /* @__PURE__ */ new Set([
1881
3053
  "recordReferences",
1882
3054
  "committedAt"
1883
3055
  ]);
1884
- function assertExactKeys2(value, allowedKeys, label) {
3056
+ function assertExactKeys3(value, allowedKeys, label) {
1885
3057
  economyAssert(
1886
3058
  value !== null && typeof value === "object" && !Array.isArray(value),
1887
3059
  "INVALID_CONTRACT",
@@ -1919,7 +3091,7 @@ function referenceOrder(left, right) {
1919
3091
  return byKind === 0 ? compareUnicodeCodeUnits(left.recordId, right.recordId) : byKind;
1920
3092
  }
1921
3093
  function assertEconomyAuthorityRecordReference(reference) {
1922
- assertExactKeys2(
3094
+ assertExactKeys3(
1923
3095
  reference,
1924
3096
  /* @__PURE__ */ new Set([
1925
3097
  "schemaVersion",
@@ -2083,7 +3255,7 @@ function assertCommitAllowedInState(manifest) {
2083
3255
  }
2084
3256
  }
2085
3257
  function assertEconomyAuthorityCommitManifest(manifest) {
2086
- assertExactKeys2(manifest, MANIFEST_KEYS, "Authority commit manifest");
3258
+ assertExactKeys3(manifest, MANIFEST_KEYS, "Authority commit manifest");
2087
3259
  economyAssert(
2088
3260
  manifest.schemaVersion === ECONOMY_CONTRACT_VERSION && COMMIT_KINDS.has(manifest.commitKind) && AUTHORITY_STATES.has(manifest.authorityStateBefore) && AUTHORITY_STATES.has(manifest.authorityStateAfter),
2089
3261
  "INVALID_CONTRACT",
@@ -2130,7 +3302,7 @@ function assertEconomyAuthorityCommitManifest(manifest) {
2130
3302
  parseIsoTimestamp(manifest.committedAt);
2131
3303
  }
2132
3304
  function assertEconomyAuthorityHead(head) {
2133
- assertExactKeys2(head, HEAD_KEYS, "Economy authority head");
3305
+ assertExactKeys3(head, HEAD_KEYS, "Economy authority head");
2134
3306
  economyAssert(
2135
3307
  head.schemaVersion === ECONOMY_CONTRACT_VERSION && AUTHORITY_STATES.has(head.state),
2136
3308
  "INVALID_CONTRACT",
@@ -2189,7 +3361,7 @@ function advanceEconomyAuthorityHead(head, manifest, manifestCanonicalHash) {
2189
3361
  };
2190
3362
  }
2191
3363
  function assertEconomyIntegrityVerificationReceipt(receipt) {
2192
- assertExactKeys2(
3364
+ assertExactKeys3(
2193
3365
  receipt,
2194
3366
  /* @__PURE__ */ new Set([
2195
3367
  "schemaVersion",
@@ -2335,7 +3507,7 @@ function assertEconomyIntegrityVerificationReceipt(receipt) {
2335
3507
  parseIsoTimestamp(receipt.verifiedAt);
2336
3508
  }
2337
3509
  function assertEconomyIntegrityAnchorManifest(manifest) {
2338
- assertExactKeys2(
3510
+ assertExactKeys3(
2339
3511
  manifest,
2340
3512
  /* @__PURE__ */ new Set([
2341
3513
  "schemaVersion",
@@ -2497,7 +3669,7 @@ function sortEconomyAuthorityRecordReferences(references) {
2497
3669
  }
2498
3670
 
2499
3671
  // src/ledger.ts
2500
- var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
3672
+ var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
2501
3673
  "purchase",
2502
3674
  "subscription",
2503
3675
  "rewarded-ad",
@@ -2514,14 +3686,14 @@ var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
2514
3686
  "event",
2515
3687
  "competition"
2516
3688
  ]);
2517
- var ACTIVITY_STATUSES = /* @__PURE__ */ new Set([
3689
+ var ACTIVITY_STATUSES2 = /* @__PURE__ */ new Set([
2518
3690
  "pending",
2519
3691
  "held",
2520
3692
  "settled",
2521
3693
  "reversed",
2522
3694
  "failed"
2523
3695
  ]);
2524
- var ACTIVITY_SOURCES = /* @__PURE__ */ new Set([
3696
+ var ACTIVITY_SOURCES2 = /* @__PURE__ */ new Set([
2525
3697
  "shopify",
2526
3698
  "ayet",
2527
3699
  "bitlabs",
@@ -2551,7 +3723,7 @@ function assertActivityEntry(entry) {
2551
3723
  );
2552
3724
  assertEconomyIdentifier(entry.transactionId, "transactionId");
2553
3725
  economyAssert(
2554
- ACTIVITY_TYPES.has(entry.activityType) && ACTIVITY_STATUSES.has(entry.status) && ACTIVITY_SOURCES.has(entry.source),
3726
+ ACTIVITY_TYPES2.has(entry.activityType) && ACTIVITY_STATUSES2.has(entry.status) && ACTIVITY_SOURCES2.has(entry.source),
2555
3727
  "INVALID_CONTRACT",
2556
3728
  "Activity type, status, or source is unsupported"
2557
3729
  );
@@ -2589,7 +3761,7 @@ function assertBalancedTransaction(transaction) {
2589
3761
  assertEconomyIdentifier(transaction.transactionId, "transactionId");
2590
3762
  assertEconomyIdentifier(transaction.idempotencyKey, "idempotencyKey");
2591
3763
  economyAssert(
2592
- ACTIVITY_TYPES.has(transaction.activityType) && ACTIVITY_STATUSES.has(transaction.status),
3764
+ ACTIVITY_TYPES2.has(transaction.activityType) && ACTIVITY_STATUSES2.has(transaction.status),
2593
3765
  "INVALID_CONTRACT",
2594
3766
  "Transaction activity type or status is unsupported"
2595
3767
  );
@@ -4628,7 +5800,7 @@ var DECISIONS = /* @__PURE__ */ new Set([
4628
5800
  "approve",
4629
5801
  "reject"
4630
5802
  ]);
4631
- function assertExactKeys3(value, allowed, label) {
5803
+ function assertExactKeys4(value, allowed, label) {
4632
5804
  economyAssert(
4633
5805
  value !== null && typeof value === "object" && !Array.isArray(value),
4634
5806
  "INVALID_CONTRACT",
@@ -4655,7 +5827,7 @@ function assertReasonCode(reasonCode) {
4655
5827
  );
4656
5828
  }
4657
5829
  function assertOperatorAdjustmentPreview(preview) {
4658
- assertExactKeys3(preview, PREVIEW_KEYS, "Operator adjustment preview");
5830
+ assertExactKeys4(preview, PREVIEW_KEYS, "Operator adjustment preview");
4659
5831
  economyAssert(
4660
5832
  preview.schemaVersion === ECONOMY_CONTRACT_VERSION && OPERATIONS.has(preview.operation) && TARGET_COMPONENTS.has(preview.targetComponent) && TRANSFER_POLICIES.has(preview.transferPolicy) && preview.refundPolicy === "not-refundable",
4661
5833
  "INVALID_CONTRACT",
@@ -4734,7 +5906,7 @@ function canonicalOperatorAdjustmentPreviewPayload(preview) {
4734
5906
  function assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash) {
4735
5907
  assertOperatorAdjustmentPreview(preview);
4736
5908
  assertCanonicalHash6(expectedPreviewHash, "expectedPreviewHash");
4737
- assertExactKeys3(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
5909
+ assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
4738
5910
  economyAssert(
4739
5911
  proposal.schemaVersion === ECONOMY_CONTRACT_VERSION && proposal.status === "pending-approval",
4740
5912
  "INVALID_CONTRACT",
@@ -4761,7 +5933,7 @@ function assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash
4761
5933
  );
4762
5934
  }
4763
5935
  function canonicalOperatorAdjustmentProposalPayload(proposal) {
4764
- assertExactKeys3(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
5936
+ assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
4765
5937
  return JSON.stringify({
4766
5938
  schemaVersion: proposal.schemaVersion,
4767
5939
  proposalId: proposal.proposalId,
@@ -4776,7 +5948,7 @@ function canonicalOperatorAdjustmentProposalPayload(proposal) {
4776
5948
  function assertOperatorAdjustmentDecision(decision, proposal, preview, expectedPreviewHash, expectedProposalHash) {
4777
5949
  assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash);
4778
5950
  assertCanonicalHash6(expectedProposalHash, "expectedProposalHash");
4779
- assertExactKeys3(decision, DECISION_KEYS, "Operator adjustment decision");
5951
+ assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
4780
5952
  economyAssert(
4781
5953
  decision.schemaVersion === ECONOMY_CONTRACT_VERSION && DECISIONS.has(decision.decision),
4782
5954
  "INVALID_CONTRACT",
@@ -4819,7 +5991,7 @@ function assertOperatorAdjustmentDecision(decision, proposal, preview, expectedP
4819
5991
  );
4820
5992
  }
4821
5993
  function canonicalOperatorAdjustmentDecisionPayload(decision) {
4822
- assertExactKeys3(decision, DECISION_KEYS, "Operator adjustment decision");
5994
+ assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
4823
5995
  return JSON.stringify({
4824
5996
  schemaVersion: decision.schemaVersion,
4825
5997
  decisionId: decision.decisionId,
@@ -4843,7 +6015,7 @@ function assertOperatorAdjustmentExecution(execution, preview, proposal, decisio
4843
6015
  expectedProposalHash
4844
6016
  );
4845
6017
  assertCanonicalHash6(expectedDecisionHash, "expectedDecisionHash");
4846
- assertExactKeys3(execution, EXECUTION_KEYS, "Operator adjustment execution");
6018
+ assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
4847
6019
  economyAssert(
4848
6020
  execution.schemaVersion === ECONOMY_CONTRACT_VERSION,
4849
6021
  "INVALID_CONTRACT",
@@ -4874,7 +6046,7 @@ function assertOperatorAdjustmentExecution(execution, preview, proposal, decisio
4874
6046
  );
4875
6047
  }
4876
6048
  function canonicalOperatorAdjustmentExecutionPayload(execution) {
4877
- assertExactKeys3(execution, EXECUTION_KEYS, "Operator adjustment execution");
6049
+ assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
4878
6050
  return JSON.stringify({
4879
6051
  schemaVersion: execution.schemaVersion,
4880
6052
  executionId: execution.executionId,
@@ -5919,7 +7091,7 @@ function createProjectionSnapshot(transactions, rebuiltAt) {
5919
7091
  }
5920
7092
 
5921
7093
  // src/ports/query.ts
5922
- var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
7094
+ var ACTIVITY_TYPES3 = /* @__PURE__ */ new Set([
5923
7095
  "purchase",
5924
7096
  "subscription",
5925
7097
  "rewarded-ad",
@@ -5936,14 +7108,14 @@ var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
5936
7108
  "event",
5937
7109
  "competition"
5938
7110
  ]);
5939
- var ACTIVITY_STATUSES2 = /* @__PURE__ */ new Set([
7111
+ var ACTIVITY_STATUSES3 = /* @__PURE__ */ new Set([
5940
7112
  "pending",
5941
7113
  "held",
5942
7114
  "settled",
5943
7115
  "reversed",
5944
7116
  "failed"
5945
7117
  ]);
5946
- var ACTIVITY_SOURCES2 = /* @__PURE__ */ new Set([
7118
+ var ACTIVITY_SOURCES3 = /* @__PURE__ */ new Set([
5947
7119
  "shopify",
5948
7120
  "ayet",
5949
7121
  "bitlabs",
@@ -5971,14 +7143,14 @@ function assertSafeDisplayString(value, label) {
5971
7143
  `${label} must be bounded and safe for display`
5972
7144
  );
5973
7145
  }
5974
- function assertOpaqueCursor(value) {
7146
+ function assertOpaqueCursor2(value) {
5975
7147
  economyAssert(
5976
7148
  typeof value === "string" && value.length > 0 && value.length <= 512 && !hasControlCharacters2(value),
5977
7149
  "INVALID_CONTRACT",
5978
7150
  "Activity cursor must be a bounded opaque value"
5979
7151
  );
5980
7152
  }
5981
- function assertUniqueValues(values, allowed, label) {
7153
+ function assertUniqueValues2(values, allowed, label) {
5982
7154
  const unique = new Set(values);
5983
7155
  economyAssert(
5984
7156
  values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
@@ -6241,7 +7413,7 @@ function assertWalletActivityEntry(entry) {
6241
7413
  assertEconomyIdentifier(entry.activityId, "activityId");
6242
7414
  assertEconomyIdentifier(entry.walletId, "walletId");
6243
7415
  economyAssert(
6244
- ACTIVITY_TYPES2.has(entry.activityType) && ACTIVITY_STATUSES2.has(entry.status) && ACTIVITY_SOURCES2.has(entry.source),
7416
+ ACTIVITY_TYPES3.has(entry.activityType) && ACTIVITY_STATUSES3.has(entry.status) && ACTIVITY_SOURCES3.has(entry.source),
6245
7417
  "INVALID_CONTRACT",
6246
7418
  "Wallet activity type, status, or source is unsupported"
6247
7419
  );
@@ -6289,20 +7461,20 @@ function assertWalletActivityPageRequest(request) {
6289
7461
  "Activity page limit must be between one and 100"
6290
7462
  );
6291
7463
  if (request.cursor !== void 0) {
6292
- assertOpaqueCursor(request.cursor);
7464
+ assertOpaqueCursor2(request.cursor);
6293
7465
  }
6294
7466
  const filter = request.filter;
6295
7467
  if (filter === void 0) {
6296
7468
  return;
6297
7469
  }
6298
7470
  if (filter.activityTypes !== void 0) {
6299
- assertUniqueValues(filter.activityTypes, ACTIVITY_TYPES2, "Activity types");
7471
+ assertUniqueValues2(filter.activityTypes, ACTIVITY_TYPES3, "Activity types");
6300
7472
  }
6301
7473
  if (filter.statuses !== void 0) {
6302
- assertUniqueValues(filter.statuses, ACTIVITY_STATUSES2, "Activity statuses");
7474
+ assertUniqueValues2(filter.statuses, ACTIVITY_STATUSES3, "Activity statuses");
6303
7475
  }
6304
7476
  if (filter.sources !== void 0) {
6305
- assertUniqueValues(filter.sources, ACTIVITY_SOURCES2, "Activity sources");
7477
+ assertUniqueValues2(filter.sources, ACTIVITY_SOURCES3, "Activity sources");
6306
7478
  }
6307
7479
  if (filter.beneficiaryAccountId !== void 0) {
6308
7480
  assertEconomyIdentifier(
@@ -6335,7 +7507,7 @@ function assertWalletActivityPage(page) {
6335
7507
  "Activity pages are bounded and cannot advertise more rows from an empty page"
6336
7508
  );
6337
7509
  if (page.nextCursor !== void 0) {
6338
- assertOpaqueCursor(page.nextCursor);
7510
+ assertOpaqueCursor2(page.nextCursor);
6339
7511
  }
6340
7512
  const activityIds = /* @__PURE__ */ new Set();
6341
7513
  let previous;
@@ -7317,7 +8489,7 @@ var RESULT_OUTCOMES = /* @__PURE__ */ new Set([
7317
8489
  "failed",
7318
8490
  "no-op"
7319
8491
  ]);
7320
- var ACTIVITY_TYPES3 = /* @__PURE__ */ new Set([
8492
+ var ACTIVITY_TYPES4 = /* @__PURE__ */ new Set([
7321
8493
  "purchase",
7322
8494
  "subscription",
7323
8495
  "rewarded-ad",
@@ -7429,7 +8601,7 @@ var PORTABLE_KEYS = /* @__PURE__ */ new Set([
7429
8601
  "signature",
7430
8602
  ...PORTABLE_BODY_KEYS
7431
8603
  ]);
7432
- function assertExactKeys4(value, allowedKeys, label) {
8604
+ function assertExactKeys5(value, allowedKeys, label) {
7433
8605
  economyAssert(
7434
8606
  value !== null && typeof value === "object" && !Array.isArray(value),
7435
8607
  "INVALID_CONTRACT",
@@ -7518,7 +8690,7 @@ function canonicalSignatureMetadata(signature) {
7518
8690
  };
7519
8691
  }
7520
8692
  function assertEconomySealedRecoveryPayload(payload) {
7521
- assertExactKeys4(
8693
+ assertExactKeys5(
7522
8694
  payload,
7523
8695
  /* @__PURE__ */ new Set([
7524
8696
  "schemaVersion",
@@ -7558,7 +8730,7 @@ function assertEconomySealedRecoveryPayload(payload) {
7558
8730
  );
7559
8731
  }
7560
8732
  function assertAcceptanceBody(body) {
7561
- assertExactKeys4(
8733
+ assertExactKeys5(
7562
8734
  body,
7563
8735
  "acceptanceEnvelopeId" in body ? ACCEPTANCE_KEYS : ACCEPTANCE_BODY_KEYS,
7564
8736
  "Recovery acceptance body"
@@ -7627,7 +8799,7 @@ function createEconomyRecoveryAcceptanceEnvelope(body, hashCanonicalPayload2) {
7627
8799
  };
7628
8800
  }
7629
8801
  function assertEconomyRecoveryAcceptanceEnvelope(envelope, hashCanonicalPayload2) {
7630
- assertExactKeys4(envelope, ACCEPTANCE_KEYS, "Recovery acceptance envelope");
8802
+ assertExactKeys5(envelope, ACCEPTANCE_KEYS, "Recovery acceptance envelope");
7631
8803
  assertAcceptanceBody(envelope);
7632
8804
  assertEconomyIdentifier(
7633
8805
  envelope.acceptanceEnvelopeId,
@@ -7668,7 +8840,7 @@ function canonicalEconomyRecoveryAcceptanceEnvelopePayload(envelope, hashCanonic
7668
8840
  });
7669
8841
  }
7670
8842
  function assertCommittedResultBody(body) {
7671
- assertExactKeys4(
8843
+ assertExactKeys5(
7672
8844
  body,
7673
8845
  "committedResultId" in body ? COMMITTED_RESULT_KEYS : COMMITTED_RESULT_BODY_KEYS,
7674
8846
  "Recovery committed-result body"
@@ -7762,7 +8934,7 @@ function createEconomyRecoveryCommittedResult(body, hashCanonicalPayload2) {
7762
8934
  };
7763
8935
  }
7764
8936
  function assertEconomyRecoveryCommittedResult(result, hashCanonicalPayload2) {
7765
- assertExactKeys4(
8937
+ assertExactKeys5(
7766
8938
  result,
7767
8939
  COMMITTED_RESULT_KEYS,
7768
8940
  "Recovery committed result"
@@ -7821,7 +8993,7 @@ function assertEconomyRecoveryResultLink(acceptance, result, hashCanonicalPayloa
7821
8993
  );
7822
8994
  }
7823
8995
  function assertEconomyEvidenceSignatureMetadata(signature) {
7824
- assertExactKeys4(
8996
+ assertExactKeys5(
7825
8997
  signature,
7826
8998
  /* @__PURE__ */ new Set([
7827
8999
  "schemaVersion",
@@ -7841,7 +9013,7 @@ function assertEconomyEvidenceSignatureMetadata(signature) {
7841
9013
  parseIsoTimestamp(signature.signedAt);
7842
9014
  }
7843
9015
  function assertEconomyEvidenceSignature(signature) {
7844
- assertExactKeys4(
9016
+ assertExactKeys5(
7845
9017
  signature,
7846
9018
  /* @__PURE__ */ new Set([
7847
9019
  "schemaVersion",
@@ -7863,7 +9035,7 @@ function assertEconomyEvidenceSignature(signature) {
7863
9035
  assertBase64url(signature.value, "Evidence signature value", 32, 2048);
7864
9036
  }
7865
9037
  function assertRegionalEvidenceBody(body) {
7866
- assertExactKeys4(
9038
+ assertExactKeys5(
7867
9039
  body,
7868
9040
  "evidenceReceiptId" in body ? REGIONAL_KEYS : REGIONAL_BODY_KEYS,
7869
9041
  "Regional evidence-receipt body"
@@ -7955,7 +9127,7 @@ function createEconomyRegionalEvidenceReceipt(body, signature, hashCanonicalPayl
7955
9127
  };
7956
9128
  }
7957
9129
  function assertEconomyRegionalEvidenceReceipt(receipt, hashCanonicalPayload2) {
7958
- assertExactKeys4(receipt, REGIONAL_KEYS, "Regional evidence receipt");
9130
+ assertExactKeys5(receipt, REGIONAL_KEYS, "Regional evidence receipt");
7959
9131
  assertRegionalEvidenceBody(receipt);
7960
9132
  assertEconomyIdentifier(receipt.evidenceReceiptId, "evidenceReceiptId");
7961
9133
  assertEconomyEvidenceSignature(receipt.signature);
@@ -8157,7 +9329,7 @@ function assertEconomyRegionalEvidenceEquality(receipts, expectedRegions, hashCa
8157
9329
  );
8158
9330
  }
8159
9331
  function assertEconomyMerkleInclusionProof(proof) {
8160
- assertExactKeys4(
9332
+ assertExactKeys5(
8161
9333
  proof,
8162
9334
  /* @__PURE__ */ new Set([
8163
9335
  "schemaVersion",
@@ -8188,7 +9360,7 @@ function assertEconomyMerkleInclusionProof(proof) {
8188
9360
  "Merkle leaf position is outside its bounded tree"
8189
9361
  );
8190
9362
  for (const step of proof.siblings) {
8191
- assertExactKeys4(
9363
+ assertExactKeys5(
8192
9364
  step,
8193
9365
  /* @__PURE__ */ new Set(["schemaVersion", "side", "hash"]),
8194
9366
  "Merkle proof step"
@@ -8277,7 +9449,7 @@ function assertEconomyMerkleInclusion(proof, anchor, hashCanonicalPayload2) {
8277
9449
  );
8278
9450
  }
8279
9451
  function assertPortableEvidenceReference(reference) {
8280
- assertExactKeys4(
9452
+ assertExactKeys5(
8281
9453
  reference,
8282
9454
  /* @__PURE__ */ new Set([
8283
9455
  "schemaVersion",
@@ -8314,7 +9486,7 @@ function canonicalPortableEvidenceReference(reference) {
8314
9486
  };
8315
9487
  }
8316
9488
  function assertPortableBody(body) {
8317
- assertExactKeys4(
9489
+ assertExactKeys5(
8318
9490
  body,
8319
9491
  "portableReceiptId" in body ? PORTABLE_KEYS : PORTABLE_BODY_KEYS,
8320
9492
  "Portable customer-receipt body"
@@ -8338,7 +9510,7 @@ function assertPortableBody(body) {
8338
9510
  assertEconomyIdentifier(value, label);
8339
9511
  }
8340
9512
  economyAssert(
8341
- ACTIVITY_TYPES3.has(body.activityType) && (body.direction === "credit" || body.direction === "debit"),
9513
+ ACTIVITY_TYPES4.has(body.activityType) && (body.direction === "credit" || body.direction === "debit"),
8342
9514
  "INVALID_CONTRACT",
8343
9515
  "Portable customer receipt has an unsupported activity or direction"
8344
9516
  );
@@ -8438,7 +9610,7 @@ function createEconomyPortableCustomerReceipt(body, signature, hashCanonicalPayl
8438
9610
  };
8439
9611
  }
8440
9612
  function assertEconomyPortableCustomerReceipt(receipt, hashCanonicalPayload2) {
8441
- assertExactKeys4(receipt, PORTABLE_KEYS, "Portable customer receipt");
9613
+ assertExactKeys5(receipt, PORTABLE_KEYS, "Portable customer receipt");
8442
9614
  assertPortableBody(receipt);
8443
9615
  assertEconomyIdentifier(receipt.portableReceiptId, "portableReceiptId");
8444
9616
  assertEconomyEvidenceSignature(receipt.signature);
@@ -8738,7 +9910,7 @@ var DOCUMENT_ID_KEYS = /* @__PURE__ */ new Set([
8738
9910
  "lifetimeProjectionId",
8739
9911
  "outboxEventId"
8740
9912
  ]);
8741
- function assertExactKeys5(value, allowed, label) {
9913
+ function assertExactKeys6(value, allowed, label) {
8742
9914
  economyAssert(
8743
9915
  value !== null && typeof value === "object" && !Array.isArray(value),
8744
9916
  "INVALID_CONTRACT",
@@ -8778,7 +9950,7 @@ function createPersonalWalletInitializationDocumentIds(subjectAccountId, hash) {
8778
9950
  };
8779
9951
  }
8780
9952
  function assertPersonalWalletInitializationCommand(command) {
8781
- assertExactKeys5(command, COMMAND_KEYS, "Wallet initialization command");
9953
+ assertExactKeys6(command, COMMAND_KEYS, "Wallet initialization command");
8782
9954
  economyAssert(
8783
9955
  command.schemaVersion === ECONOMY_CONTRACT_VERSION && command.commandType === "initialize-wallet" && command.walletKind === "personal",
8784
9956
  "INVALID_CONTRACT",
@@ -8802,7 +9974,7 @@ function canonicalPersonalWalletInitializationCommandPayload(command) {
8802
9974
  });
8803
9975
  }
8804
9976
  function assertPersonalWalletInitializationOutboxIntent(intent) {
8805
- assertExactKeys5(intent, OUTBOX_KEYS, "Wallet initialization outbox intent");
9977
+ assertExactKeys6(intent, OUTBOX_KEYS, "Wallet initialization outbox intent");
8806
9978
  economyAssert(
8807
9979
  intent.schemaVersion === ECONOMY_CONTRACT_VERSION && intent.eventType === "wallet.initialized.v1",
8808
9980
  "INVALID_CONTRACT",
@@ -8902,8 +10074,8 @@ function createPersonalWalletInitializationState(input, hash) {
8902
10074
  return state;
8903
10075
  }
8904
10076
  function assertPersonalWalletInitializationState(state) {
8905
- assertExactKeys5(state, STATE_KEYS, "Wallet initialization state");
8906
- assertExactKeys5(
10077
+ assertExactKeys6(state, STATE_KEYS, "Wallet initialization state");
10078
+ assertExactKeys6(
8907
10079
  state.documentIds,
8908
10080
  DOCUMENT_ID_KEYS,
8909
10081
  "Wallet initialization document IDs"
@@ -8935,6 +10107,13 @@ function assertPersonalWalletInitializationState(state) {
8935
10107
  }
8936
10108
  // Annotate the CommonJS export names for ESM import in node:
8937
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,
8938
10117
  BASELINE_GBP_CATALOG_VERSION,
8939
10118
  BASELINE_GBP_REFERENCE_RATE,
8940
10119
  BASELINE_GBP_TOKEN_PACKS,
@@ -8962,6 +10141,19 @@ function assertPersonalWalletInitializationState(state) {
8962
10141
  applyWalletBalanceDelta,
8963
10142
  applyWalletLifetimeDeltas,
8964
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,
8965
10157
  assertAuditedEconomyCommandEnvelope,
8966
10158
  assertBalancedTransaction,
8967
10159
  assertDeterministicWalletBalanceSummary,
@@ -9091,6 +10283,9 @@ function assertPersonalWalletInitializationState(state) {
9091
10283
  canonicalTransactionPayload,
9092
10284
  closeModuleAllowance,
9093
10285
  convertRewardPayout,
10286
+ createAdminTokenAnomalyIndicator,
10287
+ createAdminTokenAnomalyUnavailable,
10288
+ createDefaultAdminTokenReportingWindow,
9094
10289
  createEarlyBackerRetentionFromPaidLot,
9095
10290
  createEconomyPortableCustomerReceipt,
9096
10291
  createEconomyRecoveryAcceptanceEnvelope,