@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.
@@ -0,0 +1,303 @@
1
+ import { type tags } from 'typia';
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, PurchaseKind, RequestPurchaseInput, RequestPurchaseResult, StoreId, StoreProduct, StorePurchase } from './commerce-contract.js';
4
+ export { createUnsupportedCommerceCapabilities, deriveLegacyCommerceCapabilities, type LegacyCommerceCapabilities, } from './commerce-capabilities.js';
5
+ export type { CommerceAccountBindingPolicy, CommerceAuthorityCapabilities, CommerceCapabilities, CommerceCatalogCapabilities, CommerceEvidenceAuthority, CommerceFinishOwner, CommerceLifecycleCapabilities, CommercePurchaseCapabilities, } from './index.js';
6
+ /**
7
+ * Commerce v2 client contract. Pure types, validators, and helpers only: no
8
+ * provider lives here, and nothing in this module grants a purchase. The
9
+ * contract is described by docs/specs/commerce/commerce-v2-rfc.md and is a
10
+ * draft until the protocol version is released as 2.0.0.
11
+ */
12
+ export declare const commerceProtocolVersion: '2.0.0-draft.1';
13
+ export declare const commerceProtocol: 'mpgd.commerce.v2';
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';
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"];
16
+ /** Bridge event envelope; `sequence` is per session and starts at 0. */
17
+ export interface CommerceEventEnvelope {
18
+ readonly protocol: typeof commerceProtocol;
19
+ readonly sequence: NonNegativeInteger;
20
+ readonly event: CommerceEvent;
21
+ }
22
+ export type CommerceBillingAuthority = 'store' | 'host';
23
+ export type CreditMembershipScope = 'title' | 'platform';
24
+ export interface CreditPrice {
25
+ readonly currency: NonEmptyString;
26
+ readonly amount: number & tags.ExclusiveMinimum<0>;
27
+ }
28
+ export interface CreditMembershipTerms {
29
+ readonly scope: CreditMembershipScope;
30
+ readonly price: CreditPrice;
31
+ /** ISO 8601 duration, for example P30D. */
32
+ readonly period: NonEmptyString;
33
+ }
34
+ export interface CreditOffer {
35
+ readonly logicalId: CommerceLogicalProductId;
36
+ readonly storeSku: NonEmptyString;
37
+ readonly kind: PurchaseKind;
38
+ readonly title: string;
39
+ readonly description: string;
40
+ readonly price: CreditPrice;
41
+ /** Present only for credit-funded memberships. */
42
+ readonly membership?: CreditMembershipTerms;
43
+ }
44
+ export interface CreditSpendInput {
45
+ readonly titleId: NonEmptyString;
46
+ readonly currency: NonEmptyString;
47
+ readonly amount: number & tags.ExclusiveMinimum<0>;
48
+ readonly idempotencyKey: NonEmptyString;
49
+ readonly logicalId?: CommerceLogicalProductId;
50
+ }
51
+ export interface CreditDebit {
52
+ readonly lotId: NonEmptyString;
53
+ readonly amount: number & tags.ExclusiveMinimum<0>;
54
+ }
55
+ export type CreditSpendResult = {
56
+ readonly status: 'debited';
57
+ readonly entitlementId: NonEmptyString;
58
+ readonly debits: readonly CreditDebit[];
59
+ /** A repeated idempotency key returns the original debits. */
60
+ readonly alreadyProcessed?: boolean;
61
+ } | {
62
+ readonly status: 'rejected';
63
+ readonly error: CommerceErrorInfo;
64
+ };
65
+ export interface CreditEntitlement {
66
+ readonly entitlementId: NonEmptyString;
67
+ readonly titleId: NonEmptyString;
68
+ readonly logicalId: CommerceLogicalProductId;
69
+ readonly idempotencyKey: NonEmptyString;
70
+ readonly createdAt: IsoTimestamp;
71
+ readonly debits: readonly CreditDebit[];
72
+ }
73
+ export interface CreditBalance {
74
+ readonly titleId: NonEmptyString;
75
+ /** Spendable amount per currency, including eligible cross-title lots. */
76
+ readonly balances: Readonly<Record<string, number>>;
77
+ }
78
+ export type CreditLotChannel = 'store' | 'off-store' | 'promotion';
79
+ export interface CreditLotOrigin {
80
+ readonly channel: CreditLotChannel;
81
+ readonly store: StoreId;
82
+ readonly titleId: NonEmptyString;
83
+ }
84
+ export type CreditLotSpendScope = {
85
+ readonly kind: 'title';
86
+ readonly titleId: NonEmptyString;
87
+ } | {
88
+ readonly kind: 'cross-title';
89
+ };
90
+ export interface CreditLot {
91
+ /** Equals the ledgerEntryId of the granting purchase, so a replayed grant cannot create a second lot. */
92
+ readonly lotId: NonEmptyString;
93
+ readonly currency: NonEmptyString;
94
+ readonly amount: number & tags.ExclusiveMinimum<0>;
95
+ readonly remaining: number & tags.Minimum<0>;
96
+ readonly createdAt: IsoTimestamp;
97
+ readonly expiresAt?: IsoTimestamp;
98
+ readonly origin: CreditLotOrigin;
99
+ /** Derived from the origin, never supplied by the caller. */
100
+ readonly spendScope: CreditLotSpendScope;
101
+ }
102
+ export interface CreditWalletClient {
103
+ readonly store: StoreId;
104
+ listOffers(input: {
105
+ readonly titleId: string;
106
+ }): Promise<readonly CreditOffer[]>;
107
+ spend(input: CreditSpendInput): Promise<CreditSpendResult>;
108
+ listUnredeemed(input: {
109
+ readonly titleId: string;
110
+ }): Promise<readonly CreditEntitlement[]>;
111
+ redeem(input: {
112
+ readonly entitlementId: string;
113
+ readonly ledgerEntryId: string;
114
+ }): Promise<{
115
+ readonly redeemed: boolean;
116
+ }>;
117
+ getBalance(input: {
118
+ readonly titleId: string;
119
+ }): Promise<CreditBalance>;
120
+ subscribe?(listener: (event: CommerceEvent) => void): () => void;
121
+ }
122
+ export interface CommerceBridgeGetCapabilitiesPayload {
123
+ readonly protocol: typeof commerceProtocol;
124
+ }
125
+ export interface CommerceBridgeGetCapabilitiesResult {
126
+ readonly protocolVersion: NonEmptyString;
127
+ readonly store: StoreId;
128
+ readonly capabilities: CommerceCapabilities;
129
+ }
130
+ export type CommerceBridgeFetchProductsPayload = FetchProductsInput;
131
+ export interface CommerceBridgeFetchProductsResult {
132
+ readonly products: readonly StoreProduct[];
133
+ }
134
+ export type CommerceBridgeRequestPurchasePayload = RequestPurchaseInput;
135
+ export type CommerceBridgeRequestPurchaseResult = RequestPurchaseResult;
136
+ export type CommerceBridgeGetAvailablePurchasesPayload = GetAvailablePurchasesInput;
137
+ export interface CommerceBridgeGetAvailablePurchasesResult {
138
+ readonly purchases: readonly StorePurchase[];
139
+ }
140
+ export type CommerceBridgeFinishTransactionPayload = FinishTransactionInput;
141
+ export type CommerceBridgeFinishTransactionResult = FinishTransactionResult;
142
+ export interface CommerceBridgeRestorePurchasesPayload {
143
+ readonly protocol: typeof commerceProtocol;
144
+ }
145
+ export interface CommerceBridgeRestorePurchasesResult {
146
+ readonly restored: boolean;
147
+ }
148
+ export interface CommerceBridgeMethods {
149
+ readonly 'commerce.v2.getCapabilities': {
150
+ readonly payload: CommerceBridgeGetCapabilitiesPayload;
151
+ readonly result: CommerceBridgeGetCapabilitiesResult;
152
+ };
153
+ readonly 'commerce.v2.fetchProducts': {
154
+ readonly payload: CommerceBridgeFetchProductsPayload;
155
+ readonly result: CommerceBridgeFetchProductsResult;
156
+ };
157
+ readonly 'commerce.v2.requestPurchase': {
158
+ readonly payload: CommerceBridgeRequestPurchasePayload;
159
+ readonly result: CommerceBridgeRequestPurchaseResult;
160
+ };
161
+ readonly 'commerce.v2.getAvailablePurchases': {
162
+ readonly payload: CommerceBridgeGetAvailablePurchasesPayload;
163
+ readonly result: CommerceBridgeGetAvailablePurchasesResult;
164
+ };
165
+ readonly 'commerce.v2.finishTransaction': {
166
+ readonly payload: CommerceBridgeFinishTransactionPayload;
167
+ readonly result: CommerceBridgeFinishTransactionResult;
168
+ };
169
+ readonly 'commerce.v2.restorePurchases': {
170
+ readonly payload: CommerceBridgeRestorePurchasesPayload;
171
+ readonly result: CommerceBridgeRestorePurchasesResult;
172
+ };
173
+ }
174
+ export type CommerceBridgeMethod = keyof CommerceBridgeMethods;
175
+ export declare const commerceBridgeMethods: readonly ["commerce.v2.getCapabilities", "commerce.v2.fetchProducts", "commerce.v2.requestPurchase", "commerce.v2.getAvailablePurchases", "commerce.v2.finishTransaction", "commerce.v2.restorePurchases"];
176
+ /** Only NETWORK and STORE_UNAVAILABLE are retryable without reconciling first. */
177
+ export declare function defaultCommerceErrorRetryable(code: CommerceErrorCode): boolean;
178
+ export declare function isCommerceErrorCode(value: unknown): value is CommerceErrorCode;
179
+ export interface CommerceErrorOptions {
180
+ readonly message?: string;
181
+ readonly storeCode?: string;
182
+ readonly retryable?: boolean;
183
+ readonly cause?: unknown;
184
+ }
185
+ /**
186
+ * Normalized commerce failure. `code` is one of the v2 codes, `storeCode`
187
+ * keeps the store's own code verbatim, and `retryable` defaults from the code.
188
+ */
189
+ export declare class CommerceError extends PlatformOperationError {
190
+ readonly code: CommerceErrorCode;
191
+ readonly storeCode: string | undefined;
192
+ constructor(code: CommerceErrorCode, options?: CommerceErrorOptions);
193
+ toCommerceErrorInfo(): CommerceErrorInfo;
194
+ }
195
+ /**
196
+ * Reads a normalized error info from any thrown value. A `CommerceError` keeps
197
+ * its code; a plain object with a v2 `code` is accepted; any other platform
198
+ * failure or error maps to UNKNOWN with the original code kept as `storeCode`.
199
+ */
200
+ export declare function commerceErrorInfoOf(error: unknown): CommerceErrorInfo;
201
+ export type CommercePurchaseState = 'requested' | 'launched' | 'pending' | 'purchased' | 'verifying' | 'granted' | 'finishing' | 'finished' | 'cancelled' | 'failed' | 'rejected' | 'revoked';
202
+ export declare const commercePurchaseStates: readonly ["requested", "launched", "pending", "purchased", "verifying", "granted", "finishing", "finished", "cancelled", "failed", "rejected", "revoked"];
203
+ /** Allowed transitions, from the RFC lifecycle table. `pending` covers both store-side and server-side waits. */
204
+ export declare const commercePurchaseTransitions: Readonly<Record<CommercePurchaseState, readonly CommercePurchaseState[]>>;
205
+ export declare const terminalCommercePurchaseStates: readonly ["finished", "cancelled", "failed", "rejected", "revoked"];
206
+ export declare function canTransitionCommercePurchase(from: CommercePurchaseState, to: CommercePurchaseState): boolean;
207
+ export declare function assertCommercePurchaseTransition(from: CommercePurchaseState, to: CommercePurchaseState): void;
208
+ export declare function isTerminalCommercePurchaseState(state: CommercePurchaseState): boolean;
209
+ /** Only `granted` may unlock content, and only because the ledger says so. */
210
+ export type CommercePurchaseSummaryStatus = 'pending' | 'granted' | 'cancelled' | 'failed' | 'rejected' | 'revoked';
211
+ export declare function summarizeCommercePurchaseState(state: CommercePurchaseState): CommercePurchaseSummaryStatus;
212
+ /**
213
+ * Rejects a purchase the provider cannot serve before any store UI opens.
214
+ * `kind` is the catalog kind of `input.logicalId`; the caller resolves it.
215
+ */
216
+ export declare function assertRequestPurchaseSupported(capabilities: CommerceCapabilities, input: RequestPurchaseInput, kind: PurchaseKind): void;
217
+ export interface DerivedPurchaseIdempotencyKeyInput {
218
+ readonly store: StoreId;
219
+ readonly transactionId: string;
220
+ readonly token: string;
221
+ }
222
+ /**
223
+ * Key for a purchase discovered without a journal record. Every runtime derives
224
+ * the same key: `store:<storeId>:<transactionId>` by default, with each
225
+ * component percent-encoded (`encodeURIComponent`) so ids containing `:`
226
+ * cannot collide, and the forms v1 ledgers already use for Google Play
227
+ * (`play-token-sha256:<hex>`) and Apps in Toss (`apps-in-toss:purchase:<orderId>`),
228
+ * which stay byte-identical.
229
+ */
230
+ export declare function createDerivedPurchaseIdempotencyKey(input: DerivedPurchaseIdempotencyKeyInput): Promise<string>;
231
+ /** Byte-for-byte the v1 `createGooglePlayTokenTransactionId` form; A4 replaces the two copies with this helper. */
232
+ export declare function createGooglePlayTokenPurchaseKey(purchaseToken: string): Promise<string>;
233
+ export declare const commerceEventBufferLimit = 64;
234
+ export interface CommerceEventBuffer {
235
+ readonly size: number;
236
+ /** Keeps the event for the first subscriber; drops the oldest recoverable `purchaseUpdated` when full. */
237
+ push(event: CommerceEvent): void;
238
+ /** Delivers and clears every buffered event in order. */
239
+ drain(listener: (event: CommerceEvent) => void): number;
240
+ }
241
+ /**
242
+ * Buffer for events emitted before the first `subscribe` call. Over the limit
243
+ * it drops the oldest recoverable `purchaseUpdated` first: a pending or
244
+ * purchased purchase is still returned by `getAvailablePurchases`. A revoked
245
+ * purchase is not, so revoked `purchaseUpdated`, `purchaseError`, and
246
+ * `subscriptionUpdated` events are dropped oldest-first only when no
247
+ * recoverable `purchaseUpdated` remains.
248
+ */
249
+ export declare function createCommerceEventBuffer(options?: {
250
+ readonly limit?: number;
251
+ }): CommerceEventBuffer;
252
+ export declare const assertStoreProduct: (input: unknown) => StoreProduct;
253
+ export declare const isStoreProduct: (input: unknown) => input is StoreProduct;
254
+ export declare const assertStorePurchase: (input: unknown) => StorePurchase;
255
+ export declare const isStorePurchase: (input: unknown) => input is StorePurchase;
256
+ export declare const assertRequestPurchaseInput: (input: unknown) => RequestPurchaseInput;
257
+ export declare const isRequestPurchaseInput: (input: unknown) => input is RequestPurchaseInput;
258
+ export declare const assertRequestPurchaseResult: (input: unknown) => RequestPurchaseResult;
259
+ export declare const isRequestPurchaseResult: (input: unknown) => input is RequestPurchaseResult;
260
+ export declare const assertCommerceEvent: (input: unknown) => CommerceEvent;
261
+ export declare const isCommerceEvent: (input: unknown) => input is CommerceEvent;
262
+ export declare const assertCommerceEventEnvelope: (input: unknown) => CommerceEventEnvelope;
263
+ export declare const isCommerceEventEnvelope: (input: unknown) => input is CommerceEventEnvelope;
264
+ export declare const assertActiveSubscription: (input: unknown) => ActiveSubscription;
265
+ export declare const isActiveSubscription: (input: unknown) => input is ActiveSubscription;
266
+ export declare const assertFetchProductsInput: (input: unknown) => FetchProductsInput;
267
+ export declare const assertCommerceCapabilities: (input: unknown) => CommerceCapabilities;
268
+ export declare const isCommerceCapabilities: (input: unknown) => input is CommerceCapabilities;
269
+ export declare const assertCommerceErrorInfo: (input: unknown) => CommerceErrorInfo;
270
+ export declare const assertCreditOffer: (input: unknown) => CreditOffer;
271
+ export declare const assertCreditSpendInput: (input: unknown) => CreditSpendInput;
272
+ export declare const assertCreditSpendResult: (input: unknown) => CreditSpendResult;
273
+ export declare const assertCreditEntitlement: (input: unknown) => CreditEntitlement;
274
+ export declare const assertCreditBalance: (input: unknown) => CreditBalance;
275
+ export declare const assertCreditLot: (input: unknown) => CreditLot;
276
+ export declare const assertFinishTransactionInput: (input: unknown) => FinishTransactionInput;
277
+ export declare const assertFinishTransactionResult: (input: unknown) => FinishTransactionResult;
278
+ export declare const assertGetAvailablePurchasesInput: (input: unknown) => GetAvailablePurchasesInput;
279
+ export declare const assertCommerceBridgeGetCapabilitiesPayload: (input: unknown) => CommerceBridgeGetCapabilitiesPayload;
280
+ export declare const assertCommerceBridgeGetCapabilitiesResult: (input: unknown) => CommerceBridgeGetCapabilitiesResult;
281
+ export declare const assertCommerceBridgeFetchProductsPayload: (input: unknown) => FetchProductsInput;
282
+ export declare const assertCommerceBridgeFetchProductsResult: (input: unknown) => CommerceBridgeFetchProductsResult;
283
+ export declare const assertCommerceBridgeRequestPurchasePayload: (input: unknown) => RequestPurchaseInput;
284
+ export declare const assertCommerceBridgeRequestPurchaseResult: (input: unknown) => RequestPurchaseResult;
285
+ export declare const assertCommerceBridgeGetAvailablePurchasesPayload: (input: unknown) => GetAvailablePurchasesInput;
286
+ export declare const assertCommerceBridgeGetAvailablePurchasesResult: (input: unknown) => CommerceBridgeGetAvailablePurchasesResult;
287
+ export declare const assertCommerceBridgeFinishTransactionPayload: (input: unknown) => FinishTransactionInput;
288
+ export declare const assertCommerceBridgeFinishTransactionResult: (input: unknown) => FinishTransactionResult;
289
+ export declare const assertCommerceBridgeRestorePurchasesPayload: (input: unknown) => CommerceBridgeRestorePurchasesPayload;
290
+ export declare const assertCommerceBridgeRestorePurchasesResult: (input: unknown) => CommerceBridgeRestorePurchasesResult;
291
+ export interface ToCommerceAdapterOptions {
292
+ /** Forwarded to `getAvailablePurchases` during `restore`. Defaults to false. */
293
+ readonly includePending?: boolean;
294
+ }
295
+ /**
296
+ * Serves v1 `CommerceAdapter` callers from a v2 provider. The wrapper never
297
+ * grants: a `purchased` outcome becomes a `completed` result with no
298
+ * entitlements, and `authoritativeGrant` appears only when the provider reports
299
+ * an adapter settlement that already points at a ledger entry. `restore`
300
+ * returns settled purchases from `getAvailablePurchases` and no entitlements;
301
+ * entitlements come from the ledger, not from the provider.
302
+ */
303
+ export declare function toCommerceAdapter(provider: CommerceProvider, options?: ToCommerceAdapterOptions): CommerceAdapter;