@flink-app/test-utils 2.0.0-alpha.56 → 2.0.0-alpha.58
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/CHANGELOG.md +51 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/requestContext.d.ts +22 -0
- package/dist/requestContext.js +86 -0
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/requestContext.ts +44 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
# @flink-app/test-utils
|
|
2
2
|
|
|
3
|
+
## 2.0.0-alpha.58
|
|
4
|
+
|
|
5
|
+
## 2.0.0-alpha.57
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
- ef7f495: Add AsyncLocalStorage for automatic user/permissions injection in tools
|
|
10
|
+
|
|
11
|
+
**New Features:**
|
|
12
|
+
|
|
13
|
+
- Tools now receive `user` and `permissions` parameters automatically from AsyncLocalStorage
|
|
14
|
+
- Declarative permissions in tool definitions - framework checks before execution
|
|
15
|
+
- No more need for explicit `agent.withUser()` bindings
|
|
16
|
+
- Context flows automatically: handler → agent → tools
|
|
17
|
+
|
|
18
|
+
**API Changes:**
|
|
19
|
+
|
|
20
|
+
- `ToolExecutor.execute()` signature: `(input, overrides?)` instead of `(input, user?, permissions?)`
|
|
21
|
+
- `FlinkTool` handler signature includes `user?` and `permissions?` parameters
|
|
22
|
+
- Permission checking supports explicit permissions without requiring user object
|
|
23
|
+
|
|
24
|
+
**Testing:**
|
|
25
|
+
|
|
26
|
+
- New test utilities: `withRequestContext()`, `createMockUser()`, `createMockRequestContext()`
|
|
27
|
+
- Override support for unit testing: `execute(input, { user, permissions })`
|
|
28
|
+
- 13 new AsyncLocalStorage integration tests
|
|
29
|
+
|
|
30
|
+
**Developer Experience:**
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Before: Manual user passing
|
|
34
|
+
await agent.withUser(req.user).execute({ message: "..." });
|
|
35
|
+
|
|
36
|
+
// After: Automatic context flow
|
|
37
|
+
await agent.execute({ message: "..." });
|
|
38
|
+
|
|
39
|
+
// Tools with declarative permissions
|
|
40
|
+
export const Tool: FlinkToolProps = {
|
|
41
|
+
permissions: ["car:read"], // ✨ Checked by framework
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handler: FlinkTool<Ctx, In, Out> = async ({
|
|
45
|
+
input,
|
|
46
|
+
ctx,
|
|
47
|
+
user,
|
|
48
|
+
permissions, // ✨ Auto-injected
|
|
49
|
+
}) => {
|
|
50
|
+
// Permission already verified - just implement logic
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
3
54
|
## 2.0.0-alpha.56
|
|
4
55
|
|
|
5
56
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RequestContext } from '@flink-app/flink';
|
|
2
|
+
/**
|
|
3
|
+
* Create a mock request context for testing
|
|
4
|
+
*/
|
|
5
|
+
export declare function createMockRequestContext(overrides?: Partial<RequestContext>): RequestContext;
|
|
6
|
+
/**
|
|
7
|
+
* Execute a function within a mocked request context
|
|
8
|
+
* Useful for testing tools and agents that use AsyncLocalStorage
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const result = await withRequestContext(
|
|
12
|
+
* { user: { id: '123', username: 'test' }, reqId: 'req-123' },
|
|
13
|
+
* async () => {
|
|
14
|
+
* return await someTool.execute({ carId: 'car-1' });
|
|
15
|
+
* }
|
|
16
|
+
* );
|
|
17
|
+
*/
|
|
18
|
+
export declare function withRequestContext<T>(context: Partial<RequestContext>, fn: () => T | Promise<T>): Promise<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Create a test user with common properties
|
|
21
|
+
*/
|
|
22
|
+
export declare function createMockUser(overrides?: any): any;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.createMockRequestContext = createMockRequestContext;
|
|
51
|
+
exports.withRequestContext = withRequestContext;
|
|
52
|
+
exports.createMockUser = createMockUser;
|
|
53
|
+
var flink_1 = require("@flink-app/flink");
|
|
54
|
+
/**
|
|
55
|
+
* Create a mock request context for testing
|
|
56
|
+
*/
|
|
57
|
+
function createMockRequestContext(overrides) {
|
|
58
|
+
return __assign({ reqId: "test-req-" + Math.random().toString(36).substring(7), timestamp: Date.now() }, overrides);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Execute a function within a mocked request context
|
|
62
|
+
* Useful for testing tools and agents that use AsyncLocalStorage
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const result = await withRequestContext(
|
|
66
|
+
* { user: { id: '123', username: 'test' }, reqId: 'req-123' },
|
|
67
|
+
* async () => {
|
|
68
|
+
* return await someTool.execute({ carId: 'car-1' });
|
|
69
|
+
* }
|
|
70
|
+
* );
|
|
71
|
+
*/
|
|
72
|
+
function withRequestContext(context, fn) {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
74
|
+
var fullContext;
|
|
75
|
+
return __generator(this, function (_a) {
|
|
76
|
+
fullContext = createMockRequestContext(context);
|
|
77
|
+
return [2 /*return*/, flink_1.requestContext.run(fullContext, fn)];
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a test user with common properties
|
|
83
|
+
*/
|
|
84
|
+
function createMockUser(overrides) {
|
|
85
|
+
return __assign({ id: "user-" + Math.random().toString(36).substring(7), username: "testuser", email: "test@example.com" }, overrides);
|
|
86
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flink-app/test-utils",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.58",
|
|
4
4
|
"description": "Test utils for Flink",
|
|
5
5
|
"author": "joel@frost.se",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"jasmine-ts": "^0.3.3",
|
|
24
24
|
"ts-node": "^10.9.2",
|
|
25
25
|
"tsc-watch": "^4.2.9",
|
|
26
|
-
"@flink-app/flink": "2.0.0-alpha.
|
|
26
|
+
"@flink-app/flink": "2.0.0-alpha.58"
|
|
27
27
|
},
|
|
28
28
|
"gitHead": "4243e3b3cd6d4e1ca001a61baa8436bf2bbe4113",
|
|
29
29
|
"scripts": {
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RequestContext, requestContext } from '@flink-app/flink';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a mock request context for testing
|
|
5
|
+
*/
|
|
6
|
+
export function createMockRequestContext(overrides?: Partial<RequestContext>): RequestContext {
|
|
7
|
+
return {
|
|
8
|
+
reqId: "test-req-" + Math.random().toString(36).substring(7),
|
|
9
|
+
timestamp: Date.now(),
|
|
10
|
+
...overrides,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Execute a function within a mocked request context
|
|
16
|
+
* Useful for testing tools and agents that use AsyncLocalStorage
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const result = await withRequestContext(
|
|
20
|
+
* { user: { id: '123', username: 'test' }, reqId: 'req-123' },
|
|
21
|
+
* async () => {
|
|
22
|
+
* return await someTool.execute({ carId: 'car-1' });
|
|
23
|
+
* }
|
|
24
|
+
* );
|
|
25
|
+
*/
|
|
26
|
+
export async function withRequestContext<T>(
|
|
27
|
+
context: Partial<RequestContext>,
|
|
28
|
+
fn: () => T | Promise<T>
|
|
29
|
+
): Promise<T> {
|
|
30
|
+
const fullContext = createMockRequestContext(context);
|
|
31
|
+
return requestContext.run(fullContext, fn);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a test user with common properties
|
|
36
|
+
*/
|
|
37
|
+
export function createMockUser(overrides?: any) {
|
|
38
|
+
return {
|
|
39
|
+
id: "user-" + Math.random().toString(36).substring(7),
|
|
40
|
+
username: "testuser",
|
|
41
|
+
email: "test@example.com",
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
}
|