agent-first-data 0.8.0 → 0.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.
package/README.md CHANGED
@@ -63,7 +63,7 @@ Plain: args.input_path=/data/backup.tar.gz code=log event=startup config.max_fil
63
63
 
64
64
  ## API Reference
65
65
 
66
- Total: **15 public APIs and 2 types** + **AFDATA logging** (3 protocol builders + 2 redacted value helpers + 4 output functions + 1 internal + 1 utility + 4 CLI helpers + `OutputFormat` + `RedactionPolicy`)
66
+ Public APIs are grouped by role: protocol builders, redaction helpers, output formatters, internal redaction tools, utility/CLI helpers, types, and AFDATA logging integration.
67
67
 
68
68
  ### Protocol Builders (returns JsonValue)
69
69
 
@@ -82,13 +82,14 @@ buildJsonError(message: string, hint?: string, trace?: JsonValue): JsonValue
82
82
  buildJson(code: string, fields: JsonValue, trace?: JsonValue): JsonValue
83
83
  ```
84
84
 
85
- ### Redacted Values (returns JsonValue)
85
+ ### Redaction Helpers (returns JsonValue)
86
86
 
87
87
  Use these before raw HTTP/MCP/SSE serializers that do not call `outputJson`.
88
88
 
89
89
  ```typescript
90
90
  redactedValue(value: unknown): JsonValue
91
91
  redactedValueWith(value: unknown, redactionPolicy: RedactionPolicy): JsonValue
92
+ redactedValueWithOptions(value: unknown, redactionOptions: RedactionOptions): JsonValue
92
93
  ```
93
94
 
94
95
  **Use case:** structured protocol payloads (frameworks automatically serialize)
@@ -128,15 +129,18 @@ const notFound = buildJson(
128
129
  );
129
130
  ```
130
131
 
131
- ### CLI/Log Output (returns string)
132
+ ### Output Formatters (returns string)
132
133
 
133
- Format values for CLI output and logs. `outputJson` uses full `_secret` redaction by default. `outputJsonWith` supports explicit scoped policies. YAML and Plain always redact `_secret` and apply human-readable formatting.
134
+ Format values for CLI output and logs. `outputJson` uses full `_secret` redaction by default. `outputJsonWith` supports explicit scoped policies. Use the `*WithOptions` functions to pass legacy secret names such as `api_key`. YAML and Plain always redact secrets and apply human-readable formatting.
134
135
 
135
136
  ```typescript
136
137
  outputJson(value: JsonValue): string // Single-line JSON, original keys, for programs/logs
137
138
  outputJsonWith(value: JsonValue, redactionPolicy: RedactionPolicy): string
139
+ outputJsonWithOptions(value: JsonValue, redactionOptions: RedactionOptions): string
138
140
  outputYaml(value: JsonValue): string // Multi-line YAML, keys stripped, values formatted
141
+ outputYamlWithOptions(value: JsonValue, redactionOptions: RedactionOptions): string
139
142
  outputPlain(value: JsonValue): string // Single-line logfmt, keys stripped, values formatted
143
+ outputPlainWithOptions(value: JsonValue, redactionOptions: RedactionOptions): string
140
144
  ```
141
145
 
142
146
  ```typescript
@@ -145,8 +149,15 @@ enum RedactionPolicy {
145
149
  RedactionNone = "RedactionNone",
146
150
  RedactionStrict = "RedactionStrict",
147
151
  }
152
+
153
+ type RedactionOptions = {
154
+ policy?: RedactionPolicy;
155
+ secretNames?: readonly string[]; // legacy names like "api_key" or "authorization"
156
+ }
148
157
  ```
149
158
 
159
+ Secret names match exact field names at any nesting level; there is no trim, case folding, hyphen/underscore normalization, glob, regex, or substring matching. They do not change YAML/Plain suffix stripping.
160
+
150
161
  **Example:**
151
162
  ```typescript
152
163
  import { outputJson, outputYaml, outputPlain } from "agent-first-data";
@@ -179,6 +190,7 @@ console.log(outputPlain(data));
179
190
 
180
191
  ```typescript
181
192
  internalRedactSecrets(value: JsonValue): void // Manually redact secrets in-place
