Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .changeset/cookie-adapter-serialize.md

This file was deleted.

19 changes: 0 additions & 19 deletions .changeset/gen-module-write-gate.md

This file was deleted.

12 changes: 0 additions & 12 deletions .changeset/react-gated-script.md

This file was deleted.

10 changes: 0 additions & 10 deletions .changeset/ssr-server-snapshot.md

This file was deleted.

12 changes: 0 additions & 12 deletions .changeset/staged-consent-toggles.md

This file was deleted.

10 changes: 10 additions & 0 deletions examples/astro/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# astro-example

## 0.0.1

### Patch Changes

- Updated dependencies [996973e]
- Updated dependencies [e0fc26a]
- Updated dependencies [279688a]
- @policystack/react@1.2.0
2 changes: 1 addition & 1 deletion examples/astro/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "astro-example",
"version": "0.0.0",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
Expand Down
8 changes: 8 additions & 0 deletions packages/angular/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @policystack/angular

## 1.2.0

### Minor Changes

- 279688a: Consent preference toggles are now staged. `toggle()` writes to `state.draft` instead of live decisions, and nothing is gated, persisted, or script-loaded until `save()` promotes the draft in one step — scripts no longer load on checkbox tick before "Save", and returning visitors no longer get their stored record rewritten on every tick (#157). Leaving the preferences route without saving discards the draft.

API changes: `toggle(key)` no longer accepts `ActionOptions` (name the record source at `save()` instead), and `ConsentState` gains a required `draft` field. Per-category `granted` accessors in all framework bindings read `draft ?? decisions` so checkboxes respond instantly; custom panels rendering checkboxes from raw `decisions` should apply the same merge.

## 1.1.0

## 1.0.1
2 changes: 1 addition & 1 deletion packages/angular/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/angular",
"version": "1.1.0",
"version": "1.2.0",
"description": "Angular consent service and components for PolicyStack",
"license": "Apache-2.0",
"repository": {
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @policystack/cli

## 1.2.0

### Patch Changes

- Updated dependencies [035afc7]
- @policystack/vite@1.2.0

## 1.1.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/cli",
"version": "1.1.0",
"version": "1.2.0",
"description": "CLI to install PolicyStack and print a setup prompt for coding agents",
"license": "Apache-2.0",
"repository": {
Expand Down
40 changes: 40 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
# @policystack/core

## 1.2.0

### Minor Changes

- 4cc5985: `cookieAdapter()` now exposes the bare cookie value, so nothing has to re-implement its wire format (#167). `encode`/`decode` already existed as private closures; the adapter just never returned them, leaving `getSetCookieHeader()` (a whole `Set-Cookie` header) as the closest thing and forcing consumers to hand-roll base64url or string-parse the value back out.

Three new members on `CookieAdapter`:

- `serialize(record)` — the encoded cookie value on its own, exactly what `write()` puts in the cookie.
- `deserialize(value)` — the inverse, for a bare value. `parse()` still handles a full cookie header.
- `name` — the resolved cookie name, so callers using the default do not hardcode `oc_consent`.

The motivating case is seeding consent in browser tests, where `browserContext.addCookies()` needs a name and a value:

```ts
const adapter = cookieAdapter();
const store = createConsentStore(policystack);
store.acceptAll();

await context.addCookies([
{
name: adapter.name,
value: adapter.serialize(store.getConsentRecord()),
url: baseURL,
},
]);
```

A copied encoder is worth replacing here even though it matches today: `deserialize` swallows errors and returns `null`, so a value that drifts from the adapter's format does not throw — consent silently reads as undecided and the banner reappears.

- e0fc26a: Consent hooks no longer cause hydration mismatches under SSR. The React hooks passed live store state as `useSyncExternalStore`'s `getServerSnapshot`, so any returning visitor mismatched: the server has no stored record and resolves the _host's_ timezone, while the client has both (#158). Every SSR consumer had to hand-roll a `mounted` flag around consent-driven UI.

`ConsentStore` gains a `server` member (`getState()` / `has()`) returning a deterministic pre-consent snapshot: undecided, no jurisdiction, conservative opt-in posture, derived from static config alone and never from the adapter or resolver. `useConsent`, `useCategory`, and `ConsentGate` pass it as `getServerSnapshot`, and React re-reads live state once hydration commits.

The Vue, Svelte, Solid, and Angular bindings still seed from live state and are unchanged here; `store.server` is the shared primitive their fix will use.

- 279688a: Consent preference toggles are now staged. `toggle()` writes to `state.draft` instead of live decisions, and nothing is gated, persisted, or script-loaded until `save()` promotes the draft in one step — scripts no longer load on checkbox tick before "Save", and returning visitors no longer get their stored record rewritten on every tick (#157). Leaving the preferences route without saving discards the draft.

API changes: `toggle(key)` no longer accepts `ActionOptions` (name the record source at `save()` instead), and `ConsentState` gains a required `draft` field. Per-category `granted` accessors in all framework bindings read `draft ?? decisions` so checkboxes respond instantly; custom panels rendering checkboxes from raw `decisions` should apply the same merge.

## 1.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/core",
"version": "1.1.0",
"version": "1.2.0",
"description": "Core package for PolicyStack",
"license": "Apache-2.0",
"repository": {
Expand Down
23 changes: 23 additions & 0 deletions packages/react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# @policystack/react

## 1.2.0

### Minor Changes

- 996973e: `@policystack/react/consent` now exposes the provider's consent store, so `gateScript` and the `@policystack/scripts` catalogue are usable with the React bindings (#159). Previously `<PolicyStack>` created its store privately and nothing exported it, leaving no way to obtain the `ConsentStore` that `gateScript(store, def)` requires.

Two new exports:

- `<GatedScript def={...} />` — the React binding for `gateScript`. Takes the store from `<PolicyStack>`, gates the script for as long as it is mounted, and disposes on unmount. Renders no DOM and is inert during SSR. Building the definition inline (`def={ga4({ measurementId: "G-XXXXXXX" })}`) is safe: the gate follows `def.id`, so a fresh object each render neither re-gates nor drops queued pre-consent calls. Optional `onEvent` receives the `ScriptEvent` stream.
- `useConsentStore()` — returns the `ConsentStore` for handing to other core free functions such as `gateScripts`. Stable for the life of the provider and non-reactive; keep using `useConsent` / `useCategory` / `<ConsentGate>` to react to state.

Both throw the existing provider guard outside `<PolicyStack>` or under a policy-only config. That error message now names the full consent API rather than three of its members.

- e0fc26a: Consent hooks no longer cause hydration mismatches under SSR. The React hooks passed live store state as `useSyncExternalStore`'s `getServerSnapshot`, so any returning visitor mismatched: the server has no stored record and resolves the _host's_ timezone, while the client has both (#158). Every SSR consumer had to hand-roll a `mounted` flag around consent-driven UI.

`ConsentStore` gains a `server` member (`getState()` / `has()`) returning a deterministic pre-consent snapshot: undecided, no jurisdiction, conservative opt-in posture, derived from static config alone and never from the adapter or resolver. `useConsent`, `useCategory`, and `ConsentGate` pass it as `getServerSnapshot`, and React re-reads live state once hydration commits.

The Vue, Svelte, Solid, and Angular bindings still seed from live state and are unchanged here; `store.server` is the shared primitive their fix will use.

- 279688a: Consent preference toggles are now staged. `toggle()` writes to `state.draft` instead of live decisions, and nothing is gated, persisted, or script-loaded until `save()` promotes the draft in one step — scripts no longer load on checkbox tick before "Save", and returning visitors no longer get their stored record rewritten on every tick (#157). Leaving the preferences route without saving discards the draft.

API changes: `toggle(key)` no longer accepts `ActionOptions` (name the record source at `save()` instead), and `ConsentState` gains a required `draft` field. Per-category `granted` accessors in all framework bindings read `draft ?? decisions` so checkboxes respond instantly; custom panels rendering checkboxes from raw `decisions` should apply the same merge.

## 1.1.0

## 1.0.1
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/react",
"version": "1.1.0",
"version": "1.2.0",
"description": "React components and hooks for PolicyStack",
"license": "Apache-2.0",
"repository": {
Expand Down
9 changes: 9 additions & 0 deletions packages/renderers/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# @policystack/renderers

## 1.2.0

### Patch Changes

- Updated dependencies [4cc5985]
- Updated dependencies [e0fc26a]
- Updated dependencies [279688a]
- @policystack/core@1.2.0

## 1.1.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/renderers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/renderers",
"version": "1.1.0",
"version": "1.2.0",
"description": "Shared policy render layer for PolicyStack — Markdown, HTML, and PDF renderers over the Document AST.",
"license": "Apache-2.0",
"repository": {
Expand Down
2 changes: 2 additions & 0 deletions packages/scripts/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# @policystack/scripts

## 1.2.0

## 1.1.0

## 1.0.1
2 changes: 1 addition & 1 deletion packages/scripts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/scripts",
"version": "1.1.0",
"version": "1.2.0",
"description": "Consent-gated third-party tag loaders for PolicyStack (GA4, Meta Pixel, PostHog, …)",
"license": "Apache-2.0",
"repository": {
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# @policystack/sdk

## 1.2.0

## 1.1.0

## 1.0.1
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/sdk",
"version": "1.1.0",
"version": "1.2.0",
"description": "Public API for defining privacy policies with PolicyStack",
"license": "Apache-2.0",
"repository": {
Expand Down
8 changes: 8 additions & 0 deletions packages/solid/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @policystack/solid

## 1.2.0

### Minor Changes

- 279688a: Consent preference toggles are now staged. `toggle()` writes to `state.draft` instead of live decisions, and nothing is gated, persisted, or script-loaded until `save()` promotes the draft in one step — scripts no longer load on checkbox tick before "Save", and returning visitors no longer get their stored record rewritten on every tick (#157). Leaving the preferences route without saving discards the draft.

API changes: `toggle(key)` no longer accepts `ActionOptions` (name the record source at `save()` instead), and `ConsentState` gains a required `draft` field. Per-category `granted` accessors in all framework bindings read `draft ?? decisions` so checkboxes respond instantly; custom panels rendering checkboxes from raw `decisions` should apply the same merge.

## 1.1.0

## 1.0.1
2 changes: 1 addition & 1 deletion packages/solid/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/solid",
"version": "1.1.0",
"version": "1.2.0",
"description": "Solid consent components and hooks for PolicyStack",
"license": "Apache-2.0",
"repository": {
Expand Down
8 changes: 8 additions & 0 deletions packages/svelte/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @policystack/svelte

## 1.2.0

### Minor Changes

- 279688a: Consent preference toggles are now staged. `toggle()` writes to `state.draft` instead of live decisions, and nothing is gated, persisted, or script-loaded until `save()` promotes the draft in one step — scripts no longer load on checkbox tick before "Save", and returning visitors no longer get their stored record rewritten on every tick (#157). Leaving the preferences route without saving discards the draft.

API changes: `toggle(key)` no longer accepts `ActionOptions` (name the record source at `save()` instead), and `ConsentState` gains a required `draft` field. Per-category `granted` accessors in all framework bindings read `draft ?? decisions` so checkboxes respond instantly; custom panels rendering checkboxes from raw `decisions` should apply the same merge.

## 1.1.0

## 1.0.1
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/svelte",
"version": "1.1.0",
"version": "1.2.0",
"description": "Svelte components for PolicyStack",
"license": "Apache-2.0",
"repository": {
Expand Down
25 changes: 25 additions & 0 deletions packages/vite/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# @policystack/vite

## 1.2.0

### Patch Changes

- 035afc7: `policystack.gen.ts` is no longer rewritten on every build, so it stops fighting the consumer's formatter (#166).

The file is meant to be committed, which puts it under whatever formatter the project runs — and the plugin's raw `JSON.stringify` output was never going to match. Since the plugin rewrote it unconditionally at `buildStart`, every build undid the formatting and left a spurious diff, a red format check, and a build → reformat → build loop that never settled.

The header now carries a digest of the scanned content:

```ts
// AUTO-GENERATED by @policystack/vite — do not edit. (scan: 66861eea20c06b94)
```

Each build compares that digest against the current scan and skips the write entirely when they match, whatever the file has been reformatted to since — a `//` comment survives every formatter. The digest covers only what the module renders, so it is insensitive to scan ordering (renaming a source file no longer counts as a change) and to scanner diagnostics. A missing or unreadable header rewrites, so a hand-edited or pre-digest file self-heals.

The output is also pretty-printed now — one entry per line, trailing commas, `{}` for empty interface bodies, quotes on augmentation keys only where an identifier will not do — which narrows the diff on the builds where a rewrite is genuinely needed. Values stay fully quoted so each literal remains parseable as JSON.

Existing `policystack.gen.ts` files have no digest and will be rewritten once, on the first build after upgrading.

- Updated dependencies [4cc5985]
- Updated dependencies [e0fc26a]
- Updated dependencies [279688a]
- @policystack/core@1.2.0

## 1.1.0

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@policystack/vite",
"version": "1.1.0",
"version": "1.2.0",
"description": "Vite plugin that scans source files for @policystack/sdk collecting()/thirdParty() calls and populates the auto-collected registry at build time",
"keywords": [
"policystack",
Expand Down
Loading