# @tour-kit/license

## 1.3.6

### Patch Changes

- Updated dependencies [3138481]
  - @tour-kit/core@1.0.7

## 1.3.5

### Patch Changes

- d870c32: Ship the `'use client'` directive in published dists. tsup's `banner` option is
  stripped by the rollup treeshake pass (and by `minify: true`), so every package
  relying on it published client entries without the directive — importing them from a
  Next.js App-Router Server Component evaluated React-stateful code in the react-server
  layer and crashed `next build` with `createContext is not a function`. All client
  entries now get the directive injected post-build (shared
  `tooling/build/use-client.ts`); server-safe entries (`license/headless`,
  `ai/server`, tailwind plugin entries) intentionally stay directive-free.

  Also fixes `@tour-kit/media/tailwind` shipping without type declarations: the
  package's second tsup config raced the first one's DTS step, which deleted
  `dist/tailwind/index.d.ts` after it was emitted. Media now builds from a single
  config.

- Updated dependencies [d870c32]
  - @tour-kit/core@1.0.6

## 1.3.4

### Patch Changes

- 2b9e527: Stop the "Unlicensed" watermark from appearing on legitimate, paid deployments.

  Two fixes to how domain activation is handled, both aimed at the common
  Vercel/Netlify workflow where preview URLs pile up:

  - **Activation-limit reached no longer watermarks a valid key.** When Polar
    validates the key as `granted` but the auto-activation call returns `403`
    (activation limit reached), the license is now treated as a valid Pro license
    on that domain instead of falling through to the unlicensed watermark. The key
    is genuinely paid — the customer just has more live domains than slots — so we
    keep Pro unlocked, emit a one-time console warning pointing at the Polar
    dashboard, and cache the result. Previously this mapped to `status: 'invalid'`
    and rendered the watermark on the customer's production site.

  - **Ephemeral / preview hosts skip activation entirely.** Vercel preview URLs
    (`*-git-*.vercel.app`, `*-<hash>-*.vercel.app`), Netlify branch/deploy-preview
    hosts (`*--*.netlify.app`), Cloudflare Pages previews (`<hash>.*.pages.dev`),
    dev tunnels (ngrok, `loca.lt`, `trycloudflare.com`), and raw IP hosts now
    resolve to a `preview_bypass` state that unlocks Pro without calling Polar, so
    a busy preview workflow never burns the key's finite activation slots. Stable
    production hosts — including a bare `project.vercel.app` alias — still validate
    and activate normally. New `isEphemeralHost()` helper exported from the package
    root and `@tour-kit/license/headless`.

## 1.3.3

### Patch Changes

- 8a443fb: Dedupe noisy dev-only warnings to once per page/session.

  The unlicensed `[TourKit] … without a valid license` warning previously logged
  once per mounted Pro package (≈9–10× on a page using several). `<LicenseWarning>`
  now prints at most once per session. Likewise, `<TourProvider>`'s dev
  `diagnose` tip now fires once per session instead of once per provider instance
  (it printed twice on pages with multiple tours).

- d5e0ef1: Reword the unlicensed watermark badge CTA from "Buy license" to "Remove for $99". The new copy names the benefit (remove the badge) and the one-time price, and the `aria-label` now reads "remove this badge with a one-time $99 license" — higher-intent CTA framing for the production watermark, which is the primary in-app conversion surface for Tour Kit Pro. Behavior, link target, and the `unlicensed_badge_clicked` event are unchanged.
- Updated dependencies [8a443fb]
- Updated dependencies [8a443fb]
- Updated dependencies [8a443fb]
  - @tour-kit/core@1.0.3

## 1.3.2

### Patch Changes

- Updated dependencies [ef31ce6]
  - @tour-kit/core@1.0.2

## 1.3.1

### Patch Changes

- Updated dependencies [a17322c]
  - @tour-kit/core@1.0.1

## 1.3.0

### Minor Changes

