elasticdash-sdk 0.2.7-beta → 0.2.7-beta-2

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
@@ -71,7 +71,9 @@ That's it. The agent reads the baked-in guide (which transcludes the same conten
71
71
 
72
72
  > **Do not shortcut this step.** Without `ed_tools.ts` and `ed_workflows.ts` plus the init call, the SDK does not intercept tool or AI calls — your project will run without errors and produce zero traces. A vague prompt like "install elasticdash-sdk" lets the agent stop at `npm install`; the prompt above is explicit about completing integration.
73
73
 
74
- > **Init must go through `edInitObservability` (the helper inside `ed_workflows.ts`), not `import { initObservability } from 'elasticdash-sdk'` in your entry file.** Both files in the integration share one CJS module instance via `eval('require')`; importing `initObservability` directly hits a *different* ESM instance, leaving `_ed.startTrace` reading from an empty store. The symptom is `[elasticdash] startTrace: observability not initialised` at runtime. The integration guide's Step 3 explains why; the `edInitObservability` helper is the only correct path. For CLI scripts, also call `edShutdownObservability()` from a `finally` block at process exit — the SDK's auto-registered exit hooks are async and short-lived processes can terminate before the final batch flushes.
74
+ > **Init must go through `edInitObservability` (the helper inside `ed_workflows.ts`), not `import { initObservability } from 'elasticdash-sdk'` in your entry file.** Both files in the integration share one CJS module instance via `createRequire(import.meta.url)`; importing `initObservability` directly hits a *different* ESM instance, leaving `_ed.startTrace` reading from an empty store. The symptom is `[elasticdash] startTrace: observability not initialised` at runtime. The integration guide's Step 3 explains why; the `edInitObservability` helper is the only correct path. For CLI scripts, also call `edShutdownObservability()` from a `finally` block at process exit — the SDK's auto-registered exit hooks are async and short-lived processes can terminate before the final batch flushes.
75
+
76
+ > **Important: do not use `eval('require')` to load the SDK in `ed_tools.ts`.** The `eval('require')(...)` trick that older versions of this guide recommended works only in CJS — in any project with `"type": "module"` in `package.json`, it throws "require is not defined", the catch silently swallows the error, and the entire integration no-ops with zero logs and zero traces. Use `createRequire(import.meta.url)` from `node:module` instead; it works in both ESM and CJS.
75
77
 
76
78
  **Fallback** — if you don't want to add a file to your repo, you can skip `init-guide` and use this prompt instead, which directs the agent at the docs inside `node_modules/`:
77
79
 
@@ -477,21 +479,25 @@ This file loads the SDK, shares the module instance with `ed_workflows.ts`, and
477
479
 
478
480
  ```ts
479
481
  // ed_tools.ts
482
+ import { createRequire } from 'node:module';
480
483
  import { setElasticDashModule } from './ed_workflows';
481
484
 
482
- let wrapTool: <T extends (...args: any[]) => any>(name: string, fn: T) => T = (_name, fn) => fn;
485
+ let edTool: <T extends (...args: any[]) => any>(name: string, fn: T) => T = (_name, fn) => fn;
486
+
487
+ // `createRequire(import.meta.url)` works in BOTH ESM (`"type": "module"`)
488
+ // and CJS projects. Do NOT use `eval('require')` — it silently throws in
489
+ // ESM and the whole integration produces zero traces with zero logs.
490
+ const nodeRequire = createRequire(import.meta.url);
483
491
 
484
492
  try {
485
- // For Next.js / Turbopack: eval('require') bypasses static analysis.
486
- // For plain Node.js projects you can use a normal require() or import.
487
- const _edModule = (eval('require') as (id: string) => any)('elasticdash-sdk');
488
- wrapTool = _edModule.wrapTool ?? wrapTool;
493
+ const _edModule = nodeRequire('elasticdash-sdk');
494
+ edTool = _edModule.edTool ?? _edModule.wrapTool ?? edTool;
489
495
  setElasticDashModule(_edModule);
490
- } catch {
491
- // elasticdash-sdk not available — tools run without tracing
496
+ } catch (err) {
497
+ console.error('[ed_tools] failed to load elasticdash-sdk:', err);
492
498
  }
493
499
 
494
- export const myTool = wrapTool('myTool', async (input: { query: string }) => {
500
+ export const myTool = edTool('myTool', async (input: { query: string }) => {
495
501
  // ... your tool logic
496
502
  });
497
503
  ```
@@ -61,6 +61,7 @@ Create `ed_tools.ts` in the project root. This file wraps each tool function wit
61
61
 
