@plasius/economy 0.1.0 → 0.2.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.d.cts CHANGED
@@ -39,6 +39,52 @@ declare function parseIsoTimestamp(value: IsoTimestamp): number;
39
39
  /** Returns a new record with keys sorted for canonical serialization. */
40
40
  declare function sortStringRecord(value: Readonly<Record<string, string>>): Readonly<Record<string, string>>;
41
41
 
42
+ type TokenSource = "shopify" | "ayet" | "bitlabs" | "subscription" | "event" | "competition" | "adjustment";
43
+ type LotTransferPolicy = "household-allocatable" | "same-user-only" | "non-transferable";
44
+ type LotRefundState = "none" | "partial" | "refunded" | "disputed" | "chargeback-lost";
45
+ interface SourceLotV1 {
46
+ readonly schemaVersion: EconomyContractVersion;
47
+ readonly lotId: LotId;
48
+ readonly walletId: WalletId;
49
+ readonly beneficiaryAccountId: AccountId;
50
+ readonly householdId?: HouseholdId;
51
+ readonly payerAccountId?: AccountId;
52
+ readonly source: TokenSource;
53
+ readonly providerEventId?: ProviderEventId;
54
+ readonly rateVersion: string;
55
+ readonly settlementEvidenceHash: string;
56
+ readonly transferPolicy: LotTransferPolicy;
57
+ readonly refundState: LotRefundState;
58
+ readonly originalAmount: TokenSubunitString;
59
+ readonly remainingAmount: TokenSubunitString;
60
+ readonly heldAmount: TokenSubunitString;
61
+ readonly reversedAmount: TokenSubunitString;
62
+ readonly settledAt: IsoTimestamp;
63
+ readonly creditedAt: IsoTimestamp;
64
+ readonly cohortKey?: string;
65
+ }
66
+ type LotUseOperation = "allocate" | "spend" | "reclaim" | "refund";
67
+ interface LotUseContextV1 {
68
+ readonly operation: LotUseOperation;
69
+ readonly beneficiaryAccountId: AccountId;
70
+ readonly householdId?: HouseholdId;
71
+ }
72
+ interface SourceLotSliceV1 {
73
+ readonly lotId: LotId;
74
+ readonly amount: TokenSubunitString;
75
+ }
76
+ /** Validates source-lot arithmetic, evidence, and immutable provenance fields. */
77
+ declare function assertSourceLot(lot: SourceLotV1): void;
78
+ /** Returns unheld, unconsumed TokenSubunits in a source lot. */
79
+ declare function availableSourceLotAmount(lot: SourceLotV1): bigint;
80
+ /** Evaluates provider/source restrictions without trusting a browser claim. */
81
+ declare function canUseSourceLot(lot: SourceLotV1, context: LotUseContextV1): boolean;
82
+ /**
83
+ * Selects eligible lots deterministically in credited-time/lot-id order.
84
+ * The returned slices are a proposal; persistence must consume them atomically.
85
+ */
86
+ declare function selectSourceLots(lots: readonly SourceLotV1[], requestedAmount: TokenSubunitString, context: LotUseContextV1): readonly SourceLotSliceV1[];
87
+
42
88
  type ActivityType = "purchase" | "subscription" | "rewarded-ad" | "offerwall" | "allocation" | "boost" | "reclaim" | "spend" | "hold" | "refund" | "chargeback" | "adjustment" | "reversal" | "event" | "competition";
43
89
  type ActivityStatus = "pending" | "held" | "settled" | "reversed" | "failed";
44
90
  /** One signed side of an immutable double-entry transaction. */
