@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.
@@ -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
+ ```