@mpgd/platform 0.19.0 → 0.21.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.
@@ -1,5 +1,6 @@
1
1
  import { type tags } from 'typia';
2
- import { PlatformOperationError, type CommerceAdapter, type CommerceCapabilities, type LogicalProductId, type PlatformEvidenceEnvelope, type StarterLogicalProductId } from './index.js';
2
+ import { PlatformOperationError, type CommerceAdapter, type CommerceCapabilities } from './index.js';
3
+ import type { ActiveSubscription, CommerceErrorCode, CommerceErrorInfo, CommerceEvent, CommerceLogicalProductId, CommerceProvider, FetchProductsInput, FinishTransactionInput, FinishTransactionResult, GetAvailablePurchasesInput, IsoTimestamp, NonEmptyString, NonNegativeInteger, PositiveQuantity, PurchaseKind, RequestPurchaseInput, RequestPurchaseResult, StoreId, StoreProduct, StorePurchase } from './commerce-contract.js';
3
4
  export { createUnsupportedCommerceCapabilities, deriveLegacyCommerceCapabilities, type LegacyCommerceCapabilities, } from './commerce-capabilities.js';
4
5
  export type { CommerceAccountBindingPolicy, CommerceAuthorityCapabilities, CommerceCapabilities, CommerceCatalogCapabilities, CommerceEvidenceAuthority, CommerceFinishOwner, CommerceLifecycleCapabilities, CommercePurchaseCapabilities, } from './index.js';
5
6
  /**
@@ -10,157 +11,14 @@ export type { CommerceAccountBindingPolicy, CommerceAuthorityCapabilities, Comme
10
11
  */
11
12
  export declare const commerceProtocolVersion: '2.0.0-draft.1';
12
13
  export declare const commerceProtocol: 'mpgd.commerce.v2';
13
- type NonEmptyString = string & tags.MinLength<1>;
14
- type IsoTimestamp = string & tags.Format<'date-time'>;
15
- type PositiveQuantity = number & tags.Type<'uint32'> & tags.Minimum<1>;
16
- type NonNegativeInteger = number & tags.Type<'uint32'>;
17
- /**
18
- * Open store identifier. Reference providers use 'google-play', 'app-store',
19
- * 'microsoft-store', 'apps-in-toss', 'devvit', and 'verse8'; a consuming
20
- * project adds its own, for example a credit wallet id.
21
- */
22
- export type StoreId = NonEmptyString;
23
- export type PurchaseKind = 'consumable' | 'durable' | 'subscription';
24
- /**
25
- * `LogicalProductId` narrowed to its open string branch and tagged non-empty,
26
- * so validators and the generated schemas carry `minLength: 1`. Starter ids and
27
- * plain `LogicalProductId` values remain assignable.
28
- */
29
- export type CommerceLogicalProductId = Exclude<LogicalProductId, StarterLogicalProductId> & tags.MinLength<1>;
30
- export interface StorePrice {
31
- readonly formatted: string;
32
- /** ISO 4217 code or a project-declared code such as a wallet currency. */
33
- readonly currencyCode: NonEmptyString;
34
- readonly amountMicros?: number & tags.Type<'int64'>;
35
- }
36
- export interface StoreOffer {
37
- readonly offerId: NonEmptyString;
38
- readonly price: StorePrice;
39
- readonly title?: string;
40
- readonly description?: string;
41
- }
42
- export interface StoreProduct {
43
- readonly logicalId: CommerceLogicalProductId;
44
- readonly store: StoreId;
45
- readonly storeSku: NonEmptyString;
46
- readonly kind: PurchaseKind;
47
- readonly title: string;
48
- readonly description: string;
49
- readonly price: StorePrice;
50
- readonly offers?: readonly StoreOffer[];
51
- }
52
- export type StorePurchaseState = 'pending' | 'purchased' | 'revoked';
53
- export interface StorePurchaseAccountBinding {
54
- readonly kind: 'obfuscated-account-id' | 'app-account-token' | 'host-identity';
55
- readonly value?: string;
56
- }
57
- export interface StorePurchase {
58
- readonly store: StoreId;
59
- /** Store transaction id; a provider derives one when the store has none. */
60
- readonly transactionId: NonEmptyString;
61
- readonly originalTransactionId?: NonEmptyString;
62
- readonly storeSku: NonEmptyString;
63
- readonly logicalId?: CommerceLogicalProductId;
64
- readonly quantity: PositiveQuantity;
65
- readonly state: StorePurchaseState;
66
- readonly purchasedAt?: IsoTimestamp;
67
- /** Play purchase token, App Store signed transaction (JWS), or host order id. */
68
- readonly token: NonEmptyString;
69
- readonly evidence: PlatformEvidenceEnvelope;
70
- readonly accountBinding?: StorePurchaseAccountBinding;
71
- /** Present only for `authority.evidence: 'adapter-settled'`; a reconciler pointer, not a grant. */
72
- readonly settlement?: {
73
- readonly ledgerEntryId: NonEmptyString;
74
- };
75
- }
76
- export type PurchaseSource = 'shop' | 'stage_fail' | 'result' | 'event';
77
- export interface RequestPurchaseInput {
78
- readonly logicalId: CommerceLogicalProductId;
79
- readonly idempotencyKey: NonEmptyString;
80
- readonly source: PurchaseSource;
81
- readonly offerId?: NonEmptyString;
82
- /** Integer >= 1. Rejected with ITEM_UNAVAILABLE when the provider does not declare `purchase.quantity`. */
83
- readonly quantity?: PositiveQuantity;
84
- }
85
- export type RequestPurchaseResult = {
86
- readonly outcome: 'launched';
87
- } | {
88
- readonly outcome: 'purchased';
89
- readonly purchase: StorePurchase;
90
- } | {
91
- readonly outcome: 'cancelled' | 'failed';
92
- readonly error: CommerceErrorInfo;
93
- };
94
- 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';
14
+ export type { ActiveSubscription, ActiveSubscriptionState, CommerceErrorCode, CommerceErrorInfo, CommerceEvent, CommerceLogicalProductId, CommerceProvider, FetchProductsInput, FetchProductsType, FinishTransactionInput, FinishTransactionResult, GetAvailablePurchasesInput, PurchaseKind, PurchaseSource, RequestPurchaseInput, RequestPurchaseResult, StoreId, StoreOffer, StorePrice, StoreProduct, StorePurchase, StorePurchaseAccountBinding, StorePurchaseState, } from './commerce-contract.js';
95
15
  export declare const commerceErrorCodes: readonly ["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"];
