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 +15 -9
- package/docs/agent-integration-guide.md +30 -8
- package/docs/partial-mocking.md +10 -4
- package/docs/workflow-modes.md +6 -7
- package/package.json +1 -1
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 `
|
|
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
|
|
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
|
-
|
|
486
|
-
|
|
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
|
-
|
|
496
|
+
} catch (err) {
|
|
497
|
+
console.error('[ed_tools] failed to load elasticdash-sdk:', err);
|
|
492
498
|
}
|
|
493
499
|
|
|
494
|
-
export const myTool =
|
|
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 = (
|
|
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
|
-
//
|
|
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
|
-
- **`
|
|
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
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
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 `
|
|
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
|
|
package/docs/partial-mocking.md
CHANGED
|
@@ -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 `
|
|
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 } = (
|
|
117
|
+
const { applyInboundMockConfig } = nodeRequire('elasticdash-sdk');
|
|
115
118
|
applyInboundMockConfig(request);
|
|
116
|
-
} catch {
|
|
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
|
|
package/docs/workflow-modes.md
CHANGED
|
@@ -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 `
|
|
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
|
-
//
|
|
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(
|
|
244
|
-
const {
|
|
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
|