@pellux/goodvibes-contracts 1.6.0 → 1.7.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/artifacts/operator-contract.json +7590 -1633
- package/artifacts/operator-openapi.json +92169 -0
- package/artifacts/python/homeassistant_operator_client.py +630 -0
- package/dist/core-verbs.d.ts.map +1 -1
- package/dist/core-verbs.js +51 -2
- package/dist/generated/foundation-client-types.d.ts +1009 -2
- package/dist/generated/foundation-client-types.d.ts.map +1 -1
- package/dist/generated/foundation-metadata.d.ts +3 -3
- package/dist/generated/foundation-metadata.js +3 -3
- package/dist/generated/mock-daemon-fixtures.d.ts +11 -0
- package/dist/generated/mock-daemon-fixtures.d.ts.map +1 -0
- package/dist/generated/mock-daemon-fixtures.js +16279 -0
- package/dist/generated/operator-contract.d.ts.map +1 -1
- package/dist/generated/operator-contract.js +7590 -1633
- package/dist/generated/operator-method-ids.d.ts +1 -1
- package/dist/generated/operator-method-ids.d.ts.map +1 -1
- package/dist/generated/operator-method-ids.js +51 -0
- package/dist/generated/runtime-event-domains.d.ts +1 -1
- package/dist/generated/runtime-event-domains.d.ts.map +1 -1
- package/dist/generated/runtime-event-domains.js +1 -0
- package/dist/generated/webui-facade.d.ts +51 -0
- package/dist/generated/webui-facade.d.ts.map +1 -0
- package/dist/generated/webui-facade.js +18609 -0
- package/dist/testing/conformance.d.ts +56 -0
- package/dist/testing/conformance.d.ts.map +1 -0
- package/dist/testing/conformance.js +50 -0
- package/dist/testing/index.d.ts +16 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +15 -0
- package/dist/testing/mock-daemon.d.ts +58 -0
- package/dist/testing/mock-daemon.d.ts.map +1 -0
- package/dist/testing/mock-daemon.js +96 -0
- package/package.json +14 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* testing/conformance.ts — the descriptor/handler drift gate, shipped from the
|
|
3
|
+
* contracts package so every consuming front-end (terminal-shell, the tui and
|
|
4
|
+
* agent forks, the webui) runs the SAME gate against its own composition rather
|
|
5
|
+
* than keeping a divergent local copy.
|
|
6
|
+
*
|
|
7
|
+
* A gateway method catalog registers DESCRIPTORS (the contract surface) and,
|
|
8
|
+
* separately, HANDLERS (what actually answers an invoke). A descriptor with no
|
|
9
|
+
* attached handler answers 501 "Gateway method is not invokable" over both
|
|
10
|
+
* websocket and HTTP invoke — a whole verb family can look present in the
|
|
11
|
+
* contract yet be dead. That is the exact regression this gate catches: run
|
|
12
|
+
* `assertEveryDescriptorHasHandler` against a FULLY-composed catalog in the
|
|
13
|
+
* consumer's test suite and it fails loudly the moment any registered
|
|
14
|
+
* descriptor is left handler-less.
|
|
15
|
+
*
|
|
16
|
+
* The catalog is accepted through a narrow structural view, so a consumer can
|
|
17
|
+
* pass its concrete GatewayMethodCatalog (or any equivalent) without the
|
|
18
|
+
* contracts package depending on the catalog's full type.
|
|
19
|
+
*/
|
|
20
|
+
/** The minimal catalog surface this gate reads. GatewayMethodCatalog satisfies it structurally. */
|
|
21
|
+
export interface GatewayCatalogConformanceView {
|
|
22
|
+
/** Every registered method descriptor. Only the `id` field is read here. */
|
|
23
|
+
list(): ReadonlyArray<{
|
|
24
|
+
readonly id: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** True when the descriptor with this id has a handler attached. */
|
|
27
|
+
hasHandler(id: string): boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ConformanceOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Restrict the check to these descriptor ids. Use when a catalog carries
|
|
32
|
+
* builtin descriptors whose handlers are attached by a different layer (host
|
|
33
|
+
* daemon surfaces) and are legitimately absent in the composition under test.
|
|
34
|
+
*/
|
|
35
|
+
readonly onlyIds?: readonly string[];
|
|
36
|
+
/**
|
|
37
|
+
* Descriptor ids allowed to have no handler — descriptors a given
|
|
38
|
+
* composition intentionally does not answer. Prefer `onlyIds` for the common
|
|
39
|
+
* case; use `ignoreIds` to carve out a small known set from a full sweep.
|
|
40
|
+
*/
|
|
41
|
+
readonly ignoreIds?: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Return the sorted ids of every registered descriptor that has no attached
|
|
45
|
+
* handler (the 501 set), honoring `onlyIds` / `ignoreIds`. Empty means every
|
|
46
|
+
* checked descriptor is invokable.
|
|
47
|
+
*/
|
|
48
|
+
export declare function findMethodsMissingHandlers(catalog: GatewayCatalogConformanceView, options?: ConformanceOptions): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Assert every registered descriptor (honoring `onlyIds` / `ignoreIds`) has a
|
|
51
|
+
* handler attached. Throws with the full list of offending ids when any is
|
|
52
|
+
* handler-less. This is the consumer-facing gate: call it in your CI against
|
|
53
|
+
* the same catalog your daemon serves.
|
|
54
|
+
*/
|
|
55
|
+
export declare function assertEveryDescriptorHasHandler(catalog: GatewayCatalogConformanceView, options?: ConformanceOptions): void;
|
|
56
|
+
//# sourceMappingURL=conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../../src/testing/conformance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,mGAAmG;AACnG,MAAM,WAAW,6BAA6B;IAC5C,4EAA4E;IAC5E,IAAI,IAAI,aAAa,CAAC;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,oEAAoE;IACpE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,6BAA6B,EACtC,OAAO,GAAE,kBAAuB,GAC/B,MAAM,EAAE,CAUV;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,6BAA6B,EACtC,OAAO,GAAE,kBAAuB,GAC/B,IAAI,CASN"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* testing/conformance.ts — the descriptor/handler drift gate, shipped from the
|
|
3
|
+
* contracts package so every consuming front-end (terminal-shell, the tui and
|
|
4
|
+
* agent forks, the webui) runs the SAME gate against its own composition rather
|
|
5
|
+
* than keeping a divergent local copy.
|
|
6
|
+
*
|
|
7
|
+
* A gateway method catalog registers DESCRIPTORS (the contract surface) and,
|
|
8
|
+
* separately, HANDLERS (what actually answers an invoke). A descriptor with no
|
|
9
|
+
* attached handler answers 501 "Gateway method is not invokable" over both
|
|
10
|
+
* websocket and HTTP invoke — a whole verb family can look present in the
|
|
11
|
+
* contract yet be dead. That is the exact regression this gate catches: run
|
|
12
|
+
* `assertEveryDescriptorHasHandler` against a FULLY-composed catalog in the
|
|
13
|
+
* consumer's test suite and it fails loudly the moment any registered
|
|
14
|
+
* descriptor is left handler-less.
|
|
15
|
+
*
|
|
16
|
+
* The catalog is accepted through a narrow structural view, so a consumer can
|
|
17
|
+
* pass its concrete GatewayMethodCatalog (or any equivalent) without the
|
|
18
|
+
* contracts package depending on the catalog's full type.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Return the sorted ids of every registered descriptor that has no attached
|
|
22
|
+
* handler (the 501 set), honoring `onlyIds` / `ignoreIds`. Empty means every
|
|
23
|
+
* checked descriptor is invokable.
|
|
24
|
+
*/
|
|
25
|
+
export function findMethodsMissingHandlers(catalog, options = {}) {
|
|
26
|
+
const only = options.onlyIds ? new Set(options.onlyIds) : null;
|
|
27
|
+
const ignore = options.ignoreIds ? new Set(options.ignoreIds) : null;
|
|
28
|
+
return catalog
|
|
29
|
+
.list()
|
|
30
|
+
.map((descriptor) => descriptor.id)
|
|
31
|
+
.filter((id) => (only ? only.has(id) : true))
|
|
32
|
+
.filter((id) => (ignore ? !ignore.has(id) : true))
|
|
33
|
+
.filter((id) => !catalog.hasHandler(id))
|
|
34
|
+
.sort();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Assert every registered descriptor (honoring `onlyIds` / `ignoreIds`) has a
|
|
38
|
+
* handler attached. Throws with the full list of offending ids when any is
|
|
39
|
+
* handler-less. This is the consumer-facing gate: call it in your CI against
|
|
40
|
+
* the same catalog your daemon serves.
|
|
41
|
+
*/
|
|
42
|
+
export function assertEveryDescriptorHasHandler(catalog, options = {}) {
|
|
43
|
+
const missing = findMethodsMissingHandlers(catalog, options);
|
|
44
|
+
if (missing.length === 0)
|
|
45
|
+
return;
|
|
46
|
+
throw new Error(`Gateway catalog has ${missing.length} descriptor(s) with no attached handler — `
|
|
47
|
+
+ `each answers 501 "Gateway method is not invokable" over websocket and HTTP invoke. `
|
|
48
|
+
+ `Attach handlers together with the descriptors at composition time. Offending ids:\n `
|
|
49
|
+
+ missing.join('\n '));
|
|
50
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pellux/goodvibes-contracts/testing — the shipped conformance kit + mock-daemon
|
|
3
|
+
* fixture generator, the single source consuming front-ends (terminal-shell, the
|
|
4
|
+
* tui and agent forks, the webui, the Home Assistant fixtures) run instead of a
|
|
5
|
+
* divergent local copy.
|
|
6
|
+
*
|
|
7
|
+
* - conformance: assertEveryDescriptorHasHandler / findMethodsMissingHandlers —
|
|
8
|
+
* the descriptor/handler drift gate, run against a fully-composed catalog.
|
|
9
|
+
* - mock-daemon: buildMockDaemonResponses / buildMockDaemonFixtureMap /
|
|
10
|
+
* createMockDaemon / sampleFromSchema — schema-valid sample responses for
|
|
11
|
+
* every cataloged method, generated from the contract's own JSON Schemas so
|
|
12
|
+
* Playwright/HA mocks are generated rather than hand-written.
|
|
13
|
+
*/
|
|
14
|
+
export { assertEveryDescriptorHasHandler, findMethodsMissingHandlers, type GatewayCatalogConformanceView, type ConformanceOptions, } from './conformance.js';
|
|
15
|
+
export { sampleFromSchema, buildMockDaemonResponses, buildMockDaemonFixtureMap, createMockDaemon, type MockDaemonResponse, type MockDaemonFixtureMap, } from './mock-daemon.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,+BAA+B,EAC/B,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,kBAAkB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pellux/goodvibes-contracts/testing — the shipped conformance kit + mock-daemon
|
|
3
|
+
* fixture generator, the single source consuming front-ends (terminal-shell, the
|
|
4
|
+
* tui and agent forks, the webui, the Home Assistant fixtures) run instead of a
|
|
5
|
+
* divergent local copy.
|
|
6
|
+
*
|
|
7
|
+
* - conformance: assertEveryDescriptorHasHandler / findMethodsMissingHandlers —
|
|
8
|
+
* the descriptor/handler drift gate, run against a fully-composed catalog.
|
|
9
|
+
* - mock-daemon: buildMockDaemonResponses / buildMockDaemonFixtureMap /
|
|
10
|
+
* createMockDaemon / sampleFromSchema — schema-valid sample responses for
|
|
11
|
+
* every cataloged method, generated from the contract's own JSON Schemas so
|
|
12
|
+
* Playwright/HA mocks are generated rather than hand-written.
|
|
13
|
+
*/
|
|
14
|
+
export { assertEveryDescriptorHasHandler, findMethodsMissingHandlers, } from './conformance.js';
|
|
15
|
+
export { sampleFromSchema, buildMockDaemonResponses, buildMockDaemonFixtureMap, createMockDaemon, } from './mock-daemon.js';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* testing/mock-daemon.ts — generate schema-valid sample responses for every
|
|
3
|
+
* cataloged operator method, straight from the contract's own JSON Schemas.
|
|
4
|
+
*
|
|
5
|
+
* Consumers (the webui Playwright suite, the Home Assistant test fixtures) have
|
|
6
|
+
* historically hand-written a mock response per method their UI calls, which
|
|
7
|
+
* drifts silently the moment a method's output schema changes. This generator
|
|
8
|
+
* removes the hand-authoring: given the operator contract manifest, it walks
|
|
9
|
+
* each method's `outputSchema` and produces a minimal, deterministic,
|
|
10
|
+
* schema-valid body — the single source those mocks can be generated from.
|
|
11
|
+
*
|
|
12
|
+
* The walk is deterministic (no randomness, no clock) so a regenerated fixture
|
|
13
|
+
* set is byte-identical unless the contract itself changed — the property that
|
|
14
|
+
* lets a checked-in fixture artifact carry a drift check.
|
|
15
|
+
*
|
|
16
|
+
* Scope: this understands the JSON Schema subset the contract generator emits —
|
|
17
|
+
* object (properties/required), array (items), string (enum), number/integer,
|
|
18
|
+
* boolean, null, and anyOf unions. It is a fixture generator, not a full JSON
|
|
19
|
+
* Schema materializer; an unrecognized shape yields null rather than throwing,
|
|
20
|
+
* so a new schema keyword degrades to a still-valid (if minimal) sample.
|
|
21
|
+
*/
|
|
22
|
+
import type { JsonSchema, OperatorContractManifest } from '../types.js';
|
|
23
|
+
/**
|
|
24
|
+
* Produce a minimal, deterministic value that satisfies `schema`. Fills every
|
|
25
|
+
* declared object property (required and optional) so the sample exercises the
|
|
26
|
+
* full shape a consumer's mock renders.
|
|
27
|
+
*/
|
|
28
|
+
export declare function sampleFromSchema(schema: JsonSchema | undefined): unknown;
|
|
29
|
+
/** One generated mock response: what a daemon would answer for a method. */
|
|
30
|
+
export interface MockDaemonResponse {
|
|
31
|
+
readonly methodId: string;
|
|
32
|
+
readonly http: {
|
|
33
|
+
readonly method: string;
|
|
34
|
+
readonly path: string;
|
|
35
|
+
} | null;
|
|
36
|
+
readonly status: number;
|
|
37
|
+
readonly body: unknown;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build a schema-valid sample response for every method in the contract, in
|
|
41
|
+
* catalog order. A method with no `outputSchema` yields a `null` body (honest:
|
|
42
|
+
* the contract declares no shape to sample).
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildMockDaemonResponses(contract: OperatorContractManifest): MockDaemonResponse[];
|
|
45
|
+
/** A methodId -> sample response map, the fixture shape most consumers want. */
|
|
46
|
+
export type MockDaemonFixtureMap = Readonly<Record<string, MockDaemonResponse>>;
|
|
47
|
+
/** Reduce the response list to a methodId-keyed map. */
|
|
48
|
+
export declare function buildMockDaemonFixtureMap(contract: OperatorContractManifest): MockDaemonFixtureMap;
|
|
49
|
+
/**
|
|
50
|
+
* A tiny in-memory mock daemon over the generated fixtures: answer by methodId
|
|
51
|
+
* or by HTTP method+path. Returns null for an unknown method/route so a caller
|
|
52
|
+
* can fall through to its own 404, exactly like a real dispatcher.
|
|
53
|
+
*/
|
|
54
|
+
export declare function createMockDaemon(contract: OperatorContractManifest): {
|
|
55
|
+
answer(methodId: string): MockDaemonResponse | null;
|
|
56
|
+
answerHttp(method: string, path: string): MockDaemonResponse | null;
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=mock-daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-daemon.d.ts","sourceRoot":"","sources":["../../src/testing/mock-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAQxE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAoDxE;AAED,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,kBAAkB,EAAE,CAOjG;AAED,gFAAgF;AAChF,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAEhF,wDAAwD;AACxD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,oBAAoB,CAMlG;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,wBAAwB,GAAG;IACpE,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAAC;IACpD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAAC;CACrE,CAYA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
function asRecord(value) {
|
|
2
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
3
|
+
? value
|
|
4
|
+
: null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Produce a minimal, deterministic value that satisfies `schema`. Fills every
|
|
8
|
+
* declared object property (required and optional) so the sample exercises the
|
|
9
|
+
* full shape a consumer's mock renders.
|
|
10
|
+
*/
|
|
11
|
+
export function sampleFromSchema(schema) {
|
|
12
|
+
if (!schema)
|
|
13
|
+
return null;
|
|
14
|
+
const record = asRecord(schema);
|
|
15
|
+
if (!record)
|
|
16
|
+
return null;
|
|
17
|
+
// anyOf union: take the first branch that is not a bare `null` type, so the
|
|
18
|
+
// sample carries a representative value rather than degenerating to null.
|
|
19
|
+
const anyOf = record['anyOf'];
|
|
20
|
+
if (Array.isArray(anyOf) && anyOf.length > 0) {
|
|
21
|
+
const branches = anyOf;
|
|
22
|
+
const preferred = branches.find((branch) => asRecord(branch)?.['type'] !== 'null') ?? branches[0];
|
|
23
|
+
return sampleFromSchema(preferred);
|
|
24
|
+
}
|
|
25
|
+
const enumValues = record['enum'];
|
|
26
|
+
if (Array.isArray(enumValues) && enumValues.length > 0) {
|
|
27
|
+
return enumValues[0];
|
|
28
|
+
}
|
|
29
|
+
const type = record['type'];
|
|
30
|
+
if (type === 'object' || (type === undefined && asRecord(record['properties']))) {
|
|
31
|
+
const properties = asRecord(record['properties']) ?? {};
|
|
32
|
+
const out = {};
|
|
33
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
34
|
+
out[key] = sampleFromSchema(propSchema);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
if (type === 'array') {
|
|
39
|
+
const items = record['items'];
|
|
40
|
+
if (items && !Array.isArray(items)) {
|
|
41
|
+
return [sampleFromSchema(items)];
|
|
42
|
+
}
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
switch (type) {
|
|
46
|
+
case 'string':
|
|
47
|
+
return 'sample';
|
|
48
|
+
case 'number':
|
|
49
|
+
case 'integer':
|
|
50
|
+
return 0;
|
|
51
|
+
case 'boolean':
|
|
52
|
+
return false;
|
|
53
|
+
case 'null':
|
|
54
|
+
return null;
|
|
55
|
+
default:
|
|
56
|
+
// Unknown / absent type with no properties: JSON Schema's "accept anything".
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build a schema-valid sample response for every method in the contract, in
|
|
62
|
+
* catalog order. A method with no `outputSchema` yields a `null` body (honest:
|
|
63
|
+
* the contract declares no shape to sample).
|
|
64
|
+
*/
|
|
65
|
+
export function buildMockDaemonResponses(contract) {
|
|
66
|
+
return contract.operator.methods.map((method) => ({
|
|
67
|
+
methodId: method.id,
|
|
68
|
+
http: method.http ? { method: method.http.method, path: method.http.path } : null,
|
|
69
|
+
status: 200,
|
|
70
|
+
body: sampleFromSchema(method.outputSchema),
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
/** Reduce the response list to a methodId-keyed map. */
|
|
74
|
+
export function buildMockDaemonFixtureMap(contract) {
|
|
75
|
+
const map = {};
|
|
76
|
+
for (const response of buildMockDaemonResponses(contract)) {
|
|
77
|
+
map[response.methodId] = response;
|
|
78
|
+
}
|
|
79
|
+
return map;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A tiny in-memory mock daemon over the generated fixtures: answer by methodId
|
|
83
|
+
* or by HTTP method+path. Returns null for an unknown method/route so a caller
|
|
84
|
+
* can fall through to its own 404, exactly like a real dispatcher.
|
|
85
|
+
*/
|
|
86
|
+
export function createMockDaemon(contract) {
|
|
87
|
+
const responses = buildMockDaemonResponses(contract);
|
|
88
|
+
const byId = new Map(responses.map((response) => [response.methodId, response]));
|
|
89
|
+
const byHttp = new Map(responses
|
|
90
|
+
.filter((response) => response.http)
|
|
91
|
+
.map((response) => [`${response.http.method} ${response.http.path}`, response]));
|
|
92
|
+
return {
|
|
93
|
+
answer: (methodId) => byId.get(methodId) ?? null,
|
|
94
|
+
answerHttp: (method, path) => byHttp.get(`${method.toUpperCase()} ${path}`) ?? null,
|
|
95
|
+
};
|
|
96
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-contracts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"bun": "1.3.10",
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -14,10 +14,18 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"import": "./dist/index.js"
|
|
16
16
|
},
|
|
17
|
+
"./testing": {
|
|
18
|
+
"types": "./dist/testing/index.d.ts",
|
|
19
|
+
"import": "./dist/testing/index.js"
|
|
20
|
+
},
|
|
17
21
|
"./generated/foundation-client-types": {
|
|
18
22
|
"types": "./dist/generated/foundation-client-types.d.ts",
|
|
19
23
|
"import": "./dist/generated/foundation-client-types.js"
|
|
20
24
|
},
|
|
25
|
+
"./generated/mock-daemon-fixtures": {
|
|
26
|
+
"types": "./dist/generated/mock-daemon-fixtures.d.ts",
|
|
27
|
+
"import": "./dist/generated/mock-daemon-fixtures.js"
|
|
28
|
+
},
|
|
21
29
|
"./generated/foundation-metadata": {
|
|
22
30
|
"types": "./dist/generated/foundation-metadata.d.ts",
|
|
23
31
|
"import": "./dist/generated/foundation-metadata.js"
|
|
@@ -42,6 +50,10 @@
|
|
|
42
50
|
"types": "./dist/generated/runtime-event-domains.d.ts",
|
|
43
51
|
"import": "./dist/generated/runtime-event-domains.js"
|
|
44
52
|
},
|
|
53
|
+
"./generated/webui-facade": {
|
|
54
|
+
"types": "./dist/generated/webui-facade.d.ts",
|
|
55
|
+
"import": "./dist/generated/webui-facade.js"
|
|
56
|
+
},
|
|
45
57
|
"./node": {
|
|
46
58
|
"types": "./dist/node.d.ts",
|
|
47
59
|
"import": "./dist/node.js"
|
|
@@ -71,6 +83,7 @@
|
|
|
71
83
|
"import": "./dist/zod-schemas/session.js"
|
|
72
84
|
},
|
|
73
85
|
"./operator-contract.json": "./artifacts/operator-contract.json",
|
|
86
|
+
"./operator-openapi.json": "./artifacts/operator-openapi.json",
|
|
74
87
|
"./peer-contract.json": "./artifacts/peer-contract.json",
|
|
75
88
|
"./package.json": "./package.json"
|
|
76
89
|
},
|