@hypequery/protocol 0.11.1 → 0.13.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.
@@ -3,5 +3,5 @@ export { PROTOCOL_DEPLOYMENT_IDENTITY_DOMAIN, encodeProtocolDeploymentContract,
3
3
  export type { PreparedProtocolDeploymentContract } from './codec.js';
4
4
  export { DEFAULT_PROTOCOL_DEPLOYMENT_LIMITS } from './limits.js';
5
5
  export { validateProtocolDatasetContract, validateProtocolDeploymentContract, } from './validate.js';
6
- export type { ProtocolAccessPolicy, ProtocolDatasetContract, ProtocolDatasetDimension, ProtocolDatasetFieldSource, ProtocolDatasetFieldType, ProtocolDatasetFilter, ProtocolDatasetLimits, ProtocolDatasetMeasure, ProtocolDatasetMetric, ProtocolDatasetRelationship, ProtocolDatasetTenantPolicy, ProtocolDeploymentContract, ProtocolDeploymentErrorCode, ProtocolDeploymentLimits, ProtocolDeploymentOptions, ProtocolEndpointPolicy, ProtocolEndpointTenantPolicy, ProtocolNamedQueryContract, ProtocolRuntimeArtifact, } from './types.js';
6
+ export type { ProtocolAccessPolicy, ProtocolDatasetContract, ProtocolDatasetDefaults, ProtocolDatasetDimension, ProtocolDatasetFieldSource, ProtocolDatasetFieldType, ProtocolDatasetFilter, ProtocolDatasetFreshness, ProtocolDatasetLimits, ProtocolDatasetMeasure, ProtocolDatasetMetric, ProtocolDatasetRelationship, ProtocolDatasetTenantPolicy, ProtocolSemanticMetadata, ProtocolSemanticSensitivity, ProtocolDeploymentContract, ProtocolDeploymentErrorCode, ProtocolDeploymentLimits, ProtocolDeploymentOptions, ProtocolEndpointPolicy, ProtocolEndpointTenantPolicy, ProtocolMetricDerivation, ProtocolMetricInput, ProtocolNamedQueryContract, ProtocolRuntimeArtifact, } from './types.js';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/deployments/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,mCAAmC,EACnC,gCAAgC,EAChC,wCAAwC,EACxC,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,kCAAkC,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,+BAA+B,EAC/B,kCAAkC,GACnC,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/deployments/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EACL,mCAAmC,EACnC,gCAAgC,EAChC,wCAAwC,EACxC,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,kCAAkC,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,+BAA+B,EAC/B,kCAAkC,GACnC,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,2BAA2B,EAC3B,wBAAwB,EACxB,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,4BAA4B,EAC5B,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/deployments/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEtF,eAAO,MAAM,kCAAkC,EAAE,QAAQ,CAAC,wBAAwB,CAQhF,CAAC;AAEH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,yBAA8B,GACtC,QAAQ,CAAC,wBAAwB,CAAC,CAcpC"}
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/deployments/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEtF,eAAO,MAAM,kCAAkC,EAAE,QAAQ,CAAC,wBAAwB,CAShF,CAAC;AAEH,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,yBAA8B,GACtC,QAAQ,CAAC,wBAAwB,CAAC,CAcpC"}
@@ -3,6 +3,7 @@ export const DEFAULT_PROTOCOL_DEPLOYMENT_LIMITS = Object.freeze({
3
3
  maxQueries: 1_000,
4
4
  maxArtifacts: 100,
5
5
  maxDatasetItems: 1_000,
6
+ maxSemanticMetadataItems: 100,
6
7
  maxTextBytes: 4_096,
7
8
  maxSourceBytes: 1_024,
8
9
  maxPathBytes: 2_048,
@@ -3,6 +3,23 @@ import type { ProtocolIdentifier, ProtocolQualifiedIdentifier } from '../identif
3
3
  import type { ProtocolQueryImplementation, ProtocolSqlExpression } from '../query-implementations/index.js';
4
4
  import type { ProtocolSchema } from '../schemas/index.js';
5
5
  export type ProtocolDatasetFieldType = 'string' | 'number' | 'boolean' | 'timestamp';
6
+ export type ProtocolSemanticSensitivity = 'public' | 'internal' | 'confidential' | 'restricted';
7
+ export interface ProtocolSemanticMetadata {
8
+ readonly examples?: readonly string[];
9
+ readonly synonyms?: readonly string[];
10
+ readonly format?: string;
11
+ readonly unit?: string;
12
+ readonly currency?: string;
13
+ readonly timezone?: string;
14
+ readonly sensitivity?: ProtocolSemanticSensitivity;
15
+ }
16
+ export interface ProtocolDatasetFreshness {
17
+ readonly maxAgeSeconds: number;
18
+ }
19
+ export interface ProtocolDatasetDefaults {
20
+ readonly dimensions?: readonly ProtocolIdentifier[];
21
+ readonly timeGrain?: ProtocolTimeGrain;
22
+ }
6
23
  export type ProtocolAccessPolicy = {
7
24
  readonly kind: 'public';
8
25
  } | {
@@ -34,7 +51,7 @@ export type ProtocolDatasetFieldSource = {
34
51
  readonly kind: 'column';
35
52
  readonly column: string;
36
53
  } | ProtocolSqlExpression;
37
- export interface ProtocolDatasetDimension {
54
+ export interface ProtocolDatasetDimension extends ProtocolSemanticMetadata {
38
55
  readonly name: ProtocolIdentifier;
39
56
  readonly type: ProtocolDatasetFieldType;
40
57
  readonly source: ProtocolDatasetFieldSource;
@@ -43,7 +60,7 @@ export interface ProtocolDatasetDimension {
43
60
  readonly label?: string;
44
61
  readonly description?: string;
45
62
  }
46
- export interface ProtocolDatasetMeasure {
63
+ export interface ProtocolDatasetMeasure extends ProtocolSemanticMetadata {
47
64
  readonly name: ProtocolIdentifier;
48
65
  readonly aggregation: 'sum' | 'count' | 'countDistinct' | 'avg' | 'min' | 'max' | 'argMax' | 'argMin' | 'percentile' | 'stddev' | 'variance';
49
66
  readonly field: ProtocolQualifiedIdentifier;
@@ -54,7 +71,7 @@ export interface ProtocolDatasetMeasure {
54
71
  readonly label?: string;
55
72
  readonly description?: string;
56
73
  }
57
- export interface ProtocolDatasetFilter {
74
+ export interface ProtocolDatasetFilter extends ProtocolSemanticMetadata {
58
75
  readonly name: ProtocolIdentifier;
59
76
  readonly field: ProtocolQualifiedIdentifier;
60
77
  readonly operators: readonly ('eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'between' | 'like')[];
@@ -69,10 +86,37 @@ export interface ProtocolDatasetRelationship {
69
86
  readonly to: ProtocolQualifiedIdentifier;
70
87
  readonly queryable: boolean;
71
88
  }
72
- export interface ProtocolDatasetMetric {
89
+ /** One aggregate a derived metric's formula names, under the alias it named it by. */
90
+ export interface ProtocolMetricInput {
91
+ readonly alias: ProtocolIdentifier;
92
+ readonly expression: ProtocolExpression;
93
+ }
94
+ /**
95
+ * A derived metric's formula in the shape it was authored in.
96
+ *
97
+ * `ProtocolDatasetMetric.expression` inlines each input aggregate where the
98
+ * formula referenced it, which says what the metric means but loses the aliases
99
+ * the author chose. Those aliases are not cosmetic: they are emitted as the
100
+ * column names of the intermediate aggregate and referenced by the outer
101
+ * select, so a catalog rebuilt without them computes the same number through
102
+ * different SQL. `expression` here references the aliases instead, and
103
+ * validation proves that substituting the inputs back into it reproduces the
104
+ * inlined form exactly — the two can describe the same formula or the contract
105
+ * is invalid, never disagree silently.
106
+ */
107
+ export interface ProtocolMetricDerivation {
108
+ readonly inputs: readonly ProtocolMetricInput[];
109
+ readonly expression: ProtocolExpression;
110
+ }
111
+ export interface ProtocolDatasetMetric extends ProtocolSemanticMetadata {
73
112
  readonly name: ProtocolIdentifier;
74
113
  readonly kind: 'metric' | 'derived-metric' | 'grained-metric';
75
114
  readonly expression: ProtocolExpression;
115
+ /**
116
+ * Present only on a derived metric, and optional: a contract written before
117
+ * this field existed stays valid and simply is not portably executable.
118
+ */
119
+ readonly derivation?: ProtocolMetricDerivation;
76
120
  readonly dimensions: readonly ProtocolQualifiedIdentifier[];
77
121
  readonly filters: readonly ProtocolIdentifier[];
78
122
  readonly grains: readonly ProtocolTimeGrain[];
@@ -87,9 +131,13 @@ export interface ProtocolDatasetLimits {
87
131
  readonly maxFilters?: number;
88
132
  readonly maxResultSize?: number;
89
133
  }
90
- export interface ProtocolDatasetContract {
134
+ export interface ProtocolDatasetContract extends ProtocolSemanticMetadata {
91
135
  readonly name: ProtocolIdentifier;
136
+ readonly description?: string;
92
137
  readonly source: string;
138
+ readonly freshness?: ProtocolDatasetFreshness;
139
+ readonly owner?: string;
140
+ readonly defaults?: ProtocolDatasetDefaults;
93
141
  readonly tenant: ProtocolDatasetTenantPolicy;
94
142
  readonly timeField?: ProtocolQualifiedIdentifier;
95
143
  readonly dimensions: readonly ProtocolDatasetDimension[];
@@ -129,6 +177,13 @@ export interface ProtocolDeploymentLimits {
129
177
  readonly maxQueries: number;
130
178
  readonly maxArtifacts: number;
131
179
  readonly maxDatasetItems: number;
180
+ /**
181
+ * Ceiling on each semantic-metadata collection (`examples`, `synonyms`, and
182
+ * `defaults.dimensions`). Deliberately tighter than `maxDatasetItems`: these
183
+ * are authoring aids, and the definition-time validator in
184
+ * `@hypequery/datasets` applies the same ceiling.
185
+ */
186
+ readonly maxSemanticMetadataItems: number;
132
187
  readonly maxTextBytes: number;
133
188
  readonly maxSourceBytes: number;
134
189
  readonly maxPathBytes: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/deployments/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/deployments/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/deployments/validate.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,uBAAuB,EASvB,0BAA0B,EAE1B,yBAAyB,EAK1B,MAAM,YAAY,CAAC;AAsfpB,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,uBAAuB,CAEzB;AAoKD,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,0BAA0B,CA2C5B"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/deployments/validate.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,uBAAuB,EAUvB,0BAA0B,EAE1B,yBAAyB,EAK1B,MAAM,YAAY,CAAC;AA0wBpB,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,uBAAuB,CAEzB;AAqLD,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,0BAA0B,CA2C5B"}
@@ -14,6 +14,10 @@ const OPERATORS = new Set([
14
14
  'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'between', 'like',
15
15
  ]);
16
16
  const GRAINS = new Set(['day', 'week', 'month', 'quarter', 'year']);
17
+ const SENSITIVITIES = new Set(['public', 'internal', 'confidential', 'restricted']);
18
+ const SEMANTIC_METADATA_FIELDS = [
19
+ 'examples', 'synonyms', 'format', 'unit', 'currency', 'timezone', 'sensitivity',
20
+ ];
17
21
  function requireRecord(input, path) {
18
22
  if (typeof input !== 'object' || input === null || Array.isArray(input)) {
19
23
  deploymentError('HQ_DEPLOYMENT_TYPE', path);
@@ -108,6 +112,30 @@ function uniqueStrings(input, path, maxItems, parse) {
108
112
  deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', path);
109
113
  return Object.freeze(result);
110
114
  }
115
+ function validateSemanticMetadata(value, result, path, limits) {
116
+ const parseText = (item, itemPath) => (boundedText(item, itemPath, limits.maxTextBytes));
117
+ for (const key of ['examples', 'synonyms']) {
118
+ if (value[key] !== undefined) {
119
+ result[key] = uniqueStrings(value[key], `${path}.${key}`, limits.maxSemanticMetadataItems, parseText);
120
+ }
121
+ }
122
+ for (const key of ['format', 'unit', 'timezone']) {
123
+ optionalText(value[key], key, result, path, limits);
124
+ }
125
+ if (value.currency !== undefined) {
126
+ const currency = boundedText(value.currency, `${path}.currency`, limits.maxTextBytes);
127
+ if (!/^[A-Z]{3}$/.test(currency)) {
128
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.currency`);
129
+ }
130
+ result.currency = currency;
131
+ }
132
+ if (value.sensitivity !== undefined) {
133
+ if (typeof value.sensitivity !== 'string' || !SENSITIVITIES.has(value.sensitivity)) {
134
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.sensitivity`);
135
+ }
136
+ result.sensitivity = value.sensitivity;
137
+ }
138
+ }
111
139
  function validateAccess(input, path, limits) {
112
140
  const value = requireRecord(input, path);
113
141
  if (value.kind === 'public') {
@@ -223,7 +251,7 @@ function validateFieldSource(input, path, limits) {
223
251
  }
224
252
  function validateDimension(input, path, limits) {
225
253
  const value = requireRecord(input, path);
226
- exactFields(value, ['name', 'type', 'source', 'filterable', 'groupable'], ['label', 'description'], path);
254
+ exactFields(value, ['name', 'type', 'source', 'filterable', 'groupable'], ['label', 'description', ...SEMANTIC_METADATA_FIELDS], path);
227
255
  if (!['string', 'number', 'boolean', 'timestamp'].includes(value.type)) {
228
256
  deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.type`);
229
257
  }
@@ -240,11 +268,12 @@ function validateDimension(input, path, limits) {
240
268
  };
241
269
  optionalText(value.label, 'label', result, path, limits);
242
270
  optionalText(value.description, 'description', result, path, limits);
271
+ validateSemanticMetadata(value, result, path, limits);
243
272
  return freezeRecord(result);
244
273
  }
245
274
  function validateMeasure(input, path, limits) {
246
275
  const value = requireRecord(input, path);
247
- exactFields(value, ['name', 'aggregation', 'field', 'filters'], ['argField', 'level', 'sql', 'label', 'description'], path);
276
+ exactFields(value, ['name', 'aggregation', 'field', 'filters'], ['argField', 'level', 'sql', 'label', 'description', ...SEMANTIC_METADATA_FIELDS], path);
248
277
  if (typeof value.aggregation !== 'string' || !AGGREGATIONS.has(value.aggregation)) {
249
278
  deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.aggregation`);
250
279
  }
@@ -275,11 +304,12 @@ function validateMeasure(input, path, limits) {
275
304
  result.sql = nested(() => validateProtocolSqlExpression(value.sql), `${path}.sql`);
276
305
  optionalText(value.label, 'label', result, path, limits);
277
306
  optionalText(value.description, 'description', result, path, limits);
307
+ validateSemanticMetadata(value, result, path, limits);
278
308
  return freezeRecord(result);
279
309
  }
280
310
  function validateFilter(input, path, limits) {
281
311
  const value = requireRecord(input, path);
282
- exactFields(value, ['name', 'field', 'operators'], ['label', 'description'], path);
312
+ exactFields(value, ['name', 'field', 'operators'], ['label', 'description', ...SEMANTIC_METADATA_FIELDS], path);
283
313
  const operators = uniqueStrings(value.operators, `${path}.operators`, limits.maxDatasetItems, (operator, operatorPath) => {
284
314
  if (typeof operator !== 'string' || !OPERATORS.has(operator)) {
285
315
  deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', operatorPath);
@@ -295,6 +325,7 @@ function validateFilter(input, path, limits) {
295
325
  };
296
326
  optionalText(value.label, 'label', result, path, limits);
297
327
  optionalText(value.description, 'description', result, path, limits);
328
+ validateSemanticMetadata(value, result, path, limits);
298
329
  return freezeRecord(result);
299
330
  }
300
331
  function validateRelationship(input, path) {
@@ -317,9 +348,148 @@ function validateRelationship(input, path) {
317
348
  queryable: value.queryable,
318
349
  });
319
350
  }
351
+ /**
352
+ * The subset of the expression grammar a derived metric's formula may use.
353
+ *
354
+ * `validateProtocolExpression` accepts the whole of RFC 0003, which is wider
355
+ * than anything a formula can be written in: it permits comparisons, logical
356
+ * operators, a bare aggregate, and a one-argument `round`. A `derivation` exists
357
+ * to be rebuilt and executed, so accepting a form nothing can rebuild would
358
+ * publish a contract that validates and then fails at the point of use. The
359
+ * grammar is pinned here, in the artifact that defines the field, rather than
360
+ * left to whichever runtime happens to read it.
361
+ */
362
+ function validateFormulaGrammar(expression, path) {
363
+ const node = expression;
364
+ const operand = (child, childPath) => validateFormulaGrammar(child, childPath);
365
+ const numericLiteral = (child, childPath) => {
366
+ const candidate = child;
367
+ if (candidate?.kind !== 'literal' || typeof candidate.value !== 'number') {
368
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', childPath);
369
+ }
370
+ };
371
+ switch (node.kind) {
372
+ case 'reference':
373
+ return;
374
+ case 'binary':
375
+ // Arithmetic only, and never over a bare value: the authoring helpers
376
+ // take a name or another expression, never a literal.
377
+ if (!['add', 'subtract', 'multiply', 'divide'].includes(node.operator)) {
378
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.operator`);
379
+ }
380
+ operand(node.left, `${path}.left`);
381
+ operand(node.right, `${path}.right`);
382
+ return;
383
+ case 'call': {
384
+ const args = node.args;
385
+ const expected = node.function === 'round' || node.function === 'coalesce' ? 2 : 1;
386
+ if (!['nullIfZero', 'coalesce', 'round', 'floor', 'ceil'].includes(node.function)) {
387
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.function`);
388
+ }
389
+ if (args.length !== expected) {
390
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.args`);
391
+ }
392
+ operand(args[0], `${path}.args[0]`);
393
+ if (node.function === 'round')
394
+ numericLiteral(args[1], `${path}.args[1]`);
395
+ // A `coalesce` fallback is the one position accepting a bare value.
396
+ if (node.function === 'coalesce' && args[1]?.kind === 'literal') {
397
+ numericLiteral(args[1], `${path}.args[1]`);
398
+ }
399
+ else if (node.function === 'coalesce') {
400
+ operand(args[1], `${path}.args[1]`);
401
+ }
402
+ return;
403
+ }
404
+ default:
405
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', path);
406
+ }
407
+ }
408
+ /** Structural equality over two already-validated expressions. */
409
+ function sameExpression(left, right) {
410
+ if (left === right)
411
+ return true;
412
+ if (Array.isArray(left) || Array.isArray(right)) {
413
+ return Array.isArray(left) && Array.isArray(right)
414
+ && left.length === right.length
415
+ && left.every((item, index) => sameExpression(item, right[index]));
416
+ }
417
+ if (typeof left !== 'object' || typeof right !== 'object' || left === null || right === null) {
418
+ return false;
419
+ }
420
+ const leftKeys = Object.keys(left);
421
+ const rightKeys = Object.keys(right);
422
+ return leftKeys.length === rightKeys.length
423
+ && leftKeys.every(key => Object.hasOwn(right, key)
424
+ && sameExpression(left[key], right[key]));
425
+ }
426
+ /** Replaces each aliased reference with the aggregate the alias stands for. */
427
+ function substituteInputs(expression, inputs) {
428
+ if (Array.isArray(expression)) {
429
+ return expression.map(item => substituteInputs(item, inputs));
430
+ }
431
+ if (typeof expression !== 'object' || expression === null)
432
+ return expression;
433
+ const record = expression;
434
+ if (record.kind === 'reference' && typeof record.name === 'string' && inputs.has(record.name)) {
435
+ return inputs.get(record.name);
436
+ }
437
+ return Object.fromEntries(Object.entries(record).map(([key, value]) => [key, substituteInputs(value, inputs)]));
438
+ }
439
+ /**
440
+ * Validates the authored form of a derived metric's formula.
441
+ *
442
+ * Input order is significant and deliberately not sorted: each input becomes a
443
+ * column of the intermediate aggregate in this order, so reordering them
444
+ * reorders the emitted SQL. Two datasets that differ only in input order are
445
+ * genuinely different contracts.
446
+ */
447
+ function validateDerivation(input, path, limits, inlined) {
448
+ const value = requireRecord(input, path);
449
+ exactFields(value, ['inputs', 'expression'], [], path);
450
+ const items = requireArray(value.inputs, `${path}.inputs`, limits.maxDatasetItems);
451
+ if (items.length === 0)
452
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.inputs`);
453
+ const seen = new Set();
454
+ const inputs = items.map((item, index) => {
455
+ const itemPath = `${path}.inputs[${index}]`;
456
+ const record = requireRecord(item, itemPath);
457
+ exactFields(record, ['alias', 'expression'], [], itemPath);
458
+ const alias = identifier(record.alias, `${itemPath}.alias`);
459
+ if (seen.has(alias))
460
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${itemPath}.alias`);
461
+ seen.add(alias);
462
+ const expression = nested(() => validateProtocolExpression(record.expression), `${itemPath}.expression`);
463
+ // Only an aggregate can become a column of the intermediate result. A
464
+ // formula that named something else has no faithful rebuild.
465
+ if (expression.kind !== 'aggregate') {
466
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${itemPath}.expression`);
467
+ }
468
+ return freezeRecord({ alias, expression });
469
+ });
470
+ const expression = nested(() => validateProtocolExpression(value.expression), `${path}.expression`);
471
+ validateFormulaGrammar(expression, `${path}.expression`);
472
+ // A formula that is a bare reference names one of its inputs instead of
473
+ // combining them. The authoring API cannot produce it — a formula must return
474
+ // a composed expression — so nothing could rebuild it.
475
+ if (expression.kind === 'reference') {
476
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.expression`);
477
+ }
478
+ // The two forms must describe one formula. Substituting the inputs back into
479
+ // the authored form has to reproduce the inlined one exactly, or the contract
480
+ // advertises a meaning its aliases do not compute.
481
+ const substituted = substituteInputs(expression, new Map(inputs.map(entry => [entry.alias, entry.expression])));
482
+ if (!sameExpression(substituted, inlined)) {
483
+ deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `${path}.expression`);
484
+ }
485
+ return freezeRecord({
486
+ inputs: Object.freeze(inputs),
487
+ expression,
488
+ });
489
+ }
320
490
  function validateMetric(input, path, limits) {
321
491
  const value = requireRecord(input, path);
322
- exactFields(value, ['name', 'kind', 'expression', 'dimensions', 'filters', 'grains', 'endpoint'], ['grain', 'label', 'description'], path);
492
+ exactFields(value, ['name', 'kind', 'expression', 'dimensions', 'filters', 'grains', 'endpoint'], ['grain', 'derivation', 'label', 'description', ...SEMANTIC_METADATA_FIELDS], path);
323
493
  if (!['metric', 'derived-metric', 'grained-metric'].includes(value.kind)) {
324
494
  deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.kind`);
325
495
  }
@@ -353,8 +523,21 @@ function validateMetric(input, path, limits) {
353
523
  };
354
524
  if (grain !== undefined)
355
525
  result.grain = grain;
526
+ if (value.derivation !== undefined) {
527
+ // Eligibility follows the expression, not `kind`. `kind` conflates grain
528
+ // with derivation — a derived metric pinned to a grain reports
529
+ // `grained-metric` — so it can neither confirm nor deny that a formula
530
+ // exists. A metric whose expression is a bare aggregate has none, whatever
531
+ // its kind says, and a derivation attached to one describes something the
532
+ // metric does not do.
533
+ if (result.expression.kind === 'aggregate') {
534
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.derivation`);
535
+ }
536
+ result.derivation = validateDerivation(value.derivation, `${path}.derivation`, limits, result.expression);
537
+ }
356
538
  optionalText(value.label, 'label', result, path, limits);
357
539
  optionalText(value.description, 'description', result, path, limits);
540
+ validateSemanticMetadata(value, result, path, limits);
358
541
  return freezeRecord(result);
359
542
  }
360
543
  function validateLimits(input, path) {
@@ -367,6 +550,31 @@ function validateLimits(input, path) {
367
550
  }
368
551
  return freezeRecord(result);
369
552
  }
553
+ function validateFreshness(input, path) {
554
+ const value = requireRecord(input, path);
555
+ exactFields(value, ['maxAgeSeconds'], [], path);
556
+ return freezeRecord({
557
+ maxAgeSeconds: positiveInteger(value.maxAgeSeconds, `${path}.maxAgeSeconds`),
558
+ });
559
+ }
560
+ function validateDefaults(input, path, limits) {
561
+ const value = requireRecord(input, path);
562
+ exactFields(value, [], ['dimensions', 'timeGrain'], path);
563
+ const result = {};
564
+ if (value.dimensions !== undefined) {
565
+ result.dimensions = uniqueStrings(value.dimensions, `${path}.dimensions`, limits.maxSemanticMetadataItems, (dimension, dimensionPath) => identifier(dimension, dimensionPath));
566
+ }
567
+ if (value.timeGrain !== undefined) {
568
+ if (typeof value.timeGrain !== 'string' || !GRAINS.has(value.timeGrain)) {
569
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.timeGrain`);
570
+ }
571
+ result.timeGrain = value.timeGrain;
572
+ }
573
+ if (Object.keys(result).length === 0) {
574
+ deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', path);
575
+ }
576
+ return freezeRecord(result);
577
+ }
370
578
  function namedItems(input, path, maxItems, validate) {
371
579
  const items = requireArray(input, path, maxItems).map((value, index) => validate(value, `${path}[${index}]`));
372
580
  if (new Set(items.map(item => item.name)).size !== items.length) {
@@ -376,7 +584,11 @@ function namedItems(input, path, maxItems, validate) {
376
584
  }
377
585
  function validateDataset(input, path, limits) {
378
586
  const value = requireRecord(input, path);
379
- exactFields(value, ['name', 'source', 'tenant', 'dimensions', 'measures', 'filters', 'metrics', 'relationships'], ['timeField', 'limits', 'endpoint'], path);
587
+ exactFields(value, ['name', 'source', 'tenant', 'dimensions', 'measures', 'filters', 'metrics', 'relationships'], [
588
+ 'description', 'freshness', 'owner', 'defaults',
589
+ ...SEMANTIC_METADATA_FIELDS,
590
+ 'timeField', 'limits', 'endpoint',
591
+ ], path);
380
592
  const result = {
381
593
  name: identifier(value.name, `${path}.name`),
382
594
  source: boundedText(value.source, `${path}.source`, limits.maxSourceBytes),
@@ -389,6 +601,15 @@ function validateDataset(input, path, limits) {
389
601
  };
390
602
  if (value.timeField !== undefined)
391
603
  result.timeField = identifier(value.timeField, `${path}.timeField`, true);
604
+ optionalText(value.description, 'description', result, path, limits);
605
+ optionalText(value.owner, 'owner', result, path, limits);
606
+ validateSemanticMetadata(value, result, path, limits);
607
+ if (value.freshness !== undefined) {
608
+ result.freshness = validateFreshness(value.freshness, `${path}.freshness`);
609
+ }
610
+ if (value.defaults !== undefined) {
611
+ result.defaults = validateDefaults(value.defaults, `${path}.defaults`, limits);
612
+ }
392
613
  if (value.limits !== undefined)
393
614
  result.limits = validateLimits(value.limits, `${path}.limits`);
394
615
  if (value.endpoint !== undefined)
@@ -430,6 +651,12 @@ function validateArtifact(input, path) {
430
651
  function validateReferences(contract) {
431
652
  const datasets = new Map(contract.datasets.map(dataset => [dataset.name, dataset]));
432
653
  for (const [datasetIndex, dataset] of contract.datasets.entries()) {
654
+ if (dataset.defaults?.dimensions?.some(name => (!dataset.dimensions.some(dimension => dimension.name === name && dimension.groupable)))) {
655
+ deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `$.datasets[${datasetIndex}].defaults.dimensions`);
656
+ }
657
+ if (dataset.defaults?.timeGrain !== undefined && dataset.timeField === undefined) {
658
+ deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `$.datasets[${datasetIndex}].defaults.timeGrain`);
659
+ }
433
660
  for (const [relationshipIndex, relationship] of dataset.relationships.entries()) {
434
661
  if (!datasets.has(relationship.target)) {
435
662
  deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `$.datasets[${datasetIndex}].relationships[${relationshipIndex}].target`);
@@ -453,13 +680,16 @@ function validateReferences(contract) {
453
680
  && dataset.timeField === undefined) {
454
681
  deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `$.datasets[${datasetIndex}].metrics[${metricIndex}].grains`);
455
682
  }
456
- if (dataset.tenant.kind === 'required' && metric.endpoint.tenant.kind !== 'required') {
683
+ // Biconditional, as for a compiled-SQL query below. An endpoint that
684
+ // requires a tenant over a dataset carrying no tenant field resolves one
685
+ // and then has no column to scope by, so the query reads every tenant
686
+ // while both layers believe tenancy was enforced.
687
+ if ((dataset.tenant.kind === 'required') !== (metric.endpoint.tenant.kind === 'required')) {
457
688
  deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `$.datasets[${datasetIndex}].metrics[${metricIndex}].endpoint.tenant`);
458
689
  }
459
690
  }
460
- if (dataset.tenant.kind === 'required'
461
- && dataset.endpoint !== undefined
462
- && dataset.endpoint.tenant.kind !== 'required') {
691
+ if (dataset.endpoint !== undefined
692
+ && (dataset.tenant.kind === 'required') !== (dataset.endpoint.tenant.kind === 'required')) {
463
693
  deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `$.datasets[${datasetIndex}].endpoint.tenant`);
464
694
  }
465
695
  }
package/dist/index.d.ts CHANGED
@@ -11,11 +11,14 @@ export type { ProtocolIdentifier, ProtocolIdentifierErrorCode, ProtocolQualified
11
11
  export { DEFAULT_PROTOCOL_QUERY_IMPLEMENTATION_LIMITS, ProtocolQueryImplementationError, validateProtocolQueryImplementation, validateProtocolSqlExpression, } from './query-implementations/index.js';
12
12
  export { DEFAULT_PROTOCOL_QUERY_EVENT_LIMITS, ProtocolQueryDiagnosticsError, ProtocolQueryEventError, validateProtocolQueryDiagnostics, validateProtocolQueryEvent, } from './events/index.js';
13
13
  export type { ProtocolQueryDiagnostics, ProtocolQueryDiagnosticsErrorCode, ProtocolQueryErrorCategory, ProtocolQueryEvent, ProtocolQueryEventErrorCode, ProtocolQueryEventLimits, ProtocolQueryEventOptions, ProtocolQueryEventOutcome, ProtocolQueryEventTarget, ProtocolQueryOperation, ProtocolQueryTerminalReason, } from './events/index.js';
14
+ export { DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS, ProtocolSemanticInvocationError, validateProtocolSemanticInvocation, validateProtocolSemanticInvocationFailure, validateProtocolSemanticInvocationResult, } from './invocations/index.js';
15
+ export type { ProtocolSemanticInvocation, ProtocolSemanticInvocationBudget, ProtocolSemanticInvocationErrorCode, ProtocolSemanticInvocationFailure, ProtocolSemanticInvocationFailureCategory, ProtocolSemanticInvocationLimits, ProtocolSemanticInvocationMeta, ProtocolSemanticInvocationOptions, ProtocolSemanticInvocationPagination, ProtocolSemanticInvocationResult, ProtocolSemanticInvocationRow, ProtocolSemanticInvocationTarget, ProtocolSemanticInvocationValue, } from './invocations/index.js';
14
16
  export { DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS, PROTOCOL_DEPLOYMENT_BUNDLE_IDENTITY_DOMAIN, ProtocolDeploymentBundleError, encodeProtocolDeploymentBundleManifest, encodeProtocolDeploymentBundleManifestToString, hashProtocolDeploymentBundleManifest, prepareProtocolDeploymentBundleManifest, validateProtocolDeploymentBundleManifest, } from './bundles/index.js';
15
17
  export { DEFAULT_PROTOCOL_DEPLOYMENT_RELEASE_LIMITS, PROTOCOL_DEPLOYMENT_RELEASE_IDENTITY_DOMAIN, ProtocolDeploymentReleaseError, encodeProtocolDeploymentReleaseEnvelope, encodeProtocolDeploymentReleaseEnvelopeToString, hashProtocolDeploymentReleaseEnvelope, prepareProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseTarget, } from './releases/index.js';
16
18
  export type { PreparedProtocolDeploymentReleaseEnvelope, ProtocolDeploymentReleaseEnvelope, ProtocolDeploymentReleaseErrorCode, ProtocolDeploymentReleaseLimits, ProtocolDeploymentReleaseOptions, ProtocolDeploymentReleaseTarget, } from './releases/index.js';
17
19
  export type { PreparedProtocolDeploymentBundleManifest, ProtocolDeploymentBundleArtifact, ProtocolDeploymentBundleDeployment, ProtocolDeploymentBundleErrorCode, ProtocolDeploymentBundleFile, ProtocolDeploymentBundleLimits, ProtocolDeploymentBundleManifest, ProtocolDeploymentBundleOptions, } from './bundles/index.js';
18
20
  export { DEFAULT_PROTOCOL_DEPLOYMENT_LIMITS, PROTOCOL_DEPLOYMENT_IDENTITY_DOMAIN, ProtocolDeploymentError, encodeProtocolDeploymentContract, encodeProtocolDeploymentContractToString, hashProtocolDeploymentContract, prepareProtocolDeploymentContract, validateProtocolDatasetContract, validateProtocolDeploymentContract, } from './deployments/index.js';
19
- export type { PreparedProtocolDeploymentContract, ProtocolAccessPolicy, ProtocolDatasetContract, ProtocolDatasetDimension, ProtocolDatasetFieldSource, ProtocolDatasetFieldType, ProtocolDatasetFilter, ProtocolDatasetLimits, ProtocolDatasetMeasure, ProtocolDatasetMetric, ProtocolDatasetRelationship, ProtocolDatasetTenantPolicy, ProtocolDeploymentContract, ProtocolDeploymentErrorCode, ProtocolDeploymentLimits, ProtocolDeploymentOptions, ProtocolEndpointPolicy, ProtocolEndpointTenantPolicy, ProtocolNamedQueryContract, ProtocolRuntimeArtifact, } from './deployments/index.js';
21
+ export type { PreparedProtocolDeploymentContract, ProtocolAccessPolicy, ProtocolDatasetContract, ProtocolDatasetDefaults, ProtocolDatasetDimension, ProtocolDatasetFieldSource, ProtocolDatasetFieldType, ProtocolDatasetFilter, ProtocolDatasetFreshness, ProtocolDatasetLimits, ProtocolDatasetMeasure, ProtocolDatasetMetric, ProtocolDatasetRelationship, ProtocolDatasetTenantPolicy, ProtocolSemanticMetadata, ProtocolSemanticSensitivity, ProtocolDeploymentContract, ProtocolDeploymentErrorCode, ProtocolDeploymentLimits, ProtocolDeploymentOptions, ProtocolEndpointPolicy, ProtocolEndpointTenantPolicy, ProtocolMetricDerivation, ProtocolMetricInput, ProtocolNamedQueryContract, ProtocolRuntimeArtifact, } from './deployments/index.js';
20
22
  export type { ProtocolQueryImplementation, ProtocolQueryImplementationErrorCode, ProtocolQueryImplementationLimits, ProtocolQueryImplementationOptions, ProtocolSqlDialect, ProtocolSqlExpression, ProtocolSqlParameter, ProtocolSqlParameterSource, ProtocolSqlTenantPolicy, } from './query-implementations/index.js';
23
+ export { PROTOCOL_SEMANTIC_FAILURE_MESSAGES } from './invocations/failure-messages.js';
21
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,EAC5B,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACtB,iCAAiC,GAClC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kCAAkC,EAClC,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,8BAA8B,EAC9B,oCAAoC,EACpC,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,+BAA+B,EAC/B,gCAAgC,EAChC,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAE5B,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,wBAAwB,CAAC;AAEhC,YAAY,EACV,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,kBAAkB,EAClB,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,4CAA4C,EAC5C,gCAAgC,EAChC,mCAAmC,EACnC,6BAA6B,GAC9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,mCAAmC,EACnC,6BAA6B,EAC7B,uBAAuB,EACvB,gCAAgC,EAChC,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,wBAAwB,EACxB,iCAAiC,EACjC,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,yCAAyC,EACzC,0CAA0C,EAC1C,6BAA6B,EAC7B,sCAAsC,EACtC,8CAA8C,EAC9C,oCAAoC,EACpC,uCAAuC,EACvC,wCAAwC,GACzC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,0CAA0C,EAC1C,2CAA2C,EAC3C,8BAA8B,EAC9B,uCAAuC,EACvC,+CAA+C,EAC/C,qCAAqC,EACrC,wCAAwC,EACxC,yCAAyC,EACzC,uCAAuC,GACxC,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,yCAAyC,EACzC,iCAAiC,EACjC,kCAAkC,EAClC,+BAA+B,EAC/B,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EACV,wCAAwC,EACxC,gCAAgC,EAChC,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,8BAA8B,EAC9B,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,kCAAkC,EAClC,mCAAmC,EACnC,uBAAuB,EACvB,gCAAgC,EAChC,wCAAwC,EACxC,8BAA8B,EAC9B,iCAAiC,EACjC,+BAA+B,EAC/B,kCAAkC,GACnC,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACV,kCAAkC,EAClC,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACV,2BAA2B,EAC3B,oCAAoC,EACpC,iCAAiC,EACjC,kCAAkC,EAClC,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,6 +5,8 @@ export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS, ProtocolExpressionError, validatePr
5
5
  export { DEFAULT_PROTOCOL_SCHEMA_LIMITS, DEFAULT_PROTOCOL_SCHEMA_VALUE_LIMITS, ProtocolSchemaError, ProtocolSchemaValueError, applyProtocolSchemaValue, createProtocolSchemaValueParser, resolveProtocolSchemaValueLimits, validateProtocolSchema, } from './schemas/index.js';
6
6
  export { DEFAULT_PROTOCOL_QUERY_IMPLEMENTATION_LIMITS, ProtocolQueryImplementationError, validateProtocolQueryImplementation, validateProtocolSqlExpression, } from './query-implementations/index.js';
7
7
  export { DEFAULT_PROTOCOL_QUERY_EVENT_LIMITS, ProtocolQueryDiagnosticsError, ProtocolQueryEventError, validateProtocolQueryDiagnostics, validateProtocolQueryEvent, } from './events/index.js';
8
+ export { DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS, ProtocolSemanticInvocationError, validateProtocolSemanticInvocation, validateProtocolSemanticInvocationFailure, validateProtocolSemanticInvocationResult, } from './invocations/index.js';
8
9
  export { DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS, PROTOCOL_DEPLOYMENT_BUNDLE_IDENTITY_DOMAIN, ProtocolDeploymentBundleError, encodeProtocolDeploymentBundleManifest, encodeProtocolDeploymentBundleManifestToString, hashProtocolDeploymentBundleManifest, prepareProtocolDeploymentBundleManifest, validateProtocolDeploymentBundleManifest, } from './bundles/index.js';
9
10
  export { DEFAULT_PROTOCOL_DEPLOYMENT_RELEASE_LIMITS, PROTOCOL_DEPLOYMENT_RELEASE_IDENTITY_DOMAIN, ProtocolDeploymentReleaseError, encodeProtocolDeploymentReleaseEnvelope, encodeProtocolDeploymentReleaseEnvelopeToString, hashProtocolDeploymentReleaseEnvelope, prepareProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseTarget, } from './releases/index.js';
10
11
  export { DEFAULT_PROTOCOL_DEPLOYMENT_LIMITS, PROTOCOL_DEPLOYMENT_IDENTITY_DOMAIN, ProtocolDeploymentError, encodeProtocolDeploymentContract, encodeProtocolDeploymentContractToString, hashProtocolDeploymentContract, prepareProtocolDeploymentContract, validateProtocolDatasetContract, validateProtocolDeploymentContract, } from './deployments/index.js';
12
+ export { PROTOCOL_SEMANTIC_FAILURE_MESSAGES } from './invocations/failure-messages.js';
@@ -0,0 +1,8 @@
1
+ import type { ProtocolSemanticInvocationErrorCode } from './types.js';
2
+ export declare class ProtocolSemanticInvocationError extends TypeError {
3
+ readonly code: ProtocolSemanticInvocationErrorCode;
4
+ readonly path: string;
5
+ constructor(code: ProtocolSemanticInvocationErrorCode, path?: string);
6
+ }
7
+ export declare function invocationError(code: ProtocolSemanticInvocationErrorCode, path?: string): never;
8
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/invocations/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,YAAY,CAAC;AAEtE,qBAAa,+BAAgC,SAAQ,SAAS;IAC5D,QAAQ,CAAC,IAAI,EAAE,mCAAmC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,mCAAmC,EAAE,IAAI,SAAM;CAMlE;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mCAAmC,EACzC,IAAI,SAAM,GACT,KAAK,CAEP"}
@@ -0,0 +1,13 @@
1
+ export class ProtocolSemanticInvocationError extends TypeError {
2
+ code;
3
+ path;
4
+ constructor(code, path = '$') {
5
+ super(`${code} at ${path}`);
6
+ this.name = 'ProtocolSemanticInvocationError';
7
+ this.code = code;
8
+ this.path = path;
9
+ }
10
+ }
11
+ export function invocationError(code, path = '$') {
12
+ throw new ProtocolSemanticInvocationError(code, path);
13
+ }
@@ -0,0 +1,4 @@
1
+ import type { ProtocolSemanticInvocationFailureCategory } from './types.js';
2
+ /** Fixed public messages; provider exceptions belong only in private logs. */
3
+ export declare const PROTOCOL_SEMANTIC_FAILURE_MESSAGES: Readonly<Record<ProtocolSemanticInvocationFailureCategory, string>>;
4
+ //# sourceMappingURL=failure-messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-messages.d.ts","sourceRoot":"","sources":["../../src/invocations/failure-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yCAAyC,EAAE,MAAM,YAAY,CAAC;AAE5E,8EAA8E;AAC9E,eAAO,MAAM,kCAAkC,EAAE,QAAQ,CAAC,MAAM,CAAC,yCAAyC,EAAE,MAAM,CAAC,CAcjH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /** Fixed public messages; provider exceptions belong only in private logs. */
2
+ export const PROTOCOL_SEMANTIC_FAILURE_MESSAGES = Object.freeze({
3
+ "configuration-invalid": "The execution configuration is invalid.",
4
+ "not-found": "The requested target was not found.",
5
+ "unauthenticated": "Authentication is required.",
6
+ "forbidden": "Access is forbidden.",
7
+ "tenant-required": "A trusted tenant is required.",
8
+ "input-invalid": "The semantic query is invalid.",
9
+ "budget-exceeded": "The invocation budget was exceeded.",
10
+ "cancelled": "The invocation was cancelled.",
11
+ "stale-activation": "The pinned activation is no longer active.",
12
+ "unsupported-capability": "Portable execution cannot reproduce this target.",
13
+ "executor-unavailable": "The executor is unavailable.",
14
+ "executor-failed": "The executor failed.",
15
+ "output-invalid": "The executor returned an invalid result."
16
+ });
@@ -0,0 +1,6 @@
1
+ export { PROTOCOL_SEMANTIC_FAILURE_MESSAGES } from './failure-messages.js';
2
+ export { ProtocolSemanticInvocationError } from './errors.js';
3
+ export { DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS } from './limits.js';
4
+ export { validateProtocolSemanticInvocation, validateProtocolSemanticInvocationFailure, validateProtocolSemanticInvocationResult, } from './validate.js';
5
+ export type { ProtocolSemanticInvocation, ProtocolSemanticInvocationBudget, ProtocolSemanticInvocationErrorCode, ProtocolSemanticInvocationFailure, ProtocolSemanticInvocationFailureCategory, ProtocolSemanticInvocationLimits, ProtocolSemanticInvocationMeta, ProtocolSemanticInvocationOptions, ProtocolSemanticInvocationPagination, ProtocolSemanticInvocationResult, ProtocolSemanticInvocationRow, ProtocolSemanticInvocationTarget, ProtocolSemanticInvocationValue, } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/invocations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,2CAA2C,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EACL,kCAAkC,EAClC,yCAAyC,EACzC,wCAAwC,GACzC,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,0BAA0B,EAC1B,gCAAgC,EAChC,mCAAmC,EACnC,iCAAiC,EACjC,yCAAyC,EACzC,gCAAgC,EAChC,8BAA8B,EAC9B,iCAAiC,EACjC,oCAAoC,EACpC,gCAAgC,EAChC,6BAA6B,EAC7B,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { PROTOCOL_SEMANTIC_FAILURE_MESSAGES } from './failure-messages.js';
2
+ export { ProtocolSemanticInvocationError } from './errors.js';
3
+ export { DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS } from './limits.js';
4
+ export { validateProtocolSemanticInvocation, validateProtocolSemanticInvocationFailure, validateProtocolSemanticInvocationResult, } from './validate.js';
@@ -0,0 +1,4 @@
1
+ import type { ProtocolSemanticInvocationLimits, ProtocolSemanticInvocationOptions } from './types.js';
2
+ export declare const DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS: Readonly<ProtocolSemanticInvocationLimits>;
3
+ export declare function resolveSemanticInvocationLimits(options?: ProtocolSemanticInvocationOptions): Readonly<ProtocolSemanticInvocationLimits>;
4
+ //# sourceMappingURL=limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/invocations/limits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,2CAA2C,EACxD,QAAQ,CAAC,gCAAgC,CAQvC,CAAC;AAEH,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,iCAAsC,GAC9C,QAAQ,CAAC,gCAAgC,CAAC,CAe5C"}
@@ -0,0 +1,24 @@
1
+ export const DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS = Object.freeze({
2
+ maxTextBytes: 1_024,
3
+ maxMessageBytes: 1_024,
4
+ maxRows: 10_000,
5
+ maxColumnsPerRow: 256,
6
+ maxValueBytes: 65_536,
7
+ maxDeadlineMs: 3_600_000,
8
+ maxResponseBytes: 33_554_432,
9
+ });
10
+ export function resolveSemanticInvocationLimits(options = {}) {
11
+ const result = { ...DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS };
12
+ for (const key of Object.keys(result)) {
13
+ const value = options.limits?.[key];
14
+ if (value === undefined)
15
+ continue;
16
+ const maximum = DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS[key];
17
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) {
18
+ throw new RangeError(`${key} must be a positive safe integer no greater than ${maximum} `
19
+ + '(the semantic invocation v1 maximum)');
20
+ }
21
+ result[key] = value;
22
+ }
23
+ return Object.freeze(result);
24
+ }
@@ -0,0 +1,111 @@
1
+ import type { ProtocolSemanticQuery } from '../expressions/index.js';
2
+ export interface ProtocolSemanticInvocationTarget {
3
+ readonly project: string;
4
+ readonly environment: string;
5
+ }
6
+ /**
7
+ * Caller-requested ceilings. A runtime applies the most restrictive of these,
8
+ * the endpoint policy, and its own defaults — a caller can tighten a budget but
9
+ * never widen one.
10
+ */
11
+ export interface ProtocolSemanticInvocationBudget {
12
+ readonly deadlineMs?: number;
13
+ readonly maxRows?: number;
14
+ readonly maxResponseBytes?: number;
15
+ }
16
+ /**
17
+ * One dataset or metric invocation against an activated deployment.
18
+ *
19
+ * Decision 0002 sketched the dataset/metric name beside the nested query, which
20
+ * would let the two disagree. It also permits normalizing to a single
21
+ * identifier location, so the names live only inside `operation`, whose own
22
+ * `kind` discriminates dataset from metric.
23
+ *
24
+ * There is deliberately no tenant field: a caller cannot supply or change a
25
+ * tenant, which is resolved by the provider callback inside trusted execution
26
+ * context.
27
+ */
28
+ export interface ProtocolSemanticInvocation {
29
+ readonly kind: 'hypequery-semantic-invocation';
30
+ readonly version: 1;
31
+ readonly target: ProtocolSemanticInvocationTarget;
32
+ /** Pins execution to one activation. Omit to accept whichever is active. */
33
+ readonly activationRevision?: string;
34
+ readonly operation: ProtocolSemanticQuery;
35
+ readonly budget?: ProtocolSemanticInvocationBudget;
36
+ /** External correlation only; never authoritative. */
37
+ readonly correlationId?: string;
38
+ }
39
+ /**
40
+ * A result cell. Portable execution returns scalars; anything richer would need
41
+ * the RFC 0001 tagged value model, which this envelope deliberately does not
42
+ * pull into result rows.
43
+ */
44
+ export type ProtocolSemanticInvocationValue = string | number | boolean | null;
45
+ export type ProtocolSemanticInvocationRow = Readonly<Record<string, ProtocolSemanticInvocationValue>>;
46
+ export interface ProtocolSemanticInvocationPagination {
47
+ readonly limit: number;
48
+ readonly offset: number;
49
+ readonly hasMore: boolean;
50
+ }
51
+ export interface ProtocolSemanticInvocationMeta {
52
+ readonly rowCount: number;
53
+ readonly pagination?: ProtocolSemanticInvocationPagination;
54
+ }
55
+ /**
56
+ * The successful result. Operational metadata (trace, timing, cache outcome)
57
+ * belongs in the transport's own metadata rather than beside the rows shown to
58
+ * a model, so it is not carried here.
59
+ */
60
+ export interface ProtocolSemanticInvocationResult {
61
+ readonly kind: 'hypequery-semantic-invocation-result';
62
+ readonly version: 1;
63
+ /** The activation that actually served the call, never the one requested. */
64
+ readonly activationRevision: string;
65
+ readonly data: readonly ProtocolSemanticInvocationRow[];
66
+ readonly meta: ProtocolSemanticInvocationMeta;
67
+ }
68
+ /** Provider-neutral failure categories from decision 0002, plus decision 0005. */
69
+ export type ProtocolSemanticInvocationFailureCategory = 'configuration-invalid' | 'not-found' | 'unauthenticated' | 'forbidden' | 'tenant-required' | 'input-invalid' | 'budget-exceeded' | 'cancelled' | 'stale-activation'
70
+ /** Portable execution cannot reproduce this target exactly. Decision 0005. */
71
+ | 'unsupported-capability' | 'executor-unavailable' | 'executor-failed' | 'output-invalid';
72
+ /**
73
+ * A failed invocation. Closed by construction: there is no field that accepts
74
+ * SQL, parameter values, tenant identifiers, physical source details, stack
75
+ * traces, or a provider exception.
76
+ */
77
+ export interface ProtocolSemanticInvocationFailure {
78
+ readonly kind: 'hypequery-semantic-invocation-failure';
79
+ readonly version: 1;
80
+ readonly category: ProtocolSemanticInvocationFailureCategory;
81
+ /** Stable machine-readable code, e.g. `HQ_SEMANTIC_TENANT_REQUIRED`. */
82
+ readonly code: string;
83
+ readonly message: string;
84
+ /** Bounded input path for a correctable failure, e.g. `$.operation.limit`. */
85
+ readonly path?: string;
86
+ readonly retryable: boolean;
87
+ /** The caller must re-read discovery before retrying. */
88
+ readonly relist: boolean;
89
+ readonly activationRevision?: string;
90
+ }
91
+ export interface ProtocolSemanticInvocationLimits {
92
+ readonly maxTextBytes: number;
93
+ readonly maxMessageBytes: number;
94
+ readonly maxRows: number;
95
+ readonly maxColumnsPerRow: number;
96
+ readonly maxValueBytes: number;
97
+ readonly maxDeadlineMs: number;
98
+ readonly maxResponseBytes: number;
99
+ }
100
+ /**
101
+ * Validation budgets for a semantic invocation.
102
+ *
103
+ * Each configured value must be a positive safe integer no greater than the
104
+ * corresponding value in `DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS`. These
105
+ * options may tighten the v1 conformance limits but cannot raise them.
106
+ */
107
+ export interface ProtocolSemanticInvocationOptions {
108
+ readonly limits?: Partial<ProtocolSemanticInvocationLimits>;
109
+ }
110
+ export type ProtocolSemanticInvocationErrorCode = 'HQ_INVOCATION_TYPE' | 'HQ_INVOCATION_UNKNOWN_FIELD' | 'HQ_INVOCATION_INVALID_VERSION' | 'HQ_INVOCATION_INVALID_VALUE' | 'HQ_INVOCATION_TOO_MANY_ITEMS' | 'HQ_INVOCATION_TOO_LARGE' | 'HQ_INVOCATION_UNSAFE_OBJECT';
111
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/invocations/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { ProtocolSemanticInvocation, ProtocolSemanticInvocationFailure, ProtocolSemanticInvocationOptions, ProtocolSemanticInvocationResult } from './types.js';
2
+ /** Validate one dataset or metric invocation request. */
3
+ export declare function validateProtocolSemanticInvocation(input: unknown, options?: ProtocolSemanticInvocationOptions): ProtocolSemanticInvocation;
4
+ /** Validate a successful invocation result before it is returned or cached. */
5
+ export declare function validateProtocolSemanticInvocationResult(input: unknown, options?: ProtocolSemanticInvocationOptions): ProtocolSemanticInvocationResult;
6
+ /** Validate a failed invocation before it crosses a trust boundary. */
7
+ export declare function validateProtocolSemanticInvocationFailure(input: unknown, options?: ProtocolSemanticInvocationOptions): ProtocolSemanticInvocationFailure;
8
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/invocations/validate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,0BAA0B,EAE1B,iCAAiC,EAGjC,iCAAiC,EACjC,gCAAgC,EAGjC,MAAM,YAAY,CAAC;AA+KpB,yDAAyD;AACzD,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iCAAsC,GAC9C,0BAA0B,CAgC5B;AAyED,+EAA+E;AAC/E,wBAAgB,wCAAwC,CACtD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iCAAsC,GAC9C,gCAAgC,CAiBlC;AAED,uEAAuE;AACvE,wBAAgB,yCAAyC,CACvD,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iCAAsC,GAC9C,iCAAiC,CAyCnC"}
@@ -0,0 +1,306 @@
1
+ import { ProtocolExpressionError, validateProtocolSemanticQuery } from '../expressions/index.js';
2
+ import { PROTOCOL_SEMANTIC_FAILURE_MESSAGES } from './failure-messages.js';
3
+ import { invocationError } from './errors.js';
4
+ import { resolveSemanticInvocationLimits } from './limits.js';
5
+ const HEX64_PATTERN = /^[0-9a-f]{64}$/;
6
+ const FAILURE_CATEGORIES = [
7
+ 'configuration-invalid',
8
+ 'not-found',
9
+ 'unauthenticated',
10
+ 'forbidden',
11
+ 'tenant-required',
12
+ 'input-invalid',
13
+ 'budget-exceeded',
14
+ 'cancelled',
15
+ 'stale-activation',
16
+ 'unsupported-capability',
17
+ 'executor-unavailable',
18
+ 'executor-failed',
19
+ 'output-invalid',
20
+ ];
21
+ const FAILURE_CODE_PATTERN = /^[A-Z][A-Z0-9_]*$/;
22
+ const textEncoder = new TextEncoder();
23
+ function requireRecord(input, path) {
24
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
25
+ invocationError('HQ_INVOCATION_TYPE', path);
26
+ }
27
+ const prototype = Object.getPrototypeOf(input);
28
+ if (prototype !== Object.prototype && prototype !== null) {
29
+ invocationError('HQ_INVOCATION_UNSAFE_OBJECT', path);
30
+ }
31
+ if (Object.getOwnPropertySymbols(input).length > 0) {
32
+ invocationError('HQ_INVOCATION_UNSAFE_OBJECT', path);
33
+ }
34
+ for (const descriptor of Object.values(Object.getOwnPropertyDescriptors(input))) {
35
+ if (!descriptor.enumerable || !('value' in descriptor)) {
36
+ invocationError('HQ_INVOCATION_UNSAFE_OBJECT', path);
37
+ }
38
+ }
39
+ return input;
40
+ }
41
+ function requireArray(input, path, maximum) {
42
+ if (!Array.isArray(input))
43
+ invocationError('HQ_INVOCATION_TYPE', path);
44
+ if (input.length > maximum)
45
+ invocationError('HQ_INVOCATION_TOO_MANY_ITEMS', path);
46
+ if (Object.getPrototypeOf(input) !== Array.prototype || Object.getOwnPropertySymbols(input).length > 0) {
47
+ invocationError('HQ_INVOCATION_UNSAFE_OBJECT', path);
48
+ }
49
+ const descriptors = Object.getOwnPropertyDescriptors(input);
50
+ if (Object.keys(descriptors).length !== input.length + 1) {
51
+ invocationError('HQ_INVOCATION_UNSAFE_OBJECT', path);
52
+ }
53
+ for (let index = 0; index < input.length; index++) {
54
+ const descriptor = descriptors[String(index)];
55
+ if (!descriptor || !descriptor.enumerable || !('value' in descriptor)) {
56
+ invocationError('HQ_INVOCATION_UNSAFE_OBJECT', path);
57
+ }
58
+ }
59
+ return input;
60
+ }
61
+ function exactFields(value, required, optional, path) {
62
+ const allowed = new Set([...required, ...optional]);
63
+ for (const key of Object.keys(value)) {
64
+ if (!allowed.has(key))
65
+ invocationError('HQ_INVOCATION_UNKNOWN_FIELD', `${path}.${key}`);
66
+ }
67
+ for (const key of required) {
68
+ if (!Object.hasOwn(value, key))
69
+ invocationError('HQ_INVOCATION_TYPE', `${path}.${key}`);
70
+ }
71
+ }
72
+ function freezeRecord(entries) {
73
+ return Object.freeze(Object.assign(Object.create(null), entries));
74
+ }
75
+ function hasControlCharacter(text) {
76
+ for (let index = 0; index < text.length; index += 1) {
77
+ const code = text.charCodeAt(index);
78
+ if (code <= 0x1f || (code >= 0x7f && code <= 0x9f))
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+ function boundedText(value, path, maximum) {
84
+ if (typeof value !== 'string')
85
+ invocationError('HQ_INVOCATION_TYPE', path);
86
+ if (value.length > maximum || textEncoder.encode(value).byteLength > maximum) {
87
+ invocationError('HQ_INVOCATION_TOO_LARGE', path);
88
+ }
89
+ if (hasControlCharacter(value))
90
+ invocationError('HQ_INVOCATION_INVALID_VALUE', path);
91
+ return value;
92
+ }
93
+ function boundedInteger(value, path, maximum) {
94
+ if (typeof value !== 'number')
95
+ invocationError('HQ_INVOCATION_TYPE', path);
96
+ if (!Number.isSafeInteger(value) || value < 1) {
97
+ invocationError('HQ_INVOCATION_INVALID_VALUE', path);
98
+ }
99
+ if (value > maximum)
100
+ invocationError('HQ_INVOCATION_TOO_LARGE', path);
101
+ return value;
102
+ }
103
+ function nonNegativeInteger(value, path, maximum) {
104
+ if (typeof value !== 'number')
105
+ invocationError('HQ_INVOCATION_TYPE', path);
106
+ if (!Number.isSafeInteger(value) || value < 0) {
107
+ invocationError('HQ_INVOCATION_INVALID_VALUE', path);
108
+ }
109
+ if (value > maximum)
110
+ invocationError('HQ_INVOCATION_TOO_LARGE', path);
111
+ return value;
112
+ }
113
+ function requireBoolean(value, path) {
114
+ if (typeof value !== 'boolean')
115
+ invocationError('HQ_INVOCATION_TYPE', path);
116
+ return value;
117
+ }
118
+ function activationRevision(value, path) {
119
+ if (typeof value !== 'string')
120
+ invocationError('HQ_INVOCATION_TYPE', path);
121
+ if (!HEX64_PATTERN.test(value))
122
+ invocationError('HQ_INVOCATION_INVALID_VALUE', path);
123
+ return value;
124
+ }
125
+ function requireVersion(value, kind, path) {
126
+ if (value.kind !== kind) {
127
+ if (typeof value.kind !== 'string')
128
+ invocationError('HQ_INVOCATION_TYPE', `${path}.kind`);
129
+ invocationError('HQ_INVOCATION_INVALID_VALUE', `${path}.kind`);
130
+ }
131
+ if (value.version !== 1) {
132
+ if (typeof value.version !== 'number')
133
+ invocationError('HQ_INVOCATION_TYPE', `${path}.version`);
134
+ invocationError('HQ_INVOCATION_INVALID_VERSION', `${path}.version`);
135
+ }
136
+ }
137
+ function target(input, path, limits) {
138
+ const value = requireRecord(input, path);
139
+ exactFields(value, ['project', 'environment'], [], path);
140
+ const result = {};
141
+ for (const key of ['project', 'environment']) {
142
+ const text = boundedText(value[key], `${path}.${key}`, limits.maxTextBytes);
143
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(text)) {
144
+ invocationError('HQ_INVOCATION_INVALID_VALUE', `${path}.${key}`);
145
+ }
146
+ result[key] = text;
147
+ }
148
+ return freezeRecord(result);
149
+ }
150
+ function budget(input, path, limits) {
151
+ const value = requireRecord(input, path);
152
+ exactFields(value, [], ['deadlineMs', 'maxRows', 'maxResponseBytes'], path);
153
+ const result = {};
154
+ if (value.deadlineMs !== undefined) {
155
+ result.deadlineMs = boundedInteger(value.deadlineMs, `${path}.deadlineMs`, limits.maxDeadlineMs);
156
+ }
157
+ if (value.maxRows !== undefined) {
158
+ result.maxRows = boundedInteger(value.maxRows, `${path}.maxRows`, limits.maxRows);
159
+ }
160
+ if (value.maxResponseBytes !== undefined) {
161
+ result.maxResponseBytes = boundedInteger(value.maxResponseBytes, `${path}.maxResponseBytes`, limits.maxResponseBytes);
162
+ }
163
+ // An empty budget is indistinguishable from omitting the field, and two
164
+ // encodings of the same request are not portable.
165
+ if (Object.keys(result).length === 0)
166
+ invocationError('HQ_INVOCATION_INVALID_VALUE', path);
167
+ return freezeRecord(result);
168
+ }
169
+ /** Validate one dataset or metric invocation request. */
170
+ export function validateProtocolSemanticInvocation(input, options = {}) {
171
+ const limits = resolveSemanticInvocationLimits(options);
172
+ const value = requireRecord(input, '$');
173
+ exactFields(value, ['kind', 'version', 'target', 'operation'], ['activationRevision', 'budget', 'correlationId'], '$');
174
+ requireVersion(value, 'hypequery-semantic-invocation', '$');
175
+ const result = {
176
+ kind: 'hypequery-semantic-invocation',
177
+ version: 1,
178
+ target: target(value.target, '$.target', limits),
179
+ operation: semanticQuery(value.operation, '$.operation'),
180
+ };
181
+ if (value.activationRevision !== undefined) {
182
+ result.activationRevision = activationRevision(value.activationRevision, '$.activationRevision');
183
+ }
184
+ if (value.budget !== undefined)
185
+ result.budget = budget(value.budget, '$.budget', limits);
186
+ if (value.correlationId !== undefined) {
187
+ result.correlationId = boundedText(value.correlationId, '$.correlationId', limits.maxTextBytes);
188
+ }
189
+ return freezeRecord(result);
190
+ }
191
+ function semanticQuery(input, path) {
192
+ try {
193
+ return validateProtocolSemanticQuery(input);
194
+ }
195
+ catch (error) {
196
+ if (error instanceof ProtocolExpressionError) {
197
+ invocationError('HQ_INVOCATION_INVALID_VALUE', path);
198
+ }
199
+ throw error;
200
+ }
201
+ }
202
+ function row(input, path, limits) {
203
+ const value = requireRecord(input, path);
204
+ const keys = Object.keys(value);
205
+ if (keys.length > limits.maxColumnsPerRow) {
206
+ invocationError('HQ_INVOCATION_TOO_MANY_ITEMS', path);
207
+ }
208
+ const result = {};
209
+ for (const key of keys) {
210
+ const cell = value[key];
211
+ const cellPath = `${path}.${key}`;
212
+ if (cell === null || typeof cell === 'boolean') {
213
+ result[key] = cell;
214
+ }
215
+ else if (typeof cell === 'number') {
216
+ // A non-finite number has no portable JSON encoding.
217
+ if (!Number.isFinite(cell))
218
+ invocationError('HQ_INVOCATION_INVALID_VALUE', cellPath);
219
+ result[key] = cell;
220
+ }
221
+ else if (typeof cell === 'string') {
222
+ if (textEncoder.encode(cell).byteLength > limits.maxValueBytes) {
223
+ invocationError('HQ_INVOCATION_TOO_LARGE', cellPath);
224
+ }
225
+ if (hasControlCharacter(cell))
226
+ invocationError('HQ_INVOCATION_INVALID_VALUE', cellPath);
227
+ result[key] = cell;
228
+ }
229
+ else {
230
+ invocationError('HQ_INVOCATION_TYPE', cellPath);
231
+ }
232
+ }
233
+ return freezeRecord(result);
234
+ }
235
+ function meta(input, path, limits, rowCount) {
236
+ const value = requireRecord(input, path);
237
+ exactFields(value, ['rowCount'], ['pagination'], path);
238
+ const declared = nonNegativeInteger(value.rowCount, `${path}.rowCount`, limits.maxRows);
239
+ // A rowCount that disagrees with the rows it describes is a broken result,
240
+ // not a hint — the caller would page or aggregate on a false total.
241
+ if (declared !== rowCount)
242
+ invocationError('HQ_INVOCATION_INVALID_VALUE', `${path}.rowCount`);
243
+ const result = { rowCount: declared };
244
+ if (value.pagination !== undefined) {
245
+ const paginationPath = `${path}.pagination`;
246
+ const pagination = requireRecord(value.pagination, paginationPath);
247
+ exactFields(pagination, ['limit', 'offset', 'hasMore'], [], paginationPath);
248
+ result.pagination = freezeRecord({
249
+ limit: boundedInteger(pagination.limit, `${paginationPath}.limit`, limits.maxRows),
250
+ offset: nonNegativeInteger(pagination.offset, `${paginationPath}.offset`, Number.MAX_SAFE_INTEGER),
251
+ hasMore: requireBoolean(pagination.hasMore, `${paginationPath}.hasMore`),
252
+ });
253
+ }
254
+ return freezeRecord(result);
255
+ }
256
+ /** Validate a successful invocation result before it is returned or cached. */
257
+ export function validateProtocolSemanticInvocationResult(input, options = {}) {
258
+ const limits = resolveSemanticInvocationLimits(options);
259
+ const value = requireRecord(input, '$');
260
+ exactFields(value, ['kind', 'version', 'activationRevision', 'data', 'meta'], [], '$');
261
+ requireVersion(value, 'hypequery-semantic-invocation-result', '$');
262
+ const rows = requireArray(value.data, '$.data', limits.maxRows);
263
+ const data = Object.freeze(rows.map((entry, index) => row(entry, `$.data[${index}]`, limits)));
264
+ return freezeRecord({
265
+ kind: 'hypequery-semantic-invocation-result',
266
+ version: 1,
267
+ activationRevision: activationRevision(value.activationRevision, '$.activationRevision'),
268
+ data,
269
+ meta: meta(value.meta, '$.meta', limits, data.length),
270
+ });
271
+ }
272
+ /** Validate a failed invocation before it crosses a trust boundary. */
273
+ export function validateProtocolSemanticInvocationFailure(input, options = {}) {
274
+ const limits = resolveSemanticInvocationLimits(options);
275
+ const value = requireRecord(input, '$');
276
+ exactFields(value, ['kind', 'version', 'category', 'code', 'message', 'retryable', 'relist'], ['path', 'activationRevision'], '$');
277
+ requireVersion(value, 'hypequery-semantic-invocation-failure', '$');
278
+ if (typeof value.category !== 'string')
279
+ invocationError('HQ_INVOCATION_TYPE', '$.category');
280
+ if (!FAILURE_CATEGORIES.includes(value.category)) {
281
+ invocationError('HQ_INVOCATION_INVALID_VALUE', '$.category');
282
+ }
283
+ const message = boundedText(value.message, '$.message', limits.maxMessageBytes);
284
+ if (message !== PROTOCOL_SEMANTIC_FAILURE_MESSAGES[value.category]) {
285
+ invocationError('HQ_INVOCATION_INVALID_VALUE', '$.message');
286
+ }
287
+ const code = boundedText(value.code, '$.code', limits.maxTextBytes);
288
+ if (!FAILURE_CODE_PATTERN.test(code))
289
+ invocationError('HQ_INVOCATION_INVALID_VALUE', '$.code');
290
+ const result = {
291
+ kind: 'hypequery-semantic-invocation-failure',
292
+ version: 1,
293
+ category: value.category,
294
+ code,
295
+ message,
296
+ retryable: requireBoolean(value.retryable, '$.retryable'),
297
+ relist: requireBoolean(value.relist, '$.relist'),
298
+ };
299
+ if (value.path !== undefined) {
300
+ result.path = boundedText(value.path, '$.path', limits.maxTextBytes);
301
+ }
302
+ if (value.activationRevision !== undefined) {
303
+ result.activationRevision = activationRevision(value.activationRevision, '$.activationRevision');
304
+ }
305
+ return freezeRecord(result);
306
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/protocol",
3
- "version": "0.11.1",
3
+ "version": "0.13.0",
4
4
  "description": "Portable analytics contracts and TypeScript reference implementation for Hypequery",
5
5
  "keywords": [
6
6
  "hypequery",