@ontrails/testing 1.0.0-beta.14 → 1.0.0-beta.16

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +12 -12
  3. package/package.json +15 -6
  4. package/src/all.ts +153 -16
  5. package/src/assertions.ts +253 -0
  6. package/src/context.ts +67 -38
  7. package/src/contracts.ts +15 -24
  8. package/src/crosses.ts +93 -51
  9. package/src/detours.ts +155 -18
  10. package/src/effective-examples.ts +350 -0
  11. package/src/examples.ts +139 -63
  12. package/src/harness-cli.ts +19 -11
  13. package/src/harness-mcp.ts +9 -8
  14. package/src/index.ts +14 -4
  15. package/src/logger.ts +3 -1
  16. package/src/scenario.ts +368 -0
  17. package/src/signals.ts +221 -0
  18. package/src/types.ts +64 -6
  19. package/.turbo/turbo-build.log +0 -1
  20. package/.turbo/turbo-lint.log +0 -3
  21. package/.turbo/turbo-typecheck.log +0 -1
  22. package/dist/all.d.ts +0 -31
  23. package/dist/all.d.ts.map +0 -1
  24. package/dist/all.js +0 -47
  25. package/dist/all.js.map +0 -1
  26. package/dist/assertions.d.ts +0 -49
  27. package/dist/assertions.d.ts.map +0 -1
  28. package/dist/assertions.js +0 -84
  29. package/dist/assertions.js.map +0 -1
  30. package/dist/context.d.ts +0 -75
  31. package/dist/context.d.ts.map +0 -1
  32. package/dist/context.js +0 -107
  33. package/dist/context.js.map +0 -1
  34. package/dist/contracts.d.ts +0 -17
  35. package/dist/contracts.d.ts.map +0 -1
  36. package/dist/contracts.js +0 -71
  37. package/dist/contracts.js.map +0 -1
  38. package/dist/crosses.d.ts +0 -38
  39. package/dist/crosses.d.ts.map +0 -1
  40. package/dist/crosses.js +0 -213
  41. package/dist/crosses.js.map +0 -1
  42. package/dist/detours.d.ts +0 -12
  43. package/dist/detours.d.ts.map +0 -1
  44. package/dist/detours.js +0 -30
  45. package/dist/detours.js.map +0 -1
  46. package/dist/examples.d.ts +0 -23
  47. package/dist/examples.d.ts.map +0 -1
  48. package/dist/examples.js +0 -202
  49. package/dist/examples.js.map +0 -1
  50. package/dist/follows.d.ts +0 -38
  51. package/dist/follows.d.ts.map +0 -1
  52. package/dist/follows.js +0 -212
  53. package/dist/follows.js.map +0 -1
  54. package/dist/harness-cli.d.ts +0 -21
  55. package/dist/harness-cli.d.ts.map +0 -1
  56. package/dist/harness-cli.js +0 -200
  57. package/dist/harness-cli.js.map +0 -1
  58. package/dist/harness-mcp.d.ts +0 -21
  59. package/dist/harness-mcp.d.ts.map +0 -1
  60. package/dist/harness-mcp.js +0 -53
  61. package/dist/harness-mcp.js.map +0 -1
  62. package/dist/index.d.ts +0 -16
  63. package/dist/index.d.ts.map +0 -1
  64. package/dist/index.js +0 -16
  65. package/dist/index.js.map +0 -1
  66. package/dist/logger.d.ts +0 -15
  67. package/dist/logger.d.ts.map +0 -1
  68. package/dist/logger.js +0 -87
  69. package/dist/logger.js.map +0 -1
  70. package/dist/trail.d.ts +0 -20
  71. package/dist/trail.d.ts.map +0 -1
  72. package/dist/trail.js +0 -80
  73. package/dist/trail.js.map +0 -1
  74. package/dist/types.d.ts +0 -80
  75. package/dist/types.d.ts.map +0 -1
  76. package/dist/types.js +0 -5
  77. package/dist/types.js.map +0 -1
  78. package/src/__tests__/all.test.ts +0 -135
  79. package/src/__tests__/context.test.ts +0 -150
  80. package/src/__tests__/contracts.test.ts +0 -185
  81. package/src/__tests__/crosses.test.ts +0 -587
  82. package/src/__tests__/detours.test.ts +0 -55
  83. package/src/__tests__/examples.test.ts +0 -534
  84. package/src/__tests__/harness-cli.test.ts +0 -66
  85. package/src/__tests__/logger.test.ts +0 -136
  86. package/src/__tests__/trail.test.ts +0 -99
  87. package/tsconfig.json +0 -9
  88. package/tsconfig.tsbuildinfo +0 -1