193
+ internalRedactSecretsWithOptions(value: JsonValue, redactionOptions: RedactionOptions): void
182
194
  ```
183
195
 
184
196
  Most users don't need this. Output functions automatically protect secrets.
package/dist/format.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * AFDATA output formatting and protocol templates.
3
3
  *
4
- * 11 public APIs and 1 type: protocol builders, redacted value helpers,
5
- * output formatters, redaction, parseSize, and RedactionPolicy.
4
+ * 16 public APIs and 2 types: protocol builders, redacted value helpers,
5
+ * output formatters, redaction, parseSize, RedactionPolicy, and RedactionOptions.
6
6
  */
7
7
  export type JsonValue = string | number | boolean | null | JsonValue[] | {
8
8
  [key: string]: JsonValue;
@@ -18,20 +18,39 @@ export declare enum RedactionPolicy {
18
18
  RedactionNone = "RedactionNone",
19
19
  RedactionStrict = "RedactionStrict"
20
20
  }
21
+ export type RedactionOptions = {
22
+ /** Optional scoped policy. Omitted means default full redaction. */
23
+ policy?: RedactionPolicy;
24
+ /**
25
+ * Field names to treat as secrets in addition to _secret suffixes.
26
+ * Matching is exact field-name equality at any nesting level.
27
+ */
28
+ secretNames?: readonly string[];
29
+ };
21
30
  /** Format as single-line JSON. Secrets redacted, original keys, raw values. */
22
31
  export declare function outputJson(value: JsonValue): string;
23
32
  /** Format as single-line JSON with explicit redaction policy. */
24
33
  export declare function outputJsonWith(value: JsonValue, redactionPolicy: RedactionPolicy): string;
34
+ /** Format as single-line JSON with explicit redaction options. */
35
+ export declare function outputJsonWithOptions(value: JsonValue, redactionOptions: RedactionOptions): string;
25
36
  /** Format as multi-line YAML. Keys stripped, values formatted, secrets redacted. */
26
37
  export declare function outputYaml(value: JsonValue): string;
38
+ /** Format as multi-line YAML with explicit redaction options. */
39
+ export declare function outputYamlWithOptions(value: JsonValue, redactionOptions: RedactionOptions): string;
27
40
  /** Format as single-line logfmt. Keys stripped, values formatted, secrets redacted. */
28
41
  export declare function outputPlain(value: JsonValue): string;
42
+ /** Format as single-line logfmt with explicit redaction options. */
43
+ export declare function outputPlainWithOptions(value: JsonValue, redactionOptions: RedactionOptions): string;
29
44
  /** Redact _secret fields in-place. */
30
45
  export declare function internalRedactSecrets(value: JsonValue): void;
46
+ /** Redact secret fields in-place using explicit redaction options. */
47
+ export declare function internalRedactSecretsWithOptions(value: JsonValue, redactionOptions: RedactionOptions): void;
31
48
  /** Return a JSON-safe copy with default _secret redaction applied. */
32
49
  export declare function redactedValue(value: unknown): JsonValue;
33
50
  /** Return a JSON-safe copy with an explicit redaction policy applied. */
34
51
  export declare function redactedValueWith(value: unknown, redactionPolicy: RedactionPolicy): JsonValue;
52
+ /** Return a JSON-safe copy with explicit redaction options applied. */
53
+ export declare function redactedValueWithOptions(value: unknown, redactionOptions: RedactionOptions): JsonValue;
35
54
  /**
36
55
  * Parse a human-readable size string into bytes.
37
56
  * Accepts bare numbers or numbers followed by a unit letter (B/K/M/G/T).
package/dist/format.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * AFDATA output formatting and protocol templates.
3
3
  *
4
- * 11 public APIs and 1 type: protocol builders, redacted value helpers,
5
- * output formatters, redaction, parseSize, and RedactionPolicy.
4
+ * 16 public APIs and 2 types: protocol builders, redacted value helpers,
5
+ * output formatters, redaction, parseSize, RedactionPolicy, and RedactionOptions.
6
6
  */
7
7
  // ═══════════════════════════════════════════
8
8
  // Public API: Protocol Builders
@@ -48,6 +48,10 @@ export function outputJson(value) {
48
48
  export function outputJsonWith(value, redactionPolicy) {
49
49
  return JSON.stringify(redactedValueWith(value, redactionPolicy));
50
50
  }
51
+ /** Format as single-line JSON with explicit redaction options. */
52
+ export function outputJsonWithOptions(value, redactionOptions) {
53
+ return JSON.stringify(redactedValueWithOptions(value, redactionOptions));
54
+ }
51
55
  /** Format as multi-line YAML. Keys stripped, values formatted, secrets redacted. */
52
56
  export function outputYaml(value) {
53
57
  value = redactedValue(value);
@@ -55,6 +59,13 @@ export function outputYaml(value) {
55
59
  renderYamlProcessed(value, 0, lines);
56
60
  return lines.join("\n");
57
61
  }
62
+ /** Format as multi-line YAML with explicit redaction options. */
63
+ export function outputYamlWithOptions(value, redactionOptions) {
64
+ value = redactedValueWithOptions(value, redactionOptions);
65
+ const lines = ["---"];
66
+ renderYamlProcessed(value, 0, lines);
67
+ return lines.join("\n");
68
+ }
58
69
  /** Format as single-line logfmt. Keys stripped, values formatted, secrets redacted. */
59
70
  export function outputPlain(value) {
60
71
  value = redactedValue(value);
@@ -65,6 +76,16 @@ export function outputPlain(value) {
65
76
  .map(([k, v]) => `${k}=${quoteLogfmtValue(v)}`)
66
77
  .join(" ");
67
78
  }
79
+ /** Format as single-line logfmt with explicit redaction options. */
80
+ export function outputPlainWithOptions(value, redactionOptions) {
81
+ value = redactedValueWithOptions(value, redactionOptions);
82
+ const pairs = [];
83
+ collectPlainPairs(value, "", pairs);
84
+ pairs.sort(([a], [b]) => jcsCompare(a, b));
85
+ return pairs
86
+ .map(([k, v]) => `${k}=${quoteLogfmtValue(v)}`)
87
+ .join(" ");
88
+ }
68
89
  // ═══════════════════════════════════════════
69
90
  // Public API: Redaction & Utility
70
91
  // ═══════════════════════════════════════════
@@ -72,6 +93,10 @@ export function outputPlain(value) {
72
93
  export function internalRedactSecrets(value) {
73
94
  redactSecrets(value);
74
95
  }
96
+ /** Redact secret fields in-place using explicit redaction options. */
97
+ export function internalRedactSecretsWithOptions(value, redactionOptions) {
98
+ applyRedactionOptions(value, redactionOptions);
99
+ }
75
100
  /** Return a JSON-safe copy with default _secret redaction applied. */
76
101
  export function redactedValue(value) {
77
102
  const v = sanitizeForJson(value);
@@ -84,6 +109,12 @@ export function redactedValueWith(value, redactionPolicy) {
84
109
  applyRedactionPolicy(v, redactionPolicy);
85
110
  return v;
86
111
  }
112
+ /** Return a JSON-safe copy with explicit redaction options applied. */
113
+ export function redactedValueWithOptions(value, redactionOptions) {
114
+ const v = sanitizeForJson(value);
115
+ applyRedactionOptions(v, redactionOptions);
116
+ return v;
117
+ }
87
118
  /**
88
119
  * Parse a human-readable size string into bytes.
89
120
  * Accepts bare numbers or numbers followed by a unit letter (B/K/M/G/T).
@@ -123,61 +154,77 @@ export function parseSize(s) {
123
154
  // ═══════════════════════════════════════════
124
155
  // Secret Redaction
125
156
  // ═══════════════════════════════════════════
126
- function redactSecrets(value) {
157
+ const EMPTY_SECRET_NAMES = new Set();
158
+ function secretNameSet(redactionOptions) {
159
+ return new Set(redactionOptions.secretNames ?? []);
160
+ }
161
+ function keyHasSecretSuffix(key) {
162
+ return key.endsWith("_secret") || key.endsWith("_SECRET");
163
+ }
164
+ function isSecretKey(key, secretNames) {
165
+ return keyHasSecretSuffix(key) || secretNames.has(key);
166
+ }
167
+ function redactSecrets(value, secretNames = EMPTY_SECRET_NAMES) {
127
168
  if (isObject(value)) {
128
169
  for (const k of Object.keys(value)) {
129
- if (k.endsWith("_secret") || k.endsWith("_SECRET")) {
170
+ if (isSecretKey(k, secretNames)) {
130
171
  const v = value[k];
131
172
  if (isObject(v) || Array.isArray(v)) {
132
- redactSecrets(v);
173
+ redactSecrets(v, secretNames);
133
174
  }
134
175
  else {
135
176
  value[k] = "***";
136
177
  }
137
178
  }
138
179
  else {
139
- redactSecrets(value[k]);
180
+ redactSecrets(value[k], secretNames);
140
181
  }
141
182
  }
142
183
  }
143
184
  else if (Array.isArray(value)) {
144
185
  for (const item of value) {
145
- redactSecrets(item);
186
+ redactSecrets(item, secretNames);
146
187
  }
147
188
  }
148
189
  }
149
- function redactSecretsStrict(value) {
190
+ function redactSecretsStrict(value, secretNames = EMPTY_SECRET_NAMES) {
150
191
  if (isObject(value)) {
151
192
  for (const k of Object.keys(value)) {
152
- if (k.endsWith("_secret") || k.endsWith("_SECRET")) {
193
+ if (isSecretKey(k, secretNames)) {
153
194
  value[k] = "***";
154
195
  }
155
196
  else {
156
- redactSecretsStrict(value[k]);
197
+ redactSecretsStrict(value[k], secretNames);
157
198
  }
158
199
  }
159
200
  }
160
201
  else if (Array.isArray(value)) {
161
202
  for (const item of value) {
162
- redactSecretsStrict(item);
203
+ redactSecretsStrict(item, secretNames);
163
204
  }
164
205
  }
165
206
  }
166
207
  function applyRedactionPolicy(value, redactionPolicy) {
208
+ applyRedactionPolicyWithNames(value, redactionPolicy, EMPTY_SECRET_NAMES);
209
+ }
210
+ function applyRedactionOptions(value, redactionOptions) {
211
+ applyRedactionPolicyWithNames(value, redactionOptions.policy, secretNameSet(redactionOptions));
212
+ }
213
+ function applyRedactionPolicyWithNames(value, redactionPolicy, secretNames) {
167
214
  switch (redactionPolicy) {
168
215
  case RedactionPolicy.RedactionTraceOnly:
169
216
  if (isObject(value) && value.trace !== undefined) {
170
- redactSecrets(value.trace);
217
+ redactSecrets(value.trace, secretNames);
171
218
  }
172
219
  break;
173
220
  case RedactionPolicy.RedactionNone:
174
221
  break;
175
222
  case RedactionPolicy.RedactionStrict:
176
- redactSecretsStrict(value);
223
+ redactSecretsStrict(value, secretNames);
177
224
  break;
178
225
  default:
179
- // Safety fallback for unknown values.
180
- redactSecrets(value);
226
+ // Empty/unknown policy falls back to default full redaction.
227
+ redactSecrets(value, secretNames);
181
228
  break;
182
229
  }
183
230
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates.
3
3
  */
4
- export { buildJsonOk, buildJsonError, buildJson, RedactionPolicy, outputJson, outputJsonWith, outputYaml, outputPlain, internalRedactSecrets, redactedValue, redactedValueWith, parseSize, } from "./format.js";
4
+ export { buildJsonOk, buildJsonError, buildJson, RedactionPolicy, type RedactionOptions, outputJson, outputJsonWith, outputJsonWithOptions, outputYaml, outputYamlWithOptions, outputPlain, outputPlainWithOptions, internalRedactSecrets, internalRedactSecretsWithOptions, redactedValue, redactedValueWith, redactedValueWithOptions, parseSize, } from "./format.js";
5
5
  export { log, span, initJson, initPlain, initYaml } from "./afdata_logging.js";
6
6
  export { type OutputFormat, cliParseOutput, cliParseLogFilters, cliOutput, buildCliError } from "./cli.js";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates.
3
3
  */
4
- export { buildJsonOk, buildJsonError, buildJson, RedactionPolicy, outputJson, outputJsonWith, outputYaml, outputPlain, internalRedactSecrets, redactedValue, redactedValueWith, parseSize, } from "./format.js";
4
+ export { buildJsonOk, buildJsonError, buildJson, RedactionPolicy, outputJson, outputJsonWith, outputJsonWithOptions, outputYaml, outputYamlWithOptions, outputPlain, outputPlainWithOptions, internalRedactSecrets, internalRedactSecretsWithOptions, redactedValue, redactedValueWith, redactedValueWithOptions, parseSize, } from "./format.js";
5
5
  export { log, span, initJson, initPlain, initYaml } from "./afdata_logging.js";
6
6
  export { cliParseOutput, cliParseLogFilters, cliOutput, buildCliError } from "./cli.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.8.0",
4
- "description": "Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates for AI agents",
3
+ "version": "0.8.1",
4
+ "description": "A naming convention that lets AI agents understand your data without being told what it means.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",