- Add `apiBase` override for the Polar → tourkit-dash issuer migration (`tour-kit-cloud` plan/15f).

  - **New `apiBase?: string` prop on `<LicenseProvider>`** — points the validate/activate/deactivate flow at a non-Polar issuer without bumping the SDK major.
  - **New `options.apiBase` on `validateLicenseKey`, `validateKey`, `activateKey`, `deactivateKey`** — additive 4th positional arg on the low-level functions; existing positional callers are unaffected.
  - **New `resolveApiBase(override?)` export** (from `@tour-kit/license` and `@tour-kit/license/headless`) implementing the precedence chain: explicit override > `NEXT_PUBLIC_TOUR_KIT_LICENSE_API_BASE` env > `TOUR_KIT_LICENSE_API_BASE` env > Polar default.
  - **New `DEFAULT_API_BASE` export** holds the Polar URL string. v2.0.0 will flip this constant at T+90 per plan/15m.
  - **`PolarValidateResponseSchema` and `PolarActivateResponseSchema` switched to `z.looseObject`** (Zod 4's non-deprecated `.passthrough()` replacement) so the tourkit-dash issuer can add additive `tk_*` fields like `tk_tier` without breaking v1.x parsers. The `schema-no-tier.regression.test.ts` pin still holds: **Polar itself** does not emit `tier`; the looseObject change permits but does not require additive fields.
  - **New fixture** `src/__tests__/fixtures/polar-validate-response.json` — the canonical SDK-side counterpart to `tour-kit-cloud`'s byte-equality test (plan/15c §"Polar passthrough byte-equality").

  Zero behavior change for callers who don't opt in. Default issuer is still Polar; existing tests pass unchanged.

## 1.2.0

### Minor Changes

- b01b53c: Phase 8 — Trial tier + dev clarity for `@tour-kit/license`.

  - Add `<TrialBadge>` — client-derived trial countdown that flips to an Upgrade CTA when `daysLeft <= 3`. Reads from `useLicense().trial` when no `daysLeft` prop is passed.
  - Add `<LicenseDebugPanel>` — dev-only license inspection panel. Renders the literal copy `🟢 Dev bypass active (NEXT_PUBLIC_TOUR_KIT_LICENSE_KEY set, hostname=localhost)` so the dev-bypass state is unambiguous. Returns `null` in production by default.
  - Add `<LicenseTestMode tier="invalid" | "pro" | "free">` — QA-only context override so the watermark, adoption gate, and Pro fallbacks can be verified on a real production-like domain without unsetting env vars. Emits a loud `console.warn` in production and is enforced by a static guard script (`scripts/check-license-test-mode.mjs`) that fails the package test pipeline on application-source imports.
  - Add pure helper `getDaysLeft({ issuedAt, trialDays, validatedAt, serverValidatedAt }, now?)` in `@tour-kit/license/headless`. Anchors to Polar's `last_validated_at` plus local elapsed time to absorb client clock skew.
  - Extend `LicenseProviderProps` with optional `trialDays` and `trialIssuedAt`. Extend `LicenseState` with `serverValidatedAt?: number | null` (parsed from Polar `last_validated_at`). Extend `LicenseContextValue` with `trial: TrialContextValue | null`.
  - Update `polar-client.ts` to map `response.lastValidatedAt` into `state.serverValidatedAt` on validated, expired, and revoked branches. `LicenseCacheSchema` now accepts the optional field; old v1.0.x cache entries continue to parse.
  - The Polar Zod schema does NOT gain a `tier` field — the API doesn't emit one (memory project_polar_api_findings.md #187 / Phase 0 §6). Pinned with `schema-no-tier.regression.test.ts`.
  - New docs page `apps/docs/content/docs/licensing/trial.mdx` covers the trial surface, debug panel, test mode, and the future schema-migration plan when Polar ships server-side trial signalling.

### Patch Changes

- Updated dependencies [d67d905]
  - @tour-kit/core@1.0.0

## 1.1.2

### Patch Changes

- c33b3bc: Fix Pro-package SSR blackout in `<LicenseGate>` loading state.

  `LicenseProvider` validates the license inside a `useEffect`, which never fires during server rendering. That left `context.isLoading` `true` on every SSR pass, and `<LicenseGate>` (used internally by all 8 Pro packages since 1.1.0) returned `null` whenever no explicit `loading` prop was passed — wiping the entire Pro subtree from server HTML and forcing a pop-in on hydration. The release smoke app caught this as a missing `data-smoke-ok` marker on the curl probe.

  The loading branch now defaults to `children` instead of `null`. Consumers who want a skeleton during validation can still pass `loading={<Skeleton />}`; the watermark only renders once the gate decision is known.

## 1.1.1

### Patch Changes

- d777614: Phase 8 dashboard-next QA pass: analytics event coverage, a11y fixes, autostart correctness, and watermark visual polish.

  **Analytics event coverage.** New `TourEventName` values — `announcement_shown`, `announcement_dismissed`, `announcement_completed`, `checklist_task_completed`, `checklist_completed`, and `schedule_evaluated` — are now emitted by their respective providers when an analytics plugin is registered. `consolePlugin` will surface them as `[tour-kit]` groups; production destinations (`@tour-kit/analytics`) receive them via the same `track()` interface.

  **Tour autostart respects completed tours.** `<TourProvider>` no longer auto-restarts a tour that the user has already completed (or skipped) across route navigations. State is sourced from `usePersistence` when `persistence.trackCompleted` is enabled, and `ADD_COMPLETED` / `ADD_SKIPPED` reducers now dedupe to prevent the list from growing on repeat dispatches.

  **Announcement dialog a11y.** `AnnouncementModal` now forwards `aria-describedby` when a description exists and renders content with `asDialogContent` so Radix's title/description requirements are satisfied — eliminates the `DialogTitle is required` and `DialogDescription` console warnings.

  **Schedule diagnostics.** `useSchedule` exposes the evaluation `reason` (`outside_window`, `holiday`, `before_start_date`, `after_end_date`, etc.) on the hook return so consumers can render or log why a banner is hidden without inspecting the schedule shape themselves.

  **License watermark refresh.** The unlicensed badge now renders the User Tour Kit logo (14×14 SVG) in place of the amber dot — same singleton, same portal, same `pointer-events: none` wrapper, just a clearer visual signal.

  **Install graph: `@tour-kit/analytics` peer → direct dependency.** `@tour-kit/adoption`, `@tour-kit/announcements`, `@tour-kit/checklists`, `@tour-kit/hints`, `@tour-kit/react`, and `@tour-kit/scheduling` now declare `@tour-kit/analytics` as a regular dependency rather than an optional peer. Consumers no longer need to install `@tour-kit/analytics` manually for analytics events to be available — the package ships with each consumer that emits them. No runtime behaviour change for consumers who already installed it.

## 1.1.0

### Minor Changes

- 2f1a88d: License gate is now soft by default for Pro packages

  `<LicenseGate>` is rewritten as the canonical internal soft gate. It now reads `LicenseContext` directly (no longer throws when used outside `<LicenseProvider>`), always renders `children`, and on non-localhost hosts without a valid license layers a single small `Tour Kit · Unlicensed · Buy license` portal badge plus a dev-only console warning over the top. `fallback` continues to hard-replace children, but only when a provider is mounted and the state is gated.

  `<LicenseWatermark>` is replaced. It is no longer a full-screen rotated `UNLICENSED` overlay — it is now a small fixed bottom-right badge rendered into `document.body` via a portal, with `pointer-events: none` on the wrapper and `pointer-events: auto` on the link so it never blocks app clicks. Multiple mounted instances coalesce into a single visible badge via singleton ownership transfer (StrictMode-safe). Badge clicks open pricing with UTM params and emit `unlicensed_badge_clicked` via `window.gtag` or `window.dataLayer`.

  All 8 Pro packages (`@tour-kit/adoption`, `@tour-kit/announcements`, `@tour-kit/checklists`, `@tour-kit/ai`, `@tour-kit/surveys`, `@tour-kit/scheduling`, `@tour-kit/analytics`, `@tour-kit/media`) now wrap their provider/components with `<LicenseGate require="pro">` instead of `<ProGate package="...">`. The practical effect: a developer can install a Pro package, push a preview deploy, and demo the real UI to teammates before purchasing — no more hard-placeholder dead end on preview, staging, or production.

  `<ProGate>` is **not** removed. It remains exported from `@tour-kit/license` for downstream consumers who want a hard-placeholder gate, but Tour Kit's own Pro packages no longer use it internally.

  Commercial URLs aligned to `usertourkit.com` across `LicenseWarning`, `ProGate`, every Pro package `LICENSE.md`, the docs API reference, the pricing FAQ, and the license package README/CLAUDE.md.

### Patch Changes

- 6e77a3b: Point each package's `homepage` field at https://usertourkit.com/ so the "Homepage" link in the npm sidebar opens the docs site instead of the GitHub README.
- 6e77a3b: Fix localhost licensing so an empty `licenseKey` is treated as unlicensed.

  Local development still skips Polar validation and activation usage when a
  non-empty key is configured. When the key is missing or blank, Tour Kit now
  shows the same unlicensed watermark on localhost that it shows in production —
  surfacing a missing env var before it reaches a deploy.

  - `<LicenseProvider licenseKey="">` on localhost now resolves to `invalid`/`free`
    and `useLicenseGate()` / `<LicenseGate>` / `<ProGate>` gate accordingly.
  - `validateLicenseKey('')` returns the unlicensed state before any cache read
    or Polar call, on every host.
  - Whitespace-only keys are treated as missing (trimmed before presence checks,
    cache hashing, validation, activation, and render-key generation).
  - `useLicenseGate()` now reads `<LicenseProvider>` state before the hostname
    bypass, so a provider with an empty key no longer leaks Pro behavior locally.
  - `<LicenseGate>` outside a `LicenseProvider` keeps localhost quiet — there is
    no provider-owned key to inspect.

## 1.0.3

### Patch Changes

- a35d469: NPM SEO + README accuracy pass. Pure metadata and documentation — no public API changes.

  **`package.json` (11 packages, license unchanged)** — descriptions trimmed to ≤150 chars (front-loading the primary keyword phrase before npm search-card truncation) and keyword arrays reordered with high-intent long-tail terms first (`react-onboarding`, `nextjs-onboarding`, `onboarding-wizard`, `onboarding-flow`, `react-product-tour`, `product-demo`, `feature-hint`, `in-app-survey`, etc.). Generic single-word keywords (`react`, `tour`) deprioritized; `*-alternative` keywords retained or expanded.

  **READMEs (all 12 packages)** — rewritten on a unified template:

  - H1 + keyword-phrase tagline + badge row (npm version, downloads, bundle, types, license)
  - "Alternative to" line owning competitor-name SEO surface (`react-joyride-alternative`, `intro-js-alternative`, `shepherd-alternative`, etc.)
  - Quick Start that compiles against the actual exports
  - Comparison table vs major alternatives
  - Complete API reference verified against `src/index.ts` for every package — no fictional or missing exports
  - Cross-links to sibling `@tour-kit/*` npm pages
  - Docs link migrated from the broken `tour-kit.dev` / `tourkit.dev` to the live `usertourkit.com`
  - Correct license disclosure (MIT for free packages / Pro tier for proprietary)

  **Accuracy bugs fixed in the rewrite** (none of these compiled before):

  - `core` — Quick Start used `createTour({ id, steps })` and `createStep({ id, target, content: { title, description } })`, neither of which match the real signatures (`createTour(steps, options?)`, `createStep(target, content, options?)`). Rewritten using `createNamedTour` / `createNamedStep` for explicit IDs. Hook list was missing 4 public hooks (`useAdvanceOn`, `useBranch`, `useRoutePersistence`, `useUILibrary`) and 11 public utilities; all now documented.
  - `checklists` — referenced non-existent `<ChecklistItem>` (real export is `<ChecklistTask>`), `useChecklistItem` (real: `useTask`), `useChecklistProgress` (real: `useChecklistsProgress`), and claimed MIT licensing despite being a Pro package.
  - `analytics` — referenced non-existent `createAnalyticsPlugin`, `createSegmentPlugin`, and `useTrack`. Real plugin exports are `consolePlugin`, `posthogPlugin`, `mixpanelPlugin`, `amplitudePlugin`, `googleAnalyticsPlugin`. Real hooks are `useAnalytics` and `useAnalyticsOptional`. License also corrected from MIT to Pro.
  - `adoption`, `core`, `analytics`, `checklists`, `license` — broken docs URLs (`tour-kit.dev` / `tourkit.dev`) updated to `usertourkit.com`.
  - `media`, `surveys`, `scheduling` — these had no README at all; new ones added.

  This is the foundation for the npm-search SEO push: with corrected metadata and accurate, intent-rich READMEs, npm full-text indexing surfaces the packages for `react-onboarding`, `nextjs-onboarding`, `onboarding-wizard`, and competitor-alternative searches that were previously dead air.

## 1.0.2

### Patch Changes

- a7a0840: chore: publish Pro packages as public on npm

  Flip `publishConfig.access` from `restricted` to `public`. Pro-tier gating stays at runtime via `@tour-kit/license` + Polar.sh keys (watermark + console warning on unlicensed use), matching the documented "no hard block" licensing model. No code or API changes.

## 1.0.1

### Patch Changes

- 940847a: chore: update GitHub owner from `DomiDex` to `domidex01` in package metadata

  Updates `repository.url`, `homepage`, `bugs.url`, and LICENSE copyright to reflect the new GitHub account. No runtime or API changes — existing installs and imports are unaffected.

## 1.0.0

### Major Changes

- 3fce450: Replace JWT-based licensing with Polar.sh license key validation

  BREAKING CHANGES:

  - Removed `publicKey` prop from `<LicenseProvider>` (JWT verification removed)
  - Added required `organizationId` prop to `<LicenseProvider>`
  - License key format changed from JWT to Polar format (`TOURKIT-*` prefix)
  - Removed `jose` dependency

  New features:

  - Polar.sh license key validation and activation (up to 5 domains)
  - 24-hour localStorage cache with Zod integrity checks
  - Automatic dev-mode bypass (localhost, 127.0.0.1, \*.local)
  - `<LicenseWatermark>` component for soft enforcement
  - `<LicenseGate>` with interleaved validation
  - Render-time domain verification
