@hypequery/protocol 0.16.0 → 0.18.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.
@@ -0,0 +1,21 @@
1
+ import type { BuildProtocolCachePreimageOptions, ProtocolCachePreimageErrorCode } from './types.js';
2
+ export declare class ProtocolCachePreimageError extends Error {
3
+ readonly code: ProtocolCachePreimageErrorCode;
4
+ constructor(code: ProtocolCachePreimageErrorCode);
5
+ }
6
+ /**
7
+ * The RFC 0009 tenant fingerprint: tells two tenants apart without revealing
8
+ * either. Keyed by a namespace secret, because tenant identifier spaces are
9
+ * small enough that an unkeyed digest could be reversed by enumeration.
10
+ */
11
+ export declare function deriveProtocolTenantFingerprint(secret: Uint8Array, tenantId: string): string;
12
+ /**
13
+ * Builds the RFC 0009 cache preimage: the canonical bytes that identify a
14
+ * cached semantic result. Feed them to `deriveProtocolCacheKey` (RFC 0013); never
15
+ * log them, emit them, or use them as a key.
16
+ *
17
+ * Checks run in the RFC's normative order, so every implementation reports the
18
+ * same first failure.
19
+ */
20
+ export declare function buildProtocolCachePreimage(options: BuildProtocolCachePreimageOptions): string;
21
+ //# sourceMappingURL=cache-preimages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-preimages.d.ts","sourceRoot":"","sources":["../../src/cache-preimages/cache-preimages.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,iCAAiC,EACjC,8BAA8B,EAC/B,MAAM,YAAY,CAAC;AAQpB,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAC;gBAElC,IAAI,EAAE,8BAA8B;CAOjD;AAwBD;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5F;AAoED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,iCAAiC,GAAG,MAAM,CAmB7F"}
@@ -0,0 +1,143 @@
1
+ import { hmac } from '@noble/hashes/hmac';
2
+ import { sha256 } from '@noble/hashes/sha2';
3
+ import { bytesToHex } from '@noble/hashes/utils';
4
+ import { validateProtocolSemanticQuery } from '../expressions/validate.js';
5
+ import { serializeJcs } from '../values/jcs.js';
6
+ const FINGERPRINT_DOMAIN = 'hypequery.tenant.fingerprint.v1';
7
+ const MIN_SECRET_BYTES = 32;
8
+ const DEFINITION_IDENTITY = /^[0-9a-f]{64}$/;
9
+ const textEncoder = new TextEncoder();
10
+ export class ProtocolCachePreimageError extends Error {
11
+ code;
12
+ constructor(code) {
13
+ // The code and nothing else: the secret, tenant identifiers, and filter
14
+ // values are all in scope wherever this is raised.
15
+ super(code);
16
+ this.name = 'ProtocolCachePreimageError';
17
+ this.code = code;
18
+ }
19
+ }
20
+ function fail(code) {
21
+ throw new ProtocolCachePreimageError(code);
22
+ }
23
+ function requireSecret(secret) {
24
+ if (!secret || secret.byteLength === 0)
25
+ fail('HQ_CACHE_PREIMAGE_SECRET_MISSING');
26
+ if (secret.byteLength < MIN_SECRET_BYTES)
27
+ fail('HQ_CACHE_PREIMAGE_SECRET_TOO_SHORT');
28
+ return secret;
29
+ }
30
+ function fingerprint(secret, tenantId) {
31
+ if (typeof tenantId !== 'string' || tenantId.length === 0) {
32
+ fail('HQ_CACHE_PREIMAGE_INVALID_TENANT');
33
+ }
34
+ const domain = textEncoder.encode(FINGERPRINT_DOMAIN);
35
+ const id = textEncoder.encode(tenantId);
36
+ const input = new Uint8Array(domain.byteLength + 1 + id.byteLength);
37
+ input.set(domain, 0);
38
+ input.set(id, domain.byteLength + 1);
39
+ return bytesToHex(hmac(sha256, secret, input));
40
+ }
41
+ /**
42
+ * The RFC 0009 tenant fingerprint: tells two tenants apart without revealing
43
+ * either. Keyed by a namespace secret, because tenant identifier spaces are
44
+ * small enough that an unkeyed digest could be reversed by enumeration.
45
+ */
46
+ export function deriveProtocolTenantFingerprint(secret, tenantId) {
47
+ return fingerprint(requireSecret(secret), tenantId);
48
+ }
49
+ /** Byte order of the UTF-8 encoding, which is what the RFC sorts by. */
50
+ function compareUtf8(left, right) {
51
+ const a = textEncoder.encode(left);
52
+ const b = textEncoder.encode(right);
53
+ const length = Math.min(a.byteLength, b.byteLength);
54
+ for (let index = 0; index < length; index += 1) {
55
+ const difference = a[index] - b[index];
56
+ if (difference !== 0)
57
+ return difference;
58
+ }
59
+ return a.byteLength - b.byteLength;
60
+ }
61
+ function normalizeQuery(source) {
62
+ let query;
63
+ try {
64
+ query = validateProtocolSemanticQuery(source, { extension: 2 });
65
+ }
66
+ catch {
67
+ // The expression code is not surfaced, so this family's set stays closed.
68
+ fail('HQ_CACHE_PREIMAGE_INVALID_QUERY');
69
+ }
70
+ // AND-combined, so order cannot change rows; identical filters collapse.
71
+ const filters = new Map();
72
+ for (const filter of query.filters ?? [])
73
+ filters.set(serializeJcs(filter), filter);
74
+ const normalized = {
75
+ kind: query.kind,
76
+ dataset: query.dataset,
77
+ dimensions: query.dimensions ?? [],
78
+ filters: [...filters.keys()].sort(compareUtf8).map((key) => filters.get(key)),
79
+ segments: [...(query.segments ?? [])].sort(compareUtf8),
80
+ orderBy: query.orderBy ?? [],
81
+ by: query.by ?? null,
82
+ offset: query.offset || null,
83
+ };
84
+ if (query.kind === 'metric') {
85
+ normalized.metric = query.metric;
86
+ }
87
+ else {
88
+ // Absent selects every measure and `[]` selects none, so they stay distinct.
89
+ normalized.measures = query.measures ?? null;
90
+ }
91
+ return normalized;
92
+ }
93
+ function normalizeTenant(tenant, secret) {
94
+ if (tenant === null || typeof tenant !== 'object' || Array.isArray(tenant)) {
95
+ fail('HQ_CACHE_PREIMAGE_INVALID_TENANT');
96
+ }
97
+ const record = tenant;
98
+ const fields = Object.keys(record).sort().join(',');
99
+ if ((record.mode === 'none' || record.mode === 'all') && fields === 'mode') {
100
+ return { mode: record.mode };
101
+ }
102
+ if (record.mode !== 'scoped' || fields !== 'ids,mode')
103
+ fail('HQ_CACHE_PREIMAGE_INVALID_TENANT');
104
+ const ids = record.ids;
105
+ if (!Array.isArray(ids) || ids.length === 0)
106
+ fail('HQ_CACHE_PREIMAGE_INVALID_TENANT');
107
+ const fingerprints = new Set(ids.map((id) => fingerprint(secret, id)));
108
+ return { mode: 'scoped', fingerprints: [...fingerprints].sort() };
109
+ }
110
+ function normalizeRowLimit(rowLimit) {
111
+ if (rowLimit === null)
112
+ return null;
113
+ if (typeof rowLimit !== 'number' || !Number.isSafeInteger(rowLimit) || rowLimit < 0) {
114
+ fail('HQ_CACHE_PREIMAGE_INVALID_LIMIT');
115
+ }
116
+ return rowLimit;
117
+ }
118
+ /**
119
+ * Builds the RFC 0009 cache preimage: the canonical bytes that identify a
120
+ * cached semantic result. Feed them to `deriveProtocolCacheKey` (RFC 0013); never
121
+ * log them, emit them, or use them as a key.
122
+ *
123
+ * Checks run in the RFC's normative order, so every implementation reports the
124
+ * same first failure.
125
+ */
126
+ export function buildProtocolCachePreimage(options) {
127
+ const secret = requireSecret(options.secret);
128
+ if (typeof options.definitionIdentity !== 'string'
129
+ || !DEFINITION_IDENTITY.test(options.definitionIdentity)) {
130
+ fail('HQ_CACHE_PREIMAGE_INVALID_DEFINITION');
131
+ }
132
+ const query = normalizeQuery(options.query);
133
+ const tenant = normalizeTenant(options.tenant, secret);
134
+ const rowLimit = normalizeRowLimit(options.rowLimit);
135
+ return serializeJcs({
136
+ kind: 'hypequery-cache-preimage',
137
+ version: 1,
138
+ definition: options.definitionIdentity,
139
+ query,
140
+ tenant,
141
+ rowLimit,
142
+ });
143
+ }
@@ -0,0 +1,3 @@
1
+ export { ProtocolCachePreimageError, buildProtocolCachePreimage, deriveProtocolTenantFingerprint, } from './cache-preimages.js';
2
+ export type { BuildProtocolCachePreimageOptions, ProtocolCachePreimageErrorCode, ProtocolCacheTenantScope, } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache-preimages/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,+BAA+B,GAChC,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,iCAAiC,EACjC,8BAA8B,EAC9B,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
@@ -0,0 +1 @@
1
+ export { ProtocolCachePreimageError, buildProtocolCachePreimage, deriveProtocolTenantFingerprint, } from './cache-preimages.js';
@@ -0,0 +1,29 @@
1
+ /** Stable failure codes for cache preimage version 1 (RFC 0009). */
2
+ export type ProtocolCachePreimageErrorCode = 'HQ_CACHE_PREIMAGE_SECRET_MISSING' | 'HQ_CACHE_PREIMAGE_SECRET_TOO_SHORT' | 'HQ_CACHE_PREIMAGE_INVALID_DEFINITION' | 'HQ_CACHE_PREIMAGE_INVALID_QUERY' | 'HQ_CACHE_PREIMAGE_INVALID_TENANT' | 'HQ_CACHE_PREIMAGE_INVALID_LIMIT';
3
+ /**
4
+ * The tenant scope an execution runs under, as resolved server-side.
5
+ *
6
+ * `all` is a trusted execution the runtime itself scopes to every tenant. It
7
+ * is never reachable from a request and is not the cross-tenant administrative
8
+ * capability, which never touches the data plane.
9
+ */
10
+ export type ProtocolCacheTenantScope = {
11
+ readonly mode: 'none';
12
+ } | {
13
+ readonly mode: 'scoped';
14
+ readonly ids: readonly string[];
15
+ } | {
16
+ readonly mode: 'all';
17
+ };
18
+ export interface BuildProtocolCachePreimageOptions {
19
+ /** The namespace's RFC 0013 cache-key secret; keys tenant fingerprints. */
20
+ readonly secret: Uint8Array;
21
+ /** 64 lowercase hex characters; the RFC 0007 bundle identity when released. */
22
+ readonly definitionIdentity: string;
23
+ /** An RFC 0003 semantic query, validated under expression extension 2. */
24
+ readonly query: unknown;
25
+ readonly tenant: ProtocolCacheTenantScope;
26
+ /** The effective maximum row count, or `null` when none applies. */
27
+ readonly rowLimit: number | null;
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cache-preimages/types.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,MAAM,8BAA8B,GACtC,kCAAkC,GAClC,oCAAoC,GACpC,sCAAsC,GACtC,iCAAiC,GACjC,kCAAkC,GAClC,iCAAiC,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAE7B,MAAM,WAAW,iCAAiC;IAChD,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/events/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,wBAAwB,EAExB,kBAAkB,EAElB,yBAAyB,EAE1B,MAAM,YAAY,CAAC;AA4OpB,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,kBAAkB,CAuDpB;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,wBAAwB,CA+B1B"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/events/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,wBAAwB,EAExB,kBAAkB,EAElB,yBAAyB,EAE1B,MAAM,YAAY,CAAC;AAuRpB,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,kBAAkB,CAiDpB;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,wBAAwB,CAiC1B"}
@@ -25,7 +25,7 @@ const DIAGNOSTICS_CONTEXT = {
25
25
  fail: diagnosticsError,
26
26
  };
