@funnelsgrove/runtime

中文文档
0.46.0发布于 2026/11/12TypeScriptES Module近 30 天下载 9856

Shared funnel runtime contracts and helpers.

原始使用文档
文档目录12 节
  1. Owns funnel mechanics
  2. Use This Package For
  3. Do Not Use This Package For
  4. Public Surfaces
  5. Browser SDK structure
  6. Session API structure
  7. Storage Conventions
  8. Engineering Rules
  9. Build, Test, Publish
  10. Provider money
  11. Browser offer locales
  12. Visitor offer countries

@funnelsgrove/runtime

Shared funnel runtime contracts and helpers.

Read this file before editing shared funnel mechanics. Deeper runtime behavior is documented in docs/product-specs/funnel-template-runtime.md.

Owns funnel mechanics

@funnelsgrove/runtime owns the reusable mechanics that every generated or published funnel depends on: manifests, routing, env resolution, funnel state, preview/runtime detection, and generic runtime UI. Funnels bring their own copy, visual design, billing catalog, and step JSX.

Use This Package For

  • manifest types and validation
  • route resolution and entry-point handling
  • runtime mode and public env/config resolution
  • experiment assignment helpers
  • preview-bridge parsing and preview/runtime detection
  • published theme contract and CSS variable helpers
  • funnel context, flow controller, and generic runtime UI primitives
  • funnel-scoped state/storage helpers
  • browser-safe API client helpers used by funnels
  • reactive browser query-string access through useBrowserLocationSearch
  • subscription handoff and subscription management screens whose copy stays funnel-local
  • test-mode developer info surfaces for funnel preview tooling

Do Not Use This Package For

  • funnel-specific step JSX
  • brand/theme assets
  • billing catalog data
  • analytics transport
  • Stripe checkout UI
  • funnel-specific developer widget copy
  • direct provider SDK calls

