execbro-sdk
Advanced tools
| import { FlowpointOptions } from './types'; | ||
| export declare function flowpoint(options: FlowpointOptions): void; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.flowpoint = flowpoint; | ||
| function flowpoint(options) { | ||
| const g = globalThis.__EXECBRO__ ?? globalThis.__RN_AI_DEVTOOLS__; | ||
| if (!g || typeof g.addFlowpoint !== 'function') { | ||
| return; | ||
| } | ||
| g.addFlowpoint(options); | ||
| } |
| import { FlowpointEntry, FlowpointOptions, FlowpointSnapshot } from './types'; | ||
| export declare class FlowpointBuffer { | ||
| readonly contextId: string; | ||
| private entries; | ||
| private maxSize; | ||
| private seqCounter; | ||
| private currentRuns; | ||
| constructor(maxSize?: number); | ||
| add(options: FlowpointOptions): void; | ||
| getAll(): FlowpointEntry[]; | ||
| getSnapshot(): FlowpointSnapshot; | ||
| clear(): number; | ||
| } |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.FlowpointBuffer = void 0; | ||
| function randomId(length) { | ||
| let id = ''; | ||
| while (id.length < length) { | ||
| id += Math.random().toString(36).slice(2); | ||
| } | ||
| return id.slice(0, length); | ||
| } | ||
| class FlowpointBuffer { | ||
| constructor(maxSize = 500) { | ||
| this.contextId = randomId(8); | ||
| this.entries = []; | ||
| this.seqCounter = 0; | ||
| this.currentRuns = new Map(); | ||
| this.maxSize = maxSize; | ||
| } | ||
| add(options) { | ||
| const { name, step, meta, level, begin } = options; | ||
| if (begin || !this.currentRuns.has(name)) { | ||
| this.currentRuns.set(name, randomId(4)); | ||
| } | ||
| const entry = { | ||
| seq: ++this.seqCounter, | ||
| t: Date.now(), | ||
| name, | ||
| step, | ||
| run: this.currentRuns.get(name), | ||
| level: level ?? 'info', | ||
| }; | ||
| if (meta !== undefined) { | ||
| entry.meta = meta; | ||
| } | ||
| if (this.entries.length >= this.maxSize) { | ||
| this.entries.shift(); | ||
| } | ||
| this.entries.push(entry); | ||
| } | ||
| getAll() { | ||
| return [...this.entries]; | ||
| } | ||
| getSnapshot() { | ||
| return { contextId: this.contextId, entries: [...this.entries] }; | ||
| } | ||
| clear() { | ||
| const count = this.entries.length; | ||
| this.entries = []; | ||
| this.currentRuns.clear(); | ||
| return count; | ||
| } | ||
| } | ||
| exports.FlowpointBuffer = FlowpointBuffer; |
+2
-0
| import { NetworkBuffer } from './networkBuffer'; | ||
| import { ConsoleBuffer } from './consoleBuffer'; | ||
| import { FlowpointBuffer } from './flowpointBuffer'; | ||
| import { DevToolsGlobal, Capabilities } from './types'; | ||
@@ -11,2 +12,3 @@ declare global { | ||
| consoleBuffer: ConsoleBuffer; | ||
| flowpointBuffer: FlowpointBuffer; | ||
| stores: Record<string, unknown>; | ||
@@ -13,0 +15,0 @@ navigation: unknown; |
+5
-1
@@ -11,3 +11,3 @@ "use strict"; | ||
| function exposeGlobal(options) { | ||
| const { networkBuffer, consoleBuffer, stores, navigation, custom, capabilities } = options; | ||
| const { networkBuffer, consoleBuffer, flowpointBuffer, stores, navigation, custom, capabilities } = options; | ||
| const devtools = { | ||
@@ -23,2 +23,6 @@ version: SDK_VERSION, | ||
| clearConsole: () => consoleBuffer.clear(), | ||
| addFlowpoint: (options) => flowpointBuffer.add(options), | ||
| getFlowpointEntries: () => flowpointBuffer.getAll(), | ||
| getFlowpointSnapshot: () => flowpointBuffer.getSnapshot(), | ||
| clearFlowpoints: () => flowpointBuffer.clear(), | ||
| }; | ||
@@ -25,0 +29,0 @@ globalThis.__EXECBRO__ = devtools; |
+2
-1
| import { InitOptions } from './types'; | ||
| export type { InitOptions, NetworkEntry, ConsoleEntry, Capabilities, DevToolsGlobal, } from './types'; | ||
| export { flowpoint } from './flowpoint'; | ||
| export type { InitOptions, NetworkEntry, ConsoleEntry, Capabilities, DevToolsGlobal, FlowpointEntry, FlowpointOptions, FlowpointLevel, FlowpointSnapshot, } from './types'; | ||
| export declare function init(options?: InitOptions): void; | ||
| export declare function _resetForTesting(): void; |
+7
-0
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.flowpoint = void 0; | ||
| exports.init = init; | ||
@@ -7,2 +8,3 @@ exports._resetForTesting = _resetForTesting; | ||
| const consoleBuffer_1 = require("./consoleBuffer"); | ||
| const flowpointBuffer_1 = require("./flowpointBuffer"); | ||
| const networkInterceptor_1 = require("./networkInterceptor"); | ||
@@ -13,2 +15,4 @@ const consoleInterceptor_1 = require("./consoleInterceptor"); | ||
| const fastRefreshRecorder_1 = require("./fastRefreshRecorder"); | ||
| var flowpoint_1 = require("./flowpoint"); | ||
| Object.defineProperty(exports, "flowpoint", { enumerable: true, get: function () { return flowpoint_1.flowpoint; } }); | ||
| let initialized = false; | ||
@@ -25,2 +29,3 @@ function init(options) { | ||
| const consoleBuffer = new consoleBuffer_1.ConsoleBuffer(options?.maxConsoleEntries ?? 500); | ||
| const flowpointBuffer = new flowpointBuffer_1.FlowpointBuffer(options?.maxFlowpointEntries ?? 500); | ||
| const stores = options?.stores ?? {}; | ||
@@ -34,2 +39,3 @@ const navigation = options?.navigation ?? null; | ||
| consoleBuffer, | ||
| flowpointBuffer, | ||
| stores, | ||
@@ -44,2 +50,3 @@ navigation, | ||
| render: false, | ||
| flowpoints: true, | ||
| }, | ||
@@ -46,0 +53,0 @@ }); |
+27
-0
| export interface InitOptions { | ||
| maxNetworkEntries?: number; | ||
| maxConsoleEntries?: number; | ||
| maxFlowpointEntries?: number; | ||
| stores?: Record<string, unknown>; | ||
@@ -33,2 +34,23 @@ navigation?: unknown; | ||
| } | ||
| export type FlowpointLevel = 'info' | 'warn' | 'error'; | ||
| export interface FlowpointOptions { | ||
| name: string; | ||
| step: string; | ||
| meta?: unknown; | ||
| level?: FlowpointLevel; | ||
| begin?: boolean; | ||
| } | ||
| export interface FlowpointEntry { | ||
| seq: number; | ||
| t: number; | ||
| name: string; | ||
| step: string; | ||
| run: string; | ||
| level: FlowpointLevel; | ||
| meta?: unknown; | ||
| } | ||
| export interface FlowpointSnapshot { | ||
| contextId: string; | ||
| entries: FlowpointEntry[]; | ||
| } | ||
| export interface Capabilities { | ||
@@ -40,2 +62,3 @@ network: boolean; | ||
| render: boolean; | ||
| flowpoints: boolean; | ||
| } | ||
@@ -52,2 +75,6 @@ export interface DevToolsGlobal { | ||
| clearConsole: () => number; | ||
| addFlowpoint: (options: FlowpointOptions) => void; | ||
| getFlowpointEntries: () => FlowpointEntry[]; | ||
| getFlowpointSnapshot: () => FlowpointSnapshot; | ||
| clearFlowpoints: () => number; | ||
| } | ||
@@ -54,0 +81,0 @@ export interface RnGlobalsNamespace { |
+1
-1
| { | ||
| "name": "execbro-sdk", | ||
| "version": "0.5.5", | ||
| "version": "0.6.0", | ||
| "description": "Companion SDK for ExecBro (npm: execbro) — captures network requests for AI-powered React Native debugging.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
+41
-0
@@ -114,2 +114,5 @@ # execbro-sdk | ||
| // Max flowpoint entries to buffer (default: 500) | ||
| maxFlowpointEntries: 500, | ||
| // State store references for AI access | ||
@@ -133,2 +136,33 @@ stores: { | ||
| ## Flowpoints — instrument and verify flows | ||
| `flowpoint()` drops structured, timestamped breadcrumbs grouped by flow, so an AI agent | ||
| (via the ExecBro MCP tools `get_flowpoints`, `wait_for_flowpoint`, `verify_flow`) can | ||
| verify what actually happened inside a flow instead of inferring it from console logs. | ||
| ```js | ||
| import { flowpoint } from "execbro-sdk"; | ||
| async function addToCart(item) { | ||
| flowpoint({ name: "add-to-cart", step: "start", begin: true }); | ||
| await clearCart(); | ||
| flowpoint({ name: "add-to-cart", step: "cleared", meta: { removed: 3 } }); | ||
| try { | ||
| await addItem(item); | ||
| flowpoint({ name: "add-to-cart", step: "item-added" }); | ||
| } catch (e) { | ||
| flowpoint({ name: "add-to-cart", step: "failed", meta: { reason: e.message }, level: "error" }); | ||
| } | ||
| } | ||
| ``` | ||
| - `name` — the flow (grouping key, keep it stable and low-cardinality) | ||
| - `step` — the point within the flow (what verification asserts against) | ||
| - `meta` — optional free-form payload (object, string, anything JSON-ish) | ||
| - `level` — `'info'` (default) | `'warn'` | `'error'` | ||
| - `begin: true` — marks a new run of the flow, separating repeated attempts | ||
| Safe to leave in your code: like everything else in this SDK, `flowpoint()` is a | ||
| silent no-op in production builds and costs nothing. | ||
| ## How it works | ||
@@ -214,2 +248,3 @@ | ||
| navigation: true, // true if navigation was passed | ||
| flowpoints: true, | ||
| render: false, // future: render profiling | ||
@@ -234,2 +269,8 @@ }, | ||
| clearConsole(), // returns number of entries cleared | ||
| // Flowpoints | ||
| addFlowpoint(options), // used by the flowpoint() helper | ||
| getFlowpointEntries(), // all buffered flowpoints | ||
| getFlowpointSnapshot(), // { contextId, entries } — used by the MCP drain | ||
| clearFlowpoints(), // returns number of entries cleared | ||
| } | ||
@@ -236,0 +277,0 @@ ``` |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
41971
15.3%24
20%866
15.93%308
15.36%