@hypequery/protocol 0.0.0-canary-20260715102718 → 0.1.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 +9 -39
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/package.json +1 -4
- package/dist/expressions/errors.d.ts +0 -8
- package/dist/expressions/errors.d.ts.map +0 -1
- package/dist/expressions/errors.js +0 -13
- package/dist/expressions/index.d.ts +0 -5
- package/dist/expressions/index.d.ts.map +0 -1
- package/dist/expressions/index.js +0 -3
- package/dist/expressions/limits.d.ts +0 -4
- package/dist/expressions/limits.d.ts.map +0 -1
- package/dist/expressions/limits.js +0 -17
- package/dist/expressions/types.d.ts +0 -77
- package/dist/expressions/types.d.ts.map +0 -1
- package/dist/expressions/types.js +0 -1
- package/dist/expressions/validate.d.ts +0 -4
- package/dist/expressions/validate.d.ts.map +0 -1
- package/dist/expressions/validate.js +0 -338
- package/dist/identifiers/identifiers.d.ts +0 -14
- package/dist/identifiers/identifiers.d.ts.map +0 -1
- package/dist/identifiers/identifiers.js +0 -87
- package/dist/identifiers/index.d.ts +0 -4
- package/dist/identifiers/index.d.ts.map +0 -1
- package/dist/identifiers/index.js +0 -2
- package/dist/identifiers/types.d.ts +0 -16
- package/dist/identifiers/types.d.ts.map +0 -1
- package/dist/identifiers/types.js +0 -5
- package/dist/schemas/errors.d.ts +0 -8
- package/dist/schemas/errors.d.ts.map +0 -1
- package/dist/schemas/errors.js +0 -13
- package/dist/schemas/index.d.ts +0 -5
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -3
- package/dist/schemas/limits.d.ts +0 -4
- package/dist/schemas/limits.d.ts.map +0 -1
- package/dist/schemas/limits.js +0 -18
- package/dist/schemas/types.d.ts +0 -60
- package/dist/schemas/types.d.ts.map +0 -1
- package/dist/schemas/types.js +0 -1
- package/dist/schemas/validate.d.ts +0 -3
- package/dist/schemas/validate.d.ts.map +0 -1
- package/dist/schemas/validate.js +0 -391
- package/dist/values/codec.d.ts +0 -13
- package/dist/values/codec.d.ts.map +0 -1
- package/dist/values/codec.js +0 -39
- package/dist/values/errors.d.ts +0 -8
- package/dist/values/errors.d.ts.map +0 -1
- package/dist/values/errors.js +0 -13
- package/dist/values/index.d.ts +0 -7
- package/dist/values/index.d.ts.map +0 -1
- package/dist/values/index.js +0 -4
- package/dist/values/jcs.d.ts +0 -2
- package/dist/values/jcs.d.ts.map +0 -1
- package/dist/values/jcs.js +0 -23
- package/dist/values/limits.d.ts +0 -4
- package/dist/values/limits.d.ts.map +0 -1
- package/dist/values/limits.js +0 -26
- package/dist/values/parser.d.ts +0 -3
- package/dist/values/parser.d.ts.map +0 -1
- package/dist/values/parser.js +0 -254
- package/dist/values/snapshot.d.ts +0 -3
- package/dist/values/snapshot.d.ts.map +0 -1
- package/dist/values/snapshot.js +0 -96
- package/dist/values/types.d.ts +0 -78
- package/dist/values/types.d.ts.map +0 -1
- package/dist/values/types.js +0 -1
- package/dist/values/validate.d.ts +0 -7
- package/dist/values/validate.d.ts.map +0 -1
- package/dist/values/validate.js +0 -332
package/README.md
CHANGED
|
@@ -5,23 +5,20 @@ Hypequery artifacts.
|
|
|
5
5
|
|
|
6
6
|
## Current status
|
|
7
7
|
|
|
8
|
-
This package
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
This package is an intentionally empty public scaffold. It does not yet define
|
|
9
|
+
a stable protocol or an executable deployment bundle. Runtime exports will be
|
|
10
|
+
added incrementally after their language-neutral specifications and conformance
|
|
11
|
+
fixtures are accepted.
|
|
12
12
|
|
|
13
13
|
The normative source is
|
|
14
14
|
[`specs/security-protocol`](../../specs/security-protocol/README.md).
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Intended scope
|
|
17
17
|
|
|
18
|
-
The package
|
|
19
|
-
accepted protocol rules
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
closed dataset expression/query AST. Artifact envelopes and compatibility
|
|
23
|
-
checks will follow in separate changes. A closed portable query-schema tree
|
|
24
|
-
provides the next layer for named-query input and output contracts.
|
|
18
|
+
The package will contain deterministic, framework-independent implementations
|
|
19
|
+
of accepted protocol rules, including strict validation, canonical encoding,
|
|
20
|
+
digest calculation, identifiers, portable AST structures, artifact envelopes,
|
|
21
|
+
and compatibility checks.
|
|
25
22
|
|
|
26
23
|
It will not connect to ClickHouse, execute queries, load project source, access
|
|
27
24
|
credentials or the environment, perform network or filesystem I/O, implement
|
|
@@ -37,33 +34,6 @@ Only the root package export is public. Deep imports from `src` or `dist` are
|
|
|
37
34
|
unsupported. Package SemVer and protocol/artifact versions are separate; an
|
|
38
35
|
installed npm version never determines an artifact's identity.
|
|
39
36
|
|
|
40
|
-
The proposed tagged-value surface exports:
|
|
41
|
-
|
|
42
|
-
- `validateCanonicalValue`
|
|
43
|
-
- `encodeCanonicalValue` and `encodeCanonicalValueToString`
|
|
44
|
-
- `decodeCanonicalValue`
|
|
45
|
-
- `hashCanonicalValue`
|
|
46
|
-
- `ProtocolValueError` and stable error-code types
|
|
47
|
-
- tagged-value, option, and limit types
|
|
48
|
-
|
|
49
|
-
The raw conformance digest is not a deployment identity or shared cache key.
|
|
50
|
-
Those domains require separate, versioned, domain-separated contracts.
|
|
51
|
-
|
|
52
|
-
The proposed identifier surface exports strict parse, guard, split, and join
|
|
53
|
-
helpers for simple and dot-qualified logical identifiers. Identifiers are
|
|
54
|
-
ASCII, case-sensitive, preserved exactly, and are not SQL identifiers.
|
|
55
|
-
|
|
56
|
-
The proposed expression surface exports strict validators and immutable types
|
|
57
|
-
for derived formulas, comparisons, filtered aggregations, all current dataset
|
|
58
|
-
aggregations, and dataset/metric query envelopes. It intentionally excludes raw
|
|
59
|
-
SQL and tenant identity; consumers validate names and policy against a dataset
|
|
60
|
-
contract before execution.
|
|
61
|
-
|
|
62
|
-
The proposed schema surface exports strict types and validation for portable
|
|
63
|
-
query input/output schemas. It covers the current declarative Serve/Zod schema
|
|
64
|
-
features without depending on Zod or embedding executable transforms and
|
|
65
|
-
refinements.
|
|
66
|
-
|
|
67
37
|
## Runtime compatibility
|
|
68
38
|
|
|
69
39
|
This package is ESM-only. Consumers must load it with `import`; CommonJS
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
1
|
+
/**
|
|
2
|
+
* Public TypeScript reference implementation for the Hypequery protocol.
|
|
3
|
+
*
|
|
4
|
+
* The scaffold intentionally exports no runtime contract. Each future export
|
|
5
|
+
* must implement an accepted specification and ship with normative fixtures.
|
|
6
|
+
* See `specs/security-protocol/` in the repository.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { PROTOCOL_IDENTIFIER_LIMITS, ProtocolIdentifierError, isProtocolIdentifier, isProtocolQualifiedIdentifier, joinProtocolQualifiedIdentifier, parseProtocolIdentifier, parseProtocolQualifiedIdentifier, splitProtocolQualifiedIdentifier, } from './identifiers/index.js';
|
|
3
|
-
export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS, ProtocolExpressionError, validateProtocolExpression, validateProtocolSemanticQuery, } from './expressions/index.js';
|
|
4
|
-
export { DEFAULT_PROTOCOL_SCHEMA_LIMITS, ProtocolSchemaError, validateProtocolSchema, } from './schemas/index.js';
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Public contracts and TypeScript reference implementation for portable Hypequery artifacts",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -17,9 +17,6 @@
|
|
|
17
17
|
"dist",
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"@noble/hashes": "^1.8.0"
|
|
22
|
-
},
|
|
23
20
|
"devDependencies": {
|
|
24
21
|
"typescript": "^5.7.3",
|
|
25
22
|
"vitest": "^3.2.6"
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ProtocolExpressionErrorCode } from './types.js';
|
|
2
|
-
export declare class ProtocolExpressionError extends TypeError {
|
|
3
|
-
readonly code: ProtocolExpressionErrorCode;
|
|
4
|
-
readonly path: string;
|
|
5
|
-
constructor(code: ProtocolExpressionErrorCode, path?: string);
|
|
6
|
-
}
|
|
7
|
-
export declare function expressionError(code: ProtocolExpressionErrorCode, path?: string): never;
|
|
8
|
-
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/expressions/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE9D,qBAAa,uBAAwB,SAAQ,SAAS;IACpD,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,2BAA2B,EAAE,IAAI,SAAM;CAM1D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,2BAA2B,EAAE,IAAI,SAAM,GAAG,KAAK,CAEpF"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export class ProtocolExpressionError extends TypeError {
|
|
2
|
-
code;
|
|
3
|
-
path;
|
|
4
|
-
constructor(code, path = '$') {
|
|
5
|
-
super(`${code} at ${path}`);
|
|
6
|
-
this.name = 'ProtocolExpressionError';
|
|
7
|
-
this.code = code;
|
|
8
|
-
this.path = path;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
export function expressionError(code, path = '$') {
|
|
12
|
-
throw new ProtocolExpressionError(code, path);
|
|
13
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { ProtocolExpressionError } from './errors.js';
|
|
2
|
-
export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS } from './limits.js';
|
|
3
|
-
export { validateProtocolExpression, validateProtocolSemanticQuery } from './validate.js';
|
|
4
|
-
export type { ProtocolAggregation, ProtocolBinaryOperator, ProtocolComparisonOperator, ProtocolDatasetQuery, ProtocolExpression, ProtocolExpressionErrorCode, ProtocolExpressionLimits, ProtocolExpressionOptions, ProtocolFunctionName, ProtocolMetricQuery, ProtocolOrderBy, ProtocolSemanticQuery, ProtocolTimeGrain, } from './types.js';
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/expressions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,kCAAkC,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAC1F,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ProtocolExpressionLimits, ProtocolExpressionOptions } from './types.js';
|
|
2
|
-
export declare const DEFAULT_PROTOCOL_EXPRESSION_LIMITS: Readonly<ProtocolExpressionLimits>;
|
|
3
|
-
export declare function resolveExpressionLimits(options?: ProtocolExpressionOptions): Readonly<ProtocolExpressionLimits>;
|
|
4
|
-
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/expressions/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEtF,eAAO,MAAM,kCAAkC,EAAE,QAAQ,CAAC,wBAAwB,CAIhF,CAAC;AAEH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,yBAA8B,GACtC,QAAQ,CAAC,wBAAwB,CAAC,CAWpC"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_PROTOCOL_EXPRESSION_LIMITS = Object.freeze({
|
|
2
|
-
maxDepth: 16,
|
|
3
|
-
maxNodes: 1_000,
|
|
4
|
-
maxCollectionItems: 100,
|
|
5
|
-
});
|
|
6
|
-
export function resolveExpressionLimits(options = {}) {
|
|
7
|
-
const limits = { ...DEFAULT_PROTOCOL_EXPRESSION_LIMITS };
|
|
8
|
-
for (const key of Object.keys(options.limits ?? {})) {
|
|
9
|
-
const value = options.limits?.[key];
|
|
10
|
-
if (!Number.isSafeInteger(value) || value < 1
|
|
11
|
-
|| value > DEFAULT_PROTOCOL_EXPRESSION_LIMITS[key]) {
|
|
12
|
-
throw new RangeError(`${key} must be a positive integer no greater than the protocol v1 maximum`);
|
|
13
|
-
}
|
|
14
|
-
limits[key] = value;
|
|
15
|
-
}
|
|
16
|
-
return Object.freeze(limits);
|
|
17
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import type { ProtocolIdentifier, ProtocolQualifiedIdentifier } from '../identifiers/index.js';
|
|
2
|
-
import type { CanonicalValue } from '../values/index.js';
|
|
3
|
-
export type ProtocolBinaryOperator = 'add' | 'subtract' | 'multiply' | 'divide';
|
|
4
|
-
export type ProtocolFunctionName = 'nullIfZero' | 'coalesce' | 'round' | 'floor' | 'ceil';
|
|
5
|
-
export type ProtocolComparisonOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'between' | 'like';
|
|
6
|
-
export type ProtocolAggregation = 'sum' | 'count' | 'countDistinct' | 'avg' | 'min' | 'max' | 'argMax' | 'argMin' | 'percentile' | 'stddev' | 'variance';
|
|
7
|
-
export type ProtocolExpression = {
|
|
8
|
-
readonly kind: 'reference';
|
|
9
|
-
readonly name: ProtocolQualifiedIdentifier;
|
|
10
|
-
} | {
|
|
11
|
-
readonly kind: 'literal';
|
|
12
|
-
readonly value: CanonicalValue;
|
|
13
|
-
} | {
|
|
14
|
-
readonly kind: 'binary';
|
|
15
|
-
readonly operator: ProtocolBinaryOperator;
|
|
16
|
-
readonly left: ProtocolExpression;
|
|
17
|
-
readonly right: ProtocolExpression;
|
|
18
|
-
} | {
|
|
19
|
-
readonly kind: 'call';
|
|
20
|
-
readonly function: ProtocolFunctionName;
|
|
21
|
-
readonly args: readonly ProtocolExpression[];
|
|
22
|
-
} | {
|
|
23
|
-
readonly kind: 'comparison';
|
|
24
|
-
readonly operator: ProtocolComparisonOperator;
|
|
25
|
-
readonly left: ProtocolExpression;
|
|
26
|
-
readonly right: ProtocolExpression;
|
|
27
|
-
} | {
|
|
28
|
-
readonly kind: 'logical';
|
|
29
|
-
readonly operator: 'and' | 'or';
|
|
30
|
-
readonly operands: readonly ProtocolExpression[];
|
|
31
|
-
} | {
|
|
32
|
-
readonly kind: 'logical';
|
|
33
|
-
readonly operator: 'not';
|
|
34
|
-
readonly operand: ProtocolExpression;
|
|
35
|
-
} | {
|
|
36
|
-
readonly kind: 'aggregate';
|
|
37
|
-
readonly aggregation: ProtocolAggregation;
|
|
38
|
-
readonly field: ProtocolQualifiedIdentifier;
|
|
39
|
-
readonly argField?: ProtocolQualifiedIdentifier;
|
|
40
|
-
readonly level?: number;
|
|
41
|
-
readonly filters?: readonly ProtocolExpression[];
|
|
42
|
-
};
|
|
43
|
-
export type ProtocolTimeGrain = 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
44
|
-
export interface ProtocolOrderBy {
|
|
45
|
-
readonly field: ProtocolQualifiedIdentifier;
|
|
46
|
-
readonly direction: 'asc' | 'desc';
|
|
47
|
-
}
|
|
48
|
-
interface ProtocolQueryCommon {
|
|
49
|
-
readonly dataset: ProtocolIdentifier;
|
|
50
|
-
readonly dimensions?: readonly ProtocolQualifiedIdentifier[];
|
|
51
|
-
readonly filters?: readonly ProtocolExpression[];
|
|
52
|
-
readonly orderBy?: readonly ProtocolOrderBy[];
|
|
53
|
-
readonly limit?: number;
|
|
54
|
-
readonly offset?: number;
|
|
55
|
-
readonly by?: ProtocolTimeGrain;
|
|
56
|
-
readonly includeMeta?: boolean;
|
|
57
|
-
}
|
|
58
|
-
export interface ProtocolDatasetQuery extends ProtocolQueryCommon {
|
|
59
|
-
readonly kind: 'dataset';
|
|
60
|
-
readonly measures?: readonly ProtocolIdentifier[];
|
|
61
|
-
}
|
|
62
|
-
export interface ProtocolMetricQuery extends ProtocolQueryCommon {
|
|
63
|
-
readonly kind: 'metric';
|
|
64
|
-
readonly metric: ProtocolIdentifier;
|
|
65
|
-
}
|
|
66
|
-
export type ProtocolSemanticQuery = ProtocolDatasetQuery | ProtocolMetricQuery;
|
|
67
|
-
export interface ProtocolExpressionLimits {
|
|
68
|
-
readonly maxDepth: number;
|
|
69
|
-
readonly maxNodes: number;
|
|
70
|
-
readonly maxCollectionItems: number;
|
|
71
|
-
}
|
|
72
|
-
export interface ProtocolExpressionOptions {
|
|
73
|
-
readonly limits?: Partial<ProtocolExpressionLimits>;
|
|
74
|
-
}
|
|
75
|
-
export type ProtocolExpressionErrorCode = 'HQ_EXPRESSION_TYPE' | 'HQ_EXPRESSION_UNKNOWN_FIELD' | 'HQ_EXPRESSION_UNKNOWN_KIND' | 'HQ_EXPRESSION_INVALID_IDENTIFIER' | 'HQ_EXPRESSION_INVALID_VALUE' | 'HQ_EXPRESSION_INVALID_OPERATOR' | 'HQ_EXPRESSION_INVALID_ARITY' | 'HQ_EXPRESSION_INVALID_AGGREGATION' | 'HQ_EXPRESSION_INVALID_QUERY' | 'HQ_EXPRESSION_TOO_DEEP' | 'HQ_EXPRESSION_TOO_MANY_NODES' | 'HQ_EXPRESSION_TOO_MANY_ITEMS' | 'HQ_EXPRESSION_UNSAFE_OBJECT';
|
|
76
|
-
export {};
|
|
77
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/expressions/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ProtocolExpression, ProtocolExpressionOptions, ProtocolSemanticQuery } from './types.js';
|
|
2
|
-
export declare function validateProtocolExpression(input: unknown, options?: ProtocolExpressionOptions): ProtocolExpression;
|
|
3
|
-
export declare function validateProtocolSemanticQuery(input: unknown, options?: ProtocolExpressionOptions): ProtocolSemanticQuery;
|
|
4
|
-
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/expressions/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,kBAAkB,EAElB,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AA4PpB,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,kBAAkB,CAEpB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,qBAAqB,CAiDvB"}
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
import { ProtocolIdentifierError, parseProtocolIdentifier, parseProtocolQualifiedIdentifier, } from '../identifiers/index.js';
|
|
2
|
-
import { ProtocolValueError, validateCanonicalValue } from '../values/index.js';
|
|
3
|
-
import { expressionError } from './errors.js';
|
|
4
|
-
import { resolveExpressionLimits } from './limits.js';
|
|
5
|
-
const BINARY = new Set(['add', 'subtract', 'multiply', 'divide']);
|
|
6
|
-
const COMPARISONS = new Set(['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'between', 'like']);
|
|
7
|
-
const AGGREGATIONS = new Set([
|
|
8
|
-
'sum', 'count', 'countDistinct', 'avg', 'min', 'max',
|
|
9
|
-
'argMax', 'argMin', 'percentile', 'stddev', 'variance',
|
|
10
|
-
]);
|
|
11
|
-
const GRAINS = new Set(['day', 'week', 'month', 'quarter', 'year']);
|
|
12
|
-
const CALL_ARITY = Object.freeze({
|
|
13
|
-
nullIfZero: [1, 1],
|
|
14
|
-
coalesce: [2, 2],
|
|
15
|
-
round: [1, 2],
|
|
16
|
-
floor: [1, 1],
|
|
17
|
-
ceil: [1, 1],
|
|
18
|
-
});
|
|
19
|
-
function requireRecord(input, path) {
|
|
20
|
-
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
21
|
-
expressionError('HQ_EXPRESSION_TYPE', path);
|
|
22
|
-
}
|
|
23
|
-
const prototype = Object.getPrototypeOf(input);
|
|
24
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
25
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', path);
|
|
26
|
-
}
|
|
27
|
-
const descriptors = Object.getOwnPropertyDescriptors(input);
|
|
28
|
-
if (Object.getOwnPropertySymbols(input).length > 0) {
|
|
29
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', path);
|
|
30
|
-
}
|
|
31
|
-
for (const descriptor of Object.values(descriptors)) {
|
|
32
|
-
if (!descriptor.enumerable || !('value' in descriptor)) {
|
|
33
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', path);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return input;
|
|
37
|
-
}
|
|
38
|
-
function exactFields(value, required, optional, path) {
|
|
39
|
-
const allowed = new Set([...required, ...optional]);
|
|
40
|
-
for (const key of Object.keys(value)) {
|
|
41
|
-
if (!allowed.has(key))
|
|
42
|
-
expressionError('HQ_EXPRESSION_UNKNOWN_FIELD', `${path}.${key}`);
|
|
43
|
-
}
|
|
44
|
-
for (const key of required) {
|
|
45
|
-
if (!Object.hasOwn(value, key))
|
|
46
|
-
expressionError('HQ_EXPRESSION_TYPE', `${path}.${key}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function stringValue(value, path) {
|
|
50
|
-
if (typeof value !== 'string')
|
|
51
|
-
expressionError('HQ_EXPRESSION_TYPE', path);
|
|
52
|
-
return value;
|
|
53
|
-
}
|
|
54
|
-
function identifier(value, path, qualified = true) {
|
|
55
|
-
try {
|
|
56
|
-
return qualified ? parseProtocolQualifiedIdentifier(value) : parseProtocolIdentifier(value);
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
if (error instanceof ProtocolIdentifierError) {
|
|
60
|
-
expressionError('HQ_EXPRESSION_INVALID_IDENTIFIER', path);
|
|
61
|
-
}
|
|
62
|
-
throw error;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function enter(value, depth, state, path) {
|
|
66
|
-
if (depth > state.limits.maxDepth)
|
|
67
|
-
expressionError('HQ_EXPRESSION_TOO_DEEP', path);
|
|
68
|
-
state.nodes += 1;
|
|
69
|
-
if (state.nodes > state.limits.maxNodes)
|
|
70
|
-
expressionError('HQ_EXPRESSION_TOO_MANY_NODES', path);
|
|
71
|
-
if (state.active.has(value))
|
|
72
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', path);
|
|
73
|
-
state.active.add(value);
|
|
74
|
-
}
|
|
75
|
-
function arrayValue(value, path, state) {
|
|
76
|
-
if (!Array.isArray(value))
|
|
77
|
-
expressionError('HQ_EXPRESSION_TYPE', path);
|
|
78
|
-
if (Object.getPrototypeOf(value) !== Array.prototype || Object.getOwnPropertySymbols(value).length > 0) {
|
|
79
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', path);
|
|
80
|
-
}
|
|
81
|
-
if (value.length > state.limits.maxCollectionItems)
|
|
82
|
-
expressionError('HQ_EXPRESSION_TOO_MANY_ITEMS', path);
|
|
83
|
-
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
84
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
85
|
-
const descriptor = descriptors[String(index)];
|
|
86
|
-
if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) {
|
|
87
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', `${path}[${index}]`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (Object.keys(value).length !== value.length) {
|
|
91
|
-
expressionError('HQ_EXPRESSION_UNSAFE_OBJECT', path);
|
|
92
|
-
}
|
|
93
|
-
return value;
|
|
94
|
-
}
|
|
95
|
-
function freezeRecord(entries) {
|
|
96
|
-
return Object.freeze(Object.assign(Object.create(null), entries));
|
|
97
|
-
}
|
|
98
|
-
function validateExpression(input, path, depth, state) {
|
|
99
|
-
const value = requireRecord(input, path);
|
|
100
|
-
enter(value, depth, state, path);
|
|
101
|
-
try {
|
|
102
|
-
const kind = stringValue(value.kind, `${path}.kind`);
|
|
103
|
-
switch (kind) {
|
|
104
|
-
case 'reference': {
|
|
105
|
-
exactFields(value, ['kind', 'name'], [], path);
|
|
106
|
-
return freezeRecord({ kind, name: identifier(value.name, `${path}.name`) });
|
|
107
|
-
}
|
|
108
|
-
case 'literal': {
|
|
109
|
-
exactFields(value, ['kind', 'value'], [], path);
|
|
110
|
-
try {
|
|
111
|
-
return freezeRecord({ kind, value: validateCanonicalValue(value.value) });
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
if (error instanceof ProtocolValueError)
|
|
115
|
-
expressionError('HQ_EXPRESSION_INVALID_VALUE', `${path}.value`);
|
|
116
|
-
throw error;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
case 'binary': {
|
|
120
|
-
exactFields(value, ['kind', 'operator', 'left', 'right'], [], path);
|
|
121
|
-
const operator = stringValue(value.operator, `${path}.operator`);
|
|
122
|
-
if (!BINARY.has(operator))
|
|
123
|
-
expressionError('HQ_EXPRESSION_INVALID_OPERATOR', `${path}.operator`);
|
|
124
|
-
return freezeRecord({
|
|
125
|
-
kind,
|
|
126
|
-
operator,
|
|
127
|
-
left: validateExpression(value.left, `${path}.left`, depth + 1, state),
|
|
128
|
-
right: validateExpression(value.right, `${path}.right`, depth + 1, state),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
case 'call': {
|
|
132
|
-
exactFields(value, ['kind', 'function', 'args'], [], path);
|
|
133
|
-
const fn = stringValue(value.function, `${path}.function`);
|
|
134
|
-
const arity = CALL_ARITY[fn];
|
|
135
|
-
if (!arity)
|
|
136
|
-
expressionError('HQ_EXPRESSION_INVALID_OPERATOR', `${path}.function`);
|
|
137
|
-
const args = arrayValue(value.args, `${path}.args`, state);
|
|
138
|
-
if (args.length < arity[0] || args.length > arity[1]) {
|
|
139
|
-
expressionError('HQ_EXPRESSION_INVALID_ARITY', `${path}.args`);
|
|
140
|
-
}
|
|
141
|
-
return freezeRecord({
|
|
142
|
-
kind,
|
|
143
|
-
function: fn,
|
|
144
|
-
args: Object.freeze(args.map((arg, index) => validateExpression(arg, `${path}.args[${index}]`, depth + 1, state))),
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
case 'comparison': {
|
|
148
|
-
exactFields(value, ['kind', 'operator', 'left', 'right'], [], path);
|
|
149
|
-
const operator = stringValue(value.operator, `${path}.operator`);
|
|
150
|
-
if (!COMPARISONS.has(operator))
|
|
151
|
-
expressionError('HQ_EXPRESSION_INVALID_OPERATOR', `${path}.operator`);
|
|
152
|
-
const left = validateExpression(value.left, `${path}.left`, depth + 1, state);
|
|
153
|
-
const right = validateExpression(value.right, `${path}.right`, depth + 1, state);
|
|
154
|
-
validateComparisonOperands(operator, right, `${path}.right`);
|
|
155
|
-
return freezeRecord({
|
|
156
|
-
kind,
|
|
157
|
-
operator,
|
|
158
|
-
left,
|
|
159
|
-
right,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
case 'logical': {
|
|
163
|
-
exactFields(value, ['kind', 'operator'], ['operand', 'operands'], path);
|
|
164
|
-
const operator = stringValue(value.operator, `${path}.operator`);
|
|
165
|
-
if (operator === 'not') {
|
|
166
|
-
if (!Object.hasOwn(value, 'operand') || Object.hasOwn(value, 'operands')) {
|
|
167
|
-
expressionError('HQ_EXPRESSION_INVALID_ARITY', path);
|
|
168
|
-
}
|
|
169
|
-
return freezeRecord({ kind, operator, operand: validateExpression(value.operand, `${path}.operand`, depth + 1, state) });
|
|
170
|
-
}
|
|
171
|
-
if (operator !== 'and' && operator !== 'or')
|
|
172
|
-
expressionError('HQ_EXPRESSION_INVALID_OPERATOR', `${path}.operator`);
|
|
173
|
-
if (!Object.hasOwn(value, 'operands') || Object.hasOwn(value, 'operand')) {
|
|
174
|
-
expressionError('HQ_EXPRESSION_INVALID_ARITY', path);
|
|
175
|
-
}
|
|
176
|
-
const operands = arrayValue(value.operands, `${path}.operands`, state);
|
|
177
|
-
if (operands.length < 2)
|
|
178
|
-
expressionError('HQ_EXPRESSION_INVALID_ARITY', `${path}.operands`);
|
|
179
|
-
return freezeRecord({
|
|
180
|
-
kind,
|
|
181
|
-
operator,
|
|
182
|
-
operands: Object.freeze(operands.map((operand, index) => validateExpression(operand, `${path}.operands[${index}]`, depth + 1, state))),
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
case 'aggregate':
|
|
186
|
-
return validateAggregate(value, path, depth, state);
|
|
187
|
-
default:
|
|
188
|
-
expressionError('HQ_EXPRESSION_UNKNOWN_KIND', `${path}.kind`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
finally {
|
|
192
|
-
state.active.delete(value);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function validateComparisonOperands(operator, right, path) {
|
|
196
|
-
if (operator === 'like') {
|
|
197
|
-
if (right.kind !== 'literal' || typeof right.value !== 'string') {
|
|
198
|
-
expressionError('HQ_EXPRESSION_INVALID_VALUE', path);
|
|
199
|
-
}
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
if (operator !== 'in' && operator !== 'notIn' && operator !== 'between')
|
|
203
|
-
return;
|
|
204
|
-
if (right.kind !== 'literal' || typeof right.value !== 'object' || right.value === null
|
|
205
|
-
|| !('$hypequery' in right.value)) {
|
|
206
|
-
expressionError('HQ_EXPRESSION_INVALID_VALUE', path);
|
|
207
|
-
}
|
|
208
|
-
const tag = right.value.$hypequery;
|
|
209
|
-
const expectedType = operator === 'between' ? 'tuple' : 'array';
|
|
210
|
-
if (tag.type !== expectedType || !('values' in tag)) {
|
|
211
|
-
expressionError('HQ_EXPRESSION_INVALID_VALUE', path);
|
|
212
|
-
}
|
|
213
|
-
const requiredLength = operator === 'between' ? 2 : undefined;
|
|
214
|
-
if (tag.values.length === 0 || (requiredLength !== undefined && tag.values.length !== requiredLength)) {
|
|
215
|
-
expressionError('HQ_EXPRESSION_INVALID_ARITY', path);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
function validateAggregate(value, path, depth, state) {
|
|
219
|
-
exactFields(value, ['kind', 'aggregation', 'field'], ['argField', 'level', 'filters'], path);
|
|
220
|
-
const aggregation = stringValue(value.aggregation, `${path}.aggregation`);
|
|
221
|
-
if (!AGGREGATIONS.has(aggregation))
|
|
222
|
-
expressionError('HQ_EXPRESSION_INVALID_AGGREGATION', `${path}.aggregation`);
|
|
223
|
-
const isArg = aggregation === 'argMax' || aggregation === 'argMin';
|
|
224
|
-
const isPercentile = aggregation === 'percentile';
|
|
225
|
-
if (isArg !== Object.hasOwn(value, 'argField') || isPercentile !== Object.hasOwn(value, 'level')) {
|
|
226
|
-
expressionError('HQ_EXPRESSION_INVALID_AGGREGATION', path);
|
|
227
|
-
}
|
|
228
|
-
if (isArg && Object.hasOwn(value, 'filters'))
|
|
229
|
-
expressionError('HQ_EXPRESSION_INVALID_AGGREGATION', `${path}.filters`);
|
|
230
|
-
const level = value.level;
|
|
231
|
-
if (isPercentile && (typeof level !== 'number' || !Number.isFinite(level) || level < 0 || level > 1)) {
|
|
232
|
-
expressionError('HQ_EXPRESSION_INVALID_AGGREGATION', `${path}.level`);
|
|
233
|
-
}
|
|
234
|
-
const filters = value.filters === undefined ? undefined : arrayValue(value.filters, `${path}.filters`, state);
|
|
235
|
-
return freezeRecord({
|
|
236
|
-
kind: 'aggregate',
|
|
237
|
-
aggregation,
|
|
238
|
-
field: identifier(value.field, `${path}.field`),
|
|
239
|
-
...(isArg ? { argField: identifier(value.argField, `${path}.argField`) } : {}),
|
|
240
|
-
...(isPercentile ? { level } : {}),
|
|
241
|
-
...(filters ? {
|
|
242
|
-
filters: Object.freeze(filters.map((filter, index) => validatePredicate(filter, `${path}.filters[${index}]`, depth + 1, state, 'HQ_EXPRESSION_INVALID_AGGREGATION'))),
|
|
243
|
-
} : {}),
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
function newState(options) {
|
|
247
|
-
return { limits: resolveExpressionLimits(options), active: new WeakSet(), nodes: 0 };
|
|
248
|
-
}
|
|
249
|
-
export function validateProtocolExpression(input, options = {}) {
|
|
250
|
-
return validateExpression(input, '$', 1, newState(options));
|
|
251
|
-
}
|
|
252
|
-
export function validateProtocolSemanticQuery(input, options = {}) {
|
|
253
|
-
const state = newState(options);
|
|
254
|
-
const value = requireRecord(input, '$');
|
|
255
|
-
enter(value, 1, state, '$');
|
|
256
|
-
try {
|
|
257
|
-
const kind = stringValue(value.kind, '$.kind');
|
|
258
|
-
const metric = kind === 'metric';
|
|
259
|
-
if (!metric && kind !== 'dataset')
|
|
260
|
-
expressionError('HQ_EXPRESSION_INVALID_QUERY', '$.kind');
|
|
261
|
-
exactFields(value, metric ? ['kind', 'dataset', 'metric'] : ['kind', 'dataset'], metric
|
|
262
|
-
? ['dimensions', 'filters', 'orderBy', 'limit', 'offset', 'by', 'includeMeta']
|
|
263
|
-
: ['dimensions', 'measures', 'filters', 'orderBy', 'limit', 'offset', 'by', 'includeMeta'], '$');
|
|
264
|
-
const result = {
|
|
265
|
-
kind,
|
|
266
|
-
dataset: identifier(value.dataset, '$.dataset', false),
|
|
267
|
-
...(metric ? { metric: identifier(value.metric, '$.metric', false) } : {}),
|
|
268
|
-
};
|
|
269
|
-
copyIdentifierArray(value, result, 'dimensions', true, state);
|
|
270
|
-
if (!metric)
|
|
271
|
-
copyIdentifierArray(value, result, 'measures', false, state);
|
|
272
|
-
if (value.filters !== undefined) {
|
|
273
|
-
const filters = arrayValue(value.filters, '$.filters', state);
|
|
274
|
-
result.filters = Object.freeze(filters.map((filter, index) => validatePredicate(filter, `$.filters[${index}]`, 1, state, 'HQ_EXPRESSION_INVALID_QUERY')));
|
|
275
|
-
}
|
|
276
|
-
if (value.orderBy !== undefined)
|
|
277
|
-
result.orderBy = validateOrderBy(value.orderBy, state);
|
|
278
|
-
copyInteger(value, result, 'limit', 0);
|
|
279
|
-
copyInteger(value, result, 'offset', 0);
|
|
280
|
-
if (value.by !== undefined) {
|
|
281
|
-
const grain = stringValue(value.by, '$.by');
|
|
282
|
-
if (!GRAINS.has(grain))
|
|
283
|
-
expressionError('HQ_EXPRESSION_INVALID_QUERY', '$.by');
|
|
284
|
-
result.by = grain;
|
|
285
|
-
}
|
|
286
|
-
if (value.includeMeta !== undefined) {
|
|
287
|
-
if (typeof value.includeMeta !== 'boolean')
|
|
288
|
-
expressionError('HQ_EXPRESSION_INVALID_QUERY', '$.includeMeta');
|
|
289
|
-
result.includeMeta = value.includeMeta;
|
|
290
|
-
}
|
|
291
|
-
return freezeRecord(result);
|
|
292
|
-
}
|
|
293
|
-
finally {
|
|
294
|
-
state.active.delete(value);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
function validatePredicate(input, path, depth, state, errorCode) {
|
|
298
|
-
const expression = validateExpression(input, path, depth, state);
|
|
299
|
-
if (!isPredicate(expression))
|
|
300
|
-
expressionError(errorCode, path);
|
|
301
|
-
return expression;
|
|
302
|
-
}
|
|
303
|
-
function isPredicate(expression) {
|
|
304
|
-
if (expression.kind === 'comparison')
|
|
305
|
-
return true;
|
|
306
|
-
if (expression.kind !== 'logical')
|
|
307
|
-
return false;
|
|
308
|
-
return expression.operator === 'not'
|
|
309
|
-
? isPredicate(expression.operand)
|
|
310
|
-
: expression.operands.every(isPredicate);
|
|
311
|
-
}
|
|
312
|
-
function copyIdentifierArray(source, target, key, qualified, state) {
|
|
313
|
-
if (source[key] === undefined)
|
|
314
|
-
return;
|
|
315
|
-
const values = arrayValue(source[key], `$.${key}`, state);
|
|
316
|
-
target[key] = Object.freeze(values.map((item, index) => identifier(item, `$.${key}[${index}]`, qualified)));
|
|
317
|
-
}
|
|
318
|
-
function copyInteger(source, target, key, minimum) {
|
|
319
|
-
if (source[key] === undefined)
|
|
320
|
-
return;
|
|
321
|
-
const value = source[key];
|
|
322
|
-
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
323
|
-
expressionError('HQ_EXPRESSION_INVALID_QUERY', `$.${key}`);
|
|
324
|
-
}
|
|
325
|
-
target[key] = value;
|
|
326
|
-
}
|
|
327
|
-
function validateOrderBy(input, state) {
|
|
328
|
-
const values = arrayValue(input, '$.orderBy', state);
|
|
329
|
-
return Object.freeze(values.map((item, index) => {
|
|
330
|
-
const path = `$.orderBy[${index}]`;
|
|
331
|
-
const value = requireRecord(item, path);
|
|
332
|
-
exactFields(value, ['field', 'direction'], [], path);
|
|
333
|
-
const direction = stringValue(value.direction, `${path}.direction`);
|
|
334
|
-
if (direction !== 'asc' && direction !== 'desc')
|
|
335
|
-
expressionError('HQ_EXPRESSION_INVALID_QUERY', `${path}.direction`);
|
|
336
|
-
return freezeRecord({ field: identifier(value.field, `${path}.field`), direction });
|
|
337
|
-
}));
|
|
338
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type ProtocolIdentifier, type ProtocolIdentifierErrorCode, type ProtocolQualifiedIdentifier } from './types.js';
|
|
2
|
-
export declare class ProtocolIdentifierError extends TypeError {
|
|
3
|
-
readonly code: ProtocolIdentifierErrorCode;
|
|
4
|
-
constructor(code: ProtocolIdentifierErrorCode);
|
|
5
|
-
}
|
|
6
|
-
/** Parses one portable, case-sensitive logical identifier segment. */
|
|
7
|
-
export declare function parseProtocolIdentifier(input: unknown): ProtocolIdentifier;
|
|
8
|
-
/** Parses a dot-qualified portable identifier without normalizing it. */
|
|
9
|
-
export declare function parseProtocolQualifiedIdentifier(input: unknown): ProtocolQualifiedIdentifier;
|
|
10
|
-
export declare function splitProtocolQualifiedIdentifier(input: ProtocolQualifiedIdentifier): readonly ProtocolIdentifier[];
|
|
11
|
-
export declare function joinProtocolQualifiedIdentifier(segments: readonly unknown[]): ProtocolQualifiedIdentifier;
|
|
12
|
-
export declare function isProtocolIdentifier(input: unknown): input is ProtocolIdentifier;
|
|
13
|
-
export declare function isProtocolQualifiedIdentifier(input: unknown): input is ProtocolQualifiedIdentifier;
|
|
14
|
-
//# sourceMappingURL=identifiers.d.ts.map
|