96
- export interface CommerceErrorInfo {
97
- readonly code: CommerceErrorCode;
98
- readonly retryable: boolean;
99
- /** The store's original code, for example PLAY_BILLING_SERVICE_UNAVAILABLE. */
100
- readonly storeCode?: string;
101
- readonly message?: string;
102
- }
103
- export type CommerceEvent = {
104
- readonly type: 'purchaseUpdated';
105
- readonly purchase: StorePurchase;
106
- } | {
107
- readonly type: 'purchaseError';
108
- readonly logicalId?: CommerceLogicalProductId;
109
- readonly error: CommerceErrorInfo;
110
- } | {
111
- readonly type: 'subscriptionUpdated';
112
- readonly subscription: ActiveSubscription;
113
- };
114
16
  /** Bridge event envelope; `sequence` is per session and starts at 0. */
115
17
  export interface CommerceEventEnvelope {
116
18
  readonly protocol: typeof commerceProtocol;
117
19
  readonly sequence: NonNegativeInteger;
118
20
  readonly event: CommerceEvent;
119
21
  }
120
- export type FetchProductsType = 'in-app' | 'subscription' | 'all';
121
- export interface FetchProductsInput {
122
- readonly logicalIds?: readonly CommerceLogicalProductId[];
123
- readonly type?: FetchProductsType;
124
- }
125
- export interface GetAvailablePurchasesInput {
126
- readonly includePending?: boolean;
127
- }
128
- export interface FinishTransactionInput {
129
- readonly transactionId: NonEmptyString;
130
- readonly ledgerEntryId: NonEmptyString;
131
- readonly isConsumable: boolean;
132
- }
133
- export interface FinishTransactionResult {
134
- readonly finished: boolean;
135
- }
136
- export interface CommerceProvider {
137
- readonly store: StoreId;
138
- getCapabilities(): Promise<CommerceCapabilities>;
139
- fetchProducts(input: FetchProductsInput): Promise<readonly StoreProduct[]>;
140
- /** Returns `launched` when the result arrives later as a `purchaseUpdated` event. */
141
- requestPurchase(input: RequestPurchaseInput): Promise<RequestPurchaseResult>;
142
- /** Purchases the store still reports as unfinished. */
143
- getAvailablePurchases(input?: GetAvailablePurchasesInput): Promise<readonly StorePurchase[]>;
144
- /** Required when `lifecycle.finish` is 'client' or 'host'. */
145
- finishTransaction?(input: FinishTransactionInput): Promise<FinishTransactionResult>;
146
- /** Asks the store to resynchronize, for example `AppStore.sync`. */
147
- restorePurchases?(): Promise<void>;
148
- /** Designed, not implemented by any reference store provider. */
149
- getActiveSubscriptions?(): Promise<readonly ActiveSubscription[]>;
150
- /** Events emitted before the first listener are delivered to that listener. */
151
- subscribe(listener: (event: CommerceEvent) => void): () => void;
152
- }
153
- export type ActiveSubscriptionState = 'active' | 'lapsed' | 'revoked';
154
- export interface ActiveSubscription {
155
- readonly store: StoreId;
156
- readonly logicalId: CommerceLogicalProductId;
157
- readonly subscriptionId: NonEmptyString;
158
- readonly periodIndex: NonNegativeInteger;
159
- readonly state: ActiveSubscriptionState;
160
- readonly startedAt: IsoTimestamp;
161
- readonly expiresAt: IsoTimestamp;
162
- readonly autoRenew: boolean;
163
- }
164
22
  export type CommerceBillingAuthority = 'store' | 'host';
