@openpolicy/sdk 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/auto-collected.d.ts +27 -1
- package/dist/auto-collected.d.ts.map +1 -1
- package/dist/auto-collected.js +23 -1
- package/dist/auto-collected.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
- package/skills/annotate-data-collection/SKILL.md +240 -0
- package/skills/annotate-third-parties/SKILL.md +237 -0
- package/skills/annotate-third-parties/references/known-packages.md +37 -0
- package/skills/define-config/SKILL.md +286 -0
- package/skills/define-config/references/privacy-config.md +153 -0
- package/skills/define-config/references/terms-config.md +130 -0
- package/skills/getting-started/SKILL.md +251 -0
- package/skills/migrate/SKILL.md +360 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: annotate-third-parties
|
|
3
|
+
description: >
|
|
4
|
+
Mark third-party service dependencies in source code using thirdParty() so
|
|
5
|
+
the autoCollect() Vite plugin can populate the thirdParties sentinel for the
|
|
6
|
+
privacy policy config. Covers manual annotation, usePackageJson auto-detection
|
|
7
|
+
from the KNOWN_PACKAGES registry, combining both approaches, and the Providers
|
|
8
|
+
preset as a static alternative.
|
|
9
|
+
type: core
|
|
10
|
+
library: openpolicy
|
|
11
|
+
library_version: "0.0.19"
|
|
12
|
+
requires:
|
|
13
|
+
- openpolicy/vite-setup
|
|
14
|
+
sources:
|
|
15
|
+
- jamiedavenport/openpolicy:packages/sdk/src/third-parties.ts
|
|
16
|
+
- jamiedavenport/openpolicy:packages/vite-auto-collect/src/known-packages.ts
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
This skill builds on openpolicy/vite-setup. Read it first.
|
|
20
|
+
|
|
21
|
+
## How It Works
|
|
22
|
+
|
|
23
|
+
`thirdParty()` is a **runtime no-op**. It is a build-time marker — `autoCollect()` scans source files statically via `oxc-parser` and extracts the three string literal arguments. The plugin then populates the `thirdParties` sentinel exported from `@openpolicy/sdk`. Without the plugin, `thirdParty()` calls have no effect whatsoever.
|
|
24
|
+
|
|
25
|
+
The populated sentinel must be spread into `privacy.thirdParties` in the config file. Without the spread, the plugin output is discarded and the policy renders with no third parties listed.
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
Three moving parts must all be in place:
|
|
30
|
+
|
|
31
|
+
**1. `vite.config.ts` — enable the plugin**
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { defineConfig } from "vite";
|
|
35
|
+
import { autoCollect } from "@openpolicy/vite-auto-collect";
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
plugins: [
|
|
39
|
+
autoCollect({
|
|
40
|
+
thirdParties: { usePackageJson: true }, // optional — see below
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**2. Source file — annotate next to the usage**
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { thirdParty } from "@openpolicy/sdk";
|
|
50
|
+
|
|
51
|
+
// Place next to where you initialise or use the third-party SDK
|
|
52
|
+
thirdParty("Stripe", "Payment processing", "https://stripe.com/privacy");
|
|
53
|
+
|
|
54
|
+
// ... rest of your Stripe integration
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**3. `openpolicy.ts` — spread the sentinel into config**
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { defineConfig, thirdParties } from "@openpolicy/sdk";
|
|
61
|
+
|
|
62
|
+
export default defineConfig({
|
|
63
|
+
company: {
|
|
64
|
+
name: "Acme",
|
|
65
|
+
legalName: "Acme, Inc.",
|
|
66
|
+
address: "123 Main St, San Francisco, CA 94105",
|
|
67
|
+
contact: "privacy@acme.com",
|
|
68
|
+
},
|
|
69
|
+
privacy: {
|
|
70
|
+
effectiveDate: "2026-01-01",
|
|
71
|
+
thirdParties: [...thirdParties],
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Core Patterns
|
|
77
|
+
|
|
78
|
+
### 1. Manual thirdParty() annotation
|
|
79
|
+
|
|
80
|
+
Call `thirdParty(name, purpose, policyUrl)` with three string literals next to wherever you initialise the third-party integration. All three arguments must be string literals — dynamic values are silently skipped by the static analyser.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { thirdParty } from "@openpolicy/sdk";
|
|
84
|
+
|
|
85
|
+
// Correct: all string literals
|
|
86
|
+
thirdParty("Intercom", "Customer messaging", "https://www.intercom.com/legal/privacy");
|
|
87
|
+
|
|
88
|
+
// Wrong: variable — silently skipped at build time
|
|
89
|
+
const name = "Intercom";
|
|
90
|
+
thirdParty(name, "Customer messaging", "https://www.intercom.com/legal/privacy");
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Deduplication is by `name` — the first occurrence wins when files are walked in sorted alphabetical order. Calling `thirdParty()` with the same name from multiple files is safe.
|
|
94
|
+
|
|
95
|
+
### 2. usePackageJson auto-detection
|
|
96
|
+
|
|
97
|
+
`autoCollect({ thirdParties: { usePackageJson: true } })` reads `package.json` at build time and cross-references every entry in `dependencies` and `devDependencies` against the built-in KNOWN_PACKAGES registry. Matched packages are merged into `thirdParties` automatically, with deduplication by service name.
|
|
98
|
+
|
|
99
|
+
This is the fastest way to cover common services (Stripe, Sentry, PostHog, Vercel, etc.) without any source annotations.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
// vite.config.ts
|
|
103
|
+
autoCollect({ thirdParties: { usePackageJson: true } })
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
See [references/known-packages.md](references/known-packages.md) for the full list of ~30 auto-detected packages.
|
|
107
|
+
|
|
108
|
+
### 3. Combining both approaches
|
|
109
|
+
|
|
110
|
+
`thirdParty()` annotations and `usePackageJson` are merged at build time. The plugin deduplicates by service name — `thirdParty()` entries from source files are added first (sorted file order), then package.json detections fill in any remaining services not already seen.
|
|
111
|
+
|
|
112
|
+
Use this combination when:
|
|
113
|
+
- Most services are covered by the KNOWN_PACKAGES registry (`usePackageJson: true`)
|
|
114
|
+
- A few services are not in the registry and need explicit `thirdParty()` calls
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// vite.config.ts
|
|
118
|
+
autoCollect({ thirdParties: { usePackageJson: true } })
|
|
119
|
+
|
|
120
|
+
// src/lib/custom-analytics.ts
|
|
121
|
+
import { thirdParty } from "@openpolicy/sdk";
|
|
122
|
+
thirdParty("Fathom Analytics", "Privacy-friendly web analytics", "https://usefathom.com/privacy");
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// openpolicy.ts — one spread covers both sources
|
|
127
|
+
import { defineConfig, thirdParties } from "@openpolicy/sdk";
|
|
128
|
+
|
|
129
|
+
export default defineConfig({
|
|
130
|
+
privacy: {
|
|
131
|
+
thirdParties: [...thirdParties],
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 4. Providers presets as a static alternative
|
|
137
|
+
|
|
138
|
+
`Providers` from `@openpolicy/sdk` is a collection of pre-filled third-party objects for common services. Use this when you want to declare third parties statically in `openpolicy.ts` without any source annotations or plugin scanning.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { defineConfig, Providers } from "@openpolicy/sdk";
|
|
142
|
+
|
|
143
|
+
export default defineConfig({
|
|
144
|
+
privacy: {
|
|
145
|
+
thirdParties: [
|
|
146
|
+
Providers.Stripe,
|
|
147
|
+
Providers.Sentry,
|
|
148
|
+
Providers.Vercel,
|
|
149
|
+
{ name: "Custom Service", purpose: "Internal logging", policyUrl: "https://example.com/privacy" },
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Available presets: `Stripe`, `Paddle`, `LemonSqueezy`, `PayPal`, `GoogleAnalytics`, `PostHog`, `Plausible`, `Mixpanel`, `Vercel`, `Cloudflare`, `AWS`, `Auth0`, `Clerk`, `Resend`, `Postmark`, `SendGrid`, `Loops`, `Sentry`, `Datadog`.
|
|
156
|
+
|
|
157
|
+
Note: when using `Providers` statically, you can still spread `thirdParties` alongside it to capture any additional auto-collected services:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
privacy: {
|
|
161
|
+
thirdParties: [...thirdParties, Providers.Cloudflare],
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Common Mistakes
|
|
166
|
+
|
|
167
|
+
### HIGH — Using thirdParty() without the autoCollect() plugin and expecting a runtime effect
|
|
168
|
+
|
|
169
|
+
`thirdParty()` is defined as a no-op function that immediately returns `undefined`. It has no runtime behaviour. The only way it produces output in the policy is when `autoCollect()` is present in `vite.config.ts` and scans the file at build time.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
// WRONG: calling thirdParty() and expecting it to affect the policy at runtime
|
|
173
|
+
import { thirdParty } from "@openpolicy/sdk";
|
|
174
|
+
thirdParty("Stripe", "Payment processing", "https://stripe.com/privacy");
|
|
175
|
+
// Without autoCollect() in vite.config.ts, this does nothing
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
// Correct: autoCollect() in vite.config.ts is the required prerequisite
|
|
180
|
+
// vite.config.ts
|
|
181
|
+
import { autoCollect } from "@openpolicy/vite-auto-collect";
|
|
182
|
+
export default defineConfig({ plugins: [autoCollect()] });
|
|
183
|
+
|
|
184
|
+
// src/lib/stripe.ts — scanned at build time by the plugin
|
|
185
|
+
import { thirdParty } from "@openpolicy/sdk";
|
|
186
|
+
thirdParty("Stripe", "Payment processing", "https://stripe.com/privacy");
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### HIGH — Not spreading thirdParties sentinel into privacy.thirdParties
|
|
190
|
+
|
|
191
|
+
Even when `autoCollect()` scans the source and populates the sentinel, the populated value is discarded unless it is imported and spread into `privacy.thirdParties` in the config. The privacy policy then renders with an empty third-party section, which may be legally invalid.
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
// WRONG: thirdParties not imported or spread
|
|
195
|
+
export default defineConfig({
|
|
196
|
+
privacy: {
|
|
197
|
+
thirdParties: [], // static empty array, discards plugin output
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
// Correct
|
|
204
|
+
import { defineConfig, thirdParties } from "@openpolicy/sdk";
|
|
205
|
+
|
|
206
|
+
export default defineConfig({
|
|
207
|
+
privacy: {
|
|
208
|
+
thirdParties: [...thirdParties],
|
|
209
|
+
// or combine with static entries:
|
|
210
|
+
// thirdParties: [...thirdParties, Providers.Cloudflare],
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### MEDIUM — Not enabling usePackageJson when known packages are used
|
|
216
|
+
|
|
217
|
+
The KNOWN_PACKAGES registry covers ~30 common npm packages. Without `usePackageJson: true`, packages like `@sentry/browser`, `posthog-js`, or `@stripe/stripe-js` are not auto-detected and must each be annotated manually with `thirdParty()`. Enabling the option costs nothing and eliminates this annotation burden for any covered package.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
// WRONG: usePackageJson not enabled — known packages not auto-detected
|
|
221
|
+
autoCollect()
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
// Correct
|
|
226
|
+
autoCollect({ thirdParties: { usePackageJson: true } })
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## References
|
|
230
|
+
|
|
231
|
+
- [Known packages registry](references/known-packages.md) — full table of npm packages auto-detected by `usePackageJson: true`
|
|
232
|
+
- `packages/sdk/src/third-parties.ts` — thirdParty() implementation (runtime no-op)
|
|
233
|
+
- `packages/sdk/src/providers.ts` — Providers preset objects
|
|
234
|
+
- `packages/sdk/src/auto-collected.ts` — thirdParties sentinel definition
|
|
235
|
+
- `packages/vite-auto-collect/src/index.ts` — autoCollect() plugin, AutoCollectOptions type
|
|
236
|
+
- `packages/vite-auto-collect/src/analyse.ts` — static AST extraction logic
|
|
237
|
+
- `packages/vite-auto-collect/src/known-packages.ts` — KNOWN_PACKAGES registry source
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Known Packages Registry
|
|
2
|
+
|
|
3
|
+
These npm package names are auto-detected when `usePackageJson: true` is set in `autoCollect()`. The plugin reads `dependencies` and `devDependencies` from the project root `package.json` and matches entries against this registry. Multiple package names can map to the same service — deduplication is by service name, first match wins.
|
|
4
|
+
|
|
5
|
+
| npm package | Service name | Purpose |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| `stripe` | Stripe | Payment processing |
|
|
8
|
+
| `@stripe/stripe-js` | Stripe | Payment processing |
|
|
9
|
+
| `braintree` | Braintree | Payment processing |
|
|
10
|
+
| `@braintree/browser-drop-in` | Braintree | Payment processing |
|
|
11
|
+
| `@sentry/browser` | Sentry | Error tracking |
|
|
12
|
+
| `@sentry/node` | Sentry | Error tracking |
|
|
13
|
+
| `@sentry/nextjs` | Sentry | Error tracking |
|
|
14
|
+
| `@sentry/react` | Sentry | Error tracking |
|
|
15
|
+
| `@sentry/vue` | Sentry | Error tracking |
|
|
16
|
+
| `@datadog/browser-rum` | Datadog | Monitoring |
|
|
17
|
+
| `dd-trace` | Datadog | Monitoring |
|
|
18
|
+
| `posthog-js` | PostHog | Product analytics |
|
|
19
|
+
| `posthog-node` | PostHog | Product analytics |
|
|
20
|
+
| `mixpanel-browser` | Mixpanel | Product analytics |
|
|
21
|
+
| `@segment/analytics-next` | Segment | Customer data platform |
|
|
22
|
+
| `@amplitude/analytics-browser` | Amplitude | Product analytics |
|
|
23
|
+
| `amplitude-js` | Amplitude | Product analytics |
|
|
24
|
+
| `@vercel/analytics` | Vercel Analytics | Web analytics |
|
|
25
|
+
| `plausible-tracker` | Plausible | Web analytics |
|
|
26
|
+
| `logrocket` | LogRocket | Session recording |
|
|
27
|
+
| `@hotjar/browser` | Hotjar | Session recording |
|
|
28
|
+
| `resend` | Resend | Transactional email |
|
|
29
|
+
| `@sendgrid/mail` | SendGrid | Transactional email |
|
|
30
|
+
| `intercom-client` | Intercom | Customer messaging |
|
|
31
|
+
| `@intercom/messenger-js-sdk` | Intercom | Customer messaging |
|
|
32
|
+
|
|
33
|
+
## Services not in the registry
|
|
34
|
+
|
|
35
|
+
For services not listed here, use `thirdParty()` source annotations or the `Providers` preset constants from `@openpolicy/sdk`. See the main skill file for examples.
|
|
36
|
+
|
|
37
|
+
The registry source is at `packages/vite-auto-collect/src/known-packages.ts`.
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: define-config
|
|
3
|
+
description: >
|
|
4
|
+
Writing the defineConfig() object for OpenPolicyConfig — privacy, terms, cookie — including all field types, jurisdiction requirements, and preset constants from @openpolicy/sdk.
|
|
5
|
+
type: core
|
|
6
|
+
library: openpolicy
|
|
7
|
+
library_version: "0.0.19"
|
|
8
|
+
sources:
|
|
9
|
+
- jamiedavenport/openpolicy:packages/core/src/types.ts
|
|
10
|
+
- jamiedavenport/openpolicy:packages/sdk/src/constants.ts
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# openpolicy/define-config
|
|
14
|
+
|
|
15
|
+
Write and maintain the `defineConfig()` call in `openpolicy.ts`. The function is an identity function used as a type marker — it accepts `OpenPolicyConfig` and returns it unchanged.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
Minimal config with privacy policy:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// openpolicy.ts
|
|
23
|
+
import { defineConfig, dataCollected, thirdParties } from "@openpolicy/sdk";
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
company: {
|
|
27
|
+
name: "Acme",
|
|
28
|
+
legalName: "Acme, Inc.",
|
|
29
|
+
address: "123 Main St, San Francisco, CA 94105",
|
|
30
|
+
contact: "privacy@acme.com",
|
|
31
|
+
},
|
|
32
|
+
privacy: {
|
|
33
|
+
effectiveDate: "2026-01-01",
|
|
34
|
+
dataCollected: { ...dataCollected },
|
|
35
|
+
legalBasis: "legitimate_interests",
|
|
36
|
+
retention: { "Account Information": "Until account deletion" },
|
|
37
|
+
cookies: { essential: true, analytics: false, marketing: false },
|
|
38
|
+
thirdParties: [...thirdParties],
|
|
39
|
+
userRights: ["access", "erasure"],
|
|
40
|
+
jurisdictions: ["us"],
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`company` is declared once at the top level — do not repeat it inside `privacy`, `terms`, or `cookie`.
|
|
46
|
+
|
|
47
|
+
## Core Patterns
|
|
48
|
+
|
|
49
|
+
### 1. Privacy config with GDPR
|
|
50
|
+
|
|
51
|
+
Use `Compliance.GDPR` to spread the required `jurisdictions`, `legalBasis`, and `userRights` values in one step:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import {
|
|
55
|
+
defineConfig,
|
|
56
|
+
Compliance,
|
|
57
|
+
DataCategories,
|
|
58
|
+
Retention,
|
|
59
|
+
Providers,
|
|
60
|
+
dataCollected,
|
|
61
|
+
thirdParties,
|
|
62
|
+
} from "@openpolicy/sdk";
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
company: {
|
|
66
|
+
name: "Acme",
|
|
67
|
+
legalName: "Acme, Inc.",
|
|
68
|
+
address: "123 Main St, San Francisco, CA 94105",
|
|
69
|
+
contact: "privacy@acme.com",
|
|
70
|
+
},
|
|
71
|
+
privacy: {
|
|
72
|
+
effectiveDate: "2026-01-01",
|
|
73
|
+
...Compliance.GDPR,
|
|
74
|
+
dataCollected: {
|
|
75
|
+
...dataCollected,
|
|
76
|
+
...DataCategories.AccountInfo,
|
|
77
|
+
...DataCategories.UsageData,
|
|
78
|
+
},
|
|
79
|
+
retention: {
|
|
80
|
+
"Account Information": Retention.UntilAccountDeletion,
|
|
81
|
+
"Usage Data": Retention.NinetyDays,
|
|
82
|
+
},
|
|
83
|
+
cookies: { essential: true, analytics: true, marketing: false },
|
|
84
|
+
thirdParties: [...thirdParties, Providers.Stripe, Providers.PostHog],
|
|
85
|
+
children: { underAge: 13 },
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`Compliance.GDPR` expands to `{ jurisdictions: ["eu"], legalBasis: ["legitimate_interests"], userRights: ["access", "rectification", "erasure", "portability", "restriction", "objection"] }`.
|
|
91
|
+
|
|
92
|
+
### 2. Terms of service config
|
|
93
|
+
|
|
94
|
+
`governingLaw` is required — validation throws if absent.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
export default defineConfig({
|
|
98
|
+
company: { ... },
|
|
99
|
+
terms: {
|
|
100
|
+
effectiveDate: "2026-01-01",
|
|
101
|
+
acceptance: { methods: ["using the service", "creating an account"] },
|
|
102
|
+
governingLaw: { jurisdiction: "Delaware, USA" },
|
|
103
|
+
eligibility: { minimumAge: 18 },
|
|
104
|
+
accounts: {
|
|
105
|
+
registrationRequired: true,
|
|
106
|
+
userResponsibleForCredentials: true,
|
|
107
|
+
companyCanTerminate: true,
|
|
108
|
+
},
|
|
109
|
+
disclaimers: { serviceProvidedAsIs: true, noWarranties: true },
|
|
110
|
+
limitationOfLiability: {
|
|
111
|
+
excludesIndirectDamages: true,
|
|
112
|
+
liabilityCap: "fees paid in the last 12 months",
|
|
113
|
+
},
|
|
114
|
+
termination: {
|
|
115
|
+
companyCanTerminate: true,
|
|
116
|
+
userCanTerminate: true,
|
|
117
|
+
effectOfTermination: "All licenses granted to the user terminate immediately.",
|
|
118
|
+
},
|
|
119
|
+
disputeResolution: {
|
|
120
|
+
method: "arbitration",
|
|
121
|
+
venue: "San Francisco, CA",
|
|
122
|
+
classActionWaiver: true,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
All fields other than `effectiveDate`, `acceptance`, and `governingLaw` are optional. Include sections only when the corresponding policy content applies. See [references/terms-config.md](./references/terms-config.md) for the full field table.
|
|
129
|
+
|
|
130
|
+
### 3. Using Compliance presets
|
|
131
|
+
|
|
132
|
+
`Compliance.GDPR` and `Compliance.CCPA` are objects safe to spread into `privacy`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { Compliance } from "@openpolicy/sdk";
|
|
136
|
+
|
|
137
|
+
// GDPR only
|
|
138
|
+
privacy: { ...Compliance.GDPR, ... }
|
|
139
|
+
|
|
140
|
+
// Both (array values merge correctly via spread — userRights and jurisdictions union)
|
|
141
|
+
privacy: {
|
|
142
|
+
...Compliance.GDPR,
|
|
143
|
+
jurisdictions: [...Compliance.GDPR.jurisdictions, ...Compliance.CCPA.jurisdictions],
|
|
144
|
+
userRights: [...Compliance.GDPR.userRights, ...Compliance.CCPA.userRights],
|
|
145
|
+
...
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`Compliance.CCPA` does not include `legalBasis` — it provides only `jurisdictions: ["ca"]` and `userRights: ["access", "erasure", "opt_out_sale", "non_discrimination"]`.
|
|
150
|
+
|
|
151
|
+
Available preset groups from `@openpolicy/sdk`:
|
|
152
|
+
|
|
153
|
+
| Export | Content |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `DataCategories` | Named `dataCollected` entries (AccountInfo, SessionData, PaymentInfo, UsageData, DeviceInfo, LocationData, Communications) |
|
|
156
|
+
| `Retention` | Retention period strings (UntilAccountDeletion, ThirtyDays, NinetyDays, OneYear, ThreeYears, AsRequiredByLaw, …) |
|
|
157
|
+
| `Rights` | `UserRight` string constants (Access, Rectification, Erasure, …) |
|
|
158
|
+
| `LegalBases` | `LegalBasis` string constants (Consent, Contract, LegitimateInterests, …) |
|
|
159
|
+
| `Compliance` | Preset bundles: `GDPR`, `CCPA` |
|
|
160
|
+
| `Providers` | Named third-party descriptors: Stripe, PostHog, Vercel, Sentry, Clerk, Resend, … |
|
|
161
|
+
|
|
162
|
+
### 4. Cookie config
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
export default defineConfig({
|
|
166
|
+
company: { ... },
|
|
167
|
+
cookie: {
|
|
168
|
+
effectiveDate: "2026-01-01",
|
|
169
|
+
cookies: { essential: true, analytics: true, marketing: false },
|
|
170
|
+
jurisdictions: ["eu", "us"],
|
|
171
|
+
consentMechanism: {
|
|
172
|
+
hasBanner: true,
|
|
173
|
+
hasPreferencePanel: true,
|
|
174
|
+
canWithdraw: true,
|
|
175
|
+
},
|
|
176
|
+
trackingTechnologies: ["localStorage", "sessionStorage", "cookies"],
|
|
177
|
+
thirdParties: [Providers.GoogleAnalytics, Providers.Cloudflare],
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`CookiePolicyCookies` requires `essential: boolean` — all other keys are `boolean` and are treated as additional cookie categories.
|
|
183
|
+
|
|
184
|
+
## Common Mistakes
|
|
185
|
+
|
|
186
|
+
### HIGH — Using standalone PrivacyPolicyConfig instead of nested OpenPolicyConfig
|
|
187
|
+
|
|
188
|
+
Wrong:
|
|
189
|
+
```ts
|
|
190
|
+
// WRONG: standalone shape, company repeated inside the policy object
|
|
191
|
+
import type { PrivacyPolicyConfig } from "@openpolicy/sdk";
|
|
192
|
+
|
|
193
|
+
const config: PrivacyPolicyConfig = {
|
|
194
|
+
company: { name: "Acme", legalName: "Acme, Inc.", address: "...", contact: "..." },
|
|
195
|
+
effectiveDate: "2026-01-01",
|
|
196
|
+
dataCollected: {},
|
|
197
|
+
legalBasis: "consent",
|
|
198
|
+
retention: {},
|
|
199
|
+
cookies: { essential: true, analytics: false, marketing: false },
|
|
200
|
+
thirdParties: [],
|
|
201
|
+
userRights: [],
|
|
202
|
+
jurisdictions: [],
|
|
203
|
+
};
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Correct:
|
|
207
|
+
```ts
|
|
208
|
+
// correct: nested OpenPolicyConfig via defineConfig()
|
|
209
|
+
import { defineConfig } from "@openpolicy/sdk";
|
|
210
|
+
|
|
211
|
+
export default defineConfig({
|
|
212
|
+
company: { name: "Acme", legalName: "Acme, Inc.", address: "...", contact: "privacy@acme.com" },
|
|
213
|
+
privacy: {
|
|
214
|
+
effectiveDate: "2026-01-01",
|
|
215
|
+
dataCollected: {},
|
|
216
|
+
legalBasis: "consent",
|
|
217
|
+
retention: {},
|
|
218
|
+
cookies: { essential: true, analytics: false, marketing: false },
|
|
219
|
+
thirdParties: [],
|
|
220
|
+
userRights: [],
|
|
221
|
+
jurisdictions: [],
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
React components and the autoCollect pipeline read from `OpenPolicyConfig`; the standalone policy types are internal shapes not consumed by the rendering layer.
|
|
227
|
+
|
|
228
|
+
Source: `packages/core/src/types.ts`
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### HIGH — Omitting governingLaw from terms of service
|
|
233
|
+
|
|
234
|
+
Wrong:
|
|
235
|
+
```ts
|
|
236
|
+
// WRONG: governingLaw missing — validation throws at compile time
|
|
237
|
+
terms: {
|
|
238
|
+
effectiveDate: "2026-01-01",
|
|
239
|
+
acceptance: { methods: ["using the service"] },
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Correct:
|
|
244
|
+
```ts
|
|
245
|
+
terms: {
|
|
246
|
+
effectiveDate: "2026-01-01",
|
|
247
|
+
acceptance: { methods: ["using the service"] },
|
|
248
|
+
governingLaw: { jurisdiction: "Delaware, USA" },
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`governingLaw` is a required field on `TermsOfServiceConfig`. `validateTermsOfService()` emits a fatal error if `governingLaw.jurisdiction` is absent or empty. TypeScript will catch this at authoring time only if the object is typed as `Omit<TermsOfServiceConfig, "company">`.
|
|
253
|
+
|
|
254
|
+
Source: `packages/core/src/validate-terms.ts`
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### MEDIUM — Not specifying jurisdictions — GDPR/CCPA sections silently absent
|
|
259
|
+
|
|
260
|
+
Wrong:
|
|
261
|
+
```ts
|
|
262
|
+
// WRONG: jurisdictions missing — legalBasis section and GDPR/CCPA content will not appear
|
|
263
|
+
privacy: {
|
|
264
|
+
legalBasis: "legitimate_interests",
|
|
265
|
+
userRights: ["access", "erasure"],
|
|
266
|
+
// jurisdictions omitted
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Correct:
|
|
271
|
+
```ts
|
|
272
|
+
privacy: {
|
|
273
|
+
legalBasis: "legitimate_interests",
|
|
274
|
+
userRights: ["access", "erasure"],
|
|
275
|
+
jurisdictions: ["eu", "us"],
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Section builders for GDPR (`eu`) and CCPA (`ca`) content check `config.jurisdictions` before generating output. Omitting `jurisdictions` (or passing an empty array) causes those sections to be silently skipped with no warning. `Compliance.GDPR` and `Compliance.CCPA` include the correct `jurisdictions` values when spread.
|
|
280
|
+
|
|
281
|
+
Source: `packages/core/src/templates/privacy/`
|
|
282
|
+
|
|
283
|
+
## Reference
|
|
284
|
+
|
|
285
|
+
- [PrivacyPolicyConfig and CookiePolicyConfig field table](./references/privacy-config.md)
|
|
286
|
+
- [TermsOfServiceConfig field table](./references/terms-config.md)
|