agent-first-data 0.4.1 → 0.5.0

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,11 +63,11 @@ 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: **12 public APIs and 1 type** + **AFDATA logging** (3 protocol builders + 3 output functions + 1 internal + 1 utility + 4 CLI helpers + `OutputFormat`)
66
+ Total: **13 public APIs and 2 types** + **AFDATA logging** (3 protocol builders + 4 output functions + 1 internal + 1 utility + 4 CLI helpers + `OutputFormat` + `RedactionPolicy`)
67
67
 
68
68
  ### Protocol Builders (returns JsonValue)
69
69
 
70
- Build AFDATA protocol structures. Return JSON-serializable objects for API responses.
70
+ Build AFDATA protocol structures. Return JSON-serializable objects for transport payloads.
71
71
 
72
72
  ```typescript
73
73
  type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
@@ -82,7 +82,7 @@ buildJsonError(message: string, trace?: JsonValue): JsonValue
82
82
  buildJson(code: string, fields: JsonValue, trace?: JsonValue): JsonValue
83
83
  ```
84
84
 
85
- **Use case:** API responses (frameworks like Express automatically serialize)
85
+ **Use case:** structured protocol payloads (frameworks automatically serialize)
86
86
 
87
87
  **Example:**
88
88
  ```typescript
@@ -118,14 +118,22 @@ const notFound = buildJson(
118
118
 
119
119
  ### CLI/Log Output (returns string)
120
120
 
121
- Format values for CLI output and logs. **All formats redact `_secret` fields.** YAML and Plain also strip suffixes from keys and format values for human readability.
121
+ 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.
122
122
 
123
123
  ```typescript
124
124
  outputJson(value: JsonValue): string // Single-line JSON, original keys, for programs/logs
125
+ outputJsonWith(value: JsonValue, redactionPolicy: RedactionPolicy): string
125
126
  outputYaml(value: JsonValue): string // Multi-line YAML, keys stripped, values formatted
126
127
  outputPlain(value: JsonValue): string // Single-line logfmt, keys stripped, values formatted
127
128
  ```
128
129
 
130
+ ```typescript
131
+ enum RedactionPolicy {
132
+ RedactionTraceOnly = "RedactionTraceOnly",
133
+ RedactionNone = "RedactionNone",
134
+ }
135
+ ```
136
+
129
137
  **Example:**
130
138
  ```typescript
131
139
  import { outputJson, outputYaml, outputPlain } from "agent-first-data";
@@ -168,6 +176,8 @@ Most users don't need this. Output functions automatically protect secrets.
168
176
  parseSize(s: string): number | null // Parse "10M" → bytes
169
177
  ```
170
178
 
179
+ Returns `null` for invalid input and for values that cannot be represented as a safe JavaScript integer.
180
+
171
181
  **Example:**
172
182
  ```typescript
173
183
  import { parseSize } from "agent-first-data";
package/dist/format.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AFDATA output formatting and protocol templates.
3
3
  *
4
- * 8 public APIs: 3 protocol builders + 3 output formatters + 1 redaction + 1 utility.
4
+ * 9 public APIs and 1 type: 3 protocol builders + 4 output formatters + 1 redaction + 1 utility + RedactionPolicy.
5
5
  */
