@hypequery/protocol-conformance 0.15.2 → 0.16.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/README.md +8 -0
- package/dist/adapters/client-contract.d.ts +5 -0
- package/dist/adapters/client-contract.d.ts.map +1 -0
- package/dist/adapters/client-contract.js +29 -0
- package/dist/adapters/reference.d.ts +1 -1
- package/dist/adapters/reference.d.ts.map +1 -1
- package/dist/adapters/reference.js +8 -2
- package/dist/adapters/utils/client-contract-targets.d.ts +4 -0
- package/dist/adapters/utils/client-contract-targets.d.ts.map +1 -0
- package/dist/adapters/utils/client-contract-targets.js +7 -0
- package/dist/client-contract-fixtures.d.ts +3 -0
- package/dist/client-contract-fixtures.d.ts.map +1 -0
- package/dist/client-contract-fixtures.js +61 -0
- package/dist/compare.d.ts.map +1 -1
- package/dist/compare.js +8 -0
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +3 -1
- package/fixtures/client-contract-v1/README.md +29 -0
- package/fixtures/client-contract-v1/identities.json +36 -0
- package/fixtures/client-contract-v1/queries.json +484 -0
- package/fixtures/client-contract-v1/query-rejections.json +2114 -0
- package/fixtures/client-contract-v1/rejections.json +594 -0
- package/fixtures/client-contract-v1/relations.json +70 -0
- package/fixtures/client-contract-v1/success.json +696 -0
- package/fixtures/client-contract-v1/timezone-names.txt +597 -0
- package/fixtures/manifest.json +33 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -85,3 +85,11 @@ fixture family or adding an implementation.
|
|
|
85
85
|
## License
|
|
86
86
|
|
|
87
87
|
Apache-2.0.
|
|
88
|
+
|
|
89
|
+
## Client contract v1
|
|
90
|
+
|
|
91
|
+
Both protocol adapters announce `client-contract-v1`. The runner resolves the
|
|
92
|
+
family's compact success references and negative JSON Pointer patches before
|
|
93
|
+
sending complete cases over NDJSON. It checks canonical identities, normalized
|
|
94
|
+
HTTP/MCP output and exact safe rejection paths/messages, including boundary
|
|
95
|
+
inputs. Fixture composition neither validates nor repairs runtime artifacts.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-contract.d.ts","sourceRoot":"","sources":["../../src/adapters/client-contract.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE9D,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACpC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,IAAI,GAAG,aAAa,CAqB9E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { decodeProtocolClientContract, prepareProtocolClientContract, validateProtocolClientContract, validateProtocolClientQuery, } from '@hypequery/protocol';
|
|
2
|
+
import { clientContractTargets } from './utils/client-contract-targets.js';
|
|
3
|
+
export function handleClientContract(role, c) {
|
|
4
|
+
if (c.mode === 'decode') {
|
|
5
|
+
decodeProtocolClientContract(c.value);
|
|
6
|
+
return { ok: true };
|
|
7
|
+
}
|
|
8
|
+
if (c.mode === 'query') {
|
|
9
|
+
const value = c.value;
|
|
10
|
+
const result = validateProtocolClientQuery(value.contract, value.endpoint, value.input, value.transport);
|
|
11
|
+
return { ok: true, output: { body: result.body, selectedMeasures: result.selectedMeasures, effectiveLimit: result.effectiveLimit } };
|
|
12
|
+
}
|
|
13
|
+
if (c.mode === 'relation') {
|
|
14
|
+
const value = c.value;
|
|
15
|
+
if (value.contract)
|
|
16
|
+
return { ok: true, output: clientContractTargets(validateProtocolClientContract(value.contract)) };
|
|
17
|
+
const left = validateProtocolClientContract(value.left), right = validateProtocolClientContract(value.right);
|
|
18
|
+
return { ok: true, output: {
|
|
19
|
+
sameEndpointSchemas: left.endpoints.filter(e => right.endpoints.some(r => r.id === e.id && r.schemaHash === e.schemaHash)).map(e => e.id),
|
|
20
|
+
sameContentHash: left.contentHash === right.contentHash,
|
|
21
|
+
} };
|
|
22
|
+
}
|
|
23
|
+
const contract = validateProtocolClientContract(c.value);
|
|
24
|
+
if (role !== 'identity')
|
|
25
|
+
return { ok: true };
|
|
26
|
+
const { contentHash: _hash, endpoints, ...root } = contract;
|
|
27
|
+
const prepared = prepareProtocolClientContract({ ...root, endpoints: endpoints.map(({ schemaHash: _schemaHash, ...endpoint }) => endpoint) });
|
|
28
|
+
return { ok: true, output: { canonical: prepared.canonical, sha256: prepared.contentHash } };
|
|
29
|
+
}
|
|
@@ -9,7 +9,7 @@ export declare const REFERENCE_HOSTILE_OBJECT_SUITE: {
|
|
|
9
9
|
readonly count: 7;
|
|
10
10
|
readonly mechanisms: readonly ["getter", "toJSON", "proxy", "custom-prototype", "symbol-key", "sparse-array", "cycle"];
|
|
11
11
|
};
|
|
12
|
-
export declare const REFERENCE_FAMILIES: readonly ["cache-keys-v1", "cache-preimages-v1", "tagged-values-v1", "identifiers-v1", "expressions-v1", "expressions-v2", "query-schemas-v1", "query-implementations-v1", "query-events-v1", "query-diagnostics-v1", "deployments-v2", "deployments-v3", "deployment-bundles-v1", "deployment-releases-v1", "semantic-invocations-v1", "semantic-invocations-v2"];
|
|
12
|
+
export declare const REFERENCE_FAMILIES: readonly ["client-contract-v1", "cache-keys-v1", "cache-preimages-v1", "tagged-values-v1", "identifiers-v1", "expressions-v1", "expressions-v2", "query-schemas-v1", "query-implementations-v1", "query-events-v1", "query-diagnostics-v1", "deployments-v2", "deployments-v3", "deployment-bundles-v1", "deployment-releases-v1", "semantic-invocations-v1", "semantic-invocations-v2"];
|
|
13
13
|
export declare function referenceHandle(family: string, role: FixtureRole, c: Case, section?: string): HandlerResult;
|
|
14
14
|
export {};
|
|
15
15
|
//# sourceMappingURL=reference.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../../src/adapters/reference.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../../src/adapters/reference.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAc9D,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA6BpC;;;;GAIG;AACH,eAAO,MAAM,8BAA8B;;;CAWjC,CAAC;AAEX,eAAO,MAAM,kBAAkB,0XAkBrB,CAAC;AAEX,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,EACjB,CAAC,EAAE,IAAI,EACP,OAAO,CAAC,EAAE,MAAM,GACf,aAAa,CAgDf"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handleClientContract } from './client-contract.js';
|
|
1
2
|
// The TypeScript reference adapter. Maps each family/role/case to the public
|
|
2
3
|
// root export of @hypequery/protocol and returns a wire result. Every operation
|
|
3
4
|
// goes through the package's supported surface — this is exactly what a second
|
|
@@ -8,8 +9,10 @@ const STABLE_CODE = /^HQ_[A-Z0-9_]+$/;
|
|
|
8
9
|
/** Turns a thrown protocol error into a wire rejection; rethrows anything else. */
|
|
9
10
|
function mapError(error) {
|
|
10
11
|
const code = error?.code;
|
|
11
|
-
if (typeof code === 'string' && STABLE_CODE.test(code))
|
|
12
|
-
|
|
12
|
+
if (typeof code === 'string' && STABLE_CODE.test(code)) {
|
|
13
|
+
const safe = error;
|
|
14
|
+
return { ok: false, code, ...(code.startsWith('HQ_CLIENT_') ? { output: { path: safe.path, message: safe.message } } : {}) };
|
|
15
|
+
}
|
|
13
16
|
throw error;
|
|
14
17
|
}
|
|
15
18
|
function attempt(fn) {
|
|
@@ -43,6 +46,7 @@ export const REFERENCE_HOSTILE_OBJECT_SUITE = {
|
|
|
43
46
|
],
|
|
44
47
|
};
|
|
45
48
|
export const REFERENCE_FAMILIES = [
|
|
49
|
+
'client-contract-v1',
|
|
46
50
|
'cache-keys-v1',
|
|
47
51
|
'cache-preimages-v1',
|
|
48
52
|
'tagged-values-v1',
|
|
@@ -62,6 +66,8 @@ export const REFERENCE_FAMILIES = [
|
|
|
62
66
|
];
|
|
63
67
|
export function referenceHandle(family, role, c, section) {
|
|
64
68
|
switch (family) {
|
|
69
|
+
case 'client-contract-v1':
|
|
70
|
+
return attempt(() => handleClientContract(role, c));
|
|
65
71
|
case 'tagged-values-v1':
|
|
66
72
|
return handleTaggedValue(role, c);
|
|
67
73
|
case 'identifiers-v1':
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ProtocolClientContract } from '@hypequery/protocol';
|
|
2
|
+
/** Callable targets, preserving normalized endpoint order without inventing dataset access. */
|
|
3
|
+
export declare function clientContractTargets(contract: ProtocolClientContract): Record<string, unknown>;
|
|
4
|
+
//# sourceMappingURL=client-contract-targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-contract-targets.d.ts","sourceRoot":"","sources":["../../../src/adapters/utils/client-contract-targets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,+FAA+F;AAC/F,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAK/F"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Callable targets, preserving normalized endpoint order without inventing dataset access. */
|
|
2
|
+
export function clientContractTargets(contract) {
|
|
3
|
+
return {
|
|
4
|
+
queryDatasetTargets: contract.endpoints.filter(e => e.kind === 'dataset').map(e => e.id),
|
|
5
|
+
queryMetricTargets: contract.endpoints.filter(e => e.kind === 'metric').map(e => ({ dataset: e.dataset, metric: e.id })),
|
|
6
|
+
};
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-contract-fixtures.d.ts","sourceRoot":"","sources":["../src/client-contract-fixtures.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAqBjD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAwBpF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
function base(values, id) {
|
|
2
|
+
if (typeof id !== 'string' || !values.has(id))
|
|
3
|
+
throw new Error('Unknown client fixture base');
|
|
4
|
+
return structuredClone(values.get(id));
|
|
5
|
+
}
|
|
6
|
+
function patch(value, changes) {
|
|
7
|
+
for (const change of changes) {
|
|
8
|
+
if (!change.path.startsWith('/'))
|
|
9
|
+
throw new Error('Invalid client fixture pointer');
|
|
10
|
+
const parts = change.path.slice(1).split('/').map(part => part.replaceAll('~1', '/').replaceAll('~0', '~'));
|
|
11
|
+
let target = value;
|
|
12
|
+
for (const part of parts.slice(0, -1)) {
|
|
13
|
+
if (!Object.hasOwn(target, part))
|
|
14
|
+
throw new Error('Missing client fixture parent');
|
|
15
|
+
target = target[part];
|
|
16
|
+
}
|
|
17
|
+
const key = parts.at(-1);
|
|
18
|
+
if (key === '-' && Array.isArray(target))
|
|
19
|
+
target.push(structuredClone(change.value));
|
|
20
|
+
else
|
|
21
|
+
Object.defineProperty(target, key, { value: structuredClone(change.value), enumerable: true, writable: true, configurable: true });
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
export function composeClientContractCases(cases) {
|
|
26
|
+
const values = new Map(cases.filter(item => item.role === 'success' && item.case.mode === undefined)
|
|
27
|
+
.map(item => [item.id, item.case.value]));
|
|
28
|
+
return cases.map(item => {
|
|
29
|
+
const c = item.case;
|
|
30
|
+
if (c.base !== undefined)
|
|
31
|
+
return { ...item, case: { ...c, value: patch(base(values, c.base), c.set) } };
|
|
32
|
+
if (c.mode === 'query')
|
|
33
|
+
return { ...item, case: { ...c, value: { contract: base(values, c.contract), endpoint: c.endpoint, input: c.input, transport: c.transport ?? 'http' } } };
|
|
34
|
+
if (c.mode === 'relation')
|
|
35
|
+
return { ...item, case: { ...c, value: c.left === undefined ? { contract: base(values, c.contract) }
|
|
36
|
+
: { left: base(values, c.left), right: base(values, c.right) } } };
|
|
37
|
+
if (c.mode === 'boundary') {
|
|
38
|
+
const generator = c.generator;
|
|
39
|
+
let value;
|
|
40
|
+
if (generator.type === 'endpoints')
|
|
41
|
+
value = { ...base(values, 'build'), endpoints: Array.from({ length: generator.count }, () => ({})) };
|
|
42
|
+
else if (generator.type === 'descriptors') {
|
|
43
|
+
const dimensions = Object.fromEntries(Array.from({ length: 256 }, (_, i) => ['field' + i, null]));
|
|
44
|
+
value = { ...base(values, 'build'), endpoints: Array.from({ length: generator.count }, () => ({ dimensions })) };
|
|
45
|
+
}
|
|
46
|
+
else if (generator.type === 'members')
|
|
47
|
+
value = Array.from({ length: generator.count }, () => null);
|
|
48
|
+
else if (generator.type === 'bytes')
|
|
49
|
+
value = { extra: 'x'.repeat(generator.count - 12) };
|
|
50
|
+
else if (generator.type === 'depth') {
|
|
51
|
+
value = 0;
|
|
52
|
+
for (let i = 1; i < generator.count; i++)
|
|
53
|
+
value = [value];
|
|
54
|
+
}
|
|
55
|
+
else
|
|
56
|
+
throw new Error('Unknown client fixture generator');
|
|
57
|
+
return { ...item, case: { ...c, value } };
|
|
58
|
+
}
|
|
59
|
+
return item;
|
|
60
|
+
});
|
|
61
|
+
}
|
package/dist/compare.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwC7E,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwC7E,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,WAAW,CA+ElF"}
|
package/dist/compare.js
CHANGED
|
@@ -76,6 +76,11 @@ export function compareCase(ec, result) {
|
|
|
76
76
|
if (code !== ec.case.error) {
|
|
77
77
|
return outcome(ec, 'fail', { expected: String(ec.case.error), actual: String(code) });
|
|
78
78
|
}
|
|
79
|
+
if (ec.family === 'client-contract-v1') {
|
|
80
|
+
const o = output(result);
|
|
81
|
+
if (o.path !== ec.case.path || o.message !== ec.case.message)
|
|
82
|
+
return outcome(ec, 'fail', { message: 'client failure path/message mismatch' });
|
|
83
|
+
}
|
|
79
84
|
return outcome(ec, 'pass');
|
|
80
85
|
}
|
|
81
86
|
case 'non-portable': {
|
|
@@ -108,6 +113,9 @@ export function compareCase(ec, result) {
|
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
function compareSuccessOutput(ec, o) {
|
|
116
|
+
if (ec.family === 'client-contract-v1' && ec.case.expected !== undefined && !deepEqual(o, ec.case.expected)) {
|
|
117
|
+
return outcome(ec, 'fail', { message: 'client normalized output mismatch' });
|
|
118
|
+
}
|
|
111
119
|
if (ec.family === 'tagged-values-v1') {
|
|
112
120
|
if (o.canonicalHex !== ec.case.canonicalHex) {
|
|
113
121
|
return outcome(ec, 'fail', { expected: 'canonicalHex', actual: 'mismatch' });
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EAGf,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,UAAU,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;AAM3D,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAiB1E;AAgDD,sEAAsE;AACtE,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,mBAAmB,EAC7B,QAAQ,EAAE,UAAU,GACnB,cAAc,EAAE,CAoBlB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,mBAAmB,EAC7B,QAAQ,EAAE,UAAU,GACnB,cAAc,EAAE,CA0BlB;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,mBAAmB,EAC7B,QAAQ,EAAE,UAAU,GACnB,cAAc,EAAE,CAElB"}
|
package/dist/manifest.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { composeClientContractCases } from './client-contract-fixtures.js';
|
|
1
2
|
function decodePointerToken(token) {
|
|
2
3
|
return token.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
3
4
|
}
|
|
@@ -63,7 +64,8 @@ function enumerateFile(family, file, loadJson) {
|
|
|
63
64
|
/** Cases derived from the family fixture files, in manifest order. */
|
|
64
65
|
export function enumerateFamilyCases(manifest, loadJson) {
|
|
65
66
|
return manifest.families.flatMap((family) => {
|
|
66
|
-
const
|
|
67
|
+
const rawCases = family.files.flatMap((file) => enumerateFile(family, file, loadJson));
|
|
68
|
+
const cases = family.name === 'client-contract-v1' ? composeClientContractCases(rawCases) : rawCases;
|
|
67
69
|
// An identity case pins the canonical bytes and hash of the success case
|
|
68
70
|
// that shares its id. Attach that success value so an adapter can derive
|
|
69
71
|
// the canonical form without loading the success file itself.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Semantic client contract v1
|
|
2
|
+
|
|
3
|
+
Normative vectors for [RFC 0018](../../rfc/0018-semantic-client-contract.md).
|
|
4
|
+
The family is required by the TypeScript/Python conformance gates.
|
|
5
|
+
|
|
6
|
+
- success.json pins build, metric-only, empty and narrowed signed contracts.
|
|
7
|
+
- identities.json pins canonical complete documents and both identity domains.
|
|
8
|
+
- rejections.json pins malformed descriptors, identity failures, safe messages
|
|
9
|
+
and JSON Pointer paths, plus exact size/depth/count boundaries and text decoding.
|
|
10
|
+
- queries.json pins accepted strict HTTP/MCP input and complete normalized output.
|
|
11
|
+
- query-rejections.json pins invalid selections, types, nulls, operators and budgets.
|
|
12
|
+
- relations.json pins cross-view schema stability and query-target visibility.
|
|
13
|
+
- timezone-names.txt is the case-sensitive portable timezone registry. Runtime
|
|
14
|
+
package registries must match it; aliases are retained verbatim in identities.
|
|
15
|
+
|
|
16
|
+
For compact review, cases can reference a success ID via base/contract/left/right.
|
|
17
|
+
The conformance runner composes these references before dispatching the case;
|
|
18
|
+
implementations receive complete inputs and need no fixture-file access. A set
|
|
19
|
+
array adds/replaces fields in a deep-copied base using RFC 6901 JSON Pointers;
|
|
20
|
+
- appends an array element. Parents must exist. It never recomputes identities:
|
|
21
|
+
malformed shape validation must precede identity validation. The runner's boundary
|
|
22
|
+
generators expand only synthetic byte, depth, endpoint, descriptor and array-member counts.
|
|
23
|
+
Identity cases reuse the matching success value, as other fixture families do.
|
|
24
|
+
|
|
25
|
+
The query compiler preserves fixed MCP tool names; empty target sets have required
|
|
26
|
+
never-valued routing fields. JSON Schema pins structural types; call-time semantic
|
|
27
|
+
validation additionally enforces selected fields, uniqueness, portable timezones
|
|
28
|
+
and combined predicate budgets. No artifact identity authenticates a principal or
|
|
29
|
+
certifies an endpoint's execution implementation.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "build",
|
|
4
|
+
"canonical": "{\"contentHash\":\"f1a7071cfac3615ef809ce91f14c59b1ee68807b099afe1fe9ead06db1f5ecd1\",\"endpoints\":[{\"dataset\":\"countries\",\"defaultMeasures\":[],\"dimensions\":{\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{},\"id\":\"countries\",\"kind\":\"dataset\",\"limits\":{\"defaultLimit\":100,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":1000,\"maxMeasures\":0,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":0},\"measures\":{},\"metadata\":false,\"path\":\"/api/v1/datasets/countries/query\",\"schemaHash\":\"9a5f50cd7564f283d2f0ee8f3f1cdc27731683c939e176bd25919a83d28d94ca\",\"time\":null},{\"dataset\":\"orders\",\"defaultMeasures\":[\"revenue\",\"orderCount\",\"latestLabel\"],\"dimensions\":{\"amount\":{\"groupable\":true,\"nullable\":\"unknown\",\"orderable\":true,\"type\":\"number\",\"wireType\":\"number-or-string\"},\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"},\"customer.active\":{\"groupable\":false,\"nullable\":true,\"orderable\":false,\"type\":\"boolean\",\"wireType\":\"boolean\"},\"customer.tier\":{\"groupable\":true,\"nullable\":true,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{\"amount\":{\"operators\":[\"between\",\"eq\",\"gt\",\"gte\",\"in\",\"lt\",\"lte\",\"neq\",\"notIn\"],\"type\":\"number\"},\"country\":{\"operators\":[\"eq\",\"in\",\"like\",\"neq\",\"notIn\"],\"type\":\"string\"},\"customer.active\":{\"operators\":[\"eq\",\"neq\"],\"type\":\"boolean\"},\"customer.tier\":{\"operators\":[\"eq\",\"in\"],\"type\":\"string\"},\"paidStatus\":{\"operators\":[\"eq\"],\"type\":\"string\"}},\"id\":\"orders\",\"kind\":\"dataset\",\"limits\":{\"defaultLimit\":100,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":1000,\"maxMeasures\":50,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":100},\"measures\":{\"averageRevenue\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"},\"customer.unique\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"},\"latestLabel\":{\"having\":false,\"nullable\":true,\"wireType\":\"string\"},\"orderCount\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"},\"revenue\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"}},\"metadata\":true,\"path\":\"/api/v1/datasets/orders/query\",\"schemaHash\":\"88802c0d4798fd0758b7e7697f582b034afada967bfe0fdcb1cafd957144b1f3\",\"time\":{\"defaultTimezone\":\"UTC\",\"grains\":[\"day\",\"hour\",\"month\",\"week\"],\"periodFormat\":\"calendar-date-or-local-datetime-v1\",\"timezone\":true}},{\"dataset\":\"orders\",\"dimensions\":{\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"},\"customer.active\":{\"groupable\":false,\"nullable\":true,\"orderable\":false,\"type\":\"boolean\",\"wireType\":\"boolean\"},\"customer.tier\":{\"groupable\":true,\"nullable\":true,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{\"amount\":{\"operators\":[\"between\",\"eq\",\"gt\",\"gte\",\"in\",\"lt\",\"lte\",\"neq\",\"notIn\"],\"type\":\"number\"},\"country\":{\"operators\":[\"eq\",\"in\",\"like\",\"neq\",\"notIn\"],\"type\":\"string\"},\"customer.active\":{\"operators\":[\"eq\",\"neq\"],\"type\":\"boolean\"},\"customer.tier\":{\"operators\":[\"eq\",\"in\"],\"type\":\"string\"},\"paidStatus\":{\"operators\":[\"eq\"],\"type\":\"string\"}},\"id\":\"ordersRevenue\",\"kind\":\"metric\",\"limits\":{\"defaultLimit\":20,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":20,\"maxMeasures\":1,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":100},\"measures\":{\"revenue\":{\"having\":false,\"nullable\":true,\"wireType\":\"string\"}},\"metadata\":true,\"path\":\"/api/v1/metrics/revenue\",\"schemaHash\":\"e282fb74777e65328d87cfe5caa0349104630cd88137b1842289e0c83676a98d\",\"time\":{\"defaultTimezone\":\"UTC\",\"grains\":[\"day\",\"hour\",\"month\",\"week\"],\"periodFormat\":\"calendar-date-or-local-datetime-v1\",\"timezone\":true}}],\"kind\":\"hypequery-client-contract\",\"version\":1,\"view\":\"build\"}",
|
|
5
|
+
"endpointHashes": {
|
|
6
|
+
"countries": "9a5f50cd7564f283d2f0ee8f3f1cdc27731683c939e176bd25919a83d28d94ca",
|
|
7
|
+
"orders": "88802c0d4798fd0758b7e7697f582b034afada967bfe0fdcb1cafd957144b1f3",
|
|
8
|
+
"ordersRevenue": "e282fb74777e65328d87cfe5caa0349104630cd88137b1842289e0c83676a98d"
|
|
9
|
+
},
|
|
10
|
+
"sha256": "f1a7071cfac3615ef809ce91f14c59b1ee68807b099afe1fe9ead06db1f5ecd1"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "metric-only",
|
|
14
|
+
"canonical": "{\"contentHash\":\"3dc2252343be12ec4d2434a24dd86e4a4ec5aede037d646c44d14179d9672e81\",\"endpoints\":[{\"dataset\":\"orders\",\"dimensions\":{\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"},\"customer.active\":{\"groupable\":false,\"nullable\":true,\"orderable\":false,\"type\":\"boolean\",\"wireType\":\"boolean\"},\"customer.tier\":{\"groupable\":true,\"nullable\":true,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{\"amount\":{\"operators\":[\"between\",\"eq\",\"gt\",\"gte\",\"in\",\"lt\",\"lte\",\"neq\",\"notIn\"],\"type\":\"number\"},\"country\":{\"operators\":[\"eq\",\"in\",\"like\",\"neq\",\"notIn\"],\"type\":\"string\"},\"customer.active\":{\"operators\":[\"eq\",\"neq\"],\"type\":\"boolean\"},\"customer.tier\":{\"operators\":[\"eq\",\"in\"],\"type\":\"string\"},\"paidStatus\":{\"operators\":[\"eq\"],\"type\":\"string\"}},\"id\":\"ordersRevenue\",\"kind\":\"metric\",\"limits\":{\"defaultLimit\":20,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":20,\"maxMeasures\":1,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":100},\"measures\":{\"revenue\":{\"having\":false,\"nullable\":true,\"wireType\":\"string\"}},\"metadata\":true,\"path\":\"/api/v1/metrics/revenue\",\"schemaHash\":\"e282fb74777e65328d87cfe5caa0349104630cd88137b1842289e0c83676a98d\",\"time\":{\"defaultTimezone\":\"UTC\",\"grains\":[\"day\",\"hour\",\"month\",\"week\"],\"periodFormat\":\"calendar-date-or-local-datetime-v1\",\"timezone\":true}}],\"kind\":\"hypequery-client-contract\",\"version\":1,\"view\":\"authorized\"}",
|
|
15
|
+
"endpointHashes": {
|
|
16
|
+
"ordersRevenue": "e282fb74777e65328d87cfe5caa0349104630cd88137b1842289e0c83676a98d"
|
|
17
|
+
},
|
|
18
|
+
"sha256": "3dc2252343be12ec4d2434a24dd86e4a4ec5aede037d646c44d14179d9672e81"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "empty",
|
|
22
|
+
"canonical": "{\"contentHash\":\"7a31724c56ffb78f0e8e2ab022101c422671f6bb4291ae6c09b1cd634180507e\",\"endpoints\":[],\"kind\":\"hypequery-client-contract\",\"version\":1,\"view\":\"authorized\"}",
|
|
23
|
+
"endpointHashes": {},
|
|
24
|
+
"sha256": "7a31724c56ffb78f0e8e2ab022101c422671f6bb4291ae6c09b1cd634180507e"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "narrowed",
|
|
28
|
+
"canonical": "{\"contentHash\":\"c350b9b6e0351acbbac7509bf5d889afa343b9fb5048d826265d8e9f5ef895d8\",\"endpoints\":[{\"dataset\":\"countries\",\"defaultMeasures\":[],\"dimensions\":{\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{},\"id\":\"countries\",\"kind\":\"dataset\",\"limits\":{\"defaultLimit\":10,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":10,\"maxMeasures\":0,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":0},\"measures\":{},\"metadata\":false,\"path\":\"/api/v1/datasets/countries/query\",\"schemaHash\":\"9a5f50cd7564f283d2f0ee8f3f1cdc27731683c939e176bd25919a83d28d94ca\",\"time\":null},{\"dataset\":\"orders\",\"defaultMeasures\":[\"revenue\",\"orderCount\",\"latestLabel\"],\"dimensions\":{\"amount\":{\"groupable\":true,\"nullable\":\"unknown\",\"orderable\":true,\"type\":\"number\",\"wireType\":\"number-or-string\"},\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"},\"customer.active\":{\"groupable\":false,\"nullable\":true,\"orderable\":false,\"type\":\"boolean\",\"wireType\":\"boolean\"},\"customer.tier\":{\"groupable\":true,\"nullable\":true,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{\"amount\":{\"operators\":[\"between\",\"eq\",\"gt\",\"gte\",\"in\",\"lt\",\"lte\",\"neq\",\"notIn\"],\"type\":\"number\"},\"country\":{\"operators\":[\"eq\",\"in\",\"like\",\"neq\",\"notIn\"],\"type\":\"string\"},\"customer.active\":{\"operators\":[\"eq\",\"neq\"],\"type\":\"boolean\"},\"customer.tier\":{\"operators\":[\"eq\",\"in\"],\"type\":\"string\"},\"paidStatus\":{\"operators\":[\"eq\"],\"type\":\"string\"}},\"id\":\"orders\",\"kind\":\"dataset\",\"limits\":{\"defaultLimit\":10,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":10,\"maxMeasures\":50,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":100},\"measures\":{\"averageRevenue\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"},\"customer.unique\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"},\"latestLabel\":{\"having\":false,\"nullable\":true,\"wireType\":\"string\"},\"orderCount\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"},\"revenue\":{\"having\":true,\"nullable\":true,\"wireType\":\"string\"}},\"metadata\":true,\"path\":\"/api/v1/datasets/orders/query\",\"schemaHash\":\"88802c0d4798fd0758b7e7697f582b034afada967bfe0fdcb1cafd957144b1f3\",\"time\":{\"defaultTimezone\":\"UTC\",\"grains\":[\"day\",\"hour\",\"month\",\"week\"],\"periodFormat\":\"calendar-date-or-local-datetime-v1\",\"timezone\":true}},{\"dataset\":\"orders\",\"dimensions\":{\"country\":{\"groupable\":true,\"nullable\":false,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"},\"customer.active\":{\"groupable\":false,\"nullable\":true,\"orderable\":false,\"type\":\"boolean\",\"wireType\":\"boolean\"},\"customer.tier\":{\"groupable\":true,\"nullable\":true,\"orderable\":true,\"type\":\"string\",\"wireType\":\"string\"}},\"filters\":{\"amount\":{\"operators\":[\"between\",\"eq\",\"gt\",\"gte\",\"in\",\"lt\",\"lte\",\"neq\",\"notIn\"],\"type\":\"number\"},\"country\":{\"operators\":[\"eq\",\"in\",\"like\",\"neq\",\"notIn\"],\"type\":\"string\"},\"customer.active\":{\"operators\":[\"eq\",\"neq\"],\"type\":\"boolean\"},\"customer.tier\":{\"operators\":[\"eq\",\"in\"],\"type\":\"string\"},\"paidStatus\":{\"operators\":[\"eq\"],\"type\":\"string\"}},\"id\":\"ordersRevenue\",\"kind\":\"metric\",\"limits\":{\"defaultLimit\":10,\"maxDimensions\":50,\"maxFilterValues\":1000,\"maxLimit\":10,\"maxMeasures\":1,\"maxOffset\":10000,\"maxOrderBy\":50,\"maxPredicates\":100},\"measures\":{\"revenue\":{\"having\":false,\"nullable\":true,\"wireType\":\"string\"}},\"metadata\":true,\"path\":\"/api/v1/metrics/revenue\",\"schemaHash\":\"e282fb74777e65328d87cfe5caa0349104630cd88137b1842289e0c83676a98d\",\"time\":{\"defaultTimezone\":\"UTC\",\"grains\":[\"day\",\"hour\",\"month\",\"week\"],\"periodFormat\":\"calendar-date-or-local-datetime-v1\",\"timezone\":true}}],\"kind\":\"hypequery-client-contract\",\"version\":1,\"view\":\"authorized\"}",
|
|
29
|
+
"endpointHashes": {
|
|
30
|
+
"countries": "9a5f50cd7564f283d2f0ee8f3f1cdc27731683c939e176bd25919a83d28d94ca",
|
|
31
|
+
"orders": "88802c0d4798fd0758b7e7697f582b034afada967bfe0fdcb1cafd957144b1f3",
|
|
32
|
+
"ordersRevenue": "e282fb74777e65328d87cfe5caa0349104630cd88137b1842289e0c83676a98d"
|
|
33
|
+
},
|
|
34
|
+
"sha256": "c350b9b6e0351acbbac7509bf5d889afa343b9fb5048d826265d8e9f5ef895d8"
|
|
35
|
+
}
|
|
36
|
+
]
|