@chriscode/hush 2.7.2 → 2.8.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAc,WAAW,EAAU,MAAM,aAAa,CAAC;AAyJnE,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoErE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAc,WAAW,EAAU,MAAM,aAAa,CAAC;AAyJnE,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAsErE"}
@@ -164,13 +164,15 @@ export async function initCommand(options) {
164
164
  }
165
165
  const targets = detectTargets(root);
166
166
  const config = {
167
+ version: 2,
167
168
  sources: DEFAULT_SOURCES,
168
169
  targets,
169
170
  ...(project && { project }),
170
171
  };
171
172
  const yaml = stringifyYaml(config, { indent: 2 });
173
+ const schemaComment = '# yaml-language-server: $schema=https://unpkg.com/@chriscode/hush/schema.json\n';
172
174
  const configPath = join(root, 'hush.yaml');
173
- writeFileSync(configPath, yaml, 'utf-8');
175
+ writeFileSync(configPath, schemaComment + yaml, 'utf-8');
174
176
  console.log(pc.green(`\nCreated ${configPath}`));
175
177
  console.log(pc.dim('\nDetected targets:'));
176
178
  for (const target of targets) {
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ1D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAmBnD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAO5G;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAuB3D"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ1D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAmBnD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAO5G;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CA8B3D"}
@@ -39,21 +39,27 @@ export function checkSchemaVersion(config) {
39
39
  }
40
40
  export function validateConfig(config) {
41
41
  const errors = [];
42
+ const validFormats = ['dotenv', 'wrangler', 'json', 'shell', 'yaml'];
42
43
  if (!config.sources.shared) {
43
44
  errors.push('sources.shared is required');
44
45
  }
45
- for (const target of config.targets) {
46
+ if (!config.targets || config.targets.length === 0) {
47
+ errors.push('At least one target is required');
48
+ }
49
+ for (let i = 0; i < config.targets.length; i++) {
50
+ const target = config.targets[i];
51
+ const prefix = target.name ? `Target "${target.name}"` : `Target at index ${i}`;
46
52
  if (!target.name) {
47
- errors.push('Each target must have a name');
53
+ errors.push(`${prefix}: missing required field "name"`);
48
54
  }
49
55
  if (!target.path) {
50
- errors.push(`Target "${target.name}" must have a path`);
56
+ errors.push(`${prefix}: missing required field "path" (e.g., "." or "./apps/web")`);
51
57
  }
52
58
  if (!target.format) {
53
- errors.push(`Target "${target.name}" must have a format`);
59
+ errors.push(`${prefix}: missing required field "format" (one of: ${validFormats.join(', ')})`);
54
60
  }
55
- if (!['dotenv', 'wrangler', 'json', 'shell', 'yaml'].includes(target.format)) {
56
- errors.push(`Target "${target.name}" has invalid format "${target.format}"`);
61
+ else if (!validFormats.includes(target.format)) {
62
+ errors.push(`${prefix}: invalid format "${target.format}" (must be one of: ${validFormats.join(', ')})`);
57
63
  }
58
64
  }
59
65
  return errors;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chriscode/hush",
3
- "version": "2.7.2",
3
+ "version": "2.8.1",
4
4
  "description": "SOPS-based secrets management for monorepos. Encrypt once, decrypt everywhere.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,7 +57,8 @@
57
57
  },
58
58
  "files": [
59
59
  "dist",
60
- "bin"
60
+ "bin",
61
+ "schema.json"
61
62
  ],
62
63
  "publishConfig": {
63
64
  "access": "public"
package/schema.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://hush-docs.pages.dev/schema.json",
4
+ "title": "Hush Configuration",
5
+ "description": "Configuration file for Hush secrets management",
6
+ "type": "object",
7
+ "properties": {
8
+ "version": {
9
+ "type": "integer",
10
+ "description": "Schema version (current: 2)",
11
+ "minimum": 1,
12
+ "maximum": 2,
13
+ "default": 2
14
+ },
15
+ "project": {
16
+ "type": "string",
17
+ "description": "Project identifier for key management (e.g., 'my-org/my-repo')",
18
+ "pattern": "^[a-zA-Z0-9_-]+(/[a-zA-Z0-9_-]+)?$"
19
+ },
20
+ "sources": {
21
+ "type": "object",
22
+ "description": "Source .env files (plaintext, before encryption)",
23
+ "properties": {
24
+ "shared": {
25
+ "type": "string",
26
+ "description": "Shared secrets file (default: .env)",
27
+ "default": ".env"
28
+ },
29
+ "development": {
30
+ "type": "string",
31
+ "description": "Development secrets file (default: .env.development)",
32
+ "default": ".env.development"
33
+ },
34
+ "production": {
35
+ "type": "string",
36
+ "description": "Production secrets file (default: .env.production)",
37
+ "default": ".env.production"
38
+ },
39
+ "local": {
40
+ "type": "string",
41
+ "description": "Local overrides file (default: .env.local)",
42
+ "default": ".env.local"
43
+ }
44
+ },
45
+ "additionalProperties": false
46
+ },
47
+ "targets": {
48
+ "type": "array",
49
+ "description": "Output targets for decrypted secrets",
50
+ "items": {
51
+ "type": "object",
52
+ "required": ["name", "path", "format"],
53
+ "properties": {
54
+ "name": {
55
+ "type": "string",
56
+ "description": "Target identifier"
57
+ },
58
+ "path": {
59
+ "type": "string",
60
+ "description": "Directory path for output file"
61
+ },
62
+ "format": {
63
+ "type": "string",
64
+ "description": "Output format",
65
+ "enum": ["dotenv", "wrangler", "json", "shell", "yaml"]
66
+ },
67
+ "include": {
68
+ "type": "array",
69
+ "description": "Glob patterns to include (e.g., NEXT_PUBLIC_*)",
70
+ "items": { "type": "string" }
71
+ },
72
+ "exclude": {
73
+ "type": "array",
74
+ "description": "Glob patterns to exclude",
75
+ "items": { "type": "string" }
76
+ }
77
+ },
78
+ "additionalProperties": false
79
+ },
80
+ "minItems": 1
81
+ }
82
+ },
83
+ "required": ["targets"],
84
+ "additionalProperties": false
85
+ }