62
62
  ```ts
63
63
  // ed_tools.ts
64
+ import { createRequire } from 'node:module'
64
65
  import { setElasticDashModule } from './ed_workflows'
65
66
 
66
67
  // Import original tool implementations from the actual source files
@@ -76,14 +77,24 @@ type EdToolFn = <T extends (...args: any[]) => any>(name: string, fn: T) => T
76
77
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
78
  let edTool: EdToolFn = (_name: string, fn: any) => fn
78
79
 
80
+ // `createRequire` works in BOTH ESM (`"type": "module"`) and CJS projects —
81
+ // it's the only require shape that survives both. The older `eval('require')`
82
+ // trick silently throws in ESM ("require is not defined"), the catch swallows
83
+ // it, _ed stays null, and every helper in ed_workflows.ts returns silently —
84
+ // you get zero traces and zero error logs. Always use createRequire.
85
+ const nodeRequire = createRequire(import.meta.url)
86
+
79
87
  try {
80
88
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
- const _edModule = (eval('require') as (id: string) => any)('elasticdash-sdk')
89
+ const _edModule = nodeRequire('elasticdash-sdk')
82
90
  edTool = _edModule.edTool ?? _edModule.wrapTool ?? edTool
83
91
  // Share the module instance with ed_workflows.ts so trace hooks use the same context
84
92
  setElasticDashModule(_edModule)
85
- } catch {
86
- // elasticdash-sdk not availableall wrappers pass through to original functions
93
+ } catch (err) {
94
+ // Surface load failures explicitly silent failure here is the #1 cause of
95
+ // "I installed the SDK but no traces appear". Logging the error means a user
96
+ // running with ELASTICDASH_DEBUG=1 (or any time) sees what went wrong.
97
+ console.error('[ed_tools] failed to load elasticdash-sdk:', err)
87
98
  }
88
99
 
89
100
  // ---------------------------------------------------------------------------
@@ -103,7 +114,7 @@ export const myTool2 = edTool('myTool2', async (input: any) => {
103
114
  ### Key patterns
104
115
 
105
116
  - **`edTool(name, fn)`** wraps the function with automatic tracing, mocking, telemetry, and global registry registration so the CLI `run-tool <name>` and MCP `run_tool` can rerun it by name. Falls back to a passthrough if `elasticdash-sdk` is not installed.
106
- - **`eval('require')`** is used instead of `import()` to share the same module instance across `ed_tools.ts` and `ed_workflows.ts`. This avoids ESM/CJS dual-instance issues.
117
+ - **`createRequire(import.meta.url)`** is used instead of static `import()` to share the same module instance across `ed_tools.ts` and `ed_workflows.ts`. This avoids ESM/CJS dual-instance issues. Do not substitute `eval('require')` — that throws "require is not defined" in ESM projects (any project with `"type": "module"` in `package.json`), the catch swallows it, and the entire integration silently no-ops.
107
118
  - **`setElasticDashModule`** shares the loaded module with `ed_workflows.ts` so `edStartTrace`/`edEndTrace` use the same tracing context as `edTool`.
108
119
  - The exported name (e.g., `myTool1`) can differ from the original function name (e.g., `originalTool1`). The call sites in existing source files will be updated to use the new name in Step 4.
109
120
 
@@ -141,9 +152,20 @@ Every `ed_workflows.ts` should export `edStartTrace` and `edEndTrace`. These are
141
152
  ```ts
142
153
  // ed_workflows.ts — trace hooks (copy as-is)
143
154
 
144
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
145
- let _ed: any = null
146
- let _obsInitialised = false
155
+ // `var` (not `let`) is intentional. `ed_tools.ts` imports `setElasticDashModule`
156
+ // from this file and calls it during its own module load. If this module's
157
+ // re-export of YOUR_WORKFLOW (below) sits in a transitive import chain that
158
+ // reaches `ed_tools.ts`, ESM evaluates `ed_tools.ts` BEFORE this module's body
159
+ // runs — and `let _ed = null` would be in TDZ (temporal dead zone) at that
160
+ // moment, throwing `Cannot access '_ed' before initialization` inside
161
+ // setElasticDashModule. `var _ed` hoists with `undefined` so the assignment
162
+ // works during circular import. After this module's body runs, the value set
163
+ // during the circular call is preserved (no re-initialiser overwrites it).
164
+
165
+ // eslint-disable-next-line no-var, @typescript-eslint/no-explicit-any
166
+ var _ed: any
167
+ // eslint-disable-next-line no-var
168
+ var _obsInitialised: boolean
147
169
 
