@ait-kit/sdk 0.4.0 → 0.5.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 +95 -21
- package/dist/ads/adapter.d.ts +36 -0
- package/dist/ads/adapter.d.ts.map +1 -0
- package/dist/ads/adapter.js +219 -0
- package/dist/ads/platform-contract.d.ts +45 -0
- package/dist/ads/platform-contract.d.ts.map +1 -0
- package/dist/ads/platform-contract.js +7 -0
- package/dist/iap/adapter.d.ts +11 -1
- package/dist/iap/adapter.d.ts.map +1 -1
- package/dist/iap/adapter.js +13 -0
- package/dist/iap/order-history.d.ts +6 -0
- package/dist/iap/order-history.d.ts.map +1 -0
- package/dist/iap/order-history.js +54 -0
- package/dist/iap/platform-contract.d.ts +9 -1
- package/dist/iap/platform-contract.d.ts.map +1 -1
- package/dist/iap/platform-contract.js +1 -1
- package/dist/iap/purchase-flow.d.ts +1 -1
- package/dist/iap/purchase-flow.js +1 -1
- package/dist/iap/subscription-info.d.ts +6 -0
- package/dist/iap/subscription-info.d.ts.map +1 -0
- package/dist/iap/subscription-info.js +38 -0
- package/dist/identity/platform-contract.d.ts +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/notification/platform-contract.d.ts +1 -1
- package/dist/rn/ads.d.ts +7 -36
- package/dist/rn/ads.d.ts.map +1 -1
- package/dist/rn/ads.js +2 -223
- package/dist/rn/framework-contract.d.ts +1 -44
- package/dist/rn/framework-contract.d.ts.map +1 -1
- package/dist/rn/framework-contract.js +0 -6
- package/dist/rn/iap.d.ts +1 -1
- package/dist/rn/iap.d.ts.map +1 -1
- package/dist/rn/iap.js +1 -1
- package/dist/share/platform-contract.d.ts +1 -1
- package/dist/storage/platform-contract.d.ts +1 -1
- package/dist/webview/ads.d.ts +10 -0
- package/dist/webview/ads.d.ts.map +1 -0
- package/dist/webview/ads.js +14 -0
- package/dist/webview/banner-contract.d.ts +59 -0
- package/dist/webview/banner-contract.d.ts.map +1 -0
- package/dist/webview/banner.d.ts +15 -0
- package/dist/webview/banner.d.ts.map +1 -0
- package/dist/webview/banner.js +188 -0
- package/dist/{web → webview}/framework-loader.d.ts +1 -1
- package/dist/webview/framework-loader.d.ts.map +1 -0
- package/dist/{web → webview}/framework-loader.js +3 -3
- package/dist/{web → webview}/iap-contract.d.ts +4 -4
- package/dist/webview/iap-contract.d.ts.map +1 -0
- package/dist/webview/iap-contract.js +1 -0
- package/dist/webview/identity.d.ts +40 -0
- package/dist/webview/identity.d.ts.map +1 -0
- package/dist/{web → webview}/identity.js +17 -13
- package/dist/webview/index.d.ts +62 -0
- package/dist/webview/index.d.ts.map +1 -0
- package/dist/{web → webview}/index.js +20 -11
- package/dist/webview/notify-share.d.ts +50 -0
- package/dist/webview/notify-share.d.ts.map +1 -0
- package/dist/{web → webview}/notify-share.js +18 -14
- package/dist/webview/platform-loader.d.ts +4 -0
- package/dist/webview/platform-loader.d.ts.map +1 -0
- package/dist/{web → webview}/platform-loader.js +1 -1
- package/dist/webview/promotion.d.ts +13 -0
- package/dist/webview/promotion.d.ts.map +1 -0
- package/dist/{web → webview}/promotion.js +5 -3
- package/dist/webview/review.d.ts +11 -0
- package/dist/webview/review.d.ts.map +1 -0
- package/dist/webview/review.js +11 -0
- package/package.json +7 -3
- package/dist/web/framework-loader.d.ts.map +0 -1
- package/dist/web/iap-contract.d.ts.map +0 -1
- package/dist/web/identity.d.ts +0 -30
- package/dist/web/identity.d.ts.map +0 -1
- package/dist/web/index.d.ts +0 -49
- package/dist/web/index.d.ts.map +0 -1
- package/dist/web/notify-share.d.ts +0 -38
- package/dist/web/notify-share.d.ts.map +0 -1
- package/dist/web/platform-loader.d.ts +0 -4
- package/dist/web/platform-loader.d.ts.map +0 -1
- package/dist/web/promotion.d.ts +0 -9
- package/dist/web/promotion.d.ts.map +0 -1
- package/dist/web/review.d.ts +0 -7
- package/dist/web/review.d.ts.map +0 -1
- package/dist/web/review.js +0 -9
- /package/dist/{web/iap-contract.js → webview/banner-contract.js} +0 -0
package/README.md
CHANGED
|
@@ -13,20 +13,20 @@ npm install @ait-kit/sdk
|
|
|
13
13
|
|---|---|
|
|
14
14
|
| `@ait-kit/sdk` (root) | Runtime-neutral shared contracts: ad + IAP types, `SdkError`. Importable anywhere — plain Node, web, React Native — with no official SDK installed. |
|
|
15
15
|
| `@ait-kit/sdk/rn` | React Native adapters (full-screen ads, IAP). Requires the official `@apps-in-toss/framework`, declared as an **optional peer** and imported lazily. Never requires the web SDK. |
|
|
16
|
-
| `@ait-kit/sdk/
|
|
16
|
+
| `@ait-kit/sdk/webview` | WebView adapters for ads, banners, purchases, identity, storage, notifications, sharing, reviews, and promotions. Requires the official `@apps-in-toss/web-framework`, declared as an **optional peer** and imported lazily. Never requires the React Native SDK. |
|
|
17
17
|
|
|
18
18
|
The two platform entries share one internal engine but keep completely
|
|
19
19
|
separate SDK connections — in JavaScript and in the shipped type
|
|
20
20
|
declarations — so an `/rn` consumer never installs the web package and vice
|
|
21
21
|
versa.
|
|
22
22
|
|
|
23
|
-
## In-app purchases (RN +
|
|
23
|
+
## In-app purchases (RN + WebView)
|
|
24
24
|
|
|
25
25
|
Both entries expose the same IAP surface; only the loader differs:
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
28
|
import { createReactNativeIap } from "@ait-kit/sdk/rn"; // or:
|
|
29
|
-
import {
|
|
29
|
+
import { createWebViewIap } from "@ait-kit/sdk/webview";
|
|
30
30
|
|
|
31
31
|
const iap = createReactNativeIap({
|
|
32
32
|
// The ONLY place product delivery happens. Resolve only after YOUR
|
|
@@ -90,25 +90,28 @@ SDK initialization never grants or completes pending orders by itself.
|
|
|
90
90
|
|
|
91
91
|
### Feature matrix
|
|
92
92
|
|
|
93
|
-
| Capability | `/rn` | `/
|
|
93
|
+
| Capability | `/rn` | `/webview` | Notes |
|
|
94
94
|
|---|---|---|---|
|
|
95
95
|
| Product list | ✅ | ✅ | one-time + subscription together |
|
|
96
96
|
| One-time purchase | ✅ | ✅ | grant callback contract applies |
|
|
97
97
|
| Subscription purchase | ✅ | ✅ | `offerId` optional; `subscriptionId` surfaced on completion |
|
|
98
|
+
| Subscription info | ✅ | ✅ | read-only provider status and access snapshot |
|
|
99
|
+
| Completed/refunded orders | ✅ cursor | ✅ first page only | read-only; no automatic restore or refund actions |
|
|
98
100
|
| Pending orders | ✅ | ✅ | recovery is consumer-driven |
|
|
99
101
|
| Grant completion notify | ✅ | ✅ | sent only after server grant confirms |
|
|
100
|
-
| Full-screen ads | ✅ |
|
|
102
|
+
| Full-screen / rewarded ads | ✅ | ✅ | reward events only; reload after each show |
|
|
103
|
+
| Banner lifecycle | ➖ | ✅ | initialize, attach, cancel, and destroy an owned handle |
|
|
101
104
|
| Notification agreement | ✅ | ✅ | event-based, one template per request |
|
|
102
105
|
| Share link / share sheet | ✅ | ✅ | `intoss://` paths; `completed` ≠ shared |
|
|
103
106
|
| Unsupported app version | `SdkError("UNSUPPORTED")` | same | per-function `isSupported` gates |
|
|
104
107
|
|
|
105
108
|
Notification and sharing adapters ship in both entries (see below).
|
|
106
109
|
|
|
107
|
-
## Login, anonymous identity, and storage (RN +
|
|
110
|
+
## Login, anonymous identity, and storage (RN + WebView)
|
|
108
111
|
|
|
109
112
|
```ts
|
|
110
113
|
import { createReactNativeIdentity, createReactNativeStorage } from "@ait-kit/sdk/rn";
|
|
111
|
-
// or: import {
|
|
114
|
+
// or: import { createWebViewIdentity, createWebViewStorage } from "@ait-kit/sdk/webview";
|
|
112
115
|
|
|
113
116
|
const identity = createReactNativeIdentity();
|
|
114
117
|
|
|
@@ -153,14 +156,14 @@ Contracts:
|
|
|
153
156
|
- Session invalidation when the anonymous identifier changes, migration of
|
|
154
157
|
previously stored keys, and bootstrap sequencing stay with the consumer.
|
|
155
158
|
|
|
156
|
-
## Notification agreement and sharing (RN +
|
|
159
|
+
## Notification agreement and sharing (RN + WebView)
|
|
157
160
|
|
|
158
161
|
```ts
|
|
159
162
|
import {
|
|
160
163
|
createReactNativeNotification,
|
|
161
164
|
createReactNativeShare
|
|
162
165
|
} from "@ait-kit/sdk/rn";
|
|
163
|
-
// or: import {
|
|
166
|
+
// or: import { createWebViewNotification, createWebViewShare } from "@ait-kit/sdk/webview";
|
|
164
167
|
|
|
165
168
|
// 1. Notification agreement: one template, one request.
|
|
166
169
|
const notification = createReactNativeNotification();
|
|
@@ -197,11 +200,12 @@ Contracts:
|
|
|
197
200
|
stay with the consumer. (Renamed from `closed` in 0.3.0; see Migrating.)
|
|
198
201
|
- Unsupported surfaces/app versions reject with `SdkError("UNSUPPORTED")`.
|
|
199
202
|
|
|
200
|
-
## React Native full-screen ads
|
|
203
|
+
## React Native and WebView full-screen ads
|
|
201
204
|
|
|
202
205
|
```ts
|
|
203
206
|
import { createReactNativeAds } from "@ait-kit/sdk/rn";
|
|
204
207
|
|
|
208
|
+
// WebView: import { createWebViewAds } from "@ait-kit/sdk/webview";
|
|
205
209
|
const ads = createReactNativeAds();
|
|
206
210
|
await ads.loadFullScreenAd("AD_GROUP_ID"); // joins an in-flight duplicate load
|
|
207
211
|
const result = await ads.showFullScreenAd("AD_GROUP_ID");
|
|
@@ -243,8 +247,7 @@ Behavior:
|
|
|
243
247
|
|
|
244
248
|
The SDK provides ad behavior and outcomes. Your application owns server-side
|
|
245
249
|
ad reward requests, user session checks, payout limits, and ledger updates.
|
|
246
|
-
|
|
247
|
-
notification and sharing.)
|
|
250
|
+
Identity, storage, notification, and sharing adapters are also available in both entries.
|
|
248
251
|
|
|
249
252
|
## Versioning
|
|
250
253
|
|
|
@@ -259,7 +262,7 @@ official releases (see `scripts/test-package-tarballs.mjs`):
|
|
|
259
262
|
| Official package | Verified version | Peer range |
|
|
260
263
|
|---|---|---|
|
|
261
264
|
| `@apps-in-toss/framework` (RN) | 2.10.10 | `>=2.10.10` |
|
|
262
|
-
| `@apps-in-toss/web-framework` (
|
|
265
|
+
| `@apps-in-toss/web-framework` (WebView) | 3.4.0 | `>=3.4.0` |
|
|
263
266
|
|
|
264
267
|
Older versions may work where the runtime surfaces match (every capability
|
|
265
268
|
is checked per function and missing ones reject with `UNSUPPORTED`), but
|
|
@@ -298,14 +301,14 @@ now rejects with `SdkError("UNSUPPORTED")` instead of
|
|
|
298
301
|
|
|
299
302
|
```ts
|
|
300
303
|
import { createReactNativeReview } from "@ait-kit/sdk/rn";
|
|
301
|
-
//
|
|
304
|
+
// WebView: import { createWebViewReview } from "@ait-kit/sdk/webview";
|
|
302
305
|
const review = createReactNativeReview(); // share one instance across screens
|
|
303
306
|
if (await review.isSupported()) await review.request();
|
|
304
307
|
```
|
|
305
308
|
|
|
306
309
|
`ReviewAdapter` is a runtime-neutral root type. Factories accept `framework`
|
|
307
310
|
(shared `Review.request` contract or async loader), like the existing adapters.
|
|
308
|
-
RN translates the official `requestReview()` export;
|
|
311
|
+
RN translates the official `requestReview()` export; WebView calls `Review.request()`.
|
|
309
312
|
The official SDK loads only on use. Missing features/support checkers return
|
|
310
313
|
`false`; import failure throws `SDK_UNAVAILABLE`; support-check exceptions propagate.
|
|
311
314
|
`request()` rechecks support and throws `UNSUPPORTED` when unavailable.
|
|
@@ -321,14 +324,14 @@ errors by default.
|
|
|
321
324
|
|
|
322
325
|
Official reference: [Review.request](https://developers-apps-in-toss.toss.im/documentation/sdk/domains-api/review/review.request.md)
|
|
323
326
|
(Android/iOS Toss 5.253.0+, checked by the SDK). Verified package surfaces:
|
|
324
|
-
RN 2.10.10 and
|
|
327
|
+
RN 2.10.10 and WebView 3.4.0. Device UI behavior requires separate manual verification;
|
|
325
328
|
unit/tarball tests use injected SDKs or a stubbed native bridge.
|
|
326
329
|
|
|
327
330
|
## Explicit direct promotion rewards
|
|
328
331
|
|
|
329
332
|
```ts
|
|
330
333
|
import { createReactNativePromotion } from "@ait-kit/sdk/rn";
|
|
331
|
-
//
|
|
334
|
+
// WebView: import { createWebViewPromotion } from "@ait-kit/sdk/webview";
|
|
332
335
|
const promotion = createReactNativePromotion({ timeoutMs: 15_000 });
|
|
333
336
|
const support = await promotion.getSupport();
|
|
334
337
|
// RN 2.10.10 exposes no support checker: support is "unknown", not "supported".
|
|
@@ -339,14 +342,14 @@ const support = await promotion.getSupport();
|
|
|
339
342
|
`PromotionGrantResult` are runtime-neutral root types. Both factories accept
|
|
340
343
|
`framework` (shared `Promotion.grantReward` contract or async loader).
|
|
341
344
|
RN calls `grantPromotionReward({ params: { promotionCode, amount } })`;
|
|
342
|
-
|
|
343
|
-
There is no legacy
|
|
345
|
+
WebView calls only `Promotion.grantReward({ promotionCode, amount })`.
|
|
346
|
+
There is no legacy WebView fallback or fallback to/from server payment flows.
|
|
344
347
|
|
|
345
348
|
`getSupport()` reports `unsupported` for missing functions or an explicit false
|
|
346
349
|
check, `supported` for a true check, and `unknown` when a function has no checker.
|
|
347
350
|
Import failures throw `SDK_UNAVAILABLE`; support-check exceptions propagate.
|
|
348
351
|
Every grant rechecks support. RN's documented `undefined` and the provider's
|
|
349
|
-
`UNSUPPORTED_APP_VERSION` throw `UNSUPPORTED`; malformed
|
|
352
|
+
`UNSUPPORTED_APP_VERSION` throw `UNSUPPORTED`; malformed WebView responses stay unknown.
|
|
350
353
|
|
|
351
354
|
Input errors throw `INVALID_PROMOTION_INPUT` before loading/calling the SDK:
|
|
352
355
|
`promotionCode` must be non-empty without surrounding whitespace (never trimmed
|
|
@@ -400,6 +403,77 @@ payment path. This API does not require client-side mTLS certificates/proxy toke
|
|
|
400
403
|
and does not replace TrailBase claims or owned-currency accounting.
|
|
401
404
|
|
|
402
405
|
Official reference: [Promotion.grantReward](https://developers-apps-in-toss.toss.im/documentation/sdk/domains-api/promotion/promotion.grantreward.md).
|
|
403
|
-
Contracts are checked against RN 2.10.10 and
|
|
406
|
+
Contracts are checked against RN 2.10.10 and WebView 3.4.0 published types/code with
|
|
404
407
|
synthetic bridge fixtures. Device checks and official test-promotion calls remain
|
|
405
408
|
manual; no real promotion is invoked by tests.
|
|
409
|
+
|
|
410
|
+
### WebView naming migration
|
|
411
|
+
|
|
412
|
+
Use `@ait-kit/sdk/webview` and the `createWebView*` factories / `WebView*` types.
|
|
413
|
+
The legacy `@ait-kit/sdk/web` entry, `createWeb*` factories, and `Web*` types remain
|
|
414
|
+
available as deprecated aliases with identical behavior. The official peer package
|
|
415
|
+
name remains `@apps-in-toss/web-framework`.
|
|
416
|
+
|
|
417
|
+
WebView ads use the official flat `loadFullScreenAd` and `showFullScreenAd` exports.
|
|
418
|
+
Create them with `createWebViewAds()` from `@ait-kit/sdk/webview`; the same
|
|
419
|
+
load/show deadlines, single-use rules, and reward-event semantics described above apply.
|
|
420
|
+
|
|
421
|
+
### Subscription status queries
|
|
422
|
+
|
|
423
|
+
Both IAP adapters expose `getSubscriptionInfo(orderId)` and return `{ subscription }`
|
|
424
|
+
with the provider's `catalogId`, `status`, `expiresAt`, `isAutoRenew`,
|
|
425
|
+
`gracePeriodExpiresAt`, and `isAccessible` fields. Future status strings are preserved;
|
|
426
|
+
access is never inferred from a status string. Treat this as a provider snapshot,
|
|
427
|
+
not server-side entitlement verification. The query never calls `grant` or changes entitlements.
|
|
428
|
+
|
|
429
|
+
Missing capabilities, unsupported host versions, and the RN unsupported `undefined`
|
|
430
|
+
response throw `SdkError("UNSUPPORTED")`. Blank IDs throw `INVALID_IAP_INPUT`;
|
|
431
|
+
malformed payloads throw `INVALID_IAP_RESULT`. Other provider errors remain observable.
|
|
432
|
+
|
|
433
|
+
### Completed and refunded order history
|
|
434
|
+
|
|
435
|
+
`iap.getCompletedOrRefundedOrders()` returns `{ orders, hasNext, nextKey?, pagination }`.
|
|
436
|
+
Each order retains its provider `orderId`, `sku`, `status` (`COMPLETED` or `REFUNDED`),
|
|
437
|
+
and `date`. This read-only query never grants goods or revokes entitlements.
|
|
438
|
+
|
|
439
|
+
RN pages have `pagination: "cursor"`; pass `{ key: page.nextKey }` to explicitly
|
|
440
|
+
request the next page when `hasNext` is true and a cursor is present. WebView pages
|
|
441
|
+
have `pagination: "first_page_only"`: the current official WebView SDK accepts no
|
|
442
|
+
cursor. `hasNext` may still be true, but passing a non-null key throws `UNSUPPORTED`
|
|
443
|
+
before provider dispatch. Do not loop WebView page-one calls or treat them as a full restore.
|
|
444
|
+
|
|
445
|
+
Missing/unsupported capabilities throw `UNSUPPORTED`, malformed inputs throw
|
|
446
|
+
`INVALID_IAP_INPUT`, and malformed pages throw `INVALID_IAP_RESULT`. Other provider
|
|
447
|
+
errors propagate without automatic retries.
|
|
448
|
+
|
|
449
|
+
### WebView banner ads
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
import { createWebViewBannerAds } from "@ait-kit/sdk/webview";
|
|
453
|
+
const ads = createWebViewBannerAds();
|
|
454
|
+
const controller = new AbortController();
|
|
455
|
+
const banner = await ads.attachBanner("AD_GROUP_ID", "#banner", {
|
|
456
|
+
theme: "auto", tone: "grey", variant: "card", signal: controller.signal,
|
|
457
|
+
callbacks: { onNoFill: () => console.log("No banner available") }
|
|
458
|
+
});
|
|
459
|
+
// On unmount: controller.abort() also cancels a pending attachment.
|
|
460
|
+
banner.destroy(); // idempotent; only this handle is destroyed
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Initialization is lazy, shared within an adapter, and bounded by `initializeTimeoutMs`
|
|
464
|
+
(default 15 seconds; integer milliseconds from 1 to 2,147,483,647). A failed initialization can be retried.
|
|
465
|
+
An attachment resolves when the provider returns its handle; it does not claim that an
|
|
466
|
+
ad rendered or earned a reward. Render/view/click/impression/failure/no-fill callbacks
|
|
467
|
+
are forwarded on a microtask and suppressed after destruction. Synchronous attachment
|
|
468
|
+
failure rejects with `BANNER_ATTACH_FAILED`.
|
|
469
|
+
|
|
470
|
+
Each live attachment must own a distinct DOM element. SDK instances reject duplicate
|
|
471
|
+
targets with `BANNER_TARGET_IN_USE` until the previous handle is destroyed. Do not mix
|
|
472
|
+
raw provider attachments and adapter attachments on the same element. No global
|
|
473
|
+
`TossAds.destroyAll()` call is made. Use an `AbortSignal` when the target may unmount
|
|
474
|
+
while initialization is pending; the pending call rejects after initialization settles
|
|
475
|
+
and never attaches to an aborted target.
|
|
476
|
+
|
|
477
|
+
If provider cleanup throws, the handle still becomes locally destroyed and releases its
|
|
478
|
+
target claim; the provider exception remains observable. An attachment failure combined
|
|
479
|
+
with a cleanup failure rejects with an `AggregateError` retaining both errors.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type AdShowResult } from "../index.js";
|
|
2
|
+
import type { FullScreenAdSupport } from "./platform-contract.js";
|
|
3
|
+
import type { PlatformLoader } from "../platform-loader.js";
|
|
4
|
+
export type AdsPlatformLoader = PlatformLoader<FullScreenAdSupport>;
|
|
5
|
+
/** Ad kinds the SDK distinguishes; only full-screen ads exist today. */
|
|
6
|
+
export type SdkAdType = "fullscreen";
|
|
7
|
+
export interface AdsOptions {
|
|
8
|
+
/** Resolved platform loader, supplied by the runtime-specific factory. */
|
|
9
|
+
loader: AdsPlatformLoader;
|
|
10
|
+
/** Overall deadline for the show flow (default 60000ms; 0 disables). */
|
|
11
|
+
showTimeoutMs?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Overall deadline for each load, covering framework acquisition and the
|
|
14
|
+
* provider load flow (default 30000ms; 0 disables).
|
|
15
|
+
*/
|
|
16
|
+
loadTimeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface AdsAdapter {
|
|
19
|
+
/** Loads (or joins an in-flight load of) the full-screen ad for adGroupId. */
|
|
20
|
+
loadFullScreenAd(adGroupId: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Shows the full-screen ad whose load already completed and resolves with
|
|
23
|
+
* its terminal outcome. The ad is single-use and claimed synchronously:
|
|
24
|
+
* once a show starts, the unit needs a fresh load for the next attempt.
|
|
25
|
+
*/
|
|
26
|
+
showFullScreenAd(adGroupId: string): Promise<AdShowResult>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Shared full-screen ad adapter. Load state is
|
|
30
|
+
* tracked per ad type + ad unit, in-flight duplicate loads share one
|
|
31
|
+
* request, and rewards come only from the provider's `userEarnedReward`
|
|
32
|
+
* event. The adapter produces ad outcomes; server-side reward requests,
|
|
33
|
+
* session checks, and ledger handling belong to the consumer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createAdsAdapter(options: AdsOptions): AdsAdapter;
|
|
36
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/ads/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,KAAK,EAAyB,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,mBAAmB,CAAC,CAAC;AAEpE,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC;AAErC,MAAM,WAAW,UAAU;IACzB,0EAA0E;IAC1E,MAAM,EAAE,iBAAiB,CAAC;IAC1B,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD;;;;OAIG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC5D;AAmED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,CAqKhE"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { SdkError } from "../index.js";
|
|
2
|
+
import { runEventFlow } from "../event-flow.js";
|
|
3
|
+
const DEFAULT_SHOW_TIMEOUT_MS = 60_000;
|
|
4
|
+
const DEFAULT_LOAD_TIMEOUT_MS = 30_000;
|
|
5
|
+
function createAdDeadline(timeoutMs, now = monotonicNow) {
|
|
6
|
+
if (!(timeoutMs > 0)) {
|
|
7
|
+
return { remainingMs: () => undefined, race: (promise) => promise };
|
|
8
|
+
}
|
|
9
|
+
const startedAt = now();
|
|
10
|
+
return {
|
|
11
|
+
remainingMs: () => timeoutMs - (now() - startedAt),
|
|
12
|
+
race: (promise) => new Promise((resolve, reject) => {
|
|
13
|
+
const timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
14
|
+
// Attaching handlers also sinks a settlement that happens after the
|
|
15
|
+
// deadline already won; the no-op reject/resolve after settling is
|
|
16
|
+
// ignored by promise semantics.
|
|
17
|
+
promise.then((value) => {
|
|
18
|
+
clearTimeout(timer);
|
|
19
|
+
resolve(value);
|
|
20
|
+
}, (error) => {
|
|
21
|
+
clearTimeout(timer);
|
|
22
|
+
reject(error);
|
|
23
|
+
});
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Monotonic elapsed time: a system wall-clock correction while the loader
|
|
29
|
+
* is pending must not shrink or stretch the remaining budget.
|
|
30
|
+
*/
|
|
31
|
+
function monotonicNow() {
|
|
32
|
+
return typeof performance !== "undefined" && typeof performance.now === "function"
|
|
33
|
+
? performance.now()
|
|
34
|
+
: Date.now();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Shared full-screen ad adapter. Load state is
|
|
38
|
+
* tracked per ad type + ad unit, in-flight duplicate loads share one
|
|
39
|
+
* request, and rewards come only from the provider's `userEarnedReward`
|
|
40
|
+
* event. The adapter produces ad outcomes; server-side reward requests,
|
|
41
|
+
* session checks, and ledger handling belong to the consumer.
|
|
42
|
+
*/
|
|
43
|
+
export function createAdsAdapter(options) {
|
|
44
|
+
const loader = options.loader;
|
|
45
|
+
const showTimeoutMs = options.showTimeoutMs ?? DEFAULT_SHOW_TIMEOUT_MS;
|
|
46
|
+
const loadTimeoutMs = options.loadTimeoutMs ?? DEFAULT_LOAD_TIMEOUT_MS;
|
|
47
|
+
const slots = new Map();
|
|
48
|
+
const showing = new Set();
|
|
49
|
+
const adKey = (adType, adGroupId) => `${adType}:${adGroupId}`;
|
|
50
|
+
const load = (adGroupId) => {
|
|
51
|
+
const id = adKey("fullscreen", adGroupId);
|
|
52
|
+
const existing = slots.get(id);
|
|
53
|
+
// Duplicate loads join the in-flight request, and an already-completed
|
|
54
|
+
// load stays loaded until a show claims it - neither re-registers.
|
|
55
|
+
if (existing) {
|
|
56
|
+
return existing.kind === "loaded" ? Promise.resolve() : existing.promise;
|
|
57
|
+
}
|
|
58
|
+
// Slot updates run inside this promise's settlement — before the
|
|
59
|
+
// caller's await/catch continuation — so a caller that immediately
|
|
60
|
+
// retries after a failure starts a fresh registration, and a caller
|
|
61
|
+
// that immediately shows after a success finds the slot loaded. The
|
|
62
|
+
// identity check keeps a stale task from touching a newer task's slot.
|
|
63
|
+
const promise = new Promise((resolve, reject) => {
|
|
64
|
+
runLoad(adGroupId).then(() => {
|
|
65
|
+
const current = slots.get(id);
|
|
66
|
+
if (current?.kind === "loading" && current.promise === promise) {
|
|
67
|
+
slots.set(id, { kind: "loaded" });
|
|
68
|
+
}
|
|
69
|
+
resolve();
|
|
70
|
+
}, (error) => {
|
|
71
|
+
const current = slots.get(id);
|
|
72
|
+
if (current?.kind === "loading" && current.promise === promise) {
|
|
73
|
+
slots.delete(id);
|
|
74
|
+
}
|
|
75
|
+
reject(error);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
slots.set(id, { kind: "loading", promise });
|
|
79
|
+
return promise;
|
|
80
|
+
};
|
|
81
|
+
const show = (adGroupId) => {
|
|
82
|
+
const id = adKey("fullscreen", adGroupId);
|
|
83
|
+
if (showing.has(id)) {
|
|
84
|
+
return Promise.reject(new SdkError("AD_ALREADY_SHOWING", `ad group ${adGroupId} is already being shown`));
|
|
85
|
+
}
|
|
86
|
+
const slot = slots.get(id);
|
|
87
|
+
if (!slot || slot.kind === "loading") {
|
|
88
|
+
return Promise.reject(new SdkError("AD_NOT_LOADED", `loadFullScreenAd must complete before showing ad group ${adGroupId}`));
|
|
89
|
+
}
|
|
90
|
+
// Claim synchronously: the loaded marker is consumed the moment the show
|
|
91
|
+
// starts, so a concurrent reload registers fresh instead of aliasing a
|
|
92
|
+
// marker this show will never own again.
|
|
93
|
+
slots.delete(id);
|
|
94
|
+
showing.add(id);
|
|
95
|
+
return (async () => {
|
|
96
|
+
const timedOut = () => ({ status: "failed", reason: "ad show flow timed out" });
|
|
97
|
+
try {
|
|
98
|
+
// The whole show shares one budget: the loader races it, the event
|
|
99
|
+
// flow gets what remains, and the flow's own deadline produces the
|
|
100
|
+
// timeout result — its subscription cleanup completes before this
|
|
101
|
+
// promise settles, so `showing` is only released after the
|
|
102
|
+
// subscription is gone.
|
|
103
|
+
const deadline = createAdDeadline(showTimeoutMs);
|
|
104
|
+
const framework = await deadline.race(loadFramework());
|
|
105
|
+
if (!framework) {
|
|
106
|
+
return timedOut();
|
|
107
|
+
}
|
|
108
|
+
if (typeof framework.showFullScreenAd.isSupported === "function" &&
|
|
109
|
+
!framework.showFullScreenAd.isSupported()) {
|
|
110
|
+
throw new SdkError("UNSUPPORTED", "full-screen ads are not supported on this app version");
|
|
111
|
+
}
|
|
112
|
+
const remaining = deadline.remainingMs();
|
|
113
|
+
if (remaining !== undefined && remaining <= 0) {
|
|
114
|
+
return timedOut();
|
|
115
|
+
}
|
|
116
|
+
let reward;
|
|
117
|
+
return await runEventFlow({
|
|
118
|
+
register: (emit) => framework.showFullScreenAd({
|
|
119
|
+
options: { adGroupId },
|
|
120
|
+
onEvent: emit,
|
|
121
|
+
onError: (error) => emit({ type: "sdkError", error })
|
|
122
|
+
}),
|
|
123
|
+
reduce: (event) => {
|
|
124
|
+
if (event.type === "sdkError") {
|
|
125
|
+
const message = errorMessage(event.error);
|
|
126
|
+
return {
|
|
127
|
+
done: true,
|
|
128
|
+
result: { status: "failed", reason: `full-screen ad show failed: ${message}` }
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return reduceShowEvent(event, () => reward, (value) => (reward = value));
|
|
132
|
+
},
|
|
133
|
+
onTimeout: timedOut,
|
|
134
|
+
timeoutMs: remaining ?? 0
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
showing.delete(id);
|
|
139
|
+
}
|
|
140
|
+
})();
|
|
141
|
+
};
|
|
142
|
+
async function runLoad(adGroupId) {
|
|
143
|
+
// One deadline covers framework acquisition AND the provider flow. A
|
|
144
|
+
// loader that wins the race only just — or too late — leaves no budget
|
|
145
|
+
// for the provider registration, which is then skipped entirely.
|
|
146
|
+
const deadline = createAdDeadline(loadTimeoutMs);
|
|
147
|
+
const framework = await deadline.race(loadFramework());
|
|
148
|
+
if (!framework) {
|
|
149
|
+
throw new SdkError("AD_LOAD_TIMEOUT", "full-screen ad load timed out");
|
|
150
|
+
}
|
|
151
|
+
if (typeof framework.loadFullScreenAd.isSupported === "function" &&
|
|
152
|
+
!framework.loadFullScreenAd.isSupported()) {
|
|
153
|
+
throw new SdkError("UNSUPPORTED", "full-screen ads are not supported on this app version");
|
|
154
|
+
}
|
|
155
|
+
const remaining = deadline.remainingMs();
|
|
156
|
+
if (remaining !== undefined && remaining <= 0) {
|
|
157
|
+
throw new SdkError("AD_LOAD_TIMEOUT", "full-screen ad load timed out");
|
|
158
|
+
}
|
|
159
|
+
const outcome = await runEventFlow({
|
|
160
|
+
register: (emit) => framework.loadFullScreenAd({
|
|
161
|
+
options: { adGroupId },
|
|
162
|
+
onEvent: emit,
|
|
163
|
+
onError: (error) => emit({ type: "sdkError", error })
|
|
164
|
+
}),
|
|
165
|
+
reduce: (event) => event.type === "loaded"
|
|
166
|
+
? { done: true, result: undefined }
|
|
167
|
+
: { done: true, result: loadFailure(event.error) },
|
|
168
|
+
onTimeout: () => new SdkError("AD_LOAD_TIMEOUT", "full-screen ad load timed out"),
|
|
169
|
+
timeoutMs: remaining ?? 0
|
|
170
|
+
});
|
|
171
|
+
if (outcome instanceof SdkError) {
|
|
172
|
+
throw outcome;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async function loadFramework() {
|
|
176
|
+
const result = await loader();
|
|
177
|
+
if (!result.available) {
|
|
178
|
+
throw new SdkError("SDK_UNAVAILABLE", result.reason);
|
|
179
|
+
}
|
|
180
|
+
return result.module;
|
|
181
|
+
}
|
|
182
|
+
return { loadFullScreenAd: load, showFullScreenAd: show };
|
|
183
|
+
}
|
|
184
|
+
function reduceShowEvent(event, getReward, setReward) {
|
|
185
|
+
switch (event.type) {
|
|
186
|
+
case "userEarnedReward": {
|
|
187
|
+
// Runtime guard against payload-shape drift; the typed contract marks
|
|
188
|
+
// data as required.
|
|
189
|
+
if (event.data) {
|
|
190
|
+
setReward({ unitType: event.data.unitType, unitAmount: event.data.unitAmount });
|
|
191
|
+
}
|
|
192
|
+
return { done: false };
|
|
193
|
+
}
|
|
194
|
+
case "dismissed": {
|
|
195
|
+
const earned = getReward();
|
|
196
|
+
// Reward only when the provider actually emitted userEarnedReward;
|
|
197
|
+
// dismissal alone never grants anything.
|
|
198
|
+
return earned
|
|
199
|
+
? { done: true, result: { status: "rewarded", reward: earned } }
|
|
200
|
+
: { done: true, result: { status: "dismissed" } };
|
|
201
|
+
}
|
|
202
|
+
case "failedToShow":
|
|
203
|
+
return { done: true, result: { status: "failed", reason: "failedToShow" } };
|
|
204
|
+
default:
|
|
205
|
+
// requested / show / impression / clicked keep the flow running.
|
|
206
|
+
return { done: false };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** Transient provider failures are retryable and must not read as UNSUPPORTED. */
|
|
210
|
+
function loadFailure(error) {
|
|
211
|
+
if (error instanceof SdkError)
|
|
212
|
+
return error;
|
|
213
|
+
return new SdkError("AD_LOAD_FAILED", `full-screen ad load failed: ${errorMessage(error)}`, {
|
|
214
|
+
cause: error
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function errorMessage(error) {
|
|
218
|
+
return error instanceof Error ? error.message : String(error);
|
|
219
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural contract for the official React Native and WebView full-screen Ads APIs,
|
|
3
|
+
* declared from the published documentation so this package type-checks and
|
|
4
|
+
* ships without requiring the official SDK to be installed. The runtime
|
|
5
|
+
* module stays an optional peer dependency.
|
|
6
|
+
*/
|
|
7
|
+
export interface LoadFullScreenAdParams {
|
|
8
|
+
options: {
|
|
9
|
+
adGroupId: string;
|
|
10
|
+
};
|
|
11
|
+
onEvent: (event: {
|
|
12
|
+
type: "loaded";
|
|
13
|
+
}) => void;
|
|
14
|
+
onError: (error: unknown) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Discriminated union per the provider contract: only userEarnedReward carries data. */
|
|
17
|
+
export type FullScreenAdShowEvent = {
|
|
18
|
+
type: "requested" | "show" | "impression" | "clicked" | "dismissed" | "failedToShow";
|
|
19
|
+
} | {
|
|
20
|
+
type: "userEarnedReward";
|
|
21
|
+
data: {
|
|
22
|
+
unitType: string;
|
|
23
|
+
unitAmount: number;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export interface ShowFullScreenAdParams {
|
|
27
|
+
options: {
|
|
28
|
+
adGroupId: string;
|
|
29
|
+
};
|
|
30
|
+
onEvent: (event: FullScreenAdShowEvent) => void;
|
|
31
|
+
onError: (error: unknown) => void;
|
|
32
|
+
}
|
|
33
|
+
export interface FullScreenAdFunctions {
|
|
34
|
+
loadFullScreenAd(params: LoadFullScreenAdParams): () => void;
|
|
35
|
+
showFullScreenAd(params: ShowFullScreenAdParams): () => void;
|
|
36
|
+
}
|
|
37
|
+
export interface FullScreenAdSupport {
|
|
38
|
+
loadFullScreenAd: FullScreenAdFunctions["loadFullScreenAd"] & {
|
|
39
|
+
isSupported?: () => boolean;
|
|
40
|
+
};
|
|
41
|
+
showFullScreenAd: FullScreenAdFunctions["showFullScreenAd"] & {
|
|
42
|
+
isSupported?: () => boolean;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=platform-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-contract.d.ts","sourceRoot":"","sources":["../../src/ads/platform-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,cAAc,CAAA;CAAE,GACxF;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEjF,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAAC;IAC7D,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAAC;CAC9D;AAED,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,GAAG;QAC5D,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;KAC7B,CAAC;IACF,gBAAgB,EAAE,qBAAqB,CAAC,kBAAkB,CAAC,GAAG;QAC5D,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;KAC7B,CAAC;CACH"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural contract for the official React Native and WebView full-screen Ads APIs,
|
|
3
|
+
* declared from the published documentation so this package type-checks and
|
|
4
|
+
* ships without requiring the official SDK to be installed. The runtime
|
|
5
|
+
* module stays an optional peer dependency.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
package/dist/iap/adapter.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type IapGrantCallback, type IapProduct } from "../index.js";
|
|
1
|
+
import { type IapGrantCallback, type IapProduct, type IapSubscriptionInfo, type IapOrderHistoryPage } from "../index.js";
|
|
2
2
|
import type { IapPendingOrder, IapPurchaseResult } from "../index.js";
|
|
3
3
|
import { type IapPlatformLoader } from "./platform-contract.js";
|
|
4
4
|
export interface IapAdapterOptions {
|
|
5
|
+
/** Provider paging capability, fixed by the runtime factory. */
|
|
6
|
+
orderHistoryPagination: "cursor" | "first_page_only";
|
|
5
7
|
grant: IapGrantCallback;
|
|
6
8
|
/** Loader for the platform SDK module (already normalized per entry point). */
|
|
7
9
|
loader: IapPlatformLoader;
|
|
@@ -14,6 +16,14 @@ export interface IapRecoveryResult {
|
|
|
14
16
|
reason?: string;
|
|
15
17
|
}
|
|
16
18
|
export interface IapAdapter {
|
|
19
|
+
/** Read-only history; WebView rejects non-null cursors rather than repeating page one. */
|
|
20
|
+
getCompletedOrRefundedOrders(params?: {
|
|
21
|
+
key?: string | null;
|
|
22
|
+
}): Promise<IapOrderHistoryPage>;
|
|
23
|
+
/** Read-only provider snapshot; never grants or revokes entitlements. */
|
|
24
|
+
getSubscriptionInfo(orderId: string): Promise<{
|
|
25
|
+
subscription: IapSubscriptionInfo;
|
|
26
|
+
}>;
|
|
17
27
|
/** Lists purchasable products (one-time and subscription together). */
|
|
18
28
|
getProductItemList(): Promise<{
|
|
19
29
|
products: IapProduct[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/iap/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAErB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/iap/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAErB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EAEzB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,iBAAiB,EAA8B,MAAM,wBAAwB,CAAC;AAK5F,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,sBAAsB,EAAE,QAAQ,GAAG,iBAAiB,CAAC;IACrD,KAAK,EAAE,gBAAgB,CAAC;IACxB,+EAA+E;IAC/E,MAAM,EAAE,iBAAiB,CAAC;IAC1B,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,eAAe,CAAC;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0FAA0F;IAC1F,4BAA4B,CAAC,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC7F,yEAAyE;IACzE,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;IACrF,uEAAuE;IACvE,kBAAkB,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC,CAAC;IAC1D;;;;OAIG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzD,uEAAuE;IACvE,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAChF,6EAA6E;IAC7E,gBAAgB,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC,CAAC;IAC3D;;;;;OAKG;IACH,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACzE;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAuKvE"}
|
package/dist/iap/adapter.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { SdkError } from "../index.js";
|
|
2
2
|
import { IapGrantCoordinator } from "./grant-coordinator.js";
|
|
3
3
|
import {} from "./platform-contract.js";
|
|
4
|
+
import { queryOrderHistory } from "./order-history.js";
|
|
5
|
+
import { querySubscriptionInfo } from "./subscription-info.js";
|
|
4
6
|
import { runPurchaseFlow } from "./purchase-flow.js";
|
|
5
7
|
const DEFAULT_PURCHASE_TIMEOUT_MS = 180_000;
|
|
6
8
|
/**
|
|
@@ -34,6 +36,17 @@ export function createIapAdapter(options) {
|
|
|
34
36
|
return fn;
|
|
35
37
|
};
|
|
36
38
|
return {
|
|
39
|
+
async getCompletedOrRefundedOrders(params) {
|
|
40
|
+
return queryOrderHistory(load, options.orderHistoryPagination, params);
|
|
41
|
+
},
|
|
42
|
+
async getSubscriptionInfo(orderId) {
|
|
43
|
+
if (typeof orderId !== "string" || !orderId.trim()) {
|
|
44
|
+
throw new SdkError("INVALID_IAP_INPUT", "orderId must be a non-empty string");
|
|
45
|
+
}
|
|
46
|
+
const platform = await load();
|
|
47
|
+
ensureOperation(platform.getSubscriptionInfo, "getSubscriptionInfo");
|
|
48
|
+
return querySubscriptionInfo(platform, orderId);
|
|
49
|
+
},
|
|
37
50
|
async getProductItemList() {
|
|
38
51
|
const platform = await load();
|
|
39
52
|
ensureOperation(platform.getProductItemList, "getProductItemList");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type IapOrderHistoryPage } from "../index.js";
|
|
2
|
+
import { type PartialIapPlatformSdk } from "./platform-contract.js";
|
|
3
|
+
export declare function queryOrderHistory(load: () => Promise<PartialIapPlatformSdk>, pagination: IapOrderHistoryPage["pagination"], params?: {
|
|
4
|
+
key?: string | null;
|
|
5
|
+
}): Promise<IapOrderHistoryPage>;
|
|
6
|
+
//# sourceMappingURL=order-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order-history.d.ts","sourceRoot":"","sources":["../../src/iap/order-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,mBAAmB,EAAoC,MAAM,aAAa,CAAC;AACnG,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpF,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,OAAO,CAAC,qBAAqB,CAAC,EAC1C,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,EAC7C,MAAM,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CAyC9B"}
|