Public Surfaces

  • config/*: manifest, theme, font, env, and builder-preview contracts.
  • runtime/*: flow, routing, attribution, feature flags, preview bridge, URL attributes, and manifest validation.
  • runtime/published-runtime-resolution: running-experiment normalization and immutable offer-set selection from pricing assignments. Its paymentProvidersByMode result exposes the selected offer’s explicit test/live providers; missing configuration is null, without checkout’s legacy Stripe fallback.
  • services/*: API client, runtime mode, public env, project env, logger, and funnel state helpers.
  • components/*: generic runtime context, subscription handoff/management, editor panel, dev info, and base controls.
  • content/* and steps/types: shared step content and taxonomy contracts.

Browser SDK structure

funnelSdkService remains the public entry point, with the same eighteen methods and exported input/response types. It is a plain object of async functions; methods can also be destructured without losing a this binding.

Implementation lives in services/funnel-sdk/, grouped by users, uploads, checkout, and subscriptions. Each use case owns its endpoint and sequencing. Keep request mappers beside their use cases (for example, checkout/requests.ts), not in a generic mapping layer. Only runtime identity, headers, JSON transport, and API error handling belong in shared/.

SDK HTTP requests serve the funnel. Server-to-server integration clients and direct payment-provider calls do not belong here. Do not create workflow classes or files for these short request sequences. Photo uploads prepare an upload through the API, then send the original blob directly to its signed destination, without SDK headers.

From 0.12.0, payment and subscription methods always use Payments V2, including hosted checkout. An inherited paymentsApiVersion: 'v1' no longer selects V1. Pass published offer/profile/provider/plan selection; subscription mutations require the listed subscriptionRef. createOneTimePaymentIntent is removed; use createOneTimeCheckout with the Checkout Session UI instead of passing its secret to a PaymentIntent form. Server V1 routes are removed. In 0.13.0 the public configuration discriminator is V2-only and inherited runtime snapshots normalize to V2. Upgrade old published bundles before deploying server retirement. Keyed checkout creation may replay one transport failure with the same attempt; payment errors never fall back to V1. funnel-sdk.contract.test.ts captures the wire contract, while funnel-sdk.http.test.ts exercises real loopback HTTP and signed uploads.

FunnelSdkHttpError is exported alongside the facade so consumers can narrow errors without importing transport internals. Its fields and replay semantics are defined in the public SDK reference.

Session API structure

apiService keeps its thirteen public methods and four public type exports. It is also a plain object of functions, implemented in services/session/:

  • bootstrap/: verify candidate identity, reuse a request-scoped idempotency key, bootstrap once, clear only the completed record, and map the resulting user.
  • users/ and emailCapture/: profile updates and email capture, including an optional versioned lifecycle-consent payload that the SDK API records before the capture event becomes eligible for side effects, with named request/response mappers and email-response validation beside the functions.
  • uploads/: delegate the original file to the SDK signed upload, then validate its result; local object URLs are only the no-key fallback.
  • subscriptions/: resolve identity from the management URL, validate it, and call the SDK. Never substitute the stored session identity for a missing link.
  • identity.ts and bootstrap/idempotency.ts: own session storage mechanics.
  • ping/transport.ts: owns the same-origin, best-effort ping and its error handling.

These are use-case folders, not another workflow or data layer. Keep request and response mappers pure: pass runtime mode/revision explicitly instead of reading browser configuration inside a mapping function. SDK requests still go through funnelSdkService; only the same-origin ping owns a separate HTTP boundary. Validate email/canonical identity before persistence. Preserve failed bootstrap keys for explicit retry and never add an automatic retry to an uncertain write.

The pre-extraction session tests remain unchanged behavior baselines. Session boundary tests protect the facade and infrastructure ownership; real loopback tests exercise bootstrap/profile/email, URL-only subscription management, explicit bootstrap retry, and binary uploads through both API facades.

Storage Conventions

  • runtime user ids stay funnel-scoped under funnel:<funnelId>:user-id
  • runtime-generated user ids use the u_ prefix
  • paywall state is stored through runtime helpers under fg_state:<funnelId>
  • developer reset controls should clear paywall state through clearPaywallStateValue, including funnel-provided compatibility keys when a live funnel still needs them

Engineering Rules

  • Do not import @funnelsgrove/payments or @funnelsgrove/analytics here for checkout or transport orchestration.
  • Runtime UI must be generic and copy-injectable.
  • Browser-only values must resolve after mount when SSR hydration can be affected.
  • Subscription handoff app and universal links receive the known funnel-user email even when the configured template omits {email}. Store links never receive email, including case-insensitive email keys present in configured URLs or first-touch attribution.
  • Funnel code must not copy useSyncExternalStore/popstate query-string hooks. Use useBrowserLocationSearch; the shared controller also notifies it after history.pushState and history.replaceState navigation.
  • Keep env mapping centralized in config/env.config.ts.
  • V2 checkout selection requires the offer set, payment profile, provider, provider plan and plan key. runtimeConfigRevisionId is optional and must not gate the request; a deployment does not invalidate an otherwise unchanged offer. Continue forwarding a supplied revision for older API versions. Deploy the compatible API before rolling out SDK callers that omit it.

Build, Test, Publish

npm run test:run --workspace @funnelsgrove/runtime
npm run build --workspace @funnelsgrove/runtime
npm publish --workspace @funnelsgrove/runtime --access public

The build normalizes generated relative ESM imports to explicit .js files for published package consumers.

Provider money

ProviderMoney carries an integer amountMinor, normalized currency, and an explicit minorUnitExponent. moneyToMajor and formatProviderMoney consume this contract without inferring scale from locale. Provider adapters own currency-specific rules. Runtime snapshots declaring moneyContractVersion: 1 require valid money on every mapped provider plan. Legacy snapshots retain explicit labels; absent money is not an instruction to assume USD.

Browser offer locales

Language-based offer selection uses the browser language, independently of the funnel's content language. useBrowserOfferLocale remains pending through hydration and then matches navigator.language exactly to one of OFFER_SET_LOCALES, the Locale Catalog codes (pt-br → pt-BR; ru-RU does not become ru). Other languages resolve to the funnel default.

Published schema 2 snapshots can declare localeContractVersion: 1. Every offer set then carries locales: null | string[]; null is All locales. An assigned pricing experiment takes precedence over an explicit locale match, followed by the assigned active All-locales default. V1 does not fall back to an arbitrary first set. Unknown versions, missing locale fields and invalid defaults fail validation. Unversioned snapshots retain the legacy adapter.

Supported source artifacts include funnel.runtime-capabilities.json with the supported money, locale and country contract versions.

Visitor offer countries

A visitor country selects an Offer Set before the browser language. useVisitorOfferCountry(enabled) stays pending through hydration; when enabled (use offerSetsTargetCountries(config.offerSets)) it reads the host's <meta name="fg-visitor-country"> from private documents, or else requests the uncached /api/visitor-country once per page and resolves to an OFFER_SET_COUNTRIES code, or to null after a failure, an unassigned code or a 2-second timeout. Without country-targeted offer sets it resolves to null without a request. Pass country to the offer selection together with locale; in test payment mode, ?country=XX overrides it for QA.

Snapshots declaring countryContractVersion: 1 carry countries: null | string[] on every offer set (null is All countries), and their defaults must be All countries. Selection order is assigned pricing experiment, explicit country, explicit locale, then the default. Publication records that declaration in immutable version metadata. Localized runtime updates and retries require that version receipt; changing offer-set settings alone does not deploy the funnel.

版本与发布记录

@funnelsgrove/runtime 共发布 151 个版本,首次发布于 2026/04/04;过去 12 个月发布了 151 个版本。

版本发布日期距今
0.46.0latest2026/11/123 天前
0.45.02026/11/105 天前
0.44.02026/11/0412 天前
0.43.02026/10/3016 天前
0.42.02026/10/2819 天前
0.41.02026/10/2521 天前

关于 @funnelsgrove/runtime 的常见问题

@funnelsgrove/runtime 是什么?

Shared funnel runtime contracts and helpers.

如何安装 @funnelsgrove/runtime?

在项目目录运行 npm install @funnelsgrove/runtime,或使用 pnpm add / yarn add / bun add。

@funnelsgrove/runtime 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@funnelsgrove/runtime 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@funnelsgrove/runtime 可以商用吗?

@funnelsgrove/runtime 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@funnelsgrove/runtime 的下载量有多少?

根据 npm 官方下载统计,@funnelsgrove/runtime 在 2026/10/16 – 2026/11/14 这 30 天内被下载 9,856 次,日均约 329 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@funnelsgrove/runtime 还在维护吗?

最新版本 0.46.0 发布于 2026/11/12(3 天前);至今共发布 151 个版本,其中过去 12 个月发布了 151 个;首次发布于 2026/04/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。