148
170
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
149
171
  export function setElasticDashModule(mod: any): void {
@@ -219,7 +241,7 @@ export const edShutdownObservability = async (): Promise<void> => {
219
241
  }
220
242
  ```
221
243
 
222
- > **Why route init through `_ed` instead of importing `initObservability` directly?** The SDK uses AsyncLocalStorage to correlate events. Both `ed_tools.ts` and `ed_workflows.ts` must share the same SDK module instance — that's why `ed_tools.ts` loads the SDK via `eval('require')` and passes it through `setElasticDashModule`. If `main.ts` does `import { initObservability } from 'elasticdash-sdk'` directly, the ESM-loaded copy is a **different module instance** from the CJS-loaded copy that `_ed` references — init writes to one store, `startTrace` reads from another, and you get `[elasticdash] startTrace: observability not initialised` at runtime. Always init through `edInitObservability` from `ed_workflows.ts`.
244
+ > **Why route init through `_ed` instead of importing `initObservability` directly?** The SDK uses AsyncLocalStorage to correlate events. Both `ed_tools.ts` and `ed_workflows.ts` must share the same SDK module instance — that's why `ed_tools.ts` loads the SDK via `createRequire(import.meta.url)` and passes it through `setElasticDashModule`. If `main.ts` does `import { initObservability } from 'elasticdash-sdk'` directly, the ESM-loaded copy is a **different module instance** from the CJS-loaded copy that `_ed` references — init writes to one store, `startTrace` reads from another, and you get `[elasticdash] startTrace: observability not initialised` at runtime. Always init through `edInitObservability` from `ed_workflows.ts`.
223
245
 
224
246
  ### Workflow exports — simple case
225
247
 
@@ -107,16 +107,22 @@ Concurrent requests with different mock configs (or no mocks at all) run in para
107
107
 
108
108
  #### Next.js + Turbopack note
109
109
 
110
- If Turbopack flags `elasticdash-sdk` as "Module not found" at build time (some configs do this for `serverExternalPackages`), use `eval('require')`:
110
+ If Turbopack flags `elasticdash-sdk` as "Module not found" at build time (some configs do this for `serverExternalPackages`), use `createRequire(import.meta.url)`:
111
111
 
112
112
  ```ts
113
+ import { createRequire } from 'node:module';
114
+ const nodeRequire = createRequire(import.meta.url);
115
+
113
116
  try {
114
- const { applyInboundMockConfig } = (eval('require') as any)('elasticdash-sdk');
117
+ const { applyInboundMockConfig } = nodeRequire('elasticdash-sdk');
115
118
  applyInboundMockConfig(request);
116
- } catch { /* SDK not installed — proceed live */ }
119
+ } catch (err) {
120
+ console.error('[mocking] failed to load elasticdash-sdk:', err);
121
+ /* SDK not installed — proceed live */
122
+ }
117
123
  ```
118
124
 
119
- This is the same pattern users already use for `initHttpRunContext` for dashboard mode. The `try/catch` makes the SDK a soft dependency: if it's not present in prod, the route still works.
125
+ This is the same pattern users already use for `initHttpRunContext` for dashboard mode. The `try/catch` makes the SDK a soft dependency: if it's not present in prod, the route still works. **Do not substitute `eval('require')`** — it silently throws in ESM projects (`"type": "module"` in `package.json`) and the catch hides the failure, leaving the route running live in what looks like mock mode.
120
126
 
121
127
  #### Polymorphic input
122
128
 
@@ -232,18 +232,17 @@ If `runWithInitializedHttpContext` is called outside `start()` (e.g., in the han
232
232
 
233
233
  ## Importing the SDK in Next.js / Turbopack
234
234
 
235
- Turbopack statically analyzes `import()` and `require()` calls, which causes `Module not found` errors for `serverExternalPackages`. Use `eval('require')` or `createRequire` to bypass this:
235
+ Turbopack statically analyzes `import()` and `require()` calls, which causes `Module not found` errors for `serverExternalPackages`. Use `createRequire(import.meta.url)` to bypass this:
236
236
 
237
237
  ```ts
238
- // Option 1: eval('require')simple, works everywhere
239
- const { wrapTool } = (eval('require') as (id: string) => any)('elasticdash-sdk')
240
-
241
- // Option 2: createRequire — cleaner, no eval
238
+ // Recommended: createRequire — works in both ESM ("type": "module") and CJS
242
239
  import { createRequire } from 'node:module'
243
- const nodeRequire = createRequire(process.cwd() + '/')
244
- const { wrapTool } = nodeRequire('elasticdash-sdk')
240
+ const nodeRequire = createRequire(import.meta.url)
241
+ const { edTool } = nodeRequire('elasticdash-sdk')
245
242
  ```
246
243
 
244
+ > **Do not use `eval('require')`.** It looks simpler but silently throws "require is not defined" in any ESM project — the typical `try/catch` wrapping it swallows the error, the SDK never loads, and the integration produces zero traces with zero logs. Use `createRequire` unconditionally.
245
+
247
246
  Also add the SDK to `serverExternalPackages` in `next.config.js`:
248
247
 
249
248
  ```js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elasticdash-sdk",
3
- "version": "0.2.7-beta",
3
+ "version": "0.2.7-beta-2",
4
4
  "description": "AI-native SDK for ElasticDash workflow testing, tracing, and observability",
5
5
  "type": "module",
6
6
  "bin": {