@openpolicy/cli 0.0.11 → 0.0.13

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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +1 -487
  3. package/package.json +9 -3
  4. package/src/cli.ts +5 -0
  5. package/dist/_cli-BVVbyDQ9.js +0 -49
  6. package/dist/_cli-BjVuFgXe.js +0 -33
  7. package/dist/_cli-C-Vx-Nop.js +0 -58
  8. package/dist/_cli-DrypJgn2.js +0 -247
  9. package/dist/_lib-9AbI1LBo.js +0 -35
  10. package/dist/_lib-9AbI1LBo.js.map +0 -1
  11. package/dist/_lib-D2I-M4OU.js +0 -51
  12. package/dist/_lib-D2I-M4OU.js.map +0 -1
  13. package/dist/_lib-D2LkleUQ.js +0 -60
  14. package/dist/_lib-D2LkleUQ.js.map +0 -1
  15. package/dist/_lib-MI0GKJMR.js +0 -249
  16. package/dist/_lib-MI0GKJMR.js.map +0 -1
  17. package/dist/cli +0 -0
  18. package/dist/cli.d.ts +0 -3
  19. package/dist/cli.d.ts.map +0 -1
  20. package/dist/commands/generate.d.ts +0 -18
  21. package/dist/commands/generate.d.ts.map +0 -1
  22. package/dist/commands/generate.test.d.ts +0 -2
  23. package/dist/commands/generate.test.d.ts.map +0 -1
  24. package/dist/commands/init.d.ts +0 -13
  25. package/dist/commands/init.d.ts.map +0 -1
  26. package/dist/commands/init.test.d.ts +0 -2
  27. package/dist/commands/init.test.d.ts.map +0 -1
  28. package/dist/commands/validate.d.ts +0 -13
  29. package/dist/commands/validate.d.ts.map +0 -1
  30. package/dist/commands/validate.test.d.ts +0 -2
  31. package/dist/commands/validate.test.d.ts.map +0 -1
  32. package/dist/generate-ItFTJ-jj.js +0 -60
  33. package/dist/generate-ItFTJ-jj.js.map +0 -1
  34. package/dist/index.d.ts +0 -8
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/index.js +0 -22
  37. package/dist/index.js.map +0 -1
  38. package/dist/index.test.d.ts +0 -2
  39. package/dist/index.test.d.ts.map +0 -1
  40. package/dist/init-37NxG-6N.js +0 -249
  41. package/dist/init-37NxG-6N.js.map +0 -1
  42. package/dist/load-config-Bw8yiDkb.js +0 -35
  43. package/dist/load-config-Bw8yiDkb.js.map +0 -1
  44. package/dist/utils/load-config.d.ts +0 -2
  45. package/dist/utils/load-config.d.ts.map +0 -1
  46. package/dist/validate-DPge58Uv.js +0 -51
  47. package/dist/validate-DPge58Uv.js.map +0 -1
