# Licensed advanced features

Advanced capabilities ship inside the same `wts-data-table` package. They use
feature-named subpaths; there is no separate Pro package and no `/premium`
import namespace.

## Connect a renewable subscription

Use the same deployment-key verification service as WTS Calendar. Data Table
uses the service's `SUBSCRIPTION` policy: premium access ends when the paid
period ends. Calendar's perpetual-version policy is not accepted here.
Premium access is subscription-based, not tied to a package release. The service
must authorize an active subscription independently of release registration or
maintenance/version ranges. The SDK sends its installed version for diagnostics,
but does not use response version metadata as an entitlement gate. An explicit
server denial is never bypassed.

```ts
import { connectDataTableLicense } from 'wts-data-table';
import { createDataTableCardView } from 'wts-data-table/card-view';

const license = await connectDataTableLicense({
  licenseKey: deploymentKey, // public deployment key, never an admin secret
  onStatusChange(status) {
    // Show renewal/reconnection UI when status.tier becomes 'standard'.
    console.log(status.state, status.subscriptionEndsAt);
  },
});

let cards = createDataTableCardView({ license, table, mode: 'cards' });

// After your server confirms payment/renewal:
await license.refresh();
// Expired controllers were disposed; recreate them after successful renewal.
cards.destroy();
cards = createDataTableCardView({ license, table, mode: 'cards' });

// On application teardown (not after constructing a feature):
cards.destroy();
license.destroy();
```

Pass the same `license` session to any premium factory. Monthly/yearly billing
and renewal dates belong to your licensing backend, not the browser package.
A valid Premium subscription enables all eleven package-defined capabilities
below. The package owns the feature catalog; the backend's optional `features`
metadata does not grant or restrict individual capabilities. Package-wide access
still requires explicit backend authorization and a current subscription/lease.
The package remains one bundle with the same feature-named imports. Standard features remain MIT; premium code uses the
[commercial subscription notice](LICENSE-COMMERCIAL.md) and requires a separate
written subscription agreement.

In browsers the origin is derived from the consuming document. SSR and workers
must supply `domain: 'https://your-application.example'` when connecting. Keep
sessions scoped to that deployment/tenant and destroy them on teardown. The
optional factory `origin`, if supplied, must match the verified session. Card
view additionally checks the real host document, so a copied official-demo key
cannot authorize a different site.

### Renewal, outages, and running features

- The service returns `subscriptionEndsAt`, `leaseExpiresAt`, `verifiedAt`,
  and `refreshAfter`. End times are exclusive; there is no extra subscription
  grace period.
- Verification refreshes automatically (default 60 seconds, or sooner when the
  service requires it). A lease is at most five minutes and can never extend
  beyond the subscription end.
- A network error retains access only for the remaining valid lease. Once that
  lease expires, premium features stop even if the service is unreachable.
- Revocation/denial stops access immediately. No local storage cache, long-lived
  offline subscription token, or client-side renewal is used for new sessions.
- Running premium controllers are disposed on loss of access. Card view restores
  the standard table. Standard functionality and your application data remain
  available. Save editable state in your application before a subscription ends;
  disposing a controller is not an automatic save operation.
- After renewal, call `await license.refresh()` and recreate disposed premium
  controllers. A successful refresh before expiry preserves running controllers.
- `license.status`, `license.has(feature)`, and `license.subscribe(listener)`
  expose status; `subscribe` returns an unsubscribe function. `destroy()`
  aborts pending verification, removes listeners/timers, and revokes that session.

The backend must implement the
[subscription verification contract](docs/advanced/SUBSCRIPTION_LICENSING.md)
and issue a real Data Table deployment key before this flow can be deployed.
The local SDK tests use mock service responses; they do not certify production
billing, backend deployment, or key issuance.

## Expiry warning and draft recovery

Use `license.status.renewalDue` to show a renewal warning (default 24 hours,
configurable with `renewalWarningMs`). Status also exposes
`remainingSubscriptionMs` and `remainingLeaseMs`. None extends authorization.
Notifications arrive on verification and access-state changes; read status for
a live countdown.

Keep drafts in application-owned state throughout editing. A final cleanup hook:

```ts
const stopRecovery = license.subscribeBeforeAccessLoss(({ lostFeatures }) => {
  if (!lostFeatures.includes('spreadsheet-formulas')) return;
  // Maintain knownCellAddresses in the application as users edit.
  const draft = workbook.getCells(knownCellAddresses);
  // Copy synchronously. Handle persistence failure in your own UI.
  void saveDraft(draft).catch(showSaveError);
});
// Later: stopRecovery();
```

Recovery runs before normal status observers and controller disposal. Only existing
read-only getters (getSnapshot, getCell, getCells, getLayout, getDraft, getSelection,
getStatus) are permitted during that synchronous callback. Mutations, new
controllers, computation, export jobs and subscription extensions remain blocked.
Async persistence never delays cleanup. This is not automatic durable saving and
cannot recover uncommitted in-flight edits; applications should persist continuously.
After renewal recreate controllers from saved application state.

## Deployment keys only

The signed-key verifier, grant types, bundled demo tokens and signing scripts
have been removed. There is no compatibility switch. Obtain deployment keys
from the licensing backend, not a local signing script. The official portal needs
a key registered for exactly `https://wts-data-table.github.io`; local preview
needs an explicitly registered local origin. Never ship an admin credential.

## Feature entry points

| Capability | Entitlement | Primary imports |
| --- | --- | --- |
| Card view | `card-view` | `wts-data-table/card-view` |
| Advanced row model | `advanced-row-model` | `wts-data-table/remote`, `wts-data-table/remote-viewport` |
| Indexed search | `indexed-search` | `wts-data-table/search`, `wts-data-table/search-filters` |
| Background export | `background-export` | `wts-data-table/export-jobs`, `wts-data-table/durable-export` |
| Worker processing | `worker-processing` | `wts-data-table/worker-engine`, `wts-data-table/worker-table` |
| Live data | `live-data` | `wts-data-table/live-data`, `wts-data-table/live-transports` |
| Server analytics | `server-analytics` | `wts-data-table/pivot-controller`, `wts-data-table/pivot-builder` |
| Spreadsheet formulas | `spreadsheet-formulas` | `wts-data-table/formula-engine`, `wts-data-table/formula-editor` |
| Collaborative editing | `collaborative-editing` | `wts-data-table/collaboration-client`, `wts-data-table/collaboration-table` |
| Governed editing | `governed-editing` | `wts-data-table/governance-client`, `wts-data-table/governance-panel` |
| Report designer | `report-designer` | `wts-data-table/report-controller`, `wts-data-table/report-designer` |

Supporting contracts, HTTP adapters, PostgreSQL stores, and worker runtimes use
the same feature-named package subpaths. See the detailed guides in
[`docs/advanced`](docs/advanced/ROADMAP.md).

## Security and licensing boundary

The entitlement check controls access to advanced APIs in an unmodified package.
It is not user authentication, server authorization, or tamper-proof DRM. Verify
identity, tenant access, query scope, and mutations on the server. See [LICENSE](LICENSE)
for the code boundary. Already-published MIT versions retain their original terms.
