@axlsdk/studio 0.20.1 → 0.21.1
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 +29 -7
- package/dist/{chunk-KQ3HBRTC.js → chunk-YGLWYDQ3.js} +11 -4
- package/dist/chunk-YGLWYDQ3.js.map +1 -0
- package/dist/cli.cjs +92 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +83 -7
- package/dist/cli.js.map +1 -1
- package/dist/middleware.cjs +18 -5
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +8 -0
- package/dist/middleware.d.ts +8 -0
- package/dist/middleware.js +9 -3
- package/dist/middleware.js.map +1 -1
- package/dist/server/index.cjs +10 -3
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-KQ3HBRTC.js.map +0 -1
package/README.md
CHANGED
|
@@ -68,7 +68,9 @@ Your application imports from `src/runtime.ts` directly. Studio discovers everyt
|
|
|
68
68
|
npx @axlsdk/studio --open
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
This loads your config
|
|
71
|
+
This loads your config and starts the server on `http://127.0.0.1:4400`. The
|
|
72
|
+
standalone CLI binds only to IPv4 loopback, emits no CORS headers, and rejects
|
|
73
|
+
non-local HTTP hosts and browser origins across both REST and WebSocket routes.
|
|
72
74
|
|
|
73
75
|
## CLI Options
|
|
74
76
|
|
|
@@ -77,12 +79,24 @@ axl-studio [options]
|
|
|
77
79
|
|
|
78
80
|
Options:
|
|
79
81
|
--port <number> Server port (default: 4400)
|
|
82
|
+
--dangerously-bind <ip> Bind for a loopback-published container/local-forward tunnel
|
|
80
83
|
--config <path> Path to config file (default: auto-detect)
|
|
81
84
|
--conditions <list> Comma-separated Node.js import conditions (e.g., development)
|
|
85
|
+
--read-only Disable mutating endpoints
|
|
82
86
|
--open Auto-open browser
|
|
83
87
|
-h, --help Show help
|
|
84
88
|
```
|
|
85
89
|
|
|
90
|
+
For a container or devcontainer, bind the published host port to loopback and
|
|
91
|
+
make only the container listener broad:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
docker run -p 127.0.0.1:4400:4400 ... axl-studio --dangerously-bind 0.0.0.0
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The Host/Origin guard remains active. Do not publish that port on a public or
|
|
98
|
+
LAN interface; standalone Studio has no user authentication.
|
|
99
|
+
|
|
86
100
|
The `--conditions` flag is useful in monorepos where workspace packages use the `"development"` export condition to point at source instead of built dist files. Pass `--conditions development` to resolve imports through source paths.
|
|
87
101
|
|
|
88
102
|
**Note:** `--conditions` only applies to ESM `import()` resolution. Transitive `require()` calls from packages without `"type": "module"` bypass the hook and use default conditions. If a dependency loads via CJS, it will still resolve from `dist/` regardless of the flag.
|
|
@@ -179,24 +193,32 @@ const studio = createStudioMiddleware({
|
|
|
179
193
|
runtime,
|
|
180
194
|
basePath: '/studio',
|
|
181
195
|
// WebSocket upgrades bypass Express middleware — always authenticate here.
|
|
182
|
-
verifyUpgrade: (req) =>
|
|
183
|
-
const url = new URL(req.url!, `http://${req.headers.host}`);
|
|
184
|
-
return url.searchParams.get('token') === process.env.MY_SECRET;
|
|
185
|
-
},
|
|
196
|
+
verifyUpgrade: (req) => authenticateStudioRequest(req)?.isAdmin === true,
|
|
186
197
|
});
|
|
187
198
|
|
|
188
199
|
const app = express();
|
|
189
|
-
|
|
200
|
+
const authenticateStudioHttp: express.RequestHandler = (req, res, next) => {
|
|
201
|
+
if (authenticateStudioRequest(req)?.isAdmin !== true) return res.sendStatus(403);
|
|
202
|
+
next();
|
|
203
|
+
};
|
|
204
|
+
app.use('/studio', authenticateStudioHttp, studio.handler);
|
|
190
205
|
const server = app.listen(3000);
|
|
191
206
|
studio.upgradeWebSocket(server); // required for live data
|
|
192
207
|
```
|
|
193
208
|
|
|
194
|
-
Key options: `readOnly` (disable mutating endpoints for production monitoring), `evals` (lazy-load eval files), `filterTraceEvent` (per-tenant broadcast scoping), `bufferCaps` (WS replay-buffer limits). `basePath` must match your framework's mount path.
|
|
209
|
+
Key options: `readOnly` (disable mutating endpoints for production monitoring), `evals` (lazy-load eval files), `filterTraceEvent` (per-tenant broadcast scoping), `bufferCaps` (WS replay-buffer limits). `basePath` must match your framework's mount path. In production, `upgradeWebSocket()` refuses to attach without `verifyUpgrade`; `dangerouslyAllowUnauthenticatedWebSockets` is the explicit escape hatch only when an outer upgrade gate is independently guaranteed.
|
|
195
210
|
|
|
196
211
|
**See [`docs/studio-api.md`](../../docs/studio-api.md) for the full reference:** every REST endpoint, the WebSocket protocol, the complete middleware options/return tables, NestJS/Fastify/Hono examples, host body-limit guidance, lazy eval loading, multi-tenant setup, and the internal architecture.
|
|
197
212
|
|
|
198
213
|
## Security
|
|
199
214
|
|
|
215
|
+
- **Treat Studio as an administrative surface, never as a public application
|
|
216
|
+
API.** Agent routes intentionally expose resolved system prompts, tool
|
|
217
|
+
descriptions, schemas, and runtime configuration. `trace.redact` protects
|
|
218
|
+
user/model observability content; it is not authentication and does not hide
|
|
219
|
+
static agent configuration.
|
|
220
|
+
- Protect the Studio HTTP mount with your framework's authentication and
|
|
221
|
+
authorization middleware.
|
|
200
222
|
- **Always** provide `verifyUpgrade` — WebSocket upgrades bypass Express/Fastify/Koa middleware, so your auth middleware does **not** protect WebSocket connections.
|
|
201
223
|
- Consider `readOnly: true` for production monitoring — view traces, costs, and schemas without execution capability.
|
|
202
224
|
- CORS is not applied in embedded mode — the host framework owns CORS policy.
|
|
@@ -1363,7 +1363,10 @@ function createSessionRoutes(connMgr) {
|
|
|
1363
1363
|
const body = await c.req.json();
|
|
1364
1364
|
const session = runtime.session(id);
|
|
1365
1365
|
const result = await session.send(body.workflow, body.message);
|
|
1366
|
-
return c.json({
|
|
1366
|
+
return c.json({
|
|
1367
|
+
ok: true,
|
|
1368
|
+
data: { result: redactValue(result, runtime.isRedactEnabled()) }
|
|
1369
|
+
});
|
|
1367
1370
|
});
|
|
1368
1371
|
app5.post("/sessions/:id/stream", async (c) => {
|
|
1369
1372
|
const runtime = c.get("runtime");
|
|
@@ -1372,9 +1375,13 @@ function createSessionRoutes(connMgr) {
|
|
|
1372
1375
|
const session = runtime.session(id);
|
|
1373
1376
|
const stream = await session.stream(body.workflow, body.message);
|
|
1374
1377
|
const executionId = `session-${id}-${Date.now()}`;
|
|
1378
|
+
const redactOn = runtime.isRedactEnabled();
|
|
1375
1379
|
(async () => {
|
|
1376
1380
|
for await (const event of stream) {
|
|
1377
|
-
connMgr.broadcastWithWildcard(
|
|
1381
|
+
connMgr.broadcastWithWildcard(
|
|
1382
|
+
`execution:${executionId}`,
|
|
1383
|
+
redactStreamEvent(event, redactOn)
|
|
1384
|
+
);
|
|
1378
1385
|
}
|
|
1379
1386
|
})();
|
|
1380
1387
|
return c.json({ ok: true, data: { executionId, streaming: true } });
|
|
@@ -16080,7 +16087,7 @@ function createServer(options) {
|
|
|
16080
16087
|
emptyState: emptyEvalTrendData,
|
|
16081
16088
|
windows
|
|
16082
16089
|
});
|
|
16083
|
-
if (options.cors
|
|
16090
|
+
if (options.cors === true) {
|
|
16084
16091
|
app5.use("*", cors());
|
|
16085
16092
|
}
|
|
16086
16093
|
app5.onError(errorHandler);
|
|
@@ -16239,4 +16246,4 @@ export {
|
|
|
16239
16246
|
EvalAggregator,
|
|
16240
16247
|
createServer
|
|
16241
16248
|
};
|
|
16242
|
-
//# sourceMappingURL=chunk-
|
|
16249
|
+
//# sourceMappingURL=chunk-YGLWYDQ3.js.map
|