@forwardimpact/libharness 0.1.22 → 1.0.0
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/LICENSE +21 -201
- package/README.md +196 -80
- package/bin/fit-benchmark.js +44 -0
- package/bin/fit-harness.js +358 -0
- package/bin/fit-selfedit.js +165 -0
- package/bin/fit-trace.js +510 -0
- package/package.json +41 -11
- package/src/agent-runner.js +256 -0
- package/src/benchmark/apm-installer.js +207 -0
- package/src/benchmark/env-loader.js +158 -0
- package/src/benchmark/hook-env.js +40 -0
- package/src/benchmark/invariants.js +141 -0
- package/src/benchmark/judge.js +187 -0
- package/src/benchmark/npm-installer.js +87 -0
- package/src/benchmark/report.js +522 -0
- package/src/benchmark/result.js +127 -0
- package/src/benchmark/runner.js +583 -0
- package/src/benchmark/task-family.js +260 -0
- package/src/benchmark/workdir.js +298 -0
- package/src/commands/assert.js +153 -0
- package/src/commands/benchmark-definition.js +165 -0
- package/src/commands/benchmark-invariants.js +73 -0
- package/src/commands/benchmark-report.js +51 -0
- package/src/commands/benchmark-run.js +111 -0
- package/src/commands/by-discussion.js +94 -0
- package/src/commands/callback.js +119 -0
- package/src/commands/discuss.js +132 -0
- package/src/commands/facilitate.js +123 -0
- package/src/commands/output.js +36 -0
- package/src/commands/run.js +152 -0
- package/src/commands/supervise.js +136 -0
- package/src/commands/task-input.js +54 -0
- package/src/commands/tee.js +53 -0
- package/src/commands/trace.js +630 -0
- package/src/commands/work-tracker.js +35 -0
- package/src/cost.js +79 -0
- package/src/discuss-tools.js +173 -0
- package/src/discusser.js +394 -0
- package/src/events/github.js +161 -0
- package/src/facilitator.js +205 -0
- package/src/inbox-poller.js +81 -0
- package/src/index.js +72 -2
- package/src/judge.js +210 -0
- package/src/message-bus.js +118 -0
- package/src/orchestration-loop.js +330 -0
- package/src/orchestration-toolkit.js +441 -0
- package/src/orchestrator-helpers.js +23 -0
- package/src/profile-prompt.js +266 -0
- package/src/redaction.js +253 -0
- package/src/render/line-renderer.js +54 -0
- package/src/render/orchestrator-filter.js +19 -0
- package/src/render/palette.js +63 -0
- package/src/render/tool-hints.js +154 -0
- package/src/render/turn-renderer.js +96 -0
- package/src/reply-emitter.js +47 -0
- package/src/sequence-counter.js +21 -0
- package/src/signature-filter.js +27 -0
- package/src/supervisor.js +236 -0
- package/src/tee-writer.js +150 -0
- package/src/trace-collector.js +444 -0
- package/src/trace-github.js +473 -0
- package/src/trace-multi.js +101 -0
- package/src/trace-query.js +748 -0
- package/src/trace-render.js +211 -0
- package/src/trace-usage.js +249 -0
- package/src/fixture/assertions.js +0 -42
- package/src/fixture/cache.js +0 -50
- package/src/fixture/eval.js +0 -146
- package/src/fixture/index.js +0 -9
- package/src/fixture/pathway.js +0 -451
- package/src/fixture/services.js +0 -56
- package/src/mock/clients.js +0 -135
- package/src/mock/config.js +0 -45
- package/src/mock/data.js +0 -46
- package/src/mock/fs.js +0 -111
- package/src/mock/grpc.js +0 -94
- package/src/mock/http.js +0 -60
- package/src/mock/index.js +0 -36
- package/src/mock/infra.js +0 -219
- package/src/mock/logger.js +0 -42
- package/src/mock/observer.js +0 -74
- package/src/mock/resource-index.js +0 -95
- package/src/mock/service-callbacks.js +0 -39
- package/src/mock/services.js +0 -79
- package/src/mock/spy.js +0 -44
- package/src/mock/storage.js +0 -118
package/src/mock/data.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared test data for common testing scenarios
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// Sample request data
|
|
6
|
-
export const testRequestData = {
|
|
7
|
-
query: "test query",
|
|
8
|
-
userId: "test-user-123",
|
|
9
|
-
sessionId: "test-session-456",
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
// Sample vector data
|
|
13
|
-
export const testVectorData = [
|
|
14
|
-
{ id: "vector-1", embedding: [0.1, 0.2, 0.3], score: 0.9 },
|
|
15
|
-
{ id: "vector-2", embedding: [0.4, 0.5, 0.6], score: 0.8 },
|
|
16
|
-
{ id: "vector-3", embedding: [0.7, 0.8, 0.9], score: 0.7 },
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
// Sample message data
|
|
20
|
-
export const testMessageData = [
|
|
21
|
-
{ role: "system", content: "You are a helpful assistant." },
|
|
22
|
-
{ role: "user", content: "Hello, how are you?" },
|
|
23
|
-
{ role: "assistant", content: "I'm doing well, thank you for asking!" },
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
// Sample chunk data
|
|
27
|
-
export const testChunkData = [
|
|
28
|
-
{
|
|
29
|
-
id: "chunk-1",
|
|
30
|
-
text: "This is a sample text chunk for testing purposes.",
|
|
31
|
-
tokens: 10,
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: "chunk-2",
|
|
35
|
-
text: "Another sample chunk with different content.",
|
|
36
|
-
tokens: 8,
|
|
37
|
-
},
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
// Sample configuration data
|
|
41
|
-
export const testConfigData = {
|
|
42
|
-
host: "localhost",
|
|
43
|
-
port: 3000,
|
|
44
|
-
threshold: 0.5,
|
|
45
|
-
limit: 100,
|
|
46
|
-
};
|
package/src/mock/fs.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { spy } from "./spy.js";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a mock filesystem backed by an in-memory Map
|
|
4
|
-
* @param {Object<string, string>} files - Initial file contents keyed by path
|
|
5
|
-
* @returns {object} Mock fs with readFile, writeFile, readdir, stat, mkdir, access, copyFile
|
|
6
|
-
*/
|
|
7
|
-
export function createMockFs(files = {}) {
|
|
8
|
-
const data = new Map(Object.entries(files));
|
|
9
|
-
const dirs = new Set();
|
|
10
|
-
|
|
11
|
-
// Auto-create parent directories for initial files
|
|
12
|
-
for (const path of data.keys()) {
|
|
13
|
-
const parts = path.split("/");
|
|
14
|
-
for (let i = 1; i < parts.length; i++) {
|
|
15
|
-
dirs.add(parts.slice(0, i).join("/"));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
data,
|
|
21
|
-
dirs,
|
|
22
|
-
readFile: spy(async (path, encoding) => {
|
|
23
|
-
const content = data.get(path);
|
|
24
|
-
if (content === undefined) {
|
|
25
|
-
const err = new Error(
|
|
26
|
-
`ENOENT: no such file or directory, open '${path}'`,
|
|
27
|
-
);
|
|
28
|
-
err.code = "ENOENT";
|
|
29
|
-
throw err;
|
|
30
|
-
}
|
|
31
|
-
return encoding ? content : Buffer.from(content);
|
|
32
|
-
}),
|
|
33
|
-
writeFile: spy(async (path, content) => {
|
|
34
|
-
data.set(
|
|
35
|
-
path,
|
|
36
|
-
typeof content === "string" ? content : content.toString(),
|
|
37
|
-
);
|
|
38
|
-
}),
|
|
39
|
-
readdir: spy(async (path) => {
|
|
40
|
-
const entries = [];
|
|
41
|
-
const prefix = path.endsWith("/") ? path : `${path}/`;
|
|
42
|
-
for (const key of data.keys()) {
|
|
43
|
-
if (key.startsWith(prefix)) {
|
|
44
|
-
const rest = key.slice(prefix.length);
|
|
45
|
-
const name = rest.split("/")[0];
|
|
46
|
-
if (name && !entries.includes(name)) {
|
|
47
|
-
entries.push(name);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return entries;
|
|
52
|
-
}),
|
|
53
|
-
stat: spy(async (path) => {
|
|
54
|
-
if (data.has(path)) {
|
|
55
|
-
return { isFile: () => true, isDirectory: () => false };
|
|
56
|
-
}
|
|
57
|
-
if (dirs.has(path)) {
|
|
58
|
-
return { isFile: () => false, isDirectory: () => true };
|
|
59
|
-
}
|
|
60
|
-
const err = new Error(
|
|
61
|
-
`ENOENT: no such file or directory, stat '${path}'`,
|
|
62
|
-
);
|
|
63
|
-
err.code = "ENOENT";
|
|
64
|
-
throw err;
|
|
65
|
-
}),
|
|
66
|
-
mkdir: spy(async (path) => {
|
|
67
|
-
dirs.add(path);
|
|
68
|
-
}),
|
|
69
|
-
access: spy(async (path) => {
|
|
70
|
-
if (!data.has(path) && !dirs.has(path)) {
|
|
71
|
-
const err = new Error(
|
|
72
|
-
`ENOENT: no such file or directory, access '${path}'`,
|
|
73
|
-
);
|
|
74
|
-
err.code = "ENOENT";
|
|
75
|
-
throw err;
|
|
76
|
-
}
|
|
77
|
-
}),
|
|
78
|
-
copyFile: spy(async (src, dest) => {
|
|
79
|
-
const content = data.get(src);
|
|
80
|
-
if (content === undefined) {
|
|
81
|
-
const err = new Error(
|
|
82
|
-
`ENOENT: no such file or directory, copyFile '${src}'`,
|
|
83
|
-
);
|
|
84
|
-
err.code = "ENOENT";
|
|
85
|
-
throw err;
|
|
86
|
-
}
|
|
87
|
-
data.set(dest, content);
|
|
88
|
-
}),
|
|
89
|
-
existsSync: spy((path) => data.has(path) || dirs.has(path)),
|
|
90
|
-
readFileSync: spy((path, encoding) => {
|
|
91
|
-
const content = data.get(path);
|
|
92
|
-
if (content === undefined) {
|
|
93
|
-
const err = new Error(
|
|
94
|
-
`ENOENT: no such file or directory, open '${path}'`,
|
|
95
|
-
);
|
|
96
|
-
err.code = "ENOENT";
|
|
97
|
-
throw err;
|
|
98
|
-
}
|
|
99
|
-
return encoding ? content : Buffer.from(content);
|
|
100
|
-
}),
|
|
101
|
-
writeFileSync: spy((path, content) => {
|
|
102
|
-
data.set(
|
|
103
|
-
path,
|
|
104
|
-
typeof content === "string" ? content : content.toString(),
|
|
105
|
-
);
|
|
106
|
-
}),
|
|
107
|
-
mkdirSync: spy((path) => {
|
|
108
|
-
dirs.add(path);
|
|
109
|
-
}),
|
|
110
|
-
};
|
|
111
|
-
}
|
package/src/mock/grpc.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { spy } from "./spy.js";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a mock gRPC factory function
|
|
4
|
-
* @param {object} overrides - Method overrides
|
|
5
|
-
* @returns {Function} Mock gRPC factory
|
|
6
|
-
*/
|
|
7
|
-
export function createMockGrpcFn(overrides = {}) {
|
|
8
|
-
const mockGrpc = {
|
|
9
|
-
Server: function () {
|
|
10
|
-
return {
|
|
11
|
-
addService: spy(),
|
|
12
|
-
bindAsync: spy((uri, creds, callback) => callback(null, 5000)),
|
|
13
|
-
tryShutdown: spy((callback) => callback()),
|
|
14
|
-
...overrides.server,
|
|
15
|
-
};
|
|
16
|
-
},
|
|
17
|
-
loadPackageDefinition: spy(() => ({
|
|
18
|
-
test: { Test: { service: {} } },
|
|
19
|
-
})),
|
|
20
|
-
makeGenericClientConstructor: spy(() => function () {}),
|
|
21
|
-
ServerCredentials: {
|
|
22
|
-
createInsecure: spy(),
|
|
23
|
-
},
|
|
24
|
-
credentials: {
|
|
25
|
-
createInsecure: spy(),
|
|
26
|
-
},
|
|
27
|
-
status: {
|
|
28
|
-
OK: 0,
|
|
29
|
-
CANCELLED: 1,
|
|
30
|
-
UNKNOWN: 2,
|
|
31
|
-
INVALID_ARGUMENT: 3,
|
|
32
|
-
DEADLINE_EXCEEDED: 4,
|
|
33
|
-
NOT_FOUND: 5,
|
|
34
|
-
ALREADY_EXISTS: 6,
|
|
35
|
-
PERMISSION_DENIED: 7,
|
|
36
|
-
RESOURCE_EXHAUSTED: 8,
|
|
37
|
-
FAILED_PRECONDITION: 9,
|
|
38
|
-
ABORTED: 10,
|
|
39
|
-
OUT_OF_RANGE: 11,
|
|
40
|
-
UNIMPLEMENTED: 12,
|
|
41
|
-
INTERNAL: 13,
|
|
42
|
-
UNAVAILABLE: 14,
|
|
43
|
-
DATA_LOSS: 15,
|
|
44
|
-
UNAUTHENTICATED: 16,
|
|
45
|
-
},
|
|
46
|
-
...overrides.grpc,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const mockProtoLoader = {
|
|
50
|
-
loadSync: spy(() => ({})),
|
|
51
|
-
...overrides.protoLoader,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
return () => ({ grpc: mockGrpc, protoLoader: mockProtoLoader });
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Creates a mock gRPC Metadata class
|
|
59
|
-
*/
|
|
60
|
-
export class MockMetadata {
|
|
61
|
-
/**
|
|
62
|
-
* Creates a new MockMetadata instance
|
|
63
|
-
*/
|
|
64
|
-
constructor() {
|
|
65
|
-
this.data = new Map();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Sets a metadata key-value pair
|
|
70
|
-
* @param {string} key - The metadata key
|
|
71
|
-
* @param {string} value - The metadata value
|
|
72
|
-
*/
|
|
73
|
-
set(key, value) {
|
|
74
|
-
this.data.set(key, value);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Gets metadata value by key
|
|
79
|
-
* @param {string} key - The metadata key
|
|
80
|
-
* @returns {string[]} Array containing the value, or empty array if not found
|
|
81
|
-
*/
|
|
82
|
-
get(key) {
|
|
83
|
-
const value = this.data.get(key);
|
|
84
|
-
return value !== undefined ? [value] : [];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Returns all metadata as a plain object
|
|
89
|
-
* @returns {object} Object with all metadata key-value pairs
|
|
90
|
-
*/
|
|
91
|
-
getMap() {
|
|
92
|
-
return Object.fromEntries(this.data);
|
|
93
|
-
}
|
|
94
|
-
}
|
package/src/mock/http.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a mock HTTP request with event emitter behavior
|
|
3
|
-
* @param {object} options - Request options
|
|
4
|
-
* @returns {object} Mock request
|
|
5
|
-
*/
|
|
6
|
-
export function createMockRequest(options = {}) {
|
|
7
|
-
const { method = "GET", url = "/", body = {}, headers = {} } = options;
|
|
8
|
-
|
|
9
|
-
const bodyStr = JSON.stringify(body);
|
|
10
|
-
let dataCallback;
|
|
11
|
-
let endCallback;
|
|
12
|
-
let errorCallback;
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
method,
|
|
16
|
-
url,
|
|
17
|
-
headers,
|
|
18
|
-
on(event, callback) {
|
|
19
|
-
if (event === "data") dataCallback = callback;
|
|
20
|
-
if (event === "end") endCallback = callback;
|
|
21
|
-
if (event === "error") errorCallback = callback;
|
|
22
|
-
},
|
|
23
|
-
simulateBody() {
|
|
24
|
-
if (dataCallback) dataCallback(bodyStr);
|
|
25
|
-
if (endCallback) endCallback();
|
|
26
|
-
},
|
|
27
|
-
simulateError(err) {
|
|
28
|
-
if (errorCallback) errorCallback(err);
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Creates a mock HTTP response with tracking
|
|
35
|
-
* @returns {object} Mock response
|
|
36
|
-
*/
|
|
37
|
-
export function createMockResponse() {
|
|
38
|
-
const response = {
|
|
39
|
-
headersSent: false,
|
|
40
|
-
statusCode: null,
|
|
41
|
-
headers: {},
|
|
42
|
-
body: "",
|
|
43
|
-
chunks: [],
|
|
44
|
-
writeHead(status, headers) {
|
|
45
|
-
response.statusCode = status;
|
|
46
|
-
response.headers = headers || {};
|
|
47
|
-
response.headersSent = true;
|
|
48
|
-
},
|
|
49
|
-
write(data) {
|
|
50
|
-
response.chunks.push(data);
|
|
51
|
-
},
|
|
52
|
-
end(data) {
|
|
53
|
-
response.body = data || "";
|
|
54
|
-
},
|
|
55
|
-
getBody() {
|
|
56
|
-
return response.chunks.join("") + response.body;
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return response;
|
|
60
|
-
}
|
package/src/mock/index.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
createMockConfig,
|
|
3
|
-
createMockServiceConfig,
|
|
4
|
-
createMockExtensionConfig,
|
|
5
|
-
} from "./config.js";
|
|
6
|
-
export { createMockStorage, MockStorage } from "./storage.js";
|
|
7
|
-
export { createMockLogger, createSilentLogger } from "./logger.js";
|
|
8
|
-
export { createMockGrpcFn, MockMetadata } from "./grpc.js";
|
|
9
|
-
export { createMockRequest, createMockResponse } from "./http.js";
|
|
10
|
-
export {
|
|
11
|
-
createMockObserverFn,
|
|
12
|
-
createMockTracer,
|
|
13
|
-
createMockAuthFn,
|
|
14
|
-
} from "./observer.js";
|
|
15
|
-
|
|
16
|
-
export { createMockResourceIndex } from "./resource-index.js";
|
|
17
|
-
export {
|
|
18
|
-
createMockMemoryClient,
|
|
19
|
-
createMockLlmClient,
|
|
20
|
-
createMockAgentClient,
|
|
21
|
-
createMockTraceClient,
|
|
22
|
-
createMockVectorClient,
|
|
23
|
-
createMockGraphClient,
|
|
24
|
-
createMockToolClient,
|
|
25
|
-
} from "./clients.js";
|
|
26
|
-
export { createMockServiceCallbacks } from "./service-callbacks.js";
|
|
27
|
-
export { createMockFs } from "./fs.js";
|
|
28
|
-
export { spy } from "./spy.js";
|
|
29
|
-
export {
|
|
30
|
-
createMockSupabaseClient,
|
|
31
|
-
createTurtleHelpers,
|
|
32
|
-
createMockProcess,
|
|
33
|
-
withSilentConsole,
|
|
34
|
-
createMockS3Client,
|
|
35
|
-
createMockQueries,
|
|
36
|
-
} from "./infra.js";
|
package/src/mock/infra.js
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Additional infrastructure mocks for services/products tests.
|
|
3
|
-
*
|
|
4
|
-
* Historically each consumer inlined its own variant. See spec 620 for the
|
|
5
|
-
* call-site inventory.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Creates a mock Supabase-style client with configurable table and storage
|
|
10
|
-
* behaviour. Covers the patterns found across products/map/test/activity/*.
|
|
11
|
-
*
|
|
12
|
-
* @param {object} [options]
|
|
13
|
-
* @param {Record<string, object>} [options.tables] - Map of table name to
|
|
14
|
-
* override. Each override may expose `select`, `insert`, `upsert`, `delete`
|
|
15
|
-
* as async functions. Unspecified methods return `{ data: [], error: null }`.
|
|
16
|
-
* @param {Record<string, string>} [options.files] - Files exposed via
|
|
17
|
-
* `storage.from(...).list(prefix)` / `.download(path)`.
|
|
18
|
-
* @returns {object} Mock client and call-tracking arrays.
|
|
19
|
-
*/
|
|
20
|
-
export function createMockSupabaseClient({ tables = {}, files = {} } = {}) {
|
|
21
|
-
const calls = {
|
|
22
|
-
select: [],
|
|
23
|
-
insert: [],
|
|
24
|
-
upsert: [],
|
|
25
|
-
delete: [],
|
|
26
|
-
download: [],
|
|
27
|
-
list: [],
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function record(kind, entry) {
|
|
31
|
-
calls[kind].push(entry);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
calls,
|
|
36
|
-
from(table) {
|
|
37
|
-
const override = tables[table] ?? {};
|
|
38
|
-
return {
|
|
39
|
-
async select(...args) {
|
|
40
|
-
record("select", { table, args });
|
|
41
|
-
if (override.select) return override.select(...args);
|
|
42
|
-
return { data: [], error: null };
|
|
43
|
-
},
|
|
44
|
-
async insert(rows, opts) {
|
|
45
|
-
record("insert", { table, rows, options: opts });
|
|
46
|
-
if (override.insert) return override.insert(rows, opts);
|
|
47
|
-
return { data: rows, error: null };
|
|
48
|
-
},
|
|
49
|
-
async upsert(rows, opts) {
|
|
50
|
-
record("upsert", {
|
|
51
|
-
table,
|
|
52
|
-
rows,
|
|
53
|
-
onConflict: opts?.onConflict,
|
|
54
|
-
options: opts,
|
|
55
|
-
});
|
|
56
|
-
if (override.upsert) return override.upsert(rows, opts);
|
|
57
|
-
return { data: rows, error: null };
|
|
58
|
-
},
|
|
59
|
-
async delete(...args) {
|
|
60
|
-
record("delete", { table, args });
|
|
61
|
-
if (override.delete) return override.delete(...args);
|
|
62
|
-
return { error: null };
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
},
|
|
66
|
-
storage: {
|
|
67
|
-
from() {
|
|
68
|
-
return {
|
|
69
|
-
async list(prefix) {
|
|
70
|
-
record("list", { prefix });
|
|
71
|
-
const names = Object.keys(files)
|
|
72
|
-
.filter((k) => k.startsWith(prefix))
|
|
73
|
-
.map((k) => ({
|
|
74
|
-
name: k.slice(prefix.length),
|
|
75
|
-
created_at: "z",
|
|
76
|
-
}));
|
|
77
|
-
return { data: names, error: null };
|
|
78
|
-
},
|
|
79
|
-
async download(path) {
|
|
80
|
-
record("download", { path });
|
|
81
|
-
const content = files[path];
|
|
82
|
-
if (content === undefined) {
|
|
83
|
-
return { data: null, error: { message: "not found" } };
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
data: { text: async () => content },
|
|
87
|
-
error: null,
|
|
88
|
-
};
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Creates Turtle parsing helpers bound to an injected n3 Parser. Keeps
|
|
98
|
-
* libharness free of an n3 dependency while allowing services to share the
|
|
99
|
-
* parseQuads / findAll / findOne idiom.
|
|
100
|
-
*
|
|
101
|
-
* @param {import("n3").Parser | Function} ParserOrInstance - n3 Parser class
|
|
102
|
-
* or a pre-built parser instance.
|
|
103
|
-
* @param {object} [options]
|
|
104
|
-
* @param {string} [options.format="Turtle"] - Parser format.
|
|
105
|
-
* @returns {object} { parseQuads, findAll, findOne }
|
|
106
|
-
*/
|
|
107
|
-
export function createTurtleHelpers(
|
|
108
|
-
ParserOrInstance,
|
|
109
|
-
{ format = "Turtle" } = {},
|
|
110
|
-
) {
|
|
111
|
-
const isClass =
|
|
112
|
-
typeof ParserOrInstance === "function" &&
|
|
113
|
-
ParserOrInstance.prototype &&
|
|
114
|
-
typeof ParserOrInstance.prototype.parse === "function";
|
|
115
|
-
const parser = isClass ? new ParserOrInstance({ format }) : ParserOrInstance;
|
|
116
|
-
|
|
117
|
-
function parseQuads(turtle) {
|
|
118
|
-
return parser.parse(turtle);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function findAll(quads, { subject, predicate, object } = {}) {
|
|
122
|
-
return quads.filter(
|
|
123
|
-
(q) =>
|
|
124
|
-
(!subject || q.subject.value === subject) &&
|
|
125
|
-
(!predicate || q.predicate.value === predicate) &&
|
|
126
|
-
(!object || q.object.value === object),
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function findOne(quads, pattern) {
|
|
131
|
-
return findAll(quads, pattern)[0];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return { parseQuads, findAll, findOne };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Creates a minimal mock `process`-like object with env, stdout, stderr,
|
|
139
|
-
* exitCode, and simple write capture.
|
|
140
|
-
*
|
|
141
|
-
* @param {object} [options]
|
|
142
|
-
* @param {Record<string, string>} [options.env]
|
|
143
|
-
* @returns {object}
|
|
144
|
-
*/
|
|
145
|
-
export function createMockProcess({ env = {} } = {}) {
|
|
146
|
-
const stdout = { chunks: [], write: (s) => stdout.chunks.push(String(s)) };
|
|
147
|
-
const stderr = { chunks: [], write: (s) => stderr.chunks.push(String(s)) };
|
|
148
|
-
return {
|
|
149
|
-
env: { ...env },
|
|
150
|
-
stdout,
|
|
151
|
-
stderr,
|
|
152
|
-
exitCode: 0,
|
|
153
|
-
exit(code = 0) {
|
|
154
|
-
this.exitCode = code;
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Runs `fn` with `console.log`, `console.info`, and `console.warn` suppressed,
|
|
161
|
-
* returning whatever `fn` returns. Errors still propagate.
|
|
162
|
-
*
|
|
163
|
-
* @template T
|
|
164
|
-
* @param {() => T | Promise<T>} fn
|
|
165
|
-
* @returns {Promise<T>}
|
|
166
|
-
*/
|
|
167
|
-
export async function withSilentConsole(fn) {
|
|
168
|
-
const originals = {
|
|
169
|
-
log: console.log,
|
|
170
|
-
info: console.info,
|
|
171
|
-
warn: console.warn,
|
|
172
|
-
};
|
|
173
|
-
console.log = () => {};
|
|
174
|
-
console.info = () => {};
|
|
175
|
-
console.warn = () => {};
|
|
176
|
-
try {
|
|
177
|
-
return await fn();
|
|
178
|
-
} finally {
|
|
179
|
-
console.log = originals.log;
|
|
180
|
-
console.info = originals.info;
|
|
181
|
-
console.warn = originals.warn;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Creates a bag of async query stubs from a plain values object. A function
|
|
187
|
-
* value is passed through untouched; anything else becomes an async function
|
|
188
|
-
* returning that value. Collapses landmark-style `stubQueries` boilerplate.
|
|
189
|
-
*
|
|
190
|
-
* @param {Record<string, unknown>} values
|
|
191
|
-
* @returns {Record<string, Function>}
|
|
192
|
-
*/
|
|
193
|
-
export function createMockQueries(values = {}) {
|
|
194
|
-
const out = {};
|
|
195
|
-
for (const [key, val] of Object.entries(values)) {
|
|
196
|
-
out[key] = typeof val === "function" ? val : async () => val;
|
|
197
|
-
}
|
|
198
|
-
return out;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Creates a minimal mock S3 client that records command sends and returns a
|
|
203
|
-
* configurable response.
|
|
204
|
-
*
|
|
205
|
-
* @param {object} [options]
|
|
206
|
-
* @param {(command: object) => unknown} [options.sendFn] - Custom send handler.
|
|
207
|
-
* @returns {object} { client, sends }
|
|
208
|
-
*/
|
|
209
|
-
export function createMockS3Client({ sendFn } = {}) {
|
|
210
|
-
const sends = [];
|
|
211
|
-
return {
|
|
212
|
-
sends,
|
|
213
|
-
async send(command) {
|
|
214
|
-
sends.push(command);
|
|
215
|
-
if (sendFn) return sendFn(command);
|
|
216
|
-
return {};
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
}
|
package/src/mock/logger.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { spy } from "./spy.js";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a mock logger with call tracking
|
|
4
|
-
* @param {object} options - Logger options
|
|
5
|
-
* @param {boolean} options.captureOutput - Whether to capture log output
|
|
6
|
-
* @returns {object} Mock logger
|
|
7
|
-
*/
|
|
8
|
-
export function createMockLogger(options = {}) {
|
|
9
|
-
const logs = [];
|
|
10
|
-
const capture = options.captureOutput ?? false;
|
|
11
|
-
|
|
12
|
-
const createMethod = (level) =>
|
|
13
|
-
spy((appId, msg, attributes) => {
|
|
14
|
-
if (capture) {
|
|
15
|
-
logs.push({ level, appId, msg, attributes });
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
logs,
|
|
21
|
-
debug: createMethod("debug"),
|
|
22
|
-
info: createMethod("info"),
|
|
23
|
-
warn: createMethod("warn"),
|
|
24
|
-
error: createMethod("error"),
|
|
25
|
-
exception: createMethod("exception"),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Creates a silent logger that does nothing
|
|
31
|
-
* @returns {object} Silent logger
|
|
32
|
-
*/
|
|
33
|
-
export function createSilentLogger() {
|
|
34
|
-
const noop = () => {};
|
|
35
|
-
return {
|
|
36
|
-
debug: noop,
|
|
37
|
-
info: noop,
|
|
38
|
-
warn: noop,
|
|
39
|
-
error: noop,
|
|
40
|
-
exception: noop,
|
|
41
|
-
};
|
|
42
|
-
}
|
package/src/mock/observer.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { spy } from "./spy.js";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a mock observer factory
|
|
4
|
-
* @param {object} logger - Logger to use (optional)
|
|
5
|
-
* @returns {Function} Mock observer factory
|
|
6
|
-
*/
|
|
7
|
-
export function createMockObserverFn(logger = null) {
|
|
8
|
-
const mockLogger = logger || {
|
|
9
|
-
debug: spy(),
|
|
10
|
-
info: spy(),
|
|
11
|
-
error: spy(),
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
return () => ({
|
|
15
|
-
observeServerUnaryCall: async (_method, handler, call, callback) => {
|
|
16
|
-
return await handler(call, callback);
|
|
17
|
-
},
|
|
18
|
-
observeClientUnaryCall: async (_method, _request, fn) => {
|
|
19
|
-
return await fn();
|
|
20
|
-
},
|
|
21
|
-
observeClientStreamingCall: (_method, _request, fn) => {
|
|
22
|
-
return fn();
|
|
23
|
-
},
|
|
24
|
-
logger: () => mockLogger,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Creates a mock tracer
|
|
30
|
-
* @param {object} overrides - Method overrides
|
|
31
|
-
* @returns {object} Mock tracer
|
|
32
|
-
*/
|
|
33
|
-
export function createMockTracer(overrides = {}) {
|
|
34
|
-
return {
|
|
35
|
-
startSpan: spy((name, options = {}) => ({
|
|
36
|
-
span_id: `span-${Date.now()}`,
|
|
37
|
-
trace_id: `trace-${Date.now()}`,
|
|
38
|
-
name,
|
|
39
|
-
...options,
|
|
40
|
-
})),
|
|
41
|
-
startClientSpan: spy((_service, _method) => ({
|
|
42
|
-
span: {
|
|
43
|
-
span_id: `client-span-${Date.now()}`,
|
|
44
|
-
trace_id: `trace-${Date.now()}`,
|
|
45
|
-
},
|
|
46
|
-
metadata: { get: () => [], set: () => {} },
|
|
47
|
-
})),
|
|
48
|
-
startServerSpan: spy((_service, _method, _request, metadata) => ({
|
|
49
|
-
span_id: `server-span-${Date.now()}`,
|
|
50
|
-
trace_id: metadata?.get?.("x-trace-id")?.[0] || `trace-${Date.now()}`,
|
|
51
|
-
})),
|
|
52
|
-
getSpanContext: () => ({
|
|
53
|
-
run: (span, fn) => fn(),
|
|
54
|
-
getStore: () => null,
|
|
55
|
-
}),
|
|
56
|
-
endSpan: spy(),
|
|
57
|
-
recordError: spy(),
|
|
58
|
-
...overrides,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Creates a mock auth factory
|
|
64
|
-
* @param {object} options - Auth options
|
|
65
|
-
* @returns {Function} Mock auth factory
|
|
66
|
-
*/
|
|
67
|
-
export function createMockAuthFn(options = {}) {
|
|
68
|
-
const { isValid = true, serviceId = "test" } = options;
|
|
69
|
-
|
|
70
|
-
return () => ({
|
|
71
|
-
createClientInterceptor: () => () => {},
|
|
72
|
-
validateCall: () => ({ isValid, serviceId }),
|
|
73
|
-
});
|
|
74
|
-
}
|