agent-first-data 0.2.0 → 0.2.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
@@ -12,7 +12,7 @@ npm install agent-first-data
12
12
 
13
13
  ## API Reference
14
14
 
15
- Total: **9 public APIs** (4 protocol builders + 3 output functions + 1 internal + 1 utility)
15
+ Total: **9 public APIs** + **AFD logging** (4 protocol builders + 3 output functions + 1 internal + 1 utility)
16
16
 
17
17
  ### Protocol Builders (returns JsonValue)
18
18
 
@@ -249,6 +249,115 @@ console.log(outputPlain(data));
249
249
  // api_key=*** cache_ttl=3600s count=42 created_at=2025-02-07T00:00:00.000Z file_size=5.0MB payment=50000000msats price=$99.99 request_timeout=5.0s success_rate=95.5% user_name=alice
250
250
  ```
251
251
 
252
+ ## AFD Logging
253
+
254
+ AFD-compliant structured logging. Every log line is formatted using the library's own `outputJson`/`outputPlain`/`outputYaml` functions. Span fields are carried via `AsyncLocalStorage` (async-safe), automatically flattened into each log line. Zero dependencies beyond Node.js built-ins.
255
+
256
+ ### API
257
+
258
+ ```typescript
259
+ import { log, span, initJson, initPlain, initYaml } from "agent-first-data";
260
+
261
+ // Format selectors — set the output format for all subsequent log calls
262
+ initJson() // Single-line JSONL (secrets redacted, original keys) — default
263
+ initPlain() // Single-line logfmt (keys stripped, values formatted)
264
+ initYaml() // Multi-line YAML (keys stripped, values formatted)
265
+
266
+ // Logger — each method outputs a single log line to stdout
267
+ log.trace(msg, fields?)
268
+ log.debug(msg, fields?)
269
+ log.info(msg, fields?)
270
+ log.warn(msg, fields?)
271
+ log.error(msg, fields?)
272
+
273
+ // Span — run fn with additional fields on all log events
274
+ span<T>(fields, fn: () => T): T // works with sync and async functions
275
+ ```
276
+
277
+ ### Setup
278
+
279
+ ```typescript
280
+ import { log, initJson, initPlain, initYaml } from "agent-first-data";
281
+
282
+ // JSON output for production (one JSONL line per event, secrets redacted)
283
+ initJson(); // default, can be omitted
284
+
285
+ // Plain logfmt for development (keys stripped, values formatted)
286
+ initPlain();
287
+
288
+ // YAML for detailed inspection (multi-line, keys stripped, values formatted)
289
+ initYaml();
290
+ ```
291
+
292
+ ### Log Output
293
+
294
+ Output format depends on the init function used.
295
+
296
+ ```typescript
297
+ log.info("Server started");
298
+ // JSON: {"timestamp_epoch_ms":1739000000000,"message":"Server started","code":"info"}
299
+ // Plain: code=info message="Server started" timestamp_epoch_ms=1739000000000
300
+ // YAML: ---
301
+ // code: "info"
302
+ // message: "Server started"
303
+ // timestamp_epoch_ms: 1739000000000
304
+
305
+ log.warn("DNS lookup failed", { error: "timeout", domain: "example.com" });
306
+ // JSON: {"timestamp_epoch_ms":...,"message":"DNS lookup failed","error":"timeout","domain":"example.com","code":"warn"}
307
+ // Plain: code=warn domain=example.com error=timeout message="DNS lookup failed" ...
308
+ ```
309
+
310
+ ### Span Support
311
+
312
+ Use `span()` to add fields to all log events within the callback. Spans nest and work with both sync and async functions.
313
+
314
+ ```typescript
315
+ import { log, span } from "agent-first-data";
316
+
317
+ await span({ request_id: "abc-123" }, async () => {
318
+ log.info("Processing");
319
+ // {"timestamp_epoch_ms":...,"message":"Processing","request_id":"abc-123","code":"info"}
320
+
321
+ await span({ step: "validate" }, async () => {
322
+ log.info("Validating input");
323
+ // {"timestamp_epoch_ms":...,"message":"Validating input","request_id":"abc-123","step":"validate","code":"info"}
324
+ });
325
+ });
326
+ ```
327
+
328
+ ### Custom Code Override
329
+
330
+ The `code` field defaults to the log level. Override with an explicit field:
331
+
332
+ ```typescript
333
+ log.info("Server ready", { code: "startup" });
334
+ // {"timestamp_epoch_ms":...,"message":"Server ready","code":"startup"}
335
+ ```
336
+
337
+ ### Output Fields
338
+
339
+ Every log line contains:
340
+
341
+ | Field | Type | Description |
342
+ |:------|:-----|:------------|
343
+ | `timestamp_epoch_ms` | number | Unix milliseconds |
344
+ | `message` | string | Log message |
345
+ | `code` | string | Level (trace/debug/info/warn/error) or explicit override |
346
+ | *span fields* | any | From `span()` callback |
347
+ | *event fields* | any | From fields argument |
348
+
349
+ ### Log Output Formats
350
+
351
+ All three formats use the library's own output functions, so AFD suffix processing applies to log fields too:
352
+
353
+ | Format | Function | Keys | Values | Use case |
354
+ |:-------|:---------|:-----|:-------|:---------|
355
+ | **JSON** | `initJson` | original (with suffix) | raw | production, log aggregation |
356
+ | **Plain** | `initPlain` | stripped | formatted | development, compact scanning |
357
+ | **YAML** | `initYaml` | stripped | formatted | debugging, detailed inspection |
358
+
359
+ All formats automatically redact `_secret` fields in log output.
360
+
252
361
  ## Output Formats
253
362
 
254
363
  Three output formats for different use cases:
@@ -0,0 +1,40 @@
1
+ /**
2
+ * AFD-compliant structured logging.
3
+ *
4
+ * Outputs log events using agent-first-data formatting functions:
5
+ * - JSON: single-line JSONL via outputJson (secrets redacted, original keys)
6
+ * - Plain: single-line logfmt via outputPlain (keys stripped, values formatted)
7
+ * - YAML: multi-line via outputYaml (keys stripped, values formatted)
8
+ *
9
+ * Span fields are carried via AsyncLocalStorage (async-safe).
10
+ *
11
+ * Usage:
12
+ * import { log, span, initJson, initPlain, initYaml } from "agent-first-data/afd_logging";
13
+ * initJson(); // or initPlain() or initYaml()
14
+ * log.info("Server started");
15
+ * await span({ request_id: "abc" }, async () => {
16
+ * log.info("Processing", { domain: "example.com" });
17
+ * });
18
+ */
19
+ /** Set log output to single-line JSONL (secrets redacted, original keys). */
20
+ export declare function initJson(): void;
21
+ /** Set log output to single-line logfmt (keys stripped, values formatted). */
22
+ export declare function initPlain(): void;
23
+ /** Set log output to multi-line YAML (keys stripped, values formatted). */
24
+ export declare function initYaml(): void;
25
+ /**
26
+ * AFD logger. Each method outputs a single log line to stdout.
27
+ * Format is controlled by initJson/initPlain/initYaml (default: JSON).
28
+ */
29
+ export declare const log: {
30
+ trace: (msg: string, fields?: Record<string, unknown>) => void;
31
+ debug: (msg: string, fields?: Record<string, unknown>) => void;
32
+ info: (msg: string, fields?: Record<string, unknown>) => void;
33
+ warn: (msg: string, fields?: Record<string, unknown>) => void;
34
+ error: (msg: string, fields?: Record<string, unknown>) => void;
35
+ };
36
+ /**
37
+ * Run fn within a span that adds fields to all log events.
38
+ * Spans nest: inner spans inherit and can override outer span fields.
39
+ */
40
+ export declare function span<T>(fields: Record<string, unknown>, fn: () => T): T;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * AFD-compliant structured logging.
3
+ *
4
+ * Outputs log events using agent-first-data formatting functions:
5
+ * - JSON: single-line JSONL via outputJson (secrets redacted, original keys)
6
+ * - Plain: single-line logfmt via outputPlain (keys stripped, values formatted)
7
+ * - YAML: multi-line via outputYaml (keys stripped, values formatted)
8
+ *
9
+ * Span fields are carried via AsyncLocalStorage (async-safe).
10
+ *
11
+ * Usage:
12
+ * import { log, span, initJson, initPlain, initYaml } from "agent-first-data/afd_logging";
13
+ * initJson(); // or initPlain() or initYaml()
14
+ * log.info("Server started");
15
+ * await span({ request_id: "abc" }, async () => {
16
+ * log.info("Processing", { domain: "example.com" });
17
+ * });
18
+ */
19
+ import { AsyncLocalStorage } from "node:async_hooks";
20
+ import { outputJson, outputYaml, outputPlain } from "./format.js";
21
+ const spanStore = new AsyncLocalStorage();
22
+ let currentFormat = "json";
23
+ /** Set log output to single-line JSONL (secrets redacted, original keys). */
24
+ export function initJson() { currentFormat = "json"; }
25
+ /** Set log output to single-line logfmt (keys stripped, values formatted). */
26
+ export function initPlain() { currentFormat = "plain"; }
27
+ /** Set log output to multi-line YAML (keys stripped, values formatted). */
28
+ export function initYaml() { currentFormat = "yaml"; }
29
+ function emit(level, message, fields) {
30
+ const entry = {
31
+ timestamp_epoch_ms: Date.now(),
32
+ message,
33
+ };
34
+ // Span fields (from AsyncLocalStorage)
35
+ const spanFields = spanStore.getStore();
36
+ if (spanFields) {
37
+ for (const [k, v] of Object.entries(spanFields)) {
38
+ entry[k] = v;
39
+ }
40
+ }
41
+ // Event fields (override span fields on collision)
42
+ let hasCode = false;
43
+ if (fields) {
44
+ for (const [k, v] of Object.entries(fields)) {
45
+ if (k === "code")
46
+ hasCode = true;
47
+ entry[k] = v;
48
+ }
49
+ }
50
+ // Default code from level
51
+ if (!hasCode) {
52
+ entry["code"] = level;
53
+ }
54
+ // Format using the library's own output functions
55
+ const value = entry;
56
+ let line;
57
+ switch (currentFormat) {
58
+ case "plain":
59
+ line = outputPlain(value);
60
+ break;
61
+ case "yaml":
62
+ line = outputYaml(value);
63
+ break;
64
+ default:
65
+ line = outputJson(value);
66
+ break;
67
+ }
68
+ process.stdout.write(line + "\n");
69
+ }
70
+ /**
71
+ * AFD logger. Each method outputs a single log line to stdout.
72
+ * Format is controlled by initJson/initPlain/initYaml (default: JSON).
73
+ */
74
+ export const log = {
75
+ trace: (msg, fields) => emit("trace", msg, fields),
76
+ debug: (msg, fields) => emit("debug", msg, fields),
77
+ info: (msg, fields) => emit("info", msg, fields),
78
+ warn: (msg, fields) => emit("warn", msg, fields),
79
+ error: (msg, fields) => emit("error", msg, fields),
80
+ };
81
+ /**
82
+ * Run fn within a span that adds fields to all log events.
83
+ * Spans nest: inner spans inherit and can override outer span fields.
84
+ */
85
+ export function span(fields, fn) {
86
+ const parent = spanStore.getStore() ?? {};
87
+ return spanStore.run({ ...parent, ...fields }, fn);
88
+ }
package/dist/format.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 9 public APIs: 4 protocol builders + 3 output formatters + 1 redaction + 1 utility.
5
5
  */
6
- type JsonValue = string | number | boolean | null | JsonValue[] | {
6
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
7
7
  [key: string]: JsonValue;
8
8
  };
9
9
  /** Build {code: "startup", config, args, env}. */
@@ -28,4 +28,3 @@ export declare function internalRedactSecrets(value: JsonValue): void;
28
28
  * Case-insensitive. Trims whitespace. Returns null for invalid input.
29
29
  */
30
30
  export declare function parseSize(s: string): number | null;
31
- export {};
package/dist/index.d.ts CHANGED
@@ -2,3 +2,4 @@
2
2
  * Agent-First Data (AFD) — suffix-driven output formatting and protocol templates.
3
3
  */
4
4
  export { buildJsonStartup, buildJsonOk, buildJsonError, buildJson, outputJson, outputYaml, outputPlain, internalRedactSecrets, parseSize } from "./format.js";
5
+ export { log, span, initJson, initPlain, initYaml } from "./afd_logging.js";
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@
2
2
  * Agent-First Data (AFD) — suffix-driven output formatting and protocol templates.
3
3
  */
4
4
  export { buildJsonStartup, buildJsonOk, buildJsonError, buildJson, outputJson, outputYaml, outputPlain, internalRedactSecrets, parseSize } from "./format.js";
5
+ export { log, span, initJson, initPlain, initYaml } from "./afd_logging.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-first-data",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Agent-First Data (AFD) — suffix-driven output formatting and protocol templates for AI agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -14,14 +14,22 @@
14
14
  ".": {
15
15
  "import": "./dist/index.js",
16
16
  "types": "./dist/index.d.ts"
17
+ },
18
+ "./afd_logging": {
19
+ "import": "./dist/afd_logging.js",
20
+ "types": "./dist/afd_logging.d.ts"
17
21
  }
18
22
  },
19
- "files": ["dist", "README.md"],
23
+ "files": [
24
+ "dist",
25
+ "README.md"
26
+ ],
20
27
  "scripts": {
21
28
  "build": "tsc",
22
29
  "test": "node --test src/*.test.ts --experimental-strip-types"
23
30
  },
24
31
  "devDependencies": {
32
+ "@types/node": "^25.2.3",
25
33
  "typescript": "^5.0"
26
34
  }
27
35
  }