@ait-kit/sdk 0.2.0 → 0.4.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 +178 -9
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/platform-loader.d.ts +16 -0
- package/dist/platform-loader.d.ts.map +1 -0
- package/dist/platform-loader.js +35 -0
- package/dist/promotion/adapter.d.ts +3 -0
- package/dist/promotion/adapter.d.ts.map +1 -0
- package/dist/promotion/adapter.js +128 -0
- package/dist/promotion/platform-contract.d.ts +37 -0
- package/dist/promotion/platform-contract.d.ts.map +1 -0
- package/dist/promotion/platform-contract.js +1 -0
- package/dist/review/adapter.d.ts +3 -0
- package/dist/review/adapter.d.ts.map +1 -0
- package/dist/review/adapter.js +33 -0
- package/dist/review/platform-contract.d.ts +21 -0
- package/dist/review/platform-contract.d.ts.map +1 -0
- package/dist/review/platform-contract.js +1 -0
- package/dist/rn/ads.d.ts.map +1 -1
- package/dist/rn/ads.js +120 -119
- package/dist/rn/framework-loader.d.ts.map +1 -1
- package/dist/rn/framework-loader.js +6 -17
- package/dist/rn/iap.d.ts.map +1 -1
- package/dist/rn/iap.js +9 -28
- package/dist/rn/identity.d.ts.map +1 -1
- package/dist/rn/identity.js +11 -22
- package/dist/rn/index.d.ts +2 -0
- package/dist/rn/index.d.ts.map +1 -1
- package/dist/rn/index.js +2 -0
- package/dist/rn/notify-share.d.ts +3 -3
- package/dist/rn/notify-share.d.ts.map +1 -1
- package/dist/rn/notify-share.js +16 -33
- package/dist/rn/official-module.d.ts +83 -0
- package/dist/rn/official-module.d.ts.map +1 -0
- package/dist/rn/official-module.js +106 -0
- package/dist/rn/platform-loader.d.ts +4 -0
- package/dist/rn/platform-loader.d.ts.map +1 -0
- package/dist/rn/platform-loader.js +5 -0
- package/dist/rn/promotion.d.ts +9 -0
- package/dist/rn/promotion.d.ts.map +1 -0
- package/dist/rn/promotion.js +11 -0
- package/dist/rn/review.d.ts +7 -0
- package/dist/rn/review.d.ts.map +1 -0
- package/dist/rn/review.js +10 -0
- package/dist/rn/storage.d.ts.map +1 -1
- package/dist/rn/storage.js +4 -22
- package/dist/share/platform-contract.d.ts +4 -4
- package/dist/share/platform-contract.js +5 -5
- package/dist/web/framework-loader.d.ts.map +1 -1
- package/dist/web/framework-loader.js +7 -23
- package/dist/web/identity.d.ts.map +1 -1
- package/dist/web/identity.js +12 -33
- package/dist/web/index.d.ts +2 -0
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +4 -5
- package/dist/web/notify-share.d.ts +3 -2
- package/dist/web/notify-share.d.ts.map +1 -1
- package/dist/web/notify-share.js +11 -33
- package/dist/web/platform-loader.d.ts +4 -0
- package/dist/web/platform-loader.d.ts.map +1 -0
- package/dist/web/platform-loader.js +5 -0
- package/dist/web/promotion.d.ts +9 -0
- package/dist/web/promotion.d.ts.map +1 -0
- package/dist/web/promotion.js +10 -0
- package/dist/web/review.d.ts +7 -0
- package/dist/web/review.d.ts.map +1 -0
- package/dist/web/review.js +9 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ SDK initialization never grants or completes pending orders by itself.
|
|
|
99
99
|
| Grant completion notify | ✅ | ✅ | sent only after server grant confirms |
|
|
100
100
|
| Full-screen ads | ✅ | ➖ | ads are RN-only today |
|
|
101
101
|
| Notification agreement | ✅ | ✅ | event-based, one template per request |
|
|
102
|
-
| Share link / share sheet | ✅ | ✅ | `intoss://` paths; `
|
|
102
|
+
| Share link / share sheet | ✅ | ✅ | `intoss://` paths; `completed` ≠ shared |
|
|
103
103
|
| Unsupported app version | `SdkError("UNSUPPORTED")` | same | per-function `isSupported` gates |
|
|
104
104
|
|
|
105
105
|
Notification and sharing adapters ship in both entries (see below).
|
|
@@ -136,8 +136,13 @@ Contracts:
|
|
|
136
136
|
reject with `SdkError("INVALID_LOGIN_RESULT")`; unsupported environments
|
|
137
137
|
with `UNSUPPORTED`; SDK rejections propagate unchanged.
|
|
138
138
|
- **Anonymous key** results must be the documented `{ type: "HASH", hash }`
|
|
139
|
-
shape. Anything else (including
|
|
140
|
-
`SdkError("INVALID_ANONYMOUS_KEY")` — the adapter never
|
|
139
|
+
shape. Anything else (including the official SDK's `"ERROR"` sentinel)
|
|
140
|
+
rejects with `SdkError("INVALID_ANONYMOUS_KEY")` — the adapter never
|
|
141
|
+
invents a key. One exception: on React Native the official
|
|
142
|
+
`getAnonymousKey()` resolves `undefined` when the installed app is below
|
|
143
|
+
the feature's minimum version, which rejects with
|
|
144
|
+
`SdkError("UNSUPPORTED")` instead — an unsupported environment, not a
|
|
145
|
+
malformed key.
|
|
141
146
|
- **Storage** keys and string values pass through byte-for-byte: no
|
|
142
147
|
namespace prefixing, no key transformation. Compose namespaced keys
|
|
143
148
|
yourself (e.g. `cart:items`). `get` resolves `null` for missing keys;
|
|
@@ -171,10 +176,10 @@ const result = await notification.requestAgreement("TEMPLATE_CODE");
|
|
|
171
176
|
const share = createReactNativeShare();
|
|
172
177
|
const link = await share.createLink("intoss://my-app/about", "https://cdn/og.png");
|
|
173
178
|
|
|
174
|
-
// 3. Share sheet: "
|
|
179
|
+
// 3. Share sheet: "completed" means the SDK share call finished — nothing more.
|
|
175
180
|
const uiResult = await share.sendMessage(`check this out ${link}`);
|
|
176
|
-
// uiResult.status: "
|
|
177
|
-
// shared and never grants share-reward eligibility.
|
|
181
|
+
// uiResult.status: "completed" | "failed" — completed does NOT prove the
|
|
182
|
+
// user shared and never grants share-reward eligibility.
|
|
178
183
|
```
|
|
179
184
|
|
|
180
185
|
Contracts:
|
|
@@ -186,8 +191,10 @@ Contracts:
|
|
|
186
191
|
- **Share links** validate the documented `intoss://` path contract
|
|
187
192
|
(`INVALID_SHARE_PATH` otherwise) and pass the resolved link through
|
|
188
193
|
verbatim. OG image generation is the consumer's concern.
|
|
189
|
-
- **Share sheet** resolution is `
|
|
190
|
-
|
|
194
|
+
- **Share sheet** resolution is `completed`, meaning ONLY that the SDK share
|
|
195
|
+
call finished — the underlying SDKs do not report whether the sheet opened,
|
|
196
|
+
closed, or the user actually shared. Reward grants and completion tracking
|
|
197
|
+
stay with the consumer. (Renamed from `closed` in 0.3.0; see Migrating.)
|
|
191
198
|
- Unsupported surfaces/app versions reject with `SdkError("UNSUPPORTED")`.
|
|
192
199
|
|
|
193
200
|
## React Native full-screen ads
|
|
@@ -216,7 +223,16 @@ Behavior:
|
|
|
216
223
|
are single-use: after a show flow ends (rewarded, dismissed, failed,
|
|
217
224
|
timeout), a fresh load is required.
|
|
218
225
|
- The whole show flow has one deadline (`showTimeoutMs`, default 60s);
|
|
219
|
-
`loadTimeoutMs` (default 30s) bounds loads.
|
|
226
|
+
`loadTimeoutMs` (default 30s) bounds loads. The deadline is a single
|
|
227
|
+
budget covering SDK loading AND the provider event flow: a loader that
|
|
228
|
+
consumes most of it leaves only the remainder for the event wait, and a
|
|
229
|
+
fully consumed budget never registers with the provider. Timeout results
|
|
230
|
+
come from the event flow's own deadline, so the subscription is cleaned
|
|
231
|
+
up before the timeout settles — no orphaned listener outlives the call.
|
|
232
|
+
- Slot updates land inside the returned promise's settlement: a failed
|
|
233
|
+
load frees its slot before the caller's `catch` resumes (an immediate
|
|
234
|
+
retry starts a fresh registration), and a successful load is promoted
|
|
235
|
+
before the caller's `await` resumes (an immediate show works).
|
|
220
236
|
- Missing or failed-to-import framework → `SdkError("SDK_UNAVAILABLE")`;
|
|
221
237
|
unsupported app versions → `SdkError("UNSUPPORTED")`. Load failures are
|
|
222
238
|
never permanently cached — a later call retries the import.
|
|
@@ -234,3 +250,156 @@ notification and sharing.)
|
|
|
234
250
|
|
|
235
251
|
`@ait-kit/sdk` is versioned independently from the server API packages
|
|
236
252
|
(`@ait-kit/api-*`), which release in lockstep with each other.
|
|
253
|
+
|
|
254
|
+
## Verified official SDK versions
|
|
255
|
+
|
|
256
|
+
The adapters are developed and continuously checked against these exact
|
|
257
|
+
official releases (see `scripts/test-package-tarballs.mjs`):
|
|
258
|
+
|
|
259
|
+
| Official package | Verified version | Peer range |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| `@apps-in-toss/framework` (RN) | 2.10.10 | `>=2.10.10` |
|
|
262
|
+
| `@apps-in-toss/web-framework` (Web) | 3.4.0 | `>=3.4.0` |
|
|
263
|
+
|
|
264
|
+
Older versions may work where the runtime surfaces match (every capability
|
|
265
|
+
is checked per function and missing ones reject with `UNSUPPORTED`), but
|
|
266
|
+
only the versions above are verified. Newer versions are expected to work
|
|
267
|
+
via the same structural checks; if an official export shape changes, the
|
|
268
|
+
per-operation errors surface it instead of silent misbehavior.
|
|
269
|
+
|
|
270
|
+
## Migrating
|
|
271
|
+
|
|
272
|
+
### 0.3.0 — share sheet result `closed` → `completed`
|
|
273
|
+
|
|
274
|
+
`sendMessage` now resolves `{ status: "completed" }` instead of
|
|
275
|
+
`{ status: "closed" }`. The meaning also got precise: `completed` states
|
|
276
|
+
only that the SDK share **call** finished. It does not prove the share
|
|
277
|
+
sheet opened or closed, that the user shared, or that any reward
|
|
278
|
+
eligibility was earned. Update any `status === "closed"` checks; failure
|
|
279
|
+
results (`status: "failed"` with `code`/`reason`) are unchanged.
|
|
280
|
+
|
|
281
|
+
### 0.3.0 — RN adapters call the official export shapes
|
|
282
|
+
|
|
283
|
+
The React Native default loaders now convert the official flat exports
|
|
284
|
+
(`appLogin`, `getAnonymousKey`, `requestNotificationAgreement`,
|
|
285
|
+
`getTossShareLink`, `share`) into the shared adapter contracts. Previously
|
|
286
|
+
a correctly installed official RN SDK still produced
|
|
287
|
+
`SdkError("UNSUPPORTED")` for these five capabilities because the loaders
|
|
288
|
+
looked for the web SDK's namespaced shapes. Custom `framework` injections
|
|
289
|
+
using the internal namespaced contract or a loader keep working unchanged.
|
|
290
|
+
|
|
291
|
+
One error-mapping change rides along: the official RN `getAnonymousKey()`
|
|
292
|
+
resolving `undefined` (installed app below the feature's minimum version)
|
|
293
|
+
now rejects with `SdkError("UNSUPPORTED")` instead of
|
|
294
|
+
`INVALID_ANONYMOUS_KEY`; the `"ERROR"` sentinel still rejects with
|
|
295
|
+
`INVALID_ANONYMOUS_KEY`.
|
|
296
|
+
|
|
297
|
+
## Review requests
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import { createReactNativeReview } from "@ait-kit/sdk/rn";
|
|
301
|
+
// Web: import { createWebReview } from "@ait-kit/sdk/web";
|
|
302
|
+
const review = createReactNativeReview(); // share one instance across screens
|
|
303
|
+
if (await review.isSupported()) await review.request();
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
`ReviewAdapter` is a runtime-neutral root type. Factories accept `framework`
|
|
307
|
+
(shared `Review.request` contract or async loader), like the existing adapters.
|
|
308
|
+
RN translates the official `requestReview()` export; Web calls `Review.request()`.
|
|
309
|
+
The official SDK loads only on use. Missing features/support checkers return
|
|
310
|
+
`false`; import failure throws `SDK_UNAVAILABLE`; support-check exceptions propagate.
|
|
311
|
+
`request()` rechecks support and throws `UNSUPPORTED` when unavailable.
|
|
312
|
+
Concurrent requests on one instance share one Promise, cleared after success or
|
|
313
|
+
failure. There is no retry or timeout.
|
|
314
|
+
|
|
315
|
+
`Promise<void>` completion does not establish whether UI appeared or a review
|
|
316
|
+
was written. Never grant rewards, unlock features, or block navigation on review
|
|
317
|
+
completion. Complete and persist the core action first, then start a separately
|
|
318
|
+
error-handled review request without awaiting it in the core flow. The consumer
|
|
319
|
+
owns request timing, session limits, cooldowns and storage. Do not log raw SDK
|
|
320
|
+
errors by default.
|
|
321
|
+
|
|
322
|
+
Official reference: [Review.request](https://developers-apps-in-toss.toss.im/documentation/sdk/domains-api/review/review.request.md)
|
|
323
|
+
(Android/iOS Toss 5.253.0+, checked by the SDK). Verified package surfaces:
|
|
324
|
+
RN 2.10.10 and Web 3.4.0. Device UI behavior requires separate manual verification;
|
|
325
|
+
unit/tarball tests use injected SDKs or a stubbed native bridge.
|
|
326
|
+
|
|
327
|
+
## Explicit direct promotion rewards
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
import { createReactNativePromotion } from "@ait-kit/sdk/rn";
|
|
331
|
+
// Web: import { createWebPromotion } from "@ait-kit/sdk/web";
|
|
332
|
+
const promotion = createReactNativePromotion({ timeoutMs: 15_000 });
|
|
333
|
+
const support = await promotion.getSupport();
|
|
334
|
+
// RN 2.10.10 exposes no support checker: support is "unknown", not "supported".
|
|
335
|
+
// Opt into direct grants explicitly, with app-specific eligibility/budget checks.
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`PromotionAdapter`, `PromotionSupport`, `PromotionGrantInput` and
|
|
339
|
+
`PromotionGrantResult` are runtime-neutral root types. Both factories accept
|
|
340
|
+
`framework` (shared `Promotion.grantReward` contract or async loader).
|
|
341
|
+
RN calls `grantPromotionReward({ params: { promotionCode, amount } })`;
|
|
342
|
+
Web calls only `Promotion.grantReward({ promotionCode, amount })`.
|
|
343
|
+
There is no legacy Web fallback or fallback to/from server payment flows.
|
|
344
|
+
|
|
345
|
+
`getSupport()` reports `unsupported` for missing functions or an explicit false
|
|
346
|
+
check, `supported` for a true check, and `unknown` when a function has no checker.
|
|
347
|
+
Import failures throw `SDK_UNAVAILABLE`; support-check exceptions propagate.
|
|
348
|
+
Every grant rechecks support. RN's documented `undefined` and the provider's
|
|
349
|
+
`UNSUPPORTED_APP_VERSION` throw `UNSUPPORTED`; malformed Web responses stay unknown.
|
|
350
|
+
|
|
351
|
+
Input errors throw `INVALID_PROMOTION_INPUT` before loading/calling the SDK:
|
|
352
|
+
`promotionCode` must be non-empty without surrounding whitespace (never trimmed
|
|
353
|
+
into a different code), and `amount` must be a positive safe integer. Campaign
|
|
354
|
+
eligibility, maximum amounts and budgets remain the consumer's responsibility.
|
|
355
|
+
|
|
356
|
+
Results:
|
|
357
|
+
|
|
358
|
+
- `granted` has a non-empty `rewardKey` and means only that the SDK reported success.
|
|
359
|
+
- `rejected` carries an explicit documented refusal code: `4100`, `4104`, `4105`,
|
|
360
|
+
`4108`, `4109`, `4110`, `4112`, or `4114`.
|
|
361
|
+
- `unknown` means confirmation is required: SDK exceptions/sentinels, malformed or
|
|
362
|
+
contradictory responses, deadlines, `UNKNOWN_ERROR`, `4113`, or new provider
|
|
363
|
+
codes. `4113` never becomes an inferred already-granted ledger state.
|
|
364
|
+
|
|
365
|
+
Provider messages and raw errors are not included in grant results. Provider codes
|
|
366
|
+
are retained only as bounded uppercase alphanumeric/underscore tokens; do not log
|
|
367
|
+
reward keys, promotion codes or whole SDK responses.
|
|
368
|
+
|
|
369
|
+
Share one adapter instance. A concurrent grant throws `PROMOTION_IN_PROGRESS`;
|
|
370
|
+
completed results are never cached as idempotent payments. `timeoutMs` defaults to
|
|
371
|
+
0 (disabled), accepts integers through 2147483647, and covers loading and the SDK
|
|
372
|
+
call. Elapsed time is checked before dispatch and when the SDK settles, so delayed
|
|
373
|
+
timer callbacks cannot start an overdue payment or turn a late result into success.
|
|
374
|
+
After timeout the result is unknown, but the instance stays locked until the
|
|
375
|
+
actual operation settles. A loader finishing after timeout never starts payment.
|
|
376
|
+
A late success/failure cannot change the returned timeout result. There is no
|
|
377
|
+
cancellation, automatic retry, or protection across instances/devices/restarts.
|
|
378
|
+
|
|
379
|
+
Consumer UI pattern (all callbacks are supplied by the app):
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
async function grantOnce(input, ui) {
|
|
383
|
+
ui.disableGrantAction();
|
|
384
|
+
try {
|
|
385
|
+
const result = await promotion.grantReward(input);
|
|
386
|
+
if (result.status === "unknown") {
|
|
387
|
+
ui.showConfirmationRequired(); // keep disabled; never retry automatically
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
ui.showSdkResult(result); // client report only; not a server ledger receipt
|
|
391
|
+
} catch {
|
|
392
|
+
ui.showConfirmationRequired(); // do not dump raw exceptions or auto-reenable
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Posting a client result to a server is not independent payment verification.
|
|
398
|
+
Consumers requiring a server ledger must keep their existing three-stage server
|
|
399
|
+
payment path. This API does not require client-side mTLS certificates/proxy tokens
|
|
400
|
+
and does not replace TrailBase claims or owned-currency accounting.
|
|
401
|
+
|
|
402
|
+
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 Web 3.4.0 published types/code with
|
|
404
|
+
synthetic bridge fixtures. Device checks and official test-promotion calls remain
|
|
405
|
+
manual; no real promotion is invoked by tests.
|
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type AdShowResult = {
|
|
|
28
28
|
reason?: string;
|
|
29
29
|
};
|
|
30
30
|
/** Stable error codes for SDK adapter failures. */
|
|
31
|
-
export type SdkErrorCode = "SDK_UNAVAILABLE" | "UNSUPPORTED" | "AD_NOT_LOADED" | "AD_ALREADY_SHOWING" | "AD_LOAD_FAILED" | "AD_LOAD_TIMEOUT" | "INVALID_LOGIN_RESULT" | "INVALID_ANONYMOUS_KEY" | "INVALID_SHARE_PATH";
|
|
31
|
+
export type SdkErrorCode = "SDK_UNAVAILABLE" | "UNSUPPORTED" | "AD_NOT_LOADED" | "AD_ALREADY_SHOWING" | "AD_LOAD_FAILED" | "AD_LOAD_TIMEOUT" | "INVALID_LOGIN_RESULT" | "INVALID_ANONYMOUS_KEY" | "INVALID_PROMOTION_INPUT" | "PROMOTION_IN_PROGRESS" | "INVALID_SHARE_PATH";
|
|
32
32
|
/** Terminal agreement outcomes delivered by the platform event. */
|
|
33
33
|
export type SdkNotificationAgreementType = "newAgreement" | "alreadyAgreed" | "agreementRejected";
|
|
34
34
|
/**
|
|
@@ -62,12 +62,14 @@ export type SdkNotificationAgreementResult = {
|
|
|
62
62
|
reason?: string;
|
|
63
63
|
};
|
|
64
64
|
/**
|
|
65
|
-
* Result of opening the share UI. `
|
|
66
|
-
*
|
|
67
|
-
* never grants share-reward eligibility
|
|
65
|
+
* Result of opening the share UI. `completed` means ONLY that the SDK share
|
|
66
|
+
* call finished — it does NOT prove the share sheet opened or closed, that
|
|
67
|
+
* the user actually shared, and it never grants share-reward eligibility.
|
|
68
|
+
* (Renamed from `closed` in 0.3.0: the underlying SDKs guarantee the call
|
|
69
|
+
* completing, not the sheet's lifecycle.)
|
|
68
70
|
*/
|
|
69
71
|
export type SdkShareUiResult = {
|
|
70
|
-
status: "
|
|
72
|
+
status: "completed";
|
|
71
73
|
} | {
|
|
72
74
|
status: "failed";
|
|
73
75
|
code?: string;
|
|
@@ -212,4 +214,6 @@ export declare class SdkError extends Error {
|
|
|
212
214
|
cause?: unknown;
|
|
213
215
|
});
|
|
214
216
|
}
|
|
217
|
+
export type { ReviewAdapter } from "./review/platform-contract.js";
|
|
218
|
+
export type { PromotionAdapter, PromotionSupport, PromotionGrantInput, PromotionGrantResult } from "./promotion/platform-contract.js";
|
|
215
219
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oDAAoD;AACpD,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,mDAAmD;AACnD,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,oBAAoB,GACpB,gBAAgB,GAChB,iBAAiB,GACjB,sBAAsB,GACtB,uBAAuB,GACvB,oBAAoB,CAAC;AAMzB,mEAAmE;AACnE,MAAM,MAAM,4BAA4B,GAAG,cAAc,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAElG;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GACtC;IACE,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC,4BAA4B,EAAE,mBAAmB,CAAC,CAAC;IACtE,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B,GACD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC3E;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1E;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Internal runtime-neutral loader primitives; no official SDK is imported here. */
|
|
2
|
+
export type PlatformLoadResult<T> = {
|
|
3
|
+
available: true;
|
|
4
|
+
module: T;
|
|
5
|
+
} | {
|
|
6
|
+
available: false;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
export type PlatformLoader<T> = () => Promise<PlatformLoadResult<T>>;
|
|
10
|
+
/** Preserve injected loaders verbatim and construct defaults only when needed. */
|
|
11
|
+
export declare function resolvePlatformLoader<T>(framework: T | PlatformLoader<T> | undefined, createDefault: () => PlatformLoader<T>): PlatformLoader<T>;
|
|
12
|
+
/** Cache only successful selections; unavailable results and thrown loads retry. */
|
|
13
|
+
export declare function createCachedPlatformLoader<T>(load: PlatformLoader<T>, errorReason: (error: unknown) => string): PlatformLoader<T>;
|
|
14
|
+
/** Preserve existing diagnostic detail policies chosen by each adapter. */
|
|
15
|
+
export declare function frameworkImportError(packageName: string, error: unknown, includeDetails: boolean): string;
|
|
16
|
+
//# sourceMappingURL=platform-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-loader.d.ts","sourceRoot":"","sources":["../src/platform-loader.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAC5B;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAC9B;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACzC,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAErE,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,SAAS,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,SAAS,EAC5C,aAAa,EAAE,MAAM,cAAc,CAAC,CAAC,CAAC,GACrC,cAAc,CAAC,CAAC,CAAC,CAInB;AAED,oFAAoF;AACpF,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,EACvB,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GACtC,cAAc,CAAC,CAAC,CAAC,CAcnB;AAED,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CAKzG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Preserve injected loaders verbatim and construct defaults only when needed. */
|
|
2
|
+
export function resolvePlatformLoader(framework, createDefault) {
|
|
3
|
+
if (!framework)
|
|
4
|
+
return createDefault();
|
|
5
|
+
if (typeof framework === "function")
|
|
6
|
+
return framework;
|
|
7
|
+
return async () => ({ available: true, module: framework });
|
|
8
|
+
}
|
|
9
|
+
/** Cache only successful selections; unavailable results and thrown loads retry. */
|
|
10
|
+
export function createCachedPlatformLoader(load, errorReason) {
|
|
11
|
+
let cached;
|
|
12
|
+
return async () => {
|
|
13
|
+
if (cached)
|
|
14
|
+
return { available: true, module: cached.module };
|
|
15
|
+
try {
|
|
16
|
+
const result = await load();
|
|
17
|
+
// Keep the cache independent from the mutable result envelope returned
|
|
18
|
+
// to callers, as the original per-adapter loaders did.
|
|
19
|
+
if (result.available)
|
|
20
|
+
cached = { available: true, module: result.module };
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return { available: false, reason: errorReason(error) };
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Preserve existing diagnostic detail policies chosen by each adapter. */
|
|
29
|
+
export function frameworkImportError(packageName, error, includeDetails) {
|
|
30
|
+
const prefix = `failed to import ${packageName}`;
|
|
31
|
+
if (!includeDetails)
|
|
32
|
+
return prefix;
|
|
33
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
+
return `${prefix}: ${message}`;
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/promotion/adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,wBAAwB,CAAC;AAiDhC,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,EAAE,SAAS,SAAI,GAAG,gBAAgB,CA+DvG"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { SdkError } from "../index.js";
|
|
2
|
+
// Official Promotion.grantReward documentation (RN 2.10.10 / Web 3.4.0).
|
|
3
|
+
// 4113 is intentionally absent: it cannot establish this attempt's outcome.
|
|
4
|
+
const REJECTION_CODES = new Set(["4100", "4104", "4105", "4108", "4109", "4110", "4112", "4114"]);
|
|
5
|
+
function unknown(reason, providerCode) {
|
|
6
|
+
return providerCode === undefined ? { status: "unknown", reason } : { status: "unknown", reason, providerCode };
|
|
7
|
+
}
|
|
8
|
+
function normalize(value, thrown) {
|
|
9
|
+
if (typeof value !== "object" || value === null) {
|
|
10
|
+
return unknown(thrown || value === "ERROR" ? "sdk_error" : "invalid_response");
|
|
11
|
+
}
|
|
12
|
+
const data = value;
|
|
13
|
+
const rawCode = data.errorCode ?? data.code;
|
|
14
|
+
const code = typeof rawCode === "string" && /^[A-Z0-9_]{1,64}$/.test(rawCode) ? rawCode : undefined;
|
|
15
|
+
const hasError = "errorCode" in data || "code" in data || "error" in data || "message" in data;
|
|
16
|
+
if (("key" in data && (thrown || hasError)) ||
|
|
17
|
+
(data.code !== undefined && data.errorCode !== undefined && data.code !== data.errorCode)) {
|
|
18
|
+
return unknown("invalid_response", code);
|
|
19
|
+
}
|
|
20
|
+
if (!thrown && typeof data.key === "string" && data.key.trim().length > 0) {
|
|
21
|
+
return { status: "granted", rewardKey: data.key };
|
|
22
|
+
}
|
|
23
|
+
if ("key" in data)
|
|
24
|
+
return unknown("invalid_response", code);
|
|
25
|
+
if (code === "UNSUPPORTED_APP_VERSION") {
|
|
26
|
+
throw new SdkError("UNSUPPORTED", "direct promotion rewards are not supported on this app version");
|
|
27
|
+
}
|
|
28
|
+
if (code && REJECTION_CODES.has(code))
|
|
29
|
+
return { status: "rejected", providerCode: code };
|
|
30
|
+
return unknown(code ? "ambiguous_provider_error" : thrown ? "sdk_error" : "invalid_response", code);
|
|
31
|
+
}
|
|
32
|
+
function support(platform) {
|
|
33
|
+
const grant = platform.Promotion?.grantReward;
|
|
34
|
+
if (typeof grant !== "function")
|
|
35
|
+
return "unsupported";
|
|
36
|
+
if (typeof grant.isSupported !== "function")
|
|
37
|
+
return "unknown";
|
|
38
|
+
return grant.isSupported() ? "supported" : "unsupported";
|
|
39
|
+
}
|
|
40
|
+
function validate(input) {
|
|
41
|
+
if (!input || typeof input.promotionCode !== "string" || !input.promotionCode.trim() ||
|
|
42
|
+
input.promotionCode !== input.promotionCode.trim() || !Number.isSafeInteger(input.amount) || input.amount <= 0) {
|
|
43
|
+
throw new SdkError("INVALID_PROMOTION_INPUT", "promotionCode must be non-empty without surrounding whitespace and amount must be a positive safe integer");
|
|
44
|
+
}
|
|
45
|
+
// Snapshot before loading; callers cannot change the pending payment input.
|
|
46
|
+
return { promotionCode: input.promotionCode, amount: input.amount };
|
|
47
|
+
}
|
|
48
|
+
export function createPromotionAdapter(loader, timeoutMs = 0) {
|
|
49
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 0 || timeoutMs > 2_147_483_647) {
|
|
50
|
+
throw new SdkError("INVALID_PROMOTION_INPUT", "timeoutMs must be an integer from 0 to 2147483647");
|
|
51
|
+
}
|
|
52
|
+
let inFlight = false;
|
|
53
|
+
const load = async () => {
|
|
54
|
+
const result = await loader();
|
|
55
|
+
if (!result.available)
|
|
56
|
+
throw new SdkError("SDK_UNAVAILABLE", result.reason);
|
|
57
|
+
return result.module;
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
async getSupport() { return support(await load()); },
|
|
61
|
+
grantReward(input) {
|
|
62
|
+
let validated;
|
|
63
|
+
try {
|
|
64
|
+
validated = validate(input);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return Promise.reject(error);
|
|
68
|
+
}
|
|
69
|
+
if (inFlight)
|
|
70
|
+
return Promise.reject(new SdkError("PROMOTION_IN_PROGRESS", "a direct promotion request is still in progress"));
|
|
71
|
+
inFlight = true;
|
|
72
|
+
const now = typeof performance !== "undefined" && typeof performance.now === "function"
|
|
73
|
+
? performance.now.bind(performance)
|
|
74
|
+
: Date.now;
|
|
75
|
+
const startedAt = now();
|
|
76
|
+
let expired = false;
|
|
77
|
+
// Timers cannot run while JS is blocked or draining microtasks. Check the
|
|
78
|
+
// elapsed budget too, using one clock source for the entire request.
|
|
79
|
+
const hasExpired = () => expired || (timeoutMs > 0 && now() - startedAt >= timeoutMs);
|
|
80
|
+
let timer;
|
|
81
|
+
const work = Promise.resolve().then(async () => {
|
|
82
|
+
if (hasExpired())
|
|
83
|
+
return unknown("timeout");
|
|
84
|
+
const platform = await load();
|
|
85
|
+
// A loading timeout must not launch a new payment later.
|
|
86
|
+
if (hasExpired())
|
|
87
|
+
return unknown("timeout");
|
|
88
|
+
const availability = support(platform);
|
|
89
|
+
if (hasExpired())
|
|
90
|
+
return unknown("timeout");
|
|
91
|
+
if (availability === "unsupported") {
|
|
92
|
+
throw new SdkError("UNSUPPORTED", "the installed SDK or app does not support direct promotion rewards");
|
|
93
|
+
}
|
|
94
|
+
let response;
|
|
95
|
+
try {
|
|
96
|
+
response = await platform.Promotion.grantReward(validated);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (hasExpired())
|
|
100
|
+
return unknown("timeout");
|
|
101
|
+
// The RN conversion uses this only for the documented undefined result.
|
|
102
|
+
if (error instanceof SdkError && error.code === "UNSUPPORTED")
|
|
103
|
+
throw error;
|
|
104
|
+
return normalize(error, true);
|
|
105
|
+
}
|
|
106
|
+
if (hasExpired())
|
|
107
|
+
return unknown("timeout");
|
|
108
|
+
return normalize(response, false);
|
|
109
|
+
}).catch((error) => {
|
|
110
|
+
// A delayed loader/support failure must not beat an elapsed deadline.
|
|
111
|
+
if (hasExpired())
|
|
112
|
+
return unknown("timeout");
|
|
113
|
+
throw error;
|
|
114
|
+
}).finally(() => {
|
|
115
|
+
inFlight = false;
|
|
116
|
+
if (timer !== undefined)
|
|
117
|
+
clearTimeout(timer);
|
|
118
|
+
});
|
|
119
|
+
if (timeoutMs === 0)
|
|
120
|
+
return work;
|
|
121
|
+
const deadline = new Promise(resolve => {
|
|
122
|
+
timer = setTimeout(() => { expired = true; resolve(unknown("timeout")); }, timeoutMs);
|
|
123
|
+
});
|
|
124
|
+
// Only actual SDK/load settlement releases the lock, not this race.
|
|
125
|
+
return Promise.race([work, deadline]);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type PromotionSupport = "supported" | "unsupported" | "unknown";
|
|
2
|
+
export interface PromotionGrantInput {
|
|
3
|
+
promotionCode: string;
|
|
4
|
+
amount: number;
|
|
5
|
+
}
|
|
6
|
+
export type PromotionGrantResult = {
|
|
7
|
+
status: "granted";
|
|
8
|
+
rewardKey: string;
|
|
9
|
+
} | {
|
|
10
|
+
status: "rejected";
|
|
11
|
+
providerCode: string;
|
|
12
|
+
} | {
|
|
13
|
+
status: "unknown";
|
|
14
|
+
reason: "sdk_error" | "timeout" | "invalid_response" | "ambiguous_provider_error";
|
|
15
|
+
providerCode?: string;
|
|
16
|
+
};
|
|
17
|
+
/** Client SDK reports are not independently verified server ledger evidence. */
|
|
18
|
+
export interface PromotionAdapter {
|
|
19
|
+
getSupport(): Promise<PromotionSupport>;
|
|
20
|
+
grantReward(input: PromotionGrantInput): Promise<PromotionGrantResult>;
|
|
21
|
+
}
|
|
22
|
+
/** Injected results are untrusted, just like the native bridge response. */
|
|
23
|
+
export interface PromotionPlatformSdk {
|
|
24
|
+
Promotion?: {
|
|
25
|
+
grantReward?: ((input: PromotionGrantInput) => Promise<unknown>) & {
|
|
26
|
+
isSupported?: () => boolean;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export type PromotionPlatformLoader = () => Promise<{
|
|
31
|
+
available: true;
|
|
32
|
+
module: PromotionPlatformSdk;
|
|
33
|
+
} | {
|
|
34
|
+
available: false;
|
|
35
|
+
reason: string;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=platform-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-contract.d.ts","sourceRoot":"","sources":["../../src/promotion/platform-contract.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5C;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,kBAAkB,GAAG,0BAA0B,CAAC;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEN,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxC,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACxE;AAED,4EAA4E;AAC5E,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE;QACV,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG;YACjE,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;SAC7B,CAAC;KACH,CAAC;CACH;AAED,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,CAC/C;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,GACjD;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CACvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/review/adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAqB,MAAM,wBAAwB,CAAC;AAErG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,oBAAoB,GAAG,aAAa,CA6B/E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SdkError } from "../index.js";
|
|
2
|
+
export function createReviewAdapter(loader) {
|
|
3
|
+
let inFlight;
|
|
4
|
+
const load = async () => {
|
|
5
|
+
const result = await loader();
|
|
6
|
+
if (!result.available)
|
|
7
|
+
throw new SdkError("SDK_UNAVAILABLE", result.reason);
|
|
8
|
+
return result.module;
|
|
9
|
+
};
|
|
10
|
+
const supported = (platform) => {
|
|
11
|
+
const request = platform.Review?.request;
|
|
12
|
+
return typeof request === "function" &&
|
|
13
|
+
typeof request.isSupported === "function" && request.isSupported() === true;
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
async isSupported() {
|
|
17
|
+
return supported(await load());
|
|
18
|
+
},
|
|
19
|
+
request() {
|
|
20
|
+
if (inFlight)
|
|
21
|
+
return inFlight;
|
|
22
|
+
// Schedule loading after publishing the lock, including reentrant loaders.
|
|
23
|
+
inFlight = Promise.resolve().then(async () => {
|
|
24
|
+
const platform = await load();
|
|
25
|
+
if (!supported(platform)) {
|
|
26
|
+
throw new SdkError("UNSUPPORTED", "review requests are not supported on this app version");
|
|
27
|
+
}
|
|
28
|
+
await platform.Review.request();
|
|
29
|
+
}).finally(() => { inFlight = undefined; });
|
|
30
|
+
return inFlight;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Minimal injectable shape shared by the platform adapters. */
|
|
2
|
+
export interface ReviewPlatformSdk {
|
|
3
|
+
Review?: {
|
|
4
|
+
request?: (() => Promise<void>) & {
|
|
5
|
+
isSupported?: () => boolean;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export type ReviewPlatformLoader = () => Promise<{
|
|
10
|
+
available: true;
|
|
11
|
+
module: ReviewPlatformSdk;
|
|
12
|
+
} | {
|
|
13
|
+
available: false;
|
|
14
|
+
reason: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** Completion only means the SDK call settled, never that a review was written. */
|
|
17
|
+
export interface ReviewAdapter {
|
|
18
|
+
isSupported(): Promise<boolean>;
|
|
19
|
+
request(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=platform-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-contract.d.ts","sourceRoot":"","sources":["../../src/review/platform-contract.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG;YAAE,WAAW,CAAC,EAAE,MAAM,OAAO,CAAA;SAAE,CAAC;KACnE,CAAC;CACH;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,CAC5C;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAC9C;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CACvC,CAAC;AAEF,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/rn/ads.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ads.d.ts","sourceRoot":"","sources":["../../src/rn/ads.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ads.d.ts","sourceRoot":"","sources":["../../src/rn/ads.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,KAAK,EAAyB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC1F,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAE/B,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC;AAErC,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,GAAG,mBAAmB,CAAC;IAClD,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,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,oBAAoB,CAAC,OAAO,GAAE,qBAA0B,GAAG,cAAc,CAqKxF"}
|