27
27
  const HEX64_PATTERN = /^[0-9a-f]{64}$/;
28
- const OCCURRED_AT_PATTERN = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]{1,3})?Z$/;
28
+ const OCCURRED_AT_PATTERN = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:\.[0-9]{3})?Z$/;
29
29
  const OPERATIONS = ['query', 'command', 'insert'];
30
30
  const OUTCOMES = ['success', 'failure'];
31
31
  const ERROR_CATEGORIES = [
@@ -84,20 +84,37 @@ function requireString(context, value, path) {
84
84
  context.fail(context.codes.type, path);
85
85
  return value;
86
86
  }
87
- function hasControlCharacter(text) {
87
+ // The compiler's debug form spans lines, so debugQuery alone may carry tab,
88
+ // line feed, and carriage return.
89
+ const LINE_BREAK_CHARACTERS = new Set([0x09, 0x0a, 0x0d]);
90
+ // Rejects C0 controls, DEL, the C1 range, and unpaired surrogates, which have
91
+ // no UTF-8 encoding and so no canonical bytes.
92
+ function hasForbiddenCodeUnit(text, allowLineBreaks) {
88
93
  for (let index = 0; index < text.length; index += 1) {
89
94
  const code = text.charCodeAt(index);
95
+ if (code <= 0x1f && allowLineBreaks && LINE_BREAK_CHARACTERS.has(code))
96
+ continue;
90
97
  if (code <= 0x1f || (code >= 0x7f && code <= 0x9f))
91
98
  return true;
99
+ if (code >= 0xd800 && code <= 0xdbff) {
100
+ // charCodeAt past the end is NaN, which fails the range check.
101
+ const low = text.charCodeAt(index + 1);
102
+ if (!(low >= 0xdc00 && low <= 0xdfff))
103
+ return true;
104
+ index += 1;
105
+ }
106
+ else if (code >= 0xdc00 && code <= 0xdfff) {
107
+ return true;
108
+ }
92
109
  }
93
110
  return false;
94
111
  }
95
- function boundedText(context, value, path, maximum) {
112
+ function boundedText(context, value, path, maximum, allowLineBreaks = false) {
96
113
  const text = requireString(context, value, path);
97
114
  if (text.length > maximum || textEncoder.encode(text).byteLength > maximum) {
98
115
  context.fail(context.codes.tooLarge, path);
99
116
  }
100
- if (hasControlCharacter(text)) {
117
+ if (hasForbiddenCodeUnit(text, allowLineBreaks)) {
101
118
  context.fail(context.codes.invalidValue, path);
102
119
  }
103
120
  return text;
@@ -110,7 +127,21 @@ function hexIdentity(context, value, path) {
110
127
  }
111
128
  function occurredAt(context, value, path) {
112
129
  const text = requireString(context, value, path);
113
- if (!OCCURRED_AT_PATTERN.test(text) || Number.isNaN(Date.parse(text))) {
130
+ const match = OCCURRED_AT_PATTERN.exec(text);
131
+ if (!match)
132
+ context.fail(context.codes.invalidValue, path);
133
+ const [year, month, day, hour, minute, second] = match.slice(1).map(Number);
134
+ // Round-trip through Date so impossible dates (2026-02-30) and 24:00 fail
135
+ // rather than rolling over. setUTCFullYear avoids Date.UTC's 0-99 remap.
136
+ const date = new Date(0);
137
+ date.setUTCFullYear(year, month - 1, day);
138
+ date.setUTCHours(hour, minute, second, 0);
139
+ if (date.getUTCFullYear() !== year
140
+ || date.getUTCMonth() !== month - 1
141
+ || date.getUTCDate() !== day
142
+ || date.getUTCHours() !== hour
143
+ || date.getUTCMinutes() !== minute
144
+ || date.getUTCSeconds() !== second) {
114
145
  context.fail(context.codes.invalidValue, path);
115
146
  }
116
147
  return text;
@@ -166,10 +197,18 @@ function kindAndVersion(context, value, kind) {
166
197
  fail(codes.invalidVersion, '$.version');
167
198
  }
168
199
  }
200
+ function outcomeWithCategory(context, value, hasCategory) {
201
+ const outcome = stringChoice(context, value.outcome, '$.outcome', OUTCOMES);
202
+ if ((outcome === 'failure') !== hasCategory) {
203
+ context.fail(context.codes.invalidValue, '$.errorCategory');
204
+ }
205
+ return outcome;
206
+ }
169
207
  export function validateProtocolQueryEvent(input, options = {}) {
170
208
  const limits = resolveQueryEventLimits(options);
171
209
  const context = EVENT_CONTEXT;
172
210
  const value = requireRecord(context, input, '$');
211
+ kindAndVersion(context, value, 'hypequery-query-event');
173
212
  exactFields(context, value, [
174
213
  'kind',
175
214
  'version',
@@ -181,15 +220,8 @@ export function validateProtocolQueryEvent(input, options = {}) {
181
220
  'outcome',
182
221
  'durationMs',
183
222
  ], ['errorCategory', 'rowCount', 'tenantFingerprint', 'correlationId'], '$');
184
- kindAndVersion(context, value, 'hypequery-query-event');
185
- const outcome = stringChoice(context, value.outcome, '$.outcome', OUTCOMES);
186
223
  const hasCategory = Object.hasOwn(value, 'errorCategory');
187
- if (outcome === 'failure' && !hasCategory) {
188
- eventError('HQ_EVENT_INVALID_VALUE', '$.errorCategory');
189
- }
190
- if (outcome === 'success' && hasCategory) {
191
- eventError('HQ_EVENT_INVALID_VALUE', '$.errorCategory');
192
- }
224
+ // Object literal entries evaluate in order, so fields are checked in RFC order.
193
225
  return freezeRecord({
194
226
  kind: 'hypequery-query-event',
195
227
  version: 1,
@@ -198,7 +230,7 @@ export function validateProtocolQueryEvent(input, options = {}) {
198
230
  target: queryTarget(context, value.target, '$.target'),
199
231
  queryName: queryName(context, value.queryName, '$.queryName'),
200
232
  operation: stringChoice(context, value.operation, '$.operation', OPERATIONS),
201
- outcome,
233
+ outcome: outcomeWithCategory(context, value, hasCategory),
202
234
  ...(hasCategory ? {
203
235
  errorCategory: stringChoice(context, value.errorCategory, '$.errorCategory', ERROR_CATEGORIES),
204
236
  } : {}),
@@ -218,8 +250,8 @@ export function validateProtocolQueryDiagnostics(input, options = {}) {
218
250
  const limits = resolveQueryEventLimits(options);
219
251
  const context = DIAGNOSTICS_CONTEXT;
220
252
  const value = requireRecord(context, input, '$');
221
- exactFields(context, value, ['kind', 'version', 'eventId', 'queryId', 'terminalReason', 'attempts'], ['runtimeIdentity', 'debugQuery', 'safeMessage'], '$');
222
253
  kindAndVersion(context, value, 'hypequery-query-diagnostics');
254
+ exactFields(context, value, ['kind', 'version', 'eventId', 'queryId', 'terminalReason', 'attempts'], ['runtimeIdentity', 'debugQuery', 'safeMessage'], '$');
223
255
  return freezeRecord({
224
256
  kind: 'hypequery-query-diagnostics',
225
257
  version: 1,
@@ -231,7 +263,7 @@ export function validateProtocolQueryDiagnostics(input, options = {}) {
231
263
  runtimeIdentity: hexIdentity(context, value.runtimeIdentity, '$.runtimeIdentity'),
232
264
  } : {}),
233
265
  ...(Object.hasOwn(value, 'debugQuery') ? {
234
- debugQuery: boundedText(context, value.debugQuery, '$.debugQuery', limits.maxDebugBytes),
266
+ debugQuery: boundedText(context, value.debugQuery, '$.debugQuery', limits.maxDebugBytes, true),
235
267
  } : {}),
236
268
  ...(Object.hasOwn(value, 'safeMessage') ? {
237
269
  safeMessage: boundedText(context, value.safeMessage, '$.safeMessage', limits.maxStringBytes),
package/dist/index.d.ts CHANGED
@@ -2,11 +2,13 @@ export { DEFAULT_CANONICAL_VALUE_LIMITS, ProtocolValueError, decodeCanonicalValu
2
2
  export type { ArrayTaggedValue, BytesTaggedValue, CanonicalValue, CanonicalValueLimits, CanonicalValueOptions, DateTaggedValue, DatetimeTaggedValue, DecimalTaggedValue, EnumTaggedValue, IntegerTaggedValue, MapTaggedValue, ProtocolValueErrorCode, TaggedValue, TupleTaggedValue, UuidTaggedValue, } from './values/index.js';
3
3
  export { PROTOCOL_IDENTIFIER_LIMITS, ProtocolIdentifierError, isProtocolIdentifier, isProtocolQualifiedIdentifier, joinProtocolQualifiedIdentifier, parseProtocolIdentifier, parseProtocolQualifiedIdentifier, splitProtocolQualifiedIdentifier, } from './identifiers/index.js';
4
4
  export { PROTOCOL_CACHE_KEY_LIMITS, ProtocolCacheKeyError, deriveProtocolCacheKey, deriveProtocolCacheNamespaceToken, } from './cache-keys/index.js';
5
+ export { ProtocolCachePreimageError, buildProtocolCachePreimage, deriveProtocolTenantFingerprint, } from './cache-preimages/index.js';
5
6
  export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS, ProtocolExpressionError, validateProtocolExpression, validateProtocolSemanticQuery, } from './expressions/index.js';
6
7
  export { DEFAULT_PROTOCOL_SCHEMA_LIMITS, DEFAULT_PROTOCOL_SCHEMA_VALUE_LIMITS, ProtocolSchemaError, ProtocolSchemaValueError, applyProtocolSchemaValue, createProtocolSchemaValueParser, resolveProtocolSchemaValueLimits, validateProtocolSchema, } from './schemas/index.js';
7
8
  export type { ProtocolSchema, ProtocolSchemaErrorCode, ProtocolSchemaLimits, ProtocolSchemaOptions, ProtocolSchemaValueLimits, ProtocolSchemaValueOptions, ProtocolSchemaValueParser, } from './schemas/index.js';
8
9
  export type { ProtocolAggregation, ProtocolBinaryOperator, ProtocolComparisonOperator, ProtocolDatasetQuery, ProtocolExpression, ProtocolExpressionErrorCode, ProtocolExpressionExtension, ProtocolExpressionLimits, ProtocolExpressionOptions, ProtocolFunctionName, ProtocolMetricQuery, ProtocolOrderBy, ProtocolSemanticQuery, ProtocolQueryTimeGrain, ProtocolTimeGrain, } from './expressions/index.js';
9
10
  export type { DeriveProtocolCacheKeyOptions, ProtocolCacheKeyErrorCode, ProtocolCacheKeyNamespace, } from './cache-keys/index.js';
11
+ export type { BuildProtocolCachePreimageOptions, ProtocolCachePreimageErrorCode, ProtocolCacheTenantScope, } from './cache-preimages/index.js';
10
12
  export type { ProtocolIdentifier, ProtocolIdentifierErrorCode, ProtocolQualifiedIdentifier, } from './identifiers/index.js';
11
13
  export { DEFAULT_PROTOCOL_QUERY_IMPLEMENTATION_LIMITS, ProtocolQueryImplementationError, validateProtocolQueryImplementation, validateProtocolSqlExpression, } from './query-implementations/index.js';
12
14
  export { DEFAULT_PROTOCOL_QUERY_EVENT_LIMITS, ProtocolQueryDiagnosticsError, ProtocolQueryEventError, validateProtocolQueryDiagnostics, validateProtocolQueryEvent, } from './events/index.js';
@@ -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,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,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,2CAA2C,EAC3C,+BAA+B,EAC/B,kCAAkC,EAClC,yCAAyC,EACzC,wCAAwC,EACxC,oCAAoC,GACrC,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACV,0BAA0B,EAC1B,4BAA4B,EAC5B,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,wBAAwB,CAAC;AAEhC,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,sCAAsC,EACtC,uBAAuB,EACvB,gCAAgC,EAChC,wCAAwC,EACxC,8BAA8B,EAC9B,iCAAiC,EACjC,mCAAmC,EACnC,+BAA+B,EAC/B,kCAAkC,EAClC,oCAAoC,GACrC,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACV,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,kCAAkC,EAClC,oCAAoC,EACpC,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,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,EAC3B,+BAA+B,EAC/B,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,EAC3B,4BAA4B,EAC5B,oBAAoB,EACpB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,4BAA4B,EAC5B,wBAAwB,EACxB,mBAAmB,GACpB,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;AAE1C,OAAO,EAAE,kCAAkC,EAAE,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { DEFAULT_CANONICAL_VALUE_LIMITS, ProtocolValueError, decodeCanonicalValue, encodeCanonicalValue, encodeCanonicalValueToString, hashCanonicalValue, validateCanonicalValue, } from './values/index.js';
2
2
  export { PROTOCOL_IDENTIFIER_LIMITS, ProtocolIdentifierError, isProtocolIdentifier, isProtocolQualifiedIdentifier, joinProtocolQualifiedIdentifier, parseProtocolIdentifier, parseProtocolQualifiedIdentifier, splitProtocolQualifiedIdentifier, } from './identifiers/index.js';
3
3
  export { PROTOCOL_CACHE_KEY_LIMITS, ProtocolCacheKeyError, deriveProtocolCacheKey, deriveProtocolCacheNamespaceToken, } from './cache-keys/index.js';
4
+ export { ProtocolCachePreimageError, buildProtocolCachePreimage, deriveProtocolTenantFingerprint, } from './cache-preimages/index.js';
4
5
  export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS, ProtocolExpressionError, validateProtocolExpression, validateProtocolSemanticQuery, } from './expressions/index.js';
5
6
  export { DEFAULT_PROTOCOL_SCHEMA_LIMITS, DEFAULT_PROTOCOL_SCHEMA_VALUE_LIMITS, ProtocolSchemaError, ProtocolSchemaValueError, applyProtocolSchemaValue, createProtocolSchemaValueParser, resolveProtocolSchemaValueLimits, validateProtocolSchema, } from './schemas/index.js';
6
7
  export { DEFAULT_PROTOCOL_QUERY_IMPLEMENTATION_LIMITS, ProtocolQueryImplementationError, validateProtocolQueryImplementation, validateProtocolSqlExpression, } from './query-implementations/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/protocol",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "Portable analytics contracts and TypeScript reference implementation for Hypequery",
5
5
  "keywords": [
6
6
  "hypequery",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "typescript": "^5.7.3",
34
- "vitest": "^3.2.6"
34
+ "vitest": "^5.0.2"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",
@@ -48,7 +48,7 @@
48
48
  "scripts": {
49
49
  "build": "tsc --project tsconfig.json",
50
50
  "dev": "tsc --project tsconfig.json --watch",
51
- "lint": "eslint --ext .ts \"src/**/*.ts\"",
51
+ "lint": "eslint \"src/**/*.ts\"",
52
52
  "test": "vitest run",
53
53
  "types": "tsc --project tsconfig.json --noEmit && tsc --project tsconfig.test.json"
54
54
  }