@tinkerlandai/indiana-sdk 0.3.0 → 0.3.1
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 +5 -0
- package/README.md +51 -50
- package/README.zh-CN.md +149 -0
- package/dist/chunk-CRJJ4EA2.js +1 -0
- package/dist/{chunk-PTWRGCVW.js → chunk-G5ZGWOLJ.js} +1 -1
- package/dist/{funnel-runtime-host-OVCJIQRT.js → funnel-runtime-host-X7AGEGHN.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/openrouter.js +1 -1
- package/dist/{paywall-4JTI7QAB.js → paywall-Y3FIG43H.js} +1 -1
- package/dist/popup.js +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-X5UXOLOU.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Release facts and artifact evidence: [SDK release ledger](../../docs/sdk-releases.md). Earlier personal-package versions are preserved in [@houzhen888/groove-grow history](../../docs/sdk-changelog-groove-grow.md). The two packages have independent version histories.
|
|
4
4
|
|
|
5
|
+
## 0.3.1 — 2026-10-17
|
|
6
|
+
|
|
7
|
+
- Make English the default package README and include a separately linked Simplified Chinese translation.
|
|
8
|
+
- Update the package and SDK request version identifiers to 0.3.1; wire protocol 0.3 and business behavior are unchanged from the immutable 0.3.0 release.
|
|
9
|
+
|
|
5
10
|
## 0.3.0
|
|
6
11
|
|
|
7
12
|
- 0.3.0 uses wire protocol 0.3 for published screen render references. Obsolete 0.2 and its fixed headerless identity are explicitly refused before business execution; no pre-1.0 compatibility adapter is provided. Existing 0.2.0 publication evidence remains immutable.
|
package/README.md
CHANGED
|
@@ -1,33 +1,35 @@
|
|
|
1
1
|
# @tinkerlandai/indiana-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[简体中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Indiana's JavaScript and TypeScript SDK for browsers, Node.js, screen rendering, and optional AI usage integrations. Version `0.3.1` uses protocol `0.3` and requires a matching Indiana server and database deployment.
|
|
6
|
+
|
|
7
|
+
Protocol `0.3` includes standalone Feature delivery, screen render references, and protocol header validation. Historical `0.2` clients, including requests without a protocol header, are rejected before business operations run.
|
|
6
8
|
|
|
7
9
|
```sh
|
|
8
|
-
npm install @tinkerlandai/indiana-sdk@0.3.
|
|
10
|
+
npm install @tinkerlandai/indiana-sdk@0.3.1
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Version compatibility and support
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
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://tinker.cash/docs/release-notes#support-policy).
|
|
14
16
|
|
|
15
|
-
0.3.
|
|
17
|
+
Version `0.3.1` sends protocol and SDK version headers and validates the protocol declared by successful responses. Headerless historical clients retain the fixed identity `0.2`; they do not follow the current protocol automatically. Updating source code does not change an existing npm artifact or deploy a server.
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## One package, six entry points
|
|
18
20
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
| `@tinkerlandai/indiana-sdk`
|
|
22
|
-
| `@tinkerlandai/indiana-sdk/server`
|
|
23
|
-
| `@tinkerlandai/indiana-sdk/popup`
|
|
24
|
-
| `@tinkerlandai/indiana-sdk/openrouter`
|
|
25
|
-
| `@tinkerlandai/indiana-sdk/native-shell` |
|
|
26
|
-
| `@tinkerlandai/indiana-sdk/page`
|
|
21
|
+
| Import | Purpose |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `@tinkerlandai/indiana-sdk` | Browser Customer, Funnel, Feature, and standalone Paywall clients |
|
|
24
|
+
| `@tinkerlandai/indiana-sdk/server` | Trusted Node.js backend, Customer Sessions, business writes, and Funnel decisions |
|
|
25
|
+
| `@tinkerlandai/indiana-sdk/popup` | Standalone screen rendering, sanitization, and previews |
|
|
26
|
+
| `@tinkerlandai/indiana-sdk/openrouter` | Optional OpenRouter usage integration; requires its peer dependency |
|
|
27
|
+
| `@tinkerlandai/indiana-sdk/native-shell` | Static Funnel shell assets for native WebViews |
|
|
28
|
+
| `@tinkerlandai/indiana-sdk/page` | Anonymous website URL experiments using a public App environment ID |
|
|
27
29
|
|
|
28
|
-
JavaScript
|
|
30
|
+
The same package supports JavaScript and TypeScript and includes type declarations. Internal `@indiana/contracts` code is bundled; consumers do not install private workspace packages. Swift and Kotlin use their own package ecosystems and are released separately.
|
|
29
31
|
|
|
30
|
-
##
|
|
32
|
+
## Create a Customer Session from a trusted backend
|
|
31
33
|
|
|
32
34
|
```ts
|
|
33
35
|
import { createIndianaServer } from "@tinkerlandai/indiana-sdk/server";
|
|
@@ -47,7 +49,7 @@ const { customer } = await indiana.getOrCreateCustomer({
|
|
|
47
49
|
const { customerToken } = await indiana.createCustomerSession(customer.id);
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
Secret Key
|
|
52
|
+
Keep the Secret Key on your trusted backend. A Customer ID supplied by a browser is not proof of login. Give each Customer Token only to the corresponding authenticated user. App, Sandbox/Live environment, Customer identity, permissions, and allowed origins are checked independently. The SDK holds Customer credentials in memory; destroy the previous view and clear credentials when signing out or changing accounts.
|
|
51
53
|
|
|
52
54
|
```ts
|
|
53
55
|
import { createIndiana } from "@tinkerlandai/indiana-sdk";
|
|
@@ -58,25 +60,24 @@ const indiana = createIndiana({
|
|
|
58
60
|
});
|
|
59
61
|
indiana.identify(customerToken);
|
|
60
62
|
const { holdings } = await indiana.readHoldings();
|
|
61
|
-
//
|
|
63
|
+
// On sign-out:
|
|
62
64
|
indiana.reset();
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
Customer
|
|
67
|
+
Customer updates are partial patches and do not use a Customer revision. When a Guest signs in to an existing Customer, the response reports `switched: true`. Resources and history keep their original owner; create a new Session/Funnel for the target Customer. Guest financial facts are not merged.
|
|
66
68
|
|
|
67
69
|
## Optional stable fingerprint
|
|
68
70
|
|
|
69
71
|
`fingerprint` is a host-supplied stable deduplication signal, such as an installation identifier. Initialize and retain it before the first Guest/Customer request, independently of login and credentials. Reuse it across Guest identification, account changes and session renewal. The SDK does not collect or generate it.
|
|
70
72
|
|
|
71
73
|
```ts
|
|
72
|
-
// Trusted backend
|
|
73
|
-
// verifiedUser.id comes from
|
|
74
|
+
// Trusted backend: retain installationSignal independently of login.
|
|
75
|
+
// verifiedUser.id comes from your application's authenticated session.
|
|
74
76
|
const { customer } = await indiana.getOrCreateCustomer({
|
|
75
77
|
externalUserId: verifiedUser.id,
|
|
76
78
|
fingerprint: installationSignal,
|
|
77
79
|
});
|
|
78
|
-
//
|
|
79
|
-
// retain/reuse guestToken for creation retries.
|
|
80
|
+
// Reuse the signal on Guest creation. Retain guestToken separately for retries.
|
|
80
81
|
await indiana.createGuestCustomer({
|
|
81
82
|
guestToken: retainedGuestToken,
|
|
82
83
|
fingerprint: installationSignal,
|
|
@@ -85,23 +86,23 @@ await indiana.createGuestCustomer({
|
|
|
85
86
|
|
|
86
87
|
Indiana keeps the first supplied signal as an environment-scoped hash; later values do not replace it. Missing input is valid and retains per-Customer trial deduplication. `unique_fingerprint` additionally deduplicates the configured Product trial across Customers sharing the signal. Business user IDs do not identify an installation; Customer/Guest/session tokens and request IDs have their own lifecycles and should not be fingerprints.
|
|
87
88
|
|
|
88
|
-
On Web, an independent first-party installation cookie can retain the signal. Clearing it or changing browser storage can produce a new value; sign-out need not reset it. Native hosts persist a random installation signal and define reinstall, restore and reset behavior. This signal is separate from device attestation and authentication. See the
|
|
89
|
+
On Web, an independent first-party installation cookie can retain the signal. Clearing it or changing browser storage can produce a new value; sign-out need not reset it. Native hosts persist a random installation signal and define reinstall, restore and reset behavior. This signal is separate from device attestation and authentication. See the [identity guide](https://tinker.cash/docs/identity#fingerprint) for HTTP host examples. Trial conflicts remain generic to clients; retain `X-Request-Id` for server-side diagnosis.
|
|
89
90
|
|
|
90
|
-
## Funnel
|
|
91
|
+
## Funnel, Feature, and standalone Paywall
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
A trusted backend calls `createFunnelStartClient().start()` with `funnelId`, a retained `requestId`, `customer`, `locale`, and `parameters`. The Customer reference is `{ type: "id", value: customerId }` or `{ type: "externalUserId", value: verifiedUser.id }`. The latter supports creation-only `customerData` and requires `customers:write`; an existing Customer is not updated. The response includes `customerId`, which your backend can use to issue a Customer Session. Historical start-body `customerToken` and decision-body `customerId` inputs are rejected.
|
|
93
94
|
|
|
94
|
-
`createFunnelClient({ customerToken, ...options })`
|
|
95
|
+
`createFunnelClient({ customerToken, ...options })` is for clients that already hold a Customer credential. Its `start()` omits `customer` and `customerData` and runs as the credential's Customer. After response loss, retry with the same request ID and input. Put commercial parameters in `parameters.commerce`. Each Run has its own Run Token, which cannot switch Customer identity.
|
|
95
96
|
|
|
96
|
-
`createFunnelDecisionClient
|
|
97
|
+
`createFunnelDecisionClient.submit/decide` and the server entry's `createFunnelCampaignClient` use the same explicit Customer reference. Campaign `decide/start` operations report durable frequency or active-Run suppression as `suppressed` with a retry time. Report `shown` only after the Run is actually displayed; page closure or local storage cannot replace a durable presentation fact.
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
In a browser, use `createFunnelRunController` and `showFunnelRun`. The controller handles current-protocol commands, reads, retries, recovery, and subscriptions. Presentation handles provide `refresh()` and `destroy()`. Published nodes delegate business operations to the server. A client assertion or redirect is not payment evidence.
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
Each Funnel chooses local or remote evaluation. `createFunnelDecisionClient` supports `configuration()`, `features()`, submission, and result reads. `createFeatureClient` identifies configuration by `generation`. Downloaded local rules are visible to clients; use remote evaluation and verified business facts for sensitive decisions.
|
|
101
102
|
|
|
102
|
-
###
|
|
103
|
+
### Standalone Feature delivery
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
Explicitly grant a backend Key `features:read` / `events:write` and issue existing Customer/Guest Sessions to browser clients.
|
|
105
106
|
|
|
106
107
|
```ts
|
|
107
108
|
const flags = await indiana.features({ attributes: { country: "CA" } });
|
|
@@ -112,36 +113,36 @@ const unsubscribe = flags.subscribe(() =>
|
|
|
112
113
|
flags.setAttributes({ country: "US" });
|
|
113
114
|
indiana.track("Checkout Viewed", { source: "pricing" });
|
|
114
115
|
await indiana.flush();
|
|
115
|
-
//
|
|
116
|
+
// On page teardown:
|
|
116
117
|
unsubscribe();
|
|
117
118
|
flags.destroy();
|
|
118
119
|
```
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
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.
|
|
121
122
|
|
|
122
|
-
Offering
|
|
123
|
+
Offering pins the Product Version scope and hierarchy. Paywall pins a published Offering Version and independently chooses its displayed Product subset, groups, ordering, and default selection. `createPaywallStartClient`, `createPaywallSession`, and `showPaywall` use a standalone Paywall Session. After payment, read Entitlements again. Your backend still authorizes requests and consumes usage idempotently.
|
|
123
124
|
|
|
124
|
-
##
|
|
125
|
+
## Commercial capabilities and current service boundaries
|
|
125
126
|
|
|
126
|
-
|
|
127
|
+
The server implements Customer/Guest identity, Entitlement checks, holdings and ledger reads, usage and balances, Coupons/referral codes, Offering/standalone Paywall, and configured Stripe Sandbox attach, payment-method collection, subscription validation/updates/refunds/Trial, and License allocation. Each operation depends on configured payment accounts, execution mode, Product/Price terms, and its implemented scope. An API's presence does not certify every combination.
|
|
127
128
|
|
|
128
|
-
Stripe
|
|
129
|
+
In Stripe environments, Indiana executes `autumn` mode; `record_only` returns instructions for the merchant backend to execute. Both record financial and Entitlement facts from verified Stripe evidence. Collecting a payment method does not itself charge, create an Invoice, or grant extra Entitlements. Quotes, confirmations, and reads retain their durable operation IDs; a request ID cannot be reused with different input.
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
This beta does not certify complete commercial or production operation. Remaining service gaps include:
|
|
131
132
|
|
|
132
|
-
-
|
|
133
|
-
- Postpaid Billing Authorization
|
|
134
|
-
- `claimRewardProduct
|
|
135
|
-
- Apple
|
|
133
|
+
- Subscription batch processing. Conflict queries and retries have services but still require a matching deployment and business prerequisites.
|
|
134
|
+
- Postpaid Billing Authorization, Billing Coupon lists, and billing-adjustment confirmation. AutoTopup consent preparation/confirmation/revocation is implemented independently.
|
|
135
|
+
- Complete delivery for `claimRewardProduct`.
|
|
136
|
+
- Real Apple/Google store acceptance. Independent purchase/restore contracts and partial services do not certify store acceptance. `createNativeReceiptClient().recover()` uses `subscriptions/native/restore`.
|
|
136
137
|
|
|
137
|
-
Live
|
|
138
|
+
Live commercial execution remains subject to explicit server gates. Other Product/Price, Entity, subscription-addition, and quantity combinations depend on the matching server's actual capabilities.
|
|
138
139
|
|
|
139
|
-
## AI
|
|
140
|
+
## AI usage
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
The server entry provides AI SDK usage middleware; the OpenRouter entry provides a wrapper. Your host supplies a persistent idempotency key per invocation, usage/quote storage, and recovery callbacks. Recovery replays the original quoted charge without running the model again. Keep provider keys on your trusted backend.
|
|
142
143
|
|
|
143
|
-
##
|
|
144
|
+
## Publication and verification
|
|
144
145
|
|
|
145
|
-
npm
|
|
146
|
+
Publishing to npm does not deploy Web services, apply database migrations, or release Swift/Kotlin packages. Package installation, types, offline unit tests, and builds are recorded separately from real Auth/RLS, Stripe, native stores, browser checks, and hosted deployment acceptance.
|
|
146
147
|
|
|
147
|
-
|
|
148
|
+
See the [SDK release ledger](https://github.com/tinkerlandai/Indiana/blob/main/docs/sdk-releases.md) for versions and immutable publication evidence, and the [developer documentation](https://tinker.cash/docs?lang=en) for integration guides.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
[English](./README.md)
|
|
2
|
+
|
|
3
|
+
# @tinkerlandai/indiana-sdk
|
|
4
|
+
|
|
5
|
+
Indiana 的 JavaScript/TypeScript SDK,包含浏览器、Node.js、屏幕渲染与可选 AI 用量集成。本包版本为 `0.3.1`,使用协议 `0.3`;服务端和数据库必须使用匹配的当前协议。本版本有破坏性变更,不提供旧名称、旧输入或旧数据模型的兼容层。
|
|
6
|
+
|
|
7
|
+
**0.3.1 / 协议 0.3** 包含独立 Feature 下发、屏幕 render reference 与当前请求头校验。历史 0.2.0 包不能连接使用协议 0.3 的 HTTP handlers;显式或无版本头的旧 0.2 请求都在业务执行前被拒绝。
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @tinkerlandai/indiana-sdk@0.3.1
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 版本兼容与支持
|
|
14
|
+
|
|
15
|
+
当前 0.x 仅支持当前协议;1.0 起同一主版本内保持兼容。新稳定主版本发布后,旧稳定主版本至少继续支持 12 个日历月,停止支持提前至少 180 天公开通知,实际日期取两者中较晚者。详见 [版本与支持政策](../../docs/sdk-versioning-and-support.md) 和公开开发文档 `/docs/release-notes#support-policy`。
|
|
16
|
+
|
|
17
|
+
0.3.0 发送协议及 SDK 版本请求头,并校验成功响应的协议声明。历史 0.2.0 不发送这些请求头;服务端将无版本头的请求固定识别为 0.2,不自动跟随新协议。源码更新不会修改已有 npm 包,也不会自动部署服务端。
|
|
18
|
+
|
|
19
|
+
## 一个 npm 包,六个入口
|
|
20
|
+
|
|
21
|
+
| 导入入口 | 用途 |
|
|
22
|
+
| ---------------------------------------- | ----------------------------------------------------------- |
|
|
23
|
+
| `@tinkerlandai/indiana-sdk` | 浏览器 Customer、Funnel、Feature 与独立 Paywall 客户端 |
|
|
24
|
+
| `@tinkerlandai/indiana-sdk/server` | 可信 Node.js 后端、Customer Session、业务写入和 Funnel 决策 |
|
|
25
|
+
| `@tinkerlandai/indiana-sdk/popup` | 独立屏幕渲染、清洗和预览 |
|
|
26
|
+
| `@tinkerlandai/indiana-sdk/openrouter` | 可选 OpenRouter 用量集成,需要安装对应 peer dependency |
|
|
27
|
+
| `@tinkerlandai/indiana-sdk/native-shell` | 原生 WebView 的静态 Funnel shell 资源;不代表商店购买验收 |
|
|
28
|
+
| `@tinkerlandai/indiana-sdk/page` | 匿名商户页面的网址实验;使用公开的 App environment ID |
|
|
29
|
+
|
|
30
|
+
JavaScript 与 TypeScript 共用本包,声明文件随包提供。内部 `@indiana/contracts` 在构建时内联,接入方无需安装私有包。Swift 和 Kotlin 使用各自的包管理生态,不在本次 npm 发布范围内。
|
|
31
|
+
|
|
32
|
+
## 从可信后端创建 Customer Session
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createIndianaServer } from "@tinkerlandai/indiana-sdk/server";
|
|
36
|
+
|
|
37
|
+
const indiana = createIndianaServer({
|
|
38
|
+
baseUrl: process.env.INDIANA_BASE_URL!,
|
|
39
|
+
apiKey: process.env.INDIANA_SECRET_KEY!,
|
|
40
|
+
scope: {
|
|
41
|
+
projectId: process.env.INDIANA_PROJECT_ID!,
|
|
42
|
+
environment: "sandbox",
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
const user = await requireSignedInUser(request);
|
|
46
|
+
const { customer } = await indiana.getOrCreateCustomer({
|
|
47
|
+
externalUserId: user.id,
|
|
48
|
+
});
|
|
49
|
+
const { customerToken } = await indiana.createCustomerSession(customer.id);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Secret Key 仅保存在可信后端。浏览器传入的 Customer ID 不能作为登录证明;将 Customer Token 交给对应的已登录用户。App、Sandbox/Live、Customer、权限和允许来源分别校验。SDK 在内存中持有客户凭据;退出或切换身份时销毁旧视图并清理凭据。
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createIndiana } from "@tinkerlandai/indiana-sdk";
|
|
56
|
+
|
|
57
|
+
const indiana = createIndiana({
|
|
58
|
+
baseUrl,
|
|
59
|
+
scope: { projectId, environment: "sandbox" },
|
|
60
|
+
});
|
|
61
|
+
indiana.identify(customerToken);
|
|
62
|
+
const { holdings } = await indiana.readHoldings();
|
|
63
|
+
// 退出账号时:
|
|
64
|
+
indiana.reset();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Customer 使用原始业务字段;资料更新是部分 patch,没有 Customer revision。Guest 登录到已有 Customer 时返回 `switched: true`,资源和历史保留原归属,接入方应为目标 Customer 创建新 Session/Funnel;不合并旧 Guest 的财务事实。
|
|
68
|
+
|
|
69
|
+
## Optional stable fingerprint
|
|
70
|
+
|
|
71
|
+
`fingerprint` is a host-supplied stable deduplication signal, such as an installation identifier. Initialize and retain it before the first Guest/Customer request, independently of login and credentials. Reuse it across Guest identification, account changes and session renewal. The SDK does not collect or generate it.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// Trusted backend fragment: installationSignal is retained by the host;
|
|
75
|
+
// verifiedUser.id comes from the host's authenticated login.
|
|
76
|
+
const { customer } = await indiana.getOrCreateCustomer({
|
|
77
|
+
externalUserId: verifiedUser.id,
|
|
78
|
+
fingerprint: installationSignal,
|
|
79
|
+
});
|
|
80
|
+
// On Guest creation, use that same installationSignal and separately
|
|
81
|
+
// retain/reuse guestToken for creation retries.
|
|
82
|
+
await indiana.createGuestCustomer({
|
|
83
|
+
guestToken: retainedGuestToken,
|
|
84
|
+
fingerprint: installationSignal,
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Indiana keeps the first supplied signal as an environment-scoped hash; later values do not replace it. Missing input is valid and retains per-Customer trial deduplication. `unique_fingerprint` additionally deduplicates the configured Product trial across Customers sharing the signal. Business user IDs do not identify an installation; Customer/Guest/session tokens and request IDs have their own lifecycles and should not be fingerprints.
|
|
89
|
+
|
|
90
|
+
On Web, an independent first-party installation cookie can retain the signal. Clearing it or changing browser storage can produce a new value; sign-out need not reset it. Native hosts persist a random installation signal and define reinstall, restore and reset behavior. This signal is separate from device attestation and authentication. See the Web developer documentation's `/docs/identity#fingerprint` guide for executable HTTP host examples. Trial conflicts remain generic to clients; retain `X-Request-Id` for server-side diagnosis.
|
|
91
|
+
|
|
92
|
+
## Funnel、Feature 与独立 Paywall
|
|
93
|
+
|
|
94
|
+
可信后端通过 `createFunnelStartClient().start()` 提交 `funnelId`、持久保留的 `requestId`、`customer`、`locale` 和 `parameters`。`customer` 为 `{ type: "id", value: customerId }` 或 `{ type: "externalUserId", value: verifiedUser.id }`。后者可以同时提供仅用于新建的 `customerData`,需要 `customers:write` 权限;已有 Customer 不因此更新。服务端响应返回 `customerId`,后端再为它签发 Customer Session。旧的 start-body `customerToken` 和 decision `customerId` 明确拒绝。
|
|
95
|
+
|
|
96
|
+
`createFunnelClient({ customerToken, ...options })` 用于已持有 Customer 凭据的客户端;其 `start()` 不指定 `customer` 或 `customerData`,始终以凭据所属 Customer 运行。响应丢失时保留原编号和输入重试,商业参数放在 `parameters.commerce`。运行有独立的 Run Token,不能据此切换 Customer。
|
|
97
|
+
|
|
98
|
+
`createFunnelDecisionClient` 的 `submit/decide` 与 `/server` 的 `createFunnelCampaignClient` 同样使用明确的 `customer` 引用。Campaign 客户端提供显式 `decide/start`;受频率或进行中运行限制时,`start` 返回 `suppressed` 和重试时间,不伪造 Run 凭据。Run 实际展示后才提交 `shown`,不能用页面关闭或本地存储代替持久的展示事实。
|
|
99
|
+
|
|
100
|
+
浏览器使用 `createFunnelRunController` 与 `showFunnelRun`。控制器负责当前协议的命令、读取、重试、恢复和订阅;展示句柄提供 `refresh()` 和 `destroy()`。业务操作按当前发布节点委派给服务端,客户端声明或重定向不构成付款证明。
|
|
101
|
+
|
|
102
|
+
Local/Remote 求值策略由每个 Funnel 决定。`createFunnelDecisionClient` 支持当前 `configuration()`、`features()`、提交和结果读取;`createFeatureClient` 以 `generation` 标识配置。Local 下载的规则对客户端可见;敏感决策应使用 Remote 和可信业务事实。
|
|
103
|
+
|
|
104
|
+
### 独立 Feature
|
|
105
|
+
|
|
106
|
+
后端 Key 显式授予 `features:read` / `events:write`,通过现有 Customer/Guest Session 交给浏览器,不使用新的凭证种类。
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const flags = await indiana.features({ attributes: { country: "CA" } });
|
|
110
|
+
const enabled = flags.getFeatureValue("new-checkout", false);
|
|
111
|
+
const unsubscribe = flags.subscribe(() =>
|
|
112
|
+
updateView(flags.isOn("new-checkout")),
|
|
113
|
+
);
|
|
114
|
+
flags.setAttributes({ country: "US" });
|
|
115
|
+
indiana.track("Checkout Viewed", { source: "pricing" });
|
|
116
|
+
await indiana.flush();
|
|
117
|
+
// 页面卸载时:
|
|
118
|
+
unsubscribe();
|
|
119
|
+
flags.destroy();
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
每个 flag 默认本地计算,Owner/Admin 可切换为服务器计算。服务器 flag 只下发键与结果,首次结果到达前使用调用方默认值;属性变化立即丢弃旧结果。名单哈希不等于保密,敏感规则应使用服务器计算。本地 Funnel 不得依赖服务器 flag,切换时也会校验仍在运行的历史版本。`identify` / `reset` 会释放旧身份的功能实例和事件队列。
|
|
123
|
+
|
|
124
|
+
Offering 固定 Product Version 的范围与层级。Paywall 固定已发布 Offering Version,并独立选择显示的 Product 子集、分组、顺序和默认项。`createPaywallStartClient`、`createPaywallSession`、`showPaywall` 使用独立 Paywall Session,不创建占位 Funnel。付款完成后重新查询权益,业务后端仍须重新鉴权并幂等扣减用量。
|
|
125
|
+
|
|
126
|
+
## Web 商业能力与当前服务边界
|
|
127
|
+
|
|
128
|
+
当前服务端实现了 Customer/Guest、Entitlement 检查、持有与账本读取、用量和余额、Coupon/推荐码、Offering/独立 Paywall,以及配置后的 Stripe Sandbox attach、支付方式收集、订阅验证/更新/退款/Trial 和 License 分配路径。每个操作仍受已配置的支付账号、执行模式、Product/Price 条款和当前实现范围约束;接口存在不表示任意组合已验收。
|
|
129
|
+
|
|
130
|
+
Stripe 环境的 `autumn` 模式由 Indiana 执行;`record_only` 返回交给商户后端执行的指令。两种模式都从验证后的 Stripe 事实写入财务与权益。支付方式收集本身不产生扣款、Invoice 或额外权益。报价/确认/读取使用各自持久操作 ID;同一请求编号不能更换输入。
|
|
131
|
+
|
|
132
|
+
本 Beta **不认证完整商业功能或生产运行**。当前仍未接通的服务包括:
|
|
133
|
+
|
|
134
|
+
- 订阅批处理。冲突查询/重试已有对应服务,但仍需匹配部署及业务前置条件。
|
|
135
|
+
- Postpaid Billing Authorization、Billing Coupon 列表和账单调整确认。当前 AutoTopup consent 的准备/确认/撤销已有服务,不能据此推定其他授权类型可用。
|
|
136
|
+
- `claimRewardProduct` 的完整交付。
|
|
137
|
+
- Apple/Google 真实商店验收。当前独立购买/恢复的协议及部分服务实现不代表商店已验收;`createNativeReceiptClient().recover()` 使用 `subscriptions/native/restore`,不再发送旧 Funnel 原生恢复命令。
|
|
138
|
+
|
|
139
|
+
Live 商业执行仍有显式服务端门禁。其他 Product/Price、Entity、订阅追加和数量组合,以匹配服务端的实际能力为准;不自动回退到旧实现。
|
|
140
|
+
|
|
141
|
+
## AI 用量
|
|
142
|
+
|
|
143
|
+
`/server` 提供 AI SDK 用量中间件;`/openrouter` 提供 OpenRouter 包装器。宿主必须提供每次调用的持久幂等键、usage/quote 存储及恢复回调。恢复时重放原报价的扣款,不重新运行模型。密钥始终留在可信后端。
|
|
144
|
+
|
|
145
|
+
## 发布与验收
|
|
146
|
+
|
|
147
|
+
npm 发布不部署 Web 服务、不应用数据库迁移,也不发布 Swift/Kotlin 包。安装消费、类型、离线单元和构建检查,与真实 Auth/RLS、Stripe、原生商店、浏览器和线上部署分别记录;局部通过不代表整套产品验收。
|
|
148
|
+
|
|
149
|
+
版本、冻结产物哈希和 registry 回读见 [发布总账](../../docs/sdk-releases.md);当前架构与实现边界见 [开发状态](../../docs/development-status.md)。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Y as S,_b as C,gc as k,jc as L,mc as T,nc as v,oc as j,rc as R,ui as V}from"./chunk-D37O6FAW.js";var U={name:"@tinkerlandai/indiana-sdk",version:"0.3.1",description:"Framework-independent Indiana SDK for customer identity, entitlements, credits, offers and growth surfaces.",license:"UNLICENSED",repository:{type:"git",url:"git+https://github.com/tinkerlandai/Indiana.git",directory:"packages/sdk"},engines:{node:">=22"},publishConfig:{access:"public",tag:"beta"},type:"module",sideEffects:!1,files:["dist","README.md","README.zh-CN.md","CHANGELOG.md","THIRD_PARTY_NOTICES.md"],exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"},"./popup":{types:"./dist/popup.d.ts",import:"./dist/popup.js"},"./server":{types:"./dist/server.d.ts",import:"./dist/server.js"},"./openrouter":{types:"./dist/openrouter.d.ts",import:"./dist/openrouter.js"},"./native-shell":{types:"./dist/native-shell.d.ts",import:"./dist/native-shell.js"},"./page":{types:"./dist/page.d.ts",import:"./dist/page.js"}},scripts:{build:"tsup",prepack:"pnpm run build",typecheck:"tsc --noEmit"},dependencies:{"@ai-sdk/provider":"4.0.26","@types/json-schema":"7.0.15","css-tree":"^3.2.1",dompurify:"^3.4.15",zod:"4.6.5"},devDependencies:{"@indiana/contracts":"workspace:*","@openrouter/sdk":"^1.4.25","@types/css-tree":"^3.2.0",ai:"7.0.136",tsup:"^8.5.1",typescript:"^5.9.3"},peerDependencies:{"@openrouter/sdk":"^1.4.25"},peerDependenciesMeta:{"@openrouter/sdk":{optional:!0}}};var e=class extends Error{constructor(h,d,n,N,i){super(d);this.code=h;this.status=n;this.requestId=N;this.name="IndianaError",this.reason=i?.reason;let c=T(h,n??0,{...i,retryAfter:i?.retryAfterSeconds===void 0?void 0:String(i.retryAfterSeconds)});this.retryable=c.retryable,this.recovery=c.recovery,this.retryAfterSeconds=c.retryAfterSeconds}code;status;requestId;retryable;recovery;retryAfterSeconds;reason},$=Symbol("IndianaNoContent");function J(l,A){let h=l.webView??"hosted";if(!["hosted","embedded"].includes(h))throw new e("INVALID_REQUEST","Invalid Web View mode");let d=l.scope?S.parse(l.scope):void 0,n=new URL(l.baseUrl);if(n.username||n.password||n.search||n.hash)throw new e("INVALID_URL","baseUrl must not contain credentials, query, or fragment");if(n.protocol!=="https:"&&!(n.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(n.hostname)))throw new e("INVALID_URL","Use HTTPS, or HTTP on localhost during development");let N=l.fetch??globalThis.fetch.bind(globalThis),i=l.timeoutMs??1e4;if(!Number.isFinite(i)||i<=0||i>12e4)throw new e("INVALID_TIMEOUT","timeoutMs must be between 1 and 120000");let c=null,b,u=0,p=null,f=new Set;function D(){u+=1,c=null,p=null;for(let s of f)s.abort();f.clear()}async function M(s,q={},O="POST",H={}){if(!c)throw new e("NOT_IDENTIFIED","Call identify with a server-issued customer token first");let g=u,o=new AbortController;f.add(o);let y=()=>g!==u?new e("IDENTITY_CHANGED","Customer identity changed while the request was in flight"):new e("TIMEOUT","Indiana request timed out"),I,x=new Promise((r,a)=>{I=()=>a(y()),o.signal.addEventListener("abort",I,{once:!0})}),K=setTimeout(()=>o.abort(),i),G=async()=>{let r=await N(`${n.href.replace(/\/$/,"")}/api/v1/${s}`,{method:O,headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`,[v]:R.current,[j]:U.version,...d?{"X-Indiana-Project":d.projectId,"X-Indiana-Environment":d.environment}:{}},body:O==="POST"?JSON.stringify(q):void 0,signal:o.signal,credentials:"omit",cache:"no-store",redirect:"error",...H.keepalive?{keepalive:!0}:{}});if(o.signal.aborted)throw y();let a;try{a=r.status===204?$:await r.json()}catch{throw o.signal.aborted?y():new e(r.ok?"INVALID_RESPONSE":"HTTP_ERROR","The gateway returned an unreadable response",r.status,r.headers.get("X-Request-Id")??void 0)}if(o.signal.aborted)throw y();if(g!==u)throw new e("IDENTITY_CHANGED","Customer identity changed while the request was in flight");if(!r.ok){let t=L.safeParse(a),m=t.success&&(!C.safeParse(t.data.error.code).success||k(t.data.error.code,r.status)),_=m?t.data.error.code:"HTTP_ERROR",P=T(_,r.status,{retryAfter:r.headers.get("Retry-After"),recovery:m?t.data.error.recovery:void 0,reason:m?t.data.error.reason:void 0});throw new e(_,m?t.data.error.message:"Indiana request failed",r.status,r.headers.get("X-Request-Id")??(t.success?t.data.requestId:void 0),{...P,...t.success&&t.data.error.retryable===!1?{retryable:!1}:{},...P.retryAfterSeconds===void 0&&t.success&&t.data.error.retryAfterSeconds!==void 0?{retryAfterSeconds:t.data.error.retryAfterSeconds}:{}})}if(r.headers.get(v)!==R.current)throw new e("PROTOCOL_MISMATCH","Response protocol does not match this SDK");if(d&&a&&typeof a=="object"&&"scope"in a){let t=S.safeParse(a.scope);if(!t.success||t.data.projectId!==d.projectId||t.data.environment!==d.environment)throw new e("SCOPE_MISMATCH","Response scope does not match this SDK instance")}let E=r.headers.get("X-Indiana-Web-View");if(E){if(!/^\/web-view\/renderer\/[a-f0-9]{64}$/.test(E))throw new e("INVALID_RESPONSE","Invalid Web View renderer metadata");b=E}let w=r.headers.get("X-Indiana-Telemetry-Subject");if(w){if(!/^[a-f0-9]{64}$/.test(w))throw new e("INVALID_RESPONSE","Invalid telemetry identity");p!==w&&(p=w,A?.(p))}return a};try{return await Promise.race([G(),x])}catch(r){throw g!==u?new e("IDENTITY_CHANGED","Customer identity changed while the request was in flight"):r instanceof e?r:new e(o.signal.aborted?"TIMEOUT":"NETWORK_ERROR",o.signal.aborted?"Indiana request timed out":"Unable to read the Indiana response")}finally{clearTimeout(K),o.signal.removeEventListener("abort",I),f.delete(o)}}return{subjectKey:()=>p,screenUrl(s){if(!V.safeParse(s).success)throw new e("INVALID_RESPONSE","Invalid published screen render address");return new URL(s,n).href},webViewUrl(){if(h!=="embedded"){if(!b)throw new e("INVALID_RESPONSE","The gateway did not provide a hosted Web View renderer");return new URL(b,n).href}},identify(s){if(!s.trim()||/\s/.test(s)||s.length>4096)throw new e("INVALID_TOKEN","A nonempty server-issued token is required");D(),c=s},reset:D,request:M}}export{e as a,J as b};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as c,b as C}from"./chunk-X5UXOLOU.js";import{Fk as L,ci as N,di as _,gi as q,hf as V,ma as R,ok as U,qi as A,zk as T}from"./chunk-D37O6FAW.js";import{d as b,e as D,f as k,g as x}from"./chunk-MJG7X7LM.js";function j(a){let e=null,i=null,l=0,r=0,s=new Set,n=null,u=null,y=new Set,g=()=>{for(let t of y)try{t()}catch{}},o={attributes:R.parse(a.attributes??{}),onFeatureUsage:a.onFeatureUsage?(t,f)=>{s.has(t)||a.onFeatureUsage(t,structuredClone(f))}:void 0,onExperimentViewed:a.onExperimentViewed?(t,f)=>a.onExperimentViewed(structuredClone(t),structuredClone(f)):void 0,stickyBucketAssignmentDocs:structuredClone(a.stickyBucketAssignmentDocs),saveStickyBucketAssignmentDoc:a.saveStickyBucketAssignmentDoc?t=>a.saveStickyBucketAssignmentDoc(structuredClone(t)):void 0,trackedFeatureUsage:{},trackedExperiments:new Set},w=()=>({value:null,source:"unknownFeature",on:!1,off:!0,ruleId:""});function d(t,f=new Set){return s.has(t)?!n||!n.features[t]||["unknownFeature","cyclicPrerequisite"].includes(n.features[t].source):f.has(t)?!1:(f.add(t),(e?.features[t]?.rules??[]).some(p=>[...p.parentConditions??[],...(p.tracks??[]).flatMap(h=>h.experiment.parentConditions??[])].some(h=>d(h.id,f))))}let m=t=>{if(!e)throw new Error("Initialize the Feature client before evaluation");if(e.expiresAt&&Date.parse(e.expiresAt)<=Date.now())throw new Error("Feature configuration expired; refresh before evaluation");return n?.expiresAt&&Date.parse(n.expiresAt)<=Date.now()&&(n=null,o.features=e.features),s.has(t)?!n||n.expiresAt&&Date.parse(n.expiresAt)<=Date.now()?w():structuredClone(n.features[t]??w()):d(t)?w():structuredClone(x(t,o))};async function v(){if(!e||!s.size)return;if(!a.evaluateRemote)throw new Error("Remote Feature evaluation requires a server loader");let t=r;if(u?.revision===t)return u.loading;let f=l,p=e,h=[...s],I=(async()=>{let E=q.parse(await a.evaluateRemote({attributes:structuredClone(o.attributes),features:h}));if(!(f!==l||t!==r||p!==e)){if(E.generation!==p.generation)throw new Error("Feature configuration changed; refresh before evaluation");if(h.some(S=>!Object.hasOwn(E.features,S))||Object.keys(E.features).some(S=>!s.has(S)))throw new Error("Invalid remote Feature results");n=structuredClone(E),o.features={...p.features,...Object.fromEntries(Object.entries(n.features).map(([S,B])=>[S,{defaultValue:B.value}]))},g()}})();u={revision:t,loading:I};try{await I}finally{u?.loading===I&&(u=null)}}function P(){v().catch(t=>{try{a.onError?.(t)}catch{}})}async function F(){if(i)return i;let t=l,f=(async()=>{let p=await a.load(),h="remoteFeatures"in p?_.parse(p):null,I=h??N.parse(p);if(I.scope.projectId!==a.scope.projectId||I.scope.environment!==a.scope.environment)throw new Error("Feature payload scope changed");if(t!==l)throw new Error("Feature client was reset");let E=new Set(h?.remoteFeatures??[]);if([...E].some(S=>Object.hasOwn(I.features,S)))throw new Error("Remote Feature definitions must not be delivered locally");return e=structuredClone(I),s=E,n=null,u=null,r++,o.features=e.features,o.savedGroups=b(e.savedGroups),o.trackedFeatureUsage={},g(),P(),structuredClone(e)})();i=f;try{return await f}finally{i===f&&(i=null)}}return{init:F,refresh:F,refreshRemote:v,get generation(){return e?.generation??null},get expiresAt(){return e?.expiresAt??null},subscribe(t){return y.add(t),()=>{y.delete(t)}},setAttributes(t){o.attributes=R.parse(t),r++,n=null,u=null,o.features=e?.features??{},o.trackedFeatureUsage={},g(),P()},evalFeature:m,isOn(t){return m(t).on},isOff(t){return m(t).off},getFeatureValue(t,f){let p=m(t).value;return structuredClone(p===null?f:p)},reset(){l++,r++,i=null,u=null,e=null,n=null,s.clear(),o.features={},o.savedGroups={},o.stickyBucketAssignmentDocs={},o.attributes={},o.trackedFeatureUsage={},o.trackedExperiments?.clear(),g()}}}async function M(a,e){if(!/^gg_ct_[A-Za-z0-9_-]{43}$/.test(e.customerToken))throw new c("INVALID_TOKEN","A verified Customer credential is required");let i=C(a);i.identify(e.customerToken);let l=A.resolvePaywall.request.parse({selector:{type:"paywall",paywallId:e.paywallId},commerce:e.commerce,locale:e.locale,...e.requirement?{requirement:e.requirement}:{}}),r=null,s=null,n=null,u=null,y=null;async function g(){let d=A.resolvePaywall,m=d.response.parse(await i.request(d.path,d.request.parse({...l,selector:r?{type:"version",versionId:r.id}:l.selector})));if(m.paywall.paywallId!==e.paywallId)throw new c("INVALID_RESPONSE","The requested Paywall changed");if(r&&(m.paywall.id!==r.id||m.paywall.paywallId!==r.paywallId||m.paywall.offering.id!==r.offering.id))throw new c("INVALID_RESPONSE","The pinned Paywall or Offering Version changed");return r=m.paywall,structuredClone(r)}async function o(d){if(!s)throw new c("INVALID_REQUEST","A quoted purchase is required");let m=d==="read"?A.readSubscriptionOperation:A.attach,v=m.response.parse(await i.request(m.path,m.request.parse({operationId:s.operationId,...d==="read"?{}:{intent:d}})));if(v.operation.operationId!==s.operationId||v.operation.currency!==l.commerce.currency)throw new c("INVALID_RESPONSE","The purchase operation changed");return n?.status==="complete"&&v.operation.status!=="complete"||n&&n.status!=="pending"&&v.operation.status==="pending"||(n=v.operation),structuredClone(n)}let w={get view(){return r?structuredClone(r):null},get quote(){return s?structuredClone(s):null},get operation(){return n?structuredClone(n):null},get webViewUrl(){return i.webViewUrl()},refresh:g,async preview(d){if(!r)throw new c("INVALID_REQUEST","Load the Paywall first");let m=r.document.buttons[d.actionId];if(m?.type!=="checkout")throw new c("INVALID_REQUEST","Choose an authored purchase action");let v=V(m.product,d.selection,r.capabilities);if(!v)throw new c("PRODUCT_UNAVAILABLE","Choose an available Product");let P=A.previewAttach.request.parse({requestId:d.requestId,plans:[{productVersionId:v}],provider:l.commerce.provider,currency:l.commerce.currency,...d.offerId?{offerId:d.offerId}:{},...d.nativeOffer?{nativeOffer:d.nativeOffer}:{}}),F=JSON.stringify(P);if(u&&u!==F&&(!n||n.status==="pending"))throw new c("COMMAND_PENDING","Finish or cancel the original purchase before changing it");if(u===F){if(y)return y;if(s)return structuredClone(s)}u=F;let t=(async()=>{let f=A.previewAttach,p=f.response.parse(await i.request(f.path,P));if(p.quote.currency!==l.commerce.currency||p.quote.provider!==l.commerce.provider||p.quote.lines.length!==1||p.quote.lines[0].productVersionId!==v)throw new c("INVALID_RESPONSE","The purchase quote changed its selected Product or presentment");return s=p.quote,n=null,structuredClone(s)})();y=t;try{return await t}finally{y===t&&(y=null)}},confirm:()=>o("confirm"),cancel:()=>o("cancel"),read:()=>o("read"),destroy(){i.reset(),r=null,s=null,n=null,u=null}};return await g(),w}function X(a,e,i){let l=L.parse(a);if(l.evaluationMode!=="local")throw new c("EVALUATION_MODE","Remote nodes are evaluated by Grow");if(l.expiresAt&&Date.parse(l.expiresAt)<=Date.now())throw new c("CONFIGURATION_EXPIRED","Refresh local rules at the scheduled transition");let r=l.topology.nodes.find(o=>o.id===e);if(!r)throw new c("NOT_FOUND","Funnel node is unavailable");let s=R.parse(i.attributes??{}),n={attributes:s,saveStickyBucketAssignmentDoc:i.saveStickyBucketAssignmentDoc?o=>i.saveStickyBucketAssignmentDoc(structuredClone(o)):void 0,onFeatureUsage:i.onFeatureUsage?(o,w)=>i.onFeatureUsage(o,structuredClone(w)):void 0,onExperimentViewed:i.onExperimentViewed?(o,w)=>i.onExperimentViewed(structuredClone(o),structuredClone(w)):void 0,features:structuredClone(l.growth.features),savedGroups:b(l.growth.savedGroups),stickyBucketAssignmentDocs:structuredClone(i.stickyBucketAssignmentDocs)},u,y;if(r.type==="condition"){let o=l.conditions[r.id];if(!o)throw new c("INVALID_RESPONSE","Local condition rules are unavailable");u=o.find(w=>D(s,w.condition,n.savedGroups))?.port??"default"}else if(r.type==="feature"){if(!r.resources.featureKey)throw new c("INVALID_RESPONSE","Feature reference is unavailable");y=x(r.resources.featureKey,n).value,u="next"}else if(r.type==="split"){let o=r.resources.experimentId,w=o?l.growth.experiments[o]:null;if(!w||!o)throw new c("INVALID_RESPONSE","Experiment reference is unavailable");let d=k(w,n);y=d.value,u=d.inExperiment&&!d.passthrough&&typeof d.value=="string"?d.value:"notParticipating"}else throw new c("SERVER_REQUIRED","This node is driven by the authoritative Funnel runtime");let g=r.outputs[u];if(!g)throw new c("INVALID_RESPONSE","Evaluated node exit is unavailable");return{nodeId:e,port:u,target:g,...y===void 0?{}:{value:y}}}function H(a,e){return e.type==="id"?a.customerId===e.value:a.externalUserId===e.value}function O(a,e){if(a===e)return!0;if(Array.isArray(a)||Array.isArray(e))return Array.isArray(a)&&Array.isArray(e)&&a.length===e.length&&a.every((r,s)=>O(r,e[s]));if(!a||!e||typeof a!="object"||typeof e!="object")return!1;let i=Object.entries(a),l=Object.entries(e);return i.length===l.length&&i.every(([r,s])=>Object.hasOwn(e,r)&&O(s,Reflect.get(e,r)))}function ne(a){let e=/^gg_ct_[A-Za-z0-9_-]{32,128}$/.test(a.apiKey);if(typeof window<"u"&&!e)throw new c("SERVER_ONLY","Funnel starts are issued by your backend");if(!e&&!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(a.apiKey))throw new c("INVALID_TOKEN","A customer credential or server API key is required");let i=C({...a,timeoutMs:a.timeoutMs??35e3});return i.identify(a.apiKey),{async start(l){let r=U.safeParse({...l,operation:"start"});if(!r.success||r.data.operation!=="start"||(e?r.data.customer!==void 0:r.data.customer===void 0))throw new c("INVALID_REQUEST","Invalid current Funnel start");let s=r.data,n=T.safeParse(await i.request("funnels",s));if(!n.success||!n.data.runToken)throw new c("INVALID_RESPONSE","Funnel start credentials are missing");let u=n.data;if(u.run.source.id!==s.funnelId||u.run.locale!==(s.locale??"en")||!O(u.run.parameters,s.parameters??{})||(s.customer?!u.customerId||s.customer.type==="id"&&u.customerId!==s.customer.value:u.customerId!==void 0))throw new c("INVALID_RESPONSE","Funnel start contract changed");return{...u,runToken:u.runToken}}}}export{j as a,H as b,O as c,M as d,X as e,ne as f};
|
|
1
|
+
import{a as c,b as C}from"./chunk-CRJJ4EA2.js";import{Fk as L,ci as N,di as _,gi as q,hf as V,ma as R,ok as U,qi as A,zk as T}from"./chunk-D37O6FAW.js";import{d as b,e as D,f as k,g as x}from"./chunk-MJG7X7LM.js";function j(a){let e=null,i=null,l=0,r=0,s=new Set,n=null,u=null,y=new Set,g=()=>{for(let t of y)try{t()}catch{}},o={attributes:R.parse(a.attributes??{}),onFeatureUsage:a.onFeatureUsage?(t,f)=>{s.has(t)||a.onFeatureUsage(t,structuredClone(f))}:void 0,onExperimentViewed:a.onExperimentViewed?(t,f)=>a.onExperimentViewed(structuredClone(t),structuredClone(f)):void 0,stickyBucketAssignmentDocs:structuredClone(a.stickyBucketAssignmentDocs),saveStickyBucketAssignmentDoc:a.saveStickyBucketAssignmentDoc?t=>a.saveStickyBucketAssignmentDoc(structuredClone(t)):void 0,trackedFeatureUsage:{},trackedExperiments:new Set},w=()=>({value:null,source:"unknownFeature",on:!1,off:!0,ruleId:""});function d(t,f=new Set){return s.has(t)?!n||!n.features[t]||["unknownFeature","cyclicPrerequisite"].includes(n.features[t].source):f.has(t)?!1:(f.add(t),(e?.features[t]?.rules??[]).some(p=>[...p.parentConditions??[],...(p.tracks??[]).flatMap(h=>h.experiment.parentConditions??[])].some(h=>d(h.id,f))))}let m=t=>{if(!e)throw new Error("Initialize the Feature client before evaluation");if(e.expiresAt&&Date.parse(e.expiresAt)<=Date.now())throw new Error("Feature configuration expired; refresh before evaluation");return n?.expiresAt&&Date.parse(n.expiresAt)<=Date.now()&&(n=null,o.features=e.features),s.has(t)?!n||n.expiresAt&&Date.parse(n.expiresAt)<=Date.now()?w():structuredClone(n.features[t]??w()):d(t)?w():structuredClone(x(t,o))};async function v(){if(!e||!s.size)return;if(!a.evaluateRemote)throw new Error("Remote Feature evaluation requires a server loader");let t=r;if(u?.revision===t)return u.loading;let f=l,p=e,h=[...s],I=(async()=>{let E=q.parse(await a.evaluateRemote({attributes:structuredClone(o.attributes),features:h}));if(!(f!==l||t!==r||p!==e)){if(E.generation!==p.generation)throw new Error("Feature configuration changed; refresh before evaluation");if(h.some(S=>!Object.hasOwn(E.features,S))||Object.keys(E.features).some(S=>!s.has(S)))throw new Error("Invalid remote Feature results");n=structuredClone(E),o.features={...p.features,...Object.fromEntries(Object.entries(n.features).map(([S,B])=>[S,{defaultValue:B.value}]))},g()}})();u={revision:t,loading:I};try{await I}finally{u?.loading===I&&(u=null)}}function P(){v().catch(t=>{try{a.onError?.(t)}catch{}})}async function F(){if(i)return i;let t=l,f=(async()=>{let p=await a.load(),h="remoteFeatures"in p?_.parse(p):null,I=h??N.parse(p);if(I.scope.projectId!==a.scope.projectId||I.scope.environment!==a.scope.environment)throw new Error("Feature payload scope changed");if(t!==l)throw new Error("Feature client was reset");let E=new Set(h?.remoteFeatures??[]);if([...E].some(S=>Object.hasOwn(I.features,S)))throw new Error("Remote Feature definitions must not be delivered locally");return e=structuredClone(I),s=E,n=null,u=null,r++,o.features=e.features,o.savedGroups=b(e.savedGroups),o.trackedFeatureUsage={},g(),P(),structuredClone(e)})();i=f;try{return await f}finally{i===f&&(i=null)}}return{init:F,refresh:F,refreshRemote:v,get generation(){return e?.generation??null},get expiresAt(){return e?.expiresAt??null},subscribe(t){return y.add(t),()=>{y.delete(t)}},setAttributes(t){o.attributes=R.parse(t),r++,n=null,u=null,o.features=e?.features??{},o.trackedFeatureUsage={},g(),P()},evalFeature:m,isOn(t){return m(t).on},isOff(t){return m(t).off},getFeatureValue(t,f){let p=m(t).value;return structuredClone(p===null?f:p)},reset(){l++,r++,i=null,u=null,e=null,n=null,s.clear(),o.features={},o.savedGroups={},o.stickyBucketAssignmentDocs={},o.attributes={},o.trackedFeatureUsage={},o.trackedExperiments?.clear(),g()}}}async function M(a,e){if(!/^gg_ct_[A-Za-z0-9_-]{43}$/.test(e.customerToken))throw new c("INVALID_TOKEN","A verified Customer credential is required");let i=C(a);i.identify(e.customerToken);let l=A.resolvePaywall.request.parse({selector:{type:"paywall",paywallId:e.paywallId},commerce:e.commerce,locale:e.locale,...e.requirement?{requirement:e.requirement}:{}}),r=null,s=null,n=null,u=null,y=null;async function g(){let d=A.resolvePaywall,m=d.response.parse(await i.request(d.path,d.request.parse({...l,selector:r?{type:"version",versionId:r.id}:l.selector})));if(m.paywall.paywallId!==e.paywallId)throw new c("INVALID_RESPONSE","The requested Paywall changed");if(r&&(m.paywall.id!==r.id||m.paywall.paywallId!==r.paywallId||m.paywall.offering.id!==r.offering.id))throw new c("INVALID_RESPONSE","The pinned Paywall or Offering Version changed");return r=m.paywall,structuredClone(r)}async function o(d){if(!s)throw new c("INVALID_REQUEST","A quoted purchase is required");let m=d==="read"?A.readSubscriptionOperation:A.attach,v=m.response.parse(await i.request(m.path,m.request.parse({operationId:s.operationId,...d==="read"?{}:{intent:d}})));if(v.operation.operationId!==s.operationId||v.operation.currency!==l.commerce.currency)throw new c("INVALID_RESPONSE","The purchase operation changed");return n?.status==="complete"&&v.operation.status!=="complete"||n&&n.status!=="pending"&&v.operation.status==="pending"||(n=v.operation),structuredClone(n)}let w={get view(){return r?structuredClone(r):null},get quote(){return s?structuredClone(s):null},get operation(){return n?structuredClone(n):null},get webViewUrl(){return i.webViewUrl()},refresh:g,async preview(d){if(!r)throw new c("INVALID_REQUEST","Load the Paywall first");let m=r.document.buttons[d.actionId];if(m?.type!=="checkout")throw new c("INVALID_REQUEST","Choose an authored purchase action");let v=V(m.product,d.selection,r.capabilities);if(!v)throw new c("PRODUCT_UNAVAILABLE","Choose an available Product");let P=A.previewAttach.request.parse({requestId:d.requestId,plans:[{productVersionId:v}],provider:l.commerce.provider,currency:l.commerce.currency,...d.offerId?{offerId:d.offerId}:{},...d.nativeOffer?{nativeOffer:d.nativeOffer}:{}}),F=JSON.stringify(P);if(u&&u!==F&&(!n||n.status==="pending"))throw new c("COMMAND_PENDING","Finish or cancel the original purchase before changing it");if(u===F){if(y)return y;if(s)return structuredClone(s)}u=F;let t=(async()=>{let f=A.previewAttach,p=f.response.parse(await i.request(f.path,P));if(p.quote.currency!==l.commerce.currency||p.quote.provider!==l.commerce.provider||p.quote.lines.length!==1||p.quote.lines[0].productVersionId!==v)throw new c("INVALID_RESPONSE","The purchase quote changed its selected Product or presentment");return s=p.quote,n=null,structuredClone(s)})();y=t;try{return await t}finally{y===t&&(y=null)}},confirm:()=>o("confirm"),cancel:()=>o("cancel"),read:()=>o("read"),destroy(){i.reset(),r=null,s=null,n=null,u=null}};return await g(),w}function X(a,e,i){let l=L.parse(a);if(l.evaluationMode!=="local")throw new c("EVALUATION_MODE","Remote nodes are evaluated by Grow");if(l.expiresAt&&Date.parse(l.expiresAt)<=Date.now())throw new c("CONFIGURATION_EXPIRED","Refresh local rules at the scheduled transition");let r=l.topology.nodes.find(o=>o.id===e);if(!r)throw new c("NOT_FOUND","Funnel node is unavailable");let s=R.parse(i.attributes??{}),n={attributes:s,saveStickyBucketAssignmentDoc:i.saveStickyBucketAssignmentDoc?o=>i.saveStickyBucketAssignmentDoc(structuredClone(o)):void 0,onFeatureUsage:i.onFeatureUsage?(o,w)=>i.onFeatureUsage(o,structuredClone(w)):void 0,onExperimentViewed:i.onExperimentViewed?(o,w)=>i.onExperimentViewed(structuredClone(o),structuredClone(w)):void 0,features:structuredClone(l.growth.features),savedGroups:b(l.growth.savedGroups),stickyBucketAssignmentDocs:structuredClone(i.stickyBucketAssignmentDocs)},u,y;if(r.type==="condition"){let o=l.conditions[r.id];if(!o)throw new c("INVALID_RESPONSE","Local condition rules are unavailable");u=o.find(w=>D(s,w.condition,n.savedGroups))?.port??"default"}else if(r.type==="feature"){if(!r.resources.featureKey)throw new c("INVALID_RESPONSE","Feature reference is unavailable");y=x(r.resources.featureKey,n).value,u="next"}else if(r.type==="split"){let o=r.resources.experimentId,w=o?l.growth.experiments[o]:null;if(!w||!o)throw new c("INVALID_RESPONSE","Experiment reference is unavailable");let d=k(w,n);y=d.value,u=d.inExperiment&&!d.passthrough&&typeof d.value=="string"?d.value:"notParticipating"}else throw new c("SERVER_REQUIRED","This node is driven by the authoritative Funnel runtime");let g=r.outputs[u];if(!g)throw new c("INVALID_RESPONSE","Evaluated node exit is unavailable");return{nodeId:e,port:u,target:g,...y===void 0?{}:{value:y}}}function H(a,e){return e.type==="id"?a.customerId===e.value:a.externalUserId===e.value}function O(a,e){if(a===e)return!0;if(Array.isArray(a)||Array.isArray(e))return Array.isArray(a)&&Array.isArray(e)&&a.length===e.length&&a.every((r,s)=>O(r,e[s]));if(!a||!e||typeof a!="object"||typeof e!="object")return!1;let i=Object.entries(a),l=Object.entries(e);return i.length===l.length&&i.every(([r,s])=>Object.hasOwn(e,r)&&O(s,Reflect.get(e,r)))}function ne(a){let e=/^gg_ct_[A-Za-z0-9_-]{32,128}$/.test(a.apiKey);if(typeof window<"u"&&!e)throw new c("SERVER_ONLY","Funnel starts are issued by your backend");if(!e&&!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(a.apiKey))throw new c("INVALID_TOKEN","A customer credential or server API key is required");let i=C({...a,timeoutMs:a.timeoutMs??35e3});return i.identify(a.apiKey),{async start(l){let r=U.safeParse({...l,operation:"start"});if(!r.success||r.data.operation!=="start"||(e?r.data.customer!==void 0:r.data.customer===void 0))throw new c("INVALID_REQUEST","Invalid current Funnel start");let s=r.data,n=T.safeParse(await i.request("funnels",s));if(!n.success||!n.data.runToken)throw new c("INVALID_RESPONSE","Funnel start credentials are missing");let u=n.data;if(u.run.source.id!==s.funnelId||u.run.locale!==(s.locale??"en")||!O(u.run.parameters,s.parameters??{})||(s.customer?!u.customerId||s.customer.type==="id"&&u.customerId!==s.customer.value:u.customerId!==void 0))throw new c("INVALID_RESPONSE","Funnel start contract changed");return{...u,runToken:u.runToken}}}}export{j as a,H as b,O as c,M as d,X as e,ne as f};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as V}from"./chunk-6X42DWOM.js";import{a}from"./chunk-X5UXOLOU.js";import{Ag as oe,hf as re}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";function se(b){let n=b.view;if(!n?.paywall)throw new a("INVALID_REQUEST","The current node is not a Paywall");let A=n.paywall.receiptId,M=n.nodeId,f=n.visit,P=n.paywall.resolution,o=n.paywall.quote,p=n.paywall.operation,U=!1,O=n.paywall.purchaseRequestId,I=null,D=new Map,S=new Map;function R(t){let l=t.run.paywall;if(l?.receiptId===A){if(l.resolution.id!==P.id||l.resolution.offering.id!==P.offering.id)throw new a("INVALID_RESPONSE","The pinned Paywall binding changed");P=l.resolution}if(t.purchase&&t.purchase.receiptId!==A)throw new a("INVALID_RESPONSE","Purchase receipt changed");let u=t.purchase??(l?.receiptId===A?l:null),d=u?.quote??o,r=u?.operation??(d?.operationId===o?.operationId?p:null);if(d&&r&&d.operationId!==r.operationId)throw new a("INVALID_RESPONSE","Purchase operation changed");o=d,(p?.operationId!==r?.operationId||p?.status==="pending"||r?.status==="complete")&&(p=r)}async function m(t,l){if(U)throw new a("IDENTITY_CHANGED","Paywall presentation has closed");let u=D.get(t);if(u){if(JSON.stringify(u.input)!==JSON.stringify(l))throw new a("CONFLICT","A purchase request cannot change its input")}else{let y=b.view;if(!y||y.nodeId!==M||y.visit!==f||y.paywall?.receiptId!==A)throw new a("PRECONDITION_FAILED","The Paywall visit has changed");u={operation:"submit",requestId:t,nodeId:M,visit:f,revision:y.revision,input:l},D.set(t,u)}let d=await b.submit(u),r=Date.now()+3e4;for(;d.run.pendingRequest?.requestId===t&&Date.now()<r&&!U;)await new Promise(y=>setTimeout(y,1e3)),d=await b.resume(t);if(d.run.pendingRequest?.requestId===t)throw new a("COMMAND_PENDING","The purchase command is still pending; retry the original request",202);R(d)}async function E(t){if(!o)throw new a("INVALID_REQUEST","A quoted purchase is required");let l=`${t}:${o.operationId}`,u=S.get(l);if(u||(u=crypto.randomUUID(),S.set(l,u)),await m(u,{type:t==="confirm"?"paywall_confirm":"paywall_cancel",operationId:o.operationId}),!p)throw new a("INVALID_RESPONSE","The accepted purchase result is missing");return structuredClone(p)}return{get view(){return structuredClone(P)},get quote(){return o?structuredClone(o):null},get operation(){return p?structuredClone(p):null},get webViewUrl(){return b.webViewUrl},async refresh(){return R(await b.get()),structuredClone(P)},preview(t){if(O&&O!==t.requestId&&(!p||p.status==="pending"))return Promise.reject(new a("COMMAND_PENDING","Retry the original purchase before starting another"));if(O===t.requestId&&I)return I;let l=P.document.buttons[t.actionId],u=l?.type==="checkout"?re(l.product,t.selection,P.capabilities):null;if(!u)return Promise.reject(new a("PRODUCT_UNAVAILABLE","Choose an available Product in this purchase area"));O=t.requestId;let d=(async()=>{if(await m(t.requestId,{type:"paywall_quote",actionId:t.actionId,productVersionId:u,...t.offerId?{offerId:t.offerId}:{},...t.nativeOffer?{nativeOffer:t.nativeOffer}:{}}),!o)throw new a("INVALID_RESPONSE","The accepted quote is missing");return structuredClone(o)})();return I=d,d.then(()=>{I===d&&(I=null)},r=>{I===d&&(I=null),r instanceof a&&r.status!==void 0&&r.status<500&&![401,425].includes(r.status)&&(O=null)}),d},confirm:()=>E("confirm"),cancel:()=>E("cancel"),async read(){if(!o)throw new a("INVALID_REQUEST","A quoted purchase is required");if(R(await b.get(void 0,{receiptId:A,operationId:o.operationId})),!p)throw new a("INVALID_RESPONSE","The current purchase result is missing");return structuredClone(p)},destroy(){U=!0,D.clear(),S.clear()}}}async function ve(b,n){let{mountScreenPreview:A}=await import("./popup.js"),{showPaywall:M}=await import("./paywall-4JTI7QAB.js"),f=b.ownerDocument,P=f.activeElement,o=f.createElement("section"),p=f.createElement("div"),U=f.createElement("div"),O=f.createElement("p"),I=f.createElement("p"),D=f.createElement("button"),S=f.createElement("button"),R=f.createElement("button"),m=f.createElement("dialog");o.dataset.indianaFunnel="",o.setAttribute("aria-busy","false"),o.style.cssText="box-sizing:border-box;width:100%;min-width:0;font:14px/1.5 system-ui,sans-serif;color:#172033;background:#fff",U.style.cssText="display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding:12px 20px",O.setAttribute("role","status"),I.setAttribute("role","alert"),I.hidden=!0,D.type=S.type=R.type="button",U.append(D,O,I,R,S),o.append(p,U),b.append(o);let E=null,t=null,l=null,u="",d="",r=!1,y=0,j=!1,ee="",k=null,Y=Promise.resolve(),L=null,$=null,Q={},X=new Map,ne=new Set,z=new Set,W=new Set,_={},x=(e,i=null)=>{r||($=i,I.textContent=e instanceof Error?e.message:"Request failed",I.hidden=!1,R.hidden=n.client.pendingCommand===null,V(n.onError,e))};function T(){let e=n.client.view;if(!e)throw new a("INVALID_REQUEST","No current Run is available");return{requestId:crypto.randomUUID(),nodeId:e.nodeId,visit:e.visit,revision:e.revision}}async function F(e,i=!1){if(!(y&&!i||r)){y++,o.setAttribute("aria-busy","true"),I.hidden=!0,$=null;try{let h=await e();r||await H(n.client.view??h.run)}catch(h){x(h,n.client.pendingCommand?.requestId??null)}finally{y=Math.max(0,y-1),o.setAttribute("aria-busy",String(y>0)),r||(R.hidden=n.client.pendingCommand===null,D.disabled=y>0||!!n.client.pendingCommand||!n.client.view?.canBack)}}}function te(e){if(ne.has(e)||z.has(e)||r)return;z.add(e);let i=async()=>{if(r||u!==e){z.delete(e);return}if(y||n.client.pendingCommand){setTimeout(()=>{i()},250);return}try{await n.client.submit({operation:"shown",...T()}),ne.add(e)}catch(h){x(h)}finally{z.delete(e)}};i()}function Z(){k&&clearTimeout(k),!(r||!l||!["running","waiting"].includes(l.status))&&(k=setTimeout(()=>{k=null,ie().finally(Z)},l.pendingRequest?1500:5e3))}async function ie(){if(!(r||j||y)){j=!0;try{let e=await n.client.get();r||await H(n.client.view??e.run)}catch(e){x(e)}finally{j=!1}}}async function ae(e){let i=n.client.view,h=i?.screen,s=h?.customerData.nodes[e.nodeId];if(!i||!h||!s)return;if(!["refresh","next","previous","filter","sources_next","sources_previous"].includes(e.action)){let C=E?.document,q=C?oe(C,e.nodeId):null,K=q?.type==="customer_data"?q.data.outputs?.[e.action]:void 0;K&&h.outputs.includes(K)?await F(()=>n.client.submit({operation:"submit",...T(),input:{type:"screen",output:K,answers:_,selection:e.value?{[e.nodeId]:e.value}:{}}})):await n.onCustomerDataIntent?.(e,i);return}let c=e.action.startsWith("sources_")?s.resources.find(C=>C.key===e.value):null;if(e.action.startsWith("sources_")&&!c)throw new a("INVALID_REQUEST","Choose a current resource");let N=`${i.visit}:${e.nodeId}:${c?.key??""}`,w=X.get(N)??[null],v=Q[e.nodeId]??{page:1,after:null,filter:"all",...c?{resourceKey:c.key}:{}};if(e.action==="filter"){let C=e.value;if(!C||!["all","purchase","refund","source","usage","debt","settlement"].includes(C))throw new a("INVALID_REQUEST","Unknown data filter");v={page:1,after:null,filter:C},w.splice(0,w.length,null)}else if(e.action==="next"||e.action==="sources_next"){let C=c?.sources.at(-1),q=c?C?{kind:"ledger",cursor:{at:C.detail[0],id:C.id,type:"source"}}:null:h.dataCursors[e.nodeId];if(!q||!c&&!s.hasNext)return;w[v.page]=q,v={...v,page:v.page+1,after:q}}else if(e.action==="previous"||e.action==="sources_previous"){if(v.page<=1)return;v={...v,page:v.page-1,after:w[v.page-2]??null}}X.set(N,w),Q={...Q,[e.nodeId]:v},await F(()=>n.client.get({nodeId:i.nodeId,visit:i.visit,revision:i.revision,components:Q}))}function le(e){let i=e.screen?.presentation;if(!i||i.type==="inline"){m.open&&m.close(),o.parentElement!==b&&b.append(o);return}o.parentElement!==m&&(m.append(o),b.append(m));let h={sm:420,md:640,lg:900};m.style.cssText=`padding:0;border:0;max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);overflow:auto;width:${"size"in i?h[i.size]+"px":"100vw"}`,m.setAttribute("aria-label",E?.document?.name??(e.screen?.content.type==="document"?e.screen.content.document.name:"Funnel")),m.open||m.showModal()}async function ue(e){if(r)return;l=e,$&&n.client.pendingCommand?.requestId!==$&&(I.hidden=!0,$=null);let i=e.locale.startsWith("zh");if(D.textContent=i?"\u8FD4\u56DE":"Back",S.textContent=i?"\u5173\u95ED":"Close",R.textContent=i?"\u91CD\u8BD5":"Retry",D.disabled=y>0||!!n.client.pendingCommand||!e.canBack,R.hidden=n.client.pendingCommand===null,O.textContent=e.pendingRequest?i?"\u6B63\u5728\u5904\u7406":"Processing":e.instruction?.type==="wait"?i?"\u7B49\u5F85\u4E2D":"Waiting":"",ee!==`${e.revision}:${e.visit}:${e.status}:${e.stopped}`&&(ee=`${e.revision}:${e.visit}:${e.status}:${e.stopped}`,V(n.onState,structuredClone(e))),e.stopped){E?.destroy(),E=null,t?.destroy(),t=null,p.replaceChildren(),u="",d="",m.open&&m.close(),o.hidden=!0,Z();return}o.hidden=!1;let h=e.screen||e.paywall?`${e.id}:${e.nodeId}:${e.visit}`:"";if(h!==u&&(E?.destroy(),E=null,t?.destroy(),t=null,p.replaceChildren(),u=h,d="",_={...e.answers},Q={},X.clear()),le(e),e.screen){let g=e.screen.content;E||(E=A(p,{mode:"live",...g.type==="render"?{screenUrl:de(g.url)}:{rendererUrl:n.client.webViewUrl,title:g.document.name},onAction(w,J={},v={}){_={..._,...v},F(()=>n.client.submit({operation:"submit",...T(),input:{type:"screen",output:w,answers:_,selection:J}}))},onAnswers:w=>{_={..._,...w}},onCustomerDataIntent:w=>{ae(w).catch(x)},onEscape:()=>{B()},onError:w=>x(new Error(w)),onRendered:()=>te(h)}));let c={capabilities:e.screen.capabilities,customerData:e.screen.customerData,parameters:e.parameters,serverInput:{bindings:e.screen.inputs,answers:_}},N=JSON.stringify([g,e.locale,c.capabilities,c.customerData,c.parameters,e.screen.inputs]);N!==d&&(E.update(g.type==="document"?g.document:null,e.locale,c),d=N),await E.ready}else if(e.paywall&&!t){let g=await M(p,{start:async()=>se(n.client),onPurchase:n.onPurchase,onCheckoutUrl:n.onCheckoutUrl,resolveOfferId:n.resolveOfferId,onEvent:n.onEvent,onOpenUrl:c=>n.onOpenUrl?n.onOpenUrl({receiptId:e.paywall.receiptId,url:c,openIn:"same_window"}):f.defaultView?.location.assign(c),onAction:async c=>{let N=await n.client.submit({operation:"submit",requestId:crypto.randomUUID(),nodeId:e.nodeId,visit:e.visit,revision:e.revision,input:{type:"screen",output:c,answers:{}}});await H(n.client.view??N.run)},onError:x,onDismiss:()=>{!r&&n.client.view?.visit===e.visit&&B()}});r?g.host?.destroy():t=g.host,te(h)}let s=e.instruction;if(s&&["open_url","event"].includes(s.type)&&!W.has(s.receiptId)){let g=f.createElement("button");g.type="button",g.textContent=s.type==="open_url"?`${i?"\u524D\u5F80":"Continue to"} ${new URL(s.url).host}`:i?"\u7EE7\u7EED":"Continue",g.onclick=()=>{let c=T(),N=s.type==="open_url"&&!n.onOpenUrl&&s.openIn==="new_window"?ce(s.url):null;F(async()=>{let w="success";if(s.type==="open_url")if(n.onOpenUrl)try{w=await n.onOpenUrl({receiptId:s.receiptId,url:s.url,openIn:s.openIn})===!1?"failed":"opened"}catch(v){V(n.onError,v),w="failed"}else w=s.openIn==="new_window"&&!N?"failed":"opened";if(s.type==="event"){if(!n.onEvent)throw new a("EVENT_HANDLER_REQUIRED","Provide the event handler");await n.onEvent(s.event)}if(r||n.client.view?.nodeId!==c.nodeId||n.client.view.visit!==c.visit)throw new a("PRECONDITION_FAILED","The client action visit changed");let J=await n.client.submit({operation:"submit",...c,input:{type:"client_action",receiptId:s.receiptId,outcome:w}});return W.add(s.receiptId),s.type==="open_url"&&!n.onOpenUrl&&s.openIn==="same_window"&&f.defaultView?.location.assign(s.url),J})},p.replaceChildren(g)}!e.pendingRequest&&e.status==="completed"&&!W.has(`complete:${e.id}`)&&(W.add(`complete:${e.id}`),V(n.onComplete,structuredClone(e))),Z()}function ce(e){let i=f.defaultView?.open(e,"_blank")??null;return i&&(i.opener=null),i}function de(e){return n.client.screenUrl?n.client.screenUrl(e):new URL(e,f.defaultView?.location.href).href}function H(e){return Y=Y.catch(()=>{}).then(()=>ue(e)),Y}let pe=n.client.subscribe(e=>{H(e).catch(x)});function B(){return L||(r?Promise.resolve():n.client.view&&!["running","waiting"].includes(n.client.view.status)?(G(),Promise.resolve()):(L=F(()=>n.client.submit({operation:"close",...T()}),!0).then(()=>{n.client.view?.status==="closed"&&G()}).finally(()=>{L=null}),L))}function G(){r||(r=!0,k&&clearTimeout(k),pe(),E?.destroy(),t?.destroy(),m.close(),m.remove(),o.remove(),P instanceof HTMLElement&&P.isConnected&&P.focus(),V(n.onDismiss,l?structuredClone(l):null))}D.onclick=()=>{F(()=>n.client.submit({operation:"back",...T()}))},S.onclick=()=>{B()},R.onclick=()=>{F(()=>n.client.retry())},m.addEventListener("cancel",e=>{e.preventDefault(),B()});try{let e=await n.client.get();await H(n.client.view??e.run)}catch(e){throw G(),e}return{destroy:G,refresh:ie}}export{ve as showFunnelRun};
|
|
1
|
+
import{a as V}from"./chunk-6X42DWOM.js";import{a}from"./chunk-CRJJ4EA2.js";import{Ag as oe,hf as re}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";function se(b){let n=b.view;if(!n?.paywall)throw new a("INVALID_REQUEST","The current node is not a Paywall");let A=n.paywall.receiptId,M=n.nodeId,f=n.visit,P=n.paywall.resolution,o=n.paywall.quote,p=n.paywall.operation,U=!1,O=n.paywall.purchaseRequestId,I=null,D=new Map,S=new Map;function R(t){let l=t.run.paywall;if(l?.receiptId===A){if(l.resolution.id!==P.id||l.resolution.offering.id!==P.offering.id)throw new a("INVALID_RESPONSE","The pinned Paywall binding changed");P=l.resolution}if(t.purchase&&t.purchase.receiptId!==A)throw new a("INVALID_RESPONSE","Purchase receipt changed");let u=t.purchase??(l?.receiptId===A?l:null),d=u?.quote??o,r=u?.operation??(d?.operationId===o?.operationId?p:null);if(d&&r&&d.operationId!==r.operationId)throw new a("INVALID_RESPONSE","Purchase operation changed");o=d,(p?.operationId!==r?.operationId||p?.status==="pending"||r?.status==="complete")&&(p=r)}async function m(t,l){if(U)throw new a("IDENTITY_CHANGED","Paywall presentation has closed");let u=D.get(t);if(u){if(JSON.stringify(u.input)!==JSON.stringify(l))throw new a("CONFLICT","A purchase request cannot change its input")}else{let y=b.view;if(!y||y.nodeId!==M||y.visit!==f||y.paywall?.receiptId!==A)throw new a("PRECONDITION_FAILED","The Paywall visit has changed");u={operation:"submit",requestId:t,nodeId:M,visit:f,revision:y.revision,input:l},D.set(t,u)}let d=await b.submit(u),r=Date.now()+3e4;for(;d.run.pendingRequest?.requestId===t&&Date.now()<r&&!U;)await new Promise(y=>setTimeout(y,1e3)),d=await b.resume(t);if(d.run.pendingRequest?.requestId===t)throw new a("COMMAND_PENDING","The purchase command is still pending; retry the original request",202);R(d)}async function E(t){if(!o)throw new a("INVALID_REQUEST","A quoted purchase is required");let l=`${t}:${o.operationId}`,u=S.get(l);if(u||(u=crypto.randomUUID(),S.set(l,u)),await m(u,{type:t==="confirm"?"paywall_confirm":"paywall_cancel",operationId:o.operationId}),!p)throw new a("INVALID_RESPONSE","The accepted purchase result is missing");return structuredClone(p)}return{get view(){return structuredClone(P)},get quote(){return o?structuredClone(o):null},get operation(){return p?structuredClone(p):null},get webViewUrl(){return b.webViewUrl},async refresh(){return R(await b.get()),structuredClone(P)},preview(t){if(O&&O!==t.requestId&&(!p||p.status==="pending"))return Promise.reject(new a("COMMAND_PENDING","Retry the original purchase before starting another"));if(O===t.requestId&&I)return I;let l=P.document.buttons[t.actionId],u=l?.type==="checkout"?re(l.product,t.selection,P.capabilities):null;if(!u)return Promise.reject(new a("PRODUCT_UNAVAILABLE","Choose an available Product in this purchase area"));O=t.requestId;let d=(async()=>{if(await m(t.requestId,{type:"paywall_quote",actionId:t.actionId,productVersionId:u,...t.offerId?{offerId:t.offerId}:{},...t.nativeOffer?{nativeOffer:t.nativeOffer}:{}}),!o)throw new a("INVALID_RESPONSE","The accepted quote is missing");return structuredClone(o)})();return I=d,d.then(()=>{I===d&&(I=null)},r=>{I===d&&(I=null),r instanceof a&&r.status!==void 0&&r.status<500&&![401,425].includes(r.status)&&(O=null)}),d},confirm:()=>E("confirm"),cancel:()=>E("cancel"),async read(){if(!o)throw new a("INVALID_REQUEST","A quoted purchase is required");if(R(await b.get(void 0,{receiptId:A,operationId:o.operationId})),!p)throw new a("INVALID_RESPONSE","The current purchase result is missing");return structuredClone(p)},destroy(){U=!0,D.clear(),S.clear()}}}async function ve(b,n){let{mountScreenPreview:A}=await import("./popup.js"),{showPaywall:M}=await import("./paywall-Y3FIG43H.js"),f=b.ownerDocument,P=f.activeElement,o=f.createElement("section"),p=f.createElement("div"),U=f.createElement("div"),O=f.createElement("p"),I=f.createElement("p"),D=f.createElement("button"),S=f.createElement("button"),R=f.createElement("button"),m=f.createElement("dialog");o.dataset.indianaFunnel="",o.setAttribute("aria-busy","false"),o.style.cssText="box-sizing:border-box;width:100%;min-width:0;font:14px/1.5 system-ui,sans-serif;color:#172033;background:#fff",U.style.cssText="display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding:12px 20px",O.setAttribute("role","status"),I.setAttribute("role","alert"),I.hidden=!0,D.type=S.type=R.type="button",U.append(D,O,I,R,S),o.append(p,U),b.append(o);let E=null,t=null,l=null,u="",d="",r=!1,y=0,j=!1,ee="",k=null,Y=Promise.resolve(),L=null,$=null,Q={},X=new Map,ne=new Set,z=new Set,W=new Set,_={},x=(e,i=null)=>{r||($=i,I.textContent=e instanceof Error?e.message:"Request failed",I.hidden=!1,R.hidden=n.client.pendingCommand===null,V(n.onError,e))};function T(){let e=n.client.view;if(!e)throw new a("INVALID_REQUEST","No current Run is available");return{requestId:crypto.randomUUID(),nodeId:e.nodeId,visit:e.visit,revision:e.revision}}async function F(e,i=!1){if(!(y&&!i||r)){y++,o.setAttribute("aria-busy","true"),I.hidden=!0,$=null;try{let h=await e();r||await H(n.client.view??h.run)}catch(h){x(h,n.client.pendingCommand?.requestId??null)}finally{y=Math.max(0,y-1),o.setAttribute("aria-busy",String(y>0)),r||(R.hidden=n.client.pendingCommand===null,D.disabled=y>0||!!n.client.pendingCommand||!n.client.view?.canBack)}}}function te(e){if(ne.has(e)||z.has(e)||r)return;z.add(e);let i=async()=>{if(r||u!==e){z.delete(e);return}if(y||n.client.pendingCommand){setTimeout(()=>{i()},250);return}try{await n.client.submit({operation:"shown",...T()}),ne.add(e)}catch(h){x(h)}finally{z.delete(e)}};i()}function Z(){k&&clearTimeout(k),!(r||!l||!["running","waiting"].includes(l.status))&&(k=setTimeout(()=>{k=null,ie().finally(Z)},l.pendingRequest?1500:5e3))}async function ie(){if(!(r||j||y)){j=!0;try{let e=await n.client.get();r||await H(n.client.view??e.run)}catch(e){x(e)}finally{j=!1}}}async function ae(e){let i=n.client.view,h=i?.screen,s=h?.customerData.nodes[e.nodeId];if(!i||!h||!s)return;if(!["refresh","next","previous","filter","sources_next","sources_previous"].includes(e.action)){let C=E?.document,q=C?oe(C,e.nodeId):null,K=q?.type==="customer_data"?q.data.outputs?.[e.action]:void 0;K&&h.outputs.includes(K)?await F(()=>n.client.submit({operation:"submit",...T(),input:{type:"screen",output:K,answers:_,selection:e.value?{[e.nodeId]:e.value}:{}}})):await n.onCustomerDataIntent?.(e,i);return}let c=e.action.startsWith("sources_")?s.resources.find(C=>C.key===e.value):null;if(e.action.startsWith("sources_")&&!c)throw new a("INVALID_REQUEST","Choose a current resource");let N=`${i.visit}:${e.nodeId}:${c?.key??""}`,w=X.get(N)??[null],v=Q[e.nodeId]??{page:1,after:null,filter:"all",...c?{resourceKey:c.key}:{}};if(e.action==="filter"){let C=e.value;if(!C||!["all","purchase","refund","source","usage","debt","settlement"].includes(C))throw new a("INVALID_REQUEST","Unknown data filter");v={page:1,after:null,filter:C},w.splice(0,w.length,null)}else if(e.action==="next"||e.action==="sources_next"){let C=c?.sources.at(-1),q=c?C?{kind:"ledger",cursor:{at:C.detail[0],id:C.id,type:"source"}}:null:h.dataCursors[e.nodeId];if(!q||!c&&!s.hasNext)return;w[v.page]=q,v={...v,page:v.page+1,after:q}}else if(e.action==="previous"||e.action==="sources_previous"){if(v.page<=1)return;v={...v,page:v.page-1,after:w[v.page-2]??null}}X.set(N,w),Q={...Q,[e.nodeId]:v},await F(()=>n.client.get({nodeId:i.nodeId,visit:i.visit,revision:i.revision,components:Q}))}function le(e){let i=e.screen?.presentation;if(!i||i.type==="inline"){m.open&&m.close(),o.parentElement!==b&&b.append(o);return}o.parentElement!==m&&(m.append(o),b.append(m));let h={sm:420,md:640,lg:900};m.style.cssText=`padding:0;border:0;max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);overflow:auto;width:${"size"in i?h[i.size]+"px":"100vw"}`,m.setAttribute("aria-label",E?.document?.name??(e.screen?.content.type==="document"?e.screen.content.document.name:"Funnel")),m.open||m.showModal()}async function ue(e){if(r)return;l=e,$&&n.client.pendingCommand?.requestId!==$&&(I.hidden=!0,$=null);let i=e.locale.startsWith("zh");if(D.textContent=i?"\u8FD4\u56DE":"Back",S.textContent=i?"\u5173\u95ED":"Close",R.textContent=i?"\u91CD\u8BD5":"Retry",D.disabled=y>0||!!n.client.pendingCommand||!e.canBack,R.hidden=n.client.pendingCommand===null,O.textContent=e.pendingRequest?i?"\u6B63\u5728\u5904\u7406":"Processing":e.instruction?.type==="wait"?i?"\u7B49\u5F85\u4E2D":"Waiting":"",ee!==`${e.revision}:${e.visit}:${e.status}:${e.stopped}`&&(ee=`${e.revision}:${e.visit}:${e.status}:${e.stopped}`,V(n.onState,structuredClone(e))),e.stopped){E?.destroy(),E=null,t?.destroy(),t=null,p.replaceChildren(),u="",d="",m.open&&m.close(),o.hidden=!0,Z();return}o.hidden=!1;let h=e.screen||e.paywall?`${e.id}:${e.nodeId}:${e.visit}`:"";if(h!==u&&(E?.destroy(),E=null,t?.destroy(),t=null,p.replaceChildren(),u=h,d="",_={...e.answers},Q={},X.clear()),le(e),e.screen){let g=e.screen.content;E||(E=A(p,{mode:"live",...g.type==="render"?{screenUrl:de(g.url)}:{rendererUrl:n.client.webViewUrl,title:g.document.name},onAction(w,J={},v={}){_={..._,...v},F(()=>n.client.submit({operation:"submit",...T(),input:{type:"screen",output:w,answers:_,selection:J}}))},onAnswers:w=>{_={..._,...w}},onCustomerDataIntent:w=>{ae(w).catch(x)},onEscape:()=>{B()},onError:w=>x(new Error(w)),onRendered:()=>te(h)}));let c={capabilities:e.screen.capabilities,customerData:e.screen.customerData,parameters:e.parameters,serverInput:{bindings:e.screen.inputs,answers:_}},N=JSON.stringify([g,e.locale,c.capabilities,c.customerData,c.parameters,e.screen.inputs]);N!==d&&(E.update(g.type==="document"?g.document:null,e.locale,c),d=N),await E.ready}else if(e.paywall&&!t){let g=await M(p,{start:async()=>se(n.client),onPurchase:n.onPurchase,onCheckoutUrl:n.onCheckoutUrl,resolveOfferId:n.resolveOfferId,onEvent:n.onEvent,onOpenUrl:c=>n.onOpenUrl?n.onOpenUrl({receiptId:e.paywall.receiptId,url:c,openIn:"same_window"}):f.defaultView?.location.assign(c),onAction:async c=>{let N=await n.client.submit({operation:"submit",requestId:crypto.randomUUID(),nodeId:e.nodeId,visit:e.visit,revision:e.revision,input:{type:"screen",output:c,answers:{}}});await H(n.client.view??N.run)},onError:x,onDismiss:()=>{!r&&n.client.view?.visit===e.visit&&B()}});r?g.host?.destroy():t=g.host,te(h)}let s=e.instruction;if(s&&["open_url","event"].includes(s.type)&&!W.has(s.receiptId)){let g=f.createElement("button");g.type="button",g.textContent=s.type==="open_url"?`${i?"\u524D\u5F80":"Continue to"} ${new URL(s.url).host}`:i?"\u7EE7\u7EED":"Continue",g.onclick=()=>{let c=T(),N=s.type==="open_url"&&!n.onOpenUrl&&s.openIn==="new_window"?ce(s.url):null;F(async()=>{let w="success";if(s.type==="open_url")if(n.onOpenUrl)try{w=await n.onOpenUrl({receiptId:s.receiptId,url:s.url,openIn:s.openIn})===!1?"failed":"opened"}catch(v){V(n.onError,v),w="failed"}else w=s.openIn==="new_window"&&!N?"failed":"opened";if(s.type==="event"){if(!n.onEvent)throw new a("EVENT_HANDLER_REQUIRED","Provide the event handler");await n.onEvent(s.event)}if(r||n.client.view?.nodeId!==c.nodeId||n.client.view.visit!==c.visit)throw new a("PRECONDITION_FAILED","The client action visit changed");let J=await n.client.submit({operation:"submit",...c,input:{type:"client_action",receiptId:s.receiptId,outcome:w}});return W.add(s.receiptId),s.type==="open_url"&&!n.onOpenUrl&&s.openIn==="same_window"&&f.defaultView?.location.assign(s.url),J})},p.replaceChildren(g)}!e.pendingRequest&&e.status==="completed"&&!W.has(`complete:${e.id}`)&&(W.add(`complete:${e.id}`),V(n.onComplete,structuredClone(e))),Z()}function ce(e){let i=f.defaultView?.open(e,"_blank")??null;return i&&(i.opener=null),i}function de(e){return n.client.screenUrl?n.client.screenUrl(e):new URL(e,f.defaultView?.location.href).href}function H(e){return Y=Y.catch(()=>{}).then(()=>ue(e)),Y}let pe=n.client.subscribe(e=>{H(e).catch(x)});function B(){return L||(r?Promise.resolve():n.client.view&&!["running","waiting"].includes(n.client.view.status)?(G(),Promise.resolve()):(L=F(()=>n.client.submit({operation:"close",...T()}),!0).then(()=>{n.client.view?.status==="closed"&&G()}).finally(()=>{L=null}),L))}function G(){r||(r=!0,k&&clearTimeout(k),pe(),E?.destroy(),t?.destroy(),m.close(),m.remove(),o.remove(),P instanceof HTMLElement&&P.isConnected&&P.focus(),V(n.onDismiss,l?structuredClone(l):null))}D.onclick=()=>{F(()=>n.client.submit({operation:"back",...T()}))},S.onclick=()=>{B()},R.onclick=()=>{F(()=>n.client.retry())},m.addEventListener("cancel",e=>{e.preventDefault(),B()});try{let e=await n.client.get();await H(n.client.view??e.run)}catch(e){throw G(),e}return{destroy:G,refresh:ie}}export{ve as showFunnelRun};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as k,c as j,d as Z,e as $,f as Q}from"./chunk-PTWRGCVW.js";import{a as r,b}from"./chunk-X5UXOLOU.js";import{Ka as H,La as K,Ma as Y,ok as V,qi as o,zk as B}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";var M=s=>new TextEncoder().encode(JSON.stringify(s)).length;function z(s,y,n){let a=0,p=[],u=null,d,t=new Set;function e(){if(!y())throw new r("NOT_IDENTIFIED","Call identify before using Features or events")}function m(){d||!p.length||(d=setTimeout(()=>{d=void 0,F().catch(()=>{}).finally(m)},5e3),typeof d=="object"&&"unref"in d&&d.unref())}function f(i,v={}){e(),E();let g=o.trackEvents.request.parse({events:[{eventUuid:crypto.randomUUID(),timestamp:new Date().toISOString(),name:i,properties:v}]}).events[0];if(M({events:[g]})>6e4)throw new r("INVALID_REQUEST","Event exceeds the delivery size limit");if(p.length>=500)throw new r("EVENT_QUEUE_FULL","Flush pending events before tracking more");p.push(structuredClone(g)),m()}async function F(i=!1){if(e(),u)return u;let v=a,g=(async()=>{let P={inserted:0,duplicates:0,rejected:0},N=p.length;for(;N&&v===a;){let R=[];for(let T of p.slice(0,Math.min(N,100))){if(R.length&&M({events:[...R,T]})>6e4)break;R.push(T)}let A=o.trackEvents,C=A.response.parse(await s(A.path,A.request.parse({events:R}),A.method,{keepalive:i}));if(v!==a)throw new r("IDENTITY_CHANGED","Event identity changed during delivery");if(C.inserted+C.duplicates+C.rejected!==R.length)throw new r("INVALID_RESPONSE","Incomplete event acknowledgement");p.splice(0,R.length),N-=R.length,P.inserted+=C.inserted,P.duplicates+=C.duplicates,P.rejected+=C.rejected}return P})();u=g;try{return await g}finally{u===g&&(u=null)}}async function c(i={}){e();let v=a,g=!1,P=async()=>{if(g||v!==a)throw new r("IDENTITY_CHANGED","Feature identity changed");let h=o.getFeatures,I=h.response.parse(await s(h.path,h.request.parse({}),h.method));if(v!==a)throw new r("IDENTITY_CHANGED","Feature identity changed");if(n&&(I.scope.projectId!==n.projectId||I.scope.environment!==n.environment))throw new r("INVALID_RESPONSE","Feature response scope changed");return I},N=await P(),R=!0,A,C=h=>{try{i.onError?.(h)}catch{}},T=(h,I)=>{try{f(h,I)}catch(O){C(O)}},S=k({scope:N.scope,attributes:i.attributes,onError:i.onError,load:async()=>R?(R=!1,N.payload):(await P()).payload,evaluateRemote:async h=>{if(v!==a)throw new r("IDENTITY_CHANGED","Feature identity changed");let I=o.evaluateFeatures,O=I.response.parse(await s(I.path,I.request.parse(h),I.method));if(O.scope.projectId!==N.scope.projectId||O.scope.environment!==N.scope.environment)throw new r("INVALID_RESPONSE","Remote Feature response scope changed");return{generation:O.generation,evaluatedAt:O.evaluatedAt,expiresAt:O.expiresAt,features:O.features}},onExperimentViewed:(h,I)=>T("Experiment Viewed",{experimentId:h.key,variationId:I.key}),onFeatureUsage:(h,I)=>T("Feature Evaluated",{feature:h,value:I.value,source:I.source,ruleId:I.ruleId,...I.experimentResult?{variationId:I.experimentResult.key}:{}})}),G=S.refresh;function D(){clearTimeout(A),!(g||v!==a||!S.expiresAt)&&(A=setTimeout(()=>{_().catch(C)},Math.min(2147483647,Math.max(1e3,Date.parse(S.expiresAt)-Date.now()))),typeof A=="object"&&"unref"in A&&A.unref())}async function _(){try{return await G()}finally{D()}}let L=()=>{g||_().catch(C)},J=S.subscribe(D);function q(){g||(g=!0,clearTimeout(A),typeof window<"u"&&window.removeEventListener("focus",L),J(),S.reset(),t.delete(q))}t.add(q);try{await S.init()}catch(h){throw q(),h}return D(),typeof window<"u"&&window.addEventListener("focus",L),Object.assign(S,{refresh:_,destroy:q})}let w;function E(){if(w||typeof document>"u")return;let i=()=>{document.visibilityState==="hidden"&&y()&&p.length&&F(!0).catch(()=>{})};document.addEventListener("visibilitychange",i),w=()=>document.removeEventListener("visibilitychange",i)}return{features:c,track(i,v){return E(),f(i,v)},flush:F,reset(){a++,clearTimeout(d),d=void 0,p=[],u=null;for(let i of t)i();w?.(),w=void 0}}}function x(s){let{customerToken:y,...n}=s;return n}var W=s=>!(s instanceof r)||s.status===void 0||s.status>=500||[401,425].includes(s.status);function U(s){if(!/^gg_fr_[A-Za-z0-9_-]{43}$/.test(s.runToken))throw new r("INVALID_TOKEN","Run credential required");let y=b({...s,timeoutMs:s.timeoutMs??35e3});y.identify(s.runToken);let n,a=null,p=0,u=null,d=null,t=new Set;async function e(c,w){let E=p,i=B.parse(await y.request("funnels",V.parse(c)));if(E!==p)throw new r("IDENTITY_CHANGED","Run identity changed during the request");if(i.runToken&&i.runToken!==s.runToken)throw new r("INVALID_RESPONSE","Run credential changed");if(a&&(i.run.id!==a.id||i.run.source.type!==a.source.type||i.run.source.id!==a.source.id||i.run.source.versionId!==a.source.versionId||i.run.locale!==a.locale||!j(i.run.parameters,a.parameters)))throw new r("INVALID_RESPONSE","Run version changed");let v=w?.(i)??!1;if(!a||i.run.revision>=a.revision)a=i.run;else if(!v)return i;if(a)for(let g of t)try{g(structuredClone(a))}catch{}return i}async function m(){if(!u)throw new r("INVALID_REQUEST","No command is pending");let c=u,w=p,E={...u,...n?{customerToken:n}:{}};try{return await e(E,i=>w===p&&u===c&&i.run.pendingRequest?.requestId!==c.requestId?(u=null,!0):!1)}catch(i){throw w===p&&u===c&&!W(i)&&(u=null),i}}function f(c){let w=V.parse(c);if(w.operation==="start"||w.operation==="get")throw new r("INVALID_REQUEST","Mutation required");if(w.operation==="close"&&u?.operation!=="close"&&(u=null),u){if(JSON.stringify(x(u))!==JSON.stringify(x(w)))throw new r("COMMAND_PENDING","Retry the original command before sending another");if(d)return d}else u=w;let E=m();return d=E,E.then(()=>{d===E&&(d=null)},()=>{d===E&&(d=null)}),E}return{get view(){return a?structuredClone(a):null},get pendingCommand(){return u?structuredClone(x(u)):null},get webViewUrl(){return y.webViewUrl()},screenUrl(c){return y.screenUrl(c)},async get(c,w){return e({operation:"get",...c?{data:c}:{},...w?{purchase:w}:{},...n?{customerToken:n}:{}})},resume(c=a?.pendingRequest?.requestId){return c?u?.requestId===c?f(u):f({operation:"resume",requestId:c}):Promise.reject(new r("INVALID_REQUEST","No interrupted command is available"))},submit(c){return f(c)},retry(){return d||(u?f(u):Promise.reject(new r("INVALID_REQUEST","No command is pending")))},identify(c){if(!/^gg_ct_[A-Za-z0-9_-]{43}$/.test(c))throw new r("INVALID_TOKEN","Customer credential required");p++,n=c,y.identify(s.runToken)},subscribe(c){return t.add(c),()=>t.delete(c)},reset(){p++,n=void 0,a=null,u=null,d=null,y.reset(),t.clear()}}}function X(s){if(!/^gg_ct_[A-Za-z0-9_-]{32,128}$/.test(s.customerToken))throw new r("INVALID_TOKEN","A customer credential is required");if(!s.scope)throw new r("INVALID_REQUEST","An explicit App and environment scope is required");let y=Q({...s,scope:s.scope,apiKey:s.customerToken});return{async start(n){let a=await y.start(n),p=U({...s,runToken:a.runToken});return p.identify(s.customerToken),{...a,controller:p}}}}function l(s){if(s!==null&&typeof s=="object"&&"customerId"in s)throw new r("INVALID_REQUEST","Customer requests use the verified session identity")}function we(s){let y=b(s),n=y.request,a=!1,p=z(n,()=>a,s.scope),u=new Set,d=t=>{for(let e of u)try{e(t)}catch{}};return{async features(t={}){return p.features(t)},track(t,e){return p.track(t,e)},flush(){return p.flush()},async setupPayment(t){l(t);let e=o.setupPayment;return e.response.parse(await n(e.path,e.request.parse(t)))},async readPaymentSetup(t){l(t);let e=o.readPaymentSetup;return e.response.parse(await n(e.path,e.request.parse(t)))},async previewUpdate(t){l(t);let e=o.previewUpdate;return e.response.parse(await n(e.path,e.request.parse(t)))},async update(t){l(t);let e=o.update;return e.response.parse(await n(e.path,e.request.parse(t)))},async readSubscriptionUpdate(t){l(t);let e=o.readSubscriptionUpdate;return e.response.parse(await n(e.path,e.request.parse(t)))},async restoreNativePurchase(t){l(t);let e=o.restoreNativePurchase;return e.response.parse(await n(e.path,e.request.parse(t)))},async previewAttach(t){l(t);let e=o.previewAttach;return e.response.parse(await n(e.path,e.request.parse(t)))},async attach(t){l(t);let e=o.attach;return e.response.parse(await n(e.path,e.request.parse(t)))},async readSubscriptionOperation(t){l(t);let e=o.readSubscriptionOperation;return e.response.parse(await n(e.path,e.request.parse(t)))},async checkEntitlement(t){l(t);let e=o.checkEntitlement;return e.response.parse(await n(e.path,e.request.parse(t)))},async resolvePaywall(t){l(t);let e=o.resolvePaywall;return e.response.parse(await n(e.path,e.request.parse(t)))},async resolveOffering(t){l(t);let e=o.resolveOffering;return e.response.parse(await n(e.path,e.request.parse(t)))},async readHoldings(t={}){let e=o.readHoldings;return e.response.parse(await n(e.path,e.request.omit({customerId:!0}).parse(t)))},async readLedger(t){let e=o.readLedger;return e.response.parse(await n(e.path,e.request.parse({query:t})))},async readBillingInvoice(t){l(t);let e=o.readBillingInvoice;return e.response.parse(await n(e.path,e.request.parse(t)))},async readCreditStatement(t){l(t);let e=o.readCreditStatement;return e.response.parse(await n(e.path,e.request.parse(t)))},async quoteBalance(t){l(t);let e=o.quoteBalance;return e.response.parse(await n(e.path,e.request.parse({command:t})))},async readBillingControls(t={}){l(t);let e=o.readBillingControls;return e.response.parse(await n(e.path,e.request.parse(t)))},async prepareBillingAuthorization(t){l(t);let e=o.prepareBillingAuthorization;return e.response.parse(await n(e.path,e.request.parse(t)))},async confirmBillingAuthorization(t){l(t);let e=o.confirmBillingAuthorization;return e.response.parse(await n(e.path,e.request.parse(t)))},async setBillingCoupons(t){l(t);let e=o.setBillingCoupons,m=e.request.safeParse(t);if(!m.success)throw new r("INVALID_REQUEST","Invalid billing coupon list");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid billing coupon receipt");return f.data},async revokeBillingAuthorization(t){l(t);let e=o.revokeBillingAuthorization;return e.response.parse(await n(e.path,e.request.parse(t)))},async listBillingInvoices(t={after:null,limit:25}){l(t);let e=o.listBillingInvoices;return e.response.parse(await n(e.path,e.request.parse(t)))},async confirmBillingAdjustment(t){l(t);let e=o.confirmBillingAdjustment;return e.response.parse(await n(e.path,e.request.parse(t)))},subscribeIdentity(t){return u.add(t),()=>{u.delete(t)}},identify(t){if(!/^gg_ct_[A-Za-z0-9_-]{43}$/.test(t))throw new r("INVALID_TOKEN","Browser SDK requires a customer session");p.reset(),y.identify(t),a=!0,d(!0)},reset(){a=!1,p.reset(),y.reset(),d(!1)},async redeemReward(t){l(t);let e=o.redeemReward,m=e.request.safeParse({...t,requestId:t.requestId??crypto.randomUUID()});if(!m.success)throw new r("INVALID_REQUEST","Invalid reward redemption");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid reward receipt");return f.data.redemption},async claimRewardProduct(t){l(t);let e=o.claimRewardProduct,m=e.request.safeParse(t);if(!m.success)throw new r("INVALID_REQUEST","Invalid reward product claim");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid reward product checkout");return f.data.checkout},async createReferralCode(t){l(t);let e=o.createReferralCode,m=e.request.safeParse({...t,requestId:t.requestId??crypto.randomUUID()});if(!m.success)throw new r("INVALID_REQUEST","Invalid referral program");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid referral code");return f.data.referralCode},async redeemCoupon(t,e=crypto.randomUUID()){let m=o.redeemCoupon,f=m.request.safeParse({code:t,requestId:e});if(!f.success)throw new r("INVALID_REQUEST","Invalid coupon code");let F=m.response.safeParse(await n(m.path,f.data));if(!F.success)throw new r("INVALID_RESPONSE","Invalid Coupon receipt");let c=F.data;return{offer:c.offer,reason:c.reason}},async listOffers(){let t=o.listOffers.response.safeParse(await n("offers",{},"GET"));if(!t.success)throw new r("INVALID_RESPONSE","Invalid offers response");return t.data.offers}}}async function Ie(...s){return(await import("./paywall-4JTI7QAB.js")).showPaywall(...s)}async function ye(...s){return(await import("./funnel-runtime-host-OVCJIQRT.js")).showFunnelRun(...s)}export{r as IndianaError,k as createFeatureClient,X as createFunnelClient,U as createFunnelRunController,we as createIndiana,Z as createPaywallSession,$ as evaluateFunnelNode,K as formatCouponDiscount,H as formatCouponMoney,Y as formatCouponTerms,ye as showFunnelRun,Ie as showPaywall};
|
|
1
|
+
import{a as k,c as j,d as Z,e as $,f as Q}from"./chunk-G5ZGWOLJ.js";import{a as r,b}from"./chunk-CRJJ4EA2.js";import{Ka as H,La as K,Ma as Y,ok as V,qi as o,zk as B}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";var M=s=>new TextEncoder().encode(JSON.stringify(s)).length;function z(s,y,n){let a=0,p=[],u=null,d,t=new Set;function e(){if(!y())throw new r("NOT_IDENTIFIED","Call identify before using Features or events")}function m(){d||!p.length||(d=setTimeout(()=>{d=void 0,F().catch(()=>{}).finally(m)},5e3),typeof d=="object"&&"unref"in d&&d.unref())}function f(i,v={}){e(),E();let g=o.trackEvents.request.parse({events:[{eventUuid:crypto.randomUUID(),timestamp:new Date().toISOString(),name:i,properties:v}]}).events[0];if(M({events:[g]})>6e4)throw new r("INVALID_REQUEST","Event exceeds the delivery size limit");if(p.length>=500)throw new r("EVENT_QUEUE_FULL","Flush pending events before tracking more");p.push(structuredClone(g)),m()}async function F(i=!1){if(e(),u)return u;let v=a,g=(async()=>{let P={inserted:0,duplicates:0,rejected:0},N=p.length;for(;N&&v===a;){let R=[];for(let T of p.slice(0,Math.min(N,100))){if(R.length&&M({events:[...R,T]})>6e4)break;R.push(T)}let A=o.trackEvents,C=A.response.parse(await s(A.path,A.request.parse({events:R}),A.method,{keepalive:i}));if(v!==a)throw new r("IDENTITY_CHANGED","Event identity changed during delivery");if(C.inserted+C.duplicates+C.rejected!==R.length)throw new r("INVALID_RESPONSE","Incomplete event acknowledgement");p.splice(0,R.length),N-=R.length,P.inserted+=C.inserted,P.duplicates+=C.duplicates,P.rejected+=C.rejected}return P})();u=g;try{return await g}finally{u===g&&(u=null)}}async function c(i={}){e();let v=a,g=!1,P=async()=>{if(g||v!==a)throw new r("IDENTITY_CHANGED","Feature identity changed");let h=o.getFeatures,I=h.response.parse(await s(h.path,h.request.parse({}),h.method));if(v!==a)throw new r("IDENTITY_CHANGED","Feature identity changed");if(n&&(I.scope.projectId!==n.projectId||I.scope.environment!==n.environment))throw new r("INVALID_RESPONSE","Feature response scope changed");return I},N=await P(),R=!0,A,C=h=>{try{i.onError?.(h)}catch{}},T=(h,I)=>{try{f(h,I)}catch(O){C(O)}},S=k({scope:N.scope,attributes:i.attributes,onError:i.onError,load:async()=>R?(R=!1,N.payload):(await P()).payload,evaluateRemote:async h=>{if(v!==a)throw new r("IDENTITY_CHANGED","Feature identity changed");let I=o.evaluateFeatures,O=I.response.parse(await s(I.path,I.request.parse(h),I.method));if(O.scope.projectId!==N.scope.projectId||O.scope.environment!==N.scope.environment)throw new r("INVALID_RESPONSE","Remote Feature response scope changed");return{generation:O.generation,evaluatedAt:O.evaluatedAt,expiresAt:O.expiresAt,features:O.features}},onExperimentViewed:(h,I)=>T("Experiment Viewed",{experimentId:h.key,variationId:I.key}),onFeatureUsage:(h,I)=>T("Feature Evaluated",{feature:h,value:I.value,source:I.source,ruleId:I.ruleId,...I.experimentResult?{variationId:I.experimentResult.key}:{}})}),G=S.refresh;function D(){clearTimeout(A),!(g||v!==a||!S.expiresAt)&&(A=setTimeout(()=>{_().catch(C)},Math.min(2147483647,Math.max(1e3,Date.parse(S.expiresAt)-Date.now()))),typeof A=="object"&&"unref"in A&&A.unref())}async function _(){try{return await G()}finally{D()}}let L=()=>{g||_().catch(C)},J=S.subscribe(D);function q(){g||(g=!0,clearTimeout(A),typeof window<"u"&&window.removeEventListener("focus",L),J(),S.reset(),t.delete(q))}t.add(q);try{await S.init()}catch(h){throw q(),h}return D(),typeof window<"u"&&window.addEventListener("focus",L),Object.assign(S,{refresh:_,destroy:q})}let w;function E(){if(w||typeof document>"u")return;let i=()=>{document.visibilityState==="hidden"&&y()&&p.length&&F(!0).catch(()=>{})};document.addEventListener("visibilitychange",i),w=()=>document.removeEventListener("visibilitychange",i)}return{features:c,track(i,v){return E(),f(i,v)},flush:F,reset(){a++,clearTimeout(d),d=void 0,p=[],u=null;for(let i of t)i();w?.(),w=void 0}}}function x(s){let{customerToken:y,...n}=s;return n}var W=s=>!(s instanceof r)||s.status===void 0||s.status>=500||[401,425].includes(s.status);function U(s){if(!/^gg_fr_[A-Za-z0-9_-]{43}$/.test(s.runToken))throw new r("INVALID_TOKEN","Run credential required");let y=b({...s,timeoutMs:s.timeoutMs??35e3});y.identify(s.runToken);let n,a=null,p=0,u=null,d=null,t=new Set;async function e(c,w){let E=p,i=B.parse(await y.request("funnels",V.parse(c)));if(E!==p)throw new r("IDENTITY_CHANGED","Run identity changed during the request");if(i.runToken&&i.runToken!==s.runToken)throw new r("INVALID_RESPONSE","Run credential changed");if(a&&(i.run.id!==a.id||i.run.source.type!==a.source.type||i.run.source.id!==a.source.id||i.run.source.versionId!==a.source.versionId||i.run.locale!==a.locale||!j(i.run.parameters,a.parameters)))throw new r("INVALID_RESPONSE","Run version changed");let v=w?.(i)??!1;if(!a||i.run.revision>=a.revision)a=i.run;else if(!v)return i;if(a)for(let g of t)try{g(structuredClone(a))}catch{}return i}async function m(){if(!u)throw new r("INVALID_REQUEST","No command is pending");let c=u,w=p,E={...u,...n?{customerToken:n}:{}};try{return await e(E,i=>w===p&&u===c&&i.run.pendingRequest?.requestId!==c.requestId?(u=null,!0):!1)}catch(i){throw w===p&&u===c&&!W(i)&&(u=null),i}}function f(c){let w=V.parse(c);if(w.operation==="start"||w.operation==="get")throw new r("INVALID_REQUEST","Mutation required");if(w.operation==="close"&&u?.operation!=="close"&&(u=null),u){if(JSON.stringify(x(u))!==JSON.stringify(x(w)))throw new r("COMMAND_PENDING","Retry the original command before sending another");if(d)return d}else u=w;let E=m();return d=E,E.then(()=>{d===E&&(d=null)},()=>{d===E&&(d=null)}),E}return{get view(){return a?structuredClone(a):null},get pendingCommand(){return u?structuredClone(x(u)):null},get webViewUrl(){return y.webViewUrl()},screenUrl(c){return y.screenUrl(c)},async get(c,w){return e({operation:"get",...c?{data:c}:{},...w?{purchase:w}:{},...n?{customerToken:n}:{}})},resume(c=a?.pendingRequest?.requestId){return c?u?.requestId===c?f(u):f({operation:"resume",requestId:c}):Promise.reject(new r("INVALID_REQUEST","No interrupted command is available"))},submit(c){return f(c)},retry(){return d||(u?f(u):Promise.reject(new r("INVALID_REQUEST","No command is pending")))},identify(c){if(!/^gg_ct_[A-Za-z0-9_-]{43}$/.test(c))throw new r("INVALID_TOKEN","Customer credential required");p++,n=c,y.identify(s.runToken)},subscribe(c){return t.add(c),()=>t.delete(c)},reset(){p++,n=void 0,a=null,u=null,d=null,y.reset(),t.clear()}}}function X(s){if(!/^gg_ct_[A-Za-z0-9_-]{32,128}$/.test(s.customerToken))throw new r("INVALID_TOKEN","A customer credential is required");if(!s.scope)throw new r("INVALID_REQUEST","An explicit App and environment scope is required");let y=Q({...s,scope:s.scope,apiKey:s.customerToken});return{async start(n){let a=await y.start(n),p=U({...s,runToken:a.runToken});return p.identify(s.customerToken),{...a,controller:p}}}}function l(s){if(s!==null&&typeof s=="object"&&"customerId"in s)throw new r("INVALID_REQUEST","Customer requests use the verified session identity")}function we(s){let y=b(s),n=y.request,a=!1,p=z(n,()=>a,s.scope),u=new Set,d=t=>{for(let e of u)try{e(t)}catch{}};return{async features(t={}){return p.features(t)},track(t,e){return p.track(t,e)},flush(){return p.flush()},async setupPayment(t){l(t);let e=o.setupPayment;return e.response.parse(await n(e.path,e.request.parse(t)))},async readPaymentSetup(t){l(t);let e=o.readPaymentSetup;return e.response.parse(await n(e.path,e.request.parse(t)))},async previewUpdate(t){l(t);let e=o.previewUpdate;return e.response.parse(await n(e.path,e.request.parse(t)))},async update(t){l(t);let e=o.update;return e.response.parse(await n(e.path,e.request.parse(t)))},async readSubscriptionUpdate(t){l(t);let e=o.readSubscriptionUpdate;return e.response.parse(await n(e.path,e.request.parse(t)))},async restoreNativePurchase(t){l(t);let e=o.restoreNativePurchase;return e.response.parse(await n(e.path,e.request.parse(t)))},async previewAttach(t){l(t);let e=o.previewAttach;return e.response.parse(await n(e.path,e.request.parse(t)))},async attach(t){l(t);let e=o.attach;return e.response.parse(await n(e.path,e.request.parse(t)))},async readSubscriptionOperation(t){l(t);let e=o.readSubscriptionOperation;return e.response.parse(await n(e.path,e.request.parse(t)))},async checkEntitlement(t){l(t);let e=o.checkEntitlement;return e.response.parse(await n(e.path,e.request.parse(t)))},async resolvePaywall(t){l(t);let e=o.resolvePaywall;return e.response.parse(await n(e.path,e.request.parse(t)))},async resolveOffering(t){l(t);let e=o.resolveOffering;return e.response.parse(await n(e.path,e.request.parse(t)))},async readHoldings(t={}){let e=o.readHoldings;return e.response.parse(await n(e.path,e.request.omit({customerId:!0}).parse(t)))},async readLedger(t){let e=o.readLedger;return e.response.parse(await n(e.path,e.request.parse({query:t})))},async readBillingInvoice(t){l(t);let e=o.readBillingInvoice;return e.response.parse(await n(e.path,e.request.parse(t)))},async readCreditStatement(t){l(t);let e=o.readCreditStatement;return e.response.parse(await n(e.path,e.request.parse(t)))},async quoteBalance(t){l(t);let e=o.quoteBalance;return e.response.parse(await n(e.path,e.request.parse({command:t})))},async readBillingControls(t={}){l(t);let e=o.readBillingControls;return e.response.parse(await n(e.path,e.request.parse(t)))},async prepareBillingAuthorization(t){l(t);let e=o.prepareBillingAuthorization;return e.response.parse(await n(e.path,e.request.parse(t)))},async confirmBillingAuthorization(t){l(t);let e=o.confirmBillingAuthorization;return e.response.parse(await n(e.path,e.request.parse(t)))},async setBillingCoupons(t){l(t);let e=o.setBillingCoupons,m=e.request.safeParse(t);if(!m.success)throw new r("INVALID_REQUEST","Invalid billing coupon list");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid billing coupon receipt");return f.data},async revokeBillingAuthorization(t){l(t);let e=o.revokeBillingAuthorization;return e.response.parse(await n(e.path,e.request.parse(t)))},async listBillingInvoices(t={after:null,limit:25}){l(t);let e=o.listBillingInvoices;return e.response.parse(await n(e.path,e.request.parse(t)))},async confirmBillingAdjustment(t){l(t);let e=o.confirmBillingAdjustment;return e.response.parse(await n(e.path,e.request.parse(t)))},subscribeIdentity(t){return u.add(t),()=>{u.delete(t)}},identify(t){if(!/^gg_ct_[A-Za-z0-9_-]{43}$/.test(t))throw new r("INVALID_TOKEN","Browser SDK requires a customer session");p.reset(),y.identify(t),a=!0,d(!0)},reset(){a=!1,p.reset(),y.reset(),d(!1)},async redeemReward(t){l(t);let e=o.redeemReward,m=e.request.safeParse({...t,requestId:t.requestId??crypto.randomUUID()});if(!m.success)throw new r("INVALID_REQUEST","Invalid reward redemption");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid reward receipt");return f.data.redemption},async claimRewardProduct(t){l(t);let e=o.claimRewardProduct,m=e.request.safeParse(t);if(!m.success)throw new r("INVALID_REQUEST","Invalid reward product claim");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid reward product checkout");return f.data.checkout},async createReferralCode(t){l(t);let e=o.createReferralCode,m=e.request.safeParse({...t,requestId:t.requestId??crypto.randomUUID()});if(!m.success)throw new r("INVALID_REQUEST","Invalid referral program");let f=e.response.safeParse(await n(e.path,m.data));if(!f.success)throw new r("INVALID_RESPONSE","Invalid referral code");return f.data.referralCode},async redeemCoupon(t,e=crypto.randomUUID()){let m=o.redeemCoupon,f=m.request.safeParse({code:t,requestId:e});if(!f.success)throw new r("INVALID_REQUEST","Invalid coupon code");let F=m.response.safeParse(await n(m.path,f.data));if(!F.success)throw new r("INVALID_RESPONSE","Invalid Coupon receipt");let c=F.data;return{offer:c.offer,reason:c.reason}},async listOffers(){let t=o.listOffers.response.safeParse(await n("offers",{},"GET"));if(!t.success)throw new r("INVALID_RESPONSE","Invalid offers response");return t.data.offers}}}async function Ie(...s){return(await import("./paywall-Y3FIG43H.js")).showPaywall(...s)}async function ye(...s){return(await import("./funnel-runtime-host-X7AGEGHN.js")).showFunnelRun(...s)}export{r as IndianaError,k as createFeatureClient,X as createFunnelClient,U as createFunnelRunController,we as createIndiana,Z as createPaywallSession,$ as evaluateFunnelNode,K as formatCouponDiscount,H as formatCouponMoney,Y as formatCouponTerms,ye as showFunnelRun,Ie as showPaywall};
|
package/dist/openrouter.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as i}from"./chunk-
|
|
1
|
+
import{a as i}from"./chunk-CRJJ4EA2.js";import"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";import{z as R}from"zod";var c=R.number().int().min(0).max(1e9);function k(e,o){let a=c.parse(e.promptTokens),p=c.parse(e.completionTokens),s=c.parse(e.promptTokensDetails?.cachedTokens??0),t=c.parse(e.promptTokensDetails?.cacheWriteTokens??0),r=c.parse(e.promptTokensDetails?.audioTokens??0),l=c.parse(e.completionTokensDetails?.audioTokens??0),n=c.parse(e.completionTokensDetails?.reasoningTokens??0);if(c.parse(e.totalTokens)!==a+p||s+t+r>a||n+l>p||(e.promptTokensDetails?.videoTokens??0)>0)throw new i("AI_USAGE_UNAVAILABLE","Token pools must conserve usage; video needs an explicit token mapper");return{input:a-s-t-r,output:p-l-(o==="separate"?n:0),cache_read:s,cache_write:t,input_audio:r,output_audio:l,reasoning:o==="separate"?n:0}}function I(e){if(!Number.isFinite(e)||e<0)throw new i("AI_USAGE_UNAVAILABLE","Provider cost must be a nonnegative USD amount");let o=String(e),a=o.includes("e")?e.toFixed(18).replace(/0+$/,"").replace(/\.$/,""):o;if(!/^(0|[1-9]\d{0,11})(\.\d{1,18})?$/.test(a)||Number(a)!==e)throw new i("AI_USAGE_UNAVAILABLE","Provider cost exceeds the supported precision");return a}async function h(e){if(typeof window<"u")throw new i("SERVER_ONLY","OpenRouter accounting requires your backend");if(!["output","separate"].includes(e.reasoning)||!e.modelId||!e.generationId)throw new i("INVALID_REQUEST","Actual model, generation ID and reasoning pricing are required");let o={context:e.context,generationId:e.generationId,modelId:`openrouter/${e.modelId}`,usage:e.usage,tokens:null,quote:null,receipt:null,phase:"captured"};await e.persist(o);let a=e.mapTokens?e.mapTokens(e.usage):k(e.usage,e.reasoning),p=e.usage.cost==null?void 0:I(e.usage.cost),s=e.quote??await e.pricing.quoteTokens({modelId:o.modelId,tokens:a});if(s.pricing.modelId!==o.modelId||Object.keys(a).some(l=>a[l]!==s.tokens[l]))throw new i("INVALID_REQUEST","Saved quote must match the provider model and token pools");await e.persist({...o,tokens:a,quote:s,phase:"quoted"});let t=await e.pricing.trackTokens(e.client,{...e.context,quote:s,providerCostUsd:p,generationId:e.generationId});if(!t.receipt.accepted)throw new i("AI_BALANCE_REJECTED","OpenRouter usage was saved but the balance request was rejected");let r={...o,tokens:a,quote:s,receipt:t,phase:"settled"};return await e.persist(r),r}function T(e){if(typeof window<"u")throw new i("SERVER_ONLY","OpenRouter accounting requires your backend");if(!["output","separate"].includes(e.reasoning))throw new i("INVALID_REQUEST","Reasoning pricing is required");let o=e.openRouter.chat;async function a(t){if(!t.usage||!t.modelId||!t.generationId)throw new i("AI_USAGE_UNAVAILABLE","OpenRouter did not return final usage and the actual model");await h({...e,context:t.context,generationId:t.generationId,modelId:t.modelId.slice(11),usage:t.usage})}let p=async(t,r)=>{let n={context:await e.context(),generationId:null,modelId:null,usage:null,tokens:null,quote:null,receipt:null,phase:"incomplete"},d;try{d=await o.send(t,r)}catch(g){throw await e.persist(n),g}if(!(d instanceof ReadableStream)){if(n={...n,generationId:d.id,modelId:d.model?`openrouter/${d.model}`:null,usage:d.usage??null},!n.usage||!n.modelId)throw await e.persist(n),new i("AI_USAGE_UNAVAILABLE","OpenRouter omitted final accounting");return await a(n),d}let w=d.getReader(),m=!1;return new ReadableStream({async pull(g){try{let{value:u,done:A}=await w.read();if(A){if(m=!0,!n.usage||!n.modelId)throw await e.persist(n),new i("AI_USAGE_UNAVAILABLE","OpenRouter stream ended without final accounting");await a(n),g.close();return}if(u.error)throw new i("AI_PROVIDER_ERROR",u.error.message);u.usage&&(n={...n,generationId:u.id,modelId:u.model?`openrouter/${u.model}`:null,usage:u.usage}),g.enqueue(u)}catch(u){m||(m=!0,await e.persist(n)),await w.cancel(u),g.error(u)}},async cancel(g){m||(m=!0,await e.persist(n)),await w.cancel(g)}})},s=new Proxy(o,{get(t,r){return r==="send"?p:Reflect.get(t,r,t)}});return new Proxy(e.openRouter,{get(t,r){return r==="chat"?s:Reflect.get(t,r,t)}})}export{T as createOpenRouterUsageClient,h as trackOpenRouterUsage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as H}from"./chunk-6X42DWOM.js";import{a as m}from"./chunk-
|
|
1
|
+
import{a as H}from"./chunk-6X42DWOM.js";import{a as m}from"./chunk-CRJJ4EA2.js";import{Ie as U,Vl as B,hf as V,y as M}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";async function F(y,t,d){if(t.status!=="complete")throw new m("INVALID_RESPONSE","A verified completed purchase is required");if(await d.onComplete?.(t),!y||!d.check)return;let i=U.parse(await d.check());if(i.internal_feature_id!==y.internal_feature_id||i.quantity!==y.quantity)throw new m("INVALID_RESPONSE","The access requirement changed");i.allowed&&await d.onAccessGranted?.(i)}async function re(y,t){let d=t.check?U.parse(await t.check()):null;if(d?.allowed)return await t.onAccessGranted?.(d),{check:d,host:null};let i=await t.start(),p=i.view;if(!p)throw new m("INVALID_RESPONSE","Paywall presentation is missing");let{mountScreenPreview:j}=await import("./popup.js"),n=y.ownerDocument,R=new AbortController,v=n.createElement("section"),$=n.createElement("div"),I=n.createElement("div"),P=n.createElement("p"),E=n.createElement("button"),D=n.createElement("button"),f=n.createElement("dialog"),L=n.activeElement,w=p.document.screen.strings.defaultLocale.startsWith("zh");v.dataset.indianaPaywall="",v.setAttribute("aria-label",p.document.name),v.style.cssText="width:100%;box-sizing:border-box;background:#fff;color:#172033;font:14px/1.5 system-ui,sans-serif",I.style.cssText="display:flex;gap:12px;padding:12px 20px;align-items:center;flex-wrap:wrap",P.setAttribute("role","status"),D.textContent=w?"\u5173\u95ED":"Close",E.textContent=w?"\u91CD\u8BD5":"Retry",E.hidden=!0,I.append(P,E,D),v.append($,I);let N=p.document.presentation,g,u=!1,_=!1,l=null,T=!1,a=null,x=null,S=e=>{P.textContent=e instanceof Error?e.message:w?"\u8BF7\u6C42\u5931\u8D25":"Request failed",H(t.onError,e),E.hidden=a===null};async function b(e){if(!(_||u)){_=!0,E.hidden=!0,P.textContent="";try{await e()}catch(o){u||S(o)}finally{_=!1}}}async function W(e){await F(d,e,t)}async function O(e){if(u)return;if(P.textContent=e.status,e.status==="complete"){a=null,await W(e);return}if(e.status!=="pending"){a=null,l=null;return}let o=Date.now()+6e5,c=2e3;for(;!u&&Date.now()<o;){if(await new Promise(h=>{let A=()=>{clearTimeout(C),h()},C=setTimeout(()=>{R.signal.removeEventListener("abort",A),h()},c);R.signal.addEventListener("abort",A,{once:!0})}),u)return;let r=await i.read();if(r.status!=="pending"){await O(r);return}c=Math.min(c*1.5,3e4)}a=async()=>O(await i.read()),E.hidden=!1}async function z(){x?.remove(),x=null,a=z;let e=await i.confirm();if(e.status==="pending"){if(e.checkoutUrl)t.onCheckoutUrl?await t.onCheckoutUrl(e.checkoutUrl):n.defaultView?.location.assign(e.checkoutUrl);else if(e.execution||e.nativePurchase){if(!t.onPurchase)throw new m("PURCHASE_HANDLER_REQUIRED","Provide the merchant or native purchase handler");await t.onPurchase({operation:e,signal:R.signal})}}a=async()=>O(await i.read()),await O(e)}function J(e){x?.remove();let o=n.createElement("div"),c=n.createElement("button"),r=n.createElement("button"),h=n.createElement("p");h.textContent=e.lines.map(s=>s.productName).join(", ")+" \xB7 "+M(e.charge?.totalMinor??e.catalogAmountMinor-(e.discount?.amountMinor??0),e.currency),c.textContent=w?"\u786E\u8BA4\u8D2D\u4E70":"Confirm purchase",r.textContent=w?"\u53D6\u6D88":"Cancel",c.onclick=()=>{b(z)};let A=async()=>{await i.cancel(),!u&&(l=null,a=null,o.remove(),x=null)};r.onclick=()=>{a=A,b(A)};let C=n.createElement("div");for(let s of e.lines){let q=n.createElement("p");if(q.textContent=`${s.productName} \xB7 ${M(s.catalogAmountMinor,e.currency)}${B(s.interval,w?"zh-CN":"en",s.intervalCount??1)}`,C.append(q),s.trial){let G=n.createElement("p");G.textContent=w?`\u8BD5\u7528 ${s.trial.days} \u5929\uFF1B${s.trial.cardRequired?"\u9700\u8981\u63D0\u4F9B\u4ED8\u6B3E\u65B9\u5F0F":"\u65E0\u9700\u63D0\u4F9B\u4ED8\u6B3E\u65B9\u5F0F"}`:`Trial days: ${s.trial.days}; ${s.trial.cardRequired?"a payment method is required":"no payment method is required"}`,C.append(G)}}if(!e.charge){let s=n.createElement("p");s.textContent=w?"\u76EE\u5F55\u4EF7\u683C\uFF1B\u6700\u7EC8\u91D1\u989D\u4EE5\u7ED3\u8D26\u65F6\u7A0E\u8D39\u548C\u8BD5\u7528\u89C4\u5219\u4E3A\u51C6\u3002":"Catalog price; the final charge depends on checkout taxes and trial terms.",C.append(s)}o.append(h,C,c,r),I.prepend(o),x=o,a=null}async function Q(){if(!l)return;if(a=Q,!T){let o=i.view,c=o?.document.buttons[l.actionId],r=o&&c?.type==="checkout"?V(c.product,l.selection,o.capabilities):null;if(!r)throw new m("PRODUCT_UNAVAILABLE","Choose an available Product in this purchase area");let h=await t.resolveOfferId?.({actionId:l.actionId,productVersionId:r});if(u)return;h!==void 0&&(l.offerId=h),T=!0}let e=await i.preview(l);u||J(e)}function k(e="destroy"){u||(u=!0,R.abort(),g?.destroy(),i.destroy(),f.open&&f.close(),f.remove(),v.remove(),L instanceof HTMLElement&&L.isConnected&&L.focus(),e==="dismiss"&&H(t.onDismiss))}D.onclick=()=>k("dismiss"),f.addEventListener("cancel",e=>{e.preventDefault(),k("dismiss")}),E.onclick=()=>{a&&b(a)};try{if(N.type==="inline")y.append(v);else{let e={sm:420,md:640,lg:900};f.style.cssText=`padding:0;border:0;max-width:calc(100vw - 32px);max-height:calc(100dvh - 32px);overflow:auto;width:${"size"in N?e[N.size]+"px":"100vw"}`,f.setAttribute("aria-label",p.document.name),f.append(v),y.append(f),f.showModal()}g=j($,{mode:"live",rendererUrl:i.webViewUrl,title:p.document.name,onAction(e,o={}){let c=i.view,r=c?.document.buttons[e];if(r){if(r.type==="close"){b(async()=>{await t.onAction?.(e),k(t.onAction?"action":"dismiss")});return}if(r.type==="action"){a=async()=>{if(r.action.type==="event"){if(!t.onEvent)throw new m("EVENT_HANDLER_REQUIRED","Provide the event handler");await t.onEvent(r.action.event)}else t.onOpenUrl?await t.onOpenUrl(r.action.url):n.defaultView?.location.assign(r.action.url);await t.onAction?.(e),a=null},b(a);return}if(!c||!V(r.product,o,c.capabilities)){S(new m("PRODUCT_UNAVAILABLE","Choose an available Product in this purchase area"));return}if(l&&l.actionId!==e){S(new m("COMMAND_PENDING","Finish the current purchase"));return}l||(l={requestId:crypto.randomUUID(),actionId:e,selection:o},T=!1),b(Q)}},onEscape:()=>k("dismiss"),onError:e=>S(new Error(e))}),g.update(p.document.screen,p.document.screen.strings.defaultLocale,{capabilities:p.capabilities,serverInput:{bindings:[],answers:{}}}),await g.ready}catch(e){throw k(),e}return{check:d,host:{destroy:k,refresh:async()=>{let e=await i.refresh();return u||g?.updateCapabilities(e.capabilities),e}}}}export{re as showPaywall};
|
package/dist/popup.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as V}from"./chunk-6X42DWOM.js";import{a as St}from"./chunk-X5UXOLOU.js";import{Af as We,Ag as xe,Bg as bt,Cg as Ve,Ef as De,gj as xt,hj as vt,kj as kt,ng as yt,qg as $e,sf as mt,wi as wt,xf as Be,xg as qe,yf as ht,yg as Je}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";function Et(c){let p=new Intl.Locale(c);if(p.language==="zh")return p.maximize().script==="Hant"?"\u95DC\u9589\u5F48\u7A97":"\u5173\u95ED\u5F39\u7A97";let A={en:"Close popup",ja:"\u30DD\u30C3\u30D7\u30A2\u30C3\u30D7\u3092\u9589\u3058\u308B",ko:"\uD31D\uC5C5 \uB2EB\uAE30",es:"Cerrar ventana emergente",fr:"Fermer la fen\xEAtre contextuelle",de:"Popup schlie\xDFen",pt:"Fechar janela pop-up",it:"Chiudi popup",ru:"\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u0432\u0441\u043F\u043B\u044B\u0432\u0430\u044E\u0449\u0435\u0435 \u043E\u043A\u043D\u043E",vi:"\u0110\xF3ng c\u1EEDa s\u1ED5 b\u1EADt l\xEAn",th:"\u0E1B\u0E34\u0E14\u0E2B\u0E19\u0E49\u0E32\u0E15\u0E48\u0E32\u0E07\u0E1B\u0E4A\u0E2D\u0E1B\u0E2D\u0E31\u0E1B",id:"Tutup pop-up",ar:"\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0646\u0627\u0641\u0630\u0629 \u0627\u0644\u0645\u0646\u0628\u062B\u0642\u0629",he:"\u05E1\u05D2\u05D9\u05E8\u05EA \u05D4\u05D7\u05DC\u05D5\u05DF \u05D4\u05E7\u05D5\u05E4\u05E5",fa:"\u0628\u0633\u062A\u0646 \u067E\u0646\u062C\u0631\u0647\u0654 \u0628\u0627\u0632\u0634\u0648",ur:"\u067E\u0627\u067E \u0627\u067E \u0628\u0646\u062F \u06A9\u0631\u06CC\u06BA"};return A[p.language]??A.en}import Jt from"dompurify";import{parse as Bt,generate as Wt,walk as qt}from"css-tree";function At(c){if(!c.trim())return"";if(/[\\<]/.test(c))throw new Error("CSS \u6682\u4E0D\u652F\u6301\u53CD\u659C\u6760\u8F6C\u4E49\u6216 HTML \u6807\u7B7E\u3002");let p=Bt(c,{onParseError:I=>{throw Object.assign(new Error("CSS \u683C\u5F0F\u4E0D\u6B63\u786E\u3002"),{offset:I.offset})}}),A=0;return qt(p,I=>{if(++A>5e3)throw new Error("CSS \u8FC7\u4E8E\u590D\u6742\u3002");if(I.type==="Raw"||I.type==="Url"||I.type==="Atrule"&&!["media","supports","keyframes"].includes(I.name.toLowerCase())||I.type==="Function"&&["image-set","-webkit-image-set","image","src","paint"].includes(I.name.toLowerCase()))throw new Error("CSS \u4E0D\u652F\u6301\u5916\u90E8\u8D44\u6E90\u3001\u5BFC\u5165\u6216\u672A\u77E5\u8BED\u6CD5\uFF1B\u56FE\u7247\u8BF7\u4F7F\u7528 HTML img \u6807\u7B7E\u3002")}),Wt(p)}import{parse as Vt,walk as Kt}from"css-tree";function Zt(c,p,A,I){return{html:ze(c,A,I),css:Ke(p)}}function Ke(c){return At(c)}function ze(c,p,A,I){if(!c.trim())return"";let y=We(c);if(y.length)throw new Error(y[0]);let T=Jt(A),C=T.sanitize(c,{ALLOWED_TAGS:["main","section","article","header","footer","div","span","p","h1","h2","h3","h4","strong","em","b","i","small","br","hr","ul","ol","li","button","img"],ALLOWED_ATTR:["class","alt","src","width","height","title","type","disabled","data-grow-action","aria-label"],ALLOW_DATA_ATTR:!1,ALLOW_ARIA_ATTR:!1,ADD_URI_SAFE_ATTR:["data-grow-action"],ALLOWED_URI_REGEXP:/^https:\/\//i,RETURN_DOM:!0});if(!(C instanceof A.Element))throw new Error("\u65E0\u6CD5\u89E3\u6790 HTML\u3002");if(I){let b=new Set;for(let v of T.removed){let N="element"in v?v.element.nodeName.toLowerCase():void 0,H="attribute"in v?v.attribute?.name:void 0;if(!N&&!H)continue;let F=H?/<[^>]+>/g:new RegExp(`<\\s*${N}\\b[^>]*>`,"gi"),W=[...c.matchAll(F)].find($=>!b.has(`${H??N}:${$.index}`)&&(!H||new RegExp(`\\b${H}\\s*=`,"i").test($[0])));if(!W)continue;let x=W.index;b.add(`${H??N}:${x}`);let L=H==="style"?"\u5185\u8054\u6837\u5F0F\u4E0D\u4FDD\u7559\uFF0C\u8BF7\u5199\u5728 CSS \u4E2D\u3002":H?.startsWith("on")?"\u811A\u672C\u4E8B\u4EF6\u4E0D\u5141\u8BB8\uFF0C\u8BF7\u4F7F\u7528\u52A8\u4F5C\u6309\u94AE\u3002":H==="src"?"\u56FE\u7247\u53EA\u652F\u6301 https \u5730\u5740\u3002":"\u8FD9\u4E2A\u5C5E\u6027\u4E0D\u5728\u5141\u8BB8\u7684\u5E03\u5C40\u3001\u56FE\u7247\u4E0E\u52A8\u4F5C\u5C5E\u6027\u4E2D\u3002";I.push({language:"html",from:x,to:x+W[0].length,severity:"warning",message:H?`\u5DF2\u79FB\u9664\u5C5E\u6027 ${H}\uFF1A${L}`:`\u5DF2\u79FB\u9664 <${N}>\uFF1A\u8FD9\u4E2A\u6807\u7B7E\u4E0D\u5728\u5141\u8BB8\u7684\u6392\u7248\u6807\u7B7E\u4E2D\u3002`})}}let P=We(C.innerHTML);if(P.length)throw new Error(P[0]);if(C.querySelectorAll("*").length>500)throw new Error("HTML \u6700\u591A\u652F\u6301 500 \u4E2A\u5143\u7D20\u3002");for(let b of C.querySelectorAll("[data-grow-action]")){let v=b.getAttribute("data-grow-action");if(b.tagName!=="BUTTON"||!p.includes(v))throw new Error(`\u81EA\u5B9A\u4E49 HTML \u91CC\u7684\u6309\u94AE ${v.slice(0,64)} \u6CA1\u6709\u5BF9\u5E94\u7684\u52A8\u4F5C\uFF0C\u8BF7\u5148\u5728\u300C\u70B9\u51FB\u52A8\u4F5C\u300D\u91CC\u6DFB\u52A0\uFF0C\u5E76\u4F7F\u7528 button \u5143\u7D20\u3002`)}if(!C.textContent?.trim()&&!C.querySelector("img"))throw new Error("\u81EA\u5B9A\u4E49 HTML \u6E05\u6D17\u540E\u6CA1\u6709\u53EF\u663E\u793A\u7684\u5185\u5BB9\u3002");return C.innerHTML}var It=2e3,Lt=1e4,Dt=new WeakMap;function Nt(c,p,A){let I=A.document;if(!I)throw new Error("A content document is required");let y=Dt.get(A)??new Map;Dt.set(A,y);let T=(b,v)=>{let N=y.get(b);if(N!==void 0)return N;let H=v();y.set(b,H);let F=[...y.keys()].reduce((W,x)=>W+x.length,0);for(;y.size>64||F>256e3;){let W=y.keys().next().value;y.delete(W),F-=W.length}return H},C=b=>T(`html:${b}`,()=>{let v=I.createElement("div");return v.innerHTML=b,v.querySelectorAll("*").length}),P=b=>T(`css:${b}`,()=>{let v=0;return b.trim()&&Kt(Vt(b),()=>{v++}),v});for(let b of c.pages){let v=0,N=0,H=F=>{if(F.hidden||(F.type==="stack"&&F.children.forEach(H),F.type!=="custom_html"))return;let W=p?.nodes[F.id],x=[...Object.values(F.html),W?.base.html??"",...Object.values(W?.byPlan??{}).map(L=>L.html??"")];if(v+=Math.max(0,...x.map(C)),N+=P(F.css),v>It)throw new Error(`Page custom HTML exceeds ${It} elements`);if(N>Lt)throw new Error(`Page custom CSS exceeds ${Lt} syntax nodes`)};H(b.root)}}function Gt(c,p,A,I){let y=[],T="",C="";for(let P of["html","css"])try{P==="html"?T=ze(c,A,I,y):C=Ke(p)}catch(b){let v=P==="html"?c:p,N=P==="html"?/\{\{|data-grow-action/:/@import\b|url\s*\(|image-set\s*\(|[\\<]/i,H=b instanceof Error?b.message:"\u5185\u5BB9\u65E0\u6CD5\u89E3\u6790",F=P==="html"?H.match(/未知变量:(.+)/)?.[1]:void 0,W=F?v.indexOf(F):-1,x=typeof b=="object"&&b!==null&&"offset"in b&&typeof b.offset=="number"?b.offset:W>=0?v.lastIndexOf("{{",W):v.search(N);y.push({language:P,from:Math.max(0,x),to:Math.min(v.length,Math.max(0,x)+2),severity:"error",message:H})}return{html:T,css:C,diagnostics:y,valid:!y.some(P=>P.severity==="error")}}function Re(c,p,A){if(!c)return;let I={},y=p.actions.map(C=>C.id);for(let[C,P]of Object.entries(c.nodes)){let b=v=>{if(v.html===void 0)return v;if(xe(p,C)?.type!=="custom_html")throw new Error("HTML \u5546\u54C1\u6570\u636E\u53EA\u80FD\u7528\u4E8E\u81EA\u5B9A\u4E49 HTML \u7EC4\u4EF6");return{...v,html:ze(v.html,y,A)}};I[C]={...P,base:b(P.base),...P.byPlan?{byPlan:Object.fromEntries(Object.entries(P.byPlan).map(([v,N])=>[v,b(N)]))}:{}}}let T={...c,nodes:I};return Nt(p,T,A),T}var Rt=new WeakMap;function Ne(c,p){let A=$e.parse(c),I=JSON.stringify(A),y=Rt.get(p);y||(y=new Map,Rt.set(p,y));let T=Date.now();for(let[x,L]of y)L.expires<=T&&y.delete(x);let C=y.get(I);if(C)return y.delete(I),y.set(I,C),JSON.parse(C.json);let P=A.actions.map(x=>x.id),b=x=>{if(x.type==="stack")return{...x,children:x.children.map(b)};if(x.type!=="custom_html")return x;let L={};for(let[$,te]of Object.entries(x.html))L[$]=ze(te,P,p);return{...x,html:L,css:Ke(x.css)}},v={...A,pages:A.pages.map(x=>({...x,root:b(x.root)}))};Nt(v,void 0,p);let N=JSON.stringify(v),H=new TextEncoder,F=H.encode(N).length;if(F>De.documentBytes)throw new Error(`\u754C\u9762\u5185\u5BB9\u8FC7\u5927\uFF08\u4E0A\u9650 ${De.documentBytes/1e3} KB\uFF09\u3002`);let W=H.encode(I).length;if(W<=De.documentBytes){y.set(I,{json:N,bytes:W+F,expires:T+6e4});let x=[...y.values()].reduce((L,$)=>L+$.bytes,0);for(;y.size>16||x>2*1024*1024;){let[L,$]=y.entries().next().value;y.delete(L),x-=$.bytes}}return v}function Ze(c){function p(e){return e.type==="stack"&&e.interaction?.type==="select"&&e.interaction.purpose==="product"&&!!e.interaction.pickerId}function A(e){let a={};function t(r){if(p(r)){let i=a[r.interaction.pickerId]??={ids:[],defaultId:null};for(let n of r.children){let l=n.type==="stack"?n.bind?.plan:void 0;l&&!i.ids.includes(l)&&i.ids.push(l)}let s=r.children[r.interaction.defaultIndex];!i.defaultId&&s?.type==="stack"&&(i.defaultId=s.bind?.plan??null)}r.type==="stack"&&r.children.forEach(t)}return e.pages.forEach(r=>t(r.root)),a}function I(e,a,t){let r={};function i(d){if(d.hidden||d.type!=="stack")return;let u=d.children.filter(o=>!o.hidden),h=d.interaction;if(p(d)){let o=r[d.interaction.pickerId]??={ids:[],defaults:[],remembered:[]},f=t.pickers[d.interaction.pickerId]?.options??[];for(let w of u){let z=w.type==="stack"?w.bind?.plan:void 0;z&&f.includes(z)&&!o.ids.includes(z)&&o.ids.push(z),z&&w.id===a[d.id]&&o.remembered.push(z)}let m=d.children[d.interaction.defaultIndex];m?.type==="stack"&&!m.hidden&&m.bind?.plan&&o.defaults.push(m.bind.plan)}if(h?.type==="tabs"){let o=u.find(f=>f.id===a[d.id])??d.children[h.defaultIndex];o&&i(o)}else if(h?.type==="toggle"){let o=typeof a[d.id]=="boolean"?a[d.id]:h.defaultEnabled,f=d.children[o?0:1];f&&i(f)}else u.forEach(i)}let s=typeof a.__page=="string"?a.__page:e.initialPageId??e.pages[0]?.id,n=e.pages.find(d=>d.id===s);n&&i(n.root);let l={};for(let[d,u]of Object.entries(r)){let h=a[d],o=u.remembered[0]??(u.ids.includes(t.pickers[d]?.selected??"")?t.pickers[d]?.selected:u.defaults[0]);l[d]=typeof h=="string"?u.ids.includes(h)?h:"":o&&u.ids.includes(o)?o:""}for(let d of Object.keys(A(e)))l[d]??="";return l}let y=window;for(let e=0;e<c.hostDepth;e++)y=y.parent;let T=window,C={none:0,xs:4,sm:8,md:12,lg:20,xl:32},P={none:0,sm:4,md:8,lg:14,full:9999},b={system:'system-ui,-apple-system,"Segoe UI",Roboto,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans CJK SC",sans-serif',serif:'Georgia,"Times New Roman","Songti SC","Noto Serif CJK SC",serif',rounded:'ui-rounded,"SF Pro Rounded","Hiragino Maru Gothic ProN",system-ui,sans-serif',mono:"ui-monospace,SFMono-Regular,Menlo,Consolas,monospace"},v={start:"flex-start",center:"center",end:"flex-end",stretch:"stretch"},N={start:"flex-start",center:"center",end:"flex-end",between:"space-between"},H={start:"start",center:"center",end:"end",between:"stretch"},F={start:"start",center:"center",end:"end",stretch:"stretch"},W={"1:1":"1 / 1","4:3":"4 / 3","16:9":"16 / 9","3:1":"3 / 1"},x=`
|
|
1
|
+
import{a as V}from"./chunk-6X42DWOM.js";import{a as St}from"./chunk-CRJJ4EA2.js";import{Af as We,Ag as xe,Bg as bt,Cg as Ve,Ef as De,gj as xt,hj as vt,kj as kt,ng as yt,qg as $e,sf as mt,wi as wt,xf as Be,xg as qe,yf as ht,yg as Je}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";function Et(c){let p=new Intl.Locale(c);if(p.language==="zh")return p.maximize().script==="Hant"?"\u95DC\u9589\u5F48\u7A97":"\u5173\u95ED\u5F39\u7A97";let A={en:"Close popup",ja:"\u30DD\u30C3\u30D7\u30A2\u30C3\u30D7\u3092\u9589\u3058\u308B",ko:"\uD31D\uC5C5 \uB2EB\uAE30",es:"Cerrar ventana emergente",fr:"Fermer la fen\xEAtre contextuelle",de:"Popup schlie\xDFen",pt:"Fechar janela pop-up",it:"Chiudi popup",ru:"\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u0432\u0441\u043F\u043B\u044B\u0432\u0430\u044E\u0449\u0435\u0435 \u043E\u043A\u043D\u043E",vi:"\u0110\xF3ng c\u1EEDa s\u1ED5 b\u1EADt l\xEAn",th:"\u0E1B\u0E34\u0E14\u0E2B\u0E19\u0E49\u0E32\u0E15\u0E48\u0E32\u0E07\u0E1B\u0E4A\u0E2D\u0E1B\u0E2D\u0E31\u0E1B",id:"Tutup pop-up",ar:"\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0646\u0627\u0641\u0630\u0629 \u0627\u0644\u0645\u0646\u0628\u062B\u0642\u0629",he:"\u05E1\u05D2\u05D9\u05E8\u05EA \u05D4\u05D7\u05DC\u05D5\u05DF \u05D4\u05E7\u05D5\u05E4\u05E5",fa:"\u0628\u0633\u062A\u0646 \u067E\u0646\u062C\u0631\u0647\u0654 \u0628\u0627\u0632\u0634\u0648",ur:"\u067E\u0627\u067E \u0627\u067E \u0628\u0646\u062F \u06A9\u0631\u06CC\u06BA"};return A[p.language]??A.en}import Jt from"dompurify";import{parse as Bt,generate as Wt,walk as qt}from"css-tree";function At(c){if(!c.trim())return"";if(/[\\<]/.test(c))throw new Error("CSS \u6682\u4E0D\u652F\u6301\u53CD\u659C\u6760\u8F6C\u4E49\u6216 HTML \u6807\u7B7E\u3002");let p=Bt(c,{onParseError:I=>{throw Object.assign(new Error("CSS \u683C\u5F0F\u4E0D\u6B63\u786E\u3002"),{offset:I.offset})}}),A=0;return qt(p,I=>{if(++A>5e3)throw new Error("CSS \u8FC7\u4E8E\u590D\u6742\u3002");if(I.type==="Raw"||I.type==="Url"||I.type==="Atrule"&&!["media","supports","keyframes"].includes(I.name.toLowerCase())||I.type==="Function"&&["image-set","-webkit-image-set","image","src","paint"].includes(I.name.toLowerCase()))throw new Error("CSS \u4E0D\u652F\u6301\u5916\u90E8\u8D44\u6E90\u3001\u5BFC\u5165\u6216\u672A\u77E5\u8BED\u6CD5\uFF1B\u56FE\u7247\u8BF7\u4F7F\u7528 HTML img \u6807\u7B7E\u3002")}),Wt(p)}import{parse as Vt,walk as Kt}from"css-tree";function Zt(c,p,A,I){return{html:ze(c,A,I),css:Ke(p)}}function Ke(c){return At(c)}function ze(c,p,A,I){if(!c.trim())return"";let y=We(c);if(y.length)throw new Error(y[0]);let T=Jt(A),C=T.sanitize(c,{ALLOWED_TAGS:["main","section","article","header","footer","div","span","p","h1","h2","h3","h4","strong","em","b","i","small","br","hr","ul","ol","li","button","img"],ALLOWED_ATTR:["class","alt","src","width","height","title","type","disabled","data-grow-action","aria-label"],ALLOW_DATA_ATTR:!1,ALLOW_ARIA_ATTR:!1,ADD_URI_SAFE_ATTR:["data-grow-action"],ALLOWED_URI_REGEXP:/^https:\/\//i,RETURN_DOM:!0});if(!(C instanceof A.Element))throw new Error("\u65E0\u6CD5\u89E3\u6790 HTML\u3002");if(I){let b=new Set;for(let v of T.removed){let N="element"in v?v.element.nodeName.toLowerCase():void 0,H="attribute"in v?v.attribute?.name:void 0;if(!N&&!H)continue;let F=H?/<[^>]+>/g:new RegExp(`<\\s*${N}\\b[^>]*>`,"gi"),W=[...c.matchAll(F)].find($=>!b.has(`${H??N}:${$.index}`)&&(!H||new RegExp(`\\b${H}\\s*=`,"i").test($[0])));if(!W)continue;let x=W.index;b.add(`${H??N}:${x}`);let L=H==="style"?"\u5185\u8054\u6837\u5F0F\u4E0D\u4FDD\u7559\uFF0C\u8BF7\u5199\u5728 CSS \u4E2D\u3002":H?.startsWith("on")?"\u811A\u672C\u4E8B\u4EF6\u4E0D\u5141\u8BB8\uFF0C\u8BF7\u4F7F\u7528\u52A8\u4F5C\u6309\u94AE\u3002":H==="src"?"\u56FE\u7247\u53EA\u652F\u6301 https \u5730\u5740\u3002":"\u8FD9\u4E2A\u5C5E\u6027\u4E0D\u5728\u5141\u8BB8\u7684\u5E03\u5C40\u3001\u56FE\u7247\u4E0E\u52A8\u4F5C\u5C5E\u6027\u4E2D\u3002";I.push({language:"html",from:x,to:x+W[0].length,severity:"warning",message:H?`\u5DF2\u79FB\u9664\u5C5E\u6027 ${H}\uFF1A${L}`:`\u5DF2\u79FB\u9664 <${N}>\uFF1A\u8FD9\u4E2A\u6807\u7B7E\u4E0D\u5728\u5141\u8BB8\u7684\u6392\u7248\u6807\u7B7E\u4E2D\u3002`})}}let P=We(C.innerHTML);if(P.length)throw new Error(P[0]);if(C.querySelectorAll("*").length>500)throw new Error("HTML \u6700\u591A\u652F\u6301 500 \u4E2A\u5143\u7D20\u3002");for(let b of C.querySelectorAll("[data-grow-action]")){let v=b.getAttribute("data-grow-action");if(b.tagName!=="BUTTON"||!p.includes(v))throw new Error(`\u81EA\u5B9A\u4E49 HTML \u91CC\u7684\u6309\u94AE ${v.slice(0,64)} \u6CA1\u6709\u5BF9\u5E94\u7684\u52A8\u4F5C\uFF0C\u8BF7\u5148\u5728\u300C\u70B9\u51FB\u52A8\u4F5C\u300D\u91CC\u6DFB\u52A0\uFF0C\u5E76\u4F7F\u7528 button \u5143\u7D20\u3002`)}if(!C.textContent?.trim()&&!C.querySelector("img"))throw new Error("\u81EA\u5B9A\u4E49 HTML \u6E05\u6D17\u540E\u6CA1\u6709\u53EF\u663E\u793A\u7684\u5185\u5BB9\u3002");return C.innerHTML}var It=2e3,Lt=1e4,Dt=new WeakMap;function Nt(c,p,A){let I=A.document;if(!I)throw new Error("A content document is required");let y=Dt.get(A)??new Map;Dt.set(A,y);let T=(b,v)=>{let N=y.get(b);if(N!==void 0)return N;let H=v();y.set(b,H);let F=[...y.keys()].reduce((W,x)=>W+x.length,0);for(;y.size>64||F>256e3;){let W=y.keys().next().value;y.delete(W),F-=W.length}return H},C=b=>T(`html:${b}`,()=>{let v=I.createElement("div");return v.innerHTML=b,v.querySelectorAll("*").length}),P=b=>T(`css:${b}`,()=>{let v=0;return b.trim()&&Kt(Vt(b),()=>{v++}),v});for(let b of c.pages){let v=0,N=0,H=F=>{if(F.hidden||(F.type==="stack"&&F.children.forEach(H),F.type!=="custom_html"))return;let W=p?.nodes[F.id],x=[...Object.values(F.html),W?.base.html??"",...Object.values(W?.byPlan??{}).map(L=>L.html??"")];if(v+=Math.max(0,...x.map(C)),N+=P(F.css),v>It)throw new Error(`Page custom HTML exceeds ${It} elements`);if(N>Lt)throw new Error(`Page custom CSS exceeds ${Lt} syntax nodes`)};H(b.root)}}function Gt(c,p,A,I){let y=[],T="",C="";for(let P of["html","css"])try{P==="html"?T=ze(c,A,I,y):C=Ke(p)}catch(b){let v=P==="html"?c:p,N=P==="html"?/\{\{|data-grow-action/:/@import\b|url\s*\(|image-set\s*\(|[\\<]/i,H=b instanceof Error?b.message:"\u5185\u5BB9\u65E0\u6CD5\u89E3\u6790",F=P==="html"?H.match(/未知变量:(.+)/)?.[1]:void 0,W=F?v.indexOf(F):-1,x=typeof b=="object"&&b!==null&&"offset"in b&&typeof b.offset=="number"?b.offset:W>=0?v.lastIndexOf("{{",W):v.search(N);y.push({language:P,from:Math.max(0,x),to:Math.min(v.length,Math.max(0,x)+2),severity:"error",message:H})}return{html:T,css:C,diagnostics:y,valid:!y.some(P=>P.severity==="error")}}function Re(c,p,A){if(!c)return;let I={},y=p.actions.map(C=>C.id);for(let[C,P]of Object.entries(c.nodes)){let b=v=>{if(v.html===void 0)return v;if(xe(p,C)?.type!=="custom_html")throw new Error("HTML \u5546\u54C1\u6570\u636E\u53EA\u80FD\u7528\u4E8E\u81EA\u5B9A\u4E49 HTML \u7EC4\u4EF6");return{...v,html:ze(v.html,y,A)}};I[C]={...P,base:b(P.base),...P.byPlan?{byPlan:Object.fromEntries(Object.entries(P.byPlan).map(([v,N])=>[v,b(N)]))}:{}}}let T={...c,nodes:I};return Nt(p,T,A),T}var Rt=new WeakMap;function Ne(c,p){let A=$e.parse(c),I=JSON.stringify(A),y=Rt.get(p);y||(y=new Map,Rt.set(p,y));let T=Date.now();for(let[x,L]of y)L.expires<=T&&y.delete(x);let C=y.get(I);if(C)return y.delete(I),y.set(I,C),JSON.parse(C.json);let P=A.actions.map(x=>x.id),b=x=>{if(x.type==="stack")return{...x,children:x.children.map(b)};if(x.type!=="custom_html")return x;let L={};for(let[$,te]of Object.entries(x.html))L[$]=ze(te,P,p);return{...x,html:L,css:Ke(x.css)}},v={...A,pages:A.pages.map(x=>({...x,root:b(x.root)}))};Nt(v,void 0,p);let N=JSON.stringify(v),H=new TextEncoder,F=H.encode(N).length;if(F>De.documentBytes)throw new Error(`\u754C\u9762\u5185\u5BB9\u8FC7\u5927\uFF08\u4E0A\u9650 ${De.documentBytes/1e3} KB\uFF09\u3002`);let W=H.encode(I).length;if(W<=De.documentBytes){y.set(I,{json:N,bytes:W+F,expires:T+6e4});let x=[...y.values()].reduce((L,$)=>L+$.bytes,0);for(;y.size>16||x>2*1024*1024;){let[L,$]=y.entries().next().value;y.delete(L),x-=$.bytes}}return v}function Ze(c){function p(e){return e.type==="stack"&&e.interaction?.type==="select"&&e.interaction.purpose==="product"&&!!e.interaction.pickerId}function A(e){let a={};function t(r){if(p(r)){let i=a[r.interaction.pickerId]??={ids:[],defaultId:null};for(let n of r.children){let l=n.type==="stack"?n.bind?.plan:void 0;l&&!i.ids.includes(l)&&i.ids.push(l)}let s=r.children[r.interaction.defaultIndex];!i.defaultId&&s?.type==="stack"&&(i.defaultId=s.bind?.plan??null)}r.type==="stack"&&r.children.forEach(t)}return e.pages.forEach(r=>t(r.root)),a}function I(e,a,t){let r={};function i(d){if(d.hidden||d.type!=="stack")return;let u=d.children.filter(o=>!o.hidden),h=d.interaction;if(p(d)){let o=r[d.interaction.pickerId]??={ids:[],defaults:[],remembered:[]},f=t.pickers[d.interaction.pickerId]?.options??[];for(let w of u){let z=w.type==="stack"?w.bind?.plan:void 0;z&&f.includes(z)&&!o.ids.includes(z)&&o.ids.push(z),z&&w.id===a[d.id]&&o.remembered.push(z)}let m=d.children[d.interaction.defaultIndex];m?.type==="stack"&&!m.hidden&&m.bind?.plan&&o.defaults.push(m.bind.plan)}if(h?.type==="tabs"){let o=u.find(f=>f.id===a[d.id])??d.children[h.defaultIndex];o&&i(o)}else if(h?.type==="toggle"){let o=typeof a[d.id]=="boolean"?a[d.id]:h.defaultEnabled,f=d.children[o?0:1];f&&i(f)}else u.forEach(i)}let s=typeof a.__page=="string"?a.__page:e.initialPageId??e.pages[0]?.id,n=e.pages.find(d=>d.id===s);n&&i(n.root);let l={};for(let[d,u]of Object.entries(r)){let h=a[d],o=u.remembered[0]??(u.ids.includes(t.pickers[d]?.selected??"")?t.pickers[d]?.selected:u.defaults[0]);l[d]=typeof h=="string"?u.ids.includes(h)?h:"":o&&u.ids.includes(o)?o:""}for(let d of Object.keys(A(e)))l[d]??="";return l}let y=window;for(let e=0;e<c.hostDepth;e++)y=y.parent;let T=window,C={none:0,xs:4,sm:8,md:12,lg:20,xl:32},P={none:0,sm:4,md:8,lg:14,full:9999},b={system:'system-ui,-apple-system,"Segoe UI",Roboto,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans CJK SC",sans-serif',serif:'Georgia,"Times New Roman","Songti SC","Noto Serif CJK SC",serif',rounded:'ui-rounded,"SF Pro Rounded","Hiragino Maru Gothic ProN",system-ui,sans-serif',mono:"ui-monospace,SFMono-Regular,Menlo,Consolas,monospace"},v={start:"flex-start",center:"center",end:"flex-end",stretch:"stretch"},N={start:"flex-start",center:"center",end:"flex-end",between:"space-between"},H={start:"start",center:"center",end:"end",between:"stretch"},F={start:"start",center:"center",end:"end",stretch:"stretch"},W={"1:1":"1 / 1","4:3":"4 / 3","16:9":"16 / 9","3:1":"3 / 1"},x=`
|
|
2
2
|
*,*::before,*::after{box-sizing:border-box}
|
|
3
3
|
html,body{margin:0;padding:0;background:transparent}
|
|
4
4
|
body{font-family:var(--g-font);color:var(--g-text);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
|
package/dist/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as T,b as v,d as te,e as pe,f as de}from"./chunk-PTWRGCVW.js";import{a as o,b as I}from"./chunk-X5UXOLOU.js";import{Aj as Y,Cj as H,Ck as b,Dk as Z,Fk as J,G as O,Gj as C,Hj as _,Ij as W,Ll as X,Ml as ee,Wg as j,Xg as Q,Yg as K,Zg as G,_g as z,ci as $,qi as c,zj as P}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";function p(r,n){try{return r.parse(n)}catch{throw new o("INVALID_RESPONSE","Invalid gateway response")}}function le(r){if(typeof window<"u")throw new o("SERVER_ONLY","Secret API keys must stay on the backend");return{start:n=>te(r,n)}}var S=class extends o{constructor(t,e){super("DECISION_PENDING","Decision is still pending; read this decision ID or retry the original request ID",202,e);this.decisionId=t;this.decisionRequestId=e}decisionId;decisionRequestId};function U(r){if("remoteEval"in r)throw new o("INVALID_REQUEST","Configure evaluation mode on the Funnel; remoteEval is not supported");if(typeof window<"u")throw new o("SERVER_ONLY","Funnel decisions are requested by your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","A server API key is required");async function n(a,s,i=!1){let u=I({...r,fetch:(m,f)=>{let d=new Headers(f?.headers);return d.set("Accept-Encoding","identity"),i&&d.set("Prefer","respond-async"),(r.fetch??globalThis.fetch)(m,{...f,headers:d})},timeoutMs:Math.min(r.timeoutMs??1e4,s?Math.max(1,s-Date.now()):12e4)});return u.identify(r.apiKey),u.request("funnels",a)}async function t(a,s){let i=_.parse(await n(C.parse({operation:"read_decision",decisionId:a}),s));if(i.decisionId!==a)throw new o("INVALID_RESPONSE","Decision identity changed");return i}async function e(a,s,i=!1){let u=C.options[0].parse({...a,operation:"decide",funnelId:r.funnelId}),m;try{m=_.parse(await n(u,s,i))}catch(f){throw f instanceof o&&["TIMEOUT","NETWORK_ERROR","SERVICE_UNAVAILABLE"].includes(f.code)?new o("DECISION_ACCEPTANCE_UNKNOWN","Decision acceptance is unknown; retry the original request ID and input",f.status,a.requestId):f}if(m.requestId!==a.requestId||m.decision&&!v(m.decision,u.customer))throw new o("INVALID_RESPONSE","Decision request or customer changed");return{response:m,customer:u.customer}}return{async configuration(){let a=J.parse(await n({operation:"configuration",funnelId:r.funnelId}));if(a.scope.projectId!==r.scope.projectId||a.scope.environment!==r.scope.environment||a.funnelId!==r.funnelId)throw new o("SCOPE_MISMATCH","Configuration scope changed");return a},features(a={}){return T({...a,scope:r.scope,load:async()=>$.parse(await n({operation:"feature_config",funnelId:r.funnelId}))})},read:a=>t(a),async submit(a){return(await e(a,void 0,!0)).response},async decide(a){let s=Date.now()+3e4,i=await e(a,s),u=i.response,m=u.decisionId,f=250;for(;;){if(u.requestId!==a.requestId||u.decision&&!v(u.decision,i.customer))throw new o("INVALID_RESPONSE","Decision request or customer changed");if(u.decision)return u.decision;if(u.status==="failed")throw new o("DECISION_FAILED","Decision execution failed",503,a.requestId);if(Date.now()>=s)throw new S(m,a.requestId);if(await new Promise(d=>setTimeout(d,Math.min(f,s-Date.now()))),Date.now()>=s)throw new S(m,a.requestId);try{f=Math.min(1e3,f*2),u=await t(m,s)}catch(d){if(d instanceof o&&["TIMEOUT","NETWORK_ERROR","SERVICE_UNAVAILABLE","RATE_LIMITED"].includes(d.code))continue;throw d}}},async reportUsed(a){let s=W.parse(await n(C.parse({...a,operation:"report_used"})));if(s.decisionId!==a.decisionId||s.eventId!==a.eventId)throw new o("INVALID_RESPONSE","Usage receipt identity changed");return s}}}function me(r){if(typeof window<"u")throw new o("SERVER_ONLY","Native receipts are verified by your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","Server API key required");let n=I({...r,timeoutMs:r.timeoutMs??35e3});return n.identify(r.apiKey),{async recover(t){let e=X.parse(t);if(e.orderId!==e.receiptId)throw new o("INVALID_REQUEST","Native recovery requires the accepted commercial intent");let a=e.nativeEvidence,s={requestId:e.requestId,customerToken:e.customerToken,purchaseIntentId:e.orderId,...a===null?{intent:"read"}:a.provider==="apple"?{provider:"apple",signedTransaction:a.signedTransaction}:{provider:"google",purchaseToken:a.purchaseToken}},i=c.restoreNativePurchase.response.parse(await n.request(c.restoreNativePurchase.path,s));if(i.operation.requestId!==e.requestId)throw new o("INVALID_RESPONSE","Native receipt request identity changed");let u=ee.parse({scope:i.scope,requestId:e.requestId,orderId:i.operation.orderId,receiptId:i.operation.orderId,orderStatus:i.operation.status,refunded:i.operation.refunded,...i.operation.completion===null?{}:{nativeCompletion:{orderId:i.operation.orderId,receiptId:i.operation.orderId,...i.operation.completion}}});if(u.requestId!==e.requestId||u.orderId!==e.orderId||u.receiptId!==e.receiptId||u.scope.projectId!==r.scope.projectId||u.scope.environment!==r.scope.environment)throw new o("INVALID_RESPONSE","Current order receipt scope changed");return u}}}import{z as l}from"zod";var q=j,fe=l.string().regex(/^(0|[1-9]\d{0,5})(\.\d{1,12})?$/),se=l.strictObject(Object.fromEntries(q.map(r=>[r,l.number().int().nonnegative().max(1e9)]))),ie=Q,we=K,D=l.strictObject({modelId:ie,source:l.enum(["models.dev","custom"]),fetchedAt:l.iso.datetime(),rates:G,contextTier:l.number().int().nonnegative(),markupPercent:we}),x=l.strictObject({pricing:D,tokens:se,quantity:O,digest:l.string().regex(/^[a-f0-9]{64}$/)}),oe=r=>{let[n,t=""]=r.split(".");return BigInt(n)*10n**12n+BigInt(t.padEnd(12,"0"))};function Ie(r){if(typeof r!="number"||!Number.isFinite(r)||r<0)throw new o("AI_PRICE_UNAVAILABLE","A published token price is missing");let n=String(r),t=n.includes("e")?r.toFixed(12).replace(/0+$/,"").replace(/\.$/,""):n;if(Number(t)!==r||!fe.safeParse(t).success)throw new o("AI_PRICE_UNAVAILABLE","Published price exceeds the supported precision");return t}var ne=l.strictObject({input:l.number().nonnegative(),output:l.number().nonnegative(),cache_read:l.number().nonnegative().optional(),cache_write:l.number().nonnegative().optional(),reasoning:l.number().nonnegative().optional(),input_audio:l.number().nonnegative().optional(),output_audio:l.number().nonnegative().optional()}),ge=ne.extend({context_over_200k:l.unknown().optional(),tiers:l.array(ne.extend({tier:l.strictObject({type:l.literal("context"),size:l.number().int().nonnegative()})})).max(20).refine(r=>new Set(r.map(n=>n.tier.size)).size===r.length).optional()});async function re(r,n,t){let e=new TextEncoder().encode(JSON.stringify({pricing:r,tokens:n,quantity:t}));return[...new Uint8Array(await crypto.subtle.digest("SHA-256",e))].map(a=>a.toString(16).padStart(2,"0")).join("")}function ae(r,n){let t=0n;for(let w of q){if(!n[w])continue;let g=r.rates[w];if(g===void 0)throw new o("AI_PRICE_UNAVAILABLE",`No published price for ${w}; report exclusive token pools`);t+=oe(g)*BigInt(n[w])}let[e,a="0"]=String(r.markupPercent).split("e"),s=(e.split(".")[1]?.length??0)-Number(a),i=10n**BigInt(Math.max(s,0)),u=BigInt(e.replace(".",""))*10n**BigInt(Math.max(-s,0)),m=100n*i+u,f=100n*i*1000000n,d=(t*m+f-1n)/f;return O.parse(`${d/1000000n}.${(d%1000000n).toString().padStart(6,"0")}`)}function ce(r={}){if(typeof window<"u")throw new o("SERVER_ONLY","AI token pricing belongs on your backend");let n=z.parse({defaultMarkup:r.defaultMarkup??0,providerMarkups:r.providerMarkups??{},modelMarkups:r.modelMarkups??{},customModels:r.customModels??{}}),t=null,e=0;async function a(){if(!t||Date.now()>=e){e=Date.now()+15*6e4;let s=(async()=>{let i=await(r.fetch??fetch)("https://models.dev/api.json",{signal:AbortSignal.timeout(3e4)});if(!i.ok)throw new o("AI_PRICE_UNAVAILABLE","Models.dev pricing is unavailable");return{data:l.record(l.string(),l.object({models:l.record(l.string(),l.unknown())})).parse(await i.json()),fetchedAt:new Date().toISOString()}})().catch(i=>{throw t===s&&(t=null),i});t=s}return t}return{refreshPrices(){t=null,e=0},async quoteTokens(s){let i=ie.parse(s.modelId),u=se.parse(s.tokens),[m,...f]=i.split("/"),d=n.customModels[i],w,g,h,L=0;if(d?.input!==void 0&&d.output!==void 0&&q.every(E=>u[E]===0||d[E]!==void 0))w={...d,input:d.input,output:d.output},g="custom",h=new Date().toISOString();else{let E=await a(),V=E.data[m]?.models[f.join("/")];if(!V)throw new o("AI_PRICE_UNAVAILABLE","Unknown model; configure a complete custom price");let{cost:k}=l.object({cost:ge}).parse(V),M=u.input+u.cache_read+u.cache_write+u.input_audio;if(k.tiers===void 0&&k.context_over_200k!==void 0&&M>2e5)throw new o("AI_PRICE_UNAVAILABLE","A current context tier is required for this model");let N=k.tiers?.filter(y=>M>y.tier.size).sort((y,ue)=>ue.tier.size-y.tier.size)[0],B=N??k;N&&(L=N.tier.size),w=Object.fromEntries(q.filter(y=>B[y]!==void 0).map(y=>[y,Ie(B[y])])),w={...w,...d},g=d?"custom":"models.dev",h=E.fetchedAt}let R=D.parse({modelId:i,source:g,fetchedAt:h,rates:w,contextTier:L,markupPercent:n.modelMarkups[i]??n.providerMarkups[m]??n.defaultMarkup}),F=ae(R,u);return x.parse({pricing:R,tokens:u,quantity:F,digest:await re(R,u,F)})},async trackTokens(s,i){let u=x.parse(i.quote);if(u.quantity!==ae(u.pricing,u.tokens)||u.digest!==await re(u.pricing,u.tokens,u.quantity))throw new o("INVALID_REQUEST","AI quote changed after pricing");let m=i.properties??{},f=i.providerCostUsd===void 0?void 0:l.string().regex(/^(0|[1-9]\d{0,11})(\.\d{1,18})?$/).parse(i.providerCostUsd),d=i.generationId===void 0?void 0:l.string().min(1).max(120).parse(i.generationId),w=8+ +(f!==void 0)+ +(d!==void 0);if(Object.keys(m).some(h=>h.startsWith("ai_")))throw new o("INVALID_REQUEST","AI tracking reserves ai_ event properties");if(Object.keys(m).length>16-w)throw new o("INVALID_REQUEST","AI tracking properties exceed the available event budget");let g={operation:"consume",internal_feature_id:i.internal_feature_id,quantity:u.quantity,idempotencyKey:i.idempotencyKey,properties:{...m,...f!==void 0?{ai_provider_cost_usd:f}:{},...d!==void 0?{ai_generation_id:d}:{},ai_model:u.pricing.modelId,ai_source:u.pricing.source,ai_price_at:u.pricing.fetchedAt,ai_quote_hash:u.digest,ai_markup:String(u.pricing.markupPercent),ai_tier:String(u.pricing.contextTier),ai_tokens:q.map(h=>u.tokens[h]).join(","),ai_rates:"v1:"+q.map(h=>u.pricing.rates[h]===void 0?"-":oe(u.pricing.rates[h]).toString(36)).join(",")},...i.entityId?{entityId:i.entityId}:{}};return s.mutateBalance({customerId:i.customerId,command:g})}}}async function he(r,n,t={}){let{config:e,model_markups:a}=await r.readAiPricing(n);return ce({defaultMarkup:e.default_markup??0,providerMarkups:Object.fromEntries(Object.entries(e.provider_markups??{}).map(([s,i])=>[s,i.markup])),modelMarkups:Object.fromEntries(Object.entries(a??{}).filter(([,s])=>s.markup!==void 0).map(([s,i])=>[s,i.markup])),customModels:Object.fromEntries(Object.entries(a??{}).filter(([,s])=>s.input_cost!==void 0||s.output_cost!==void 0).map(([s,i])=>[s,{...i.input_cost!==void 0?{input:String(i.input_cost)}:{},...i.output_cost!==void 0?{output:String(i.output_cost)}:{}}])),...t})}import{z as ye}from"zod";var A=ye.number().int().min(0).max(Number.MAX_SAFE_INTEGER);function Se(r,n){let t=A.parse(r.inputTokens.total),e=A.parse(r.outputTokens.total),a=A.parse(r.inputTokens.cacheRead??0),s=A.parse(r.inputTokens.cacheWrite??0),i=A.parse(r.outputTokens.reasoning??0);if(a+s>t||i>e||r.inputTokens.noCache!==void 0&&A.parse(r.inputTokens.noCache)!==t-a-s||r.outputTokens.text!==void 0&&A.parse(r.outputTokens.text)!==e-i)throw new o("AI_USAGE_UNAVAILABLE","Provider token counts do not conserve total usage");return{input:t-a-s,cache_read:a,cache_write:s,output:n==="output"?e:e-i,reasoning:n==="separate"?i:0,input_audio:0,output_audio:0}}function Ae(r){if(typeof window<"u")throw new o("SERVER_ONLY","AI usage belongs on the trusted backend");if(!r.modelId||!["output","separate"].includes(r.reasoning))throw new o("INVALID_REQUEST","Model ID and reasoning pricing are required");async function n(e){await r.persist({context:e,modelId:r.modelId,usage:null,tokens:null,quote:null,receipt:null,phase:"incomplete"})}async function t(e,a){let s={context:e,modelId:r.modelId,usage:a,tokens:null,quote:null,receipt:null,phase:"captured"};await r.persist(s);let i=r.mapTokens?r.mapTokens(a):Se(a,r.reasoning),u=await r.pricing.quoteTokens({modelId:r.modelId,tokens:i});await r.persist({...s,tokens:i,quote:u,phase:"quoted"});let m=await r.pricing.trackTokens(r.client,{...e,quote:u});if(!m.receipt.accepted)throw new o("AI_BALANCE_REJECTED","AI usage was captured but the balance operation was rejected");await r.persist({...s,tokens:i,quote:u,receipt:m,phase:"settled"})}return{specificationVersion:"v4",async wrapGenerate({doGenerate:e}){let a=await r.context(),s;try{s=await e()}catch(i){throw await n(a),i}return await t(a,s.usage),s},async wrapStream({doStream:e}){let a=await r.context(),s;try{s=await e()}catch(d){throw await n(a),d}let i=!1,u=!1,m=s.stream.getReader();async function f(){i||u||(u=!0,await n(a))}return{...s,stream:new ReadableStream({async pull(d){try{let{value:w,done:g}=await m.read();if(g){if(!i)throw await f(),new o("AI_USAGE_UNAVAILABLE","Stream ended without final usage; no amount was invented");d.close();return}if(w.type==="finish"){if(i)throw new o("AI_USAGE_UNAVAILABLE","Provider sent more than one final usage record");i=!0,await t(a,w.usage)}d.enqueue(w)}catch(w){try{await f()}finally{d.error(w),await m.cancel(w)}}},async cancel(d){try{await f()}finally{await m.cancel(d)}}})}}}}function qe(r){if(typeof window<"u")throw new o("SERVER_ONLY","Funnel receipts are sent by your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","A server API key is required");let n=I(r);return n.identify(r.apiKey),{async signal(t){let e=P.parse({...t,operation:"signal"}),a=Y.parse(await n.request("funnels",e));if(a.runId!==t.runId||a.eventId!==t.eventId||a.scope.projectId!==r.scope.projectId||a.scope.environment!==r.scope.environment)throw new o("INVALID_RESPONSE","Receipt identity changed");return a},async readResults(t){let e=P.parse({operation:"read_results",runId:t}),a=H.parse(await n.request("funnels",e));if(a.runId!==t||a.scope.projectId!==r.scope.projectId||a.scope.environment!==r.scope.environment)throw new o("INVALID_RESPONSE","Result identity changed");return a}}}function Ee(r){if(typeof window<"u")throw new o("SERVER_ONLY","Campaign entry requires your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","A server API key is required");let n=I({...r,timeoutMs:r.timeoutMs??35e3});n.identify(r.apiKey);let t=U(r);return{async decide(e){let a=b.parse({...e,funnelId:r.funnelId,operation:"campaign_decide"}),s=_.parse(await n.request("funnels",a));if(s.scope.projectId!==r.scope.projectId||s.scope.environment!==r.scope.environment)throw new o("SCOPE_MISMATCH","Campaign scope changed");let i=s.decisionId,u=s.requestId,m=Date.now()+(r.timeoutMs??3e4);for(;s.status==="pending";){if(Date.now()>=m)throw new S(i,u);if(await new Promise(f=>setTimeout(f,250)),s=await t.read(i),s.requestId!==u)throw new o("INVALID_RESPONSE","Campaign decision identity changed")}if(s.status==="failed")throw new o("DECISION_FAILED","Campaign decision execution failed");if(!s.decision||!v(s.decision,a.customer))throw new o("INVALID_RESPONSE","Campaign Customer changed");return s.decision},async start(e){let a=b.parse({...e,funnelId:r.funnelId,operation:"campaign_start"}),s=Z.parse(await n.request("funnels",a));if(s.scope.projectId!==r.scope.projectId||s.scope.environment!==r.scope.environment)throw new o("SCOPE_MISMATCH","Campaign scope changed");if(!("suppressed"in s)&&(s.run.source.id!==r.funnelId||!s.customerId||a.customer.type==="id"&&s.customerId!==a.customer.value))throw new o("INVALID_RESPONSE","Campaign Funnel or Customer changed");return s}}}function tt(){if(typeof window<"u")throw new o("SERVER_ONLY","Guest identity is issued by your backend");let r=crypto.getRandomValues(new Uint8Array(32));return"gg_gc_"+btoa(String.fromCharCode(...r)).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")}function nt(r){if(typeof window<"u")throw new o("SERVER_ONLY","Secret API keys must stay on your backend");let n=I(r);return n.identify(r.apiKey),{async getFeatures(t={}){let e=c.getFeatures;return p(e.response,await n.request(e.path,e.request.parse(t),e.method))},async evaluateFeatures(t){let e=c.evaluateFeatures;return p(e.response,await n.request(e.path,e.request.parse(t),e.method))},async trackEvents(t){let e=c.trackEvents;return p(e.response,await n.request(e.path,e.request.parse(t),e.method))},async resolvePaywall(t){let e=c.resolvePaywall;return p(e.response,await n.request(e.path,e.request.parse(t)))},async resolveOffering(t){let e=c.resolveOffering;return p(e.response,await n.request(e.path,e.request.parse(t)))},async checkEntitlement(t){let e=c.checkEntitlement;return p(e.response,await n.request(e.path,e.request.parse(t)))},async setupPayment(t){let e=c.setupPayment;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readPaymentSetup(t){let e=c.readPaymentSetup;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewSubscriptionBatch(t){let e=c.previewSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async confirmSubscriptionBatch(t){let e=c.confirmSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionBatch(t){let e=c.readSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async abandonSubscriptionBatch(t){let e=c.abandonSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageSubscriptionTrial(t){let e=c.manageSubscriptionTrial;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionTrial(t){let e=c.readSubscriptionTrial;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listSubscriptions(t){let e=c.listSubscriptions;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listPurchases(t){let e=c.listPurchases;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listSubscriptionConflicts(t){let e=c.listSubscriptionConflicts;return p(e.response,await n.request(e.path,e.request.parse(t)))},async retrySubscriptionConflict(t){let e=c.retrySubscriptionConflict;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewRefund(t){let e=c.previewRefund;return p(e.response,await n.request(e.path,e.request.parse(t)))},async refund(t){let e=c.refund;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readRefund(t){let e=c.readRefund;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewUpdate(t){let e=c.previewUpdate;return p(e.response,await n.request(e.path,e.request.parse(t)))},async update(t){let e=c.update;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionUpdate(t){let e=c.readSubscriptionUpdate;return p(e.response,await n.request(e.path,e.request.parse(t)))},async restoreNativePurchase(t){let e=c.restoreNativePurchase;return p(e.response,await n.request(e.path,e.request.parse(t)))},async verifySubscriptions(t){let e=c.verifySubscriptions;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewAttach(t){let e=c.previewAttach;return p(e.response,await n.request(e.path,e.request.parse(t)))},async attach(t){let e=c.attach;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionOperation(t){let e=c.readSubscriptionOperation;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readAiPricing(t){let e=c.readAiPricing;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readUsage(t){let e=c.readUsage;return p(e.response,await n.request(e.path,e.request.parse(t)))},async setUsage(t){let e=c.setUsage;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageBalanceGrant(t){let e=c.manageBalanceGrant;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readBalanceSource(t){let e=c.readBalanceSource;return p(e.response,await n.request(e.path,e.request.parse(t)))},async adjustBalance(t){let e=c.adjustBalance;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listBalanceGrants(t){let e=c.listBalanceGrants;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageBillingLimits(t){let e=c.manageBillingLimits;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSeats(t){let e=c.readSeats;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageSeat(t){let e=c.manageSeat;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageUsageEntity(t){let e=c.manageUsageEntity;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readUsageAnalytics(t){let e=c.readUsageAnalytics;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readCreditAnalytics(t){let e=c.readCreditAnalytics;return p(e.response,await n.request(e.path,e.request.parse(t)))},async submitUsageBatch(t){let e=c.submitUsageBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readUsageBatch(t){let e=c.readUsageBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readHoldings(t){let e=c.readHoldings;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readLedger(t){let e=c.readLedger;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readBillingInvoice(t){let e=c.readBillingInvoice;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readCreditStatement(t){let e=c.readCreditStatement;return p(e.response,await n.request(e.path,e.request.parse(t)))},async quoteBalance(t){let e=c.quoteBalance;return p(e.response,await n.request(e.path,e.request.parse(t)))},async trackUsage(t){let e=c.trackUsage;return p(e.response,await n.request(e.path,e.request.parse(t)))},async mutateBalance(t){let e=c.mutateBalance;return p(e.response,await n.request(e.path,e.request.parse(t)))},async getCustomer(t){let e=c.getCustomer,a=e.request.safeParse(t);if(!a.success)throw new o("INVALID_REQUEST","Invalid customer lookup");let s=e.response.safeParse(await n.request(e.path,a.data));if(!s.success)throw new o("INVALID_RESPONSE","Invalid customer response");return s.data},async listCustomers(t={}){let e=c.listCustomers,a=e.request.safeParse(t);if(!a.success)throw new o("INVALID_REQUEST","Invalid customer filters");let s=e.response.safeParse(await n.request(e.path,a.data));if(!s.success)throw new o("INVALID_RESPONSE","Invalid customer response");return s.data},async updateCustomer(t){let e=c.updateCustomer,a=e.request.safeParse(t);if(!a.success)throw new o("INVALID_REQUEST","Invalid customer patch");let s=e.response.safeParse(await n.request(e.path,a.data));if(!s.success)throw new o("INVALID_RESPONSE","Invalid customer response");return s.data},async createGuestCustomer(t){let e=c.createGuestCustomer;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async resumeGuestSession(t){let e=c.resumeGuestSession;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async claimGuestCustomer(t){let e=c.claimGuestCustomer;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async renewCustomerSession(t){let e=c.renewSession;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async revokeCustomerSessions(t){let e=c.revokeSessions;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async createCustomerSession(t){let e=c.createSession.request.safeParse({customerId:t});if(!e.success)throw new o("INVALID_REQUEST","A customer ID is required");let a=c.createSession.response.safeParse(await n.request("customer-sessions",e.data));if(!a.success)throw new o("INVALID_RESPONSE","Invalid customer session response");return a.data},async getOrCreateCustomer(t){let e=c.createCustomer.request.safeParse(t);if(!e.success)throw new o("INVALID_REQUEST","Invalid customer input");let a=c.createCustomer.response.safeParse(await n.request("customers",e.data));if(!a.success)throw new o("INVALID_RESPONSE","Invalid customer response");return a.data},async grantOffer(t){let e=c.grantOffer.request.safeParse({...t,requestId:t.requestId??crypto.randomUUID()});if(!e.success)throw new o("INVALID_REQUEST","Invalid offer grant");let a=c.grantOffer.response.safeParse(await n.request("offers/grant",e.data));if(!a.success)throw new o("INVALID_RESPONSE","Invalid offer response");return a.data}}}async function rt(r,n){if(typeof window<"u")throw new o("SERVER_ONLY","Renewal requires your backend");let{funnelCredentialCommandSchema:t,funnelCredentialResponseSchema:e}=await import("./src-RZJKF6LQ.js"),a=I(r);return a.identify(r.apiKey),e.parse(await a.request("funnels",t.parse({...n,operation:"renew_run"})))}export{S as FunnelDecisionTimeoutError,o as IndianaError,D as aiPriceSnapshotSchema,x as aiTokenQuoteSchema,ce as createAiPricing,Ae as createAiUsageMiddleware,he as createConfiguredAiPricing,T as createFeatureClient,Ee as createFunnelCampaignClient,U as createFunnelDecisionClient,qe as createFunnelOrchestrationClient,de as createFunnelStartClient,tt as createGuestToken,nt as createIndianaServer,me as createNativeReceiptClient,le as createPaywallStartClient,pe as evaluateFunnelNode,rt as renewFunnelRun};
|
|
1
|
+
import{a as T,b as v,d as te,e as pe,f as de}from"./chunk-G5ZGWOLJ.js";import{a as o,b as I}from"./chunk-CRJJ4EA2.js";import{Aj as Y,Cj as H,Ck as b,Dk as Z,Fk as J,G as O,Gj as C,Hj as _,Ij as W,Ll as X,Ml as ee,Wg as j,Xg as Q,Yg as K,Zg as G,_g as z,ci as $,qi as c,zj as P}from"./chunk-D37O6FAW.js";import"./chunk-MJG7X7LM.js";function p(r,n){try{return r.parse(n)}catch{throw new o("INVALID_RESPONSE","Invalid gateway response")}}function le(r){if(typeof window<"u")throw new o("SERVER_ONLY","Secret API keys must stay on the backend");return{start:n=>te(r,n)}}var S=class extends o{constructor(t,e){super("DECISION_PENDING","Decision is still pending; read this decision ID or retry the original request ID",202,e);this.decisionId=t;this.decisionRequestId=e}decisionId;decisionRequestId};function U(r){if("remoteEval"in r)throw new o("INVALID_REQUEST","Configure evaluation mode on the Funnel; remoteEval is not supported");if(typeof window<"u")throw new o("SERVER_ONLY","Funnel decisions are requested by your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","A server API key is required");async function n(a,s,i=!1){let u=I({...r,fetch:(m,f)=>{let d=new Headers(f?.headers);return d.set("Accept-Encoding","identity"),i&&d.set("Prefer","respond-async"),(r.fetch??globalThis.fetch)(m,{...f,headers:d})},timeoutMs:Math.min(r.timeoutMs??1e4,s?Math.max(1,s-Date.now()):12e4)});return u.identify(r.apiKey),u.request("funnels",a)}async function t(a,s){let i=_.parse(await n(C.parse({operation:"read_decision",decisionId:a}),s));if(i.decisionId!==a)throw new o("INVALID_RESPONSE","Decision identity changed");return i}async function e(a,s,i=!1){let u=C.options[0].parse({...a,operation:"decide",funnelId:r.funnelId}),m;try{m=_.parse(await n(u,s,i))}catch(f){throw f instanceof o&&["TIMEOUT","NETWORK_ERROR","SERVICE_UNAVAILABLE"].includes(f.code)?new o("DECISION_ACCEPTANCE_UNKNOWN","Decision acceptance is unknown; retry the original request ID and input",f.status,a.requestId):f}if(m.requestId!==a.requestId||m.decision&&!v(m.decision,u.customer))throw new o("INVALID_RESPONSE","Decision request or customer changed");return{response:m,customer:u.customer}}return{async configuration(){let a=J.parse(await n({operation:"configuration",funnelId:r.funnelId}));if(a.scope.projectId!==r.scope.projectId||a.scope.environment!==r.scope.environment||a.funnelId!==r.funnelId)throw new o("SCOPE_MISMATCH","Configuration scope changed");return a},features(a={}){return T({...a,scope:r.scope,load:async()=>$.parse(await n({operation:"feature_config",funnelId:r.funnelId}))})},read:a=>t(a),async submit(a){return(await e(a,void 0,!0)).response},async decide(a){let s=Date.now()+3e4,i=await e(a,s),u=i.response,m=u.decisionId,f=250;for(;;){if(u.requestId!==a.requestId||u.decision&&!v(u.decision,i.customer))throw new o("INVALID_RESPONSE","Decision request or customer changed");if(u.decision)return u.decision;if(u.status==="failed")throw new o("DECISION_FAILED","Decision execution failed",503,a.requestId);if(Date.now()>=s)throw new S(m,a.requestId);if(await new Promise(d=>setTimeout(d,Math.min(f,s-Date.now()))),Date.now()>=s)throw new S(m,a.requestId);try{f=Math.min(1e3,f*2),u=await t(m,s)}catch(d){if(d instanceof o&&["TIMEOUT","NETWORK_ERROR","SERVICE_UNAVAILABLE","RATE_LIMITED"].includes(d.code))continue;throw d}}},async reportUsed(a){let s=W.parse(await n(C.parse({...a,operation:"report_used"})));if(s.decisionId!==a.decisionId||s.eventId!==a.eventId)throw new o("INVALID_RESPONSE","Usage receipt identity changed");return s}}}function me(r){if(typeof window<"u")throw new o("SERVER_ONLY","Native receipts are verified by your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","Server API key required");let n=I({...r,timeoutMs:r.timeoutMs??35e3});return n.identify(r.apiKey),{async recover(t){let e=X.parse(t);if(e.orderId!==e.receiptId)throw new o("INVALID_REQUEST","Native recovery requires the accepted commercial intent");let a=e.nativeEvidence,s={requestId:e.requestId,customerToken:e.customerToken,purchaseIntentId:e.orderId,...a===null?{intent:"read"}:a.provider==="apple"?{provider:"apple",signedTransaction:a.signedTransaction}:{provider:"google",purchaseToken:a.purchaseToken}},i=c.restoreNativePurchase.response.parse(await n.request(c.restoreNativePurchase.path,s));if(i.operation.requestId!==e.requestId)throw new o("INVALID_RESPONSE","Native receipt request identity changed");let u=ee.parse({scope:i.scope,requestId:e.requestId,orderId:i.operation.orderId,receiptId:i.operation.orderId,orderStatus:i.operation.status,refunded:i.operation.refunded,...i.operation.completion===null?{}:{nativeCompletion:{orderId:i.operation.orderId,receiptId:i.operation.orderId,...i.operation.completion}}});if(u.requestId!==e.requestId||u.orderId!==e.orderId||u.receiptId!==e.receiptId||u.scope.projectId!==r.scope.projectId||u.scope.environment!==r.scope.environment)throw new o("INVALID_RESPONSE","Current order receipt scope changed");return u}}}import{z as l}from"zod";var q=j,fe=l.string().regex(/^(0|[1-9]\d{0,5})(\.\d{1,12})?$/),se=l.strictObject(Object.fromEntries(q.map(r=>[r,l.number().int().nonnegative().max(1e9)]))),ie=Q,we=K,D=l.strictObject({modelId:ie,source:l.enum(["models.dev","custom"]),fetchedAt:l.iso.datetime(),rates:G,contextTier:l.number().int().nonnegative(),markupPercent:we}),x=l.strictObject({pricing:D,tokens:se,quantity:O,digest:l.string().regex(/^[a-f0-9]{64}$/)}),oe=r=>{let[n,t=""]=r.split(".");return BigInt(n)*10n**12n+BigInt(t.padEnd(12,"0"))};function Ie(r){if(typeof r!="number"||!Number.isFinite(r)||r<0)throw new o("AI_PRICE_UNAVAILABLE","A published token price is missing");let n=String(r),t=n.includes("e")?r.toFixed(12).replace(/0+$/,"").replace(/\.$/,""):n;if(Number(t)!==r||!fe.safeParse(t).success)throw new o("AI_PRICE_UNAVAILABLE","Published price exceeds the supported precision");return t}var ne=l.strictObject({input:l.number().nonnegative(),output:l.number().nonnegative(),cache_read:l.number().nonnegative().optional(),cache_write:l.number().nonnegative().optional(),reasoning:l.number().nonnegative().optional(),input_audio:l.number().nonnegative().optional(),output_audio:l.number().nonnegative().optional()}),ge=ne.extend({context_over_200k:l.unknown().optional(),tiers:l.array(ne.extend({tier:l.strictObject({type:l.literal("context"),size:l.number().int().nonnegative()})})).max(20).refine(r=>new Set(r.map(n=>n.tier.size)).size===r.length).optional()});async function re(r,n,t){let e=new TextEncoder().encode(JSON.stringify({pricing:r,tokens:n,quantity:t}));return[...new Uint8Array(await crypto.subtle.digest("SHA-256",e))].map(a=>a.toString(16).padStart(2,"0")).join("")}function ae(r,n){let t=0n;for(let w of q){if(!n[w])continue;let g=r.rates[w];if(g===void 0)throw new o("AI_PRICE_UNAVAILABLE",`No published price for ${w}; report exclusive token pools`);t+=oe(g)*BigInt(n[w])}let[e,a="0"]=String(r.markupPercent).split("e"),s=(e.split(".")[1]?.length??0)-Number(a),i=10n**BigInt(Math.max(s,0)),u=BigInt(e.replace(".",""))*10n**BigInt(Math.max(-s,0)),m=100n*i+u,f=100n*i*1000000n,d=(t*m+f-1n)/f;return O.parse(`${d/1000000n}.${(d%1000000n).toString().padStart(6,"0")}`)}function ce(r={}){if(typeof window<"u")throw new o("SERVER_ONLY","AI token pricing belongs on your backend");let n=z.parse({defaultMarkup:r.defaultMarkup??0,providerMarkups:r.providerMarkups??{},modelMarkups:r.modelMarkups??{},customModels:r.customModels??{}}),t=null,e=0;async function a(){if(!t||Date.now()>=e){e=Date.now()+15*6e4;let s=(async()=>{let i=await(r.fetch??fetch)("https://models.dev/api.json",{signal:AbortSignal.timeout(3e4)});if(!i.ok)throw new o("AI_PRICE_UNAVAILABLE","Models.dev pricing is unavailable");return{data:l.record(l.string(),l.object({models:l.record(l.string(),l.unknown())})).parse(await i.json()),fetchedAt:new Date().toISOString()}})().catch(i=>{throw t===s&&(t=null),i});t=s}return t}return{refreshPrices(){t=null,e=0},async quoteTokens(s){let i=ie.parse(s.modelId),u=se.parse(s.tokens),[m,...f]=i.split("/"),d=n.customModels[i],w,g,h,L=0;if(d?.input!==void 0&&d.output!==void 0&&q.every(E=>u[E]===0||d[E]!==void 0))w={...d,input:d.input,output:d.output},g="custom",h=new Date().toISOString();else{let E=await a(),V=E.data[m]?.models[f.join("/")];if(!V)throw new o("AI_PRICE_UNAVAILABLE","Unknown model; configure a complete custom price");let{cost:k}=l.object({cost:ge}).parse(V),M=u.input+u.cache_read+u.cache_write+u.input_audio;if(k.tiers===void 0&&k.context_over_200k!==void 0&&M>2e5)throw new o("AI_PRICE_UNAVAILABLE","A current context tier is required for this model");let N=k.tiers?.filter(y=>M>y.tier.size).sort((y,ue)=>ue.tier.size-y.tier.size)[0],B=N??k;N&&(L=N.tier.size),w=Object.fromEntries(q.filter(y=>B[y]!==void 0).map(y=>[y,Ie(B[y])])),w={...w,...d},g=d?"custom":"models.dev",h=E.fetchedAt}let R=D.parse({modelId:i,source:g,fetchedAt:h,rates:w,contextTier:L,markupPercent:n.modelMarkups[i]??n.providerMarkups[m]??n.defaultMarkup}),F=ae(R,u);return x.parse({pricing:R,tokens:u,quantity:F,digest:await re(R,u,F)})},async trackTokens(s,i){let u=x.parse(i.quote);if(u.quantity!==ae(u.pricing,u.tokens)||u.digest!==await re(u.pricing,u.tokens,u.quantity))throw new o("INVALID_REQUEST","AI quote changed after pricing");let m=i.properties??{},f=i.providerCostUsd===void 0?void 0:l.string().regex(/^(0|[1-9]\d{0,11})(\.\d{1,18})?$/).parse(i.providerCostUsd),d=i.generationId===void 0?void 0:l.string().min(1).max(120).parse(i.generationId),w=8+ +(f!==void 0)+ +(d!==void 0);if(Object.keys(m).some(h=>h.startsWith("ai_")))throw new o("INVALID_REQUEST","AI tracking reserves ai_ event properties");if(Object.keys(m).length>16-w)throw new o("INVALID_REQUEST","AI tracking properties exceed the available event budget");let g={operation:"consume",internal_feature_id:i.internal_feature_id,quantity:u.quantity,idempotencyKey:i.idempotencyKey,properties:{...m,...f!==void 0?{ai_provider_cost_usd:f}:{},...d!==void 0?{ai_generation_id:d}:{},ai_model:u.pricing.modelId,ai_source:u.pricing.source,ai_price_at:u.pricing.fetchedAt,ai_quote_hash:u.digest,ai_markup:String(u.pricing.markupPercent),ai_tier:String(u.pricing.contextTier),ai_tokens:q.map(h=>u.tokens[h]).join(","),ai_rates:"v1:"+q.map(h=>u.pricing.rates[h]===void 0?"-":oe(u.pricing.rates[h]).toString(36)).join(",")},...i.entityId?{entityId:i.entityId}:{}};return s.mutateBalance({customerId:i.customerId,command:g})}}}async function he(r,n,t={}){let{config:e,model_markups:a}=await r.readAiPricing(n);return ce({defaultMarkup:e.default_markup??0,providerMarkups:Object.fromEntries(Object.entries(e.provider_markups??{}).map(([s,i])=>[s,i.markup])),modelMarkups:Object.fromEntries(Object.entries(a??{}).filter(([,s])=>s.markup!==void 0).map(([s,i])=>[s,i.markup])),customModels:Object.fromEntries(Object.entries(a??{}).filter(([,s])=>s.input_cost!==void 0||s.output_cost!==void 0).map(([s,i])=>[s,{...i.input_cost!==void 0?{input:String(i.input_cost)}:{},...i.output_cost!==void 0?{output:String(i.output_cost)}:{}}])),...t})}import{z as ye}from"zod";var A=ye.number().int().min(0).max(Number.MAX_SAFE_INTEGER);function Se(r,n){let t=A.parse(r.inputTokens.total),e=A.parse(r.outputTokens.total),a=A.parse(r.inputTokens.cacheRead??0),s=A.parse(r.inputTokens.cacheWrite??0),i=A.parse(r.outputTokens.reasoning??0);if(a+s>t||i>e||r.inputTokens.noCache!==void 0&&A.parse(r.inputTokens.noCache)!==t-a-s||r.outputTokens.text!==void 0&&A.parse(r.outputTokens.text)!==e-i)throw new o("AI_USAGE_UNAVAILABLE","Provider token counts do not conserve total usage");return{input:t-a-s,cache_read:a,cache_write:s,output:n==="output"?e:e-i,reasoning:n==="separate"?i:0,input_audio:0,output_audio:0}}function Ae(r){if(typeof window<"u")throw new o("SERVER_ONLY","AI usage belongs on the trusted backend");if(!r.modelId||!["output","separate"].includes(r.reasoning))throw new o("INVALID_REQUEST","Model ID and reasoning pricing are required");async function n(e){await r.persist({context:e,modelId:r.modelId,usage:null,tokens:null,quote:null,receipt:null,phase:"incomplete"})}async function t(e,a){let s={context:e,modelId:r.modelId,usage:a,tokens:null,quote:null,receipt:null,phase:"captured"};await r.persist(s);let i=r.mapTokens?r.mapTokens(a):Se(a,r.reasoning),u=await r.pricing.quoteTokens({modelId:r.modelId,tokens:i});await r.persist({...s,tokens:i,quote:u,phase:"quoted"});let m=await r.pricing.trackTokens(r.client,{...e,quote:u});if(!m.receipt.accepted)throw new o("AI_BALANCE_REJECTED","AI usage was captured but the balance operation was rejected");await r.persist({...s,tokens:i,quote:u,receipt:m,phase:"settled"})}return{specificationVersion:"v4",async wrapGenerate({doGenerate:e}){let a=await r.context(),s;try{s=await e()}catch(i){throw await n(a),i}return await t(a,s.usage),s},async wrapStream({doStream:e}){let a=await r.context(),s;try{s=await e()}catch(d){throw await n(a),d}let i=!1,u=!1,m=s.stream.getReader();async function f(){i||u||(u=!0,await n(a))}return{...s,stream:new ReadableStream({async pull(d){try{let{value:w,done:g}=await m.read();if(g){if(!i)throw await f(),new o("AI_USAGE_UNAVAILABLE","Stream ended without final usage; no amount was invented");d.close();return}if(w.type==="finish"){if(i)throw new o("AI_USAGE_UNAVAILABLE","Provider sent more than one final usage record");i=!0,await t(a,w.usage)}d.enqueue(w)}catch(w){try{await f()}finally{d.error(w),await m.cancel(w)}}},async cancel(d){try{await f()}finally{await m.cancel(d)}}})}}}}function qe(r){if(typeof window<"u")throw new o("SERVER_ONLY","Funnel receipts are sent by your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","A server API key is required");let n=I(r);return n.identify(r.apiKey),{async signal(t){let e=P.parse({...t,operation:"signal"}),a=Y.parse(await n.request("funnels",e));if(a.runId!==t.runId||a.eventId!==t.eventId||a.scope.projectId!==r.scope.projectId||a.scope.environment!==r.scope.environment)throw new o("INVALID_RESPONSE","Receipt identity changed");return a},async readResults(t){let e=P.parse({operation:"read_results",runId:t}),a=H.parse(await n.request("funnels",e));if(a.runId!==t||a.scope.projectId!==r.scope.projectId||a.scope.environment!==r.scope.environment)throw new o("INVALID_RESPONSE","Result identity changed");return a}}}function Ee(r){if(typeof window<"u")throw new o("SERVER_ONLY","Campaign entry requires your backend");if(!/^gg_sk_[A-Za-z0-9_-]{32,128}$/.test(r.apiKey))throw new o("INVALID_TOKEN","A server API key is required");let n=I({...r,timeoutMs:r.timeoutMs??35e3});n.identify(r.apiKey);let t=U(r);return{async decide(e){let a=b.parse({...e,funnelId:r.funnelId,operation:"campaign_decide"}),s=_.parse(await n.request("funnels",a));if(s.scope.projectId!==r.scope.projectId||s.scope.environment!==r.scope.environment)throw new o("SCOPE_MISMATCH","Campaign scope changed");let i=s.decisionId,u=s.requestId,m=Date.now()+(r.timeoutMs??3e4);for(;s.status==="pending";){if(Date.now()>=m)throw new S(i,u);if(await new Promise(f=>setTimeout(f,250)),s=await t.read(i),s.requestId!==u)throw new o("INVALID_RESPONSE","Campaign decision identity changed")}if(s.status==="failed")throw new o("DECISION_FAILED","Campaign decision execution failed");if(!s.decision||!v(s.decision,a.customer))throw new o("INVALID_RESPONSE","Campaign Customer changed");return s.decision},async start(e){let a=b.parse({...e,funnelId:r.funnelId,operation:"campaign_start"}),s=Z.parse(await n.request("funnels",a));if(s.scope.projectId!==r.scope.projectId||s.scope.environment!==r.scope.environment)throw new o("SCOPE_MISMATCH","Campaign scope changed");if(!("suppressed"in s)&&(s.run.source.id!==r.funnelId||!s.customerId||a.customer.type==="id"&&s.customerId!==a.customer.value))throw new o("INVALID_RESPONSE","Campaign Funnel or Customer changed");return s}}}function tt(){if(typeof window<"u")throw new o("SERVER_ONLY","Guest identity is issued by your backend");let r=crypto.getRandomValues(new Uint8Array(32));return"gg_gc_"+btoa(String.fromCharCode(...r)).replaceAll("+","-").replaceAll("/","_").replaceAll("=","")}function nt(r){if(typeof window<"u")throw new o("SERVER_ONLY","Secret API keys must stay on your backend");let n=I(r);return n.identify(r.apiKey),{async getFeatures(t={}){let e=c.getFeatures;return p(e.response,await n.request(e.path,e.request.parse(t),e.method))},async evaluateFeatures(t){let e=c.evaluateFeatures;return p(e.response,await n.request(e.path,e.request.parse(t),e.method))},async trackEvents(t){let e=c.trackEvents;return p(e.response,await n.request(e.path,e.request.parse(t),e.method))},async resolvePaywall(t){let e=c.resolvePaywall;return p(e.response,await n.request(e.path,e.request.parse(t)))},async resolveOffering(t){let e=c.resolveOffering;return p(e.response,await n.request(e.path,e.request.parse(t)))},async checkEntitlement(t){let e=c.checkEntitlement;return p(e.response,await n.request(e.path,e.request.parse(t)))},async setupPayment(t){let e=c.setupPayment;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readPaymentSetup(t){let e=c.readPaymentSetup;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewSubscriptionBatch(t){let e=c.previewSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async confirmSubscriptionBatch(t){let e=c.confirmSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionBatch(t){let e=c.readSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async abandonSubscriptionBatch(t){let e=c.abandonSubscriptionBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageSubscriptionTrial(t){let e=c.manageSubscriptionTrial;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionTrial(t){let e=c.readSubscriptionTrial;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listSubscriptions(t){let e=c.listSubscriptions;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listPurchases(t){let e=c.listPurchases;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listSubscriptionConflicts(t){let e=c.listSubscriptionConflicts;return p(e.response,await n.request(e.path,e.request.parse(t)))},async retrySubscriptionConflict(t){let e=c.retrySubscriptionConflict;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewRefund(t){let e=c.previewRefund;return p(e.response,await n.request(e.path,e.request.parse(t)))},async refund(t){let e=c.refund;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readRefund(t){let e=c.readRefund;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewUpdate(t){let e=c.previewUpdate;return p(e.response,await n.request(e.path,e.request.parse(t)))},async update(t){let e=c.update;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionUpdate(t){let e=c.readSubscriptionUpdate;return p(e.response,await n.request(e.path,e.request.parse(t)))},async restoreNativePurchase(t){let e=c.restoreNativePurchase;return p(e.response,await n.request(e.path,e.request.parse(t)))},async verifySubscriptions(t){let e=c.verifySubscriptions;return p(e.response,await n.request(e.path,e.request.parse(t)))},async previewAttach(t){let e=c.previewAttach;return p(e.response,await n.request(e.path,e.request.parse(t)))},async attach(t){let e=c.attach;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSubscriptionOperation(t){let e=c.readSubscriptionOperation;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readAiPricing(t){let e=c.readAiPricing;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readUsage(t){let e=c.readUsage;return p(e.response,await n.request(e.path,e.request.parse(t)))},async setUsage(t){let e=c.setUsage;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageBalanceGrant(t){let e=c.manageBalanceGrant;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readBalanceSource(t){let e=c.readBalanceSource;return p(e.response,await n.request(e.path,e.request.parse(t)))},async adjustBalance(t){let e=c.adjustBalance;return p(e.response,await n.request(e.path,e.request.parse(t)))},async listBalanceGrants(t){let e=c.listBalanceGrants;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageBillingLimits(t){let e=c.manageBillingLimits;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readSeats(t){let e=c.readSeats;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageSeat(t){let e=c.manageSeat;return p(e.response,await n.request(e.path,e.request.parse(t)))},async manageUsageEntity(t){let e=c.manageUsageEntity;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readUsageAnalytics(t){let e=c.readUsageAnalytics;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readCreditAnalytics(t){let e=c.readCreditAnalytics;return p(e.response,await n.request(e.path,e.request.parse(t)))},async submitUsageBatch(t){let e=c.submitUsageBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readUsageBatch(t){let e=c.readUsageBatch;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readHoldings(t){let e=c.readHoldings;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readLedger(t){let e=c.readLedger;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readBillingInvoice(t){let e=c.readBillingInvoice;return p(e.response,await n.request(e.path,e.request.parse(t)))},async readCreditStatement(t){let e=c.readCreditStatement;return p(e.response,await n.request(e.path,e.request.parse(t)))},async quoteBalance(t){let e=c.quoteBalance;return p(e.response,await n.request(e.path,e.request.parse(t)))},async trackUsage(t){let e=c.trackUsage;return p(e.response,await n.request(e.path,e.request.parse(t)))},async mutateBalance(t){let e=c.mutateBalance;return p(e.response,await n.request(e.path,e.request.parse(t)))},async getCustomer(t){let e=c.getCustomer,a=e.request.safeParse(t);if(!a.success)throw new o("INVALID_REQUEST","Invalid customer lookup");let s=e.response.safeParse(await n.request(e.path,a.data));if(!s.success)throw new o("INVALID_RESPONSE","Invalid customer response");return s.data},async listCustomers(t={}){let e=c.listCustomers,a=e.request.safeParse(t);if(!a.success)throw new o("INVALID_REQUEST","Invalid customer filters");let s=e.response.safeParse(await n.request(e.path,a.data));if(!s.success)throw new o("INVALID_RESPONSE","Invalid customer response");return s.data},async updateCustomer(t){let e=c.updateCustomer,a=e.request.safeParse(t);if(!a.success)throw new o("INVALID_REQUEST","Invalid customer patch");let s=e.response.safeParse(await n.request(e.path,a.data));if(!s.success)throw new o("INVALID_RESPONSE","Invalid customer response");return s.data},async createGuestCustomer(t){let e=c.createGuestCustomer;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async resumeGuestSession(t){let e=c.resumeGuestSession;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async claimGuestCustomer(t){let e=c.claimGuestCustomer;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async renewCustomerSession(t){let e=c.renewSession;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async revokeCustomerSessions(t){let e=c.revokeSessions;return e.response.parse(await n.request(e.path,e.request.parse(t)))},async createCustomerSession(t){let e=c.createSession.request.safeParse({customerId:t});if(!e.success)throw new o("INVALID_REQUEST","A customer ID is required");let a=c.createSession.response.safeParse(await n.request("customer-sessions",e.data));if(!a.success)throw new o("INVALID_RESPONSE","Invalid customer session response");return a.data},async getOrCreateCustomer(t){let e=c.createCustomer.request.safeParse(t);if(!e.success)throw new o("INVALID_REQUEST","Invalid customer input");let a=c.createCustomer.response.safeParse(await n.request("customers",e.data));if(!a.success)throw new o("INVALID_RESPONSE","Invalid customer response");return a.data},async grantOffer(t){let e=c.grantOffer.request.safeParse({...t,requestId:t.requestId??crypto.randomUUID()});if(!e.success)throw new o("INVALID_REQUEST","Invalid offer grant");let a=c.grantOffer.response.safeParse(await n.request("offers/grant",e.data));if(!a.success)throw new o("INVALID_RESPONSE","Invalid offer response");return a.data}}}async function rt(r,n){if(typeof window<"u")throw new o("SERVER_ONLY","Renewal requires your backend");let{funnelCredentialCommandSchema:t,funnelCredentialResponseSchema:e}=await import("./src-RZJKF6LQ.js"),a=I(r);return a.identify(r.apiKey),e.parse(await a.request("funnels",t.parse({...n,operation:"renew_run"})))}export{S as FunnelDecisionTimeoutError,o as IndianaError,D as aiPriceSnapshotSchema,x as aiTokenQuoteSchema,ce as createAiPricing,Ae as createAiUsageMiddleware,he as createConfiguredAiPricing,T as createFeatureClient,Ee as createFunnelCampaignClient,U as createFunnelDecisionClient,qe as createFunnelOrchestrationClient,de as createFunnelStartClient,tt as createGuestToken,nt as createIndianaServer,me as createNativeReceiptClient,le as createPaywallStartClient,pe as evaluateFunnelNode,rt as renewFunnelRun};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinkerlandai/indiana-sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Framework-independent Indiana SDK for customer identity, entitlements, credits, offers and growth surfaces.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
22
|
"README.md",
|
|
23
|
+
"README.zh-CN.md",
|
|
23
24
|
"CHANGELOG.md",
|
|
24
25
|
"THIRD_PARTY_NOTICES.md"
|
|
25
26
|
],
|
package/dist/chunk-X5UXOLOU.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Y as S,_b as C,gc as k,jc as L,mc as T,nc as v,oc as j,rc as R,ui as V}from"./chunk-D37O6FAW.js";var U={name:"@tinkerlandai/indiana-sdk",version:"0.3.0",description:"Framework-independent Indiana SDK for customer identity, entitlements, credits, offers and growth surfaces.",license:"UNLICENSED",repository:{type:"git",url:"git+https://github.com/tinkerlandai/Indiana.git",directory:"packages/sdk"},engines:{node:">=22"},publishConfig:{access:"public",tag:"beta"},type:"module",sideEffects:!1,files:["dist","README.md","CHANGELOG.md","THIRD_PARTY_NOTICES.md"],exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"},"./popup":{types:"./dist/popup.d.ts",import:"./dist/popup.js"},"./server":{types:"./dist/server.d.ts",import:"./dist/server.js"},"./openrouter":{types:"./dist/openrouter.d.ts",import:"./dist/openrouter.js"},"./native-shell":{types:"./dist/native-shell.d.ts",import:"./dist/native-shell.js"},"./page":{types:"./dist/page.d.ts",import:"./dist/page.js"}},scripts:{build:"tsup",prepack:"pnpm run build",typecheck:"tsc --noEmit"},dependencies:{"@ai-sdk/provider":"4.0.26","@types/json-schema":"7.0.15","css-tree":"^3.2.1",dompurify:"^3.4.15",zod:"4.6.5"},devDependencies:{"@indiana/contracts":"workspace:*","@openrouter/sdk":"^1.4.25","@types/css-tree":"^3.2.0",ai:"7.0.136",tsup:"^8.5.1",typescript:"^5.9.3"},peerDependencies:{"@openrouter/sdk":"^1.4.25"},peerDependenciesMeta:{"@openrouter/sdk":{optional:!0}}};var e=class extends Error{constructor(f,d,n,N,i){super(d);this.code=f;this.status=n;this.requestId=N;this.name="IndianaError",this.reason=i?.reason;let c=T(f,n??0,{...i,retryAfter:i?.retryAfterSeconds===void 0?void 0:String(i.retryAfterSeconds)});this.retryable=c.retryable,this.recovery=c.recovery,this.retryAfterSeconds=c.retryAfterSeconds}code;status;requestId;retryable;recovery;retryAfterSeconds;reason},$=Symbol("IndianaNoContent");function J(l,A){let f=l.webView??"hosted";if(!["hosted","embedded"].includes(f))throw new e("INVALID_REQUEST","Invalid Web View mode");let d=l.scope?S.parse(l.scope):void 0,n=new URL(l.baseUrl);if(n.username||n.password||n.search||n.hash)throw new e("INVALID_URL","baseUrl must not contain credentials, query, or fragment");if(n.protocol!=="https:"&&!(n.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(n.hostname)))throw new e("INVALID_URL","Use HTTPS, or HTTP on localhost during development");let N=l.fetch??globalThis.fetch.bind(globalThis),i=l.timeoutMs??1e4;if(!Number.isFinite(i)||i<=0||i>12e4)throw new e("INVALID_TIMEOUT","timeoutMs must be between 1 and 120000");let c=null,b,u=0,p=null,h=new Set;function O(){u+=1,c=null,p=null;for(let s of h)s.abort();h.clear()}async function M(s,q={},D="POST",H={}){if(!c)throw new e("NOT_IDENTIFIED","Call identify with a server-issued customer token first");let g=u,o=new AbortController;h.add(o);let y=()=>g!==u?new e("IDENTITY_CHANGED","Customer identity changed while the request was in flight"):new e("TIMEOUT","Indiana request timed out"),I,x=new Promise((r,a)=>{I=()=>a(y()),o.signal.addEventListener("abort",I,{once:!0})}),K=setTimeout(()=>o.abort(),i),G=async()=>{let r=await N(`${n.href.replace(/\/$/,"")}/api/v1/${s}`,{method:D,headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`,[v]:R.current,[j]:U.version,...d?{"X-Indiana-Project":d.projectId,"X-Indiana-Environment":d.environment}:{}},body:D==="POST"?JSON.stringify(q):void 0,signal:o.signal,credentials:"omit",cache:"no-store",redirect:"error",...H.keepalive?{keepalive:!0}:{}});if(o.signal.aborted)throw y();let a;try{a=r.status===204?$:await r.json()}catch{throw o.signal.aborted?y():new e(r.ok?"INVALID_RESPONSE":"HTTP_ERROR","The gateway returned an unreadable response",r.status,r.headers.get("X-Request-Id")??void 0)}if(o.signal.aborted)throw y();if(g!==u)throw new e("IDENTITY_CHANGED","Customer identity changed while the request was in flight");if(!r.ok){let t=L.safeParse(a),m=t.success&&(!C.safeParse(t.data.error.code).success||k(t.data.error.code,r.status)),_=m?t.data.error.code:"HTTP_ERROR",P=T(_,r.status,{retryAfter:r.headers.get("Retry-After"),recovery:m?t.data.error.recovery:void 0,reason:m?t.data.error.reason:void 0});throw new e(_,m?t.data.error.message:"Indiana request failed",r.status,r.headers.get("X-Request-Id")??(t.success?t.data.requestId:void 0),{...P,...t.success&&t.data.error.retryable===!1?{retryable:!1}:{},...P.retryAfterSeconds===void 0&&t.success&&t.data.error.retryAfterSeconds!==void 0?{retryAfterSeconds:t.data.error.retryAfterSeconds}:{}})}if(r.headers.get(v)!==R.current)throw new e("PROTOCOL_MISMATCH","Response protocol does not match this SDK");if(d&&a&&typeof a=="object"&&"scope"in a){let t=S.safeParse(a.scope);if(!t.success||t.data.projectId!==d.projectId||t.data.environment!==d.environment)throw new e("SCOPE_MISMATCH","Response scope does not match this SDK instance")}let E=r.headers.get("X-Indiana-Web-View");if(E){if(!/^\/web-view\/renderer\/[a-f0-9]{64}$/.test(E))throw new e("INVALID_RESPONSE","Invalid Web View renderer metadata");b=E}let w=r.headers.get("X-Indiana-Telemetry-Subject");if(w){if(!/^[a-f0-9]{64}$/.test(w))throw new e("INVALID_RESPONSE","Invalid telemetry identity");p!==w&&(p=w,A?.(p))}return a};try{return await Promise.race([G(),x])}catch(r){throw g!==u?new e("IDENTITY_CHANGED","Customer identity changed while the request was in flight"):r instanceof e?r:new e(o.signal.aborted?"TIMEOUT":"NETWORK_ERROR",o.signal.aborted?"Indiana request timed out":"Unable to read the Indiana response")}finally{clearTimeout(K),o.signal.removeEventListener("abort",I),h.delete(o)}}return{subjectKey:()=>p,screenUrl(s){if(!V.safeParse(s).success)throw new e("INVALID_RESPONSE","Invalid published screen render address");return new URL(s,n).href},webViewUrl(){if(f!=="embedded"){if(!b)throw new e("INVALID_RESPONSE","The gateway did not provide a hosted Web View renderer");return new URL(b,n).href}},identify(s){if(!s.trim()||/\s/.test(s)||s.length>4096)throw new e("INVALID_TOKEN","A nonempty server-issued token is required");O(),c=s},reset:O,request:M}}export{e as a,J as b};
|