@mpgd/platform 0.18.0 → 0.20.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/capability-conformance.js +103 -1
- package/dist/commerce-capabilities.d.ts +9 -0
- package/dist/commerce-capabilities.js +24 -0
- package/dist/commerce-conformance.d.ts +518 -0
- package/dist/commerce-conformance.js +2162 -0
- package/dist/commerce-contract.d.ts +222 -0
- package/dist/commerce-contract.js +1 -0
- package/dist/commerce-vectors.d.ts +277 -0
- package/dist/commerce-vectors.js +3089 -0
- package/dist/commerce.d.ts +303 -0
- package/dist/commerce.js +5623 -0
- package/dist/index.d.ts +53 -0
- package/package.json +18 -2
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type { CommerceCapabilities, LogicalProductId, PlatformEvidenceEnvelope, StarterLogicalProductId } from './index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Commerce v2 client contract types (RFC "Client contract"). This module is
|
|
4
|
+
* typia-free on purpose: `./index` references `CommerceProvider` for
|
|
5
|
+
* `PlatformGateway.commerceV2`, and headless consumers type-check
|
|
6
|
+
* `@mpgd/platform` with `skipLibCheck: false` and no DOM lib, where typia's
|
|
7
|
+
* root declarations do not compile. `./commerce` re-exports everything here
|
|
8
|
+
* and builds the validators and JSON Schemas from these same types.
|
|
9
|
+
*
|
|
10
|
+
* The validation tags below are the structural phantom form typia reads
|
|
11
|
+
* (`'typia.tag'`), mirrored field for field from `@typia/interface` so the
|
|
12
|
+
* generated validators and schemas are identical to the typia aliases;
|
|
13
|
+
* `commerce-contract.test.ts` proves that parity and the schema alignment
|
|
14
|
+
* validator compares the committed files byte for byte.
|
|
15
|
+
*/
|
|
16
|
+
type CommerceTag<Props extends object> = {
|
|
17
|
+
'typia.tag'?: Props;
|
|
18
|
+
};
|
|
19
|
+
/** `tags.MinLength<Value>` */
|
|
20
|
+
export type CommerceMinLength<Value extends number> = CommerceTag<{
|
|
21
|
+
target: 'string';
|
|
22
|
+
kind: 'minLength';
|
|
23
|
+
value: Value;
|
|
24
|
+
validate: `${Value} <= $input.length`;
|
|
25
|
+
exclusive: true;
|
|
26
|
+
schema: {
|
|
27
|
+
minLength: Value;
|
|
28
|
+
};
|
|
29
|
+
}>;
|
|
30
|
+
/** `tags.Format<'date-time'>` */
|
|
31
|
+
export type CommerceDateTimeFormat = CommerceTag<{
|
|
32
|
+
target: 'string';
|
|
33
|
+
kind: 'format';
|
|
34
|
+
value: 'date-time';
|
|
35
|
+
validate: '$importInternal("isFormatDateTime")($input)';
|
|
36
|
+
exclusive: ['format', 'pattern'];
|
|
37
|
+
schema: {
|
|
38
|
+
format: 'date-time';
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
41
|
+
/** `tags.Type<'uint32'>` */
|
|
42
|
+
export type CommerceUint32 = CommerceTag<{
|
|
43
|
+
target: 'number';
|
|
44
|
+
kind: 'type';
|
|
45
|
+
value: 'uint32';
|
|
46
|
+
validate: '$importInternal("isTypeUint32")($input)';
|
|
47
|
+
exclusive: true;
|
|
48
|
+
schema: {
|
|
49
|
+
type: 'integer';
|
|
50
|
+
minimum: 0;
|
|
51
|
+
};
|
|
52
|
+
}>;
|
|
53
|
+
/** `tags.Type<'int64'>` */
|
|
54
|
+
export type CommerceInt64 = CommerceTag<{
|
|
55
|
+
target: 'bigint' | 'number';
|
|
56
|
+
kind: 'type';
|
|
57
|
+
value: 'int64';
|
|
58
|
+
validate: {
|
|
59
|
+
number: '$importInternal("isTypeInt64")($input)';
|
|
60
|
+
bigint: 'true';
|
|
61
|
+
};
|
|
62
|
+
exclusive: true;
|
|
63
|
+
schema: {
|
|
64
|
+
type: 'integer';
|
|
65
|
+
};
|
|
66
|
+
}>;
|
|
67
|
+
/** `tags.Minimum<Value>` for a number literal */
|
|
68
|
+
export type CommerceMinimum<Value extends number> = CommerceTag<{
|
|
69
|
+
target: 'number';
|
|
70
|
+
kind: 'minimum';
|
|
71
|
+
value: Value;
|
|
72
|
+
validate: `${Value} <= $input`;
|
|
73
|
+
exclusive: ['minimum', 'exclusiveMinimum'];
|
|
74
|
+
schema: {
|
|
75
|
+
minimum: Value;
|
|
76
|
+
};
|
|
77
|
+
}>;
|
|
78
|
+
export type NonEmptyString = string & CommerceMinLength<1>;
|
|
79
|
+
export type IsoTimestamp = string & CommerceDateTimeFormat;
|
|
80
|
+
export type PositiveQuantity = number & CommerceUint32 & CommerceMinimum<1>;
|
|
81
|
+
export type NonNegativeInteger = number & CommerceUint32;
|
|
82
|
+
/**
|
|
83
|
+
* Open store identifier. Reference providers use 'google-play', 'app-store',
|
|
84
|
+
* 'microsoft-store', 'apps-in-toss', 'devvit', and 'verse8'; a consuming
|
|
85
|
+
* project adds its own, for example a credit wallet id.
|
|
86
|
+
*/
|
|
87
|
+
export type StoreId = NonEmptyString;
|
|
88
|
+
export type PurchaseKind = 'consumable' | 'durable' | 'subscription';
|
|
89
|
+
/**
|
|
90
|
+
* `LogicalProductId` narrowed to its open string branch and tagged non-empty,
|
|
91
|
+
* so validators and the generated schemas carry `minLength: 1`. Starter ids and
|
|
92
|
+
* plain `LogicalProductId` values remain assignable.
|
|
93
|
+
*/
|
|
94
|
+
export type CommerceLogicalProductId = Exclude<LogicalProductId, StarterLogicalProductId> & CommerceMinLength<1>;
|
|
95
|
+
export interface StorePrice {
|
|
96
|
+
readonly formatted: string;
|
|
97
|
+
/** ISO 4217 code or a project-declared code such as a wallet currency. */
|
|
98
|
+
readonly currencyCode: NonEmptyString;
|
|
99
|
+
readonly amountMicros?: number & CommerceInt64;
|
|
100
|
+
}
|
|
101
|
+
export interface StoreOffer {
|
|
102
|
+
readonly offerId: NonEmptyString;
|
|
103
|
+
readonly price: StorePrice;
|
|
104
|
+
readonly title?: string;
|
|
105
|
+
readonly description?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface StoreProduct {
|
|
108
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
109
|
+
readonly store: StoreId;
|
|
110
|
+
readonly storeSku: NonEmptyString;
|
|
111
|
+
readonly kind: PurchaseKind;
|
|
112
|
+
readonly title: string;
|
|
113
|
+
readonly description: string;
|
|
114
|
+
readonly price: StorePrice;
|
|
115
|
+
readonly offers?: readonly StoreOffer[];
|
|
116
|
+
}
|
|
117
|
+
export type StorePurchaseState = 'pending' | 'purchased' | 'revoked';
|
|
118
|
+
export interface StorePurchaseAccountBinding {
|
|
119
|
+
readonly kind: 'obfuscated-account-id' | 'app-account-token' | 'host-identity';
|
|
120
|
+
readonly value?: string;
|
|
121
|
+
}
|
|
122
|
+
export interface StorePurchase {
|
|
123
|
+
readonly store: StoreId;
|
|
124
|
+
/** Store transaction id; a provider derives one when the store has none. */
|
|
125
|
+
readonly transactionId: NonEmptyString;
|
|
126
|
+
readonly originalTransactionId?: NonEmptyString;
|
|
127
|
+
readonly storeSku: NonEmptyString;
|
|
128
|
+
readonly logicalId?: CommerceLogicalProductId;
|
|
129
|
+
readonly quantity: PositiveQuantity;
|
|
130
|
+
readonly state: StorePurchaseState;
|
|
131
|
+
readonly purchasedAt?: IsoTimestamp;
|
|
132
|
+
/** Play purchase token, App Store signed transaction (JWS), or host order id. */
|
|
133
|
+
readonly token: NonEmptyString;
|
|
134
|
+
readonly evidence: PlatformEvidenceEnvelope;
|
|
135
|
+
readonly accountBinding?: StorePurchaseAccountBinding;
|
|
136
|
+
/** Present only for `authority.evidence: 'adapter-settled'`; a reconciler pointer, not a grant. */
|
|
137
|
+
readonly settlement?: {
|
|
138
|
+
readonly ledgerEntryId: NonEmptyString;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export type PurchaseSource = 'shop' | 'stage_fail' | 'result' | 'event';
|
|
142
|
+
export interface RequestPurchaseInput {
|
|
143
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
144
|
+
readonly idempotencyKey: NonEmptyString;
|
|
145
|
+
readonly source: PurchaseSource;
|
|
146
|
+
readonly offerId?: NonEmptyString;
|
|
147
|
+
/** Integer >= 1. Rejected with ITEM_UNAVAILABLE when the provider does not declare `purchase.quantity`. */
|
|
148
|
+
readonly quantity?: PositiveQuantity;
|
|
149
|
+
}
|
|
150
|
+
export type RequestPurchaseResult = {
|
|
151
|
+
readonly outcome: 'launched';
|
|
152
|
+
} | {
|
|
153
|
+
readonly outcome: 'purchased';
|
|
154
|
+
readonly purchase: StorePurchase;
|
|
155
|
+
} | {
|
|
156
|
+
readonly outcome: 'cancelled' | 'failed';
|
|
157
|
+
readonly error: CommerceErrorInfo;
|
|
158
|
+
};
|
|
159
|
+
export type CommerceErrorCode = 'USER_CANCELLED' | 'OUTCOME_UNKNOWN' | 'ALREADY_OWNED' | 'IN_PROGRESS' | 'ITEM_UNAVAILABLE' | 'NOT_PREPARED' | 'NETWORK' | 'STORE_UNAVAILABLE' | 'CONFIGURATION_REQUIRED' | 'ACTION_REQUIRED' | 'ACCOUNT_BINDING_REQUIRED' | 'INSUFFICIENT_BALANCE' | 'INVALID_RESPONSE' | 'UNKNOWN';
|
|
160
|
+
export interface CommerceErrorInfo {
|
|
161
|
+
readonly code: CommerceErrorCode;
|
|
162
|
+
readonly retryable: boolean;
|
|
163
|
+
/** The store's original code, for example PLAY_BILLING_SERVICE_UNAVAILABLE. */
|
|
164
|
+
readonly storeCode?: string;
|
|
165
|
+
readonly message?: string;
|
|
166
|
+
}
|
|
167
|
+
export type CommerceEvent = {
|
|
168
|
+
readonly type: 'purchaseUpdated';
|
|
169
|
+
readonly purchase: StorePurchase;
|
|
170
|
+
} | {
|
|
171
|
+
readonly type: 'purchaseError';
|
|
172
|
+
readonly logicalId?: CommerceLogicalProductId;
|
|
173
|
+
readonly error: CommerceErrorInfo;
|
|
174
|
+
} | {
|
|
175
|
+
readonly type: 'subscriptionUpdated';
|
|
176
|
+
readonly subscription: ActiveSubscription;
|
|
177
|
+
};
|
|
178
|
+
export type FetchProductsType = 'in-app' | 'subscription' | 'all';
|
|
179
|
+
export interface FetchProductsInput {
|
|
180
|
+
readonly logicalIds?: readonly CommerceLogicalProductId[];
|
|
181
|
+
readonly type?: FetchProductsType;
|
|
182
|
+
}
|
|
183
|
+
export interface GetAvailablePurchasesInput {
|
|
184
|
+
readonly includePending?: boolean;
|
|
185
|
+
}
|
|
186
|
+
export interface FinishTransactionInput {
|
|
187
|
+
readonly transactionId: NonEmptyString;
|
|
188
|
+
readonly ledgerEntryId: NonEmptyString;
|
|
189
|
+
readonly isConsumable: boolean;
|
|
190
|
+
}
|
|
191
|
+
export interface FinishTransactionResult {
|
|
192
|
+
readonly finished: boolean;
|
|
193
|
+
}
|
|
194
|
+
export interface CommerceProvider {
|
|
195
|
+
readonly store: StoreId;
|
|
196
|
+
getCapabilities(): Promise<CommerceCapabilities>;
|
|
197
|
+
fetchProducts(input: FetchProductsInput): Promise<readonly StoreProduct[]>;
|
|
198
|
+
/** Returns `launched` when the result arrives later as a `purchaseUpdated` event. */
|
|
199
|
+
requestPurchase(input: RequestPurchaseInput): Promise<RequestPurchaseResult>;
|
|
200
|
+
/** Purchases the store still reports as unfinished. */
|
|
201
|
+
getAvailablePurchases(input?: GetAvailablePurchasesInput): Promise<readonly StorePurchase[]>;
|
|
202
|
+
/** Required when `lifecycle.finish` is 'client' or 'host'. */
|
|
203
|
+
finishTransaction?(input: FinishTransactionInput): Promise<FinishTransactionResult>;
|
|
204
|
+
/** Asks the store to resynchronize, for example `AppStore.sync`. */
|
|
205
|
+
restorePurchases?(): Promise<void>;
|
|
206
|
+
/** Designed, not implemented by any reference store provider. */
|
|
207
|
+
getActiveSubscriptions?(): Promise<readonly ActiveSubscription[]>;
|
|
208
|
+
/** Events emitted before the first listener are delivered to that listener. */
|
|
209
|
+
subscribe(listener: (event: CommerceEvent) => void): () => void;
|
|
210
|
+
}
|
|
211
|
+
export type ActiveSubscriptionState = 'active' | 'lapsed' | 'revoked';
|
|
212
|
+
export interface ActiveSubscription {
|
|
213
|
+
readonly store: StoreId;
|
|
214
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
215
|
+
readonly subscriptionId: NonEmptyString;
|
|
216
|
+
readonly periodIndex: NonNegativeInteger;
|
|
217
|
+
readonly state: ActiveSubscriptionState;
|
|
218
|
+
readonly startedAt: IsoTimestamp;
|
|
219
|
+
readonly expiresAt: IsoTimestamp;
|
|
220
|
+
readonly autoRenew: boolean;
|
|
221
|
+
}
|
|
222
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { type tags } from 'typia';
|
|
2
|
+
import type { ActiveSubscriptionState, CommerceAuthorityCapabilities, CommerceBillingAuthority, CommerceErrorCode, CommerceLifecycleCapabilities, CommerceLogicalProductId, CommercePurchaseCapabilities, CommercePurchaseState, CreditLotOrigin, CreditLotSpendScope, CreditMembershipTerms, PurchaseKind, PurchaseSource, StorePurchaseState } from './commerce.js';
|
|
3
|
+
/**
|
|
4
|
+
* Conformance vector format for docs/specs/commerce/vectors/*.json. A3 adds
|
|
5
|
+
* the runner; A2 fixes the file shape so every provider and the reference
|
|
6
|
+
* runtime read the same fixtures. Step inputs are fixture shorthand: the
|
|
7
|
+
* runner fills the profile's store, quantity 1, request source `shop`, and
|
|
8
|
+
* fake evidence before calling the typed provider.
|
|
9
|
+
*/
|
|
10
|
+
type NonEmptyString = string & tags.MinLength<1>;
|
|
11
|
+
type IsoTimestamp = string & tags.Format<'date-time'>;
|
|
12
|
+
type NonNegativeInteger = number & tags.Type<'uint32'>;
|
|
13
|
+
export interface CommerceConformanceProfile {
|
|
14
|
+
readonly store: NonEmptyString;
|
|
15
|
+
/** Omitted blocks default to all supported. */
|
|
16
|
+
readonly purchase?: CommercePurchaseCapabilities;
|
|
17
|
+
readonly lifecycle?: CommerceLifecycleCapabilities;
|
|
18
|
+
readonly authority?: CommerceAuthorityCapabilities;
|
|
19
|
+
/**
|
|
20
|
+
* The scenario is finish-owner independent: when a caller-supplied provider
|
|
21
|
+
* runs the vector, the runner derives `journal`, `finishCalls`,
|
|
22
|
+
* `verifyRequests`, and `available` from the provider's declared
|
|
23
|
+
* capabilities instead of this fixture profile (RFC "Conformance vectors",
|
|
24
|
+
* adaptive vectors). The reference harness ignores the flag.
|
|
25
|
+
*/
|
|
26
|
+
readonly adaptive?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface CommerceConformanceCatalogEntry {
|
|
29
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
30
|
+
readonly kind: PurchaseKind;
|
|
31
|
+
readonly storeSku: NonEmptyString;
|
|
32
|
+
/** Membership terms for credit-funded subscription products. */
|
|
33
|
+
readonly membership?: CreditMembershipTerms;
|
|
34
|
+
}
|
|
35
|
+
export interface CommerceConformanceWallet {
|
|
36
|
+
readonly currencies: readonly NonEmptyString[] & tags.MinItems<1>;
|
|
37
|
+
readonly billingAuthority: CommerceBillingAuthority;
|
|
38
|
+
}
|
|
39
|
+
/** Fixture purchase; `store`, `quantity`, and `evidence` come from the profile. */
|
|
40
|
+
export interface CommerceConformancePurchaseFixture {
|
|
41
|
+
readonly transactionId: NonEmptyString;
|
|
42
|
+
readonly storeSku: NonEmptyString;
|
|
43
|
+
readonly token: NonEmptyString;
|
|
44
|
+
readonly state: StorePurchaseState;
|
|
45
|
+
readonly originalTransactionId?: NonEmptyString;
|
|
46
|
+
readonly purchasedAt?: IsoTimestamp;
|
|
47
|
+
readonly settlement?: {
|
|
48
|
+
readonly ledgerEntryId: NonEmptyString;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Explicit normalized class; the runner never guesses it from `storeCode`. */
|
|
52
|
+
export interface CommerceConformanceErrorFixture {
|
|
53
|
+
readonly code: CommerceErrorCode;
|
|
54
|
+
readonly retryable: boolean;
|
|
55
|
+
readonly storeCode?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Partial expectation; omitted fields are not assertions. */
|
|
58
|
+
export interface CommerceConformanceErrorExpectation {
|
|
59
|
+
readonly code: CommerceErrorCode;
|
|
60
|
+
readonly retryable?: boolean;
|
|
61
|
+
readonly storeCode?: string;
|
|
62
|
+
}
|
|
63
|
+
export type CommerceConformanceRequestResultFixture = {
|
|
64
|
+
readonly outcome: 'launched';
|
|
65
|
+
} | {
|
|
66
|
+
readonly outcome: 'purchased';
|
|
67
|
+
readonly purchase: CommerceConformancePurchaseFixture;
|
|
68
|
+
} | {
|
|
69
|
+
readonly outcome: 'cancelled' | 'failed';
|
|
70
|
+
readonly error: CommerceConformanceErrorFixture;
|
|
71
|
+
};
|
|
72
|
+
export type CommerceConformanceFinishResultFixture = {
|
|
73
|
+
readonly finished: boolean;
|
|
74
|
+
} | {
|
|
75
|
+
readonly error: CommerceErrorCode;
|
|
76
|
+
};
|
|
77
|
+
export interface CommerceConformanceVerifyDecision {
|
|
78
|
+
readonly status: 'granted' | 'pending' | 'rejected';
|
|
79
|
+
readonly ledgerEntryId?: NonEmptyString;
|
|
80
|
+
readonly finalization?: 'pending' | 'completed';
|
|
81
|
+
readonly alreadyProcessed?: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface CommerceConformanceLotFixture {
|
|
84
|
+
readonly ledgerEntryId: NonEmptyString;
|
|
85
|
+
readonly currency: NonEmptyString;
|
|
86
|
+
readonly amount: number & tags.ExclusiveMinimum<0>;
|
|
87
|
+
readonly origin: CreditLotOrigin;
|
|
88
|
+
readonly createdAt: IsoTimestamp;
|
|
89
|
+
readonly expiresAt?: IsoTimestamp;
|
|
90
|
+
}
|
|
91
|
+
export interface CommerceConformanceSpendInput {
|
|
92
|
+
readonly titleId: NonEmptyString;
|
|
93
|
+
readonly currency: NonEmptyString;
|
|
94
|
+
readonly amount: number & tags.ExclusiveMinimum<0>;
|
|
95
|
+
readonly idempotencyKey: NonEmptyString;
|
|
96
|
+
}
|
|
97
|
+
export interface CommerceConformanceDebitExpectation {
|
|
98
|
+
readonly lotId: NonEmptyString;
|
|
99
|
+
readonly amount: number & tags.ExclusiveMinimum<0>;
|
|
100
|
+
}
|
|
101
|
+
export interface CommerceConformanceSpendExpectation {
|
|
102
|
+
readonly status: 'debited' | 'rejected';
|
|
103
|
+
readonly debits?: readonly CommerceConformanceDebitExpectation[];
|
|
104
|
+
readonly alreadyProcessed?: boolean;
|
|
105
|
+
readonly error?: CommerceConformanceErrorExpectation;
|
|
106
|
+
}
|
|
107
|
+
export interface CommerceConformanceRequestPurchaseExpectation {
|
|
108
|
+
readonly outcome: 'launched' | 'purchased' | 'cancelled' | 'failed';
|
|
109
|
+
readonly error?: CommerceConformanceErrorExpectation;
|
|
110
|
+
}
|
|
111
|
+
export interface CommerceConformanceFetchProductsExpectation {
|
|
112
|
+
readonly logicalIds: readonly CommerceLogicalProductId[];
|
|
113
|
+
}
|
|
114
|
+
export type CommerceConformanceStep = {
|
|
115
|
+
readonly actor: 'runtime';
|
|
116
|
+
readonly action: 'start' | 'stop' | 'reconcile';
|
|
117
|
+
} | {
|
|
118
|
+
readonly actor: 'game';
|
|
119
|
+
readonly action: 'requestPurchase';
|
|
120
|
+
readonly input: {
|
|
121
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
122
|
+
readonly idempotencyKey: NonEmptyString;
|
|
123
|
+
readonly source?: PurchaseSource;
|
|
124
|
+
readonly offerId?: NonEmptyString;
|
|
125
|
+
readonly quantity?: number & tags.Type<'uint32'> & tags.Minimum<1>;
|
|
126
|
+
};
|
|
127
|
+
readonly returns?: CommerceConformanceRequestPurchaseExpectation;
|
|
128
|
+
} | {
|
|
129
|
+
readonly actor: 'game';
|
|
130
|
+
readonly action: 'fetchProducts';
|
|
131
|
+
readonly input?: {
|
|
132
|
+
readonly logicalIds?: readonly CommerceLogicalProductId[];
|
|
133
|
+
readonly type?: 'in-app' | 'subscription' | 'all';
|
|
134
|
+
};
|
|
135
|
+
readonly returns?: CommerceConformanceFetchProductsExpectation;
|
|
136
|
+
} | {
|
|
137
|
+
readonly actor: 'store';
|
|
138
|
+
readonly action: 'complete' | 'update';
|
|
139
|
+
readonly purchase: CommerceConformancePurchaseFixture;
|
|
140
|
+
} | {
|
|
141
|
+
readonly actor: 'store';
|
|
142
|
+
readonly action: 'error';
|
|
143
|
+
readonly logicalId?: CommerceLogicalProductId;
|
|
144
|
+
readonly error: CommerceConformanceErrorFixture;
|
|
145
|
+
} | {
|
|
146
|
+
readonly actor: 'store';
|
|
147
|
+
readonly action: 'queueRequest';
|
|
148
|
+
readonly result: CommerceConformanceRequestResultFixture;
|
|
149
|
+
} | {
|
|
150
|
+
readonly actor: 'store';
|
|
151
|
+
readonly action: 'queueFinish';
|
|
152
|
+
readonly result: CommerceConformanceFinishResultFixture;
|
|
153
|
+
} | {
|
|
154
|
+
readonly actor: 'backend';
|
|
155
|
+
readonly action: 'queueVerify';
|
|
156
|
+
readonly decision: CommerceConformanceVerifyDecision;
|
|
157
|
+
} | {
|
|
158
|
+
readonly actor: 'backend';
|
|
159
|
+
readonly action: 'push';
|
|
160
|
+
readonly transactionId: NonEmptyString;
|
|
161
|
+
readonly entryId: NonEmptyString;
|
|
162
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
163
|
+
} | {
|
|
164
|
+
readonly actor: 'backend';
|
|
165
|
+
readonly action: 'revoke';
|
|
166
|
+
readonly ledgerEntryId: NonEmptyString;
|
|
167
|
+
readonly entryId: NonEmptyString;
|
|
168
|
+
readonly reason: NonEmptyString;
|
|
169
|
+
} | {
|
|
170
|
+
readonly actor: 'wallet';
|
|
171
|
+
readonly action: 'creditFromGrant';
|
|
172
|
+
readonly lot: CommerceConformanceLotFixture;
|
|
173
|
+
} | {
|
|
174
|
+
readonly actor: 'wallet';
|
|
175
|
+
readonly action: 'spend';
|
|
176
|
+
readonly input: CommerceConformanceSpendInput;
|
|
177
|
+
readonly returns?: CommerceConformanceSpendExpectation;
|
|
178
|
+
} | {
|
|
179
|
+
readonly actor: 'wallet';
|
|
180
|
+
readonly action: 'renewDue';
|
|
181
|
+
} | {
|
|
182
|
+
readonly actor: 'clock';
|
|
183
|
+
readonly action: 'set';
|
|
184
|
+
readonly at: IsoTimestamp;
|
|
185
|
+
};
|
|
186
|
+
export type CommerceConformanceActor = CommerceConformanceStep['actor'];
|
|
187
|
+
export type CommerceConformanceAction = CommerceConformanceStep['action'];
|
|
188
|
+
export interface CommerceConformanceVerifyRequestExpectation {
|
|
189
|
+
readonly idempotencyKey: NonEmptyString;
|
|
190
|
+
readonly store: NonEmptyString;
|
|
191
|
+
readonly transactionId: NonEmptyString;
|
|
192
|
+
readonly token: NonEmptyString;
|
|
193
|
+
}
|
|
194
|
+
export interface CommerceConformanceLedgerEntryExpectation {
|
|
195
|
+
readonly entryId: NonEmptyString;
|
|
196
|
+
readonly type: 'grant' | 'revoke' | 'period';
|
|
197
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
198
|
+
/** The grant a `revoke` entry reverses. */
|
|
199
|
+
readonly reverses?: NonEmptyString;
|
|
200
|
+
readonly reason?: NonEmptyString;
|
|
201
|
+
}
|
|
202
|
+
export interface CommerceConformanceFinishCallExpectation {
|
|
203
|
+
readonly by: 'client' | 'host';
|
|
204
|
+
readonly transactionId: NonEmptyString;
|
|
205
|
+
readonly ledgerEntryId: NonEmptyString;
|
|
206
|
+
readonly isConsumable: boolean;
|
|
207
|
+
readonly result: 'finished' | CommerceErrorCode;
|
|
208
|
+
}
|
|
209
|
+
export interface CommerceConformanceAvailableExpectation {
|
|
210
|
+
readonly transactionId: NonEmptyString;
|
|
211
|
+
readonly storeSku?: NonEmptyString;
|
|
212
|
+
readonly state?: StorePurchaseState;
|
|
213
|
+
}
|
|
214
|
+
export interface CommerceConformanceEntitlementExpectation {
|
|
215
|
+
readonly id: NonEmptyString;
|
|
216
|
+
readonly logicalId?: CommerceLogicalProductId;
|
|
217
|
+
}
|
|
218
|
+
export interface CommerceConformanceLotExpectation {
|
|
219
|
+
readonly lotId: NonEmptyString;
|
|
220
|
+
readonly currency?: NonEmptyString;
|
|
221
|
+
readonly amount?: number & tags.ExclusiveMinimum<0>;
|
|
222
|
+
readonly remaining: number & tags.Minimum<0>;
|
|
223
|
+
readonly origin?: CreditLotOrigin;
|
|
224
|
+
readonly spendScope?: CreditLotSpendScope;
|
|
225
|
+
}
|
|
226
|
+
export interface CommerceConformanceScheduledDebitExpectation {
|
|
227
|
+
readonly idempotencyKey: NonEmptyString;
|
|
228
|
+
readonly lotId: NonEmptyString;
|
|
229
|
+
readonly amount: number & tags.ExclusiveMinimum<0>;
|
|
230
|
+
}
|
|
231
|
+
export type CommerceConformanceSubscriptionEventType = 'subscriptionStarted' | 'subscriptionRenewed' | 'subscriptionLapsed' | 'subscriptionRevoked';
|
|
232
|
+
export interface CommerceConformanceSubscriptionEventExpectation {
|
|
233
|
+
readonly type: CommerceConformanceSubscriptionEventType;
|
|
234
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
235
|
+
readonly periodIndex: NonNegativeInteger;
|
|
236
|
+
readonly expiresAt: IsoTimestamp;
|
|
237
|
+
readonly reason?: CommerceErrorCode;
|
|
238
|
+
}
|
|
239
|
+
export interface CommerceConformanceActiveSubscriptionExpectation {
|
|
240
|
+
readonly logicalId: CommerceLogicalProductId;
|
|
241
|
+
readonly periodIndex?: NonNegativeInteger;
|
|
242
|
+
readonly state?: ActiveSubscriptionState;
|
|
243
|
+
readonly expiresAt?: IsoTimestamp;
|
|
244
|
+
}
|
|
245
|
+
export interface CommerceConformanceExpectation {
|
|
246
|
+
/** Full state sequence per journal key. */
|
|
247
|
+
readonly journal?: Readonly<Record<string, readonly CommercePurchaseState[]>>;
|
|
248
|
+
readonly verifyRequests?: readonly CommerceConformanceVerifyRequestExpectation[];
|
|
249
|
+
readonly ledger?: readonly CommerceConformanceLedgerEntryExpectation[];
|
|
250
|
+
readonly finishCalls?: readonly CommerceConformanceFinishCallExpectation[];
|
|
251
|
+
readonly available?: readonly CommerceConformanceAvailableExpectation[];
|
|
252
|
+
readonly entitlements?: readonly CommerceConformanceEntitlementExpectation[];
|
|
253
|
+
readonly lots?: readonly CommerceConformanceLotExpectation[];
|
|
254
|
+
/** Spendable balance per title and currency. */
|
|
255
|
+
readonly balances?: Readonly<Record<string, Readonly<Record<string, number>>>>;
|
|
256
|
+
readonly debits?: readonly CommerceConformanceScheduledDebitExpectation[];
|
|
257
|
+
readonly events?: readonly CommerceConformanceSubscriptionEventExpectation[];
|
|
258
|
+
readonly activeSubscriptions?: readonly CommerceConformanceActiveSubscriptionExpectation[];
|
|
259
|
+
readonly purchaseUiOpened?: NonNegativeInteger;
|
|
260
|
+
}
|
|
261
|
+
export interface CommerceConformanceVector {
|
|
262
|
+
/** Equals the file name without `.json`. */
|
|
263
|
+
readonly vector: string & tags.Pattern<'^[a-z0-9]+(?:-[a-z0-9]+)*$'>;
|
|
264
|
+
readonly protocol: NonEmptyString;
|
|
265
|
+
readonly summary: NonEmptyString;
|
|
266
|
+
readonly profile: CommerceConformanceProfile;
|
|
267
|
+
readonly catalog?: readonly CommerceConformanceCatalogEntry[];
|
|
268
|
+
readonly wallet?: CommerceConformanceWallet;
|
|
269
|
+
readonly steps: readonly CommerceConformanceStep[] & tags.MinItems<1>;
|
|
270
|
+
readonly expect: CommerceConformanceExpectation;
|
|
271
|
+
}
|
|
272
|
+
/** Validates one vector file. Catalog logical ids must be unique. */
|
|
273
|
+
export declare function assertCommerceConformanceVector(input: unknown): CommerceConformanceVector;
|
|
274
|
+
export declare function isCommerceConformanceVector(input: unknown): input is CommerceConformanceVector;
|
|
275
|
+
/** The vector name a file at `path` must declare. */
|
|
276
|
+
export declare function commerceConformanceVectorNameOf(path: string): string;
|
|
277
|
+
export {};
|