@mpgd/capacitor-play-billing 0.1.7 → 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/dist/provider.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Capacitor } from '@capacitor/core';
2
+ import { createGooglePlayTokenPurchaseKey } from '@mpgd/platform/commerce';
2
3
  import { CapacitorPlayBilling } from './plugin.js';
3
4
  const googlePlayProductPurchaseEvidenceSchema = 'google-play.product-purchase.v2';
4
5
  class PlayPurchaseIntegrityError extends Error {
@@ -13,6 +14,12 @@ function isValidPurchaseToken(value) {
13
14
  /**
14
15
  * Resubmit owned purchases after a callback was missed or the app restarted.
15
16
  * A native purchase is never credited locally; only the backend response grants it.
17
+ *
18
+ * @deprecated v1 recovery driver. Commerce v2 games register
19
+ * `createCapacitorPlayBillingServiceProvider` and let the single reconciler
20
+ * in `@mpgd/game-services` (PR C1) resolve unfinished purchases from
21
+ * `getAvailablePurchases` and `purchaseUpdated`; this driver is removed with
22
+ * the v1 adapter in the next major version.
16
23
  */
17
24
  export async function recoverOwnedPlayPurchases(input) {
18
25
  if (input.playerId.trim() === '') {
@@ -38,7 +45,7 @@ export async function recoverOwnedPlayPurchases(input) {
38
45
  playerId: input.playerId,
39
46
  productId,
40
47
  platformTransactionId: result.transactionId,
41
- idempotencyKey: await createGooglePlayTokenTransactionId(token),
48
+ idempotencyKey: await createGooglePlayTokenPurchaseKey(token),
42
49
  purchasedAt: purchasedAt ?? input.now?.() ?? new Date().toISOString(),
43
50
  evidence: result.evidence,
44
51
  });
@@ -268,7 +275,7 @@ async function convertPurchase(purchase) {
268
275
  return { status: 'pending', entitlementIds: [], evidence };
269
276
  }
270
277
  const transactionId = purchase.orderId?.trim()
271
- || await createGooglePlayTokenTransactionId(purchase.purchaseToken);
278
+ || await createGooglePlayTokenPurchaseKey(purchase.purchaseToken);
272
279
  return {
273
280
  status: 'completed',
274
281
  transactionId,
@@ -276,18 +283,15 @@ async function convertPurchase(purchase) {
276
283
  evidence,
277
284
  };
278
285
  }
279
- /** Must remain byte-for-byte compatible with the server's token transaction ID. */
280
- export async function createGooglePlayTokenTransactionId(purchaseToken) {
281
- if (!isValidPurchaseToken(purchaseToken)) {
282
- throw new TypeError('Google Play purchase token is invalid.');
283
- }
284
- const subtle = globalThis.crypto?.subtle;
285
- if (subtle === undefined) {
286
- throw new Error('Web Crypto is required to hash Google Play purchase tokens.');
287
- }
288
- const digest = new Uint8Array(await subtle.digest('SHA-256', new TextEncoder().encode(purchaseToken)));
289
- return `play-token-sha256:${[...digest].map((value) => value.toString(16).padStart(2, '0')).join('')}`;
290
- }
286
+ /**
287
+ * The server's token transaction ID, computed by the one shared helper so the
288
+ * plugin and `@mpgd/game-services` can never drift.
289
+ *
290
+ * @deprecated Use `createGooglePlayTokenPurchaseKey` from `@mpgd/platform/commerce`;
291
+ * this alias is the same function (same key, same `TypeError` for an invalid
292
+ * token) and will be removed in the next major version.
293
+ */
294
+ export const createGooglePlayTokenTransactionId = createGooglePlayTokenPurchaseKey;
291
295
  function success(id, data) {
292
296
  return { id, ok: true, data };
293
297
  }
@@ -0,0 +1,89 @@
1
+ import type { PlatformProviderAvailability } from '@mpgd/platform';
2
+ import { type StoreSdk, type StoreSdkCapabilities, type StoreSdkError, type StoreSdkErrorCodeMap, type StoreSdkPurchase } from '@mpgd/adapter-capacitor';
3
+ import type { CapacitorPlayBillingPlugin, PlayPurchase } from './definitions.js';
4
+ /** The store id of the Play Billing `StoreSdk` (RFC "Capabilities", `google-play`). */
5
+ export declare const googlePlayStoreId: 'google-play';
6
+ /**
7
+ * What the Play Billing plugin supports (RFC "Capabilities" profile row for
8
+ * `google-play`): one-time consumables and durables, no subscriptions, no
9
+ * multi-quantity, pending purchases, no restore call, one-time offers, and a
10
+ * server-owned finish (the backend acknowledges or consumes after the grant).
11
+ */
12
+ export declare const playBillingStoreSdkCapabilities: StoreSdkCapabilities;
13
+ /**
14
+ * `defaultStoreSdkErrorCodeMap` plus every `PLAY_BILLING_*` code the plugin or
15
+ * this SDK emits that the default map does not already normalize.
16
+ */
17
+ export declare const playBillingStoreSdkErrorCodeMap: StoreSdkErrorCodeMap;
18
+ /** One Play product the SDK sells; the provider maps it to a logical id. */
19
+ export interface PlayBillingStoreSdkProduct {
20
+ /** The Play product id (SKU). */
21
+ readonly sku: string;
22
+ readonly kind: 'consumable' | 'durable';
23
+ /**
24
+ * Default one-time offer (`offerToken`) when Play lists more than one
25
+ * eligible offer; a request may name another through `offerId`.
26
+ */
27
+ readonly offerToken?: string;
28
+ }
29
+ export interface CreateCapacitorPlayBillingStoreSdkInput {
30
+ readonly products: readonly PlayBillingStoreSdkProduct[];
31
+ /** Defaults to the registered `CapacitorPlayBilling` plugin. */
32
+ readonly plugin?: CapacitorPlayBillingPlugin;
33
+ /** Defaults to `Capacitor.getPlatform() === 'android'`. */
34
+ readonly isAndroid?: () => boolean;
35
+ /**
36
+ * Diagnostics hook for a plugin purchase the SDK leaves out of
37
+ * `getAvailablePurchases` and events: a SKU not in `products` (for example
38
+ * a retired product) or a multi-line purchase. Such a purchase has no
39
+ * logical id for the reconciler; the backend finalizer still sees it
40
+ * through the Play Developer API.
41
+ */
42
+ readonly onUnmappedPurchase?: (purchase: PlayPurchase) => void;
43
+ }
44
+ export interface CapacitorPlayBillingStoreSdk extends StoreSdk {
45
+ readonly store: typeof googlePlayStoreId;
46
+ getAvailability(): Promise<PlatformProviderAvailability>;
47
+ }
48
+ interface PlayBillingStoreSdkErrorOptions {
49
+ readonly retryable?: boolean;
50
+ readonly storeCode?: string;
51
+ readonly cause?: unknown;
52
+ }
53
+ /** A plugin rejection or an SDK integrity failure, carrying the plugin code. */
54
+ export declare class PlayBillingStoreSdkError extends Error implements StoreSdkError {
55
+ readonly code: string;
56
+ readonly retryable?: boolean;
57
+ readonly storeCode?: string;
58
+ constructor(code: string, message: string, options?: PlayBillingStoreSdkErrorOptions);
59
+ }
60
+ /**
61
+ * `StoreSdk` over `@mpgd/capacitor-play-billing`'s plugin for
62
+ * `createStoreCommerceProvider`. It speaks Play product ids and plugin codes
63
+ * only: `fetchProducts` is `getProducts`, `requestPurchase` is `purchase` with
64
+ * the obfuscated account id from the request's account binding and the offer
65
+ * token from `offerId`, `getAvailablePurchases` is `getPurchases` filtered to
66
+ * unfinished entries (purchased and not acknowledged, plus pending on
67
+ * request), and `purchaseUpdated` events are the plugin's. A purchased plugin
68
+ * outcome is `purchased`; a pending one is `launched`, because Play resolves
69
+ * it later through `purchaseUpdated` or `getPurchases`; a cancelled one is
70
+ * `cancelled`; a plugin rejection is `failed` with the plugin code, which the
71
+ * provider normalizes (`PLAY_BILLING_TIMEOUT`, `PLAY_BILLING_INTERRUPTED`, and
72
+ * `PLAY_BILLING_EMPTY_PURCHASE` become `OUTCOME_UNKNOWN` and stay recoverable).
73
+ * `transactionId` is the order id or, until Play assigns one, the token key
74
+ * `play-token-sha256:<hex>` v1 ledgers already use. Nothing here grants, and
75
+ * nothing here acknowledges or consumes: the backend finalizer owns both.
76
+ */
77
+ export declare function createCapacitorPlayBillingStoreSdk(input: CreateCapacitorPlayBillingStoreSdkInput): CapacitorPlayBillingStoreSdk;
78
+ /** Validates a purchase token exactly as the v1 provider does. */
79
+ export declare function isValidPlayPurchaseToken(value: unknown): value is string;
80
+ /**
81
+ * `StoreSdkPurchase` of one plugin purchase: `token` is the purchase token,
82
+ * `transactionId` is the order id or the token key when Play has not assigned
83
+ * one yet (the v1 rule, so ledgers written by v1 deduplicate), `purchasedAt`
84
+ * is `purchaseTime` as ISO 8601 when it is a valid instant, and the account
85
+ * binding is the obfuscated account id the purchase flow recorded. Throws
86
+ * `PLAY_BILLING_EVIDENCE_INVALID` for a shape the plugin never produces.
87
+ */
88
+ export declare function toPlayBillingSdkPurchase(purchase: PlayPurchase): Promise<StoreSdkPurchase>;
89
+ export {};