package/dist/follows.js DELETED
@@ -1,212 +0,0 @@
1
- /**
2
- * testFollows — composition-aware scenario testing for trails with follow.
3
- *
4
- * Tests the follow graph: which trails were followed, in what order,
5
- * and supports failure injection from followed trail examples.
6
- */
7
- import { describe, expect, test } from 'bun:test';
8
- import { executeTrail, InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
9
- import { assertErrorMatch, assertFullMatch, assertSchemaMatch, } from './assertions.js';
10
- import { mergeServiceOverrides, mergeTestContext } from './context.js';
11
- const collectDeclaredServices = (trailDef, trailsMap) => {
12
- const seenServiceIds = new Set();
13
- const seenTrailIds = new Set();
14
- const services = [];
15
- const collect = (candidate) => {
16
- for (const declaredService of candidate.services) {
17
- if (seenServiceIds.has(declaredService.id)) {
18
- continue;
19
- }
20
- seenServiceIds.add(declaredService.id);
21
- services.push(declaredService);
22
- }
23
- };
24
- const visit = (candidate) => {
25
- if (seenTrailIds.has(candidate.id)) {
26
- return;
27
- }
28
- seenTrailIds.add(candidate.id);
29
- collect(candidate);
30
- for (const followedId of candidate.follow) {
31
- const followedTrail = trailsMap?.get(followedId);
32
- if (followedTrail) {
33
- visit(followedTrail);
34
- }
35
- }
36
- };
37
- visit(trailDef);
38
- return services;
39
- };
40
- const resolveMockServices = async (trailDef, trailsMap) => {
41
- const services = {};
42
- for (const declaredService of collectDeclaredServices(trailDef, trailsMap)) {
43
- if (!declaredService.mock) {
44
- continue;
45
- }
46
- services[declaredService.id] = await declaredService.mock();
47
- }
48
- return services;
49
- };
50
- // ---------------------------------------------------------------------------
51
- // Injection helpers
52
- // ---------------------------------------------------------------------------
53
- /**
54
- * Find an error example on a trail by name or description substring.
55
- */
56
- const findErrorExample = (trailDef, description) => {
57
- const example = trailDef.examples?.find((ex) => ex.error !== undefined &&
58
- (ex.description?.includes(description) || ex.name.includes(description)));
59
- return example?.error;
60
- };
61
- /**
62
- * Try to inject an error from a followed trail's example.
63
- * Returns undefined when no injection is configured for this trail ID.
64
- */
65
- const tryInjectError = (id, scenario, trailsMap) => {
66
- const injection = scenario.injectFromExample?.[id];
67
- if (injection === undefined) {
68
- return undefined;
69
- }
70
- const trailDef = trailsMap?.get(id);
71
- if (trailDef === undefined) {
72
- return Result.err(new InternalError(`Cannot inject: trail "${id}" not in topo`));
73
- }
74
- const errorName = findErrorExample(trailDef, injection);
75
- if (errorName === undefined) {
76
- return Result.err(new InternalError(`No error example matching "${injection}" on trail "${id}"`));
77
- }
78
- return Result.err(new Error(errorName));
79
- };
80
- /**
81
- * Execute a trail from the map, validating input first.
82
- */
83
- const executeFromMap = (id, input, trailsMap, ctx, services, follow) => {
84
- const trailDef = trailsMap?.get(id);
85
- if (trailDef === undefined) {
86
- return undefined;
87
- }
88
- const nestedCtx = follow ? { ...ctx, follow } : ctx;
89
- return executeTrail(trailDef, input, {
90
- ctx: nestedCtx,
91
- services,
92
- });
93
- };
94
- // ---------------------------------------------------------------------------
95
- // Follow factory
96
- // ---------------------------------------------------------------------------
97
- /**
98
- * Build a recording follow function that optionally injects errors.
99
- */
100
- const createRecordingFollow = (trace, scenario, trailsMap, baseFollow, ctx, services) => {
101
- // The generic O on FollowFn is erased at runtime; the cast is safe
102
- // because callers narrow via isOk/isErr before accessing the value.
103
- const follow = (id, input) => {
104
- trace.push({ id, input });
105
- const injected = tryInjectError(id, scenario, trailsMap);
106
- if (injected !== undefined) {
107
- return Promise.resolve(injected);
108
- }
109
- if (baseFollow !== undefined) {
110
- return baseFollow(id, input);
111
- }
112
- const executed = executeFromMap(id, input, trailsMap, ctx, services, follow);
113
- if (executed !== undefined) {
114
- return Promise.resolve(executed);
115
- }
116
- return Promise.resolve(Result.ok());
117
- };
118
- return follow;
119
- };
120
- // ---------------------------------------------------------------------------
121
- // Scenario assertions
122
- // ---------------------------------------------------------------------------
123
- const assertScenarioResult = (result, scenario, trailDef) => {
124
- if (scenario.expectValue !== undefined) {
125
- assertFullMatch(result, scenario.expectValue);
126
- }
127
- else if (scenario.expectErr !== undefined) {
128
- assertErrorMatch(result, scenario.expectErr, scenario.expectErrMessage);
129
- }
130
- else if (scenario.expectErrMessage !== undefined) {
131
- expect(result.isErr()).toBe(true);
132
- if (result.isErr()) {
133
- expect(result.error.message).toContain(scenario.expectErrMessage);
134
- }
135
- }
136
- else if (scenario.expectOk === true) {
137
- expect(result.isOk()).toBe(true);
138
- assertSchemaMatch(result, trailDef.output);
139
- }
140
- };
141
- const assertFollowTrace = (trace, scenario) => {
142
- if (scenario.expectFollowed !== undefined) {
143
- const followedIds = trace.map((r) => r.id);
144
- expect(followedIds).toEqual([...scenario.expectFollowed]);
145
- }
146
- if (scenario.expectFollowedCount !== undefined) {
147
- const counts = {};
148
- for (const record of trace) {
149
- counts[record.id] = (counts[record.id] ?? 0) + 1;
150
- }
151
- expect(counts).toEqual({ ...scenario.expectFollowedCount });
152
- }
153
- };
154
- const handleValidationError = (validated, scenario) => {
155
- if (!validated.isErr()) {
156
- return false;
157
- }
158
- if (scenario.expectErr === ValidationError) {
159
- expect(validated.error).toBeInstanceOf(ValidationError);
160
- if (scenario.expectErrMessage !== undefined) {
161
- expect(validated.error.message).toContain(scenario.expectErrMessage);
162
- }
163
- return true;
164
- }
165
- throw new Error(`Input validation failed unexpectedly: ${validated.error.message}`);
166
- };
167
- // ---------------------------------------------------------------------------
168
- // Scenario runner
169
- // ---------------------------------------------------------------------------
170
- const buildTestContext = (scenario, ctx, trailsMap, services) => {
171
- const trace = [];
172
- const baseCtx = mergeTestContext(ctx);
173
- const follow = createRecordingFollow(trace, scenario, trailsMap, baseCtx.follow, baseCtx, services);
174
- return { testCtx: { ...baseCtx, follow }, trace };
175
- };
176
- const runScenario = async (trailDef, scenario, ctx, trailsMap, services) => {
177
- const validated = validateInput(trailDef.input, scenario.input);
178
- if (handleValidationError(validated, scenario)) {
179
- return;
180
- }
181
- const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap, services);
182
- const result = await executeTrail(trailDef, scenario.input, {
183
- ctx: testCtx,
184
- services,
185
- });
186
- assertFollowTrace(trace, scenario);
187
- assertScenarioResult(result, scenario, trailDef);
188
- };
189
- /**
190
- * Generate a describe block for a composition trail with one test per scenario.
191
- *
192
- * @example
193
- * ```ts
194
- * testFollows(onboardTrail, [
195
- * {
196
- * description: "follows add then relate",
197
- * input: { name: "Alpha" },
198
- * expectOk: true,
199
- * expectFollowed: ["entity.add", "entity.relate"],
200
- * },
201
- * ]);
202
- * ```
203
- */
204
- export const testFollows = (trailDef, scenarios, options) => {
205
- describe(trailDef.id, () => {
206
- test.each([...scenarios])('$description', async (scenario) => {
207
- const services = mergeServiceOverrides(await resolveMockServices(trailDef, options?.trails), options?.ctx, options?.services);
208
- await runScenario(trailDef, scenario, options?.ctx, options?.trails, services);
209
- });
210
- });
211
- };
212
- //# sourceMappingURL=follows.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"follows.js","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"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"}
@@ -1,21 +0,0 @@
1
- /**
2
- * CLI integration test harness.
3
- *
4
- * Builds CLI commands from an App, executes them in-process,
5
- * and captures stdout/stderr.
6
- */
7
- import type { CliHarness, CliHarnessOptions } from './types.js';
8
- /**
9
- * Create a CLI harness for integration testing.
10
- *
11
- * Builds commands from the app's topo and provides a `run()` method
12
- * that parses command strings and executes them in-process.
13
- *
14
- * ```ts
15
- * const harness = createCliHarness({ app });
16
- * const result = await harness.run("entity show --name Alpha --output json");
17
- * expect(result.exitCode).toBe(0);
18
- * ```
19
- */
20
- export declare const createCliHarness: (options: CliHarnessOptions) => CliHarness;
21
- //# sourceMappingURL=harness-cli.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"harness-cli.d.ts","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AA4PpB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,iBAAiB,KAAG,UAM7D,CAAC"}
@@ -1,200 +0,0 @@
1
- /**
2
- * CLI integration test harness.
3
- *
4
- * Builds CLI commands from an App, executes them in-process,
5
- * and captures stdout/stderr.
6
- */
7
- import { buildCliCommands } from '@ontrails/cli';
8
- import { createTestContext } from './context.js';
9
- // ---------------------------------------------------------------------------
10
- // Tokenizer
11
- // ---------------------------------------------------------------------------
12
- /** Parse a command string into tokens (simple split, no quoting support). */
13
- const parseCommandString = (input) => input
14
- .trim()
15
- .split(/\s+/)
16
- .filter((s) => s.length > 0);
17
- // ---------------------------------------------------------------------------
18
- // Command resolution
19
- // ---------------------------------------------------------------------------
20
- const matchesPath = (path, tokens) => path.length <= tokens.length &&
21
- path.every((segment, index) => tokens[index] === segment);
22
- /** Resolve a command from tokens using the longest matching command path. */
23
- const resolveCommand = (commands, tokens) => {
24
- if (tokens.length === 0) {
25
- return undefined;
26
- }
27
- const [match] = commands
28
- .filter((command) => matchesPath(command.path, tokens))
29
- .toSorted((a, b) => b.path.length - a.path.length);
30
- if (match === undefined) {
31
- return undefined;
32
- }
33
- return { command: match, flagTokens: tokens.slice(match.path.length) };
34
- };
35
- // ---------------------------------------------------------------------------
36
- // Flag parsing
37
- // ---------------------------------------------------------------------------
38
- /** Parse a value flag (--key value) and return new index. */
39
- const parseValueFlag = (key, next, flags) => {
40
- const num = Number(next);
41
- flags[key] = Number.isNaN(num) ? next : num;
42
- };
43
- /** Parse a single flag token and advance the index. */
44
- const parseSingleFlag = (tokens, i, flags) => {
45
- const token = tokens[i];
46
- if (token === undefined || !token.startsWith('--')) {
47
- return i + 1;
48
- }
49
- const key = token.slice(2);
50
- const next = tokens[i + 1];
51
- if (next !== undefined && !next.startsWith('-')) {
52
- parseValueFlag(key, next, flags);
53
- return i + 2;
54
- }
55
- flags[key] = true;
56
- return i + 1;
57
- };
58
- /** Parse flag tokens into a record. */
59
- const parseFlagTokens = (tokens) => {
60
- const flags = {};
61
- let i = 0;
62
- while (i < tokens.length) {
63
- i = parseSingleFlag(tokens, i, flags);
64
- }
65
- return flags;
66
- };
67
- /** Create interceptors for stdout/stderr capture. */
68
- const captureStreams = () => {
69
- let stdout = '';
70
- let stderr = '';
71
- const origStdoutWrite = process.stdout.write;
72
- const origStderrWrite = process.stderr.write;
73
- process.stdout.write = ((chunk) => {
74
- stdout +=
75
- typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk);
76
- return true;
77
- });
78
- process.stderr.write = ((chunk) => {
79
- stderr +=
80
- typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk);
81
- return true;
82
- });
83
- return {
84
- getStderr: () => stderr,
85
- getStdout: () => stdout,
86
- restore: () => {
87
- process.stdout.write = origStdoutWrite;
88
- process.stderr.write = origStderrWrite;
89
- },
90
- writeStdout: (text) => {
91
- stdout += text;
92
- },
93
- };
94
- };
95
- // ---------------------------------------------------------------------------
96
- // Output formatting
97
- // ---------------------------------------------------------------------------
98
- /** Try to parse a string as JSON, returning undefined on failure. */
99
- const tryParseJson = (text) => {
100
- try {
101
- return JSON.parse(text);
102
- }
103
- catch {
104
- return undefined;
105
- }
106
- };
107
- /** Format result value into stdout and build the CLI result. */
108
- const formatSuccessResult = (value, flags, streams) => {
109
- const outputMode = flags['output'] ?? (flags['json'] === true ? 'json' : 'text');
110
- if (outputMode === 'json') {
111
- const jsonStr = `${JSON.stringify(value, null, 2)}\n`;
112
- streams.writeStdout(jsonStr);
113
- return {
114
- exitCode: 0,
115
- json: tryParseJson(jsonStr),
116
- stderr: streams.getStderr(),
117
- stdout: streams.getStdout(),
118
- };
119
- }
120
- const formatted = typeof value === 'string'
121
- ? `${value}\n`
122
- : `${JSON.stringify(value, null, 2)}\n`;
123
- streams.writeStdout(formatted);
124
- return {
125
- exitCode: 0,
126
- json: tryParseJson(streams.getStdout().trim()),
127
- stderr: streams.getStderr(),
128
- stdout: streams.getStdout(),
129
- };
130
- };
131
- // ---------------------------------------------------------------------------
132
- // Execute command
133
- // ---------------------------------------------------------------------------
134
- /** Build an error result from a caught exception. */
135
- const buildErrorResult = (error, streams) => {
136
- streams.restore();
137
- const message = error instanceof Error ? error.message : String(error);
138
- return {
139
- exitCode: 1,
140
- stderr: streams.getStderr() || message,
141
- stdout: streams.getStdout(),
142
- };
143
- };
144
- /** Execute a resolved command and return the result. */
145
- const executeCommand = async (command, flags, streams) => {
146
- const ctx = createTestContext();
147
- const result = await command.execute({}, flags, ctx);
148
- streams.restore();
149
- if (result.isErr()) {
150
- return {
151
- exitCode: 1,
152
- stderr: streams.getStderr() || result.error.message,
153
- stdout: streams.getStdout(),
154
- };
155
- }
156
- return formatSuccessResult(result.value, flags, streams);
157
- };
158
- /** Run the full command pipeline: resolve, parse, execute. */
159
- const runCommand = async (commands, commandString) => {
160
- const parts = parseCommandString(commandString);
161
- const resolved = resolveCommand(commands, parts);
162
- if (resolved === undefined) {
163
- return {
164
- exitCode: 1,
165
- stderr: `Unknown command: ${commandString}`,
166
- stdout: '',
167
- };
168
- }
169
- const { command, flagTokens } = resolved;
170
- const flags = parseFlagTokens(flagTokens);
171
- const streams = captureStreams();
172
- try {
173
- return await executeCommand(command, flags, streams);
174
- }
175
- catch (error) {
176
- return buildErrorResult(error, streams);
177
- }
178
- };
179
- // ---------------------------------------------------------------------------
180
- // createCliHarness
181
- // ---------------------------------------------------------------------------
182
- /**
183
- * Create a CLI harness for integration testing.
184
- *
185
- * Builds commands from the app's topo and provides a `run()` method
186
- * that parses command strings and executes them in-process.
187
- *
188
- * ```ts
189
- * const harness = createCliHarness({ app });
190
- * const result = await harness.run("entity show --name Alpha --output json");
191
- * expect(result.exitCode).toBe(0);
192
- * ```
193
- */
194
- export const createCliHarness = (options) => {
195
- const commands = buildCliCommands(options.app);
196
- return {
197
- run: (commandString) => runCommand(commands, commandString),
198
- };
199
- };
200
- //# sourceMappingURL=harness-cli.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"harness-cli.js","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOjD,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,6EAA6E;AAC7E,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAY,EAAE,CACrD,KAAK;KACF,IAAI,EAAE;KACN,KAAK,CAAC,KAAK,CAAC;KACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAEjC,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,WAAW,GAAG,CAClB,IAAuB,EACvB,MAAyB,EAChB,EAAE,CACX,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;IAC5B,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAC;AAE5D,6EAA6E;AAC7E,MAAM,cAAc,GAAG,CACrB,QAAsB,EACtB,MAAgB,EAC2C,EAAE;IAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ;SACrB,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;SACtD,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAErD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACzE,CAAC,CAAC;AAEF,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,6DAA6D;AAC7D,MAAM,cAAc,GAAG,CACrB,GAAW,EACX,IAAY,EACZ,KAA8B,EACxB,EAAE;IACR,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9C,CAAC,CAAC;AAEF,uDAAuD;AACvD,MAAM,eAAe,GAAG,CACtB,MAAgB,EAChB,CAAS,EACT,KAA8B,EACtB,EAAE;IACV,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAE3B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAChD,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAClB,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC,CAAC;AAEF,uCAAuC;AACvC,MAAM,eAAe,GAAG,CAAC,MAAgB,EAA2B,EAAE;IACpE,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QACzB,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAaF,qDAAqD;AACrD,MAAM,cAAc,GAAG,GAAoB,EAAE;IAC3C,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAC7C,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;IAE7C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAA0B,EAAW,EAAE;QAC9D,MAAM;YACJ,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC,CAAgC,CAAC;IAElC,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAA0B,EAAW,EAAE;QAC9D,MAAM;YACJ,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC,CAAgC,CAAC;IAElC,OAAO;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM;QACvB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM;QACvB,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,eAAe,CAAC;YACvC,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,eAAe,CAAC;QACzC,CAAC;QACD,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE;YAC5B,MAAM,IAAI,IAAI,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,qEAAqE;AACrE,MAAM,YAAY,GAAG,CAAC,IAAY,EAAW,EAAE;IAC7C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF,gEAAgE;AAChE,MAAM,mBAAmB,GAAG,CAC1B,KAAc,EACd,KAA8B,EAC9B,OAAwB,EACN,EAAE;IACpB,MAAM,UAAU,GACd,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAEhE,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;QACtD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC;YAC3B,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;YAC3B,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;SAC5B,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GACb,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,GAAG,KAAK,IAAI;QACd,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IAC5C,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAE/B,OAAO;QACL,QAAQ,EAAE,CAAC;QACX,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC;QAC9C,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;QAC3B,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;KAC5B,CAAC;AACJ,CAAC,CAAC;AAEF,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,qDAAqD;AACrD,MAAM,gBAAgB,GAAG,CACvB,KAAc,EACd,OAAwB,EACN,EAAE;IACpB,OAAO,CAAC,OAAO,EAAE,CAAC;IAClB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO;QACL,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,OAAO;QACtC,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;KAC5B,CAAC;AACJ,CAAC,CAAC;AAEF,wDAAwD;AACxD,MAAM,cAAc,GAAG,KAAK,EAC1B,OAAmB,EACnB,KAA8B,EAC9B,OAAwB,EACG,EAAE;IAC7B,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,CAAC,OAAO,EAAE,CAAC;IAElB,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;QACnB,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO;YACnD,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE;SAC5B,CAAC;IACJ,CAAC;IAED,OAAO,mBAAmB,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC,CAAC;AAEF,8DAA8D;AAC9D,MAAM,UAAU,GAAG,KAAK,EACtB,QAAsB,EACtB,aAAqB,EACM,EAAE;IAC7B,MAAM,KAAK,GAAG,kBAAkB,CAAC,aAAa,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO;YACL,QAAQ,EAAE,CAAC;YACX,MAAM,EAAE,oBAAoB,aAAa,EAAE;YAC3C,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;IACzC,MAAM,KAAK,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IAEjC,IAAI,CAAC;QACH,OAAO,MAAM,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC,CAAC;AAEF,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA0B,EAAc,EAAE;IACzE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAE/C,OAAO;QACL,GAAG,EAAE,CAAC,aAAqB,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,aAAa,CAAC;KACpE,CAAC;AACJ,CAAC,CAAC"}
@@ -1,21 +0,0 @@
1
- /**
2
- * MCP integration test harness.
3
- *
4
- * Builds MCP tools from an App, invokes them directly (no transport),
5
- * and returns the MCP tool response.
6
- */
7
- import type { McpHarness, McpHarnessOptions } from './types.js';
8
- /**
9
- * Create an MCP harness for integration testing.
10
- *
11
- * Builds MCP tools from the app's topo and provides a `callTool()` method
12
- * that invokes tools directly without any transport boundary.
13
- *
14
- * ```ts
15
- * const harness = createMcpHarness({ app });
16
- * const result = await harness.callTool("myapp_entity_show", { name: "Alpha" });
17
- * expect(result.isError).toBe(false);
18
- * ```
19
- */
20
- export declare const createMcpHarness: (options: McpHarnessOptions) => McpHarness;
21
- //# sourceMappingURL=harness-mcp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"harness-mcp.d.ts","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,iBAAiB,KAAG,UAmC7D,CAAC"}
@@ -1,53 +0,0 @@
1
- /**
2
- * MCP integration test harness.
3
- *
4
- * Builds MCP tools from an App, invokes them directly (no transport),
5
- * and returns the MCP tool response.
6
- */
7
- import { buildMcpTools } from '@ontrails/mcp';
8
- // ---------------------------------------------------------------------------
9
- // createMcpHarness
10
- // ---------------------------------------------------------------------------
11
- /**
12
- * Create an MCP harness for integration testing.
13
- *
14
- * Builds MCP tools from the app's topo and provides a `callTool()` method
15
- * that invokes tools directly without any transport boundary.
16
- *
17
- * ```ts
18
- * const harness = createMcpHarness({ app });
19
- * const result = await harness.callTool("myapp_entity_show", { name: "Alpha" });
20
- * expect(result.isError).toBe(false);
21
- * ```
22
- */
23
- export const createMcpHarness = (options) => {
24
- const toolsResult = buildMcpTools(options.app);
25
- if (toolsResult.isErr()) {
26
- throw toolsResult.error;
27
- }
28
- const toolMap = new Map();
29
- for (const tool of toolsResult.value) {
30
- toolMap.set(tool.name, tool);
31
- }
32
- return {
33
- async callTool(name, args) {
34
- const tool = toolMap.get(name);
35
- if (tool === undefined) {
36
- return {
37
- content: [{ text: `Unknown tool: ${name}`, type: 'text' }],
38
- isError: true,
39
- };
40
- }
41
- const result = await tool.handler(args, {
42
- abortSignal: undefined,
43
- progressToken: undefined,
44
- sendProgress: undefined,
45
- });
46
- return {
47
- content: result.content,
48
- isError: result.isError ?? false,
49
- };
50
- },
51
- };
52
- };
53
- //# sourceMappingURL=harness-mcp.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"harness-mcp.js","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAS9C,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA0B,EAAc,EAAE;IACzE,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC;QACxB,MAAM,WAAW,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO;QACL,KAAK,CAAC,QAAQ,CACZ,IAAY,EACZ,IAA6B;YAE7B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oBAC1D,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;gBACtC,WAAW,EAAE,SAAS;gBACtB,aAAa,EAAE,SAAS;gBACxB,YAAY,EAAE,SAAS;aACxB,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;aACjC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
package/dist/index.d.ts DELETED
@@ -1,16 +0,0 @@
1
- export { testAll } from './all.js';
2
- export { testExamples } from './examples.js';
3
- export { testCrosses } from './crosses.js';
4
- export { testTrail } from './trail.js';
5
- export { testContracts } from './contracts.js';
6
- export { testDetours } from './detours.js';
7
- export { assertErrorMatch, assertFullMatch, assertSchemaMatch, expectErr, expectOk, } from './assertions.js';
8
- export { createCrossContext, createTestContext, defaultMintPermit, } from './context.js';
9
- export { createTestLogger } from './logger.js';
10
- export { createCliHarness } from './harness-cli.js';
11
- export { createMcpHarness } from './harness-mcp.js';
12
- export type { CreateCrossContextOptions } from './context.js';
13
- export type { MintableTrail, MintedPermit, TestExecutionOptions, } from './context.js';
14
- export type { TestCrossOptions } from './crosses.js';
15
- export type { CrossScenario, TestScenario, TestLogger, TestTrailContextOptions, CliHarness, CliHarnessOptions, CliHarnessResult, McpHarness, McpHarnessOptions, McpHarnessResult, } from './types.js';
16
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,YAAY,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC9D,YAAY,EACV,aAAa,EACb,YAAY,EACZ,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,YAAY,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,uBAAuB,EACvB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js DELETED
@@ -1,16 +0,0 @@
1
- // Contract-driven testing
2
- export { testAll } from './all.js';
3
- export { testExamples } from './examples.js';
4
- export { testCrosses } from './crosses.js';
5
- export { testTrail } from './trail.js';
6
- export { testContracts } from './contracts.js';
7
- export { testDetours } from './detours.js';
8
- // Assertions
9
- export { assertErrorMatch, assertFullMatch, assertSchemaMatch, expectErr, expectOk, } from './assertions.js';
10
- // Mock factories
11
- export { createCrossContext, createTestContext, defaultMintPermit, } from './context.js';
12
- export { createTestLogger } from './logger.js';
13
- // Trailhead harnesses
14
- export { createCliHarness } from './harness-cli.js';
15
- export { createMcpHarness } from './harness-mcp.js';
16
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAEzB,iBAAiB;AACjB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,sBAAsB;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/logger.d.ts DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * Test logger that captures log records for assertion.
3
- */
4
- import type { LogLevel } from '@ontrails/logging';
5
- import type { TestLogger } from './types.js';
6
- /**
7
- * Create a test logger that captures all log records in an array.
8
- *
9
- * Records are not printed. Use `entries`, `find()`, and `assertLogged()`
10
- * to inspect what was logged during a test.
11
- */
12
- export declare const createTestLogger: (options?: {
13
- level?: LogLevel;
14
- }) => TestLogger;
15
- //# sourceMappingURL=logger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAA0B,MAAM,mBAAmB,CAAC;AAE1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA+G7C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,UAAU;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,KAAG,UACG,CAAC"}