@openpolicy/sdk 0.0.19 → 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/index.d.ts +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- 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,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)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# PrivacyPolicyConfig Field Reference
|
|
2
|
+
|
|
3
|
+
When used inside `defineConfig()`, `company` is omitted — it lives at the top level of `OpenPolicyConfig`. All other fields below are on `privacy: Omit<PrivacyPolicyConfig, "company">`.
|
|
4
|
+
|
|
5
|
+
## PrivacyPolicyConfig
|
|
6
|
+
|
|
7
|
+
| Field | Type | Required | Notes |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `effectiveDate` | `string` | Yes | ISO date string (e.g. `"2026-01-01"`). Validation fails if empty. |
|
|
10
|
+
| `dataCollected` | `Record<string, string[]>` | Yes | At least one entry required. Keys are category labels; values are arrays of data point labels. Use `DataCategories.*` presets or spread `dataCollected` sentinel. |
|
|
11
|
+
| `legalBasis` | `LegalBasis \| LegalBasis[]` | Yes (GDPR) | Required when `"eu"` is in `jurisdictions`. Accepts a single value or array. |
|
|
12
|
+
| `retention` | `Record<string, string>` | Yes | Keys should match `dataCollected` categories. Use `Retention.*` preset strings. |
|
|
13
|
+
| `cookies` | `{ essential: boolean; analytics: boolean; marketing: boolean }` | Yes | All three booleans required. Drives cookie policy sections. |
|
|
14
|
+
| `thirdParties` | `{ name: string; purpose: string; policyUrl?: string }[]` | Yes | Can be empty array. Use `Providers.*` presets or spread `thirdParties` sentinel. |
|
|
15
|
+
| `userRights` | `UserRight[]` | Yes | Empty array triggers a warning. GDPR recommends 6 rights; CCPA recommends 4. |
|
|
16
|
+
| `jurisdictions` | `Jurisdiction[]` | Yes | Controls which jurisdiction-specific sections appear. See values below. |
|
|
17
|
+
| `children` | `{ underAge: number; noticeUrl?: string }` | No | Include when service is directed at children. `underAge` must be a positive integer. |
|
|
18
|
+
|
|
19
|
+
### LegalBasis values
|
|
20
|
+
|
|
21
|
+
| Constant | String value |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `LegalBases.Consent` | `"consent"` |
|
|
24
|
+
| `LegalBases.Contract` | `"contract"` |
|
|
25
|
+
| `LegalBases.LegalObligation` | `"legal_obligation"` |
|
|
26
|
+
| `LegalBases.VitalInterests` | `"vital_interests"` |
|
|
27
|
+
| `LegalBases.PublicTask` | `"public_task"` |
|
|
28
|
+
| `LegalBases.LegitimateInterests` | `"legitimate_interests"` |
|
|
29
|
+
|
|
30
|
+
### Jurisdiction values
|
|
31
|
+
|
|
32
|
+
| Value | Region |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `"us"` | United States |
|
|
35
|
+
| `"eu"` | European Union (triggers GDPR sections) |
|
|
36
|
+
| `"ca"` | California, USA (triggers CCPA sections) |
|
|
37
|
+
| `"au"` | Australia |
|
|
38
|
+
| `"nz"` | New Zealand |
|
|
39
|
+
| `"other"` | Other / unspecified |
|
|
40
|
+
|
|
41
|
+
### UserRight values
|
|
42
|
+
|
|
43
|
+
| Constant | String value | Required by |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `Rights.Access` | `"access"` | GDPR, CCPA |
|
|
46
|
+
| `Rights.Rectification` | `"rectification"` | GDPR |
|
|
47
|
+
| `Rights.Erasure` | `"erasure"` | GDPR, CCPA |
|
|
48
|
+
| `Rights.Portability` | `"portability"` | GDPR |
|
|
49
|
+
| `Rights.Restriction` | `"restriction"` | GDPR |
|
|
50
|
+
| `Rights.Objection` | `"objection"` | GDPR |
|
|
51
|
+
| `Rights.OptOutSale` | `"opt_out_sale"` | CCPA |
|
|
52
|
+
| `Rights.NonDiscrimination` | `"non_discrimination"` | CCPA |
|
|
53
|
+
|
|
54
|
+
### DataCategories presets
|
|
55
|
+
|
|
56
|
+
Each entry is a `Record<string, string[]>` safe to spread into `dataCollected`:
|
|
57
|
+
|
|
58
|
+
| Constant | Category label | Data points |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `DataCategories.AccountInfo` | `"Account Information"` | Name, Email address |
|
|
61
|
+
| `DataCategories.SessionData` | `"Session Data"` | IP address, User agent, Browser type |
|
|
62
|
+
| `DataCategories.PaymentInfo` | `"Payment Information"` | Card last 4 digits, Billing name, Billing address |
|
|
63
|
+
| `DataCategories.UsageData` | `"Usage Data"` | Pages visited, Features used, Time spent |
|
|
64
|
+
| `DataCategories.DeviceInfo` | `"Device Information"` | Device type, Operating system, Browser version |
|
|
65
|
+
| `DataCategories.LocationData` | `"Location Data"` | Country, City, Timezone |
|
|
66
|
+
| `DataCategories.Communications` | `"Communications"` | Email content, Support tickets |
|
|
67
|
+
|
|
68
|
+
### Retention presets
|
|
69
|
+
|
|
70
|
+
| Constant | String value |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `Retention.UntilAccountDeletion` | `"Until account deletion"` |
|
|
73
|
+
| `Retention.UntilSessionExpiry` | `"Until session expiry"` |
|
|
74
|
+
| `Retention.ThirtyDays` | `"30 days"` |
|
|
75
|
+
| `Retention.NinetyDays` | `"90 days"` |
|
|
76
|
+
| `Retention.OneYear` | `"1 year"` |
|
|
77
|
+
| `Retention.ThreeYears` | `"3 years"` |
|
|
78
|
+
| `Retention.AsRequiredByLaw` | `"As required by applicable law"` |
|
|
79
|
+
|
|
80
|
+
### Providers presets
|
|
81
|
+
|
|
82
|
+
Each entry is a `{ name: string; purpose: string; policyUrl: string }` safe to use in `thirdParties`:
|
|
83
|
+
|
|
84
|
+
**Payments:** `Providers.Stripe`, `Providers.Paddle`, `Providers.LemonSqueezy`, `Providers.PayPal`
|
|
85
|
+
|
|
86
|
+
**Analytics:** `Providers.GoogleAnalytics`, `Providers.PostHog`, `Providers.Plausible`, `Providers.Mixpanel`
|
|
87
|
+
|
|
88
|
+
**Infrastructure:** `Providers.Vercel`, `Providers.Cloudflare`, `Providers.AWS`
|
|
89
|
+
|
|
90
|
+
**Auth:** `Providers.Auth0`, `Providers.Clerk`
|
|
91
|
+
|
|
92
|
+
**Email:** `Providers.Resend`, `Providers.Postmark`, `Providers.SendGrid`, `Providers.Loops`
|
|
93
|
+
|
|
94
|
+
**Monitoring:** `Providers.Sentry`, `Providers.Datadog`
|
|
95
|
+
|
|
96
|
+
### Compliance presets
|
|
97
|
+
|
|
98
|
+
| Preset | Expands to |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `Compliance.GDPR` | `{ jurisdictions: ["eu"], legalBasis: ["legitimate_interests"], userRights: ["access", "rectification", "erasure", "portability", "restriction", "objection"] }` |
|
|
101
|
+
| `Compliance.CCPA` | `{ jurisdictions: ["ca"], userRights: ["access", "erasure", "opt_out_sale", "non_discrimination"] }` |
|
|
102
|
+
|
|
103
|
+
### Validation behavior
|
|
104
|
+
|
|
105
|
+
- `effectiveDate` empty → fatal error
|
|
106
|
+
- `company.*` fields empty → fatal error per field
|
|
107
|
+
- `dataCollected` has zero keys → fatal error
|
|
108
|
+
- `userRights` empty → warning only
|
|
109
|
+
- `"eu"` in jurisdictions + no `legalBasis` → fatal error
|
|
110
|
+
- `"eu"` in jurisdictions + missing GDPR right → warning per right
|
|
111
|
+
- `"ca"` in jurisdictions + missing CCPA right → warning per right
|
|
112
|
+
- `children.underAge` ≤ 0 → fatal error
|
|
113
|
+
|
|
114
|
+
Source: `packages/core/src/validate.ts`
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## CookiePolicyConfig
|
|
119
|
+
|
|
120
|
+
When used inside `defineConfig()`, supply as `cookie: Omit<CookiePolicyConfig, "company">`.
|
|
121
|
+
|
|
122
|
+
| Field | Type | Required | Notes |
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| `effectiveDate` | `string` | Yes | ISO date string. |
|
|
125
|
+
| `cookies` | `CookiePolicyCookies` | Yes | `essential: boolean` is required; all other keys are `boolean` and treated as additional cookie categories. |
|
|
126
|
+
| `jurisdictions` | `Jurisdiction[]` | Yes | Same values as `PrivacyPolicyConfig.jurisdictions`. |
|
|
127
|
+
| `thirdParties` | `{ name: string; purpose: string; policyUrl?: string }[]` | No | Use `Providers.*` presets. |
|
|
128
|
+
| `trackingTechnologies` | `string[]` | No | e.g. `["cookies", "localStorage", "sessionStorage", "pixel"]` |
|
|
129
|
+
| `consentMechanism` | `{ hasBanner: boolean; hasPreferencePanel: boolean; canWithdraw: boolean }` | No | Required when `"eu"` in jurisdictions for GDPR compliance. |
|
|
130
|
+
|
|
131
|
+
### CookiePolicyCookies shape
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
type CookiePolicyCookies = {
|
|
135
|
+
essential: boolean; // required
|
|
136
|
+
[key: string]: boolean; // additional categories
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Example with custom categories:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
cookie: {
|
|
144
|
+
effectiveDate: "2026-01-01",
|
|
145
|
+
cookies: {
|
|
146
|
+
essential: true,
|
|
147
|
+
analytics: true,
|
|
148
|
+
marketing: false,
|
|
149
|
+
preferences: true,
|
|
150
|
+
},
|
|
151
|
+
jurisdictions: ["eu", "us"],
|
|
152
|
+
}
|
|
153
|
+
```
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# TermsOfServiceConfig Field Reference
|
|
2
|
+
|
|
3
|
+
When used inside `defineConfig()`, supply as `terms: Omit<TermsOfServiceConfig, "company">`. `company` lives at the top level of `OpenPolicyConfig`.
|
|
4
|
+
|
|
5
|
+
## Required fields
|
|
6
|
+
|
|
7
|
+
| Field | Type | Notes |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| `effectiveDate` | `string` | ISO date string. Validation fails if empty. |
|
|
10
|
+
| `acceptance` | `{ methods: string[] }` | How users accept — e.g. `["using the service", "creating an account"]`. Warning if `methods` is empty. |
|
|
11
|
+
| `governingLaw` | `{ jurisdiction: string }` | **Required.** Validation throws fatal error if `jurisdiction` is absent or empty. |
|
|
12
|
+
|
|
13
|
+
## Optional sections
|
|
14
|
+
|
|
15
|
+
All fields below are optional. Include only those that apply to the service. Omitting a field causes the corresponding policy section to be absent from the rendered document.
|
|
16
|
+
|
|
17
|
+
| Field | Type | Notes |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `eligibility` | `{ minimumAge: number; jurisdictionRestrictions?: string[] }` | Include when service has age or geographic restrictions. |
|
|
20
|
+
| `accounts` | `{ registrationRequired: boolean; userResponsibleForCredentials: boolean; companyCanTerminate: boolean }` | Include when the service has user accounts. |
|
|
21
|
+
| `prohibitedUses` | `string[]` | List of prohibited use descriptions. e.g. `["Scraping content without permission", "Impersonating other users"]`. |
|
|
22
|
+
| `userContent` | `{ usersOwnContent: boolean; licenseGrantedToCompany: boolean; licenseDescription?: string; companyCanRemoveContent: boolean }` | Include when users upload or create content. |
|
|
23
|
+
| `intellectualProperty` | `{ companyOwnsService: boolean; usersMayNotCopy: boolean }` | Standard IP clause. |
|
|
24
|
+
| `payments` | `{ hasPaidFeatures: boolean; refundPolicy?: string; priceChangesNotice?: string }` | Include when service has paid tiers or subscriptions. |
|
|
25
|
+
| `availability` | `{ noUptimeGuarantee: boolean; maintenanceWindows?: string }` | SaaS services typically include this. |
|
|
26
|
+
| `termination` | `{ companyCanTerminate: boolean; userCanTerminate: boolean; effectOfTermination?: string }` | Include to describe account closure behavior. |
|
|
27
|
+
| `disclaimers` | `{ serviceProvidedAsIs: boolean; noWarranties: boolean }` | Strongly recommended — validation emits a warning if absent. |
|
|
28
|
+
| `limitationOfLiability` | `{ excludesIndirectDamages: boolean; liabilityCap?: string }` | Strongly recommended — validation emits a warning if absent. |
|
|
29
|
+
| `indemnification` | `{ userIndemnifiesCompany: boolean; scope?: string }` | Include when the service exposes the company to user-generated liability. |
|
|
30
|
+
| `thirdPartyServices` | `{ name: string; purpose: string }[]` | Third-party services embedded in the product (note: no `policyUrl` field here, unlike privacy's `thirdParties`). |
|
|
31
|
+
| `disputeResolution` | `{ method: DisputeResolutionMethod; venue?: string; classActionWaiver?: boolean }` | Include to specify arbitration or litigation preference. |
|
|
32
|
+
| `changesPolicy` | `{ noticeMethod: string; noticePeriodDays?: number }` | Describe how users are notified of ToS changes. |
|
|
33
|
+
| `privacyPolicyUrl` | `string` | URL of the privacy policy. Cross-references the privacy document. |
|
|
34
|
+
|
|
35
|
+
## DisputeResolutionMethod values
|
|
36
|
+
|
|
37
|
+
| Value | Meaning |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `"arbitration"` | Binding arbitration |
|
|
40
|
+
| `"litigation"` | Court litigation |
|
|
41
|
+
| `"mediation"` | Non-binding mediation |
|
|
42
|
+
|
|
43
|
+
## Validation behavior
|
|
44
|
+
|
|
45
|
+
- `effectiveDate` empty → fatal error
|
|
46
|
+
- `company.*` fields empty → fatal error per field
|
|
47
|
+
- `governingLaw.jurisdiction` empty or missing → fatal error
|
|
48
|
+
- `acceptance.methods` empty → warning only
|
|
49
|
+
- `disclaimers` absent → warning only
|
|
50
|
+
- `limitationOfLiability` absent → warning only
|
|
51
|
+
|
|
52
|
+
Source: `packages/core/src/validate-terms.ts`
|
|
53
|
+
|
|
54
|
+
## Complete example
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { defineConfig } from "@openpolicy/sdk";
|
|
58
|
+
|
|
59
|
+
export default defineConfig({
|
|
60
|
+
company: {
|
|
61
|
+
name: "Acme",
|
|
62
|
+
legalName: "Acme, Inc.",
|
|
63
|
+
address: "123 Main St, San Francisco, CA 94105",
|
|
64
|
+
contact: "legal@acme.com",
|
|
65
|
+
},
|
|
66
|
+
terms: {
|
|
67
|
+
effectiveDate: "2026-01-01",
|
|
68
|
+
acceptance: { methods: ["using the service", "creating an account"] },
|
|
69
|
+
governingLaw: { jurisdiction: "Delaware, USA" },
|
|
70
|
+
eligibility: { minimumAge: 18 },
|
|
71
|
+
accounts: {
|
|
72
|
+
registrationRequired: true,
|
|
73
|
+
userResponsibleForCredentials: true,
|
|
74
|
+
companyCanTerminate: true,
|
|
75
|
+
},
|
|
76
|
+
prohibitedUses: [
|
|
77
|
+
"Scraping content without written permission",
|
|
78
|
+
"Using the service to distribute malware",
|
|
79
|
+
"Impersonating other users or Acme employees",
|
|
80
|
+
],
|
|
81
|
+
userContent: {
|
|
82
|
+
usersOwnContent: true,
|
|
83
|
+
licenseGrantedToCompany: true,
|
|
84
|
+
licenseDescription: "A worldwide, royalty-free license to host and display your content.",
|
|
85
|
+
companyCanRemoveContent: true,
|
|
86
|
+
},
|
|
87
|
+
intellectualProperty: {
|
|
88
|
+
companyOwnsService: true,
|
|
89
|
+
usersMayNotCopy: true,
|
|
90
|
+
},
|
|
91
|
+
payments: {
|
|
92
|
+
hasPaidFeatures: true,
|
|
93
|
+
refundPolicy: "30-day money-back guarantee on annual plans.",
|
|
94
|
+
priceChangesNotice: "30 days written notice before price changes take effect.",
|
|
95
|
+
},
|
|
96
|
+
availability: {
|
|
97
|
+
noUptimeGuarantee: true,
|
|
98
|
+
maintenanceWindows: "Scheduled maintenance occurs Sundays 02:00–04:00 UTC.",
|
|
99
|
+
},
|
|
100
|
+
termination: {
|
|
101
|
+
companyCanTerminate: true,
|
|
102
|
+
userCanTerminate: true,
|
|
103
|
+
effectOfTermination: "All licenses granted to the user terminate immediately upon account closure.",
|
|
104
|
+
},
|
|
105
|
+
disclaimers: { serviceProvidedAsIs: true, noWarranties: true },
|
|
106
|
+
limitationOfLiability: {
|
|
107
|
+
excludesIndirectDamages: true,
|
|
108
|
+
liabilityCap: "fees paid by the user in the twelve months preceding the claim",
|
|
109
|
+
},
|
|
110
|
+
indemnification: {
|
|
111
|
+
userIndemnifiesCompany: true,
|
|
112
|
+
scope: "Claims arising from user content or user violations of these Terms.",
|
|
113
|
+
},
|
|
114
|
+
thirdPartyServices: [
|
|
115
|
+
{ name: "Stripe", purpose: "Payment processing" },
|
|
116
|
+
{ name: "AWS", purpose: "Cloud infrastructure" },
|
|
117
|
+
],
|
|
118
|
+
disputeResolution: {
|
|
119
|
+
method: "arbitration",
|
|
120
|
+
venue: "San Francisco, CA",
|
|
121
|
+
classActionWaiver: true,
|
|
122
|
+
},
|
|
123
|
+
changesPolicy: {
|
|
124
|
+
noticeMethod: "Email notification to the address on your account",
|
|
125
|
+
noticePeriodDays: 30,
|
|
126
|
+
},
|
|
127
|
+
privacyPolicyUrl: "https://acme.com/privacy",
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
```
|