@mpgd/adapter-capacitor 0.18.0 → 0.19.1

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.
@@ -62,6 +62,12 @@ export interface CreateBridgeCommerceProviderInput {
62
62
  */
63
63
  readonly acceptsFinishRetry?: boolean;
64
64
  /**
65
+ * The bridge host accepts `FinishTransactionInput.revoked` (same contract,
66
+ * and its provider declares `acceptsRevokedFinish`). Absent, the provider
67
+ * does not declare it and callers never send `revoked`.
68
+ */
69
+ readonly acceptsRevokedFinish?: boolean;
70
+ /**
65
71
  * The host's purchase presentation facts
66
72
  * (`CommerceProviderBridge.subscribePresentation`), each fact of a call
67
73
  * that opened no sheet delivered before that call's answer. Only with it
@@ -241,6 +241,7 @@ export function createBridgeCommerceProvider(input) {
241
241
  const provider = {
242
242
  store: input.store,
243
243
  ...(input.acceptsFinishRetry === true ? { acceptsFinishRetry: true } : {}),
244
+ ...(input.acceptsRevokedFinish === true ? { acceptsRevokedFinish: true } : {}),
244
245
  async getCapabilities() {
245
246
  return (await send('commerce.v2.getCapabilities', { protocol: commerceProtocol }))
246
247
  .capabilities;
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { createNativePurchasePresentation, purchasePresentationTimeoutMs, type N
7
7
  export { createCapacitorProviderRegistry, createDegradedCommerceCapabilities, createDegradedNotificationCapabilities, type CapacitorCommerceServiceProvider, type CapacitorNotificationServiceProvider, type CapacitorNotificationsV2Service, type CapacitorProviderCapabilitySnapshot, type CapacitorProviderRegistry, type CapacitorServiceProvider, type NativeBridge, } from './providers.js';
8
8
  export { assertCommerceBridgeResult, commerceV2InvalidPayloadBridgeErrorCode, commerceV2MethodUnsupportedBridgeErrorCode, createBridgeCommerceProvider, createCommerceProviderBridge, createCommerceServiceProvider, type CommerceProviderBridge, type CreateBridgeCommerceProviderInput, type CreateCommerceProviderBridgeInput, type CreateCommerceServiceProviderInput, } from './commerce-bridge.js';
9
9
  export { accountBindingLookupFailedStoreCode, createStoreCommerceProvider, purchaseGateFailedStoreCode, purchaseGateTimeoutMs, purchasesPausedStoreCode, recoverableErrorCodes, type CreateStoreCommerceProviderInput, type StoreCommerceCapabilityOverrides, type StoreCommerceProductMapping, type StoreCommerceProvider, type StorePurchaseGate, type StorePurchaseGateDecision, type StorePurchaseGateRequest, } from './store-commerce-provider.js';
10
- export { defaultStoreSdkErrorCodeMap, normalizeStoreSdkError, type StoreSdk, type StoreSdkCapabilities, type StoreSdkError, type StoreSdkErrorCodeMap, type StoreSdkEvent, type StoreSdkEventName, type StoreSdkEventOf, type StoreSdkFetchProductsInput, type StoreSdkFinishTransactionInput, type StoreSdkFinishTransactionResult, type StoreSdkGetAvailablePurchasesInput, type StoreSdkProduct, type StoreSdkPurchase, type StoreSdkRequestPurchaseInput, type StoreSdkRequestPurchaseResult, } from './store-sdk.js';
10
+ export { defaultStoreSdkErrorCodeMap, normalizeStoreSdkError, type StoreSdk, type StoreSdkCapabilities, type StoreSdkError, type StoreSdkErrorCodeMap, type StoreSdkEvent, type StoreSdkEventName, type StoreSdkEventOf, type StoreSdkFetchProductsInput, type StoreSdkFinishTransactionInput, type StoreSdkGrantedFinishTransactionInput, type StoreSdkRevokedFinishTransactionInput, type StoreSdkFinishTransactionResult, type StoreSdkGetAvailablePurchasesInput, type StoreSdkProduct, type StoreSdkPurchase, type StoreSdkRequestPurchaseInput, type StoreSdkRequestPurchaseResult, } from './store-sdk.js';
11
11
  export { createCapacitorAppEvents, type CapacitorAppEventsApi, type CapacitorIncomingUrlKind, type CapacitorVisibilitySource, } from './app-events.js';
12
12
  export { CapacitorNativeHttpError, createCapacitorNativeJsonTransport, type CapacitorJsonRequest, type CapacitorJsonResponse, type CapacitorNativeHttpErrorCode, type CapacitorNativeJsonTransport, type CreateCapacitorNativeJsonTransportInput, } from './native-http.js';
13
13
  export { createCapacitorViewport, type CapacitorViewportBaseState, type CapacitorOccupiedSurfaceInput, type CapacitorViewportController, type CapacitorViewportHost, } from './viewport.js';
package/dist/index.js CHANGED
@@ -76,6 +76,7 @@ export function createCapacitorPlatformGateway(input) {
76
76
  store: commerceProvider.commerce.store,
77
77
  // The host below is this package's, on the same contract.
78
78
  acceptsFinishRetry: commerceProvider.commerce.acceptsFinishRetry === true,
79
+ acceptsRevokedFinish: commerceProvider.commerce.acceptsRevokedFinish === true,
79
80
  request: (method, payload) => request(method, payload),
80
81
  // The provider's channel (`NativeBridge`) may carry other protocols.
81
82
  // Only an envelope that names another protocol is dropped; anything
@@ -349,11 +349,15 @@ export function createStoreCommerceProvider(input) {
349
349
  };
350
350
  const finishTransaction = sdk.finishTransaction;
351
351
  const restorePurchases = sdk.restorePurchases;
352
+ /** The SDK reads `revoked` and has a finish to take it. */
353
+ const revokedFinish = finishTransaction !== undefined && sdk.acceptsRevokedFinish === true;
352
354
  const provider = {
353
355
  store,
354
356
  ...(presentation === undefined ? {} : { presentation: presentation.presentation }),
355
357
  // `retry` is forwarded to the SDK below.
356
358
  ...(finishTransaction === undefined ? {} : { acceptsFinishRetry: true }),
359
+ // `revoked` is forwarded only to an SDK that reads it.
360
+ ...(revokedFinish ? { acceptsRevokedFinish: true } : {}),
357
361
  getCapabilities,
358
362
  async fetchProducts(request = {}) {
359
363
  const type = request.type ?? 'all';
@@ -476,7 +480,14 @@ export function createStoreCommerceProvider(input) {
476
480
  const purchase = toStorePurchase(candidate);
477
481
  // A revoked purchase is not recoverable, and a pending one is listed
478
482
  // only on request; both still reach the reconciler through events.
479
- if (purchase.state === 'revoked' || (purchase.state === 'pending' && !includePending)) {
483
+ // An SDK that finishes revoked transactions keeps its unfinished
484
+ // revoked consumables listed (the only kind a revoked finish takes):
485
+ // the reconciler finishes them once the backend answered for them,
486
+ // and verifies or grants none of them. A revoked purchase of another
487
+ // kind, or of a SKU the catalog does not map, stays filtered.
488
+ if ((purchase.state === 'revoked'
489
+ && !(revokedFinish && bySku.get(candidate.sku)?.kind === 'consumable'))
490
+ || (purchase.state === 'pending' && !includePending)) {
480
491
  continue;
481
492
  }
482
493
  purchases.push(purchase);
@@ -488,14 +499,26 @@ export function createStoreCommerceProvider(input) {
488
499
  // Finishing is authorized by a ledger entry only; the id is validated
489
500
  // before the store hears about it.
490
501
  const finish = assertFinishTransactionInput(request);
502
+ if (finish.revoked === true && !revokedFinish) {
503
+ // Never an ordinary finish in its place: the SDK cannot tell the
504
+ // two apart, and this one would run without a grant.
505
+ return { finished: false };
506
+ }
491
507
  let reported;
492
508
  try {
493
- reported = await finishTransaction.call(sdk, {
494
- transactionId: finish.transactionId,
495
- isConsumable: finish.isConsumable,
496
- ledgerEntryId: finish.ledgerEntryId,
497
- ...(finish.retry === true ? { retry: true } : {}),
498
- });
509
+ reported = await finishTransaction.call(sdk, finish.revoked === true
510
+ ? {
511
+ transactionId: finish.transactionId,
512
+ isConsumable: true,
513
+ revoked: true,
514
+ ...(finish.ledgerEntryId === undefined ? {} : { ledgerEntryId: finish.ledgerEntryId }),
515
+ }
516
+ : {
517
+ transactionId: finish.transactionId,
518
+ isConsumable: finish.isConsumable,
519
+ ledgerEntryId: finish.ledgerEntryId,
520
+ ...(finish.retry === true ? { retry: true } : {}),
521
+ });
499
522
  }
500
523
  catch (error) {
501
524
  throw normalize(error);
@@ -21,6 +21,16 @@ export interface StoreSdk {
21
21
  getAvailablePurchases(input: StoreSdkGetAvailablePurchasesInput): Promise<readonly StoreSdkPurchase[]>;
22
22
  /** Present when `capabilities.finish` is 'client' or 'host'. Called only after a ledger grant. */
23
23
  finishTransaction?(input: StoreSdkFinishTransactionInput): Promise<StoreSdkFinishTransactionResult>;
24
+ /**
25
+ * `finishTransaction` reads `revoked`: it finishes a transaction it still
26
+ * lists as revoked, and only that. `createStoreCommerceProvider` then
27
+ * declares `CommerceProvider.acceptsRevokedFinish` and keeps the revoked
28
+ * consumables `getAvailablePurchases` reports (still unfinished in the
29
+ * store) in its list, so the reconciler can finish them on a later launch; an SDK
30
+ * without it never receives the field, so a store that would read the call
31
+ * as an ordinary finish (a consume) is never asked.
32
+ */
33
+ readonly acceptsRevokedFinish?: boolean;
24
34
  /** Asks the store to resynchronize, for example `AppStore.sync`. */
25
35
  restorePurchases?(): Promise<void>;
26
36
  addListener<TEvent extends StoreSdkEventName>(eventName: TEvent, listener: (event: StoreSdkEventOf<TEvent>) => void): () => void;
@@ -126,13 +136,29 @@ export interface StoreSdkPurchase {
126
136
  /** Store-specific detail the provider never reads; kept for diagnostics only. */
127
137
  readonly raw?: Readonly<Record<string, unknown>>;
128
138
  }
129
- export interface StoreSdkFinishTransactionInput {
139
+ /**
140
+ * What `StoreSdk.finishTransaction` is asked to finish: a purchase the
141
+ * backend ledger granted, or (only for an SDK that declares
142
+ * `acceptsRevokedFinish`) a consumable the store revoked while it was still
143
+ * unfinished, which no grant stands for.
144
+ */
145
+ export type StoreSdkFinishTransactionInput = StoreSdkGrantedFinishTransactionInput | StoreSdkRevokedFinishTransactionInput;
146
+ export interface StoreSdkGrantedFinishTransactionInput {
130
147
  readonly transactionId: string;
131
148
  readonly isConsumable: boolean;
132
149
  /** `FinishTransactionInput.retry`: an earlier finish of this purchase was asked for. */
133
150
  readonly retry?: boolean;
134
151
  /** The ledger entry that authorized the finish; a plugin may record it. */
135
152
  readonly ledgerEntryId: string;
153
+ readonly revoked?: false;
154
+ }
155
+ /** `RevokedFinishTransactionInput`: finish a revoked consumable, granting nothing. */
156
+ export interface StoreSdkRevokedFinishTransactionInput {
157
+ readonly transactionId: string;
158
+ readonly isConsumable: true;
159
+ readonly revoked: true;
160
+ /** The reversed grant's ledger entry; absent when nothing was ever granted. */
161
+ readonly ledgerEntryId?: string;
136
162
  }
137
163
  export interface StoreSdkFinishTransactionResult {
138
164
  readonly finished: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpgd/adapter-capacitor",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "description": "Capacitor platform adapter for mpgd Android and iOS shells.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -51,11 +51,11 @@
51
51
  ],
52
52
  "dependencies": {
53
53
  "@capacitor/app": "8.1.1",
54
- "@mpgd/capacitor-game-services": "0.9.5",
55
- "@mpgd/game-services": "0.32.0",
56
- "@mpgd/target-config": "0.24.5",
57
- "@mpgd/platform": "0.34.0",
58
- "@mpgd/bridge": "0.18.0"
54
+ "@mpgd/bridge": "0.18.1",
55
+ "@mpgd/platform": "0.35.0",
56
+ "@mpgd/capacitor-game-services": "0.9.6",
57
+ "@mpgd/target-config": "0.24.7",
58
+ "@mpgd/game-services": "0.33.1"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@capacitor-community/admob": "^8.1.0",
@@ -92,7 +92,7 @@
92
92
  "ttsc": "0.34.2",
93
93
  "typescript": "7.0.2",
94
94
  "vitest": "^4.0.0",
95
- "@mpgd/game-runtime": "0.9.0"
95
+ "@mpgd/game-runtime": "0.10.1"
96
96
  },
97
97
  "main": "./dist/index.js",
98
98
  "types": "./dist/index.d.ts",