# Version 2.1.0

> TypeScript declarations for both entries - full UI build and headless - published alongside the JS bundles

Source: https://zest.freshjuice.dev/changelog/v2.1.0/
Date: 2026-04-26

`@freshjuice/zest@2.1.0` ships hand-written `.d.ts` declarations for both entries. No more `declare module '@freshjuice/zest/headless'` stubs in consumer projects, no `@types/freshjuice__zest` shim, no `// @ts-ignore`. Drop in, autocomplete works. See the [full release on GitHub](https://github.com/freshjuice-dev/zest/releases/tag/v2.1.0).

> **Zero runtime change.** Every JS bundle Rollup produces in v2.1.0 is byte-identical to v2.0.0. The only diff is the new `.d.ts` companions in `dist/`.

## Highlights

### Types for the full UI build

`dist/zest.d.ts` covers everything the full build exposes:

```typescript
import Zest, {
  ConsentState,
  ConsentCategory,
  InitOptions,
  ZestEvents
} from '@freshjuice/zest';

const config: InitOptions = {
  position: 'bottom-right',
  theme: 'auto',
  accentColor: '#0071e3',
  policyUrl: '/privacy',
  respectDNT: true,
  callbacks: {
    onAccept: (consent: ConsentState) => {
      if (consent.analytics) initAnalytics();
    }
  }
};

Zest.init(config);

Zest.on(Zest.EVENTS.CHANGE, (e) => {
  // e.detail is fully typed as { consent, previous? }
});
```

The `window.ZestConfig` global is also typed — set it before loading the script tag and TypeScript will know what it accepts.

### Types for the headless build

`dist/zest.headless.d.ts` covers the consent engine without any UI surface:

```typescript
import Zest, { ConsentState } from '@freshjuice/zest/headless';

Zest.init({ respectDNT: true, expiration: 365 });

if (!Zest.hasConsentDecision()) {
  myCustomBanner.show();
}

acceptBtn.addEventListener('click', () => {
  Zest.acceptAll();
});

Zest.on(Zest.EVENTS.CHANGE, (e) => {
  // ConsentState fully inferred
});
```

Named exports (`init`, `acceptAll`, `rejectAll`, `getConsent`, `EVENTS`, …) are all exported for tree-shake-friendly consumers.

### `package.json` `exports` map

The `exports` map now declares `types` for every entry point so modern resolvers find them automatically:

```json
{
  "exports": {
    ".": {
      "types": "./dist/zest.d.ts",
      "import": "./dist/zest.esm.min.js",
      "default": "./dist/zest.min.js"
    },
    "./headless": {
      "types": "./dist/zest.headless.d.ts",
      "import": "./dist/zest.headless.esm.min.js",
      "default": "./dist/zest.headless.esm.min.js"
    }
  }
}
```

A top-level `"types": "dist/zest.d.ts"` is also set so legacy resolvers (older TypeScript, certain Webpack setups) still find the declarations.

## Migration

If your project had a hand-rolled stub:

```diff
- // env.d.ts or types.d.ts
- declare module '@freshjuice/zest/headless' {
-   const Zest: { /* …handwritten partial surface… */ };
-   export default Zest;
- }
```

Delete it. Bump the dependency:

```bash
npm install @freshjuice/zest@^2.1.0
```

That's it. TypeScript / VS Code / Astro / IDE autocomplete all resolve out of the box.

## Install

```bash
npm install @freshjuice/zest
```

```javascript
// Full build (banner + modal + widget, auto-init)
import Zest from '@freshjuice/zest';

// Headless (BYO UI, manual init)
import Zest from '@freshjuice/zest/headless';
```

Or via CDN:

```html
<script src="https://unpkg.com/@freshjuice/zest@2"></script>
```

