@guckdev/sdk 0.1.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 ADDED
@@ -0,0 +1,44 @@
1
+ # Guck (JS SDK)
2
+
3
+ Guck is a tiny, MCP-first telemetry store for AI debugging. This package
4
+ includes the JS SDK.
5
+
6
+ For full docs, see the repo README.
7
+
8
+ ## Install
9
+
10
+ This package is intended to be used from the monorepo workspace.
11
+ For the CLI (`guck ...`), use `@guckdev/cli`.
12
+
13
+ ## Quick start
14
+
15
+ ```sh
16
+ guck init
17
+ guck wrap --service debate-room --session room-123 -- pnpm run dev
18
+ # in another terminal
19
+ guck mcp
20
+ ```
21
+
22
+ ## Auto-capture stdout/stderr
23
+
24
+ Enable auto-capture early in your app startup to patch `process.stdout` and
25
+ `process.stderr` and emit Guck events:
26
+
27
+ ```ts
28
+ import "@guckdev/sdk/auto";
29
+ // or
30
+ import { installAutoCapture } from "@guckdev/sdk";
31
+ installAutoCapture();
32
+ ```
33
+
34
+ Behavior: output is buffered by line and emitted as `stdout`/`stderr` events.
35
+
36
+ Config toggles:
37
+
38
+ ```json
39
+ { "sdk": { "enabled": true, "capture_stdout": true, "capture_stderr": true } }
40
+ ```
41
+
42
+ If you're using `guck wrap`, the CLI sets `GUCK_WRAPPED=1` and the SDK
43
+ auto-capture intentionally skips to avoid double logging. Call the import or
44
+ `installAutoCapture()` early so it wraps writes during startup.
package/dist/auto.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":""}
package/dist/auto.js ADDED
@@ -0,0 +1,3 @@
1
+ import { installAutoCapture } from "./sdk/auto.js";
2
+ installAutoCapture();
3
+ //# sourceMappingURL=auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.js","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { emit } from "./sdk/emit.js";
2
+ export { installAutoCapture } from "./sdk/auto.js";
3
+ export type { GuckEvent, GuckLevel, GuckConfig } from "@guckdev/core";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { emit } from "./sdk/emit.js";
2
+ export { installAutoCapture } from "./sdk/auto.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,6 @@
1
+ type StopHandle = {
2
+ stop: () => void;
3
+ };
4
+ export declare const installAutoCapture: () => StopHandle;
5
+ export {};
6
+ //# sourceMappingURL=auto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../src/sdk/auto.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC;AAkEvC,eAAO,MAAM,kBAAkB,QAAO,UAiErC,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { emit } from "./emit.js";
2
+ import { loadConfig } from "@guckdev/core";
3
+ let installed = null;
4
+ const shouldCapture = () => {
5
+ if (process.env.GUCK_WRAPPED === "1") {
6
+ return false;
7
+ }
8
+ const { config } = loadConfig();
9
+ if (!config.enabled) {
10
+ return false;
11
+ }
12
+ if (!config.sdk.enabled) {
13
+ return false;
14
+ }
15
+ return config.sdk.capture_stdout || config.sdk.capture_stderr;
16
+ };
17
+ const flushLine = (target, line) => {
18
+ if (!line.trim()) {
19
+ return;
20
+ }
21
+ void emit({
22
+ type: target.type,
23
+ level: target.level,
24
+ message: line,
25
+ source: { kind: target.type },
26
+ });
27
+ };
28
+ const installCaptureFor = (target, bufferRef) => {
29
+ const original = target.stream.write.bind(target.stream);
30
+ const patched = (chunk, encoding, cb) => {
31
+ const result = original(chunk, encoding, cb);
32
+ const resolvedEncoding = typeof encoding === "string" ? encoding : "utf8";
33
+ const text = Buffer.isBuffer(chunk)
34
+ ? chunk.toString(resolvedEncoding)
35
+ : String(chunk);
36
+ bufferRef.value += text;
37
+ const lines = bufferRef.value.split(/\r?\n/);
38
+ bufferRef.value = lines.pop() ?? "";
39
+ for (const line of lines) {
40
+ flushLine(target, line);
41
+ }
42
+ return result;
43
+ };
44
+ target.stream.write = patched;
45
+ return original;
46
+ };
47
+ export const installAutoCapture = () => {
48
+ if (installed) {
49
+ return installed;
50
+ }
51
+ if (!shouldCapture()) {
52
+ const noOp = { stop: () => { } };
53
+ installed = noOp;
54
+ return noOp;
55
+ }
56
+ const buffers = {
57
+ stdout: { value: "" },
58
+ stderr: { value: "" },
59
+ };
60
+ const originals = {};
61
+ const { config } = loadConfig();
62
+ if (config.sdk.capture_stdout) {
63
+ originals.stdout = installCaptureFor({ stream: process.stdout, type: "stdout", level: "info" }, buffers.stdout);
64
+ }
65
+ if (config.sdk.capture_stderr) {
66
+ originals.stderr = installCaptureFor({ stream: process.stderr, type: "stderr", level: "error" }, buffers.stderr);
67
+ }
68
+ const flush = () => {
69
+ if (config.sdk.capture_stdout && buffers.stdout.value.trim()) {
70
+ flushLine({ stream: process.stdout, type: "stdout", level: "info" }, buffers.stdout.value);
71
+ buffers.stdout.value = "";
72
+ }
73
+ if (config.sdk.capture_stderr && buffers.stderr.value.trim()) {
74
+ flushLine({ stream: process.stderr, type: "stderr", level: "error" }, buffers.stderr.value);
75
+ buffers.stderr.value = "";
76
+ }
77
+ };
78
+ const beforeExit = () => flush();
79
+ process.on("beforeExit", beforeExit);
80
+ process.on("exit", beforeExit);
81
+ const stop = () => {
82
+ flush();
83
+ if (originals.stdout) {
84
+ process.stdout.write = originals.stdout;
85
+ }
86
+ if (originals.stderr) {
87
+ process.stderr.write = originals.stderr;
88
+ }
89
+ process.off("beforeExit", beforeExit);
90
+ process.off("exit", beforeExit);
91
+ installed = null;
92
+ };
93
+ const handle = { stop };
94
+ installed = handle;
95
+ return handle;
96
+ };
97
+ //# sourceMappingURL=auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto.js","sourceRoot":"","sources":["../../src/sdk/auto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { GuckEvent } from "@guckdev/core";
2
+ export declare const emit: (input: Partial<GuckEvent>) => Promise<void>;
3
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/sdk/emit.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,SAAS,EAKV,MAAM,eAAe,CAAC;AA6DvB,eAAO,MAAM,IAAI,UAAiB,QAAQ,SAAS,CAAC,KAAG,QAAQ,IAAI,CAQlE,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { appendEvent, loadConfig, redactEvent, resolveStoreDir, } from "@guckdev/core";
3
+ let cached;
4
+ const defaultRunId = process.env.GUCK_RUN_ID ?? randomUUID();
5
+ const defaultSessionId = process.env.GUCK_SESSION_ID;
6
+ const normalizeLevel = (level) => {
7
+ if (!level) {
8
+ return "info";
9
+ }
10
+ const lower = level.toLowerCase();
11
+ if (lower === "trace" ||
12
+ lower === "debug" ||
13
+ lower === "info" ||
14
+ lower === "warn" ||
15
+ lower === "error" ||
16
+ lower === "fatal") {
17
+ return lower;
18
+ }
19
+ return "info";
20
+ };
21
+ const toEvent = (input, defaults) => {
22
+ return {
23
+ id: input.id ?? randomUUID(),
24
+ ts: input.ts ?? new Date().toISOString(),
25
+ level: normalizeLevel(input.level),
26
+ type: input.type ?? "log",
27
+ service: input.service ?? defaults.service,
28
+ run_id: input.run_id ?? defaultRunId,
29
+ session_id: input.session_id ?? defaultSessionId,
30
+ message: input.message,
31
+ data: input.data,
32
+ tags: input.tags,
33
+ trace_id: input.trace_id,
34
+ span_id: input.span_id,
35
+ source: input.source ?? { kind: "sdk" },
36
+ };
37
+ };
38
+ const getCached = () => {
39
+ if (cached) {
40
+ return cached;
41
+ }
42
+ const loaded = loadConfig();
43
+ const storeDir = resolveStoreDir(loaded.config, loaded.rootDir);
44
+ cached = { storeDir, config: loaded.config };
45
+ return cached;
46
+ };
47
+ export const emit = async (input) => {
48
+ const { storeDir, config } = getCached();
49
+ if (!config.enabled) {
50
+ return;
51
+ }
52
+ const event = toEvent(input, { service: config.default_service });
53
+ const redacted = redactEvent(config, event);
54
+ await appendEvent(storeDir, redacted);
55
+ };
56
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/sdk/emit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,WAAW,EAGX,UAAU,EACV,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,IAAI,MAKS,CAAC;AAEd,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,UAAU,EAAE,CAAC;AAC7D,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;AAErD,MAAM,cAAc,GAAG,CAAC,KAAc,EAAa,EAAE;IACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,IACE,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,MAAM;QAChB,KAAK,KAAK,MAAM;QAChB,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,OAAO,EACjB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CACd,KAAyB,EACzB,QAA6B,EAClB,EAAE;IACb,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,UAAU,EAAE;QAC5B,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACxC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC;QAClC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,KAAK;QACzB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;QAC1C,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,YAAY;QACpC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,gBAAgB;QAChD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE;KACxC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAChE,MAAM,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC7C,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,EAAE,KAAyB,EAAiB,EAAE;IACrE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@guckdev/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Guck JS SDK",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ },
12
+ "./auto": {
13
+ "types": "./dist/auto.d.ts",
14
+ "import": "./dist/auto.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "scripts",
20
+ "src",
21
+ "tsconfig.json"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "scripts": {
27
+ "build": "node scripts/ensure-deps.mjs && tsc -p tsconfig.json",
28
+ "build:watch": "tsc -p tsconfig.json --watch",
29
+ "test": "pnpm run build && node --test test/*.test.js",
30
+ "prepare": "pnpm run build"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "dependencies": {
36
+ "@guckdev/core": "workspace:*"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "25.2.2"
40
+ }
41
+ }
@@ -0,0 +1,23 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+
5
+ const dep = { name: "@guckdev/core", entry: "dist/index.js" };
6
+
7
+ const npmExecPath = process.env.npm_execpath;
8
+ const run = (cwd, args) => {
9
+ const cmd = npmExecPath ? process.execPath : "pnpm";
10
+ const cmdArgs = npmExecPath ? [npmExecPath, ...args] : args;
11
+ const result = spawnSync(cmd, cmdArgs, { cwd, stdio: "inherit" });
12
+ if (result.status !== 0) {
13
+ process.exit(result.status ?? 1);
14
+ }
15
+ };
16
+
17
+ const depDir = path.join(process.cwd(), "node_modules", dep.name);
18
+ if (existsSync(depDir)) {
19
+ const entryPath = path.join(depDir, dep.entry);
20
+ if (!existsSync(entryPath)) {
21
+ run(depDir, ["run", "build"]);
22
+ }
23
+ }
package/src/auto.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { installAutoCapture } from "./sdk/auto.js";
2
+
3
+ installAutoCapture();
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { emit } from "./sdk/emit.js";
2
+ export { installAutoCapture } from "./sdk/auto.js";
3
+ export type { GuckEvent, GuckLevel, GuckConfig } from "@guckdev/core";
@@ -0,0 +1,135 @@
1
+ import { emit } from "./emit.js";
2
+ import { GuckEvent, loadConfig } from "@guckdev/core";
3
+
4
+ type StopHandle = { stop: () => void };
5
+
6
+ type WriteTarget = {
7
+ stream: NodeJS.WriteStream;
8
+ type: "stdout" | "stderr";
9
+ level: GuckEvent["level"];
10
+ };
11
+
12
+ type WriteFn = typeof process.stdout.write;
13
+
14
+ type CaptureState = {
15
+ stop: () => void;
16
+ };
17
+
18
+ let installed: CaptureState | null = null;
19
+
20
+ const shouldCapture = (): boolean => {
21
+ if (process.env.GUCK_WRAPPED === "1") {
22
+ return false;
23
+ }
24
+ const { config } = loadConfig();
25
+ if (!config.enabled) {
26
+ return false;
27
+ }
28
+ if (!config.sdk.enabled) {
29
+ return false;
30
+ }
31
+ return config.sdk.capture_stdout || config.sdk.capture_stderr;
32
+ };
33
+
34
+ const flushLine = (target: WriteTarget, line: string): void => {
35
+ if (!line.trim()) {
36
+ return;
37
+ }
38
+ void emit({
39
+ type: target.type,
40
+ level: target.level,
41
+ message: line,
42
+ source: { kind: target.type },
43
+ });
44
+ };
45
+
46
+ const installCaptureFor = (
47
+ target: WriteTarget,
48
+ bufferRef: { value: string },
49
+ ): WriteFn => {
50
+ const original = target.stream.write.bind(target.stream);
51
+ const patched: WriteFn = (chunk: any, encoding?: any, cb?: any) => {
52
+ const result = original(chunk, encoding as any, cb as any);
53
+ const resolvedEncoding: BufferEncoding =
54
+ typeof encoding === "string" ? (encoding as BufferEncoding) : "utf8";
55
+ const text = Buffer.isBuffer(chunk)
56
+ ? chunk.toString(resolvedEncoding)
57
+ : String(chunk);
58
+ bufferRef.value += text;
59
+ const lines = bufferRef.value.split(/\r?\n/);
60
+ bufferRef.value = lines.pop() ?? "";
61
+ for (const line of lines) {
62
+ flushLine(target, line);
63
+ }
64
+ return result;
65
+ };
66
+ target.stream.write = patched as typeof target.stream.write;
67
+ return original;
68
+ };
69
+
70
+ export const installAutoCapture = (): StopHandle => {
71
+ if (installed) {
72
+ return installed;
73
+ }
74
+
75
+ if (!shouldCapture()) {
76
+ const noOp = { stop: () => {} };
77
+ installed = noOp;
78
+ return noOp;
79
+ }
80
+
81
+ const buffers = {
82
+ stdout: { value: "" },
83
+ stderr: { value: "" },
84
+ };
85
+
86
+ const originals: Partial<Record<"stdout" | "stderr", WriteFn>> = {};
87
+
88
+ const { config } = loadConfig();
89
+
90
+ if (config.sdk.capture_stdout) {
91
+ originals.stdout = installCaptureFor(
92
+ { stream: process.stdout, type: "stdout", level: "info" },
93
+ buffers.stdout,
94
+ );
95
+ }
96
+ if (config.sdk.capture_stderr) {
97
+ originals.stderr = installCaptureFor(
98
+ { stream: process.stderr, type: "stderr", level: "error" },
99
+ buffers.stderr,
100
+ );
101
+ }
102
+
103
+ const flush = () => {
104
+ if (config.sdk.capture_stdout && buffers.stdout.value.trim()) {
105
+ flushLine({ stream: process.stdout, type: "stdout", level: "info" }, buffers.stdout.value);
106
+ buffers.stdout.value = "";
107
+ }
108
+ if (config.sdk.capture_stderr && buffers.stderr.value.trim()) {
109
+ flushLine({ stream: process.stderr, type: "stderr", level: "error" }, buffers.stderr.value);
110
+ buffers.stderr.value = "";
111
+ }
112
+ };
113
+
114
+ const beforeExit = () => flush();
115
+
116
+ process.on("beforeExit", beforeExit);
117
+ process.on("exit", beforeExit);
118
+
119
+ const stop = () => {
120
+ flush();
121
+ if (originals.stdout) {
122
+ process.stdout.write = originals.stdout as typeof process.stdout.write;
123
+ }
124
+ if (originals.stderr) {
125
+ process.stderr.write = originals.stderr as typeof process.stderr.write;
126
+ }
127
+ process.off("beforeExit", beforeExit);
128
+ process.off("exit", beforeExit);
129
+ installed = null;
130
+ };
131
+
132
+ const handle = { stop };
133
+ installed = handle;
134
+ return handle;
135
+ };
@@ -0,0 +1,78 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import {
3
+ appendEvent,
4
+ GuckEvent,
5
+ GuckLevel,
6
+ loadConfig,
7
+ redactEvent,
8
+ resolveStoreDir,
9
+ } from "@guckdev/core";
10
+
11
+ let cached:
12
+ | {
13
+ storeDir: string;
14
+ config: ReturnType<typeof loadConfig>["config"];
15
+ }
16
+ | undefined;
17
+
18
+ const defaultRunId = process.env.GUCK_RUN_ID ?? randomUUID();
19
+ const defaultSessionId = process.env.GUCK_SESSION_ID;
20
+
21
+ const normalizeLevel = (level?: string): GuckLevel => {
22
+ if (!level) {
23
+ return "info";
24
+ }
25
+ const lower = level.toLowerCase();
26
+ if (
27
+ lower === "trace" ||
28
+ lower === "debug" ||
29
+ lower === "info" ||
30
+ lower === "warn" ||
31
+ lower === "error" ||
32
+ lower === "fatal"
33
+ ) {
34
+ return lower;
35
+ }
36
+ return "info";
37
+ };
38
+
39
+ const toEvent = (
40
+ input: Partial<GuckEvent>,
41
+ defaults: { service: string },
42
+ ): GuckEvent => {
43
+ return {
44
+ id: input.id ?? randomUUID(),
45
+ ts: input.ts ?? new Date().toISOString(),
46
+ level: normalizeLevel(input.level),
47
+ type: input.type ?? "log",
48
+ service: input.service ?? defaults.service,
49
+ run_id: input.run_id ?? defaultRunId,
50
+ session_id: input.session_id ?? defaultSessionId,
51
+ message: input.message,
52
+ data: input.data,
53
+ tags: input.tags,
54
+ trace_id: input.trace_id,
55
+ span_id: input.span_id,
56
+ source: input.source ?? { kind: "sdk" },
57
+ };
58
+ };
59
+
60
+ const getCached = () => {
61
+ if (cached) {
62
+ return cached;
63
+ }
64
+ const loaded = loadConfig();
65
+ const storeDir = resolveStoreDir(loaded.config, loaded.rootDir);
66
+ cached = { storeDir, config: loaded.config };
67
+ return cached;
68
+ };
69
+
70
+ export const emit = async (input: Partial<GuckEvent>): Promise<void> => {
71
+ const { storeDir, config } = getCached();
72
+ if (!config.enabled) {
73
+ return;
74
+ }
75
+ const event = toEvent(input, { service: config.default_service });
76
+ const redacted = redactEvent(config, event);
77
+ await appendEvent(storeDir, redacted);
78
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "rootDir": "src",
7
+ "outDir": "dist",
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "strict": true,
12
+ "noUncheckedIndexedAccess": true,
13
+ "esModuleInterop": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "skipLibCheck": true,
16
+ "types": ["node"]
17
+ },
18
+ "include": ["src/**/*.ts"]
19
+ }