@@ -1,247 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import { resolve } from "node:path";
3
- import consola from "consola";
4
- //#region src/commands/init.ts
5
- const DATA_CATEGORY_MAP = {
6
- name: {
7
- group: "Personal Information",
8
- label: "Full name"
9
- },
10
- email: {
11
- group: "Personal Information",
12
- label: "Email address"
13
- },
14
- ip_address: {
15
- group: "Technical Data",
16
- label: "IP address"
17
- },
18
- device_info: {
19
- group: "Technical Data",
20
- label: "Device type and browser"
21
- },
22
- location: {
23
- group: "Location Data",
24
- label: "Approximate location"
25
- },
26
- payment_info: {
27
- group: "Financial Data",
28
- label: "Payment card details"
29
- },
30
- usage_data: {
31
- group: "Usage Data",
32
- label: "Pages visited and features used"
33
- }
34
- };
35
- function toJurisdictions(choice) {
36
- if (choice === "gdpr") return ["eu"];
37
- if (choice === "ccpa") return ["ca"];
38
- if (choice === "both") return ["eu", "ca"];
39
- return ["us"];
40
- }
41
- function toDataCollected(categories) {
42
- const groups = {};
43
- for (const cat of categories) {
44
- const mapping = DATA_CATEGORY_MAP[cat];
45
- if (!mapping) continue;
46
- groups[mapping.group] = [...groups[mapping.group] ?? [], mapping.label];
47
- }
48
- return Object.keys(groups).length > 0 ? groups : { "Personal Information": ["Email address"] };
49
- }
50
- function toUserRights(jurisdictions) {
51
- const rights = new Set(["access", "erasure"]);
52
- if (jurisdictions.includes("eu")) for (const r of [
53
- "rectification",
54
- "portability",
55
- "restriction",
56
- "objection"
57
- ]) rights.add(r);
58
- if (jurisdictions.includes("ca")) for (const r of ["opt_out_sale", "non_discrimination"]) rights.add(r);
59
- return Array.from(rights);
60
- }
61
- function renderPrivacyConfig(values) {
62
- const dataLines = Object.entries(values.dataCollected).map(([k, v]) => ` ${JSON.stringify(k)}: ${JSON.stringify(v)},`).join("\n");
63
- return `import { definePrivacyPolicy } from "@openpolicy/sdk";
64
-
65
- export default definePrivacyPolicy({
66
- effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
67
- company: {
68
- name: ${JSON.stringify(values.companyName)},
69
- legalName: ${JSON.stringify(values.legalName)},
70
- address: ${JSON.stringify(values.address)},
71
- contact: ${JSON.stringify(values.contact)},
72
- },
73
- dataCollected: {
74
- ${dataLines}
75
- },
76
- legalBasis: ${JSON.stringify(values.legalBasis)},
77
- retention: {
78
- "All personal data": "As long as necessary for the purposes described in this policy",
79
- },
80
- cookies: {
81
- essential: true,
82
- analytics: ${values.hasCookies},
83
- marketing: false,
84
- },
85
- thirdParties: [],
86
- userRights: ${JSON.stringify(values.userRights)},
87
- jurisdictions: ${JSON.stringify(values.jurisdictions)},
88
- });
89
- `;
90
- }
91
- function renderTermsConfig(values) {
92
- return `import { defineTermsOfService } from "@openpolicy/sdk";
93
-
94
- export default defineTermsOfService({
95
- effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
96
- company: {
97
- name: ${JSON.stringify(values.companyName)},
98
- legalName: ${JSON.stringify(values.legalName)},
99
- address: ${JSON.stringify(values.address)},
100
- contact: ${JSON.stringify(values.contact)},
101
- },
102
- acceptance: {
103
- methods: ["using the service", "creating an account"],
104
- },
105
- eligibility: {
106
- minimumAge: 13,
107
- },
108
- accounts: {
109
- registrationRequired: false,
110
- userResponsibleForCredentials: true,
111
- companyCanTerminate: true,
112
- },
113
- prohibitedUses: [
114
- "Violating any applicable laws or regulations",
115
- "Infringing on intellectual property rights",
116
- "Transmitting harmful or malicious content",
117
- ],
118
- intellectualProperty: {
119
- companyOwnsService: true,
120
- usersMayNotCopy: true,
121
- },
122
- termination: {
123
- companyCanTerminate: true,
124
- userCanTerminate: true,
125
- },
126
- disclaimers: {
127
- serviceProvidedAsIs: true,
128
- noWarranties: true,
129
- },
130
- limitationOfLiability: {
131
- excludesIndirectDamages: true,
132
- },
133
- governingLaw: {
134
- jurisdiction: ${JSON.stringify(values.jurisdiction)},
135
- },
136
- changesPolicy: {
137
- noticeMethod: "email or prominent notice on our website",
138
- noticePeriodDays: 30,
139
- },
140
- });
141
- `;
142
- }
143
- const initCommand = defineCommand({
144
- meta: {
145
- name: "init",
146
- description: "Interactively create a policy config file"
147
- },
148
- args: {
149
- out: {
150
- type: "string",
151
- description: "Output path for generated config",
152
- default: ""
153
- },
154
- yes: {
155
- type: "boolean",
156
- description: "Skip prompts and use defaults (CI mode)",
157
- default: false
158
- },
159
- type: {
160
- type: "string",
161
- description: "Policy type: \"privacy\" or \"terms\"",
162
- default: "privacy"
163
- }
164
- },
165
- async run({ args }) {
166
- const policyType = args.type === "terms" ? "terms" : "privacy";
167
- const defaultOut = policyType === "terms" ? "./terms.config.ts" : "./privacy.config.ts";
168
- consola.start(`OpenPolicy init wizard (${policyType})`);
169
- const companyName = String(await consola.prompt("Company name?", {
170
- type: "text",
171
- cancel: "reject"
172
- }));
173
- const legalName = String(await consola.prompt("Legal entity name?", {
174
- type: "text",
175
- cancel: "reject",
176
- initial: companyName
177
- }));
178
- const address = String(await consola.prompt("Company address?", {
179
- type: "text",
180
- cancel: "reject"
181
- }));
182
- const contact = String(await consola.prompt(policyType === "terms" ? "Legal contact email?" : "Privacy contact email?", {
183
- type: "text",
184
- cancel: "reject"
185
- }));
186
- let source;
187
- if (policyType === "terms") source = renderTermsConfig({
188
- companyName,
189
- legalName,
190
- address,
191
- contact,
192
- jurisdiction: String(await consola.prompt("Governing law jurisdiction? (e.g. Delaware, USA)", {
193
- type: "text",
194
- cancel: "reject",
195
- initial: "Delaware, USA"
196
- }))
197
- });
198
- else {
199
- const jurisdictionChoice = String(await consola.prompt("Jurisdiction?", {
200
- type: "select",
201
- cancel: "reject",
202
- options: [
203
- "gdpr",
204
- "ccpa",
205
- "both"
206
- ]
207
- }));
208
- const dataCategories = await consola.prompt("Data categories collected?", {
209
- type: "multiselect",
210
- cancel: "reject",
211
- options: [
212
- "name",
213
- "email",
214
- "ip_address",
215
- "device_info",
216
- "location",
217
- "payment_info",
218
- "usage_data"
219
- ]
220
- });
221
- const hasCookies = Boolean(await consola.prompt("Does your app use cookies?", {
222
- type: "confirm",
223
- cancel: "reject",
224
- initial: true
225
- }));
226
- const jurisdictions = toJurisdictions(jurisdictionChoice);
227
- const dataCollected = toDataCollected(dataCategories);
228
- const userRights = toUserRights(jurisdictions);
229
- source = renderPrivacyConfig({
230
- companyName,
231
- legalName,
232
- address,
233
- contact,
234
- jurisdictions,
235
- dataCollected,
236
- legalBasis: jurisdictions.includes("eu") ? "Legitimate interests and consent" : "",
237
- hasCookies,
238
- userRights
239
- });
240
- }
241
- const outPath = resolve(args.out || defaultOut);
242
- await Bun.write(outPath, source);
243
- consola.success(`Config written to ${outPath}`);
244
- }
245
- });
246
- //#endregion
247
- export { initCommand };
@@ -1,35 +0,0 @@
1
- import { resolve } from "node:path";
2
- import consola from "consola";
3
- import { existsSync } from "node:fs";
4
- //#region src/utils/detect-type.ts
5
- function detectType(explicitType, configPath) {
6
- if (explicitType === "privacy" || explicitType === "terms") return explicitType;
7
- return configPath.toLowerCase().includes("terms") ? "terms" : "privacy";
8
- }
9
- //#endregion
10
- //#region src/utils/load-config.ts
11
- async function loadConfig(configPath) {
12
- const absPath = resolve(configPath);
13
- if (!existsSync(absPath)) {
14
- consola.error(`Config file not found: ${absPath}`);
15
- process.exit(1);
16
- }
17
- let mod;
18
- try {
19
- mod = await import(absPath);
20
- } catch (err) {
21
- consola.error(`Failed to load config: ${absPath}`);
22
- consola.error(err);
23
- process.exit(1);
24
- }
25
- const config = mod["default"] ?? mod["module.exports"] ?? mod;
26
- if (config === null || config === void 0 || typeof config !== "object") {
27
- consola.error(`Config must export a non-null object: ${absPath}`);
28
- process.exit(1);
29
- }
30
- return config;
31
- }
32
- //#endregion
33
- export { detectType as n, loadConfig as t };
34
-
35
- //# sourceMappingURL=_lib-9AbI1LBo.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_lib-9AbI1LBo.js","names":[],"sources":["../src/utils/detect-type.ts","../src/utils/load-config.ts"],"sourcesContent":["export function detectType(\n\texplicitType: string | undefined,\n\tconfigPath: string,\n): \"privacy\" | \"terms\" {\n\tif (explicitType === \"privacy\" || explicitType === \"terms\") {\n\t\treturn explicitType;\n\t}\n\treturn configPath.toLowerCase().includes(\"terms\") ? \"terms\" : \"privacy\";\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport consola from \"consola\";\n\nexport async function loadConfig(configPath: string): Promise<unknown> {\n\tconst absPath = resolve(configPath);\n\n\tif (!existsSync(absPath)) {\n\t\tconsola.error(`Config file not found: ${absPath}`);\n\t\tprocess.exit(1);\n\t}\n\n\tlet mod: unknown;\n\ttry {\n\t\tmod = await import(absPath);\n\t} catch (err) {\n\t\tconsola.error(`Failed to load config: ${absPath}`);\n\t\tconsola.error(err);\n\t\tprocess.exit(1);\n\t}\n\n\tconst config =\n\t\t(mod as Record<string, unknown>)[\"default\"] ??\n\t\t(mod as Record<string, unknown>)[\"module.exports\"] ??\n\t\tmod;\n\n\tif (config === null || config === undefined || typeof config !== \"object\") {\n\t\tconsola.error(`Config must export a non-null object: ${absPath}`);\n\t\tprocess.exit(1);\n\t}\n\n\treturn config;\n}\n"],"mappings":";;;;AAAA,SAAgB,WACf,cACA,YACsB;AACtB,KAAI,iBAAiB,aAAa,iBAAiB,QAClD,QAAO;AAER,QAAO,WAAW,aAAa,CAAC,SAAS,QAAQ,GAAG,UAAU;;;;ACH/D,eAAsB,WAAW,YAAsC;CACtE,MAAM,UAAU,QAAQ,WAAW;AAEnC,KAAI,CAAC,WAAW,QAAQ,EAAE;AACzB,UAAQ,MAAM,0BAA0B,UAAU;AAClD,UAAQ,KAAK,EAAE;;CAGhB,IAAI;AACJ,KAAI;AACH,QAAM,MAAM,OAAO;UACX,KAAK;AACb,UAAQ,MAAM,0BAA0B,UAAU;AAClD,UAAQ,MAAM,IAAI;AAClB,UAAQ,KAAK,EAAE;;CAGhB,MAAM,SACJ,IAAgC,cAChC,IAAgC,qBACjC;AAED,KAAI,WAAW,QAAQ,WAAW,KAAA,KAAa,OAAO,WAAW,UAAU;AAC1E,UAAQ,MAAM,yCAAyC,UAAU;AACjE,UAAQ,KAAK,EAAE;;AAGhB,QAAO"}
@@ -1,51 +0,0 @@
1
- import { n as detectType, t as loadConfig } from "./_lib-9AbI1LBo.js";
2
- import { defineCommand } from "citty";
3
- import { validatePrivacyPolicy, validateTermsOfService } from "@openpolicy/core";
4
- import consola from "consola";
5
- //#region src/commands/validate.ts
6
- const validateCommand = defineCommand({
7
- meta: {
8
- name: "validate",
9
- description: "Validate a policy config for compliance"
10
- },
11
- args: {
12
- config: {
13
- type: "positional",
14
- description: "Path to policy config file",
15
- default: "./policy.config.ts"
16
- },
17
- jurisdiction: {
18
- type: "string",
19
- description: "Jurisdiction to validate against: gdpr, ccpa, or all",
20
- default: "all"
21
- },
22
- type: {
23
- type: "string",
24
- description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
25
- default: ""
26
- }
27
- },
28
- async run({ args }) {
29
- const configPath = args.config ?? "./policy.config.ts";
30
- const policyType = detectType(args.type || void 0, configPath);
31
- consola.start(`Validating ${policyType} policy: ${configPath}`);
32
- const config = await loadConfig(configPath);
33
- const issues = policyType === "terms" ? validateTermsOfService(config) : validatePrivacyPolicy(config);
34
- if (issues.length === 0) {
35
- consola.success("Config is valid — no issues found.");
36
- return;
37
- }
38
- for (const issue of issues) if (issue.level === "error") consola.error(issue.message);
39
- else consola.warn(issue.message);
40
- const errors = issues.filter((i) => i.level === "error");
41
- if (errors.length > 0) {
42
- consola.fail(`Validation failed with ${errors.length} error(s).`);
43
- process.exit(1);
44
- }
45
- consola.success("Validation passed with warnings.");
46
- }
47
- });
48
- //#endregion
49
- export { validateCommand };
50
-
51
- //# sourceMappingURL=_lib-D2I-M4OU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_lib-D2I-M4OU.js","names":[],"sources":["../src/commands/validate.ts"],"sourcesContent":["import type {\n\tPrivacyPolicyConfig,\n\tTermsOfServiceConfig,\n} from \"@openpolicy/core\";\nimport {\n\tvalidatePrivacyPolicy,\n\tvalidateTermsOfService,\n} from \"@openpolicy/core\";\nimport { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { detectType } from \"../utils/detect-type\";\nimport { loadConfig } from \"../utils/load-config\";\n\nexport const validateCommand = defineCommand({\n\tmeta: {\n\t\tname: \"validate\",\n\t\tdescription: \"Validate a policy config for compliance\",\n\t},\n\targs: {\n\t\tconfig: {\n\t\t\ttype: \"positional\",\n\t\t\tdescription: \"Path to policy config file\",\n\t\t\tdefault: \"./policy.config.ts\",\n\t\t},\n\t\tjurisdiction: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Jurisdiction to validate against: gdpr, ccpa, or all\",\n\t\t\tdefault: \"all\",\n\t\t},\n\t\ttype: {\n\t\t\ttype: \"string\",\n\t\t\tdescription:\n\t\t\t\t'Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)',\n\t\t\tdefault: \"\",\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst configPath = args.config ?? \"./policy.config.ts\";\n\t\tconst policyType = detectType(args.type || undefined, configPath);\n\n\t\tconsola.start(`Validating ${policyType} policy: ${configPath}`);\n\n\t\tconst config = await loadConfig(configPath);\n\t\tconst issues =\n\t\t\tpolicyType === \"terms\"\n\t\t\t\t? validateTermsOfService(config as TermsOfServiceConfig)\n\t\t\t\t: validatePrivacyPolicy(config as PrivacyPolicyConfig);\n\n\t\tif (issues.length === 0) {\n\t\t\tconsola.success(\"Config is valid — no issues found.\");\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const issue of issues) {\n\t\t\tif (issue.level === \"error\") {\n\t\t\t\tconsola.error(issue.message);\n\t\t\t} else {\n\t\t\t\tconsola.warn(issue.message);\n\t\t\t}\n\t\t}\n\n\t\tconst errors = issues.filter((i) => i.level === \"error\");\n\t\tif (errors.length > 0) {\n\t\t\tconsola.fail(`Validation failed with ${errors.length} error(s).`);\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconsola.success(\"Validation passed with warnings.\");\n\t},\n});\n"],"mappings":";;;;;AAaA,MAAa,kBAAkB,cAAc;CAC5C,MAAM;EACL,MAAM;EACN,aAAa;EACb;CACD,MAAM;EACL,QAAQ;GACP,MAAM;GACN,aAAa;GACb,SAAS;GACT;EACD,cAAc;GACb,MAAM;GACN,aAAa;GACb,SAAS;GACT;EACD,MAAM;GACL,MAAM;GACN,aACC;GACD,SAAS;GACT;EACD;CACD,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,aAAa,KAAK,UAAU;EAClC,MAAM,aAAa,WAAW,KAAK,QAAQ,KAAA,GAAW,WAAW;AAEjE,UAAQ,MAAM,cAAc,WAAW,WAAW,aAAa;EAE/D,MAAM,SAAS,MAAM,WAAW,WAAW;EAC3C,MAAM,SACL,eAAe,UACZ,uBAAuB,OAA+B,GACtD,sBAAsB,OAA8B;AAExD,MAAI,OAAO,WAAW,GAAG;AACxB,WAAQ,QAAQ,qCAAqC;AACrD;;AAGD,OAAK,MAAM,SAAS,OACnB,KAAI,MAAM,UAAU,QACnB,SAAQ,MAAM,MAAM,QAAQ;MAE5B,SAAQ,KAAK,MAAM,QAAQ;EAI7B,MAAM,SAAS,OAAO,QAAQ,MAAM,EAAE,UAAU,QAAQ;AACxD,MAAI,OAAO,SAAS,GAAG;AACtB,WAAQ,KAAK,0BAA0B,OAAO,OAAO,YAAY;AACjE,WAAQ,KAAK,EAAE;;AAGhB,UAAQ,QAAQ,mCAAmC;;CAEpD,CAAC"}
@@ -1,60 +0,0 @@
1
- import { n as detectType, t as loadConfig } from "./_lib-9AbI1LBo.js";
2
- import { defineCommand } from "citty";
3
- import { join } from "node:path";
4
- import { compilePolicy } from "@openpolicy/core";
5
- import consola from "consola";
6
- //#region src/commands/generate.ts
7
- const generateCommand = defineCommand({
8
- meta: {
9
- name: "generate",
10
- description: "Compile a policy config to one or more output formats"
11
- },
12
- args: {
13
- config: {
14
- type: "positional",
15
- description: "Path to policy config file",
16
- default: "./policy.config.ts"
17
- },
18
- format: {
19
- type: "string",
20
- description: "Comma-separated output formats: markdown,pdf,jsx",
21
- default: "markdown"
22
- },
23
- out: {
24
- type: "string",
25
- description: "Output directory",
26
- default: "./output"
27
- },
28
- type: {
29
- type: "string",
30
- description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
31
- default: ""
32
- }
33
- },
34
- async run({ args }) {
35
- const formats = (args.format ?? "markdown").split(",").map((f) => f.trim()).filter(Boolean);
36
- const outDir = args.out ?? "./output";
37
- const configPath = args.config ?? "./policy.config.ts";
38
- const policyType = detectType(args.type || void 0, configPath);
39
- consola.start(`Generating ${policyType} policy from ${configPath} → formats: ${formats.join(", ")}`);
40
- const config = await loadConfig(configPath);
41
- const outputFilename = policyType === "terms" ? "terms-of-service" : "privacy-policy";
42
- const results = compilePolicy(policyType === "terms" ? {
43
- type: "terms",
44
- ...config
45
- } : {
46
- type: "privacy",
47
- ...config
48
- }, { formats });
49
- for (const result of results) {
50
- const outPath = join(outDir, `${outputFilename}.${result.format === "markdown" ? "md" : result.format}`);
51
- await Bun.write(outPath, result.content);
52
- consola.success(`Written: ${outPath}`);
53
- }
54
- consola.success(`Policy generation complete → ${outDir}`);
55
- }
56
- });
57
- //#endregion
58
- export { generateCommand };
59
-
60
- //# sourceMappingURL=_lib-D2LkleUQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_lib-D2LkleUQ.js","names":[],"sources":["../src/commands/generate.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport type {\n\tOutputFormat,\n\tPrivacyPolicyConfig,\n\tTermsOfServiceConfig,\n} from \"@openpolicy/core\";\nimport { compilePolicy } from \"@openpolicy/core\";\nimport { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { detectType } from \"../utils/detect-type\";\nimport { loadConfig } from \"../utils/load-config\";\n\nexport const generateCommand = defineCommand({\n\tmeta: {\n\t\tname: \"generate\",\n\t\tdescription: \"Compile a policy config to one or more output formats\",\n\t},\n\targs: {\n\t\tconfig: {\n\t\t\ttype: \"positional\",\n\t\t\tdescription: \"Path to policy config file\",\n\t\t\tdefault: \"./policy.config.ts\",\n\t\t},\n\t\tformat: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Comma-separated output formats: markdown,pdf,jsx\",\n\t\t\tdefault: \"markdown\",\n\t\t},\n\t\tout: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Output directory\",\n\t\t\tdefault: \"./output\",\n\t\t},\n\t\ttype: {\n\t\t\ttype: \"string\",\n\t\t\tdescription:\n\t\t\t\t'Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)',\n\t\t\tdefault: \"\",\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst formats = (args.format ?? \"markdown\")\n\t\t\t.split(\",\")\n\t\t\t.map((f) => f.trim())\n\t\t\t.filter(Boolean) as OutputFormat[];\n\n\t\tconst outDir = args.out ?? \"./output\";\n\t\tconst configPath = args.config ?? \"./policy.config.ts\";\n\t\tconst policyType = detectType(args.type || undefined, configPath);\n\n\t\tconsola.start(\n\t\t\t`Generating ${policyType} policy from ${configPath} → formats: ${formats.join(\", \")}`,\n\t\t);\n\n\t\tconst config = await loadConfig(configPath);\n\n\t\tconst outputFilename =\n\t\t\tpolicyType === \"terms\" ? \"terms-of-service\" : \"privacy-policy\";\n\n\t\tconst results = compilePolicy(\n\t\t\tpolicyType === \"terms\"\n\t\t\t\t? { type: \"terms\", ...(config as TermsOfServiceConfig) }\n\t\t\t\t: { type: \"privacy\", ...(config as PrivacyPolicyConfig) },\n\t\t\t{ formats },\n\t\t);\n\n\t\tfor (const result of results) {\n\t\t\tconst ext = result.format === \"markdown\" ? \"md\" : result.format;\n\t\t\tconst outPath = join(outDir, `${outputFilename}.${ext}`);\n\t\t\tawait Bun.write(outPath, result.content);\n\t\t\tconsola.success(`Written: ${outPath}`);\n\t\t}\n\n\t\tconsola.success(`Policy generation complete → ${outDir}`);\n\t},\n});\n"],"mappings":";;;;;;AAYA,MAAa,kBAAkB,cAAc;CAC5C,MAAM;EACL,MAAM;EACN,aAAa;EACb;CACD,MAAM;EACL,QAAQ;GACP,MAAM;GACN,aAAa;GACb,SAAS;GACT;EACD,QAAQ;GACP,MAAM;GACN,aAAa;GACb,SAAS;GACT;EACD,KAAK;GACJ,MAAM;GACN,aAAa;GACb,SAAS;GACT;EACD,MAAM;GACL,MAAM;GACN,aACC;GACD,SAAS;GACT;EACD;CACD,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,WAAW,KAAK,UAAU,YAC9B,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;EAEjB,MAAM,SAAS,KAAK,OAAO;EAC3B,MAAM,aAAa,KAAK,UAAU;EAClC,MAAM,aAAa,WAAW,KAAK,QAAQ,KAAA,GAAW,WAAW;AAEjE,UAAQ,MACP,cAAc,WAAW,eAAe,WAAW,cAAc,QAAQ,KAAK,KAAK,GACnF;EAED,MAAM,SAAS,MAAM,WAAW,WAAW;EAE3C,MAAM,iBACL,eAAe,UAAU,qBAAqB;EAE/C,MAAM,UAAU,cACf,eAAe,UACZ;GAAE,MAAM;GAAS,GAAI;GAAiC,GACtD;GAAE,MAAM;GAAW,GAAI;GAAgC,EAC1D,EAAE,SAAS,CACX;AAED,OAAK,MAAM,UAAU,SAAS;GAE7B,MAAM,UAAU,KAAK,QAAQ,GAAG,eAAe,GADnC,OAAO,WAAW,aAAa,OAAO,OAAO,SACD;AACxD,SAAM,IAAI,MAAM,SAAS,OAAO,QAAQ;AACxC,WAAQ,QAAQ,YAAY,UAAU;;AAGvC,UAAQ,QAAQ,gCAAgC,SAAS;;CAE1D,CAAC"}
@@ -1,249 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import { resolve } from "node:path";
3
- import consola from "consola";
4
- //#region src/commands/init.ts
5
- const DATA_CATEGORY_MAP = {
6
- name: {
7
- group: "Personal Information",
8
- label: "Full name"
9
- },
10
- email: {
11
- group: "Personal Information",
12
- label: "Email address"
13
- },
14
- ip_address: {
15
- group: "Technical Data",
16
- label: "IP address"
17
- },
18
- device_info: {
19
- group: "Technical Data",
20
- label: "Device type and browser"
21
- },
22
- location: {
23
- group: "Location Data",
24
- label: "Approximate location"
25
- },
26
- payment_info: {
27
- group: "Financial Data",
28
- label: "Payment card details"
29
- },
30
- usage_data: {
31
- group: "Usage Data",
32
- label: "Pages visited and features used"
33
- }
34
- };
35
- function toJurisdictions(choice) {
36
- if (choice === "gdpr") return ["eu"];
37
- if (choice === "ccpa") return ["ca"];
38
- if (choice === "both") return ["eu", "ca"];
39
- return ["us"];
40
- }
41
- function toDataCollected(categories) {
42
- const groups = {};
43
- for (const cat of categories) {
44
- const mapping = DATA_CATEGORY_MAP[cat];
45
- if (!mapping) continue;
46
- groups[mapping.group] = [...groups[mapping.group] ?? [], mapping.label];
47
- }
48
- return Object.keys(groups).length > 0 ? groups : { "Personal Information": ["Email address"] };
49
- }
50
- function toUserRights(jurisdictions) {
51
- const rights = new Set(["access", "erasure"]);
52
- if (jurisdictions.includes("eu")) for (const r of [
53
- "rectification",
54
- "portability",
55
- "restriction",
56
- "objection"
57
- ]) rights.add(r);
58
- if (jurisdictions.includes("ca")) for (const r of ["opt_out_sale", "non_discrimination"]) rights.add(r);
59
- return Array.from(rights);
60
- }
61
- function renderPrivacyConfig(values) {
62
- const dataLines = Object.entries(values.dataCollected).map(([k, v]) => ` ${JSON.stringify(k)}: ${JSON.stringify(v)},`).join("\n");
63
- return `import { definePrivacyPolicy } from "@openpolicy/sdk";
64
-
65
- export default definePrivacyPolicy({
66
- effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
67
- company: {
68
- name: ${JSON.stringify(values.companyName)},
69
- legalName: ${JSON.stringify(values.legalName)},
70
- address: ${JSON.stringify(values.address)},
71
- contact: ${JSON.stringify(values.contact)},
72
- },
73
- dataCollected: {
74
- ${dataLines}
75
- },
76
- legalBasis: ${JSON.stringify(values.legalBasis)},
77
- retention: {
78
- "All personal data": "As long as necessary for the purposes described in this policy",
79
- },
80
- cookies: {
81
- essential: true,
82
- analytics: ${values.hasCookies},
83
- marketing: false,
84
- },
85
- thirdParties: [],
86
- userRights: ${JSON.stringify(values.userRights)},
87
- jurisdictions: ${JSON.stringify(values.jurisdictions)},
88
- });
89
- `;
90
- }
91
- function renderTermsConfig(values) {
92
- return `import { defineTermsOfService } from "@openpolicy/sdk";
93
-
94
- export default defineTermsOfService({
95
- effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
96
- company: {
97
- name: ${JSON.stringify(values.companyName)},
98
- legalName: ${JSON.stringify(values.legalName)},
99
- address: ${JSON.stringify(values.address)},
100
- contact: ${JSON.stringify(values.contact)},
101
- },
102
- acceptance: {
103
- methods: ["using the service", "creating an account"],
104
- },
105
- eligibility: {
106
- minimumAge: 13,
107
- },
108
- accounts: {
109
- registrationRequired: false,
110
- userResponsibleForCredentials: true,
111
- companyCanTerminate: true,
112
- },
113
- prohibitedUses: [
114
- "Violating any applicable laws or regulations",
115
- "Infringing on intellectual property rights",
116
- "Transmitting harmful or malicious content",
117
- ],
118
- intellectualProperty: {
119
- companyOwnsService: true,
120
- usersMayNotCopy: true,
121
- },
122
- termination: {
123
- companyCanTerminate: true,
124
- userCanTerminate: true,
125
- },
126
- disclaimers: {
127
- serviceProvidedAsIs: true,
128
- noWarranties: true,
129
- },
130
- limitationOfLiability: {
131
- excludesIndirectDamages: true,
132
- },
133
- governingLaw: {
134
- jurisdiction: ${JSON.stringify(values.jurisdiction)},
135
- },
136
- changesPolicy: {
137
- noticeMethod: "email or prominent notice on our website",
138
- noticePeriodDays: 30,
139
- },
140
- });
141
- `;
142
- }
143
- const initCommand = defineCommand({
144
- meta: {
145
- name: "init",
146
- description: "Interactively create a policy config file"
147
- },
148
- args: {
149
- out: {
150
- type: "string",
151
- description: "Output path for generated config",
152
- default: ""
153
- },
154
- yes: {
155
- type: "boolean",
156
- description: "Skip prompts and use defaults (CI mode)",
157
- default: false
158
- },
159
- type: {
160
- type: "string",
161
- description: "Policy type: \"privacy\" or \"terms\"",
162
- default: "privacy"
163
- }
164
- },
165
- async run({ args }) {
166
- const policyType = args.type === "terms" ? "terms" : "privacy";
167
- const defaultOut = policyType === "terms" ? "./terms.config.ts" : "./privacy.config.ts";
168
- consola.start(`OpenPolicy init wizard (${policyType})`);
169
- const companyName = String(await consola.prompt("Company name?", {
170
- type: "text",
171
- cancel: "reject"
172
- }));
173
- const legalName = String(await consola.prompt("Legal entity name?", {
174
- type: "text",
175
- cancel: "reject",
176
- initial: companyName
177
- }));
178
- const address = String(await consola.prompt("Company address?", {
179
- type: "text",
180
- cancel: "reject"
181
- }));
182
- const contact = String(await consola.prompt(policyType === "terms" ? "Legal contact email?" : "Privacy contact email?", {
183
- type: "text",
184
- cancel: "reject"
185
- }));
186
- let source;
187
- if (policyType === "terms") source = renderTermsConfig({
188
- companyName,
189
- legalName,
190
- address,
191
- contact,
192
- jurisdiction: String(await consola.prompt("Governing law jurisdiction? (e.g. Delaware, USA)", {
193
- type: "text",
194
- cancel: "reject",
195
- initial: "Delaware, USA"
196
- }))
197
- });
198
- else {
199
- const jurisdictionChoice = String(await consola.prompt("Jurisdiction?", {
200
- type: "select",
201
- cancel: "reject",
202
- options: [
203
- "gdpr",
204
- "ccpa",
205
- "both"
206
- ]
207
- }));
208
- const dataCategories = await consola.prompt("Data categories collected?", {
209
- type: "multiselect",
210
- cancel: "reject",
211
- options: [
212
- "name",
213
- "email",
214
- "ip_address",
215
- "device_info",
216
- "location",
217
- "payment_info",
218
- "usage_data"
219
- ]
220
- });
221
- const hasCookies = Boolean(await consola.prompt("Does your app use cookies?", {
222
- type: "confirm",
223
- cancel: "reject",
224
- initial: true
225
- }));
226
- const jurisdictions = toJurisdictions(jurisdictionChoice);
227
- const dataCollected = toDataCollected(dataCategories);
228
- const userRights = toUserRights(jurisdictions);
229
- source = renderPrivacyConfig({
230
- companyName,
231
- legalName,
232
- address,
233
- contact,
234
- jurisdictions,
235
- dataCollected,
236
- legalBasis: jurisdictions.includes("eu") ? "Legitimate interests and consent" : "",
237
- hasCookies,
238
- userRights
239
- });
240
- }
241
- const outPath = resolve(args.out || defaultOut);
242
- await Bun.write(outPath, source);
243
- consola.success(`Config written to ${outPath}`);
244
- }
245
- });
246
- //#endregion
247
- export { initCommand };
248
-
249
- //# sourceMappingURL=_lib-MI0GKJMR.js.map