@tinkerlandai/longplay-sdk 0.10.15 → 0.10.16
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/CHANGELOG.md +6 -0
- package/README.md +13 -15
- package/README.zh-CN.md +14 -16
- package/dist/{ai-usage-C3dCagmQ.d.ts → ai-usage-DejUdb17.d.ts} +1 -1
- package/dist/{api-Cefn6AaL.d.ts → api-RQUBSSEJ.d.ts} +60 -26
- package/dist/{chunk-OZZMZH7X.js → chunk-26HU2HXU.js} +1 -1
- package/dist/chunk-4IGRIYOQ.js +1 -0
- package/dist/{chunk-V73OHOTK.js → chunk-55MXKW5J.js} +1 -1
- package/dist/{chunk-6RZKX552.js → chunk-67XTOBGE.js} +1 -1
- package/dist/{chunk-RT35MPPD.js → chunk-6MBVIE3H.js} +1 -1
- package/dist/chunk-AC32XJZW.js +1 -0
- package/dist/{chunk-VXY2C4AL.js → chunk-APO7QUBB.js} +1 -1
- package/dist/chunk-EEZLS2YP.js +1 -0
- package/dist/chunk-EFFXE6CX.js +6 -0
- package/dist/chunk-FKBSUKXE.js +1 -0
- package/dist/{chunk-TPAQWTO4.js → chunk-JKLILKI5.js} +1 -1
- package/dist/{chunk-VSMITXQD.js → chunk-LC2VUKYM.js} +1 -1
- package/dist/{chunk-LUIKKMG5.js → chunk-M5HQW67G.js} +1 -1
- package/dist/chunk-ML6EHT43.js +10 -0
- package/dist/chunk-PFHS7HK3.js +17 -0
- package/dist/chunk-T5COWMDA.js +1 -0
- package/dist/{configuration-sync-D2n_gGj6.d.ts → configuration-sync-C2jtm37f.d.ts} +97 -9
- package/dist/{content-WXHCWIUL.js → content-XCLXWNGN.js} +1 -1
- package/dist/{funnel-local-client-9U-_hkEE.d.ts → funnel-local-client-P_R6FHVV.d.ts} +7995 -5523
- package/dist/{funnel-node-evaluation-DSSSmXHX.d.ts → funnel-node-evaluation-BLnJp8vj.d.ts} +11 -13
- package/dist/{funnel-process-client-BaHMeArI.d.ts → funnel-process-client-CY-GQ_SF.d.ts} +5498 -4539
- package/dist/funnel-runtime-host-GFTN7KQK.js +1 -0
- package/dist/index.d.ts +1258 -273
- package/dist/index.js +1 -1
- package/dist/native-shell.js +1 -1
- package/dist/openrouter.d.ts +3 -3
- package/dist/openrouter.js +1 -1
- package/dist/page.d.ts +2 -2
- package/dist/page.js +1 -1
- package/dist/paywall-H3KQZEJG.js +1 -0
- package/dist/popup.d.ts +11 -5
- package/dist/popup.js +1 -1
- package/dist/react-native.d.ts +1541 -7
- package/dist/react-native.js +1 -1
- package/dist/{screen-D81zCpfi.d.ts → screen-DRP7nsrQ.d.ts} +613 -357
- package/dist/screen-renderer-IZ3VJGU6.js +1 -0
- package/dist/server.d.ts +717 -9
- package/dist/server.js +1 -1
- package/dist/visual.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-33FQUT3Z.js +0 -179
- package/dist/chunk-E5ECPR6Z.js +0 -1
- package/dist/chunk-LHA6VWP7.js +0 -1
- package/dist/chunk-MOWYD2TV.js +0 -1
- package/dist/chunk-RQZ42NQJ.js +0 -6
- package/dist/chunk-VSJOHWDL.js +0 -17
- package/dist/chunk-XAHWOLRT.js +0 -1
- package/dist/funnel-runtime-host-WQ64FAME.js +0 -1
- package/dist/paywall-H4YN4FTL.js +0 -1
- package/dist/screen-renderer-NHJ6OQTF.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.16 — 2026-11-05
|
|
4
|
+
|
|
5
|
+
- Add bounded local display interactions, responsive presentation and brand fonts to the shared screen renderer, including billing controls and catalog-backed quantity sliders.
|
|
6
|
+
- Apply checkout availability consistently to native controls, static HTML and interactive HTML without rewriting authored content or dropping invalid capability data. Preserve live controls and local state across refreshes.
|
|
7
|
+
- Align structural and semantic screen validation across JavaScript, React Native, Swift, Kotlin, Python and Go. Wire protocol stays `0.10`; purchase authorization and runtime execution remain server-owned.
|
|
8
|
+
|
|
3
9
|
## 0.10.15 — 2026-11-04
|
|
4
10
|
|
|
5
11
|
- No API or behavior change from 0.10.14. This is the first release published through a release candidate (`0.10.15-rc.1` on npm `next`) before the stable version. The README describes the `next` and `latest` channels. Wire protocol stays `0.10`.
|
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<p>
|
|
2
|
-
<a href="https://longplayai.com">
|
|
3
|
-
<img src="https://longplayai.com/brand/indiana-mark.png" alt="Longplay" width="72" height="72" />
|
|
2
|
+
<a href="https://www.longplayai.com">
|
|
3
|
+
<img src="https://www.longplayai.com/site/brand/indiana-mark.png" alt="Longplay" width="72" height="72" />
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
# @tinkerlandai/longplay-sdk
|
|
8
8
|
|
|
9
|
-
This source checkout is SDK 0.10.
|
|
9
|
+
This source checkout is SDK 0.10.14, protocol 0.10. These examples use `https://api.longplayai.com` with a Sandbox App and credentials issued by the production deployment. Sandbox still contains production data; do not reuse credentials from the separate test deployment. Confirm runtime readiness in [environment state](../../docs/development-status.md) before running them.
|
|
10
10
|
|
|
11
11
|
[简体中文](./README.zh-CN.md)
|
|
12
12
|
|
|
@@ -18,9 +18,7 @@ The Longplay business SDK groups its capabilities as **Identity, Commerce, exper
|
|
|
18
18
|
npm install --save-exact @tinkerlandai/longplay-sdk@latest
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
The first install resolves latest and saves an exact package.json version. Commit the lockfile and use npm ci for later builds.
|
|
22
|
-
|
|
23
|
-
IAM Funnel entries and their initial reliability fixes require SDK 0.10.5 or later. Select this release explicitly with `npm install --save-exact @tinkerlandai/longplay-sdk@0.10.5`; current mutable tags are recorded in the [release records](../../docs/sdk-releases.md).
|
|
21
|
+
The first install resolves latest and saves an exact package.json version. Commit the lockfile and use npm ci for later builds. [SDK distribution](../../docs/sdk-releases.md) records package availability; source changes do not publish artifacts. Existing versioned artifacts remain immutable.
|
|
24
22
|
|
|
25
23
|
This SDK requires HTTP protocol 0.10. The runtime must serve the same current protocol; publishing a package does not deploy the server. Publication and accepted environment scope are recorded in the [release ledger](../../docs/sdk-releases.md) and [development status](../../docs/development-status.md).
|
|
26
24
|
|
|
@@ -31,7 +29,7 @@ The data/session layer handles public JSON, integrity checks and authenticated o
|
|
|
31
29
|
The classic-script entry reuses the npm browser implementation, with no bundler:
|
|
32
30
|
|
|
33
31
|
```sh
|
|
34
|
-
SDK_MODULE_URL="$(curl -fsS https://longplayai.com/sdk/module)" &&
|
|
32
|
+
SDK_MODULE_URL="$(curl -fsS https://cdn.longplayai.com/sdk/module)" &&
|
|
35
33
|
printf 'export * from "%s";\n' "$SDK_MODULE_URL" > longplay-sdk.js
|
|
36
34
|
```
|
|
37
35
|
|
|
@@ -57,7 +55,7 @@ printf 'export * from "%s";\n' "$SDK_MODULE_URL" > longplay-sdk.js
|
|
|
57
55
|
</script>
|
|
58
56
|
```
|
|
59
57
|
|
|
60
|
-
Commit the generated longplay-sdk.js to lock the immutable module URL; resolve it again only when upgrading. The optional classic loader at `https://longplayai.com/sdk.js` still follows Web releases and uses matching API/credentials. `Longplay.ready` provides every root browser export plus `createPageExperiments` and `createVisualExperiments`; replace npm imports below with destructuring those names. Loading activates no sessions, events or experiments. Server Keys remain on your backend; Funnel start/recovery and logout cleanup retain the existing contracts. Duplicate tags share readiness, failures reject the Promise and UI loads lazily. With `async`/`defer`, wait for the loader tag's load event before accessing `Longplay`. CSP must allow the script origin and API connections. Page experiments use the same script entry; explicitly create their clients and call `start()`. See [script distribution](../../docs/sdk-architecture.md#web-script-distribution) and [the complete integration example](https://longplayai.com/docs/javascript#script).
|
|
58
|
+
Commit the generated longplay-sdk.js to lock the immutable module URL; resolve it again only when upgrading. The optional classic loader at `https://cdn.longplayai.com/sdk.js` still follows Web releases and uses matching API/credentials. `Longplay.ready` provides every root browser export plus `createPageExperiments` and `createVisualExperiments`; replace npm imports below with destructuring those names. Loading activates no sessions, events or experiments. Server Keys remain on your backend; Funnel start/recovery and logout cleanup retain the existing contracts. Duplicate tags share readiness, failures reject the Promise and UI loads lazily. With `async`/`defer`, wait for the loader tag's load event before accessing `Longplay`. CSP must allow the script origin and API connections. Page experiments use the same script entry; explicitly create their clients and call `start()`. See [script distribution](../../docs/sdk-architecture.md#web-script-distribution) and [the complete integration example](https://www.longplayai.com/docs/sdk/javascript#script).
|
|
61
59
|
|
|
62
60
|
## React Native core
|
|
63
61
|
|
|
@@ -65,7 +63,7 @@ Use the independent `@tinkerlandai/longplay-react-native` package. The `@tinkerl
|
|
|
65
63
|
|
|
66
64
|
## Version compatibility and support
|
|
67
65
|
|
|
68
|
-
During `0.x`, only the current protocol is supported. Starting with `1.0`, compatibility is preserved within each stable major version. Once the next stable major is published, the preceding stable major remains supported for at least 12 calendar months, with at least 180 days' public notice before retirement. The later deadline applies. See the [support policy](https://longplayai.com/docs/
|
|
66
|
+
During `0.x`, only the current protocol is supported. Starting with `1.0`, compatibility is preserved within each stable major version. Once the next stable major is published, the preceding stable major remains supported for at least 12 calendar months, with at least 180 days' public notice before retirement. The later deadline applies. See the [support policy](https://www.longplayai.com/docs/guides/version-support#support-policy).
|
|
69
67
|
|
|
70
68
|
The SDK sends current protocol and SDK version headers and validates the protocol declared by successful responses. Old 0.x protocols are not converted into the current contract. Updating source code does not change an existing npm artifact or deploy a server.
|
|
71
69
|
|
|
@@ -86,7 +84,7 @@ The same package supports JavaScript and TypeScript and includes type declaratio
|
|
|
86
84
|
|
|
87
85
|
For an independent **Page, Popup or Banner resource**, import `createLongplay` and `mountContent` from the root entry, resolve it with `longplay.resolveContent(...)`, then mount the result. `/page` runs GB URL redirect experiments on an existing merchant page; `/visual` applies GB visual changes to that page. `/popup` exposes lower-level screen rendering and preview primitives. Its name does not select or resolve a Popup resource. The public import paths stay unchanged; see [entry ownership](../../docs/sdk-architecture.md#public-entry-points-and-capability-ownership).
|
|
88
86
|
|
|
89
|
-
The separate [Python server SDK](../python/README.md) provides synchronous and asynchronous Customer, holdings, entitlement-check and usage clients against the same current HTTP protocol. It is distributed from `https://longplayai.com/sdk/python` (not PyPI) and is not part of this npm package.
|
|
87
|
+
The separate [Python server SDK](../python/README.md) provides synchronous and asynchronous Customer, holdings, entitlement-check and usage clients against the same current HTTP protocol. It is distributed from `https://cdn.longplayai.com/sdk/python` (not PyPI) and is not part of this npm package.
|
|
90
88
|
|
|
91
89
|
The [Go server SDK](../go/README.md) provides the same initial capabilities with typed responses, Context cancellation and goroutine-safe client reuse. It is installed with `go get longplayai.com/sdk/go` through the default Go module proxy and shares the release version with the other business SDKs.
|
|
92
90
|
|
|
@@ -211,7 +209,7 @@ await process.detach();
|
|
|
211
209
|
|
|
212
210
|
Local execution needs the shared public configuration manager and a published configuration. Login binds the current Run to the account's existing Customer without replacing the Run, answers, history, pinned Version or deadlines. A new account can claim the Guest Customer in place. Another account cannot take over a bound Run; use a new process handle. Commercial assets and historical Customer ownership are preserved.
|
|
213
211
|
|
|
214
|
-
Web IAM hosts opt in with `createIamFunnelProcessEntries`. React Native exports `createFunnelProcess`; Swift and Kotlin expose `LongplayFunnelProcess` and `LongplayFunnelProcessBridge` over the same merchant backend. Native hosts retain their command-storage adapter and presentation session across login. See the [identity contract](../../docs/funnel-customer-get-or-create.md
|
|
212
|
+
Web IAM hosts opt in with `createIamFunnelProcessEntries`. React Native exports `createFunnelProcess`; Swift and Kotlin expose `LongplayFunnelProcess` and `LongplayFunnelProcessBridge` over the same merchant backend. Native hosts retain their command-storage adapter and presentation session across login. See the [identity contract](../../docs/funnel-customer-get-or-create.md#sdk-and-merchant-adapter) for storage, attribution and recovery details.
|
|
215
213
|
|
|
216
214
|
### Bucketing identity across independent consumers
|
|
217
215
|
|
|
@@ -219,7 +217,7 @@ Funnel, standalone Features and page experiments evaluate independently. Matchin
|
|
|
219
217
|
|
|
220
218
|
For Customer-based evaluation, `id` means the Longplay Customer UUID (`customer.id`); `externalUserId` means the merchant account ID (`customer.externalUserId`). Choose the experiment's `hashAttribute` explicitly when creating it and preserve that meaning in every consumer. Do not put the merchant account ID into `attributes.id`. Supply local attributes from your trusted backend's Customer data; `identify(customerToken)` authenticates requests but does not populate local bucketing attributes. These attributes are evaluation data, not authorization.
|
|
221
219
|
|
|
222
|
-
`setAttributes()` replaces the complete object, so retain the bucketing fields on every update. Anonymous page/visual experiments instead default `id` and `deviceId` to the shared first-party device cookie; they do not automatically match an account-based experiment. An open visual client rereads its payload every 60 seconds while visible, so a stopped experiment or disabled delivery reverts without a page reload. Sticky capabilities differ by adapter: managed Local Run instructions receive server state, while pure local tools require their existing host persistence adapter for durable Sticky. No new shared state is introduced. See the [architecture boundary](../../docs/growthbook-sdk-delivery.md
|
|
220
|
+
`setAttributes()` replaces the complete object, so retain the bucketing fields on every update. Anonymous page/visual experiments instead default `id` and `deviceId` to the shared first-party device cookie; they do not automatically match an account-based experiment. An open visual client rereads its payload every 60 seconds while visible, so a stopped experiment or disabled delivery reverts without a page reload. Sticky capabilities differ by adapter: managed Local Run instructions receive server state, while pure local tools require their existing host persistence adapter for durable Sticky. No new shared state is introduced. See the [architecture boundary](../../docs/growthbook-sdk-delivery.md#cross-consumer-evaluation-and-bucketing-identity).
|
|
223
221
|
|
|
224
222
|
### Server-side local Funnel evaluation
|
|
225
223
|
|
|
@@ -273,7 +271,7 @@ unsubscribe();
|
|
|
273
271
|
flags.destroy();
|
|
274
272
|
```
|
|
275
273
|
|
|
276
|
-
The selected environment's integration settings control behavior events, experiment exposures and Feature usage independently. New environments enable
|
|
274
|
+
The selected environment's integration settings control behavior events, experiment exposures and Feature usage independently. New environments enable behavior events, experiment exposures and Feature usage collection. `flush()` includes a `skipped` count for intentionally disabled collection. The database rechecks every batch, including direct SDK/server and Funnel ingestion. Running experiment/Bandit dependencies prevent incompatible collection changes. These controls do not delete history or affect commercial usage accounting.
|
|
277
275
|
|
|
278
276
|
Flags default to local evaluation; Owner/Admin can switch each flag to server evaluation. Server-evaluated flags deliver only keys and results, using the caller's fallback until the first result arrives. Attribute changes immediately discard old results. List hashes are not a secrecy boundary. Local Funnels cannot depend on server-evaluated flags; mode switches also check active historical Runs. `identify` / `reset` release the previous identity's Feature instances and event queue.
|
|
279
277
|
|
|
@@ -395,7 +393,7 @@ const host = await showFunnelRun(container, {
|
|
|
395
393
|
});
|
|
396
394
|
// Retain started.runToken in your host's secure credential storage.
|
|
397
395
|
// Restore the same Run: await flow.restore(originalRunToken).
|
|
398
|
-
host.destroy(); // Detach UI; accepted backend work
|
|
396
|
+
host.destroy(); // Detach UI; accepted backend work retains its server lifecycle.
|
|
399
397
|
started.controller.reset();
|
|
400
398
|
```
|
|
401
399
|
|
|
@@ -531,4 +529,4 @@ In `record_only` mode your backend owns payment execution, verifies its results
|
|
|
531
529
|
|
|
532
530
|
The Server entry exports `createMerchantBridgeHandler`, `createMerchantBridgeAuthorityResolver`, `signMerchantBridgeMessage` and `verifyMerchantBridgeMessage`. Supply backend signing keys, native authorization/CSRF, implemented capabilities/profiles and typed handlers. Set `resolveOperationAuthority: createMerchantBridgeAuthorityResolver(server)` so every financial/read command obtains fresh Longplay authority from the original operation API. A signed service request still requires confirmation and exact scope/Customer ownership; it cannot issue user sessions.
|
|
533
531
|
|
|
534
|
-
Handlers must durably reserve the original operation before external effects and retain the same provider idempotency key. The SDK's preceding lookup is not a concurrency lock. `operation.read` returns `found` or `not_received` without creating effects. Recover `RESULT_UNKNOWN` through that original operation; never infer permission from a browser quote or `pending`. Console discovery is configuration validation, not commercial completion. See the [merchant specification](https://longplayai.com/docs/merchant-execution) for exact fields and recovery.
|
|
532
|
+
Handlers must durably reserve the original operation before external effects and retain the same provider idempotency key. The SDK's preceding lookup is not a concurrency lock. `operation.read` returns `found` or `not_received` without creating effects. Recover `RESULT_UNKNOWN` through that original operation; never infer permission from a browser quote or `pending`. Console discovery is configuration validation, not commercial completion. See the [merchant specification](https://www.longplayai.com/docs/guides/merchant-execution) for exact fields and recovery.
|
package/README.zh-CN.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<p>
|
|
2
|
-
<a href="https://longplayai.com">
|
|
3
|
-
<img src="https://longplayai.com/brand/indiana-mark.png" alt="Longplay" width="72" height="72" />
|
|
2
|
+
<a href="https://www.longplayai.com">
|
|
3
|
+
<img src="https://www.longplayai.com/site/brand/indiana-mark.png" alt="Longplay" width="72" height="72" />
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
[English](./README.md)
|
|
8
8
|
|
|
9
|
-
当前源码为 SDK 0.10.
|
|
9
|
+
当前源码为 SDK 0.10.14、协议 0.10。本页示例使用 `https://api.longplayai.com` 以及生产部署内签发的 Sandbox App/凭据。Sandbox 仍属于生产数据,不能复用独立测试部署的凭据。运行前核对[环境状态](../../docs/development-status.md),确认服务已就绪。
|
|
10
10
|
|
|
11
11
|
# @tinkerlandai/longplay-sdk
|
|
12
12
|
|
|
@@ -18,11 +18,9 @@
|
|
|
18
18
|
npm install --save-exact @tinkerlandai/longplay-sdk@latest
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
首次安装解析最新稳定版,--save-exact 将结果固定在 package.json。提交锁文件,后续构建使用 npm ci
|
|
21
|
+
首次安装解析最新稳定版,--save-exact 将结果固定在 package.json。提交锁文件,后续构建使用 npm ci。[SDK 分发](../../docs/sdk-releases.md)记录包版本;源码修改不代表已发布,已有版本产物保持不可变。
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
SDK 0.10.7 要求 HTTP 协议 0.10。服务端须使用同一当前协议,不提供旧协议兼容;发布包不会部署服务端。实际发布、标签与环境验收范围见 [SDK 发布总账](../../docs/sdk-releases.md) 和 [开发状态](../../docs/development-status.md)。
|
|
23
|
+
当前 SDK 要求 HTTP 协议 0.10。服务端须使用同一当前协议,不提供旧协议兼容;发布包不会部署服务端。实际发布、标签与环境验收范围见 [SDK 发布总账](../../docs/sdk-releases.md) 和 [开发状态](../../docs/development-status.md)。
|
|
26
24
|
|
|
27
25
|
数据/会话层负责公开 JSON、完整性校验和鉴权操作;展示宿主将会话接口接入打包的屏幕渲染器,渲染器消费已提供的数据并返回动作意图。客户端按需加载展示;`/server` 入口使用商户后端的受限 Server Key,不加载屏幕展示。SDK 本地检查不替代运行时授权或付款核实。后台 Preview 为同一个展示宿主提供模拟会话和数据。
|
|
28
26
|
|
|
@@ -31,7 +29,7 @@ SDK 0.10.7 要求 HTTP 协议 0.10。服务端须使用同一当前协议,不
|
|
|
31
29
|
普通 script 标签复用 npm 浏览器实现,无需打包工具:
|
|
32
30
|
|
|
33
31
|
```sh
|
|
34
|
-
SDK_MODULE_URL="$(curl -fsS https://longplayai.com/sdk/module)" &&
|
|
32
|
+
SDK_MODULE_URL="$(curl -fsS https://cdn.longplayai.com/sdk/module)" &&
|
|
35
33
|
printf 'export * from "%s";\n' "$SDK_MODULE_URL" > longplay-sdk.js
|
|
36
34
|
```
|
|
37
35
|
|
|
@@ -57,7 +55,7 @@ printf 'export * from "%s";\n' "$SDK_MODULE_URL" > longplay-sdk.js
|
|
|
57
55
|
</script>
|
|
58
56
|
```
|
|
59
57
|
|
|
60
|
-
提交生成的 longplay-sdk.js,即可锁定不可变模块地址;仅在升级时重新解析。经典脚本 `https://longplayai.com/sdk.js` 仍随 Web 发布更新,并配套使用同环境 API 和凭据。`Longplay.ready` 返回根入口的全部浏览器导出,以及 `createPageExperiments` / `createVisualExperiments`;下文 npm import 可替换为从该 Promise 解构同名函数。加载不自动创建会话、发送事件或启动实验。Server Key 留在后端,Funnel 启动恢复与退出清理沿用现有流程。重复标签共用 ready,失败会拒绝 Promise,UI 按需加载。加载标签使用普通 script;添加 async/defer 时先等标签 load 事件,再访问 `Longplay`。CSP 需允许脚本来源和 API 连接。页面实验也使用该统一入口,显式创建客户端并调用 `start()`。详见 [script 分发](../../docs/sdk-architecture.md#web-script-distribution)和[完整接入示例](https://longplayai.com/docs/javascript#script)。
|
|
58
|
+
提交生成的 longplay-sdk.js,即可锁定不可变模块地址;仅在升级时重新解析。经典脚本 `https://cdn.longplayai.com/sdk.js` 仍随 Web 发布更新,并配套使用同环境 API 和凭据。`Longplay.ready` 返回根入口的全部浏览器导出,以及 `createPageExperiments` / `createVisualExperiments`;下文 npm import 可替换为从该 Promise 解构同名函数。加载不自动创建会话、发送事件或启动实验。Server Key 留在后端,Funnel 启动恢复与退出清理沿用现有流程。重复标签共用 ready,失败会拒绝 Promise,UI 按需加载。加载标签使用普通 script;添加 async/defer 时先等标签 load 事件,再访问 `Longplay`。CSP 需允许脚本来源和 API 连接。页面实验也使用该统一入口,显式创建客户端并调用 `start()`。详见 [script 分发](../../docs/sdk-architecture.md#web-script-distribution)和[完整接入示例](https://www.longplayai.com/zh-hans/docs/sdk/javascript#script)。
|
|
61
59
|
|
|
62
60
|
## React Native 核心入口
|
|
63
61
|
|
|
@@ -75,7 +73,7 @@ Flow `commit_segment` 只包含固定 requestId、停车位置 nodeId/visit/
|
|
|
75
73
|
|
|
76
74
|
## 版本兼容与支持
|
|
77
75
|
|
|
78
|
-
当前 0.x 仅支持当前协议;1.0 起同一主版本内保持兼容。新稳定主版本发布后,旧稳定主版本至少继续支持 12 个日历月,停止支持提前至少 180 天公开通知,实际日期取两者中较晚者。详见 [版本与支持政策](../../docs/sdk-versioning-and-support.md) 和公开开发文档 `/docs/
|
|
76
|
+
当前 0.x 仅支持当前协议;1.0 起同一主版本内保持兼容。新稳定主版本发布后,旧稳定主版本至少继续支持 12 个日历月,停止支持提前至少 180 天公开通知,实际日期取两者中较晚者。详见 [版本与支持政策](../../docs/sdk-versioning-and-support.md) 和公开开发文档 `/zh-hans/docs/guides/version-support#support-policy`。
|
|
79
77
|
|
|
80
78
|
SDK 发送当前协议及 SDK 版本请求头,并校验成功响应的协议声明;旧 0.x 协议不会自动转换成当前协议。源码更新不会修改已有 npm 包,也不会自动部署服务端。
|
|
81
79
|
|
|
@@ -96,7 +94,7 @@ JavaScript 与 TypeScript 共用本包,声明文件随包提供。内部 `@ind
|
|
|
96
94
|
|
|
97
95
|
展示独立的 **Page、Popup 或 Banner 资源**,从主入口导入 `createLongplay` 和 `mountContent`,先用 `longplay.resolveContent(...)` 解析,再挂载结果。`/page` 用于商户现有页面的 GB 网址跳转实验,`/visual` 用于该页面的 GB 视觉修改;`/popup` 提供底层屏幕渲染与预览工具,不负责选择或解析 Popup 资源。现有公开导入路径保持不变,详见[入口职责](../../docs/sdk-architecture.md#public-entry-points-and-capability-ownership)。
|
|
98
96
|
|
|
99
|
-
独立的 [Python 服务端 SDK](../python/README.md) 使用同一当前 HTTP 协议,提供同步、异步 Customer、持仓/权益检查和用量上报。它从 `https://longplayai.com/sdk/python` 分发(不在 PyPI),不属于这个 npm 包。
|
|
97
|
+
独立的 [Python 服务端 SDK](../python/README.md) 使用同一当前 HTTP 协议,提供同步、异步 Customer、持仓/权益检查和用量上报。它从 `https://cdn.longplayai.com/sdk/python` 分发(不在 PyPI),不属于这个 npm 包。
|
|
100
98
|
|
|
101
99
|
[Go 服务端 SDK](../go/README.md) 提供同样的首版能力,使用类型化响应、Context 取消和 goroutine 并发复用客户端。通过 Go 默认模块代理以 `go get longplayai.com/sdk/go` 安装,与其他业务 SDK 共用发行版本。
|
|
102
100
|
|
|
@@ -191,7 +189,7 @@ Funnel、独立 Feature 和页面实验各自求值、各自使用结果。App
|
|
|
191
189
|
|
|
192
190
|
Customer 求值中的 `id` 是 Longplay Customer UUID(`customer.id`),`externalUserId` 是商户账号 ID(`customer.externalUserId`)。创建实验时明确选择 `hashAttribute`,每个消费方保持相同语义;不要把商户账号 ID 填进 `attributes.id`。本地属性来自可信后端给当前用户的 Customer 数据;`identify(customerToken)` 负责请求认证,不会自动补齐本地分桶属性。属性仅用于求值,不构成授权。
|
|
193
191
|
|
|
194
|
-
`setAttributes()` 替换整个对象,每次更新都保留分桶字段。匿名页面/视觉实验默认的 `id` 和 `deviceId` 来自共用的第一方设备 cookie,不自动与账号实验同组。已打开的页面在可见时每 60 秒重新读取视觉配置,实验停止或关闭投放后无需刷新页面即可撤销修改。各适配器的 Sticky 能力有区别:共用 Run 的 Local 指令读取服务端状态,纯本地工具的持久 Sticky 使用已有宿主适配器,不新增共享状态。完整要求见[架构边界](../../docs/growthbook-sdk-delivery.md
|
|
192
|
+
`setAttributes()` 替换整个对象,每次更新都保留分桶字段。匿名页面/视觉实验默认的 `id` 和 `deviceId` 来自共用的第一方设备 cookie,不自动与账号实验同组。已打开的页面在可见时每 60 秒重新读取视觉配置,实验停止或关闭投放后无需刷新页面即可撤销修改。各适配器的 Sticky 能力有区别:共用 Run 的 Local 指令读取服务端状态,纯本地工具的持久 Sticky 使用已有宿主适配器,不新增共享状态。完整要求见[架构边界](../../docs/growthbook-sdk-delivery.md#cross-consumer-evaluation-and-bucketing-identity)。
|
|
195
193
|
|
|
196
194
|
### 服务端 SDK 本地 Funnel 求值
|
|
197
195
|
|
|
@@ -218,7 +216,7 @@ const used = await session.evaluate({ track: true });
|
|
|
218
216
|
|
|
219
217
|
默认求值不触发曝光。仅在确实使用结果时传 `{ track: true }`,成功计算并保存 Sticky 后才调用已配置的 `onExperimentViewed`/`onFeatureUsage`,按本会话内的原生分配/值去重。回调接入已有事件 tracker,异常通过 `onError` 报告;事件送达与重试由 tracker 负责,不生成持久的曝光或使用回执。
|
|
220
218
|
|
|
221
|
-
含商业节点的混合图、资源/Bundle 输出、过期配置明确拒绝,不自动执行远程 `decide()
|
|
219
|
+
含商业节点的混合图、资源/Bundle 输出、过期配置明确拒绝,不自动执行远程 `decide()`。远程幂等、已提交回执和财务检查保持原义;本地结果不能代替发券、付款、权益或全局频控。使用前确认目标运行时支持相同协议与配置投递契约。
|
|
222
220
|
|
|
223
221
|
### 独立 Feature
|
|
224
222
|
|
|
@@ -264,7 +262,7 @@ Offering 固定 Product Version 的范围与层级。Paywall 固定已发布 Off
|
|
|
264
262
|
|
|
265
263
|
Stripe 环境的 `longplay` 模式由 Longplay 执行;`record_only` 返回交给商户后端执行的指令。两种模式都从验证后的 Stripe 事实写入财务与权益。支付方式收集本身不产生扣款、Invoice 或额外权益。报价/确认/读取使用各自持久操作 ID;同一请求编号不能更换输入。
|
|
266
264
|
|
|
267
|
-
|
|
265
|
+
包安装成功**不代表完整商业功能或生产环境已验收**。当前仍未接通的服务包括:
|
|
268
266
|
|
|
269
267
|
- 订阅批处理。冲突查询/重试已有对应服务,但仍需匹配部署及业务前置条件。
|
|
270
268
|
- Postpaid Billing Authorization、Billing Coupon 列表和账单调整确认。当前 AutoTopup consent 的准备/确认/撤销已有服务,不能据此推定其他授权类型可用。
|
|
@@ -287,7 +285,7 @@ npm 发布不部署 Web 服务、不应用数据库迁移,也不发布 Swift
|
|
|
287
285
|
|
|
288
286
|
## 共享公共配置
|
|
289
287
|
|
|
290
|
-
|
|
288
|
+
`createConfigurationSync({ origin, scope })`;`scope` 必须明确包含 `projectId`、`environment` 和 `environmentId`。将同一个实例作为 `configuration` 传给 `createLongplay`、Funnel start/Run controller 和 `createPageExperiments`,共用清单、文件缓存、并发请求和更新通知。`/server` 导出的 `createSynchronizedFunnelLocalEvaluator(configuration, funnelId)` 使用同一份规范 Funnel 文件与 GB 代次进行纯判断,保留仅可信服务端执行的边界。
|
|
291
289
|
|
|
292
290
|
公共配置由匹配运行端发布。公共文件不需要 Customer 凭据;业务操作沿用原凭据和服务端资格检查。完整调用见[英文说明](README.md#shared-public-configuration)。
|
|
293
291
|
|
|
@@ -376,4 +374,4 @@ export async function showBanner(
|
|
|
376
374
|
|
|
377
375
|
Server 入口导出 `createMerchantBridgeHandler`、`createMerchantBridgeAuthorityResolver`、`signMerchantBridgeMessage` 和 `verifyMerchantBridgeMessage`。配置后端签名密钥、原生授权/CSRF、实际已实现的能力与 profiles,并设置 `resolveOperationAuthority: createMerchantBridgeAuthorityResolver(server)`,每次从 Longplay 原操作 API 读取最新权限。服务签名仍需原确认事实和准确范围、Customer 归属,不能据此签发用户会话。
|
|
378
376
|
|
|
379
|
-
业务处理器必须在调用外部渠道前持久预留原 operationId,并使用稳定渠道幂等键;SDK 的先查询不能代替并发锁。`operation.read` 返回 `found` 或 `not_received`,严格只读。`RESULT_UNKNOWN` 只恢复原操作,不能根据浏览器报价或 pending 状态自行推断执行权限。Console 能力检查不证明商业完成。精确字段和恢复规则见[商户接入规范](https://longplayai.com/zh-hans/docs/merchant-execution)。
|
|
377
|
+
业务处理器必须在调用外部渠道前持久预留原 operationId,并使用稳定渠道幂等键;SDK 的先查询不能代替并发锁。`operation.read` 返回 `found` 或 `not_received`,严格只读。`RESULT_UNKNOWN` 只恢复原操作,不能根据浏览器报价或 pending 状态自行推断执行权限。Console 能力检查不证明商业完成。精确字段和恢复规则见[商户接入规范](https://www.longplayai.com/zh-hans/docs/guides/merchant-execution)。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LanguageModelV4Usage, LanguageModelV4Middleware } from '@ai-sdk/provider';
|
|
2
|
-
import { F as FoundationApi, A as ApiInput } from './api-
|
|
2
|
+
import { F as FoundationApi, A as ApiInput } from './api-RQUBSSEJ.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
declare const tokenCounts: z.ZodObject<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as StackNode } from './screen-
|
|
1
|
+
import { S as StackNode } from './screen-DRP7nsrQ.js';
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
import { z as z$1 } from 'zod';
|
|
4
4
|
|
|
@@ -3985,11 +3985,11 @@ declare const apiOperations: {
|
|
|
3985
3985
|
field: z$1.ZodEnum<{
|
|
3986
3986
|
quantity: "quantity";
|
|
3987
3987
|
currency: "currency";
|
|
3988
|
+
product: "product";
|
|
3988
3989
|
price: "price";
|
|
3989
3990
|
subscription: "subscription";
|
|
3990
3991
|
status: "status";
|
|
3991
3992
|
cancelAtPeriodEnd: "cancelAtPeriodEnd";
|
|
3992
|
-
product: "product";
|
|
3993
3993
|
periodStart: "periodStart";
|
|
3994
3994
|
periodEnd: "periodEnd";
|
|
3995
3995
|
trialEnd: "trialEnd";
|
|
@@ -4709,20 +4709,6 @@ declare const apiOperations: {
|
|
|
4709
4709
|
eventId: z$1.ZodString;
|
|
4710
4710
|
customerId: z$1.ZodUUID;
|
|
4711
4711
|
occurredAt: z$1.ZodISODateTime;
|
|
4712
|
-
}, z$1.core.$strict>, z$1.ZodObject<{
|
|
4713
|
-
type: z$1.ZodLiteral<"dispute.updated">;
|
|
4714
|
-
merchantDisputeId: z$1.ZodString;
|
|
4715
|
-
merchantInvoiceId: z$1.ZodString;
|
|
4716
|
-
status: z$1.ZodEnum<{
|
|
4717
|
-
funds_withdrawn: "funds_withdrawn";
|
|
4718
|
-
funds_reinstated: "funds_reinstated";
|
|
4719
|
-
}>;
|
|
4720
|
-
amountMinor: z$1.ZodNumber;
|
|
4721
|
-
currency: z$1.ZodString;
|
|
4722
|
-
provider: z$1.ZodLiteral<"merchant">;
|
|
4723
|
-
eventId: z$1.ZodString;
|
|
4724
|
-
customerId: z$1.ZodUUID;
|
|
4725
|
-
occurredAt: z$1.ZodISODateTime;
|
|
4726
4712
|
}, z$1.core.$strict>], "type">]>;
|
|
4727
4713
|
readonly response: z$1.ZodObject<{
|
|
4728
4714
|
requestId: z$1.ZodUUID;
|
|
@@ -12164,8 +12150,8 @@ declare const apiOperations: {
|
|
|
12164
12150
|
rows: z$1.ZodArray<z$1.ZodObject<{
|
|
12165
12151
|
id: z$1.ZodUUID;
|
|
12166
12152
|
sourceKind: z$1.ZodEnum<{
|
|
12167
|
-
usage: "usage";
|
|
12168
12153
|
product: "product";
|
|
12154
|
+
usage: "usage";
|
|
12169
12155
|
manual: "manual";
|
|
12170
12156
|
}>;
|
|
12171
12157
|
providerInvoiceId: z$1.ZodNullable<z$1.ZodString>;
|
|
@@ -12382,8 +12368,8 @@ declare const apiOperations: {
|
|
|
12382
12368
|
invoice: z$1.ZodObject<{
|
|
12383
12369
|
id: z$1.ZodUUID;
|
|
12384
12370
|
sourceKind: z$1.ZodEnum<{
|
|
12385
|
-
usage: "usage";
|
|
12386
12371
|
product: "product";
|
|
12372
|
+
usage: "usage";
|
|
12387
12373
|
manual: "manual";
|
|
12388
12374
|
}>;
|
|
12389
12375
|
providerInvoiceId: z$1.ZodNullable<z$1.ZodString>;
|
|
@@ -13446,14 +13432,30 @@ declare const apiOperations: {
|
|
|
13446
13432
|
schemaVersion: z$1.ZodLiteral<4>;
|
|
13447
13433
|
name: z$1.ZodString;
|
|
13448
13434
|
surface: z$1.ZodEnum<{
|
|
13449
|
-
paywall: "paywall";
|
|
13450
13435
|
popup: "popup";
|
|
13436
|
+
paywall: "paywall";
|
|
13451
13437
|
onboarding: "onboarding";
|
|
13452
13438
|
page: "page";
|
|
13453
13439
|
banner: "banner";
|
|
13454
13440
|
}>;
|
|
13455
13441
|
initialPageId: z$1.ZodOptional<z$1.ZodString>;
|
|
13456
13442
|
presentation: z$1.ZodDiscriminatedUnion<[z$1.ZodObject<{
|
|
13443
|
+
desktopWidth: z$1.ZodOptional<z$1.ZodObject<{
|
|
13444
|
+
min: z$1.ZodNumber;
|
|
13445
|
+
max: z$1.ZodNumber;
|
|
13446
|
+
viewport: z$1.ZodNumber;
|
|
13447
|
+
}, z$1.core.$strict>>;
|
|
13448
|
+
mobile: z$1.ZodOptional<z$1.ZodEnum<{
|
|
13449
|
+
sheet: "sheet";
|
|
13450
|
+
fullscreen: "fullscreen";
|
|
13451
|
+
}>>;
|
|
13452
|
+
backdrop: z$1.ZodOptional<z$1.ZodEnum<{
|
|
13453
|
+
none: "none";
|
|
13454
|
+
scrim: "scrim";
|
|
13455
|
+
dim: "dim";
|
|
13456
|
+
"strong-dim": "strong-dim";
|
|
13457
|
+
blur: "blur";
|
|
13458
|
+
}>>;
|
|
13457
13459
|
type: z$1.ZodLiteral<"modal">;
|
|
13458
13460
|
size: z$1.ZodEnum<{
|
|
13459
13461
|
sm: "sm";
|
|
@@ -13461,6 +13463,22 @@ declare const apiOperations: {
|
|
|
13461
13463
|
lg: "lg";
|
|
13462
13464
|
}>;
|
|
13463
13465
|
}, z$1.core.$strict>, z$1.ZodObject<{
|
|
13466
|
+
desktopWidth: z$1.ZodOptional<z$1.ZodObject<{
|
|
13467
|
+
min: z$1.ZodNumber;
|
|
13468
|
+
max: z$1.ZodNumber;
|
|
13469
|
+
viewport: z$1.ZodNumber;
|
|
13470
|
+
}, z$1.core.$strict>>;
|
|
13471
|
+
mobile: z$1.ZodOptional<z$1.ZodEnum<{
|
|
13472
|
+
sheet: "sheet";
|
|
13473
|
+
fullscreen: "fullscreen";
|
|
13474
|
+
}>>;
|
|
13475
|
+
backdrop: z$1.ZodOptional<z$1.ZodEnum<{
|
|
13476
|
+
none: "none";
|
|
13477
|
+
scrim: "scrim";
|
|
13478
|
+
dim: "dim";
|
|
13479
|
+
"strong-dim": "strong-dim";
|
|
13480
|
+
blur: "blur";
|
|
13481
|
+
}>>;
|
|
13464
13482
|
type: z$1.ZodLiteral<"sheet">;
|
|
13465
13483
|
size: z$1.ZodEnum<{
|
|
13466
13484
|
sm: "sm";
|
|
@@ -13477,11 +13495,11 @@ declare const apiOperations: {
|
|
|
13477
13495
|
background: z$1.ZodString;
|
|
13478
13496
|
text: z$1.ZodString;
|
|
13479
13497
|
radius: z$1.ZodEnum<{
|
|
13480
|
-
none: "none";
|
|
13481
|
-
full: "full";
|
|
13482
13498
|
sm: "sm";
|
|
13483
13499
|
md: "md";
|
|
13484
13500
|
lg: "lg";
|
|
13501
|
+
none: "none";
|
|
13502
|
+
full: "full";
|
|
13485
13503
|
}>;
|
|
13486
13504
|
font: z$1.ZodEnum<{
|
|
13487
13505
|
system: "system";
|
|
@@ -13489,6 +13507,14 @@ declare const apiOperations: {
|
|
|
13489
13507
|
rounded: "rounded";
|
|
13490
13508
|
mono: "mono";
|
|
13491
13509
|
}>;
|
|
13510
|
+
fontAssets: z$1.ZodOptional<z$1.ZodObject<{
|
|
13511
|
+
family: z$1.ZodString;
|
|
13512
|
+
faces: z$1.ZodArray<z$1.ZodObject<{
|
|
13513
|
+
url: z$1.ZodString;
|
|
13514
|
+
weight: z$1.ZodNumber;
|
|
13515
|
+
family: z$1.ZodOptional<z$1.ZodString>;
|
|
13516
|
+
}, z$1.core.$strict>>;
|
|
13517
|
+
}, z$1.core.$strict>>;
|
|
13492
13518
|
}, z$1.core.$strict>;
|
|
13493
13519
|
pages: z$1.ZodArray<z$1.ZodObject<{
|
|
13494
13520
|
id: z$1.ZodString;
|
|
@@ -13499,11 +13525,11 @@ declare const apiOperations: {
|
|
|
13499
13525
|
background: z$1.ZodString;
|
|
13500
13526
|
text: z$1.ZodString;
|
|
13501
13527
|
radius: z$1.ZodEnum<{
|
|
13502
|
-
none: "none";
|
|
13503
|
-
full: "full";
|
|
13504
13528
|
sm: "sm";
|
|
13505
13529
|
md: "md";
|
|
13506
13530
|
lg: "lg";
|
|
13531
|
+
none: "none";
|
|
13532
|
+
full: "full";
|
|
13507
13533
|
}>;
|
|
13508
13534
|
font: z$1.ZodEnum<{
|
|
13509
13535
|
system: "system";
|
|
@@ -13511,6 +13537,14 @@ declare const apiOperations: {
|
|
|
13511
13537
|
rounded: "rounded";
|
|
13512
13538
|
mono: "mono";
|
|
13513
13539
|
}>;
|
|
13540
|
+
fontAssets: z$1.ZodOptional<z$1.ZodObject<{
|
|
13541
|
+
family: z$1.ZodString;
|
|
13542
|
+
faces: z$1.ZodArray<z$1.ZodObject<{
|
|
13543
|
+
url: z$1.ZodString;
|
|
13544
|
+
weight: z$1.ZodNumber;
|
|
13545
|
+
family: z$1.ZodOptional<z$1.ZodString>;
|
|
13546
|
+
}, z$1.core.$strict>>;
|
|
13547
|
+
}, z$1.core.$strict>>;
|
|
13514
13548
|
}, z$1.core.$strict>>;
|
|
13515
13549
|
editorPosition: z$1.ZodOptional<z$1.ZodObject<{
|
|
13516
13550
|
x: z$1.ZodNumber;
|
|
@@ -14726,8 +14760,8 @@ declare const apiOperations: {
|
|
|
14726
14760
|
}, z$1.core.$strict>, z$1.ZodObject<{
|
|
14727
14761
|
type: z$1.ZodLiteral<"transaction">;
|
|
14728
14762
|
purpose: z$1.ZodEnum<{
|
|
14729
|
-
invoice: "invoice";
|
|
14730
14763
|
product: "product";
|
|
14764
|
+
invoice: "invoice";
|
|
14731
14765
|
}>;
|
|
14732
14766
|
productVersionId: z$1.ZodNullable<z$1.ZodUUID>;
|
|
14733
14767
|
productName: z$1.ZodNullable<z$1.ZodString>;
|
|
@@ -14847,8 +14881,8 @@ declare const apiOperations: {
|
|
|
14847
14881
|
invoice: z$1.ZodObject<{
|
|
14848
14882
|
id: z$1.ZodUUID;
|
|
14849
14883
|
sourceKind: z$1.ZodEnum<{
|
|
14850
|
-
usage: "usage";
|
|
14851
14884
|
product: "product";
|
|
14885
|
+
usage: "usage";
|
|
14852
14886
|
manual: "manual";
|
|
14853
14887
|
}>;
|
|
14854
14888
|
providerInvoiceId: z$1.ZodNullable<z$1.ZodString>;
|
|
@@ -16224,8 +16258,8 @@ declare const apiOperations: {
|
|
|
16224
16258
|
holdingStatus: z$1.ZodDefault<z$1.ZodEnum<{
|
|
16225
16259
|
"": "";
|
|
16226
16260
|
unavailable: "unavailable";
|
|
16227
|
-
active: "active";
|
|
16228
16261
|
none: "none";
|
|
16262
|
+
active: "active";
|
|
16229
16263
|
expired: "expired";
|
|
16230
16264
|
scheduled: "scheduled";
|
|
16231
16265
|
}>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{f as o}from"./chunk-
|
|
1
|
+
import{f as o}from"./chunk-PFHS7HK3.js";var n=class extends Error{constructor(t,s,y,i,r){super(s);this.code=t;this.status=y;this.requestId=i;this.name="IndianaError",this.reason=r?.reason;let e=o(t,y??0,{...r,retryAfter:r?.retryAfterSeconds===void 0?void 0:String(r.retryAfterSeconds)});this.retryable=e.retryable,this.recovery=e.recovery,this.retryAfterSeconds=e.retryAfterSeconds}code;status;requestId;commandRequestId;retryable;recovery;retryAfterSeconds;reason};export{n as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as dn,c as fn,d as mn,e as pn}from"./chunk-LC2VUKYM.js";import{a as gn}from"./chunk-EEZLS2YP.js";import{a as te,b as Y}from"./chunk-APO7QUBB.js";import{a as m}from"./chunk-26HU2HXU.js";import{a as ln,b as cn,c as Ce}from"./chunk-6MBVIE3H.js";import{$a as un,Ea as Te,Fa as tn,R as Ge,T as Re,Ta as rn,U as Be,Ua as on,V as Je,W as je,Xa as an,Ya as sn,a as qe,cb as le,da as Q,ea as ze,fa as J,ga as Ke,ha as Oe,ia as M,ka as Qe,la as Ye,ma as $e,n as ue,na as We,oa as Ze,ua as ne,va as Xe,ya as en,za as nn}from"./chunk-EFFXE6CX.js";import{B as ve,Fa as He,v as Ue,y as ke}from"./chunk-PFHS7HK3.js";function qn(e){let n=null,t=null,s=0,d=0,w=new Set,f=null,o=null,g=new Set,i=()=>{for(let a of g)try{a()}catch{}},l={attributes:ve.parse(e.attributes??{}),onFeatureUsage:e.onFeatureUsage?(a,r)=>{!w.has(a)&&(!n||!("analyticsConfig"in n)||n.analyticsConfig.featureUsageEnabled)&&e.onFeatureUsage(a,structuredClone(r),structuredClone(l.attributes))}:void 0,onExperimentViewed:e.onExperimentViewed?(a,r)=>(!n||!("analyticsConfig"in n)||n.analyticsConfig.experimentViewsEnabled)&&e.onExperimentViewed(structuredClone(a),structuredClone(r),structuredClone(l.attributes)):void 0,stickyBucketAssignmentDocs:structuredClone(e.stickyBucketAssignmentDocs),saveStickyBucketAssignmentDoc:e.saveStickyBucketAssignmentDoc?a=>e.saveStickyBucketAssignmentDoc(structuredClone(a)):void 0,trackedFeatureUsage:{},trackedExperiments:new Set},u=()=>({value:null,source:"unknownFeature",on:!1,off:!0,ruleId:""});function c(a,r=new Set){return w.has(a)?!f||!f.features[a]||["unknownFeature","cyclicPrerequisite"].includes(f.features[a].source):r.has(a)?!1:(r.add(a),(n?.features[a]?.rules??[]).some(p=>[...p.parentConditions??[],...(p.tracks??[]).flatMap(v=>v.experiment.parentConditions??[])].some(v=>c(v.id,r))))}let h=a=>{if(e.assertUsable?.(n?.generation),!n)throw new Error("Initialize the Feature client before evaluation");if(n.expiresAt&&Date.parse(n.expiresAt)<=Date.now())throw new Error("Feature configuration expired; refresh before evaluation");return f?.expiresAt&&Date.parse(f.expiresAt)<=Date.now()&&(f=null,l.features=n.features),w.has(a)?!f||f.expiresAt&&Date.parse(f.expiresAt)<=Date.now()?u():structuredClone(f.features[a]??u()):e.evaluateRemote&&(l.attributes?.merchandise||l.attributes?.merchandiseId)&&!f||c(a)?u():structuredClone(ke(a,l))};async function F(){if(!n||!w.size&&!l.attributes?.merchandise&&!l.attributes?.merchandiseId)return;if(!e.evaluateRemote){if(w.size)throw new Error("Remote Feature evaluation requires a server loader");return}let a=d;if(o?.revision===a)return o.loading;let r=s,p=n,v=[...w],C=(async()=>{let S=je.parse(await e.evaluateRemote({attributes:structuredClone(l.attributes),features:v}));if(!(r!==s||a!==d||p!==n)){if(e.assertUsable?.(p.generation),S.generation!==p.generation)throw new Error("Feature configuration changed; refresh before evaluation");if(v.some(R=>!Object.hasOwn(S.features,R))||Object.keys(S.features).some(R=>!w.has(R)))throw new Error("Invalid remote Feature results");if(l.attributes?.merchandise||l.attributes?.merchandiseId){if(!S.merchandiseContext)throw new Error("Server did not resolve merchandise context");l.attributes=ve.parse({...l.attributes,...S.merchandiseContext})}f=structuredClone(S),l.features={...p.features,...Object.fromEntries(Object.entries(f.features).map(([R,O])=>[R,{defaultValue:O.value}]))},i()}})();o={revision:a,loading:C};try{await C}finally{o?.loading===C&&(o=null)}}function N(){F().catch(a=>{try{e.onError?.(a)}catch{}})}async function L(){if(t)return t;let a=s,r=(async()=>{let p=await e.load(),v="remoteFeatures"in p?Be.parse(p):null,C=v??Re.parse(p);if(C.scope.projectId!==e.scope.projectId||C.scope.environment!==e.scope.environment)throw new Error("Feature payload scope changed");if(a!==s)throw new Error("Feature client was reset");if(e.assertUsable&&n?.generation===C.generation){let{evaluatedAt:R,expiresAt:O,...D}=n,{evaluatedAt:x,expiresAt:k,...G}=C;if(M(D)!==M(G))throw new Error("Immutable Feature generation changed content");return n.evaluatedAt=C.evaluatedAt,n.expiresAt=C.expiresAt,i(),(!f||f.expiresAt&&Date.parse(f.expiresAt)<=Date.now())&&N(),structuredClone(n)}let S=new Set(v?.remoteFeatures??[]);if([...S].some(R=>Object.hasOwn(C.features,R)))throw new Error("Remote Feature definitions must not be delivered locally");return n&&"analyticsConfig"in n&&"analyticsConfig"in C&&!n.analyticsConfig.experimentViewsEnabled&&v?.analyticsConfig.experimentViewsEnabled&&l.trackedExperiments?.clear(),n=structuredClone(C),w=S,f=null,o=null,d++,l.features=n.features,l.savedGroups=Ue(n.savedGroups),l.trackedFeatureUsage={},i(),N(),structuredClone(n)})();t=r;try{return await r}finally{t===r&&(t=null)}}return{init:L,refresh:L,refreshRemote:F,get generation(){return n?.generation??null},get expiresAt(){return n?.expiresAt??null},subscribe(a){return g.add(a),()=>{g.delete(a)}},setAttributes(a){let r=ve.parse(a);(l.attributes?.merchandise||l.attributes?.merchandiseId||a.merchandise||a.merchandiseId)&&l.trackedExperiments?.clear(),l.attributes=r,d++,f=null,o=null,l.features=n?.features??{},l.trackedFeatureUsage={},i(),N()},evalFeature:h,isOn(a){return h(a).on},isOff(a){return h(a).off},getFeatureValue(a,r){let p=h(a).value;return structuredClone(p===null?r:p)},reset(){s++,d++,t=null,o=null,n=null,f=null,w.clear(),l.features={},l.savedGroups={},l.stickyBucketAssignmentDocs={},l.attributes={},l.trackedFeatureUsage={},l.trackedExperiments?.clear(),i()}}}function yn(e){let n,t,s=()=>new m("COMMAND_STORAGE_INVALID","Durable command storage is unavailable"),d=Promise.resolve().then(async()=>{if(n=e.storage??globalThis.localStorage,t=e.locks??globalThis.navigator?.locks,!n||!t||!globalThis.crypto?.subtle)throw s();let o=new TextEncoder().encode(JSON.stringify([new URL(e.baseUrl??le).href,e.runToken])),g=new Uint8Array(await crypto.subtle.digest("SHA-256",o));return"indiana.funnel.commands.v1."+Array.from(g,i=>i.toString(16).padStart(2,"0")).join("")});d.catch(()=>{});async function w(o){try{let g=await d;return await t.request(g,{mode:"exclusive"},()=>o(g))}catch(g){throw g instanceof m?g:s()}}function f(o){let g=n.getItem(o);if(g===null)return{revision:0,entry:null};if(g.length>1048576)throw s();let i=JSON.parse(g);if(!i||typeof i!="object"||!("revision"in i)||!("entry"in i)||!Number.isSafeInteger(i.revision)||Number(i.revision)<0)throw s();return{revision:Number(i.revision),entry:i.entry}}return{read:()=>w(f),write:(o,g)=>w(i=>{if(f(i).revision!==o)return null;if(!Number.isSafeInteger(o+1))throw s();return n.setItem(i,JSON.stringify({revision:o+1,entry:g})),o+1})}}function be(e,n){let t=en.safeParse(n);if(!t.success)throw new m("INVALID_RESPONSE","Funnel response contract changed");let s=t.data;if(e.scope&&(s.scope.projectId!==e.scope.projectId||s.scope.environment!==e.scope.environment))throw new m("SCOPE_MISMATCH","Funnel scope changed");return s}async function Pe(e,n){let t=We.parse(n),{artifact:s,environmentId:d}=t.content,w=new te(e.baseUrl??le).origin,f=new te(s.url,w);if(f.origin!==w||f.username||f.password||f.search||f.hash||f.pathname!==`/api/v1/configuration/${d}/artifacts/${s.sha256}`)throw new m("INVALID_RESPONSE","Public Paywall locator is not trusted");let o=new AbortController,g,i=new Promise((u,c)=>{g=setTimeout(()=>{let h=new m("TIMEOUT","Public Paywall read timed out");o.abort(h),c(h)},J.initializationMs)}),l=(async()=>{let u=await(e.fetch??globalThis.fetch)(f,{method:"GET",credentials:"omit",redirect:"error",cache:"default",signal:o.signal});if(o.signal.aborted&&(u.body?.cancel().catch(()=>{}),o.signal.throwIfAborted()),!u.ok||!u.headers.get("content-type")?.toLowerCase().startsWith("application/json")||Number(u.headers.get("content-length"))>s.byteLength)throw u.body?.cancel().catch(()=>{}),new m("INVALID_RESPONSE","Public Paywall is unavailable");let c=await ln(u,s.byteLength,{signal:o.signal,error:h=>new m("INVALID_RESPONSE",h==="missing"?"Public Paywall body is missing":"Public Paywall exceeds its byte limit")});if(!Ce(c,s))throw new m("INVALID_RESPONSE","Public Paywall digest or size changed");return Ze(t,JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(c)))})();try{return await Promise.race([l,i])}finally{clearTimeout(g)}}var _e=(e,n)=>new m(e,n);function et(e){return sn(e,_e)}async function De(e,n,{predict:t=!0}={}){let s=n.instruction;if(s?.type!=="evaluate_segment")throw new Error("Local segment instruction required");if(!e)throw new m("CONFIGURATION_UNAVAILABLE","Local execution requires public configuration");if(e.scope.environmentId!==s.environmentId)throw new m("SCOPE_MISMATCH","Evaluation environment changed");let d=null,w;if(t)try{let f=await e.funnel(n.source.id,n.source.versionId);w=f.manifest.generation,d=Nn(e,n,f)}catch{d=null}return w??=e.snapshot?.generation??(await e.refresh()).generation,{advance:{policyRevision:s.policyRevision,generation:w},prediction:d}}function Nn(e,n,t){let s=n.instruction;if(s?.type!=="evaluate_segment"||!t.growth||t.control.evaluationMode!=="local"||t.control.evaluationRevision!==s.policyRevision)return null;let{analyticsConfig:d,remoteFeatures:w,...f}=t.growth,o=rn({scope:{projectId:e.scope.projectId,environment:e.scope.environment},funnelId:n.source.id,versionId:n.source.versionId,evaluationMode:"local",evaluationRevision:s.policyRevision,document:t.document,payload:Re.parse(f)}),g=On(o,t.document,{...n,...s}),i=g.steps.at(-1),l=g.boundary??(i?.result.port==="value"?{nodeId:i.nodeId,visit:n.visit+g.steps.length-1}:null);return l?{runId:n.id,from:{nodeId:n.nodeId,visit:n.visit,revision:n.revision},nodeId:l.nodeId,visit:l.visit,terminal:!g.boundary}:null}function On(e,n,t){return un(e,n,t,_e)}import{z as j}from"zod";var wn=Q.refine(e=>!["start","get","review"].includes(e.operation)&&!("customerToken"in e),"Persist only the original mutation, without credentials").transform(e=>{if(e.operation==="start"||e.operation==="get"||e.operation==="review")throw new m("COMMAND_STORAGE_INVALID","Stored mutation required");return e}),In=j.strictObject({schemaVersion:j.literal(1),scope:qe,runId:j.uuid(),funnelId:j.uuid(),versionId:j.uuid(),processBindingIds:j.record(j.uuid(),j.uuid().nullable()).optional(),command:wn.optional(),closeCommand:wn.refine(e=>e.operation==="close").optional(),purchase:j.strictObject({receiptId:j.uuid(),operationId:j.uuid(),generation:j.number().int().nonnegative()}).optional(),closed:j.literal(!0).optional()}).refine(e=>!e.closeCommand||e.command&&e.command.operation!=="close"&&e.command.requestId!==e.closeCommand.requestId,"Close requires a separate request identity").refine(e=>e.command!==void 0||e.purchase!==void 0,"A recovery record requires an original obligation"),U=()=>new m("COMMAND_STORAGE_CONFLICT","Another host changed this Run's pending command"),Se=(e,n)=>JSON.stringify(e)===JSON.stringify(n);function hn(e){let n=0,t=null,s=i=>JSON.stringify([i.scope,i.runId,i.funnelId,i.versionId]),d=Promise.resolve();async function w(){let i=await e.read();if(!Number.isSafeInteger(i.revision)||i.revision<0)throw new m("COMMAND_STORAGE_INVALID","Invalid command storage revision");return{revision:i.revision,entry:i.entry===null?null:In.parse(i.entry)}}function f(i){let l=d.then(i);return d=l.catch(()=>{}),l}async function o(i){for(let l=0;l<4;l++){let u=await w();if(u.entry&&t!==null&&s(u.entry)!==t)throw U();let c=i(u.entry,u.revision);if(Se(u.entry,c)){n=u.revision;return}let h=await e.write(u.revision,c);if(h!==null){if(!Number.isSafeInteger(h)||h<=u.revision)throw U();n=h;return}}throw U()}function g(i,l){if(!i||!l)return i;if(i.processBindingIds&&Object.hasOwn(i.processBindingIds,l)){let u={...i.processBindingIds};delete u[l],i={...i,processBindingIds:u}}return i.command?.requestId===l?i.closeCommand?{...i,command:i.closeCommand,closeCommand:void 0}:i.purchase?{...i,command:void 0}:null:i.closeCommand?.requestId===l?{...i,closeCommand:void 0}:i}return{bind(i){let l=JSON.stringify([i.scope,i.runId,i.funnelId,i.versionId]);if(t!==null&&t!==l)throw U();t=l},async load(){let i=await w();return n=i.revision,t=i.entry?s(i.entry):null,i.entry},retain(i){let l=In.parse(i),u=l.command;return!u||t!==null&&s(l)!==t?Promise.reject(U()):(t??=s(l),f(()=>o((c,h)=>{if(c&&!Se(s(c),s(l)))throw U();if(c&&l.processBindingIds){for(let[F,N]of Object.entries(l.processBindingIds))if(c.processBindingIds&&Object.hasOwn(c.processBindingIds,F)&&c.processBindingIds[F]!==N)throw U();c={...c,processBindingIds:{...c.processBindingIds,...l.processBindingIds}}}if(!c){if(h!==n&&u.operation!=="close")throw U();return l}if(!c.command)return{...c,command:u,...u.operation==="close"?{closed:!0}:{}};if(u.operation==="close"&&c.command.operation!=="close"){if(c.command.requestId===u.requestId||c.closeCommand&&!Se(c.closeCommand,u))throw U();return{...c,closeCommand:u,closed:!0}}if(!Se(c.command,u))throw U();return c})))},observePurchase(i,l,u,c){return f(()=>o((h,F)=>{if(!h&&F!==n||h&&s(h)!==s({...i,schemaVersion:1}))throw U();if(h?.purchase&&h.purchase.generation>l.generation)return g(h,c);if(h?.purchase&&h.purchase.generation===l.generation&&h.purchase.operationId!==l.operationId)throw U();return u?!h?.purchase||h.purchase.operationId!==l.operationId?g(h,c):g(h.command?{...h,purchase:void 0}:null,c):g({schemaVersion:1,...i,...h,purchase:l},c)}))},settle(i){return f(()=>o(l=>g(l,i)))}}}function ct(e,n){return n.type==="id"?e.customerId===n.value:e.externalUserId===n.value}function ce(e,n){if(e===n)return!0;if(Array.isArray(e)||Array.isArray(n))return Array.isArray(e)&&Array.isArray(n)&&e.length===n.length&&e.every((d,w)=>ce(d,n[w]));if(!e||!n||typeof e!="object"||typeof n!="object")return!1;let t=Object.entries(e),s=Object.entries(n);return t.length===s.length&&t.every(([d,w])=>Object.hasOwn(n,d)&&ce(w,Reflect.get(n,d)))}function vn(e,n){let t=n&&{...n},s=null,d=0,w=new AbortController;function f(){d++,w.abort(new m("IDENTITY_CHANGED","Run identity changed")),w=new AbortController}let o=!1,g,i=0,l=new Set;return{get scope(){return t},bindScope(u){if(t&&(t.projectId!==u.projectId||t.environment!==u.environment))throw new m("SCOPE_MISMATCH","Run scope changed");t??={...u}},get view(){return s},get generation(){return d},get signal(){return w.signal},get disposed(){return o},get customerToken(){return g},get readSequence(){return i},nextRead(){return++i},assertCurrent(u,c="Run identity changed during the request"){if(u!==d||o)throw new m("IDENTITY_CHANGED",c)},assertRun(u){if(s&&(u.id!==s.id||u.source.type!==s.source.type||u.source.id!==s.source.id||u.source.versionId!==s.source.versionId||u.locale!==s.locale||!ce(u.parameters,s.parameters)))throw new m("INVALID_RESPONSE","Run version changed");if(e&&u.source.id!==e)throw new m("INVALID_RESPONSE","Run belongs to another Funnel")},publish(u,c,h,F,N){if(!(u.operation==="review"&&s&&s!==h&&c.run.revision<=s.revision)&&!(s&&c.run.revision===s.revision&&F!==void 0&&F<i)&&(u.operation==="review"&&!c.run.stopped&&["running","waiting"].includes(c.run.status)&&s&&c.run.nodeId===s.nodeId&&c.run.visit===s.visit&&c.run.revision===s.revision&&(c.run.screen=s.screen,(s.paywall?.quote?.operationId===c.review?.activeOperationId||!s.paywall?.quote&&c.review?.activeOperationId===null)&&(c.run.paywall=s.paywall)),!(s?.paywall&&c.run.paywall&&s.paywall.receiptId===c.run.paywall.receiptId&&(c.run.paywall.selectionGeneration??0)<(s.paywall.selectionGeneration??0)))){if(!s||c.run.revision>=s.revision)s=c.run;else if(!N)return;if(s)for(let L of l)try{L(structuredClone(s))}catch{}}},identify(u){if(o)throw new m("IDENTITY_CHANGED","Controller was reset");if(!ue.test(u))throw new m("INVALID_TOKEN","Customer credential required");f(),g=u},subscribe(u){return l.add(u),()=>l.delete(u)},reset(){o||(o=!0,f(),g=void 0,s=null,l.clear())}}}var re=/^gg_sk_[A-Za-z0-9_-]{32,128}$/;function wt(e,n,t="A server API key is required"){if(typeof window<"u")throw new m("SERVER_ONLY",n);if(!re.test(e))throw new m("INVALID_TOKEN",t)}function It(e){let n=Y(e);return n.identify(e.apiKey),n}function $(e){let{customerToken:n,...t}=e;return t}var Tn=e=>!(e instanceof m)||e.status===void 0||e.status>=500||[401,425].includes(e.status)||e.recovery==="recover_operation";function Rn({journal:e,state:n,call:t,processIdentity:s}){let d=null,w=null,f=!1,o={command:null,close:null},g=new Set,i,l=null,u=e?e.load().then(a=>{if(n.disposed)throw new m("IDENTITY_CHANGED","Controller was reset during command restoration");if(l=a,!a)return;if(s){if([a.command,a.closeCommand].some(p=>p&&!Object.hasOwn(a.processBindingIds??{},p.requestId)))throw new m("COMMAND_STORAGE_INVALID","The original process identity is missing");s.restore(a.processBindingIds??{})}if(n.scope&&(a.scope.projectId!==n.scope.projectId||a.scope.environment!==n.scope.environment))throw new m("SCOPE_MISMATCH","Pending command belongs to another scope");if(i=a.purchase,f=a.closed===!0,!a.command)return;let r=a.command;d=r.operation==="close"?null:r,w=r.operation==="close"?r:a.closeCommand?.operation==="close"?a.closeCommand:null,w&&(f=!0);for(let p of[d,w])p&&g.add(p.requestId)}):Promise.resolve();u.catch(()=>{});async function c(a){e&&await u;let r=n.generation;if(e){if(!n.view||!n.scope)throw new m("COMMAND_STORAGE_INVALID","Read the original scoped Run before persisting a mutation");await e.retain({schemaVersion:1,scope:n.scope,runId:n.view.id,funnelId:n.view.source.id,versionId:n.view.source.versionId,command:$(a),...s?{processBindingIds:{[a.requestId]:s.binding(a.requestId)}}:{}})}if(r!==n.generation||d!==a&&w!==a)throw new m("IDENTITY_CHANGED","Run changed before command dispatch");let p=g.has(a.requestId);g.add(a.requestId);try{return await t(a)}catch(v){throw r===n.generation&&(d===a||w===a)&&!p&&!Tn(v)&&(e&&await e.settle(a.requestId),r===n.generation&&L(a)),v}}function h(a){let r=Q.parse(a);if(r.operation==="start"||r.operation==="get"||r.operation==="review")throw new m("INVALID_REQUEST","Mutation required");if(f&&r.operation!=="close"){if(d?.requestId===r.requestId)return N(r.requestId);throw new m("COMMAND_PENDING","Close preserves the original recovery record; settle it by identity")}if(r.operation==="close"){if(d?.requestId===r.requestId)throw new m("INVALID_REQUEST","Close requires its own request identity");if(f=!0,w&&JSON.stringify($(w))!==JSON.stringify($(r)))throw new m("COMMAND_PENDING","Retry the original Close");return w??=r,o.close?o.close:F(w,"close")}if(d){if(JSON.stringify($(d))!==JSON.stringify($(r)))throw new m("COMMAND_PENDING","Retry the original command before sending another");if(o.command)return o.command}else d=r;return F(d,"command")}function F(a,r){let p=c(a);o[r]=p;let v=()=>{o[r]===p&&(o[r]=null)};return p.then(v,v),p}function N(a){return t({operation:"get",settlementRequestId:a})}function L(a){return!a||d!==a&&w!==a?!1:(d===a&&(d=null),w===a&&(w=null),g.delete(a.requestId),!d&&!w&&(l=null),!0)}return{ready:u,get pending(){return d},get closing(){return w},get closeRequested(){return f},get inFlight(){return o.command},get closeFlight(){return o.close},get purchase(){return i},assertBinding(a){if(l&&(a.run.id!==l.runId||a.run.source.id!==l.funnelId||a.run.source.versionId!==l.versionId))throw new m("SCOPE_MISMATCH","Stored command belongs to another Run or Version")},async observe(a,r,p,v){let C=a.operation==="get"?a.settlementRequestId:"requestId"in a&&a.operation!=="start"?a.requestId:void 0,S=C&&r.settlement?.state==="settled"&&r.run.pendingRequest?.requestId!==C&&(a.operation==="get"||!f||a.operation==="close"||!["running","waiting"].includes(r.run.status))?C:void 0,R=d?.requestId===S?d:w?.requestId===S?w:void 0;e?.bind({scope:r.scope,runId:r.run.id,funnelId:r.run.source.id,versionId:r.run.source.versionId});let O=r.run.paywall,D=O??r.purchase,x=D?.operation,k=r.settlement&&(!O||O.purchaseRequestId===r.settlement.requestId)&&(!i||i.operationId===r.settlement.operationId)?r.settlement:void 0,G=x?.operationId??D?.quote?.operationId??k?.operationId,H=D?.receiptId??k?.receiptId,de=O?.selectionGeneration??i?.generation??0;if(e&&G&&H&&a.operation!=="review"&&(!n.view||r.run.revision>=n.view.revision)&&(v===void 0||v>=n.readSequence)&&(!i||de>=i.generation)){let Z={receiptId:H,operationId:G,generation:de},fe=x?.status==="complete"||D?.canReselect===!0;await e.observePurchase({scope:r.scope,runId:r.run.id,funnelId:r.run.source.id,versionId:r.run.source.versionId},Z,fe,S),n.assertCurrent(p),(!i||Z.generation>=i.generation)&&(v===void 0||v>=n.readSequence)&&(fe?i?.operationId===Z.operationId&&(i=void 0):i=Z)}else e&&S&&await e.settle(S);return n.assertCurrent(p),S?L(R):!1},stop(){f=!0},submit:h,settle:N,reset(){f=!0,d=null,w=null,i=void 0,l=null,o.close=null,g.clear(),o.command=null}}}function Cn(e){if(e={...e},typeof e.runToken!="string"||!/^gg_fr_[A-Za-z0-9_-]{43}$/.test(e.runToken))throw new m("INVALID_TOKEN","Run credential required");if(e.serverKey&&(typeof window<"u"||!re.test(e.serverKey)))throw new m("SERVER_ONLY","Run Server-Key proof belongs to the merchant backend");if(e.serverKey&&e.session)throw new m("INVALID_REQUEST","Choose Customer session or Server-Key proof for this Run");let n=Y({...e,session:void 0,timeoutMs:e.timeoutMs??35e3}),t=vn(e.funnelId,e.scope??e.configuration?.scope),s=e.session?.subscribeIdentity(i),d=null,w=e.funnelCommandStorage??(typeof window<"u"&&window.isSecureContext?yn(e):void 0),f=w&&hn(w),o=Rn({journal:f,state:t,call:l,processIdentity:e.process});async function g(r){if(e.process)return e.process.request(r);let p=t.generation;t.assertCurrent(p);let v=performance.now()+(e.timeoutMs??35e3),C=t.customerToken??("customerToken"in r?r.customerToken:void 0);if(e.session){let O=t.signal,D,x=()=>{},k=new Promise((G,H)=>{x=()=>H(O.reason),O.addEventListener("abort",x,{once:!0}),D=setTimeout(()=>H(new m("TIMEOUT","Longplay request timed out")),Math.max(1,v-performance.now()))});try{C=await Promise.race([Promise.resolve().then(()=>(t.assertCurrent(p),e.session.access())),k])}finally{clearTimeout(D),O.removeEventListener("abort",x)}}t.assertCurrent(p);let S={...r,...C?{customerToken:C}:{}},R=r.operation==="page_experiments"?Te.parse(S):Q.parse(S);return n.requestWithCredential("funnels",R,e.runToken,{headers:e.serverKey&&!C?{[nn]:e.serverKey}:void 0,timeoutMs:Math.max(1,v-performance.now())})}function i(){s?.(),t.reset(),o.reset(),d=null,n.dispose()}async function l(r,p){let v=t.generation,C=()=>t.assertCurrent(v);f&&await o.ready,C();let S=t.view,R=be(e,await g(r));if(r.operation==="review"&&!R.review)throw new m("INVALID_RESPONSE","Historical projection is missing");if(C(),R.runToken&&R.runToken!==e.runToken)throw new m("INVALID_RESPONSE","Run credential changed");let O=r.operation==="get"?r.settlementRequestId:"requestId"in r&&r.operation!=="start"?r.requestId:void 0;if(O&&R.settlement?.requestId!==O)throw new m("INVALID_RESPONSE","Exact command settlement is missing or belongs to another command");o.assertBinding(R),t.assertRun(R.run),t.bindScope(R.scope);let D=await o.observe(r,R,v,p);return!R.run.stopped&&["running","waiting"].includes(R.run.status)&&r.operation==="get"&&r.settlementRequestId||(C(),["running","waiting"].includes(R.run.status)||o.stop(),t.publish(r,R,S,p,D)),R}let u=o.submit,c=null,h=new WeakMap;function F(r){let p=h.get(r);if(p)return p;let v=L(r);return h.set(r,v),v}let N=!1;async function L(r){let p=await r;if(p.run.instruction?.type!=="evaluate_segment")return p;if(c)return c;N=!0;let v=t.generation,C=(async()=>{for(let S=0;S<32&&p.run.instruction?.type==="evaluate_segment";S++){if(o.pending||o.closeRequested)return p;let R=p.run;if(p.run.instruction?.type==="evaluate_segment"){let{advance:D}=await De(e.configuration,R,{predict:!1});if(v!==t.generation)throw new m("IDENTITY_CHANGED","Run identity changed during segment calculation");if(o.pending||o.closeRequested)return p;if(t.view&&(t.view.revision!==R.revision||t.view.visit!==R.visit||t.view.nodeId!==R.nodeId))return l({operation:"get"});let x=!0;De(e.configuration,R).then(({prediction:k})=>{x&&v===t.generation&&!o.closeRequested&&t.view?.id===R.id&&!t.view.stopped&&t.view.nodeId===R.nodeId&&t.view.visit===R.visit&&t.view.revision===R.revision&&(d=k)}).catch(()=>{});try{p=await u({operation:"commit_segment",requestId:Xe(R.id,R.visit,`segment:${R.revision}`),nodeId:R.nodeId,visit:R.visit,revision:R.revision,...D})}finally{x=!1,d=null}}}return p})();c=C;try{return await C}finally{c===C&&(c=null)}}let a={get configuration(){return N?e.configuration:void 0},get configurationReady(){return!0},get view(){return t.view?structuredClone(t.view):null},get pendingCommand(){let r=o.closing??o.pending;return r?structuredClone($(r)):null},get pendingCommands(){return[o.pending,o.closing].filter(r=>r!==null).map(r=>structuredClone($(r)))},get pendingPurchase(){return o.purchase?structuredClone(o.purchase):null},get hasDurableJournal(){return f!==void 0},get prediction(){let r=t.view;return d&&r&&!r.stopped&&["running","waiting"].includes(r.status)&&r.id===d.runId&&r.nodeId===d.from.nodeId&&r.visit===d.from.visit&&r.revision===d.from.revision&&!o.closeRequested?structuredClone(d):null},settle:o.settle,get webViewUrl(){return"bundled"},resolvePaywall(r){return Pe(e,r)},async pageExperiments(r,p=[]){let v=t.generation;t.assertCurrent(v);let C=t.view?.id;if(!C)throw new m("INVALID_REQUEST","Read the Run before its page experiments");let S=tn.parse(await g(Te.parse({operation:"page_experiments",release:r,usedReceiptIds:p})));if(t.assertCurrent(v),S.runId!==C||S.scope.projectId!==t.scope?.projectId||S.scope.environment!==t.scope?.environment)throw new m("SCOPE_MISMATCH","Page experiment Run changed");return S},review(r){return l({operation:"review",...r?{receiptId:r}:{}},t.nextRead())},async get(r,p){f&&await o.ready,p??=o.purchase&&{receiptId:o.purchase.receiptId,operationId:o.purchase.operationId};let v=t.nextRead();return F(l({operation:"get",...r?{data:r}:{},...p?{purchase:p}:{}},v))},resume(r=t.view?.pendingRequest?.requestId){return r?o.closeRequested?a.settle(r):o.pending?.requestId===r?F(u(o.pending)):F(u({operation:"resume",requestId:r})):Promise.reject(new m("INVALID_REQUEST","No interrupted command is available"))},submit(r){return F(u(r))},retry(){return o.closeFlight?o.closeFlight:o.closing?u(o.closing):o.closeRequested&&o.pending?a.settle(o.pending.requestId):o.inFlight?F(o.inFlight):o.pending?F(u(o.pending)):Promise.reject(new m("INVALID_REQUEST","No command is pending"))},identify(r){t.identify(r),d=null,n.reset()},subscribe:t.subscribe,reset:i};return a}import{ZodError as _n}from"zod";function bn(e,n,t,s){try{return e.parse(n)}catch(d){throw s&&d instanceof _n?new m(t,s):d}}async function Ee(e,n,t,s={},d){let w=typeof s=="function"?{}:s,f=bn(n.request,t,"INVALID_REQUEST",w.request);try{let o=await e(n.path,f,n.method,d),g=typeof s=="function"?s:s.parseResponse;return g?g(n.response,o):bn(n.response,o,"INVALID_RESPONSE",w.response)}catch(o){throw o instanceof m&&f!==null&&typeof f=="object"&&"requestId"in f&&typeof f.requestId=="string"&&(o.commandRequestId??=f.requestId),o}}async function Ht(e,n){if(!ue.test(n.customerToken))throw new m("INVALID_TOKEN","A verified Customer credential is required");if(e.session&&e.session.peek()!==n.customerToken)throw new m("SCOPE_MISMATCH","Paywall credential does not match the shared session");let t=ne.resolvePaywall.request.parse({funnelId:n.funnelId,funnelVersionId:n.funnelVersionId,selector:n.paywallVersionId?{type:"version",versionId:n.paywallVersionId}:{type:"paywall",paywallId:n.paywallId},commerce:n.commerce,locale:n.locale,...n.requirement?{requirement:n.requirement}:{}}),s=Y(e);e.session||s.identify(n.customerToken);let d=null,w=!1,f=null,o=null,g=null,i=null,l=null,u=null,c=null,h=0;function F(){if(w)throw new m("IDENTITY_CHANGED","Paywall is closed")}async function N(){F();let p=ne.resolvePaywall,v=await Ee(s.request,p,{...t,selector:d?{type:"version",versionId:d.id}:t.selector}),C=await Pe(e,v.paywall);if(F(),n.paywallVersionId?C.id!==n.paywallVersionId:C.paywallId!==n.paywallId)throw new m("INVALID_RESPONSE","The requested Paywall changed");if(d&&(!dn(C,d)||C.paywallId!==d.paywallId))throw new m("INVALID_RESPONSE","The pinned Paywall or Offering Version changed");return d=C,structuredClone(d)}async function L(p){if(F(),i&&p!=="read")throw new m("COMMAND_PENDING","Wait for the original quote");if(!f)throw new m("INVALID_REQUEST","A quoted purchase is required");let v=f;if(p!=="read"){if(c){if(u===p)return c;throw new m("COMMAND_PENDING","Wait for the original purchase command")}if(u&&u!==p)throw new m("COMMAND_PENDING","Read the original purchase before changing an uncertain command");u=p,h++}let C=u,S=h,R=p==="read"&&c===null,O=p==="read"?ne.readSubscriptionOperation:ne.attach,D=(async()=>{let x=await Ee(s.request,O,{operationId:v.operationId,...p==="read"?{}:{intent:p}});return fn(x.operation,{operationId:v.operationId,currency:t.commerce.currency},"The purchase operation changed"),F(),f?.operationId!==v.operationId?structuredClone(x.operation):(o=pn(o,x.operation),(p!=="read"||R&&c===null)&&h===S&&u===C&&(u=null),structuredClone(o))})();if(p!=="read"){c=D;let x=()=>{c===D&&(c=null)};D.then(x,x)}return D}let a={get view(){return d?structuredClone(d):null},get quote(){return f?structuredClone(f):null},get operation(){return o?structuredClone(o):null},get webViewUrl(){return"bundled"},get recovery(){return gn({quote:f,operation:o,requestId:l,pending:i!==null||u!==null,destroyed:w})},get pendingCancellation(){return!w&&u==="cancel"},refresh:N,async preview(p){if(F(),!d)throw new m("INVALID_REQUEST","Load the Paywall first");let v=d.document.buttons[p.actionId];if(v?.type!=="checkout")throw new m("INVALID_REQUEST","Choose an authored purchase action");let C=Ge(v.product,p.selection,d.capabilities);if(!C)throw new m("PRODUCT_UNAVAILABLE","Choose an available Product");let S=He(d.document.screen,C,p.selection,d.capabilities),R=ne.previewAttach.request.parse({funnelId:t.funnelId,funnelVersionId:t.funnelVersionId,requestId:p.requestId,plans:[{productVersionId:C,...Object.keys(S).length?{featureQuantities:S}:{}}],provider:t.commerce.provider,currency:t.commerce.currency,...p.offerId?{offerId:p.offerId}:{},...p.nativeOffer?{nativeOffer:p.nativeOffer}:{}}),O=JSON.stringify(R);if(g&&g!==O&&(i||u||!o||o.status==="pending"))throw new m("COMMAND_PENDING","Finish or cancel the original purchase before changing it");if(g===O){if(i)return i;if(f)return structuredClone(f)}g!==O&&(f=null,o=null),g=O,l=R.requestId;let D=(async()=>{let x=ne.previewAttach,k=await Ee(s.request,x,R);return F(),mn(k.quote,{productVersionId:C,featureQuantities:S,currency:t.commerce.currency,provider:t.commerce.provider},"The purchase quote changed its selected Product or presentment"),f=k.quote,o=null,structuredClone(f)})();i=D;try{return await D}finally{i===D&&(i=null)}},confirm:()=>L("confirm"),cancel:()=>L("cancel"),read:()=>L("read"),destroy(){w||(w=!0,r?.(),s.dispose(),d=null,f=null,o=null,g=null,l=null)}},r=e.session?.subscribeIdentity(a.destroy);try{return await N(),a}catch(p){throw a.destroy(),p}}import{z as Vn}from"zod";import{z as ge}from"zod";var Dn=ge.record(ge.string().regex(/^[a-f0-9]{64}$/),ge.strictObject({at:ge.number(),text:ge.string()})),oe=2*1048576,xn=100;function Ln(){try{return typeof window>"u"?void 0:window.localStorage}catch{return}}function Pn(e,n){let t=n===void 0?Ln():n,s=new Map,d=0,w=!1,f=!1,o,g;async function i(u){if(!t)return null;let c;try{let h=await Promise.race([Promise.resolve().then(()=>t.getItem(u)),new Promise(F=>{c=setTimeout(()=>F(null),xn)})]);return typeof h=="string"&&h.length<=oe&&new TextEncoder().encode(h).byteLength<=oe?h:null}catch{return null}finally{clearTimeout(c)}}function l(){if(g)return g;let u=(async()=>{try{let c=await i(`${e}:artifacts`);if(c)return Dn.parse(JSON.parse(c))}catch{}return{}})();return g=u,u.finally(()=>{g===u&&(g=void 0)}),u}return{async readManifest(){return i(e)},writeManifest(u){!t||u.length>oe||new TextEncoder().encode(u).byteLength>oe||(o=u,!f&&(f=!0,Promise.resolve().then(async()=>{try{for(;o!==void 0;){let c=o;try{await t.setItem(e,c)}catch{}o===c&&(o=void 0)}}finally{f=!1}})))},async readArtifact(u){let c=(await l())[u],h=Date.now();return c&&h>=c.at&&h-c.at<=J.retentionMs?c.text:void 0},writeArtifact(u,c){if(!t||c.length>oe)return;let h=s.get(u);if(h?.text===c||!h&&s.size>=128)return;let F=new TextEncoder().encode(c).byteLength;d-(h?.byteLength??0)+F>oe||(s.set(u,{text:c,byteLength:F}),d+=F-(h?.byteLength??0),!w&&(w=!0,Promise.resolve().then(async()=>{try{for(;s.size;){let N=new Map(s);try{let L={...await l()},a=Date.now();for(let[C,S]of N)L[C]={at:a,text:S.text};let r={},p=2,v=0;for(let[C,S]of Object.entries(L).sort(([,R],[,O])=>O.at-R.at)){if(S.at>a||a-S.at>J.retentionMs)continue;let R=new TextEncoder().encode(JSON.stringify({[C]:S})).byteLength;p+R>oe||v>=128||(r[C]=S,p+=R,v++)}await t.setItem(`${e}:artifacts`,JSON.stringify(r))}catch{}finally{for(let[L,a]of N)s.get(L)===a&&(s.delete(L),d-=a.byteLength)}}}finally{w=!1}})))}}}var E=(e,n)=>new m(e,n),W=()=>performance.now(),Sn=e=>{typeof e=="object"&&"unref"in e&&e.unref()};function rr(e){let n=Ke.parse(e.scope),t=new te(e.origin??le);if(t.username||t.password||t.search||t.hash||t.pathname!=="/"||t.protocol!=="https:"&&!(t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)))throw E("INVALID_URL","Configuration requires a trusted HTTPS origin");let s=new Set([t.origin,...(e.assetOrigins??[]).map(I=>{let y=new te(I);if(y.protocol!=="https:"||y.username||y.password||y.search||y.hash||y.pathname!=="/")throw E("INVALID_URL","Invalid configuration asset origin");return y.origin})]),d=e.fetch??globalThis.fetch.bind(globalThis),w=`/api/v1/configuration/${n.environmentId}`,f=`indiana:configuration:1:${t.origin}:${M(n)}`,o=Pn(f,e.storage),g,i=0,l=0,u=!1,c=!1,h=0,F=0,N,L,a,r,p=0,v=new Set,C=new Set,S=new Map,R=new Map,O=0,D=!1;function x(){for(let I of v)try{I()}catch{}}function k(I){try{e.onError?.(I)}catch{}}let G=()=>!c&&!u&&!!g&&W()<i&&Date.now()<l;function H(){if(!G())throw E("CONFIGURATION_EXPIRED","Refresh configuration before using it")}function de(I,y,b){if(!S.has(I)){for(;S.size&&(S.size>=128||O+b>J.maxCacheBytes);){let P=S.entries().next().value;O-=P[1].byteLength,S.delete(P[0])}S.set(I,{text:y,byteLength:b}),O+=b}}function Z(I,y,b){return cn(I,y,{signal:b,error:P=>E("INVALID_RESPONSE",P==="missing"?"Configuration body is missing":"Configuration exceeds its byte limit")})}function fe(I){let y=new te(I,t);if(!s.has(y.origin)||y.username||y.password||y.hash||y.search)throw E("INVALID_URL","Configuration artifact origin is not trusted");return y.href}async function Fe(I,y,b=!1){let P=await d(fe(I),{method:"GET",credentials:"omit",redirect:"error",cache:b?"default":"no-cache",signal:y,headers:{}});if(P.status===429){let T=P.headers.get("retry-after")??"";p=/^\d+$/.test(T)?Number(T)*1e3:Math.max(0,Date.parse(T)-Date.now())||15e3}if(!P.ok&&P.status!==304)throw E(`CONFIGURATION_HTTP_${P.status}`,"Configuration synchronization failed");return P}function Fn(I,y,b){let P=Date.parse(I.headers.get("x-indiana-config-validated-at")??""),T=Date.parse(I.headers.get("x-indiana-config-valid-until")??""),_=Date.parse(I.headers.get("date")??""),A=I.headers.get("age"),B=A!==null&&/^\d+(\.\d+)?$/.test(A)?Number(A)*1e3:NaN;if(![P,T,_,B].every(Number.isFinite)||T<=P||T-P>J.maxControlAgeMs||P>_+1e3)throw E("INVALID_RESPONSE","Configuration freshness evidence is invalid");let V=Math.min(T-P,b.maxControlAgeSeconds*1e3,J.maxControlAgeMs)-Math.max(B,_-P,0)-(W()-y);if(V<=0)throw E("CONFIGURATION_EXPIRED","Configuration validation expired in transit");return W()+V}function Ae(){if(clearTimeout(a),clearTimeout(r),c||!v.size)return;G()&&(r=setTimeout(()=>{G()?Ae():x()},Math.max(1,i-W())),Sn(r));let I=F?Math.min(15e3,1e3*2**Math.min(F-1,4)):Math.min(15e3,(g?.policy.refreshIntervalSeconds??15)*1e3);a=setTimeout(()=>{ie().catch(k)},Math.max(p,I*(.8+Math.random()*.2))),Sn(a)}async function ie(){if(c)throw E("CONFIGURATION_DISPOSED","Configuration manager was destroyed");if(N)return N;let I=h,y=new AbortController;L=y;let b=(async()=>{if(!D){D=!0;try{let he=await o.readManifest();if(he&&!g){let K=Oe.parse(JSON.parse(he));M(K.scope)===M(n)&&(g=K)}}catch{}}y.signal.throwIfAborted();let A=g,B=W(),q=await Fe(w,y.signal);q.status===304&&(!A||!q.headers.has("x-indiana-config-validated-at")||!q.headers.has("x-indiana-config-valid-until")||!q.headers.has("age"))&&(q=await Fe(w,y.signal));let V=q.status===304?A:Oe.parse(JSON.parse(await Z(q,J.maxManifestBytes,y.signal))),{generation:ae,...se}=V,z=q.headers.get("etag");if(M(V.scope)!==M(n)||Qe(se)!==ae||z!==`"${ae}"`&&z!==`W/"${ae}"`)throw E("INVALID_RESPONSE","Configuration scope or content identity changed");if(A&&(V.revision<A.revision||V.revision===A.revision&&V.generation!==A.generation))throw E("INVALID_RESPONSE","Configuration revision moved backwards or changed identity");for(let[he,K]of Object.entries(A?.funnels??{})){let ee=V.funnels[he];if(ee&&(ee.controlRevision<K.controlRevision||ee.evaluationRevision<K.evaluationRevision||ee.controlRevision===K.controlRevision&&ee.state!==K.state||ee.evaluationRevision===K.evaluationRevision&&ee.evaluationMode!==K.evaluationMode))throw E("INVALID_RESPONSE","Funnel control revision changed identity")}let X=Fn(q,B,V.policy);if(y.signal.throwIfAborted(),I!==h)throw E("CONFIGURATION_DISPOSED","Configuration scope changed");return g=V,i=X,l=Date.now()+Math.max(0,X-W()),u=!1,F=0,p=0,o.writeManifest(M(V)),x(),structuredClone(V)})(),P=setTimeout(()=>y.abort(E("CONFIGURATION_UNAVAILABLE","Configuration initialization timed out")),J.initializationMs),T=new Promise((A,B)=>y.signal.addEventListener("abort",()=>B(y.signal.reason),{once:!0})),_=Promise.race([b,T]).catch(A=>{throw F++,(A instanceof Vn.ZodError||A instanceof SyntaxError||A instanceof m&&["CONFIGURATION_HTTP_404","CONFIGURATION_HTTP_410","INVALID_RESPONSE"].includes(A.code))&&(i=0,u=!0,x()),A}).finally(()=>{clearTimeout(P),N===_&&(N=void 0),Ae()});return N=_,_}async function ye(I){let y=I.sha256,b=se=>Ce(se,I);fe(I.url);let P=S.get(y);if(P){if(P.byteLength!==I.byteLength)throw E("INVALID_RESPONSE","Configuration artifact digest or size mismatch");return S.delete(y),S.set(y,P),P.text}let T=R.get(y);if(T){if(T.byteLength!==I.byteLength)throw E("INVALID_RESPONSE","Configuration artifact digest or size mismatch");return T.promise}let _=new AbortController;C.add(_);let A=h,B=(async()=>{try{let X=await o.readArtifact(y);if(X&&b(X)){if(_.signal.throwIfAborted(),c||A!==h)throw E("CONFIGURATION_DISPOSED","Configuration scope changed");return de(y,X,I.byteLength),X}}catch{}_.signal.throwIfAborted();let se=await Fe(I.url,_.signal,!0),z=await Z(se,I.byteLength,_.signal);if(!b(z))throw E("INVALID_RESPONSE","Configuration artifact digest or size mismatch");if(c||A!==h)throw E("CONFIGURATION_DISPOSED","Configuration scope changed");return de(y,z,I.byteLength),o.writeArtifact(y,z),z})(),q=setTimeout(()=>_.abort(E("CONFIGURATION_UNAVAILABLE","Configuration artifact timed out")),J.initializationMs),V=new Promise((se,z)=>_.signal.addEventListener("abort",()=>z(_.signal.reason),{once:!0})),ae=Promise.race([B,V]).finally(()=>{clearTimeout(q),C.delete(_),R.delete(y)});return R.set(y,{promise:ae,byteLength:I.byteLength}),ae}async function we(){return G()||await ie(),H(),g}async function me(I){let y,b=new Promise((P,T)=>{y=setTimeout(()=>T(E("CONFIGURATION_UNAVAILABLE","Configuration initialization timed out")),J.initializationMs)});try{return await Promise.race([I(),b])}finally{clearTimeout(y)}}function pe(I,y){if(H(),g?.generation!==I.generation)throw E("CONFIGURATION_CHANGED","Configuration changed while preparing a snapshot");if(y&&g.funnels[y]?.state!=="active")throw E("FUNNEL_STOPPED","Funnel is paused or unavailable")}async function xe(I){let y=I.gb.features;if(!y)throw E("CONFIGURATION_UNAVAILABLE","Public Feature delivery is disabled");let b=I.artifacts[y];if(b.formatVersion!==1)throw E("UNSUPPORTED_SCHEMA","Unsupported public GB configuration format");let P=Je.parse(JSON.parse(await ye(b)));if(M(P.scope)!==M({projectId:n.projectId,environment:n.environment})||P.generation!==b.generation||P.remoteFeatures.some(T=>Object.hasOwn(P.features,T)))throw E("INVALID_RESPONSE","Public GB configuration scope or generation is invalid");return pe(I),{...P,evaluatedAt:new Date().toISOString(),expiresAt:new Date(Date.now()+Math.max(0,i-W())).toISOString()}}async function Le(I,y){let b=await we(),P=b.funnels[I];y&&(!P||P.evaluationMode==="local"&&!P.versions[y])&&(N&&await N,b=await ie()),pe(b,I);let T=b.funnels[I];if(T.evaluationMode!=="local")throw E("EVALUATION_MODE","This Funnel executes at Longplay; public graph loading is disabled");let _=y??T.currentVersionId,A=T.versions[_];if(!A)throw E("CONFIGURATION_UNAVAILABLE","Pinned Funnel Version is unavailable");if(b.artifacts[A.artifact].formatVersion!==3)throw E("UNSUPPORTED_SCHEMA","Unsupported public Funnel format");let[B,q]=await Promise.all([ye(b.artifacts[A.artifact]).then(V=>$e(JSON.parse(V))),T.evaluationMode==="local"?xe(b):void 0]);if(q&&M(Ye(B,q))!==M(A.dependencies))throw E("INVALID_RESPONSE","Funnel and GB dependency contract do not match");return pe(b,I),{document:B,growth:q,versionId:_,control:structuredClone(T),manifest:structuredClone(b)}}async function Ve(I,y){try{return await Le(I,y)}catch(b){if(!(b instanceof m)||!(b.code==="CONFIGURATION_CHANGED"||b.code==="CONFIGURATION_HTTP_404"&&G()))throw b;let P=g?.generation;if(N&&await N,await ie(),b.code!=="CONFIGURATION_CHANGED"&&g?.generation===P)throw b;return Le(I,y)}}function Ne(){u=!0,x(),ie().catch(k)}let Ie=()=>{(typeof document>"u"||document.visibilityState==="visible")&&Ne()};function An(I){if(c)throw E("CONFIGURATION_DISPOSED","Configuration manager was destroyed");return v.add(I),v.size===1&&(typeof window<"u"&&(window.addEventListener("online",Ne),window.addEventListener("focus",Ie),document.addEventListener("visibilitychange",Ie)),Ae()),()=>{v.delete(I),v.size||(clearTimeout(a),clearTimeout(r),Me())}}function Me(){typeof window<"u"&&(window.removeEventListener("online",Ne),window.removeEventListener("focus",Ie),document.removeEventListener("visibilitychange",Ie))}return{scope:Object.freeze({...n}),refresh:ie,subscribe:An,assertFresh:H,assertFeatures(I){H();let y=g.gb.features;if(!y)throw E("CONFIGURATION_UNAVAILABLE","Public Feature delivery is disabled");if(I!==void 0&&g.artifacts[y].generation!==I)throw E("CONFIGURATION_CHANGED","Refresh changed Feature configuration before evaluation")},get fresh(){return G()},get snapshot(){return g?structuredClone(g):null},get remainingMs(){return G()?Math.max(0,i-W()):0},async features(){return me(async()=>xe(await we()))},pageExperiments:()=>me(async()=>{let I=await we(),y=I.gb.pageExperiments;if(!y)throw E("CONFIGURATION_UNAVAILABLE","Public page experiments are disabled");let b=I.artifacts[y];if(b.formatVersion!==1)throw E("UNSUPPORTED_SCHEMA","Unsupported page experiment format");let P=an.parse(JSON.parse(await ye(b)));if(P.environmentId!==n.environmentId||P.generation!==b.generation)throw E("INVALID_RESPONSE","Page experiment scope or generation changed");return pe(I),P}),funnel:(I,y)=>me(()=>Ve(I,y)),paywall:(I,y)=>me(async()=>{let b=await we(),P=b.paywalls?.[I];if(!P||!y&&P.state!=="published")throw E("PAYWALL_UNAVAILABLE","Published Paywall is unavailable");let T=y??P.currentVersionId,_=P.versions[T],A=_&&b.artifacts[_.artifact];if(!A||A.kind!=="paywall"||A.formatVersion!==1)throw E("UNSUPPORTED_SCHEMA","Public Paywall format is unavailable");let B=ze.parse(JSON.parse(await ye(A)));return pe(b),{document:B,versionId:T,version:_.version,control:structuredClone(P),manifest:structuredClone(b)}}),async localFunnel(I,y){let b=await me(()=>Ve(I,y));if(!b.growth)throw E("EVALUATION_MODE","This Funnel requires remote execution");let{analyticsConfig:P,remoteFeatures:T,..._}=b.growth;return on({scope:{projectId:n.projectId,environment:n.environment},funnelId:I,versionId:b.versionId,evaluationMode:"local",evaluationRevision:b.control.evaluationRevision,document:b.document,payload:_})},assertFunnel(I,y,b){H();let P=g.funnels[I];if(!P||P.state!=="active")throw E("FUNNEL_STOPPED","Funnel is paused or unavailable");if(P.evaluationMode!=="local")throw E("EVALUATION_MODE","This Funnel now executes at Longplay");if(y!==void 0&&P.controlRevision!==y)throw E("RUN_RECONCILIATION_REQUIRED","Reconcile the original Run after a control change");if(b!==void 0&&!P.versions[b])throw E("CONFIGURATION_UNAVAILABLE","Pinned Funnel Version is unavailable")},destroy(){if(!c){c=!0,h++,i=0,L?.abort(E("CONFIGURATION_DISPOSED","Configuration manager was destroyed")),clearTimeout(a),clearTimeout(r),Me(),x(),v.clear();for(let I of C)I.abort(E("CONFIGURATION_DISPOSED","Configuration manager was destroyed"));S.clear(),O=0}}}}function En(e){let n=ue.test(e.apiKey);if(typeof window<"u"&&!n)throw new m("SERVER_ONLY","Funnel starts are issued by your backend");if(!n&&!re.test(e.apiKey))throw new m("INVALID_TOKEN","A customer credential or server API key is required");return{async start(t){let s=Q.safeParse({...t,operation:"start"});if(!s.success||s.data.operation!=="start"||(n?s.data.customer!==void 0:s.data.customer===void 0))throw new m("INVALID_REQUEST","Invalid current Funnel start");let d=s.data,w=Y({...e,timeoutMs:e.timeoutMs??35e3});try{e.session||w.identify(e.apiKey);let f=be(e,await w.request("funnels",d));if(!f.runToken)throw new m("INVALID_RESPONSE","Funnel start credentials are missing");if(f.run.source.id!==d.funnelId||f.run.locale!==(d.locale??"en")||!ce(f.run.parameters,d.parameters??{})||(d.customer?!f.customerId||d.customer.type==="id"&&f.customerId!==d.customer.value:f.customerId!==void 0))throw new m("INVALID_RESPONSE","Funnel start contract changed");return{...f,runToken:f.runToken}}finally{w.dispose()}}}}async function yr(e){e={...e};let n=e.configuration;if(!n)throw new m("CONFIGURATION_UNAVAILABLE","Local conditions require public configuration");let t={projectId:n.scope.projectId,environment:n.scope.environment};if(e.scope&&M(t)!==M(e.scope))throw new m("SCOPE_MISMATCH","Configuration and transport scopes differ");if((await n.funnel(e.funnelId)).control.evaluationMode!=="local")throw new m("EVALUATION_MODE","This Funnel uses Remote evaluation");let d=re.test(e.credential);if(d?!e.customerId:e.customerId!==void 0)throw new m("INVALID_REQUEST","Only Server-Key starts name their Customer");let w=En({...e,scope:t,apiKey:e.credential}),f=o=>{let g=Cn({...e,scope:t,runToken:o,...d?{serverKey:e.credential}:{}});return d||g.identify(e.credential),g};return{async start(o){let g=await w.start({...o,funnelId:e.funnelId,...d?{customer:{type:"id",value:e.customerId}}:{}}),i=f(g.runToken),l=await i.get();return{...g,...l,controller:i}},async restore(o){let g=f(o),i=await g.get();if(i.run.source.id!==e.funnelId)throw g.reset(),new m("SCOPE_MISMATCH","Run belongs to another Funnel");return{...i,runToken:o,controller:g}}}}export{Ee as a,qn as b,be as c,_e as d,et as e,On as f,yn as g,ct as h,ce as i,wt as j,It as k,Cn as l,Ht as m,rr as n,En as o,yr as p};
|