165
23
  export type CreditMembershipScope = 'title' | 'platform';
166
24
  export interface CreditPrice {
@@ -188,6 +46,12 @@ export interface CreditSpendInput {
188
46
  readonly currency: NonEmptyString;
189
47
  readonly amount: number & tags.ExclusiveMinimum<0>;
190
48
  readonly idempotencyKey: NonEmptyString;
49
+ /**
50
+ * The offer being bought; the wallet prices the spend against it and issues
51
+ * an entitlement. Without it the spend is a plain debit of `amount` with no
52
+ * entitlement, an owner-side form the conformance vectors use; a wallet
53
+ * service should require it from game clients.
54
+ */
191
55
  readonly logicalId?: CommerceLogicalProductId;
192
56
  }
193
57
  export interface CreditDebit {
@@ -198,6 +62,8 @@ export type CreditSpendResult = {
198
62
  readonly status: 'debited';
199
63
  readonly entitlementId: NonEmptyString;
200
64
  readonly debits: readonly CreditDebit[];
65
+ /** When the wallet settled the spend; a replay repeats the original time. */
66
+ readonly createdAt?: IsoTimestamp;
201
67
  /** A repeated idempotency key returns the original debits. */
202
68
  readonly alreadyProcessed?: boolean;
203
69
  } | {
@@ -211,6 +77,8 @@ export interface CreditEntitlement {
211
77
  readonly idempotencyKey: NonEmptyString;
212
78
  readonly createdAt: IsoTimestamp;
213
79
  readonly debits: readonly CreditDebit[];
80
+ /** Units bought at spend time; the provider reports it rather than deriving one from today's price. */
81
+ readonly quantity?: PositiveQuantity;
214
82
  }
215
83
  export interface CreditBalance {
216
84
  readonly titleId: NonEmptyString;
@@ -241,6 +109,13 @@ export interface CreditLot {
241
109
  /** Derived from the origin, never supplied by the caller. */
242
110
  readonly spendScope: CreditLotSpendScope;
243
111
  }
112
+ /**
113
+ * The client a consuming project implements against its wallet service.
114
+ * `createCreditCommerceProvider` (`@mpgd/platform/commerce-wallet`) turns it
115
+ * into a `CommerceProvider`. A `spend` of a membership offer starts the
116
+ * membership under the spend's idempotency key as its subscription id; the
117
+ * wallet service alone renews, lapses, and expires it.
118
+ */
244
119
  export interface CreditWalletClient {
245
120
  readonly store: StoreId;
246
121
  listOffers(input: {
@@ -250,6 +125,7 @@ export interface CreditWalletClient {
250
125
  listUnredeemed(input: {
251
126
  readonly titleId: string;
252
127
  }): Promise<readonly CreditEntitlement[]>;
128
+ /** Redeems an entitlement for the ledger entry that granted it; the wallet service verifies the pair. */
253
129
  redeem(input: {
254
130
  readonly entitlementId: string;
255
131
  readonly ledgerEntryId: string;
@@ -259,7 +135,15 @@ export interface CreditWalletClient {
259
135
  getBalance(input: {
260
136
  readonly titleId: string;
261
137
  }): Promise<CreditBalance>;
262
- subscribe?(listener: (event: CommerceEvent) => void): () => void;
138
+ /** Memberships the wallet service reports as active for the title; absent when the wallet sells none. */
139
+ getActiveSubscriptions?(input: {
140
+ readonly titleId: string;
141
+ }): Promise<readonly ActiveSubscription[]>;
142
+ /** With `input.titleId`, only events that concern that title (platform memberships concern every title). */
143
+ subscribe?(listener: (event: CommerceEvent) => void, input?: CreditWalletSubscribeInput): () => void;
144
+ }
145
+ export interface CreditWalletSubscribeInput {
146
+ readonly titleId?: string;
263
147
  }
264
148
  export interface CommerceBridgeGetCapabilitiesPayload {
265
149
  readonly protocol: typeof commerceProtocol;