@wabot-dev/framework 0.9.26 → 0.9.80
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 +27 -0
- package/dist/src/feature/chat-bot/stripAnsweredMedia.js +19 -0
- package/dist/src/feature/chat-controller/runChatControllers.js +4 -1
- package/dist/src/feature/rest-controller/runRestControllers.js +11 -6
- package/dist/src/index.d.ts +9 -1
- package/dist/src/index.js +2 -2
- package/dist/src/testing/LlmJudge.js +93 -0
- package/dist/src/testing/MockChatAdapter.js +68 -0
- package/dist/src/testing/TestChatMemory.js +73 -0
- package/dist/src/testing/asyncHarness.js +66 -0
- package/dist/src/testing/auth.js +114 -0
- package/dist/src/testing/chatBotHarness.js +88 -0
- package/dist/src/testing/chatControllerHarness.js +94 -0
- package/dist/src/testing/conformance/chatAdapterConformanceCases.js +656 -0
- package/dist/src/testing/fixtures.js +53 -0
- package/dist/src/testing/helpers.js +42 -0
- package/dist/src/testing/index.d.ts +776 -0
- package/dist/src/testing/index.js +13 -0
- package/dist/src/testing/repositories.js +34 -0
- package/dist/src/testing/restHarness.js +127 -0
- package/dist/src/testing/testImageBase64.js +5 -0
- package/dist/src/testing/validation.js +66 -0
- package/package.json +19 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { MockChatAdapter } from './MockChatAdapter.js';
|
|
2
|
+
export { TestChatMemory, TestChatRepository } from './TestChatMemory.js';
|
|
3
|
+
export { ChatBotHarness, createChatBotHarness } from './chatBotHarness.js';
|
|
4
|
+
export { ChatControllerHarness, createChatControllerHarness } from './chatControllerHarness.js';
|
|
5
|
+
export { LlmJudge, renderTranscript } from './LlmJudge.js';
|
|
6
|
+
export { botItem, documentMessage, humanItem, humanMessage, imageMessage, testImageBase64Url, testPdfBase64Url } from './fixtures.js';
|
|
7
|
+
export { chatAdapterConformanceCases } from './conformance/chatAdapterConformanceCases.js';
|
|
8
|
+
export { RestHarness, createRestHarness } from './restHarness.js';
|
|
9
|
+
export { AsyncHarness, createAsyncHarness } from './asyncHarness.js';
|
|
10
|
+
export { entityFixture, useMemoryRepositories } from './repositories.js';
|
|
11
|
+
export { TestApiKeyRepository, TestJwt, setupTestJwt } from './auth.js';
|
|
12
|
+
export { assertInvalid, assertValid, validateFixture } from './validation.js';
|
|
13
|
+
export { isValidCronSequence, wait, waitUntil } from './helpers.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { container } from '../core/injection/index.js';
|
|
3
|
+
import { MemoryRepositoryAdapter } from '../feature/repository/MemoryRepositoryAdapter.js';
|
|
4
|
+
import '../feature/repository/RepositoryMetadataStore.js';
|
|
5
|
+
import { RepositoryAdapterRegistry } from '../feature/repository/RepositoryAdapterRegistry.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Back every @repository with an in-RAM adapter (no PostgreSQL, no `.wabot/`
|
|
9
|
+
* persistence). Call it once at the top of a test file, before resolving any
|
|
10
|
+
* repository (each @repository caches its runtime on first use). Test files
|
|
11
|
+
* run in separate processes, so each file gets its own empty store.
|
|
12
|
+
*/
|
|
13
|
+
function useMemoryRepositories() {
|
|
14
|
+
const adapter = new MemoryRepositoryAdapter({ persist: false });
|
|
15
|
+
container.resolve(RepositoryAdapterRegistry).setDefault(adapter);
|
|
16
|
+
return adapter;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Build an entity in "already created" state (id and createdAt set), so
|
|
20
|
+
* tests can seed data without going through a repository create().
|
|
21
|
+
*/
|
|
22
|
+
function entityFixture(entityConstructor, data, options = {}) {
|
|
23
|
+
const createdAt = options.createdAt ?? Date.now();
|
|
24
|
+
const fullData = {
|
|
25
|
+
...data,
|
|
26
|
+
id: options.id ?? randomUUID(),
|
|
27
|
+
createdAt: createdAt instanceof Date ? createdAt.getTime() : createdAt,
|
|
28
|
+
};
|
|
29
|
+
const entity = new entityConstructor(fullData);
|
|
30
|
+
entity.validate();
|
|
31
|
+
return entity;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { entityFixture, useMemoryRepositories };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import '../feature/socket-controller/metadata/SocketControllerMetadataStore.js';
|
|
2
|
+
import { container } from '../core/injection/index.js';
|
|
3
|
+
import '../core/error/setupErrorHandlers.js';
|
|
4
|
+
import 'debug';
|
|
5
|
+
import '../core/validation/metadata/ValidationMetadataStore.js';
|
|
6
|
+
import 'socket.io';
|
|
7
|
+
import '../feature/socket/SocketServerConfig.js';
|
|
8
|
+
import '../feature/socket/SocketServerProvider.js';
|
|
9
|
+
import '../addon/auth/api-key/ApiKeyHandshakeGuardMiddleware.js';
|
|
10
|
+
import '../feature/rest-controller/metadata/RestControllerMetadataStore.js';
|
|
11
|
+
import { registerRestControllers } from '../feature/rest-controller/runRestControllers.js';
|
|
12
|
+
import '../addon/auth/api-key/ApiKeyGuardMiddleware.js';
|
|
13
|
+
import 'node:crypto';
|
|
14
|
+
import '../addon/auth/api-key/PgApiKeyRepository.js';
|
|
15
|
+
import '../addon/auth/jwt/JwtHandshakeGuardMiddleware.js';
|
|
16
|
+
import '../addon/auth/jwt/JwtGuardMiddleware.js';
|
|
17
|
+
import '../addon/auth/jwt/Jwt.js';
|
|
18
|
+
import '../addon/auth/jwt/JwtAccessAndRefreshTokenDto.js';
|
|
19
|
+
import { JwtConfig } from '../addon/auth/jwt/JwtConfig.js';
|
|
20
|
+
import '../addon/auth/jwt/JwtSigner.js';
|
|
21
|
+
import '../addon/auth/jwt/JwtTokenDto.js';
|
|
22
|
+
import '../addon/auth/jwt/PgJwtRefreshTokenRepository.js';
|
|
23
|
+
import { ExpressProvider } from '../feature/express/ExpressProvider.js';
|
|
24
|
+
import { HttpServerProvider } from '../feature/http/HttpServerProvider.js';
|
|
25
|
+
import { setupTestJwt } from './auth.js';
|
|
26
|
+
import { Container } from '../core/injection/Container.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Mounts @restController classes on a private HTTP server (ephemeral port)
|
|
30
|
+
* and exercises the real pipeline: parsers, middlewares/guards, validation
|
|
31
|
+
* and error mapping.
|
|
32
|
+
*/
|
|
33
|
+
class RestHarness {
|
|
34
|
+
container;
|
|
35
|
+
jwt;
|
|
36
|
+
server;
|
|
37
|
+
baseUrl = '';
|
|
38
|
+
constructor(options) {
|
|
39
|
+
const child = container.createChildContainer();
|
|
40
|
+
child.register(Container, { useValue: child });
|
|
41
|
+
if (options.jwt) {
|
|
42
|
+
this.jwt = setupTestJwt(options.jwt === true ? {} : options.jwt);
|
|
43
|
+
child.registerInstance(JwtConfig, this.jwt.config);
|
|
44
|
+
}
|
|
45
|
+
for (const [token, instance] of options.register ?? []) {
|
|
46
|
+
child.registerInstance(token, instance);
|
|
47
|
+
}
|
|
48
|
+
this.container = child;
|
|
49
|
+
const httpServerProvider = new HttpServerProvider();
|
|
50
|
+
const expressProvider = new ExpressProvider(httpServerProvider);
|
|
51
|
+
registerRestControllers(options.controllers, {
|
|
52
|
+
baseContainer: child,
|
|
53
|
+
expressProvider,
|
|
54
|
+
});
|
|
55
|
+
this.server = httpServerProvider.getHttpServer();
|
|
56
|
+
}
|
|
57
|
+
static async create(options) {
|
|
58
|
+
const harness = new RestHarness(options);
|
|
59
|
+
await harness.listen();
|
|
60
|
+
return harness;
|
|
61
|
+
}
|
|
62
|
+
listen() {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
this.server.once('error', reject);
|
|
65
|
+
this.server.listen(0, '127.0.0.1', () => {
|
|
66
|
+
const address = this.server.address();
|
|
67
|
+
if (!address || typeof address === 'string') {
|
|
68
|
+
reject(new Error('RestHarness: could not determine server port'));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.baseUrl = `http://127.0.0.1:${address.port}`;
|
|
72
|
+
resolve();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
get url() {
|
|
77
|
+
return this.baseUrl;
|
|
78
|
+
}
|
|
79
|
+
async request(method, path, options = {}) {
|
|
80
|
+
const url = new URL(path, this.baseUrl);
|
|
81
|
+
for (const [key, value] of Object.entries(options.query ?? {})) {
|
|
82
|
+
url.searchParams.set(key, value);
|
|
83
|
+
}
|
|
84
|
+
const headers = { ...options.headers };
|
|
85
|
+
let body;
|
|
86
|
+
if (options.body !== undefined) {
|
|
87
|
+
headers['Content-Type'] = headers['Content-Type'] ?? 'application/json';
|
|
88
|
+
body = JSON.stringify(options.body);
|
|
89
|
+
}
|
|
90
|
+
const response = await fetch(url, { method: method.toUpperCase(), headers, body });
|
|
91
|
+
const text = await response.text();
|
|
92
|
+
let parsed = text;
|
|
93
|
+
try {
|
|
94
|
+
parsed = text ? JSON.parse(text) : null;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// keep raw text when the response is not JSON
|
|
98
|
+
}
|
|
99
|
+
return { status: response.status, body: parsed, headers: response.headers };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Client that sends every request with a freshly signed Bearer token for
|
|
103
|
+
* the given authInfo (requires the jwt option).
|
|
104
|
+
*/
|
|
105
|
+
as(authInfo) {
|
|
106
|
+
const jwt = this.jwt;
|
|
107
|
+
if (!jwt) {
|
|
108
|
+
throw new Error('RestHarness: enable the jwt option to use as(authInfo)');
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
request: (method, path, options = {}) => this.request(method, path, {
|
|
112
|
+
...options,
|
|
113
|
+
headers: { Authorization: `Bearer ${jwt.sign(authInfo)}`, ...options.headers },
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async close() {
|
|
118
|
+
await new Promise((resolve, reject) => {
|
|
119
|
+
this.server.close((err) => (err ? reject(err) : resolve()));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function createRestHarness(options) {
|
|
124
|
+
return RestHarness.create(options);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export { RestHarness, createRestHarness };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Generated from wabot-test-image.jpeg (a store receipt photo, total 11.570).
|
|
2
|
+
// Embedded as base64 so the testing entrypoint works from dist without shipping binary assets.
|
|
3
|
+
const testImageBase64 = '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';
|
|
4
|
+
|
|
5
|
+
export { testImageBase64 };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import '../core/injection/index.js';
|
|
2
|
+
import '../core/validation/metadata/ValidationMetadataStore.js';
|
|
3
|
+
import { validateAndTransform } from '../core/validation/validateAndTransform.js';
|
|
4
|
+
|
|
5
|
+
function flattenValidationError(error, path = '') {
|
|
6
|
+
const out = [];
|
|
7
|
+
if (!error)
|
|
8
|
+
return out;
|
|
9
|
+
if (Array.isArray(error.items)) {
|
|
10
|
+
error.items.forEach((itemErrors, idx) => {
|
|
11
|
+
if (!itemErrors)
|
|
12
|
+
return;
|
|
13
|
+
const itemPath = `${path}[${idx}]`;
|
|
14
|
+
const list = Array.isArray(itemErrors) ? itemErrors : [itemErrors];
|
|
15
|
+
list.forEach((itemError) => out.push(...flattenValidationError(itemError, itemPath)));
|
|
16
|
+
});
|
|
17
|
+
if (out.length > 0)
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
if (error.properties && typeof error.properties === 'object') {
|
|
21
|
+
for (const propName in error.properties) {
|
|
22
|
+
const propErrors = error.properties[propName];
|
|
23
|
+
const propPath = path ? `${path}.${propName}` : propName;
|
|
24
|
+
if (Array.isArray(propErrors)) {
|
|
25
|
+
propErrors.forEach((propError) => out.push(...flattenValidationError(propError, propPath)));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (out.length > 0)
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
if (typeof error.description === 'string') {
|
|
32
|
+
out.push({ path: path || '(root)', message: error.description });
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/** Validate data against a decorated model and get flattened issues. */
|
|
37
|
+
function validateFixture(modelConstructor, data) {
|
|
38
|
+
const result = validateAndTransform(data, modelConstructor);
|
|
39
|
+
if (result.error) {
|
|
40
|
+
return { issues: flattenValidationError(result.error) };
|
|
41
|
+
}
|
|
42
|
+
return { value: result.value, issues: [] };
|
|
43
|
+
}
|
|
44
|
+
/** Assert the data is valid for the model; returns the transformed value. */
|
|
45
|
+
function assertValid(modelConstructor, data) {
|
|
46
|
+
const { value, issues } = validateFixture(modelConstructor, data);
|
|
47
|
+
if (issues.length > 0) {
|
|
48
|
+
const detail = issues.map((issue) => ` ${issue.path}: ${issue.message}`).join('\n');
|
|
49
|
+
throw new Error(`Expected ${modelConstructor.name} to be valid, but got:\n${detail}`);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
/** Assert the data is invalid; optionally that a specific path has an issue. */
|
|
54
|
+
function assertInvalid(modelConstructor, data, options = {}) {
|
|
55
|
+
const { issues } = validateFixture(modelConstructor, data);
|
|
56
|
+
if (issues.length === 0) {
|
|
57
|
+
throw new Error(`Expected ${modelConstructor.name} to be invalid, but it passed validation`);
|
|
58
|
+
}
|
|
59
|
+
if (options.path && !issues.some((issue) => issue.path === options.path)) {
|
|
60
|
+
const paths = issues.map((issue) => issue.path).join(', ');
|
|
61
|
+
throw new Error(`Expected an issue at path '${options.path}', but issues were at: ${paths}`);
|
|
62
|
+
}
|
|
63
|
+
return issues;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { assertInvalid, assertValid, validateFixture };
|
package/package.json
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wabot-dev/framework",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.80",
|
|
4
4
|
"description": "Framework for IA Chat Bots",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"module": "dist/src/index.js",
|
|
8
8
|
"types": "dist/src/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/src/index.d.ts",
|
|
12
|
+
"import": "./dist/src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./testing": {
|
|
15
|
+
"types": "./dist/src/testing/index.d.ts",
|
|
16
|
+
"import": "./dist/src/testing/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
9
19
|
"license": "MIT",
|
|
10
20
|
"repository": {
|
|
11
21
|
"type": "git",
|
|
@@ -43,10 +53,12 @@
|
|
|
43
53
|
"LICENSE.md"
|
|
44
54
|
],
|
|
45
55
|
"scripts": {
|
|
46
|
-
"build": "rollup --config rollup.config.ts --configPlugin typescript && tsup --dts-only --format esm --out-dir dist/src src/index.ts",
|
|
56
|
+
"build": "rollup --config rollup.config.ts --configPlugin typescript && tsup --dts-only --format esm --out-dir dist/src src/index.ts && tsup --dts-only --format esm --out-dir dist/src/testing src/testing/index.ts",
|
|
47
57
|
"test:units": "node --import @yucacodes/ts --test './src/**/*.unit.test.ts'",
|
|
48
58
|
"test:integration": "node --import @yucacodes/ts --import ./env.mjs --test './src/**/*.integration.test.ts'",
|
|
49
59
|
"test:multiprocess": "node --import @yucacodes/ts --import ./env.mjs --test './src/**/*.multiprocess.test.ts'",
|
|
60
|
+
"test:elia": "node --import @yucacodes/ts --test './test/elia/**/*.unit.test.ts'",
|
|
61
|
+
"test:elia:eval": "node --import @yucacodes/ts --import ./env.mjs --test './test/elia/**/*.eval.test.ts'",
|
|
50
62
|
"fmt": "prettier --write .",
|
|
51
63
|
"fmt:check": "prettier --check .",
|
|
52
64
|
"types:check": "tsc --noEmit",
|
|
@@ -62,6 +74,11 @@
|
|
|
62
74
|
"@rollup/plugin-typescript": "12.1.2",
|
|
63
75
|
"rollup": "^4.60.0"
|
|
64
76
|
},
|
|
77
|
+
"overrides": {
|
|
78
|
+
"gaxios": {
|
|
79
|
+
"uuid": "^11.1.1"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
65
82
|
"peerDependencies": {
|
|
66
83
|
"@anthropic-ai/sdk": "^0.60.0",
|
|
67
84
|
"@google/genai": "^1.16.0",
|