@logbrew/sdk 0.1.2 → 0.1.3
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 +15 -0
- package/examples/agent-timeline.cjs +87 -0
- package/examples/agent-timeline.mjs +79 -0
- package/examples/index.mjs +15 -0
- package/examples/package.json +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,14 @@ The package supports both ESM `import` and CommonJS `require`.
|
|
|
13
13
|
The shipped package also includes `.d.ts` and `.d.cts` declarations so ESM and CommonJS TypeScript consumers can install it directly without a separate build step.
|
|
14
14
|
The package ships copyable examples under `node_modules/@logbrew/sdk/examples/`. Use the fake `LOGBREW_API_KEY` placeholder in docs, keep the real key in your app configuration, and call `previewJson()` when you want to inspect queued JSON before sending. Type declarations document payload shapes such as `ReleaseAttributes`, `SpanAttributes`, `MetricAttributes`, transport responses, SDK errors, lifecycle helpers, W3C trace helpers, product timeline helpers, console capture, Pino destination, and Winston transport APIs.
|
|
15
15
|
|
|
16
|
+
After install, discover and run the packaged examples:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
node node_modules/@logbrew/sdk/examples/index.mjs --list
|
|
20
|
+
node node_modules/@logbrew/sdk/examples/index.mjs agent-timeline
|
|
21
|
+
npm --prefix node_modules/@logbrew/sdk/examples run agent-timeline
|
|
22
|
+
```
|
|
23
|
+
|
|
16
24
|
## Example
|
|
17
25
|
|
|
18
26
|
```js
|
|
@@ -183,6 +191,13 @@ client.action("evt_payment_api", new Date().toISOString(), createNetworkMileston
|
|
|
183
191
|
|
|
184
192
|
Timeline helpers keep only primitive metadata, strip query strings and hashes from route templates, normalize HTTP methods, infer failed network milestones from status codes `400` and above, and serialize through the existing `action` event type. Keep metadata low-cardinality, such as `sessionId`, `traceId`, `routeTemplate`, `method`, `statusCode`, `durationMs`, `screen`, `funnel`, and `step`.
|
|
185
193
|
|
|
194
|
+
The packaged `agent-timeline` example shows a two-event checkout timeline that an AI assistant can inspect without session replay or payload capture. It combines product action metadata, network milestone metadata, explicit `traceparent` propagation, and a drop-only `eventFilter` that removes low-value info logs:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
node node_modules/@logbrew/sdk/examples/index.mjs agent-timeline
|
|
198
|
+
node node_modules/@logbrew/sdk/examples/index.mjs agent-timeline:cjs
|
|
199
|
+
```
|
|
200
|
+
|
|
186
201
|
## Console Capture
|
|
187
202
|
|
|
188
203
|
If an app already uses `console.info()`, `console.warn()`, or `console.error()`, install explicit capture on the console object you own:
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
let sdk;
|
|
2
|
+
try {
|
|
3
|
+
sdk = require("@logbrew/sdk");
|
|
4
|
+
} catch (error) {
|
|
5
|
+
if (error && error.code === "MODULE_NOT_FOUND") {
|
|
6
|
+
sdk = require("../index.cjs");
|
|
7
|
+
} else {
|
|
8
|
+
throw error;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
createNetworkMilestoneAttributes,
|
|
14
|
+
createProductActionAttributes,
|
|
15
|
+
createTraceparentHeaders,
|
|
16
|
+
LogBrewClient,
|
|
17
|
+
RecordingTransport
|
|
18
|
+
} = sdk;
|
|
19
|
+
|
|
20
|
+
const traceId = "4bf92f3577b34da6a3ce929d0e0e4736";
|
|
21
|
+
const spanId = "b7ad6b7169203331";
|
|
22
|
+
const sessionId = "sess_checkout_001";
|
|
23
|
+
const timestamp = "2026-06-02T10:00:00Z";
|
|
24
|
+
|
|
25
|
+
const client = LogBrewClient.create({
|
|
26
|
+
apiKey: "LOGBREW_API_KEY",
|
|
27
|
+
sdkName: "checkout-agent-timeline",
|
|
28
|
+
sdkVersion: "1.0.0",
|
|
29
|
+
eventFilter(event) {
|
|
30
|
+
return !(event.type === "log" && event.attributes.level === "info");
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
client.action("evt_checkout_started", timestamp, createProductActionAttributes({
|
|
35
|
+
name: "checkout.started",
|
|
36
|
+
status: "success",
|
|
37
|
+
sessionId,
|
|
38
|
+
traceId,
|
|
39
|
+
routeTemplate: "/checkout/:step?coupon=private#payment",
|
|
40
|
+
funnel: "checkout",
|
|
41
|
+
step: "start",
|
|
42
|
+
metadata: { service: "checkout", plan: "pro" }
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
client.action("evt_payment_api", "2026-06-02T10:00:01Z", createNetworkMilestoneAttributes({
|
|
46
|
+
routeTemplate: "https://api.example.invalid/payments/123?card=private#retry",
|
|
47
|
+
method: "POST",
|
|
48
|
+
statusCode: 503,
|
|
49
|
+
durationMs: 241.5,
|
|
50
|
+
sessionId,
|
|
51
|
+
traceId,
|
|
52
|
+
metadata: { service: "payments", retryable: true }
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
client.log("evt_debug_noise", "2026-06-02T10:00:02Z", {
|
|
56
|
+
message: "debug heartbeat",
|
|
57
|
+
level: "info",
|
|
58
|
+
logger: "checkout"
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const headers = createTraceparentHeaders({
|
|
62
|
+
traceId,
|
|
63
|
+
spanId,
|
|
64
|
+
traceFlags: "01"
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const preview = client.previewJson();
|
|
68
|
+
if (preview.includes("card=private") || preview.includes("coupon=private") || preview.includes("#payment")) {
|
|
69
|
+
throw new Error("agent timeline leaked query or hash metadata");
|
|
70
|
+
}
|
|
71
|
+
if (client.pendingEvents() !== 2) {
|
|
72
|
+
throw new Error(`expected two retained timeline events, got ${client.pendingEvents()}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(preview);
|
|
76
|
+
|
|
77
|
+
client.shutdown(RecordingTransport.alwaysAccept()).then((response) => {
|
|
78
|
+
console.error(JSON.stringify({
|
|
79
|
+
ok: true,
|
|
80
|
+
events: 2,
|
|
81
|
+
traceparent: headers.traceparent,
|
|
82
|
+
status: response.statusCode
|
|
83
|
+
}));
|
|
84
|
+
}).catch((error) => {
|
|
85
|
+
console.error(error);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const sdk = await import("@logbrew/sdk").catch(async (error) => {
|
|
2
|
+
if (error && error.code === "ERR_MODULE_NOT_FOUND") {
|
|
3
|
+
return import("../index.js");
|
|
4
|
+
}
|
|
5
|
+
throw error;
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
createNetworkMilestoneAttributes,
|
|
10
|
+
createProductActionAttributes,
|
|
11
|
+
createTraceparentHeaders,
|
|
12
|
+
LogBrewClient,
|
|
13
|
+
RecordingTransport
|
|
14
|
+
} = sdk;
|
|
15
|
+
|
|
16
|
+
const traceId = "4bf92f3577b34da6a3ce929d0e0e4736";
|
|
17
|
+
const spanId = "b7ad6b7169203331";
|
|
18
|
+
const sessionId = "sess_checkout_001";
|
|
19
|
+
const timestamp = "2026-06-02T10:00:00Z";
|
|
20
|
+
|
|
21
|
+
const client = LogBrewClient.create({
|
|
22
|
+
apiKey: "LOGBREW_API_KEY",
|
|
23
|
+
sdkName: "checkout-agent-timeline",
|
|
24
|
+
sdkVersion: "1.0.0",
|
|
25
|
+
eventFilter(event) {
|
|
26
|
+
return !(event.type === "log" && event.attributes.level === "info");
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
client.action("evt_checkout_started", timestamp, createProductActionAttributes({
|
|
31
|
+
name: "checkout.started",
|
|
32
|
+
status: "success",
|
|
33
|
+
sessionId,
|
|
34
|
+
traceId,
|
|
35
|
+
routeTemplate: "/checkout/:step?coupon=private#payment",
|
|
36
|
+
funnel: "checkout",
|
|
37
|
+
step: "start",
|
|
38
|
+
metadata: { service: "checkout", plan: "pro" }
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
client.action("evt_payment_api", "2026-06-02T10:00:01Z", createNetworkMilestoneAttributes({
|
|
42
|
+
routeTemplate: "https://api.example.invalid/payments/123?card=private#retry",
|
|
43
|
+
method: "POST",
|
|
44
|
+
statusCode: 503,
|
|
45
|
+
durationMs: 241.5,
|
|
46
|
+
sessionId,
|
|
47
|
+
traceId,
|
|
48
|
+
metadata: { service: "payments", retryable: true }
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
client.log("evt_debug_noise", "2026-06-02T10:00:02Z", {
|
|
52
|
+
message: "debug heartbeat",
|
|
53
|
+
level: "info",
|
|
54
|
+
logger: "checkout"
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const headers = createTraceparentHeaders({
|
|
58
|
+
traceId,
|
|
59
|
+
spanId,
|
|
60
|
+
traceFlags: "01"
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const preview = client.previewJson();
|
|
64
|
+
if (preview.includes("card=private") || preview.includes("coupon=private") || preview.includes("#payment")) {
|
|
65
|
+
throw new Error("agent timeline leaked query or hash metadata");
|
|
66
|
+
}
|
|
67
|
+
if (client.pendingEvents() !== 2) {
|
|
68
|
+
throw new Error(`expected two retained timeline events, got ${client.pendingEvents()}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(preview);
|
|
72
|
+
|
|
73
|
+
const response = await client.shutdown(RecordingTransport.alwaysAccept());
|
|
74
|
+
console.error(JSON.stringify({
|
|
75
|
+
ok: true,
|
|
76
|
+
events: 2,
|
|
77
|
+
traceparent: headers.traceparent,
|
|
78
|
+
status: response.statusCode
|
|
79
|
+
}));
|
package/examples/index.mjs
CHANGED
|
@@ -10,6 +10,9 @@ const installedLauncherPrefix = "node node_modules/@logbrew/sdk/examples/index.m
|
|
|
10
10
|
const repoLauncherPrefix = "node examples/index.mjs";
|
|
11
11
|
|
|
12
12
|
const examples = {
|
|
13
|
+
"agent-timeline": new URL("./agent-timeline.mjs", import.meta.url),
|
|
14
|
+
"agent-timeline:esm": new URL("./agent-timeline.mjs", import.meta.url),
|
|
15
|
+
"agent-timeline:cjs": new URL("./agent-timeline.cjs", import.meta.url),
|
|
13
16
|
"readme-example": new URL("./readme-example.mjs", import.meta.url),
|
|
14
17
|
"readme-example:esm": new URL("./readme-example.mjs", import.meta.url),
|
|
15
18
|
"readme-example:cjs": new URL("./readme-example.cjs", import.meta.url),
|
|
@@ -25,6 +28,9 @@ function isInstalledPackageContext() {
|
|
|
25
28
|
function exampleCommands() {
|
|
26
29
|
if (!isInstalledPackageContext()) {
|
|
27
30
|
return {
|
|
31
|
+
"agent-timeline": `${repoPrefix} && ${repoLauncherPrefix} agent-timeline`,
|
|
32
|
+
"agent-timeline:esm": `${repoPrefix} && ${repoLauncherPrefix} agent-timeline:esm`,
|
|
33
|
+
"agent-timeline:cjs": `${repoPrefix} && ${repoLauncherPrefix} agent-timeline:cjs`,
|
|
28
34
|
"readme-example": `${repoPrefix} && ${repoLauncherPrefix} readme-example`,
|
|
29
35
|
"readme-example:esm": `${repoPrefix} && ${repoLauncherPrefix} readme-example:esm`,
|
|
30
36
|
"readme-example:cjs": `${repoPrefix} && ${repoLauncherPrefix} readme-example:cjs`,
|
|
@@ -36,6 +42,9 @@ function exampleCommands() {
|
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
return {
|
|
45
|
+
"agent-timeline": `${installedLauncherPrefix} agent-timeline`,
|
|
46
|
+
"agent-timeline:esm": `${installedLauncherPrefix} agent-timeline:esm`,
|
|
47
|
+
"agent-timeline:cjs": `${installedLauncherPrefix} agent-timeline:cjs`,
|
|
39
48
|
"readme-example": `${installedLauncherPrefix} readme-example`,
|
|
40
49
|
"readme-example:esm": `${installedLauncherPrefix} readme-example:esm`,
|
|
41
50
|
"readme-example:cjs": `${installedLauncherPrefix} readme-example:cjs`,
|
|
@@ -49,6 +58,9 @@ function exampleCommands() {
|
|
|
49
58
|
function helperCommands() {
|
|
50
59
|
if (!isInstalledPackageContext()) {
|
|
51
60
|
return {
|
|
61
|
+
"agent-timeline": `${repoExamplesPrefix} && ${repoNpmHelperPrefix} agent-timeline | ${repoExamplesPrefix} && ${repoPnpmHelperPrefix} agent-timeline`,
|
|
62
|
+
"agent-timeline:esm": `${repoExamplesPrefix} && ${repoNpmHelperPrefix} agent-timeline:esm | ${repoExamplesPrefix} && ${repoPnpmHelperPrefix} agent-timeline:esm`,
|
|
63
|
+
"agent-timeline:cjs": `${repoExamplesPrefix} && ${repoNpmHelperPrefix} agent-timeline:cjs | ${repoExamplesPrefix} && ${repoPnpmHelperPrefix} agent-timeline:cjs`,
|
|
52
64
|
"readme-example": `${repoExamplesPrefix} && ${repoNpmHelperPrefix} readme-example | ${repoExamplesPrefix} && ${repoPnpmHelperPrefix} readme-example`,
|
|
53
65
|
"readme-example:esm": `${repoExamplesPrefix} && ${repoNpmHelperPrefix} readme-example:esm | ${repoExamplesPrefix} && ${repoPnpmHelperPrefix} readme-example:esm`,
|
|
54
66
|
"readme-example:cjs": `${repoExamplesPrefix} && ${repoNpmHelperPrefix} readme-example:cjs | ${repoExamplesPrefix} && ${repoPnpmHelperPrefix} readme-example:cjs`,
|
|
@@ -59,6 +71,9 @@ function helperCommands() {
|
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
return {
|
|
74
|
+
"agent-timeline": `${installedHelperPrefix} agent-timeline | ${installedPnpmHelperPrefix} agent-timeline`,
|
|
75
|
+
"agent-timeline:esm": `${installedHelperPrefix} agent-timeline:esm | ${installedPnpmHelperPrefix} agent-timeline:esm`,
|
|
76
|
+
"agent-timeline:cjs": `${installedHelperPrefix} agent-timeline:cjs | ${installedPnpmHelperPrefix} agent-timeline:cjs`,
|
|
62
77
|
"readme-example": `${installedHelperPrefix} readme-example | ${installedPnpmHelperPrefix} readme-example`,
|
|
63
78
|
"readme-example:esm": `${installedHelperPrefix} readme-example:esm | ${installedPnpmHelperPrefix} readme-example:esm`,
|
|
64
79
|
"readme-example:cjs": `${installedHelperPrefix} readme-example:cjs | ${installedPnpmHelperPrefix} readme-example:cjs`,
|
package/examples/package.json
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
"scripts": {
|
|
5
5
|
"help": "node ./index.mjs --help",
|
|
6
6
|
"list": "node ./index.mjs --list",
|
|
7
|
+
"agent-timeline": "node ./index.mjs agent-timeline",
|
|
8
|
+
"agent-timeline:esm": "node ./index.mjs agent-timeline:esm",
|
|
9
|
+
"agent-timeline:cjs": "node ./index.mjs agent-timeline:cjs",
|
|
7
10
|
"readme-example": "node ./index.mjs readme-example",
|
|
8
11
|
"readme-example:esm": "node ./index.mjs readme-example:esm",
|
|
9
12
|
"readme-example:cjs": "node ./index.mjs readme-example:cjs",
|