@mpgd/platform 0.21.0 → 0.22.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.
@@ -355,6 +355,14 @@ export interface CommerceConformanceContext extends CommerceConformanceFixtureCo
355
355
  export interface CommerceConformanceRunOptions {
356
356
  /** Supplies a provider over the caller's fake SDK; defaults to the fake store or the reference wallet. */
357
357
  readonly createProvider?: (context: CommerceConformanceContext) => CommerceConformanceHarness | Promise<CommerceConformanceHarness>;
358
+ /**
359
+ * Supplies the runtime under test over the harness provider, backend, and
360
+ * journal; defaults to the reference reconciler
361
+ * (`createCommerceConformanceRuntime`). The reference run an adaptive
362
+ * vector is derived from always uses the reference reconciler, so the
363
+ * derived expectations stay the RFC's regardless of the runtime under test.
364
+ */
365
+ readonly createRuntime?: (input: CreateCommerceConformanceRuntimeInput, context: CommerceConformanceContext) => CommerceConformanceRuntime | Promise<CommerceConformanceRuntime>;
358
366
  readonly playerId?: string;
359
367
  readonly titleId?: string;
360
368
  }
@@ -1107,7 +1107,7 @@ async function runVectorIn(vector, options, family) {
1107
1107
  // A harness that cannot be built is a failed run, never a rejected promise.
1108
1108
  let execution;
1109
1109
  try {
1110
- execution = await prepareExecution(vector, options.createProvider ?? createCommerceConformanceHarness, ids);
1110
+ execution = await prepareExecution(vector, options.createProvider ?? createCommerceConformanceHarness, ids, options.createRuntime);
1111
1111
  }
1112
1112
  catch (error) {
1113
1113
  return failed([
@@ -1200,7 +1200,7 @@ async function runVectorIn(vector, options, family) {
1200
1200
  ...(adaptive === undefined ? {} : { adaptive }),
1201
1201
  };
1202
1202
  }
1203
- async function prepareExecution(vector, createHarness, ids) {
1203
+ async function prepareExecution(vector, createHarness, ids, createRuntime) {
1204
1204
  const clock = createCommerceConformanceClock();
1205
1205
  const journal = createCommerceConformanceJournal();
1206
1206
  const harnessRef = {};
@@ -1224,14 +1224,17 @@ async function prepareExecution(vector, createHarness, ids) {
1224
1224
  };
1225
1225
  const harness = await createHarness(context);
1226
1226
  harnessRef.current = harness;
1227
- const runtime = createCommerceConformanceRuntime({
1227
+ const runtimeInput = {
1228
1228
  provider: harness.provider,
1229
1229
  backend,
1230
1230
  journal,
1231
1231
  clock,
1232
1232
  catalog: context.catalog,
1233
1233
  playerId: ids.playerId,
1234
- });
1234
+ };
1235
+ const runtime = createRuntime === undefined
1236
+ ? createCommerceConformanceRuntime(runtimeInput)
1237
+ : await createRuntime(runtimeInput, context);
1235
1238
  return { vector, harness, runtime, backend, journal, clock, adaptation };
1236
1239
  }
1237
1240
  /** Runs every step; a thrown step ends the run with a failure at that step. */
@@ -1,4 +1,4 @@
1
- import type { CommerceCapabilities, LogicalProductId, PlatformEvidenceEnvelope, StarterLogicalProductId } from './index.js';
1
+ import type { CommerceCapabilities, CommerceFinishOwner, LogicalProductId, PlatformEvidenceEnvelope, StarterLogicalProductId } from './index.js';
2
2
  /**
3
3
  * Commerce v2 client contract types (RFC "Client contract"). This module is
4
4
  * typia-free on purpose: `./index` references `CommerceProvider` for
@@ -199,7 +199,13 @@ export interface CommerceProvider {
199
199
  requestPurchase(input: RequestPurchaseInput): Promise<RequestPurchaseResult>;
200
200
  /** Purchases the store still reports as unfinished. */
201
201
  getAvailablePurchases(input?: GetAvailablePurchasesInput): Promise<readonly StorePurchase[]>;
202
- /** Required when `lifecycle.finish` is 'client' or 'host'. */
202
+ /**
203
+ * Required when `lifecycle.finish` is 'client' or 'host'. Idempotent per
204
+ * transaction: the reconciler calls it again after a crash between a
205
+ * successful finish and its journal write, and on every pass while a
206
+ * finish keeps failing, so finishing an already finished transaction
207
+ * answers `{ finished: true }` rather than failing.
208
+ */
203
209
  finishTransaction?(input: FinishTransactionInput): Promise<FinishTransactionResult>;
204
210
  /** Asks the store to resynchronize, for example `AppStore.sync`. */
205
211
  restorePurchases?(): Promise<void>;
@@ -219,4 +225,27 @@ export interface ActiveSubscription {
219
225
  readonly expiresAt: IsoTimestamp;
220
226
  readonly autoRenew: boolean;
221
227
  }
228
+ /** What the backend accepts for one store (RFC "Provider capabilities endpoint"). */
229
+ export interface CommerceServiceStoreCapabilities {
230
+ readonly store: StoreId;
231
+ /** Evidence schemas the backend routes for this store. */
232
+ readonly schemas: readonly NonEmptyString[];
233
+ /** Who finishes a granted purchase of this store, as the backend expects it. */
234
+ readonly finish: CommerceFinishOwner;
235
+ readonly purchase: {
236
+ readonly consumable: boolean;
237
+ readonly durable: boolean;
238
+ readonly subscription: boolean;
239
+ };
240
+ }
241
+ /**
242
+ * The backend's published commerce capabilities (RFC "Provider capabilities
243
+ * endpoint"): the protocol version it speaks and one row per store its
244
+ * evidence registry accepts. The client runtime compares it with its
245
+ * provider's capability block at start.
246
+ */
247
+ export interface CommerceServiceCapabilities {
248
+ readonly commerceProtocolVersion: NonEmptyString;
249
+ readonly stores: readonly CommerceServiceStoreCapabilities[];
250
+ }
222
251
  export {};
@@ -1,6 +1,6 @@
1
1
  import { type tags } from 'typia';
2
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
+ import type { ActiveSubscription, CommerceErrorCode, CommerceErrorInfo, CommerceEvent, CommerceLogicalProductId, CommerceProvider, CommerceServiceCapabilities, FetchProductsInput, FinishTransactionInput, FinishTransactionResult, GetAvailablePurchasesInput, IsoTimestamp, NonEmptyString, NonNegativeInteger, PositiveQuantity, PurchaseKind, RequestPurchaseInput, RequestPurchaseResult, StoreId, StoreProduct, StorePurchase } from './commerce-contract.js';
4
4
  export { createUnsupportedCommerceCapabilities, deriveLegacyCommerceCapabilities, type LegacyCommerceCapabilities, } from './commerce-capabilities.js';
5
5
  export type { CommerceAccountBindingPolicy, CommerceAuthorityCapabilities, CommerceCapabilities, CommerceCatalogCapabilities, CommerceEvidenceAuthority, CommerceFinishOwner, CommerceLifecycleCapabilities, CommercePurchaseCapabilities, } from './index.js';
6
6
  /**
@@ -11,7 +11,7 @@ export type { CommerceAccountBindingPolicy, CommerceAuthorityCapabilities, Comme
11
11
  */
12
12
  export declare const commerceProtocolVersion: '2.0.0-draft.1';
13
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';
14
+ export type { ActiveSubscription, ActiveSubscriptionState, CommerceErrorCode, CommerceErrorInfo, CommerceEvent, CommerceLogicalProductId, CommerceProvider, CommerceServiceCapabilities, CommerceServiceStoreCapabilities, FetchProductsInput, FetchProductsType, FinishTransactionInput, FinishTransactionResult, GetAvailablePurchasesInput, PurchaseKind, PurchaseSource, RequestPurchaseInput, RequestPurchaseResult, StoreId, StoreOffer, StorePrice, StoreProduct, StorePurchase, StorePurchaseAccountBinding, StorePurchaseState, } from './commerce-contract.js';
15
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
16
  /** Bridge event envelope; `sequence` is per session and starts at 0. */
17
17
  export interface CommerceEventEnvelope {
@@ -250,8 +250,9 @@ export interface DerivedPurchaseIdempotencyKeyInput {
250
250
  * the same key: `store:<storeId>:<transactionId>` by default, with each
251
251
  * component percent-encoded (`encodeURIComponent`) so ids containing `:`
252
252
  * cannot collide, and the forms v1 ledgers already use for Google Play
253
- * (`play-token-sha256:<hex>`) and Apps in Toss (`apps-in-toss:purchase:<orderId>`),
254
- * which stay byte-identical.
253
+ * (`play-token-sha256:<hex>`) and Apps in Toss
254
+ * (`apps-in-toss:purchase:<encodeURIComponent(orderId)>`), which stay
255
+ * byte-identical.
255
256
  */
256
257
  export declare function createDerivedPurchaseIdempotencyKey(input: DerivedPurchaseIdempotencyKeyInput): Promise<string>;
257
258
  /** Byte-for-byte the v1 `createGooglePlayTokenTransactionId` form; A4 replaces the two copies with this helper. */
@@ -292,6 +293,8 @@ export declare const isActiveSubscription: (input: unknown) => input is ActiveSu
292
293
  export declare const assertFetchProductsInput: (input: unknown) => FetchProductsInput;
293
294
  export declare const assertCommerceCapabilities: (input: unknown) => CommerceCapabilities;
294
295
  export declare const isCommerceCapabilities: (input: unknown) => input is CommerceCapabilities;
296
+ export declare const assertCommerceServiceCapabilities: (input: unknown) => CommerceServiceCapabilities;
297
+ export declare const isCommerceServiceCapabilities: (input: unknown) => input is CommerceServiceCapabilities;
295
298
  export declare const assertCommerceErrorInfo: (input: unknown) => CommerceErrorInfo;
296
299
  export declare const assertCreditOffer: (input: unknown) => CreditOffer;
297
300
  export declare const assertCreditSpendInput: (input: unknown) => CreditSpendInput;
package/dist/commerce.js CHANGED
@@ -204,8 +204,9 @@ export function assertRequestPurchaseSupported(capabilities, input, kind) {
204
204
  * the same key: `store:<storeId>:<transactionId>` by default, with each
205
205
  * component percent-encoded (`encodeURIComponent`) so ids containing `:`
206
206
  * cannot collide, and the forms v1 ledgers already use for Google Play
207
- * (`play-token-sha256:<hex>`) and Apps in Toss (`apps-in-toss:purchase:<orderId>`),
208
- * which stay byte-identical.
207
+ * (`play-token-sha256:<hex>`) and Apps in Toss
208
+ * (`apps-in-toss:purchase:<encodeURIComponent(orderId)>`), which stay
209
+ * byte-identical.
209
210
  */
210
211
  export async function createDerivedPurchaseIdempotencyKey(input) {
211
212
  const store = readIdentifier(input.store, 128);
@@ -220,7 +221,8 @@ export async function createDerivedPurchaseIdempotencyKey(input) {
220
221
  throw new TypeError('Derived purchase keys require a transaction id.');
221
222
  }
222
223
  if (store === 'apps-in-toss') {
223
- return `apps-in-toss:purchase:${transactionId}`;
224
+ // Byte for byte the v1 `createAppsInTossPurchaseIdempotencyKey` form.
225
+ return `apps-in-toss:purchase:${encodeURIComponent(transactionId)}`;
224
226
  }
225
227
  return `store:${encodeURIComponent(store)}:${encodeURIComponent(transactionId)}`;
226
228
  }
@@ -3307,6 +3309,207 @@ export const isCommerceCapabilities = (() => {
3307
3309
  }));
3308
3310
  return (input, _exceptionable = true) => "object" === typeof input && null !== input && _io0(input, true);
3309
3311
  })();
3312
+ export const assertCommerceServiceCapabilities = (() => {
3313
+ const _ao0 = (input, _path, _exceptionable = true) => ("string" === typeof input.commerceProtocolVersion && (1 <= input.commerceProtocolVersion.length || _assertGuard_1._assertGuard(_exceptionable, {
3314
+ method: "typia.createAssertEquals",
3315
+ path: _path + ".commerceProtocolVersion",
3316
+ expected: "string & CommerceMinLength<1>",
3317
+ value: input.commerceProtocolVersion
3318
+ }, _errorFactory)) || _assertGuard_1._assertGuard(_exceptionable, {
3319
+ method: "typia.createAssertEquals",
3320
+ path: _path + ".commerceProtocolVersion",
3321
+ expected: "(string & CommerceMinLength<1>)",
3322
+ value: input.commerceProtocolVersion
3323
+ }, _errorFactory)) && ((Array.isArray(input.stores) || _assertGuard_1._assertGuard(_exceptionable, {
3324
+ method: "typia.createAssertEquals",
3325
+ path: _path + ".stores",
3326
+ expected: "ReadonlyArray<CommerceServiceStoreCapabilities>",
3327
+ value: input.stores
3328
+ }, _errorFactory)) && input.stores.every((elem, _index3) => ("object" === typeof elem && null !== elem || _assertGuard_1._assertGuard(_exceptionable, {
3329
+ method: "typia.createAssertEquals",
3330
+ path: _path + ".stores[" + _index3 + "]",
3331
+ expected: "CommerceServiceStoreCapabilities",
3332
+ value: elem
3333
+ }, _errorFactory)) && _ao1(elem, _path + ".stores[" + _index3 + "]", true && _exceptionable) || _assertGuard_1._assertGuard(_exceptionable, {
3334
+ method: "typia.createAssertEquals",
3335
+ path: _path + ".stores[" + _index3 + "]",
3336
+ expected: "CommerceServiceStoreCapabilities",
3337
+ value: elem
3338
+ }, _errorFactory)) || _assertGuard_1._assertGuard(_exceptionable, {
3339
+ method: "typia.createAssertEquals",
3340
+ path: _path + ".stores",
3341
+ expected: "ReadonlyArray<CommerceServiceStoreCapabilities>",
3342
+ value: input.stores
3343
+ }, _errorFactory)) && (2 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
3344
+ if (["commerceProtocolVersion", "stores"].some(prop => key === prop))
3345
+ return true;
3346
+ const value = input[key];
3347
+ if (undefined === value)
3348
+ return true;
3349
+ return _assertGuard_1._assertGuard(_exceptionable, {
3350
+ method: "typia.createAssertEquals",
3351
+ path: _path + _accessExpressionAsString_1._accessExpressionAsString(key),
3352
+ expected: "undefined",
3353
+ value: value
3354
+ }, _errorFactory);
3355
+ })));
3356
+ const _ao1 = (input, _path, _exceptionable = true) => ("string" === typeof input.store && (1 <= input.store.length || _assertGuard_1._assertGuard(_exceptionable, {
3357
+ method: "typia.createAssertEquals",
3358
+ path: _path + ".store",
3359
+ expected: "string & CommerceMinLength<1>",
3360
+ value: input.store
3361
+ }, _errorFactory)) || _assertGuard_1._assertGuard(_exceptionable, {
3362
+ method: "typia.createAssertEquals",
3363
+ path: _path + ".store",
3364
+ expected: "(string & CommerceMinLength<1>)",
3365
+ value: input.store
3366
+ }, _errorFactory)) && ((Array.isArray(input.schemas) || _assertGuard_1._assertGuard(_exceptionable, {
3367
+ method: "typia.createAssertEquals",
3368
+ path: _path + ".schemas",
3369
+ expected: "ReadonlyArray<NonEmptyString>",
3370
+ value: input.schemas
3371
+ }, _errorFactory)) && input.schemas.every((elem, _index4) => "string" === typeof elem && (1 <= elem.length || _assertGuard_1._assertGuard(_exceptionable, {
3372
+ method: "typia.createAssertEquals",
3373
+ path: _path + ".schemas[" + _index4 + "]",
3374
+ expected: "string & CommerceMinLength<1>",
3375
+ value: elem
3376
+ }, _errorFactory)) || _assertGuard_1._assertGuard(_exceptionable, {
3377
+ method: "typia.createAssertEquals",
3378
+ path: _path + ".schemas[" + _index4 + "]",
3379
+ expected: "(string & CommerceMinLength<1>)",
3380
+ value: elem
3381
+ }, _errorFactory)) || _assertGuard_1._assertGuard(_exceptionable, {
3382
+ method: "typia.createAssertEquals",
3383
+ path: _path + ".schemas",
3384
+ expected: "ReadonlyArray<NonEmptyString>",
3385
+ value: input.schemas
3386
+ }, _errorFactory)) && ("client" === input.finish || "host" === input.finish || "none" === input.finish || "server" === input.finish || _assertGuard_1._assertGuard(_exceptionable, {
3387
+ method: "typia.createAssertEquals",
3388
+ path: _path + ".finish",
3389
+ expected: "(\"client\" | \"host\" | \"none\" | \"server\")",
3390
+ value: input.finish
3391
+ }, _errorFactory)) && (("object" === typeof input.purchase && null !== input.purchase || _assertGuard_1._assertGuard(_exceptionable, {
3392
+ method: "typia.createAssertEquals",
3393
+ path: _path + ".purchase",
3394
+ expected: "{ readonly consumable: boolean; readonly durable: boolean; readonly subscription: boolean; }",
3395
+ value: input.purchase
3396
+ }, _errorFactory)) && _ao2(input.purchase, _path + ".purchase", true && _exceptionable) || _assertGuard_1._assertGuard(_exceptionable, {
3397
+ method: "typia.createAssertEquals",
3398
+ path: _path + ".purchase",
3399
+ expected: "{ readonly consumable: boolean; readonly durable: boolean; readonly subscription: boolean; }",
3400
+ value: input.purchase
3401
+ }, _errorFactory)) && (4 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
3402
+ if (["store", "schemas", "finish", "purchase"].some(prop => key === prop))
3403
+ return true;
3404
+ const value = input[key];
3405
+ if (undefined === value)
3406
+ return true;
3407
+ return _assertGuard_1._assertGuard(_exceptionable, {
3408
+ method: "typia.createAssertEquals",
3409
+ path: _path + _accessExpressionAsString_1._accessExpressionAsString(key),
3410
+ expected: "undefined",
3411
+ value: value
3412
+ }, _errorFactory);
3413
+ })));
3414
+ const _ao2 = (input, _path, _exceptionable = true) => ("boolean" === typeof input.consumable || _assertGuard_1._assertGuard(_exceptionable, {
3415
+ method: "typia.createAssertEquals",
3416
+ path: _path + ".consumable",
3417
+ expected: "boolean",
3418
+ value: input.consumable
3419
+ }, _errorFactory)) && ("boolean" === typeof input.durable || _assertGuard_1._assertGuard(_exceptionable, {
3420
+ method: "typia.createAssertEquals",
3421
+ path: _path + ".durable",
3422
+ expected: "boolean",
3423
+ value: input.durable
3424
+ }, _errorFactory)) && ("boolean" === typeof input.subscription || _assertGuard_1._assertGuard(_exceptionable, {
3425
+ method: "typia.createAssertEquals",
3426
+ path: _path + ".subscription",
3427
+ expected: "boolean",
3428
+ value: input.subscription
3429
+ }, _errorFactory)) && (3 === Object.keys(input).length || (false === _exceptionable || Object.keys(input).every(key => {
3430
+ if (["consumable", "durable", "subscription"].some(prop => key === prop))
3431
+ return true;
3432
+ const value = input[key];
3433
+ if (undefined === value)
3434
+ return true;
3435
+ return _assertGuard_1._assertGuard(_exceptionable, {
3436
+ method: "typia.createAssertEquals",
3437
+ path: _path + _accessExpressionAsString_1._accessExpressionAsString(key),
3438
+ expected: "undefined",
3439
+ value: value
3440
+ }, _errorFactory);
3441
+ })));
3442
+ const _io0 = (input, _exceptionable = true) => "string" === typeof input.commerceProtocolVersion && 1 <= input.commerceProtocolVersion.length && (Array.isArray(input.stores) && input.stores.every((elem, _index1) => "object" === typeof elem && null !== elem && _io1(elem, true && _exceptionable))) && (2 === Object.keys(input).length || Object.keys(input).every(key => {
3443
+ if (["commerceProtocolVersion", "stores"].some(prop => key === prop))
3444
+ return true;
3445
+ const value = input[key];
3446
+ if (undefined === value)
3447
+ return true;
3448
+ return false;
3449
+ }));
3450
+ const _io1 = (input, _exceptionable = true) => "string" === typeof input.store && 1 <= input.store.length && (Array.isArray(input.schemas) && input.schemas.every((elem, _index2) => "string" === typeof elem && 1 <= elem.length)) && ("client" === input.finish || "host" === input.finish || "none" === input.finish || "server" === input.finish) && ("object" === typeof input.purchase && null !== input.purchase && _io2(input.purchase, true && _exceptionable)) && (4 === Object.keys(input).length || Object.keys(input).every(key => {
3451
+ if (["store", "schemas", "finish", "purchase"].some(prop => key === prop))
3452
+ return true;
3453
+ const value = input[key];
3454
+ if (undefined === value)
3455
+ return true;
3456
+ return false;
3457
+ }));
3458
+ const _io2 = (input, _exceptionable = true) => "boolean" === typeof input.consumable && "boolean" === typeof input.durable && "boolean" === typeof input.subscription && (3 === Object.keys(input).length || Object.keys(input).every(key => {
3459
+ if (["consumable", "durable", "subscription"].some(prop => key === prop))
3460
+ return true;
3461
+ const value = input[key];
3462
+ if (undefined === value)
3463
+ return true;
3464
+ return false;
3465
+ }));
3466
+ const __is = (input, _exceptionable = true) => "object" === typeof input && null !== input && _io0(input, true);
3467
+ let _errorFactory;
3468
+ return (input, errorFactory) => {
3469
+ if (false === __is(input)) {
3470
+ _errorFactory = errorFactory;
3471
+ ((input, _path, _exceptionable = true) => ("object" === typeof input && null !== input || _assertGuard_1._assertGuard(true, {
3472
+ method: "typia.createAssertEquals",
3473
+ path: _path + "",
3474
+ expected: "CommerceServiceCapabilities",
3475
+ value: input
3476
+ }, _errorFactory)) && _ao0(input, _path + "", true) || _assertGuard_1._assertGuard(true, {
3477
+ method: "typia.createAssertEquals",
3478
+ path: _path + "",
3479
+ expected: "CommerceServiceCapabilities",
3480
+ value: input
3481
+ }, _errorFactory))(input, "$input", true);
3482
+ }
3483
+ return input;
3484
+ };
3485
+ })();
3486
+ export const isCommerceServiceCapabilities = (() => {
3487
+ const _io0 = (input, _exceptionable = true) => "string" === typeof input.commerceProtocolVersion && 1 <= input.commerceProtocolVersion.length && (Array.isArray(input.stores) && input.stores.every((elem, _index1) => "object" === typeof elem && null !== elem && _io1(elem, true && _exceptionable))) && (2 === Object.keys(input).length || Object.keys(input).every(key => {
3488
+ if (["commerceProtocolVersion", "stores"].some(prop => key === prop))
3489
+ return true;
3490
+ const value = input[key];
3491
+ if (undefined === value)
3492
+ return true;
3493
+ return false;
3494
+ }));
3495
+ const _io1 = (input, _exceptionable = true) => "string" === typeof input.store && 1 <= input.store.length && (Array.isArray(input.schemas) && input.schemas.every((elem, _index2) => "string" === typeof elem && 1 <= elem.length)) && ("client" === input.finish || "host" === input.finish || "none" === input.finish || "server" === input.finish) && ("object" === typeof input.purchase && null !== input.purchase && _io2(input.purchase, true && _exceptionable)) && (4 === Object.keys(input).length || Object.keys(input).every(key => {
3496
+ if (["store", "schemas", "finish", "purchase"].some(prop => key === prop))
3497
+ return true;
3498
+ const value = input[key];
3499
+ if (undefined === value)
3500
+ return true;
3501
+ return false;
3502
+ }));
3503
+ const _io2 = (input, _exceptionable = true) => "boolean" === typeof input.consumable && "boolean" === typeof input.durable && "boolean" === typeof input.subscription && (3 === Object.keys(input).length || Object.keys(input).every(key => {
3504
+ if (["consumable", "durable", "subscription"].some(prop => key === prop))
3505
+ return true;
3506
+ const value = input[key];
3507
+ if (undefined === value)
3508
+ return true;
3509
+ return false;
3510
+ }));
3511
+ return (input, _exceptionable = true) => "object" === typeof input && null !== input && _io0(input, true);
3512
+ })();
3310
3513
  export const assertCommerceErrorInfo = (() => {
3311
3514
  const _iv0 = new Set(["ACCOUNT_BINDING_REQUIRED", "ACTION_REQUIRED", "ALREADY_OWNED", "CONFIGURATION_REQUIRED", "INSUFFICIENT_BALANCE", "INVALID_RESPONSE", "IN_PROGRESS", "ITEM_UNAVAILABLE", "NETWORK", "NOT_PREPARED", "OUTCOME_UNKNOWN", "STORE_UNAVAILABLE", "UNKNOWN", "USER_CANCELLED"]);
3312
3515
  const _av0 = new Set(["ACCOUNT_BINDING_REQUIRED", "ACTION_REQUIRED", "ALREADY_OWNED", "CONFIGURATION_REQUIRED", "INSUFFICIENT_BALANCE", "INVALID_RESPONSE", "IN_PROGRESS", "ITEM_UNAVAILABLE", "NETWORK", "NOT_PREPARED", "OUTCOME_UNKNOWN", "STORE_UNAVAILABLE", "UNKNOWN", "USER_CANCELLED"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpgd/platform",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Shared platform gateway, monetization, ads, leaderboard, identity, lifecycle, and storage contracts for mpgd games.",
5
5
  "license": "MIT",
6
6
  "repository": {