6
6
  export type JsonValue = string | number | boolean | null | JsonValue[] | {
7
7
  [key: string]: JsonValue;
@@ -12,8 +12,14 @@ export declare function buildJsonOk(result: JsonValue, trace?: JsonValue): JsonV
12
12
  export declare function buildJsonError(message: string, trace?: JsonValue): JsonValue;
13
13
  /** Build {code: "<custom>", ...fields, trace?}. */
14
14
  export declare function buildJson(code: string, fields: JsonValue, trace?: JsonValue): JsonValue;
15
+ export declare enum RedactionPolicy {
16
+ RedactionTraceOnly = "RedactionTraceOnly",
17
+ RedactionNone = "RedactionNone"
18
+ }
15
19
  /** Format as single-line JSON. Secrets redacted, original keys, raw values. */
16
20
  export declare function outputJson(value: JsonValue): string;
21
+ /** Format as single-line JSON with explicit redaction policy. */
22
+ export declare function outputJsonWith(value: JsonValue, redactionPolicy: RedactionPolicy): string;
17
23
  /** Format as multi-line YAML. Keys stripped, values formatted, secrets redacted. */
18
24
  export declare function outputYaml(value: JsonValue): string;
19
25
  /** Format as single-line logfmt. Keys stripped, values formatted, secrets redacted. */
package/dist/format.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AFDATA output formatting and protocol templates.
3
3
  *
4
- * 8 public APIs: 3 protocol builders + 3 output formatters + 1 redaction + 1 utility.
4
+ * 9 public APIs and 1 type: 3 protocol builders + 4 output formatters + 1 redaction + 1 utility + RedactionPolicy.
5
5
  */
6
6
  // ═══════════════════════════════════════════
7
7
  // Public API: Protocol Builders
@@ -31,20 +31,33 @@ export function buildJson(code, fields, trace) {
31
31
  // ═══════════════════════════════════════════
32
32
  // Public API: Output Formatters
33
33
  // ═══════════════════════════════════════════
34
+ export var RedactionPolicy;
35
+ (function (RedactionPolicy) {
36
+ RedactionPolicy["RedactionTraceOnly"] = "RedactionTraceOnly";
37
+ RedactionPolicy["RedactionNone"] = "RedactionNone";
38
+ })(RedactionPolicy || (RedactionPolicy = {}));
34
39
  /** Format as single-line JSON. Secrets redacted, original keys, raw values. */
35
40
  export function outputJson(value) {
36
- const v = JSON.parse(JSON.stringify(value));
41
+ const v = sanitizeForJson(value);
37
42
  redactSecrets(v);
38
43
  return JSON.stringify(v);
39
44
  }
45
+ /** Format as single-line JSON with explicit redaction policy. */
46
+ export function outputJsonWith(value, redactionPolicy) {
47
+ const v = sanitizeForJson(value);
48
+ applyRedactionPolicy(v, redactionPolicy);
49
+ return JSON.stringify(v);
50
+ }
40
51
  /** Format as multi-line YAML. Keys stripped, values formatted, secrets redacted. */
41
52
  export function outputYaml(value) {
53
+ value = sanitizeForJson(value);
42
54
  const lines = ["---"];
43
55
  renderYamlProcessed(value, 0, lines);
44
56
  return lines.join("\n");
45
57
  }
46
58
  /** Format as single-line logfmt. Keys stripped, values formatted, secrets redacted. */
47
59
  export function outputPlain(value) {
60
+ value = sanitizeForJson(value);
48
61
  const pairs = [];
49
62
  collectPlainPairs(value, "", pairs);
50
63
  pairs.sort(([a], [b]) => jcsCompare(a, b));
@@ -90,7 +103,10 @@ export function parseSize(s) {
90
103
  const n = Number(numStr);
91
104
  if (isNaN(n) || n < 0 || !isFinite(n))
92
105
  return null;
93
- return Math.trunc(n * mult);
106
+ const result = Math.trunc(n * mult);
107
+ if (!Number.isSafeInteger(result))
108
+ return null;
109
+ return result;
94
110
  }
95
111
  // ═══════════════════════════════════════════
96
112
  // Secret Redaction
@@ -118,6 +134,21 @@ function redactSecrets(value) {
118
134
  }
119
135
  }
120
136
  }
137
+ function applyRedactionPolicy(value, redactionPolicy) {
138
+ switch (redactionPolicy) {
139
+ case RedactionPolicy.RedactionTraceOnly:
140
+ if (isObject(value) && value.trace !== undefined) {
141
+ redactSecrets(value.trace);
142
+ }
143
+ break;
144
+ case RedactionPolicy.RedactionNone:
145
+ break;
146
+ default:
147
+ // Safety fallback for unknown values.
148
+ redactSecrets(value);
149
+ break;
150
+ }
151
+ }
121
152
  // ═══════════════════════════════════════════
122
153
  // Suffix Processing
123
154
  // ═══════════════════════════════════════════
@@ -473,6 +504,52 @@ function plainScalar(value) {
473
504
  // ═══════════════════════════════════════════
474
505
  // Utilities
475
506
  // ═══════════════════════════════════════════
507
+ function sanitizeForJson(value, stack = new WeakSet()) {
508
+ if (value === null)
509
+ return null;
510
+ const t = typeof value;
511
+ if (t === "string")
512
+ return value;
513
+ if (t === "boolean")
514
+ return value;
515
+ if (t === "number") {
516
+ const n = value;
517
+ return Number.isFinite(n) ? n : "<unsupported:number>";
518
+ }
519
+ if (t === "bigint")
520
+ return "<unsupported:bigint>";
521
+ if (t === "undefined")
522
+ return "<unsupported:undefined>";
523
+ if (t === "function")
524
+ return "<unsupported:function>";
525
+ if (t === "symbol")
526
+ return "<unsupported:symbol>";
527
+ if (value instanceof Error)
528
+ return value.message;
529
+ if (value instanceof Date)
530
+ return value.toISOString();
531
+ if (Array.isArray(value)) {
532
+ if (stack.has(value))
533
+ return "<unsupported:circular>";
534
+ stack.add(value);
535
+ const out = value.map((item) => sanitizeForJson(item, stack));
536
+ stack.delete(value);
537
+ return out;
538
+ }
539
+ if (typeof value === "object") {
540
+ const obj = value;
541
+ if (stack.has(obj))
542
+ return "<unsupported:circular>";
543
+ stack.add(obj);
544
+ const out = {};
545
+ for (const [k, v] of Object.entries(obj)) {
546
+ out[k] = sanitizeForJson(v, stack);
547
+ }
548
+ stack.delete(obj);
549
+ return out;
550
+ }
551
+ return "<unsupported:unknown>";
552
+ }
476
553
  function isObject(value) {
477
554
  return typeof value === "object" && value !== null && !Array.isArray(value);
478
555
  }
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, outputJson, outputYaml, outputPlain, internalRedactSecrets, parseSize } from "./format.js";
4
+ export { buildJsonOk, buildJsonError, buildJson, RedactionPolicy, outputJson, outputJsonWith, outputYaml, outputPlain, internalRedactSecrets, 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, outputJson, outputYaml, outputPlain, internalRedactSecrets, parseSize } from "./format.js";
4
+ export { buildJsonOk, buildJsonError, buildJson, RedactionPolicy, outputJson, outputJsonWith, outputYaml, outputPlain, internalRedactSecrets, 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,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Agent-First Data (AFDATA) — suffix-driven output formatting and protocol templates for AI agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,10 +26,11 @@
26
26
  ],
27
27
  "scripts": {
28
28
  "build": "tsc",
29
- "test": "node --test src/*.test.ts --experimental-strip-types"
29
+ "test": "tsx --test src/*.test.ts"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^25.2.3",
33
+ "tsx": "^4.20.6",
33
34
  "typescript": "^5.0"
34
35
  }
35
36
  }