@@ -75,6 +121,8 @@ interface ActivityEntryV1 {
75
121
  readonly status: ActivityStatus;
76
122
  readonly occurredAt: IsoTimestamp;
77
123
  readonly amount: TokenSubunitString;
124
+ /** Stable source identity used for filtering and provenance presentation. */
125
+ readonly source: TokenSource;
78
126
  readonly beneficiaryAccountId?: AccountId;
79
127
  readonly maskedReference?: string;
80
128
  readonly sourceLabel: string;
@@ -217,52 +265,6 @@ declare function convertRewardPayout(providerPayoutMinorUnits: string, rate: Rew
217
265
  /** Maps BitLabs' signed callback state into an immutable journal transition. */
218
266
  declare function mapBitLabsConversionState(state: string): RewardActivityTransitionV1;
219
267
 
220
- type TokenSource = "shopify" | "ayet" | "bitlabs" | "subscription" | "event" | "competition" | "adjustment";
221
- type LotTransferPolicy = "household-allocatable" | "same-user-only" | "non-transferable";
222
- type LotRefundState = "none" | "partial" | "refunded" | "disputed" | "chargeback-lost";
223
- interface SourceLotV1 {
224
- readonly schemaVersion: EconomyContractVersion;
225
- readonly lotId: LotId;
226
- readonly walletId: WalletId;
227
- readonly beneficiaryAccountId: AccountId;
228
- readonly householdId?: HouseholdId;
229
- readonly payerAccountId?: AccountId;
230
- readonly source: TokenSource;
231
- readonly providerEventId?: ProviderEventId;
232
- readonly rateVersion: string;
233
- readonly settlementEvidenceHash: string;
234
- readonly transferPolicy: LotTransferPolicy;
235
- readonly refundState: LotRefundState;
236
- readonly originalAmount: TokenSubunitString;
237
- readonly remainingAmount: TokenSubunitString;
238
- readonly heldAmount: TokenSubunitString;
239
- readonly reversedAmount: TokenSubunitString;
240
- readonly settledAt: IsoTimestamp;
241
- readonly creditedAt: IsoTimestamp;
242
- readonly cohortKey?: string;
243
- }
244
- type LotUseOperation = "allocate" | "spend" | "reclaim" | "refund";
245
- interface LotUseContextV1 {
246
- readonly operation: LotUseOperation;
247
- readonly beneficiaryAccountId: AccountId;
248
- readonly householdId?: HouseholdId;
249
- }
250
- interface SourceLotSliceV1 {
251
- readonly lotId: LotId;
252
- readonly amount: TokenSubunitString;
253
- }
254
- /** Validates source-lot arithmetic, evidence, and immutable provenance fields. */
255
- declare function assertSourceLot(lot: SourceLotV1): void;
256
- /** Returns unheld, unconsumed TokenSubunits in a source lot. */
257
- declare function availableSourceLotAmount(lot: SourceLotV1): bigint;
258
- /** Evaluates provider/source restrictions without trusting a browser claim. */
259
- declare function canUseSourceLot(lot: SourceLotV1, context: LotUseContextV1): boolean;
260
- /**
261
- * Selects eligible lots deterministically in credited-time/lot-id order.
262
- * The returned slices are a proposal; persistence must consume them atomically.
263
- */
264
- declare function selectSourceLots(lots: readonly SourceLotV1[], requestedAmount: TokenSubunitString, context: LotUseContextV1): readonly SourceLotSliceV1[];
265
-
266
268
  type AllocationStatus = "active" | "closed";
267
269
  type PeriodicLimitWindow = "daily" | "weekly" | "monthly";
268
270
  interface GameplayLimitsV1 {
package/dist/index.d.ts CHANGED
@@ -39,6 +39,52 @@ declare function parseIsoTimestamp(value: IsoTimestamp): number;
39
39
  /** Returns a new record with keys sorted for canonical serialization. */
40
40
  declare function sortStringRecord(value: Readonly<Record<string, string>>): Readonly<Record<string, string>>;
41
41
 
42
+ type TokenSource = "shopify" | "ayet" | "bitlabs" | "subscription" | "event" | "competition" | "adjustment";
43
+ type LotTransferPolicy = "household-allocatable" | "same-user-only" | "non-transferable";
44
+ type LotRefundState = "none" | "partial" | "refunded" | "disputed" | "chargeback-lost";
45
+ interface SourceLotV1 {
46
+ readonly schemaVersion: EconomyContractVersion;
47
+ readonly lotId: LotId;
48
+ readonly walletId: WalletId;
49
+ readonly beneficiaryAccountId: AccountId;
50
+ readonly householdId?: HouseholdId;
51
+ readonly payerAccountId?: AccountId;
52
+ readonly source: TokenSource;
53
+ readonly providerEventId?: ProviderEventId;
54
+ readonly rateVersion: string;
55
+ readonly settlementEvidenceHash: string;
56
+ readonly transferPolicy: LotTransferPolicy;
57
+ readonly refundState: LotRefundState;
58
+ readonly originalAmount: TokenSubunitString;
59
+ readonly remainingAmount: TokenSubunitString;
60
+ readonly heldAmount: TokenSubunitString;
61
+ readonly reversedAmount: TokenSubunitString;
62
+ readonly settledAt: IsoTimestamp;
63
+ readonly creditedAt: IsoTimestamp;
64
+ readonly cohortKey?: string;
65
+ }
66
+ type LotUseOperation = "allocate" | "spend" | "reclaim" | "refund";
67
+ interface LotUseContextV1 {
68
+ readonly operation: LotUseOperation;
69
+ readonly beneficiaryAccountId: AccountId;
70
+ readonly householdId?: HouseholdId;
71
+ }
72
+ interface SourceLotSliceV1 {
73
+ readonly lotId: LotId;
74
+ readonly amount: TokenSubunitString;
75
+ }
76
+ /** Validates source-lot arithmetic, evidence, and immutable provenance fields. */
77
+ declare function assertSourceLot(lot: SourceLotV1): void;
78
+ /** Returns unheld, unconsumed TokenSubunits in a source lot. */
79
+ declare function availableSourceLotAmount(lot: SourceLotV1): bigint;
80
+ /** Evaluates provider/source restrictions without trusting a browser claim. */
81
+ declare function canUseSourceLot(lot: SourceLotV1, context: LotUseContextV1): boolean;
82
+ /**
83
+ * Selects eligible lots deterministically in credited-time/lot-id order.
84
+ * The returned slices are a proposal; persistence must consume them atomically.
85
+ */
86
+ declare function selectSourceLots(lots: readonly SourceLotV1[], requestedAmount: TokenSubunitString, context: LotUseContextV1): readonly SourceLotSliceV1[];
87
+
42
88
  type ActivityType = "purchase" | "subscription" | "rewarded-ad" | "offerwall" | "allocation" | "boost" | "reclaim" | "spend" | "hold" | "refund" | "chargeback" | "adjustment" | "reversal" | "event" | "competition";
43
89
  type ActivityStatus = "pending" | "held" | "settled" | "reversed" | "failed";
44
90
  /** One signed side of an immutable double-entry transaction. */
@@ -75,6 +121,8 @@ interface ActivityEntryV1 {
75
121
  readonly status: ActivityStatus;
76
122
  readonly occurredAt: IsoTimestamp;
77
123
  readonly amount: TokenSubunitString;
124
+ /** Stable source identity used for filtering and provenance presentation. */
125
+ readonly source: TokenSource;
78
126
  readonly beneficiaryAccountId?: AccountId;
79
127
  readonly maskedReference?: string;
80
128
  readonly sourceLabel: string;
@@ -217,52 +265,6 @@ declare function convertRewardPayout(providerPayoutMinorUnits: string, rate: Rew
217
265
  /** Maps BitLabs' signed callback state into an immutable journal transition. */
218
266
  declare function mapBitLabsConversionState(state: string): RewardActivityTransitionV1;
219
267
 
220
- type TokenSource = "shopify" | "ayet" | "bitlabs" | "subscription" | "event" | "competition" | "adjustment";
221
- type LotTransferPolicy = "household-allocatable" | "same-user-only" | "non-transferable";
222
- type LotRefundState = "none" | "partial" | "refunded" | "disputed" | "chargeback-lost";
223
- interface SourceLotV1 {
224
- readonly schemaVersion: EconomyContractVersion;
225
- readonly lotId: LotId;
226
- readonly walletId: WalletId;
227
- readonly beneficiaryAccountId: AccountId;
228
- readonly householdId?: HouseholdId;
229
- readonly payerAccountId?: AccountId;
230
- readonly source: TokenSource;
231
- readonly providerEventId?: ProviderEventId;
232
- readonly rateVersion: string;
233
- readonly settlementEvidenceHash: string;
234
- readonly transferPolicy: LotTransferPolicy;
235
- readonly refundState: LotRefundState;
236
- readonly originalAmount: TokenSubunitString;
237
- readonly remainingAmount: TokenSubunitString;
238
- readonly heldAmount: TokenSubunitString;
239
- readonly reversedAmount: TokenSubunitString;
240
- readonly settledAt: IsoTimestamp;
241
- readonly creditedAt: IsoTimestamp;
242
- readonly cohortKey?: string;
243
- }
244
- type LotUseOperation = "allocate" | "spend" | "reclaim" | "refund";
245
- interface LotUseContextV1 {
246
- readonly operation: LotUseOperation;
247
- readonly beneficiaryAccountId: AccountId;
248
- readonly householdId?: HouseholdId;
249
- }
250
- interface SourceLotSliceV1 {
251
- readonly lotId: LotId;
252
- readonly amount: TokenSubunitString;
253
- }
254
- /** Validates source-lot arithmetic, evidence, and immutable provenance fields. */
255
- declare function assertSourceLot(lot: SourceLotV1): void;
256
- /** Returns unheld, unconsumed TokenSubunits in a source lot. */
257
- declare function availableSourceLotAmount(lot: SourceLotV1): bigint;
258
- /** Evaluates provider/source restrictions without trusting a browser claim. */
259
- declare function canUseSourceLot(lot: SourceLotV1, context: LotUseContextV1): boolean;
260
- /**
261
- * Selects eligible lots deterministically in credited-time/lot-id order.
262
- * The returned slices are a proposal; persistence must consume them atomically.
263
- */
264
- declare function selectSourceLots(lots: readonly SourceLotV1[], requestedAmount: TokenSubunitString, context: LotUseContextV1): readonly SourceLotSliceV1[];
265
-
266
268
  type AllocationStatus = "active" | "closed";
267
269
  type PeriodicLimitWindow = "daily" | "weekly" | "monthly";
268
270
  interface GameplayLimitsV1 {
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ function assertInRange(amount) {
37
37
  }
38
38
  function parseTokenSubunits(value) {
39
39
  economyAssert(
40
- CANONICAL_INTEGER.test(value),
40
+ typeof value === "string" && CANONICAL_INTEGER.test(value),
41
41
  "INVALID_AMOUNT",
42
42
  "TokenSubunit amount must be a canonical base-10 integer string"
43
43
  );
@@ -86,12 +86,17 @@ var ECONOMY_CONTRACT_VERSION = "1";
86
86
  var IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
87
87
  function assertEconomyIdentifier(value, label = "identifier") {
88
88
  economyAssert(
89
- IDENTIFIER.test(value),
89
+ typeof value === "string" && IDENTIFIER.test(value),
90
90
  "INVALID_CONTRACT",
91
91
  `${label} must be a non-empty opaque identifier`
92
92
  );
93
93
  }
94
94
  function parseIsoTimestamp(value) {
95
+ economyAssert(
96
+ typeof value === "string",
97
+ "INVALID_CONTRACT",
98
+ "Timestamp must be an ISO-8601 UTC value"
99
+ );
95
100
  const match = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{3}))?Z$/u.exec(
96
101
  value
97
102
  );
@@ -813,6 +818,15 @@ var ACTIVITY_STATUSES = /* @__PURE__ */ new Set([
813
818
  "reversed",
814
819
  "failed"
815
820
  ]);
821
+ var ACTIVITY_SOURCES = /* @__PURE__ */ new Set([
822
+ "shopify",
823
+ "ayet",
824
+ "bitlabs",
825
+ "subscription",
826
+ "event",
827
+ "competition",
828
+ "adjustment"
829
+ ]);
816
830
  function assertCanonicalHash(value, label) {
817
831
  economyAssert(
818
832
  /^sha256:[a-f0-9]{64}$/u.test(value),
@@ -834,9 +848,9 @@ function assertActivityEntry(entry) {
834
848
  );
835
849
  assertEconomyIdentifier(entry.transactionId, "transactionId");
836
850
  economyAssert(
837
- ACTIVITY_TYPES.has(entry.activityType) && ACTIVITY_STATUSES.has(entry.status),
851
+ ACTIVITY_TYPES.has(entry.activityType) && ACTIVITY_STATUSES.has(entry.status) && ACTIVITY_SOURCES.has(entry.source),
838
852
  "INVALID_CONTRACT",
839
- "Activity type or status is unsupported"
853
+ "Activity type, status, or source is unsupported"
840
854
  );
841
855
  parseIsoTimestamp(entry.occurredAt);
842
856
  economyAssert(
@@ -852,13 +866,13 @@ function assertActivityEntry(entry) {
852
866
  }
853
867
  if (entry.maskedReference !== void 0) {
854
868
  economyAssert(
855
- entry.maskedReference.length > 0 && entry.maskedReference.length <= 128 && !hasControlCharacters(entry.maskedReference),
869
+ typeof entry.maskedReference === "string" && entry.maskedReference.length > 0 && entry.maskedReference.length <= 128 && !hasControlCharacters(entry.maskedReference),
856
870
  "INVALID_CONTRACT",
857
871
  "Masked activity references must be bounded and safe for display"
858
872
  );
859
873
  }
860
874
  economyAssert(
861
- entry.sourceLabel.trim().length > 0 && entry.sourceLabel.length <= 128 && !hasControlCharacters(entry.sourceLabel),
875
+ typeof entry.sourceLabel === "string" && entry.sourceLabel.trim().length > 0 && entry.sourceLabel.length <= 128 && !hasControlCharacters(entry.sourceLabel),
862
876
  "INVALID_CONTRACT",
863
877
  "Activity source labels must be bounded and safe for display"
864
878
  );