@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/README.md +7 -1
- package/dist/index.cjs +20 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -46
- package/dist/index.d.ts +48 -46
- package/dist/index.js +20 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
);
|