@openpolicy/cli 0.0.11 → 0.0.12
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/dist/cli.js +120 -316
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { defineCommand, runMain } from "citty";
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
4
|
import { join, resolve } from "node:path";
|
|
4
5
|
import consola from "consola";
|
|
5
6
|
import { existsSync, watch } from "node:fs";
|
|
6
|
-
import {
|
|
7
|
-
import { compilePolicy, expandOpenPolicyConfig, isOpenPolicyConfig, validatePrivacyPolicy, validateTermsOfService } from "@openpolicy/core";
|
|
7
|
+
import { compilePolicy, expandOpenPolicyConfig, isOpenPolicyConfig, validateCookiePolicy, validatePrivacyPolicy, validateTermsOfService } from "@openpolicy/core";
|
|
8
8
|
//#region \0rolldown/runtime.js
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
10
10
|
var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -19,265 +19,109 @@ var __exportAll = (all, no_symbols) => {
|
|
|
19
19
|
};
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region package.json
|
|
22
|
-
var version = "0.0.
|
|
22
|
+
var version = "0.0.12";
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region src/commands/init.ts
|
|
25
|
-
var init_exports = /* @__PURE__ */ __exportAll({
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (choice === "ccpa") return ["ca"];
|
|
29
|
-
if (choice === "both") return ["eu", "ca"];
|
|
30
|
-
return ["us"];
|
|
31
|
-
}
|
|
32
|
-
function toDataCollected(categories) {
|
|
33
|
-
const groups = {};
|
|
34
|
-
for (const cat of categories) {
|
|
35
|
-
const mapping = DATA_CATEGORY_MAP[cat];
|
|
36
|
-
if (!mapping) continue;
|
|
37
|
-
groups[mapping.group] = [...groups[mapping.group] ?? [], mapping.label];
|
|
38
|
-
}
|
|
39
|
-
return Object.keys(groups).length > 0 ? groups : { "Personal Information": ["Email address"] };
|
|
40
|
-
}
|
|
41
|
-
function toUserRights(jurisdictions) {
|
|
42
|
-
const rights = new Set(["access", "erasure"]);
|
|
43
|
-
if (jurisdictions.includes("eu")) for (const r of [
|
|
44
|
-
"rectification",
|
|
45
|
-
"portability",
|
|
46
|
-
"restriction",
|
|
47
|
-
"objection"
|
|
48
|
-
]) rights.add(r);
|
|
49
|
-
if (jurisdictions.includes("ca")) for (const r of ["opt_out_sale", "non_discrimination"]) rights.add(r);
|
|
50
|
-
return Array.from(rights);
|
|
51
|
-
}
|
|
52
|
-
function renderPrivacyConfig(values) {
|
|
53
|
-
const dataLines = Object.entries(values.dataCollected).map(([k, v]) => ` ${JSON.stringify(k)}: ${JSON.stringify(v)},`).join("\n");
|
|
54
|
-
return `import { definePrivacyPolicy } from "@openpolicy/sdk";
|
|
55
|
-
|
|
56
|
-
export default definePrivacyPolicy({
|
|
57
|
-
effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
|
|
58
|
-
company: {
|
|
59
|
-
name: ${JSON.stringify(values.companyName)},
|
|
60
|
-
legalName: ${JSON.stringify(values.legalName)},
|
|
61
|
-
address: ${JSON.stringify(values.address)},
|
|
62
|
-
contact: ${JSON.stringify(values.contact)},
|
|
63
|
-
},
|
|
64
|
-
dataCollected: {
|
|
65
|
-
${dataLines}
|
|
66
|
-
},
|
|
67
|
-
legalBasis: ${JSON.stringify(values.legalBasis)},
|
|
68
|
-
retention: {
|
|
69
|
-
"All personal data": "As long as necessary for the purposes described in this policy",
|
|
70
|
-
},
|
|
71
|
-
cookies: {
|
|
72
|
-
essential: true,
|
|
73
|
-
analytics: ${values.hasCookies},
|
|
74
|
-
marketing: false,
|
|
75
|
-
},
|
|
76
|
-
thirdParties: [],
|
|
77
|
-
userRights: ${JSON.stringify(values.userRights)},
|
|
78
|
-
jurisdictions: ${JSON.stringify(values.jurisdictions)},
|
|
25
|
+
var init_exports = /* @__PURE__ */ __exportAll({
|
|
26
|
+
getOpenPolicyTemplate: () => getOpenPolicyTemplate,
|
|
27
|
+
initCommand: () => initCommand
|
|
79
28
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return `import { defineTermsOfService } from "@openpolicy/sdk";
|
|
29
|
+
function getOpenPolicyTemplate(companyName, contactEmail, policies) {
|
|
30
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
31
|
+
return `import { defineConfig } from "@openpolicy/sdk";
|
|
84
32
|
|
|
85
|
-
export default
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
eligibility: {
|
|
97
|
-
minimumAge: 13,
|
|
98
|
-
},
|
|
99
|
-
accounts: {
|
|
100
|
-
registrationRequired: false,
|
|
101
|
-
userResponsibleForCredentials: true,
|
|
102
|
-
companyCanTerminate: true,
|
|
103
|
-
},
|
|
104
|
-
prohibitedUses: [
|
|
105
|
-
"Violating any applicable laws or regulations",
|
|
106
|
-
"Infringing on intellectual property rights",
|
|
107
|
-
"Transmitting harmful or malicious content",
|
|
108
|
-
],
|
|
109
|
-
intellectualProperty: {
|
|
110
|
-
companyOwnsService: true,
|
|
111
|
-
usersMayNotCopy: true,
|
|
112
|
-
},
|
|
113
|
-
termination: {
|
|
114
|
-
companyCanTerminate: true,
|
|
115
|
-
userCanTerminate: true,
|
|
116
|
-
},
|
|
117
|
-
disclaimers: {
|
|
118
|
-
serviceProvidedAsIs: true,
|
|
119
|
-
noWarranties: true,
|
|
120
|
-
},
|
|
121
|
-
limitationOfLiability: {
|
|
122
|
-
excludesIndirectDamages: true,
|
|
123
|
-
},
|
|
124
|
-
governingLaw: {
|
|
125
|
-
jurisdiction: ${JSON.stringify(values.jurisdiction)},
|
|
126
|
-
},
|
|
127
|
-
changesPolicy: {
|
|
128
|
-
noticeMethod: "email or prominent notice on our website",
|
|
129
|
-
noticePeriodDays: 30,
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
`;
|
|
133
|
-
}
|
|
134
|
-
var DATA_CATEGORY_MAP, initCommand;
|
|
135
|
-
var init_init = __esmMin((() => {
|
|
136
|
-
DATA_CATEGORY_MAP = {
|
|
137
|
-
name: {
|
|
138
|
-
group: "Personal Information",
|
|
139
|
-
label: "Full name"
|
|
140
|
-
},
|
|
141
|
-
email: {
|
|
142
|
-
group: "Personal Information",
|
|
143
|
-
label: "Email address"
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
company: {
|
|
35
|
+
name: "${companyName}",
|
|
36
|
+
legalName: "${companyName}",
|
|
37
|
+
address: "",
|
|
38
|
+
contact: "${contactEmail}",
|
|
39
|
+
},${policies.includes("privacy") ? `
|
|
40
|
+
privacy: {
|
|
41
|
+
effectiveDate: "${today}",
|
|
42
|
+
dataCollected: {
|
|
43
|
+
"Personal Information": ["Email address"],
|
|
144
44
|
},
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
45
|
+
legalBasis: "Legitimate interests",
|
|
46
|
+
retention: {
|
|
47
|
+
"All personal data": "As long as necessary for the purposes described in this policy",
|
|
148
48
|
},
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
49
|
+
cookies: { essential: true, analytics: false, marketing: false },
|
|
50
|
+
thirdParties: [],
|
|
51
|
+
userRights: ["access", "erasure"],
|
|
52
|
+
jurisdictions: ["us"],
|
|
53
|
+
},` : ""}${policies.includes("terms") ? `
|
|
54
|
+
terms: {
|
|
55
|
+
effectiveDate: "${today}",
|
|
56
|
+
acceptance: { methods: ["using the service", "creating an account"] },
|
|
57
|
+
eligibility: { minimumAge: 13 },
|
|
58
|
+
accounts: {
|
|
59
|
+
registrationRequired: false,
|
|
60
|
+
userResponsibleForCredentials: true,
|
|
61
|
+
companyCanTerminate: true,
|
|
152
62
|
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
63
|
+
prohibitedUses: [
|
|
64
|
+
"Violating any applicable laws or regulations",
|
|
65
|
+
"Infringing on intellectual property rights",
|
|
66
|
+
"Transmitting harmful or malicious content",
|
|
67
|
+
],
|
|
68
|
+
intellectualProperty: { companyOwnsService: true, usersMayNotCopy: true },
|
|
69
|
+
termination: { companyCanTerminate: true, userCanTerminate: true },
|
|
70
|
+
disclaimers: { serviceProvidedAsIs: true, noWarranties: true },
|
|
71
|
+
limitationOfLiability: { excludesIndirectDamages: true },
|
|
72
|
+
governingLaw: { jurisdiction: "Delaware, USA" },
|
|
73
|
+
changesPolicy: {
|
|
74
|
+
noticeMethod: "email or prominent notice on our website",
|
|
75
|
+
noticePeriodDays: 30,
|
|
156
76
|
},
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
77
|
+
},` : ""}${policies.includes("cookie") ? `
|
|
78
|
+
cookie: {
|
|
79
|
+
effectiveDate: "${today}",
|
|
80
|
+
cookies: { essential: true, analytics: false, functional: false, marketing: false },
|
|
81
|
+
jurisdictions: ["us"],
|
|
82
|
+
},` : ""}
|
|
83
|
+
});
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
var initCommand;
|
|
87
|
+
var init_init = __esmMin((() => {
|
|
166
88
|
initCommand = defineCommand({
|
|
167
89
|
meta: {
|
|
168
90
|
name: "init",
|
|
169
91
|
description: "Interactively create a policy config file"
|
|
170
92
|
},
|
|
171
|
-
args: {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
},
|
|
177
|
-
yes: {
|
|
178
|
-
type: "boolean",
|
|
179
|
-
description: "Skip prompts and use defaults (CI mode)",
|
|
180
|
-
default: false
|
|
181
|
-
},
|
|
182
|
-
type: {
|
|
183
|
-
type: "string",
|
|
184
|
-
description: "Policy type: \"privacy\" or \"terms\"",
|
|
185
|
-
default: "privacy"
|
|
186
|
-
}
|
|
187
|
-
},
|
|
93
|
+
args: { out: {
|
|
94
|
+
type: "string",
|
|
95
|
+
description: "Output path for generated config",
|
|
96
|
+
default: "openpolicy.ts"
|
|
97
|
+
} },
|
|
188
98
|
async run({ args }) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
consola.
|
|
192
|
-
const companyName = String(await consola.prompt("Company name?", {
|
|
193
|
-
type: "text",
|
|
194
|
-
cancel: "reject"
|
|
195
|
-
}));
|
|
196
|
-
const legalName = String(await consola.prompt("Legal entity name?", {
|
|
197
|
-
type: "text",
|
|
198
|
-
cancel: "reject",
|
|
199
|
-
initial: companyName
|
|
200
|
-
}));
|
|
201
|
-
const address = String(await consola.prompt("Company address?", {
|
|
99
|
+
consola.box("Welcome to OpenPolicy\nGenerate privacy policies, terms of service, and cookie policies from a single config file.");
|
|
100
|
+
consola.start("Let's get you set up.");
|
|
101
|
+
const source = getOpenPolicyTemplate(String(await consola.prompt("Company name?", {
|
|
202
102
|
type: "text",
|
|
203
103
|
cancel: "reject"
|
|
204
|
-
}))
|
|
205
|
-
const contact = String(await consola.prompt(policyType === "terms" ? "Legal contact email?" : "Privacy contact email?", {
|
|
104
|
+
})), String(await consola.prompt("Contact email?", {
|
|
206
105
|
type: "text",
|
|
207
106
|
cancel: "reject"
|
|
107
|
+
})), await consola.prompt("Which policies do you need?", {
|
|
108
|
+
type: "multiselect",
|
|
109
|
+
cancel: "reject",
|
|
110
|
+
options: [
|
|
111
|
+
"privacy",
|
|
112
|
+
"terms",
|
|
113
|
+
"cookie"
|
|
114
|
+
]
|
|
208
115
|
}));
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
companyName,
|
|
212
|
-
legalName,
|
|
213
|
-
address,
|
|
214
|
-
contact,
|
|
215
|
-
jurisdiction: String(await consola.prompt("Governing law jurisdiction? (e.g. Delaware, USA)", {
|
|
216
|
-
type: "text",
|
|
217
|
-
cancel: "reject",
|
|
218
|
-
initial: "Delaware, USA"
|
|
219
|
-
}))
|
|
220
|
-
});
|
|
221
|
-
else {
|
|
222
|
-
const jurisdictionChoice = String(await consola.prompt("Jurisdiction?", {
|
|
223
|
-
type: "select",
|
|
224
|
-
cancel: "reject",
|
|
225
|
-
options: [
|
|
226
|
-
"gdpr",
|
|
227
|
-
"ccpa",
|
|
228
|
-
"both"
|
|
229
|
-
]
|
|
230
|
-
}));
|
|
231
|
-
const dataCategories = await consola.prompt("Data categories collected?", {
|
|
232
|
-
type: "multiselect",
|
|
233
|
-
cancel: "reject",
|
|
234
|
-
options: [
|
|
235
|
-
"name",
|
|
236
|
-
"email",
|
|
237
|
-
"ip_address",
|
|
238
|
-
"device_info",
|
|
239
|
-
"location",
|
|
240
|
-
"payment_info",
|
|
241
|
-
"usage_data"
|
|
242
|
-
]
|
|
243
|
-
});
|
|
244
|
-
const hasCookies = Boolean(await consola.prompt("Does your app use cookies?", {
|
|
245
|
-
type: "confirm",
|
|
246
|
-
cancel: "reject",
|
|
247
|
-
initial: true
|
|
248
|
-
}));
|
|
249
|
-
const jurisdictions = toJurisdictions(jurisdictionChoice);
|
|
250
|
-
const dataCollected = toDataCollected(dataCategories);
|
|
251
|
-
const userRights = toUserRights(jurisdictions);
|
|
252
|
-
source = renderPrivacyConfig({
|
|
253
|
-
companyName,
|
|
254
|
-
legalName,
|
|
255
|
-
address,
|
|
256
|
-
contact,
|
|
257
|
-
jurisdictions,
|
|
258
|
-
dataCollected,
|
|
259
|
-
legalBasis: jurisdictions.includes("eu") ? "Legitimate interests and consent" : "",
|
|
260
|
-
hasCookies,
|
|
261
|
-
userRights
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
const outPath = resolve(args.out || defaultOut);
|
|
265
|
-
await Bun.write(outPath, source);
|
|
116
|
+
const outPath = resolve(args.out);
|
|
117
|
+
await writeFile(outPath, source);
|
|
266
118
|
consola.success(`Config written to ${outPath}`);
|
|
119
|
+
consola.info(`Open ${outPath} and fill in your company's details — address, legal name, and any policy-specific fields.`);
|
|
120
|
+
consola.info(`When you're ready, run:\n\n openpolicy generate ${args.out}\n\nto compile your policies to HTML or Markdown.`);
|
|
267
121
|
}
|
|
268
122
|
});
|
|
269
123
|
}));
|
|
270
124
|
//#endregion
|
|
271
|
-
//#region src/utils/detect-type.ts
|
|
272
|
-
function detectType(explicitType, configPath) {
|
|
273
|
-
if (explicitType === "privacy" || explicitType === "terms" || explicitType === "cookie") return explicitType;
|
|
274
|
-
const lower = configPath.toLowerCase();
|
|
275
|
-
if (lower.includes("cookie")) return "cookie";
|
|
276
|
-
if (lower.includes("terms")) return "terms";
|
|
277
|
-
return "privacy";
|
|
278
|
-
}
|
|
279
|
-
var init_detect_type = __esmMin((() => {}));
|
|
280
|
-
//#endregion
|
|
281
125
|
//#region src/utils/load-config.ts
|
|
282
126
|
async function loadConfig(configPath, bustCache = false) {
|
|
283
127
|
const absPath = resolve(configPath);
|
|
@@ -305,28 +149,13 @@ var init_load_config = __esmMin((() => {}));
|
|
|
305
149
|
//#endregion
|
|
306
150
|
//#region src/commands/generate.ts
|
|
307
151
|
var generate_exports = /* @__PURE__ */ __exportAll({ generateCommand: () => generateCommand });
|
|
308
|
-
function
|
|
309
|
-
if (policyType === "terms") return {
|
|
310
|
-
type: "terms",
|
|
311
|
-
...config
|
|
312
|
-
};
|
|
313
|
-
if (policyType === "cookie") return {
|
|
314
|
-
type: "cookie",
|
|
315
|
-
...config
|
|
316
|
-
};
|
|
317
|
-
return {
|
|
318
|
-
type: "privacy",
|
|
319
|
-
...config
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
async function generateFromConfig(configPath, formats, outDir, explicitType, bustCache = false) {
|
|
323
|
-
if (!existsSync(configPath)) return false;
|
|
152
|
+
async function generateFromConfig(configPath, formats, outDir, bustCache = false) {
|
|
324
153
|
const config = await loadConfig(configPath, bustCache);
|
|
325
154
|
if (isOpenPolicyConfig(config)) {
|
|
326
155
|
const inputs = expandOpenPolicyConfig(config);
|
|
327
156
|
if (inputs.length === 0) {
|
|
328
157
|
consola.warn(`Unified config has no privacy or terms sections: ${configPath}`);
|
|
329
|
-
return
|
|
158
|
+
return;
|
|
330
159
|
}
|
|
331
160
|
await mkdir(outDir, { recursive: true });
|
|
332
161
|
for (const input of inputs) {
|
|
@@ -339,23 +168,12 @@ async function generateFromConfig(configPath, formats, outDir, explicitType, bus
|
|
|
339
168
|
consola.success(`Written: ${outPath}`);
|
|
340
169
|
}
|
|
341
170
|
}
|
|
342
|
-
return
|
|
343
|
-
}
|
|
344
|
-
const policyType = detectType(explicitType, configPath);
|
|
345
|
-
consola.start(`Generating ${policyType} policy from ${configPath} → formats: ${formats.join(", ")}`);
|
|
346
|
-
const outputFilename = policyType === "terms" ? "terms-of-service" : policyType === "cookie" ? "cookie-policy" : "privacy-policy";
|
|
347
|
-
const results = compilePolicy(toPolicyInput(policyType, config), { formats });
|
|
348
|
-
await mkdir(outDir, { recursive: true });
|
|
349
|
-
for (const result of results) {
|
|
350
|
-
const outPath = join(outDir, `${outputFilename}.${result.format === "markdown" ? "md" : result.format}`);
|
|
351
|
-
await writeFile(outPath, result.content, "utf-8");
|
|
352
|
-
consola.success(`Written: ${outPath}`);
|
|
171
|
+
return;
|
|
353
172
|
}
|
|
354
|
-
|
|
173
|
+
throw new Error(`[openpolicy] Config must use defineConfig() (OpenPolicyConfig): ${configPath}`);
|
|
355
174
|
}
|
|
356
175
|
var generateCommand;
|
|
357
176
|
var init_generate = __esmMin((() => {
|
|
358
|
-
init_detect_type();
|
|
359
177
|
init_load_config();
|
|
360
178
|
generateCommand = defineCommand({
|
|
361
179
|
meta: {
|
|
@@ -365,8 +183,8 @@ var init_generate = __esmMin((() => {
|
|
|
365
183
|
args: {
|
|
366
184
|
config: {
|
|
367
185
|
type: "positional",
|
|
368
|
-
description: "Path
|
|
369
|
-
default: "./openpolicy.ts
|
|
186
|
+
description: "Path to policy config file",
|
|
187
|
+
default: "./openpolicy.ts"
|
|
370
188
|
},
|
|
371
189
|
format: {
|
|
372
190
|
type: "string",
|
|
@@ -378,43 +196,32 @@ var init_generate = __esmMin((() => {
|
|
|
378
196
|
description: "Output directory",
|
|
379
197
|
default: "./output"
|
|
380
198
|
},
|
|
381
|
-
type: {
|
|
382
|
-
type: "string",
|
|
383
|
-
description: "Policy type: \"privacy\", \"terms\", or \"cookie\" (auto-detected from filename if omitted)",
|
|
384
|
-
default: ""
|
|
385
|
-
},
|
|
386
199
|
watch: {
|
|
387
200
|
type: "boolean",
|
|
388
|
-
description: "Watch config
|
|
201
|
+
description: "Watch config file and regenerate on changes",
|
|
389
202
|
default: false
|
|
390
203
|
}
|
|
391
204
|
},
|
|
392
205
|
async run({ args }) {
|
|
393
206
|
const formats = args.format.split(",").map((f) => f.trim()).filter(Boolean);
|
|
394
207
|
const outDir = args.out;
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const watchablePaths = [];
|
|
399
|
-
for (const configPath of configPaths) if (await generateFromConfig(configPath, formats, outDir, explicitType)) watchablePaths.push(configPath);
|
|
400
|
-
else if (hasMultipleConfigs) consola.warn(`Config not found, skipping: ${configPath}`);
|
|
401
|
-
else throw new Error(`Config not found: ${configPath}`);
|
|
208
|
+
const configPath = args.config;
|
|
209
|
+
if (!existsSync(configPath)) throw new Error(`Config not found: ${configPath}`);
|
|
210
|
+
await generateFromConfig(configPath, formats, outDir);
|
|
402
211
|
consola.success(`Policy generation complete → ${outDir}`);
|
|
403
|
-
if (args.watch
|
|
212
|
+
if (args.watch) {
|
|
404
213
|
consola.info("Watching for changes...");
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
});
|
|
417
|
-
}
|
|
214
|
+
let debounceTimer = null;
|
|
215
|
+
watch(configPath, () => {
|
|
216
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
217
|
+
debounceTimer = setTimeout(async () => {
|
|
218
|
+
try {
|
|
219
|
+
await generateFromConfig(configPath, formats, outDir, true);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
consola.error(`Error regenerating ${configPath}:`, err);
|
|
222
|
+
}
|
|
223
|
+
}, 100);
|
|
224
|
+
});
|
|
418
225
|
}
|
|
419
226
|
}
|
|
420
227
|
});
|
|
@@ -424,7 +231,6 @@ var init_generate = __esmMin((() => {
|
|
|
424
231
|
var validate_exports = /* @__PURE__ */ __exportAll({ validateCommand: () => validateCommand });
|
|
425
232
|
var validateCommand;
|
|
426
233
|
var init_validate = __esmMin((() => {
|
|
427
|
-
init_detect_type();
|
|
428
234
|
init_load_config();
|
|
429
235
|
validateCommand = defineCommand({
|
|
430
236
|
meta: {
|
|
@@ -441,31 +247,29 @@ var init_validate = __esmMin((() => {
|
|
|
441
247
|
type: "string",
|
|
442
248
|
description: "Jurisdiction to validate against: gdpr, ccpa, or all",
|
|
443
249
|
default: "all"
|
|
444
|
-
},
|
|
445
|
-
type: {
|
|
446
|
-
type: "string",
|
|
447
|
-
description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
|
|
448
|
-
default: ""
|
|
449
250
|
}
|
|
450
251
|
},
|
|
451
252
|
async run({ args }) {
|
|
452
253
|
const configPath = args.config ?? "./policy.config.ts";
|
|
453
|
-
const policyType = detectType(args.type || void 0, configPath);
|
|
454
|
-
consola.start(`Validating ${policyType} policy: ${configPath}`);
|
|
455
254
|
const config = await loadConfig(configPath);
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
255
|
+
if (!isOpenPolicyConfig(config)) throw new Error(`[openpolicy] Config must use defineConfig() (OpenPolicyConfig): ${configPath}`);
|
|
256
|
+
const inputs = expandOpenPolicyConfig(config);
|
|
257
|
+
let totalErrors = 0;
|
|
258
|
+
for (const input of inputs) {
|
|
259
|
+
consola.start(`Validating ${input.type} policy: ${configPath}`);
|
|
260
|
+
const issues = input.type === "terms" ? validateTermsOfService(input) : input.type === "cookie" ? validateCookiePolicy(input) : validatePrivacyPolicy(input);
|
|
261
|
+
if (issues.length === 0) {
|
|
262
|
+
consola.success(`${input.type}: no issues found.`);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
for (const issue of issues) if (issue.level === "error") consola.error(issue.message);
|
|
266
|
+
else consola.warn(issue.message);
|
|
267
|
+
const errors = issues.filter((i) => i.level === "error");
|
|
268
|
+
totalErrors += errors.length;
|
|
269
|
+
if (errors.length > 0) consola.fail(`${input.type}: validation failed with ${errors.length} error(s).`);
|
|
270
|
+
else consola.success(`${input.type}: validation passed with warnings.`);
|
|
467
271
|
}
|
|
468
|
-
|
|
272
|
+
if (totalErrors > 0) process.exit(1);
|
|
469
273
|
}
|
|
470
274
|
});
|
|
471
275
|
}));
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpolicy/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for generating and validating OpenPolicy privacy policy documents",
|
|
6
|
-
"license": "
|
|
6
|
+
"license": "GPL-3.0-only",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/jamiedavenport/openpolicy",
|