@mpgd/adapter-capacitor 0.16.3 → 0.17.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/README.md CHANGED
@@ -133,6 +133,47 @@ normalizes every SDK failure through `mapError` into a `CommerceError` whose
133
133
  `storeCode` keeps the store's own code. It never grants and never sets
134
134
  `settlement`; the backend ledger decides.
135
135
 
136
+ `purchaseGate` is an optional sales switch for new purchases, separate from
137
+ the account binding (and from StoreKit's `appAccountToken`). It is asked once
138
+ per `requestPurchase`, after the product, availability, and kind checks and
139
+ before `accountBinding`, with `{ store, logicalId, storeSku, kind, source }`,
140
+ and answers `{ allowed: true }` or `{ allowed: false, storeCode?, message?,
141
+ retryable? }`. A refusal never opens the store UI and is answered as data:
142
+ `{ outcome: 'failed', error: { code: 'ITEM_UNAVAILABLE', storeCode:
143
+ 'PURCHASES_PAUSED' } }` (or the gate's own `storeCode`), `retryable` false
144
+ unless the gate says otherwise. A gate that could not answer refuses too,
145
+ with `PURCHASE_GATE_FAILED` and always retryable, whether it threw, returned
146
+ something malformed, or did not answer within `purchaseGateTimeoutMs` (three
147
+ seconds): the sales flag is unknown rather than closed. An answer that
148
+ arrives after the timeout is ignored and never opens the store. A thrown
149
+ `CommerceError` keeps its own code, except a code that claims a launched or
150
+ cancelled sheet (`OUTCOME_UNKNOWN`, `ALREADY_OWNED`, `USER_CANCELLED`), which
151
+ becomes `PURCHASE_GATE_FAILED` because nothing was launched. The reconciler
152
+ journals a refused attempt as terminal `failed` even when it is retryable:
153
+ only trusted presentation facts (`not-started`) keep a key reusable, and the
154
+ Capacitor bridge does not carry them yet, so a later try uses a new
155
+ idempotency key. The store provider deliberately exposes no `presentation`
156
+ that could only ever say `not-started`, because the game runtime's purchase
157
+ coordinator would take it as a closure source and quarantine the game after
158
+ every launched purchase. The gate runs while the gateway already holds the
159
+ purchase's external activity (the game is paused, with no sheet shown), so it
160
+ should answer from a flag the game already holds rather than a slow network
161
+ call; the timeout bounds that pause. Recovery, restore, finishing, events, `fetchProducts`, and
162
+ `getAvailablePurchases` never
163
+ ask the gate, so purchases already paid for keep reconciling while new sales
164
+ are refused. A failed or missing account binding is a `failed` result too,
165
+ not a throw: a thrown `CommerceError` keeps its code (with the same exception
166
+ for launched or cancelled codes), and anything else is
167
+ `ACCOUNT_BINDING_REQUIRED` with `ACCOUNT_BINDING_LOOKUP_FAILED`, retryable.
168
+ Over the bridge a thrown error keeps only `code`, `message`, and
169
+ `retryable`, while a result keeps `storeCode`, so the game can tell
170
+ `PURCHASES_PAUSED` from `PLAY_BILLING_ACCOUNT_LOOKUP_FAILED`. The gate is not
171
+ reflected in `getCapabilities()`: `availability` describes the store and
172
+ gates the reconciler (a paused gate there would read as `STORE_UNAVAILABLE`
173
+ and lose the reason), and a capability read stays free of server round trips.
174
+ A shop hides its buy buttons from the same server flag it hands the gate,
175
+ for example the sales flag of its account binding response.
176
+
136
177
  Two failure classes are not terminal. When `requestPurchase` throws or
137
178
  returns a code that normalizes to `OUTCOME_UNKNOWN` (for example
138
179
  `PLAY_BILLING_TIMEOUT`, `PLAY_BILLING_INTERRUPTED`,
@@ -45,6 +45,12 @@ export interface CreateBridgeCommerceProviderInput {
45
45
  /** Sends one validated bridge request; the gateway's `request` fits. */
46
46
  readonly request: <TData>(method: BridgeCommerceV2Method, payload: unknown) => Promise<TData>;
47
47
  readonly subscribe: (listener: (event: BridgeCommerceEvent) => void) => () => void;
48
+ /**
49
+ * The bridge host accepts `FinishTransactionInput.retry` (it is built on the
50
+ * same contract and its provider declares `acceptsFinishRetry`). Absent, the
51
+ * provider does not declare it and callers never send `retry`.
52
+ */
53
+ readonly acceptsFinishRetry?: boolean;
48
54
  }
49
55
  /**
50
56
  * `CommerceProvider` over a bridge that serves the `commerce.v2.*` methods and
@@ -186,6 +186,7 @@ export function createBridgeCommerceProvider(input) {
186
186
  };
187
187
  return {
188
188
  store: input.store,
189
+ ...(input.acceptsFinishRetry === true ? { acceptsFinishRetry: true } : {}),
189
190
  async getCapabilities() {
190
191
  return (await send('commerce.v2.getCapabilities', { protocol: commerceProtocol }))
191
192
  .capabilities;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import { type CapacitorServiceProvider, type NativeBridge } from './providers.js
5
5
  export { capacitorCrashlyticsPluginName, capacitorCrashReportingProvider, createCapacitorCrashReporter, createLocalCrashCollectionPreferenceStore, type CrashCollectionPreferenceStore, type CapacitorCrashlyticsPlugin, type CapacitorCrashReporterOptions, type CapacitorCrashReportingOptions, } from './crash-reporting.js';
6
6
  export { createCapacitorProviderRegistry, createDegradedCommerceCapabilities, createDegradedNotificationCapabilities, type CapacitorCommerceServiceProvider, type CapacitorNotificationServiceProvider, type CapacitorNotificationsV2Service, type CapacitorProviderCapabilitySnapshot, type CapacitorProviderRegistry, type CapacitorServiceProvider, type NativeBridge, } from './providers.js';
7
7
  export { assertCommerceBridgeResult, commerceV2InvalidPayloadBridgeErrorCode, commerceV2MethodUnsupportedBridgeErrorCode, createBridgeCommerceProvider, createCommerceProviderBridge, createCommerceServiceProvider, type CommerceProviderBridge, type CreateBridgeCommerceProviderInput, type CreateCommerceProviderBridgeInput, type CreateCommerceServiceProviderInput, } from './commerce-bridge.js';
8
- export { createStoreCommerceProvider, recoverableErrorCodes, type CreateStoreCommerceProviderInput, type StoreCommerceCapabilityOverrides, type StoreCommerceProductMapping, type StoreCommerceProvider, } from './store-commerce-provider.js';
8
+ 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';
9
9
  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
10
  export { createCapacitorAppEvents, type CapacitorAppEventsApi, type CapacitorIncomingUrlKind, type CapacitorVisibilitySource, } from './app-events.js';
11
11
  export { CapacitorNativeHttpError, createCapacitorNativeJsonTransport, type CapacitorJsonRequest, type CapacitorJsonResponse, type CapacitorNativeHttpErrorCode, type CapacitorNativeJsonTransport, type CreateCapacitorNativeJsonTransportInput, } from './native-http.js';
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { createCapacitorViewport } from './viewport.js';
12
12
  export { capacitorCrashlyticsPluginName, capacitorCrashReportingProvider, createCapacitorCrashReporter, createLocalCrashCollectionPreferenceStore, } from './crash-reporting.js';
13
13
  export { createCapacitorProviderRegistry, createDegradedCommerceCapabilities, createDegradedNotificationCapabilities, } from './providers.js';
14
14
  export { assertCommerceBridgeResult, commerceV2InvalidPayloadBridgeErrorCode, commerceV2MethodUnsupportedBridgeErrorCode, createBridgeCommerceProvider, createCommerceProviderBridge, createCommerceServiceProvider, } from './commerce-bridge.js';
15
- export { createStoreCommerceProvider, recoverableErrorCodes, } from './store-commerce-provider.js';
15
+ export { accountBindingLookupFailedStoreCode, createStoreCommerceProvider, purchaseGateFailedStoreCode, purchaseGateTimeoutMs, purchasesPausedStoreCode, recoverableErrorCodes, } from './store-commerce-provider.js';
16
16
  export { defaultStoreSdkErrorCodeMap, normalizeStoreSdkError, } from './store-sdk.js';
17
17
  export { createCapacitorAppEvents, } from './app-events.js';
18
18
  export { CapacitorNativeHttpError, createCapacitorNativeJsonTransport, } from './native-http.js';
@@ -63,6 +63,8 @@ export function createCapacitorPlatformGateway(input) {
63
63
  ? undefined
64
64
  : createBridgeCommerceProvider({
65
65
  store: commerceProvider.commerce.store,
66
+ // The host below is this package's, on the same contract.
67
+ acceptsFinishRetry: commerceProvider.commerce.acceptsFinishRetry === true,
66
68
  request: (method, payload) => request(method, payload),
67
69
  // The provider's channel (`NativeBridge`) may carry other protocols.
68
70
  // Only an envelope that names another protocol is dropped; anything
@@ -1,5 +1,5 @@
1
1
  import type { PlatformEvidenceEnvelope } from '@mpgd/platform';
2
- import { type CommerceAuthorityCapabilities, type CommerceCatalogCapabilities, type CommerceErrorCode, type CommerceLifecycleCapabilities, type CommerceLogicalProductId, type CommerceProvider, type CommercePurchaseCapabilities, type PurchaseKind, type StoreId, type StorePurchaseAccountBinding } from '@mpgd/platform/commerce';
2
+ import { type CommerceAuthorityCapabilities, type CommerceCatalogCapabilities, type CommerceErrorCode, type CommerceLifecycleCapabilities, type CommerceLogicalProductId, type CommerceProvider, type CommercePurchaseCapabilities, type PurchaseKind, type PurchaseSource, type StoreId, type StorePurchaseAccountBinding } from '@mpgd/platform/commerce';
3
3
  import { type StoreSdk, type StoreSdkErrorCodeMap, type StoreSdkPurchase } from './store-sdk.js';
4
4
  /** One catalog product sold through the store under `storeSku`. */
5
5
  export interface StoreCommerceProductMapping {
@@ -15,6 +15,41 @@ export interface StoreCommerceCapabilityOverrides {
15
15
  readonly catalog?: Partial<CommerceCatalogCapabilities>;
16
16
  readonly lifecycle?: Partial<CommerceLifecycleCapabilities>;
17
17
  }
18
+ /** What a purchase gate is asked about: one new purchase, before any store UI opens. */
19
+ export interface StorePurchaseGateRequest {
20
+ readonly store: StoreId;
21
+ readonly logicalId: CommerceLogicalProductId;
22
+ readonly storeSku: string;
23
+ readonly kind: PurchaseKind;
24
+ readonly source: PurchaseSource;
25
+ }
26
+ /**
27
+ * A purchase gate's answer. A refusal becomes a `failed` purchase result with
28
+ * `ITEM_UNAVAILABLE` and `storeCode` (default `PURCHASES_PAUSED`), returned as
29
+ * data so the reason survives the bridge; `retryable` defaults to false.
30
+ */
31
+ export type StorePurchaseGateDecision = {
32
+ readonly allowed: true;
33
+ } | {
34
+ readonly allowed: false;
35
+ readonly storeCode?: string;
36
+ readonly message?: string;
37
+ readonly retryable?: boolean;
38
+ };
39
+ /**
40
+ * The game's sales switch: asked before a NEW purchase opens the store UI,
41
+ * after the product, availability, and kind checks and before the account
42
+ * binding. Recovery, restore, finishing, events, and `getAvailablePurchases`
43
+ * never consult it, so purchases already paid for keep reconciling while new
44
+ * sales are refused. A gate that throws refuses the purchase (fail closed).
45
+ */
46
+ export type StorePurchaseGate = (request: StorePurchaseGateRequest) => StorePurchaseGateDecision | Promise<StorePurchaseGateDecision>;
47
+ /** `storeCode` of a purchase the gate refused without naming its own. */
48
+ export declare const purchasesPausedStoreCode: 'PURCHASES_PAUSED';
49
+ /** `storeCode` of a purchase refused because the gate threw or answered nonsense. */
50
+ export declare const purchaseGateFailedStoreCode: 'PURCHASE_GATE_FAILED';
51
+ /** `storeCode` of a purchase refused because the account binding lookup threw. */
52
+ export declare const accountBindingLookupFailedStoreCode: 'ACCOUNT_BINDING_LOOKUP_FAILED';
18
53
  export interface CreateStoreCommerceProviderInput {
19
54
  readonly sdk: StoreSdk;
20
55
  /** Defaults to `sdk.store`. */
@@ -27,8 +62,15 @@ export interface CreateStoreCommerceProviderInput {
27
62
  * and SKU; a store provider replaces it to match its backend verifier.
28
63
  */
29
64
  readonly evidencePayload?: (purchase: StoreSdkPurchase) => PlatformEvidenceEnvelope['payload'];
30
- /** Resolves the player's store account binding before a purchase opens. */
65
+ /**
66
+ * Resolves the player's store account binding before a purchase opens. A
67
+ * failure (thrown, or no binding while `authority.accountBinding` is
68
+ * `required`) is answered as a `failed` purchase result, not thrown, so its
69
+ * `storeCode` survives the bridge.
70
+ */
31
71
  readonly accountBinding?: () => Promise<StorePurchaseAccountBinding | undefined>;
72
+ /** Optional sales switch for new purchases; see `StorePurchaseGate`. */
73
+ readonly purchaseGate?: StorePurchaseGate;
32
74
  readonly capabilities?: StoreCommerceCapabilityOverrides;
33
75
  readonly authority: CommerceAuthorityCapabilities;
34
76
  /** Per-store error codes merged over `defaultStoreSdkErrorCodeMap`. */
@@ -39,6 +81,13 @@ export interface StoreCommerceProvider extends CommerceProvider {
39
81
  dispose(): void;
40
82
  }
41
83
  /**
84
+ * Upper bound on one purchase gate answer. The gate runs while the gateway
85
+ * holds the purchase's external activity, so a gate that never settles would
86
+ * keep the game paused; past this bound the purchase is refused
87
+ * (`PURCHASE_GATE_FAILED`, retryable) and a late answer is ignored.
88
+ */
89
+ export declare const purchaseGateTimeoutMs = 3000;
90
+ /**
42
91
  * `CommerceProvider` over an in-process `StoreSdk`. The provider maps logical
43
92
  * ids to store SKUs both ways, composes `CommerceCapabilities` from the SDK
44
93
  * declaration, builds `StorePurchase` evidence, buffers SDK events until the
@@ -1,6 +1,19 @@
1
1
  import { assertFinishTransactionInput, assertFinishTransactionResult, assertRequestPurchaseSupported, assertStoreProduct, assertStorePurchase, CommerceError, createCommerceEventBuffer, } from '@mpgd/platform/commerce';
2
2
  import { defaultStoreSdkErrorCodeMap, normalizeStoreSdkError, } from './store-sdk.js';
3
+ /** `storeCode` of a purchase the gate refused without naming its own. */
4
+ export const purchasesPausedStoreCode = 'PURCHASES_PAUSED';
5
+ /** `storeCode` of a purchase refused because the gate threw or answered nonsense. */
6
+ export const purchaseGateFailedStoreCode = 'PURCHASE_GATE_FAILED';
7
+ /** `storeCode` of a purchase refused because the account binding lookup threw. */
8
+ export const accountBindingLookupFailedStoreCode = 'ACCOUNT_BINDING_LOOKUP_FAILED';
3
9
  const availabilityTimeoutMs = 3_000;
10
+ /**
11
+ * Upper bound on one purchase gate answer. The gate runs while the gateway
12
+ * holds the purchase's external activity, so a gate that never settles would
13
+ * keep the game paused; past this bound the purchase is refused
14
+ * (`PURCHASE_GATE_FAILED`, retryable) and a late answer is ignored.
15
+ */
16
+ export const purchaseGateTimeoutMs = 3_000;
4
17
  const availabilitySet = new Set([
5
18
  'unsupported',
6
19
  'configuration-required',
@@ -176,6 +189,8 @@ export function createStoreCommerceProvider(input) {
176
189
  const restorePurchases = sdk.restorePurchases;
177
190
  const provider = {
178
191
  store,
192
+ // `retry` is forwarded to the SDK below.
193
+ ...(finishTransaction === undefined ? {} : { acceptsFinishRetry: true }),
179
194
  getCapabilities,
180
195
  async fetchProducts(request = {}) {
181
196
  const type = request.type ?? 'all';
@@ -245,11 +260,34 @@ export function createStoreCommerceProvider(input) {
245
260
  const capabilities = await getCapabilities();
246
261
  assertAvailable(capabilities.availability, store);
247
262
  assertRequestPurchaseSupported(capabilities, request, mapping.kind);
248
- const accountBinding = await input.accountBinding?.();
249
- if (input.authority.accountBinding === 'required' && accountBinding === undefined) {
250
- throw new CommerceError('ACCOUNT_BINDING_REQUIRED', {
251
- message: `Store ${store} requires an account binding before a purchase.`,
263
+ // Pre-launch refusals below are data, not throws: a `failed` result
264
+ // keeps its `storeCode` across the bridge, a thrown error does not.
265
+ if (input.purchaseGate !== undefined) {
266
+ const refusal = await askPurchaseGate(input.purchaseGate, {
267
+ store,
268
+ logicalId: mapping.logicalId,
269
+ storeSku: mapping.storeSku,
270
+ kind: mapping.kind,
271
+ source: request.source,
252
272
  });
273
+ if (refusal !== undefined) {
274
+ return { outcome: 'failed', error: refusal };
275
+ }
276
+ }
277
+ let accountBinding;
278
+ try {
279
+ accountBinding = await input.accountBinding?.();
280
+ }
281
+ catch (error) {
282
+ return { outcome: 'failed', error: accountBindingFailure(error, store) };
283
+ }
284
+ if (input.authority.accountBinding === 'required' && accountBinding === undefined) {
285
+ return {
286
+ outcome: 'failed',
287
+ error: new CommerceError('ACCOUNT_BINDING_REQUIRED', {
288
+ message: `Store ${store} requires an account binding before a purchase.`,
289
+ }).toCommerceErrorInfo(),
290
+ };
253
291
  }
254
292
  const offerId = request.offerId ?? mapping.offerId;
255
293
  let result;
@@ -322,6 +360,7 @@ export function createStoreCommerceProvider(input) {
322
360
  transactionId: finish.transactionId,
323
361
  isConsumable: finish.isConsumable,
324
362
  ledgerEntryId: finish.ledgerEntryId,
363
+ ...(finish.retry === true ? { retry: true } : {}),
325
364
  });
326
365
  }
327
366
  catch (error) {
@@ -387,6 +426,88 @@ function defaultEvidencePayload(purchase) {
387
426
  : { originalTransactionId: purchase.originalTransactionId }),
388
427
  };
389
428
  }
429
+ /**
430
+ * Codes a pre-launch hook (the purchase gate or the account binding) must not
431
+ * report: they claim a store sheet was shown or may hold a purchase, and
432
+ * nothing was launched. A hook that throws one is reported under the hook's
433
+ * own refusal code instead.
434
+ */
435
+ function misleadsBeforeLaunch(code) {
436
+ return recoverableErrorCodes.has(code) || code === 'USER_CANCELLED';
437
+ }
438
+ /**
439
+ * Asks the gate about one new purchase, bounded by `purchaseGateTimeoutMs`;
440
+ * undefined means allowed. A refusal
441
+ * (`allowed: false`) is the gate's definitive answer: `PURCHASES_PAUSED` or
442
+ * its own code, retryable only when it says so. A gate that could not answer
443
+ * (it threw, timed out, or returned anything malformed) is `PURCHASE_GATE_FAILED`, and
444
+ * always retryable: the sales flag is unknown, not closed, so asking again
445
+ * may succeed. A thrown `CommerceError` keeps its code unless the code
446
+ * claims a launched or cancelled sheet.
447
+ */
448
+ async function askPurchaseGate(gate, request) {
449
+ const gateFailed = (message, cause) => new CommerceError('ITEM_UNAVAILABLE', {
450
+ message,
451
+ storeCode: purchaseGateFailedStoreCode,
452
+ retryable: true,
453
+ ...(cause === undefined ? {} : { cause }),
454
+ }).toCommerceErrorInfo();
455
+ let decision;
456
+ let timer;
457
+ try {
458
+ decision = await Promise.race([
459
+ Promise.resolve().then(() => gate(request)),
460
+ new Promise((_resolve, reject) => {
461
+ timer = setTimeout(() => reject(new Error(`The purchase gate did not answer within ${purchaseGateTimeoutMs} ms.`)), purchaseGateTimeoutMs);
462
+ }),
463
+ ]);
464
+ }
465
+ catch (error) {
466
+ if (error instanceof CommerceError && !misleadsBeforeLaunch(error.code)) {
467
+ return error.toCommerceErrorInfo();
468
+ }
469
+ return gateFailed(`The purchase gate of ${request.store} failed; ${request.logicalId} is not sold now.`, error);
470
+ }
471
+ finally {
472
+ if (timer !== undefined) {
473
+ clearTimeout(timer);
474
+ }
475
+ }
476
+ if (isRecord(decision) && decision.allowed === true) {
477
+ return undefined;
478
+ }
479
+ if (!isRecord(decision) || decision.allowed !== false) {
480
+ return gateFailed(`The purchase gate of ${request.store} returned an invalid decision.`);
481
+ }
482
+ const storeCode = typeof decision.storeCode === 'string' && decision.storeCode.length > 0
483
+ ? decision.storeCode
484
+ : purchasesPausedStoreCode;
485
+ return new CommerceError('ITEM_UNAVAILABLE', {
486
+ message: typeof decision.message === 'string' && decision.message.length > 0
487
+ ? decision.message
488
+ : `New purchases of ${request.logicalId} are paused.`,
489
+ storeCode,
490
+ retryable: decision.retryable === true,
491
+ }).toCommerceErrorInfo();
492
+ }
493
+ /**
494
+ * A failed account binding lookup. A `CommerceError` keeps its code (a store
495
+ * provider names its own lookup failure) unless the code claims a launched or
496
+ * cancelled sheet; anything else is `ACCOUNT_BINDING_REQUIRED` with
497
+ * `ACCOUNT_BINDING_LOOKUP_FAILED`, retryable, so every store reports the
498
+ * same reason.
499
+ */
500
+ function accountBindingFailure(error, store) {
501
+ if (error instanceof CommerceError && !misleadsBeforeLaunch(error.code)) {
502
+ return error.toCommerceErrorInfo();
503
+ }
504
+ return new CommerceError('ACCOUNT_BINDING_REQUIRED', {
505
+ message: `Store ${store} could not resolve the account binding.`,
506
+ storeCode: accountBindingLookupFailedStoreCode,
507
+ retryable: true,
508
+ cause: error,
509
+ }).toCommerceErrorInfo();
510
+ }
390
511
  function assertAvailable(availability, store) {
391
512
  switch (availability) {
392
513
  case 'available':
@@ -91,6 +91,8 @@ export interface StoreSdkPurchase {
91
91
  export interface StoreSdkFinishTransactionInput {
92
92
  readonly transactionId: string;
93
93
  readonly isConsumable: boolean;
94
+ /** `FinishTransactionInput.retry`: an earlier finish of this purchase was asked for. */
95
+ readonly retry?: boolean;
94
96
  /** The ledger entry that authorized the finish; a plugin may record it. */
95
97
  readonly ledgerEntryId: string;
96
98
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpgd/adapter-capacitor",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
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.3",
55
- "@mpgd/platform": "0.32.0",
56
- "@mpgd/game-services": "0.30.5",
57
- "@mpgd/bridge": "0.16.4",
58
- "@mpgd/target-config": "0.24.3"
54
+ "@mpgd/capacitor-game-services": "0.9.4",
55
+ "@mpgd/game-services": "0.31.0",
56
+ "@mpgd/platform": "0.33.0",
57
+ "@mpgd/bridge": "0.17.0",
58
+ "@mpgd/target-config": "0.24.4"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@capacitor-community/admob": "^8.1.0",
@@ -89,10 +89,10 @@
89
89
  "@capacitor/core": "8.5.2",
90
90
  "@capacitor/local-notifications": "8.3.1",
91
91
  "@capawesome/capacitor-app-review": "8.1.0",
92
- "ttsc": "0.32.1",
92
+ "ttsc": "0.34.2",
93
93
  "typescript": "7.0.2",
94
94
  "vitest": "^4.0.0",
95
- "@mpgd/game-runtime": "0.8.9"
95
+ "@mpgd/game-runtime": "0.8.10"
96
96
  },
97
97
  "main": "./dist/index.js",
98
98
  "types": "./dist/index.d.ts",