@spotto/semantic-query 1.0.70-alpha.34 → 1.0.70-alpha.35

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.
@@ -1,91 +1,91 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveName = void 0;
4
- /**
5
- * Resolve a NAME to the ids it means — the one place a human word becomes a
6
- * record reference.
7
- *
8
- * The ladder is exact → case-insensitive → unique partial, and it is
9
- * deliberately conservative at every rung:
10
- *
11
- * - An EXACT match wins outright, even if partials also exist. "Bob" must not
12
- * become ambiguous just because "Bobby" is also on staff.
13
- * - Several records sharing one exact name resolve to ALL of them. Two people
14
- * genuinely called "Sam Lee" is a data fact, not a question to ask; both are
15
- * matched and the answer covers the name as asked.
16
- * - A partial match is accepted ONLY when it is unique. "Bri" matching both
17
- * "Brian" and "Brisbane Bob" is refused, with both named, because picking
18
- * one would answer a different question and look exactly like an answer.
19
- * - No match is refused with the nearest candidates offered.
20
- *
21
- * The failure modes are what make this safe to expose to a model. A regex
22
- * fallback — which is what the prototype did for assets — would match whatever
23
- * it happened to match, silently.
24
- */
25
- /**
26
- * How many candidates an ambiguity message names. Enough to disambiguate a
27
- * genuine near-miss, few enough that the error is not a directory listing.
28
- */
29
- const AMBIGUITY_EXAMPLES = 3;
30
- /** Up to three nearest candidates by simple containment, for a suggestion. */
31
- function nearest(catalogue, want) {
32
- const needle = want.trim().toLowerCase();
33
- if (!needle)
34
- return undefined;
35
- const hits = catalogue
36
- .filter((r) => {
37
- const n = r.name.toLowerCase();
38
- return n.includes(needle.slice(0, 3)) || needle.includes(n.slice(0, 3));
39
- })
40
- .slice(0, 3)
41
- .map((r) => { var _a; return (_a = r.label) !== null && _a !== void 0 ? _a : r.name; });
42
- return hits.length ? `Did you mean: ${hits.join(', ')}?` : undefined;
43
- }
44
- function resolveName(catalogue, rawName, opts) {
45
- const want = typeof rawName === 'string' ? rawName.trim() : '';
46
- if (!want) {
47
- return {
48
- ids: [],
49
- issue: {
50
- code: 'BAD_SHAPE',
51
- path: opts.path,
52
- message: `${opts.noun} needs a name`,
53
- },
54
- };
55
- }
56
- const all = catalogue !== null && catalogue !== void 0 ? catalogue : [];
57
- const lower = want.toLowerCase();
58
- const exact = all.filter((r) => r.name.toLowerCase() === lower);
59
- const partial = all.filter((r) => r.name.toLowerCase().includes(lower));
60
- // Exact wins outright — a longer name that merely CONTAINS this one must not
61
- // make an exact match ambiguous.
62
- const hit = exact.length ? exact : partial;
63
- if (!hit.length) {
64
- return {
65
- ids: [],
66
- issue: Object.assign({ code: 'UNKNOWN_NAME', path: opts.path, message: `No ${opts.noun} called '${want}' in this organisation` }, (nearest(all, want) ? { suggestion: nearest(all, want) } : {})),
67
- };
68
- }
69
- if (!exact.length && partial.length > 1) {
70
- // NAMED, NOT ENUMERATED. Listing every match turns this message into a
71
- // directory: the catalogue is org-scoped but not user-group scoped, and
72
- // these endpoints are gated on `assets:view` rather than `users:view` — so
73
- // an unbounded list let a confined field worker recover the whole staff
74
- // roster one letter at a time. A handful of examples is what makes the
75
- // error actionable; the rest is only useful to someone fishing.
76
- const shown = partial.slice(0, AMBIGUITY_EXAMPLES).map((r) => { var _a; return (_a = r.label) !== null && _a !== void 0 ? _a : r.name; });
77
- const rest = partial.length - shown.length;
78
- return {
79
- ids: [],
80
- issue: {
81
- code: 'AMBIGUOUS_NAME',
82
- path: opts.path,
83
- message: `'${want}' matches ${partial.length} ${opts.noun}s ` +
84
- `(${shown.join(', ')}${rest > 0 ? `, and ${rest} more` : ''}) — be more specific`,
85
- },
86
- };
87
- }
88
- return { ids: [...new Set(hit.map((r) => r.id))] };
89
- }
90
- exports.resolveName = resolveName;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveName = void 0;
4
+ /**
5
+ * Resolve a NAME to the ids it means — the one place a human word becomes a
6
+ * record reference.
7
+ *
8
+ * The ladder is exact → case-insensitive → unique partial, and it is
9
+ * deliberately conservative at every rung:
10
+ *
11
+ * - An EXACT match wins outright, even if partials also exist. "Bob" must not
12
+ * become ambiguous just because "Bobby" is also on staff.
13
+ * - Several records sharing one exact name resolve to ALL of them. Two people
14
+ * genuinely called "Sam Lee" is a data fact, not a question to ask; both are
15
+ * matched and the answer covers the name as asked.
16
+ * - A partial match is accepted ONLY when it is unique. "Bri" matching both
17
+ * "Brian" and "Brisbane Bob" is refused, with both named, because picking
18
+ * one would answer a different question and look exactly like an answer.
19
+ * - No match is refused with the nearest candidates offered.
20
+ *
21
+ * The failure modes are what make this safe to expose to a model. A regex
22
+ * fallback — which is what the prototype did for assets — would match whatever
23
+ * it happened to match, silently.
24
+ */
25
+ /**
26
+ * How many candidates an ambiguity message names. Enough to disambiguate a
27
+ * genuine near-miss, few enough that the error is not a directory listing.
28
+ */
29
+ const AMBIGUITY_EXAMPLES = 3;
30
+ /** Up to three nearest candidates by simple containment, for a suggestion. */
31
+ function nearest(catalogue, want) {
32
+ const needle = want.trim().toLowerCase();
33
+ if (!needle)
34
+ return undefined;
35
+ const hits = catalogue
36
+ .filter((r) => {
37
+ const n = r.name.toLowerCase();
38
+ return n.includes(needle.slice(0, 3)) || needle.includes(n.slice(0, 3));
39
+ })
40
+ .slice(0, 3)
41
+ .map((r) => { var _a; return (_a = r.label) !== null && _a !== void 0 ? _a : r.name; });
42
+ return hits.length ? `Did you mean: ${hits.join(', ')}?` : undefined;
43
+ }
44
+ function resolveName(catalogue, rawName, opts) {
45
+ const want = typeof rawName === 'string' ? rawName.trim() : '';
46
+ if (!want) {
47
+ return {
48
+ ids: [],
49
+ issue: {
50
+ code: 'BAD_SHAPE',
51
+ path: opts.path,
52
+ message: `${opts.noun} needs a name`,
53
+ },
54
+ };
55
+ }
56
+ const all = catalogue !== null && catalogue !== void 0 ? catalogue : [];
57
+ const lower = want.toLowerCase();
58
+ const exact = all.filter((r) => r.name.toLowerCase() === lower);
59
+ const partial = all.filter((r) => r.name.toLowerCase().includes(lower));
60
+ // Exact wins outright — a longer name that merely CONTAINS this one must not
61
+ // make an exact match ambiguous.
62
+ const hit = exact.length ? exact : partial;
63
+ if (!hit.length) {
64
+ return {
65
+ ids: [],
66
+ issue: Object.assign({ code: 'UNKNOWN_NAME', path: opts.path, message: `No ${opts.noun} called '${want}' in this organisation` }, (nearest(all, want) ? { suggestion: nearest(all, want) } : {})),
67
+ };
68
+ }
69
+ if (!exact.length && partial.length > 1) {
70
+ // NAMED, NOT ENUMERATED. Listing every match turns this message into a
71
+ // directory: the catalogue is org-scoped but not user-group scoped, and
72
+ // these endpoints are gated on `assets:view` rather than `users:view` — so
73
+ // an unbounded list let a confined field worker recover the whole staff
74
+ // roster one letter at a time. A handful of examples is what makes the
75
+ // error actionable; the rest is only useful to someone fishing.
76
+ const shown = partial.slice(0, AMBIGUITY_EXAMPLES).map((r) => { var _a; return (_a = r.label) !== null && _a !== void 0 ? _a : r.name; });
77
+ const rest = partial.length - shown.length;
78
+ return {
79
+ ids: [],
80
+ issue: {
81
+ code: 'AMBIGUOUS_NAME',
82
+ path: opts.path,
83
+ message: `'${want}' matches ${partial.length} ${opts.noun}s ` +
84
+ `(${shown.join(', ')}${rest > 0 ? `, and ${rest} more` : ''}) — be more specific`,
85
+ },
86
+ };
87
+ }
88
+ return { ids: [...new Set(hit.map((r) => r.id))] };
89
+ }
90
+ exports.resolveName = resolveName;
91
91
  //# sourceMappingURL=resolve-name.js.map
package/dist/suggest.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- /**
2
- * Nearest-candidate matching for "did you mean…" suggestions on validation
3
- * errors — an unknown field or dropdown value is rejected WITH the closest
4
- * real name, so an honest error is also an actionable one.
5
- *
6
- * Substring matching alone is not enough: the canonical case is
7
- * `SerialNo` → `SerialNumber`, and "serialno" is NOT a substring of
8
- * "serialnumber" (…n-o… vs …n-u…) nor within any sane edit-distance
9
- * tolerance (5 edits). The longest-shared-prefix pass is what makes that
10
- * documented case actually produce a suggestion.
11
- */
12
- export declare function nearest(candidates: string[], wanted: string): string | undefined;
1
+ /**
2
+ * Nearest-candidate matching for "did you mean…" suggestions on validation
3
+ * errors — an unknown field or dropdown value is rejected WITH the closest
4
+ * real name, so an honest error is also an actionable one.
5
+ *
6
+ * Substring matching alone is not enough: the canonical case is
7
+ * `SerialNo` → `SerialNumber`, and "serialno" is NOT a substring of
8
+ * "serialnumber" (…n-o… vs …n-u…) nor within any sane edit-distance
9
+ * tolerance (5 edits). The longest-shared-prefix pass is what makes that
10
+ * documented case actually produce a suggestion.
11
+ */
12
+ export declare function nearest(candidates: string[], wanted: string): string | undefined;
package/dist/suggest.js CHANGED
@@ -1,70 +1,70 @@
1
- "use strict";
2
- /**
3
- * Nearest-candidate matching for "did you mean…" suggestions on validation
4
- * errors — an unknown field or dropdown value is rejected WITH the closest
5
- * real name, so an honest error is also an actionable one.
6
- *
7
- * Substring matching alone is not enough: the canonical case is
8
- * `SerialNo` → `SerialNumber`, and "serialno" is NOT a substring of
9
- * "serialnumber" (…n-o… vs …n-u…) nor within any sane edit-distance
10
- * tolerance (5 edits). The longest-shared-prefix pass is what makes that
11
- * documented case actually produce a suggestion.
12
- */
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.nearest = void 0;
15
- function editDistance(a, b) {
16
- const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
17
- const cur = new Array(b.length + 1);
18
- for (let i = 1; i <= a.length; i++) {
19
- cur[0] = i;
20
- for (let j = 1; j <= b.length; j++) {
21
- cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
22
- }
23
- prev.splice(0, prev.length, ...cur);
24
- }
25
- return prev[b.length];
26
- }
27
- function nearest(candidates, wanted) {
28
- const w = wanted.toLowerCase().trim();
29
- if (!w)
30
- return undefined;
31
- const lower = candidates.map((c) => c.toLowerCase());
32
- const exact = lower.indexOf(w);
33
- if (exact >= 0)
34
- return candidates[exact];
35
- for (let i = 0; i < lower.length; i++) {
36
- if (lower[i].startsWith(w) || w.startsWith(lower[i]))
37
- return candidates[i];
38
- }
39
- for (let i = 0; i < lower.length; i++) {
40
- if (lower[i].includes(w) || w.includes(lower[i]))
41
- return candidates[i];
42
- }
43
- let prefixBest;
44
- let prefixLen = 0;
45
- for (let i = 0; i < lower.length; i++) {
46
- let n = 0;
47
- while (n < w.length && n < lower[i].length && w[n] === lower[i][n])
48
- n++;
49
- if (n > prefixLen) {
50
- prefixLen = n;
51
- prefixBest = candidates[i];
52
- }
53
- }
54
- if (prefixBest && prefixLen >= Math.max(4, Math.ceil(w.length / 2))) {
55
- return prefixBest;
56
- }
57
- let best;
58
- let bestScore = Infinity;
59
- const tolerance = Math.max(2, Math.floor(w.length / 3));
60
- for (let i = 0; i < lower.length; i++) {
61
- const d = editDistance(w, lower[i]);
62
- if (d < bestScore) {
63
- bestScore = d;
64
- best = candidates[i];
65
- }
66
- }
67
- return bestScore <= tolerance ? best : undefined;
68
- }
69
- exports.nearest = nearest;
1
+ "use strict";
2
+ /**
3
+ * Nearest-candidate matching for "did you mean…" suggestions on validation
4
+ * errors — an unknown field or dropdown value is rejected WITH the closest
5
+ * real name, so an honest error is also an actionable one.
6
+ *
7
+ * Substring matching alone is not enough: the canonical case is
8
+ * `SerialNo` → `SerialNumber`, and "serialno" is NOT a substring of
9
+ * "serialnumber" (…n-o… vs …n-u…) nor within any sane edit-distance
10
+ * tolerance (5 edits). The longest-shared-prefix pass is what makes that
11
+ * documented case actually produce a suggestion.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.nearest = void 0;
15
+ function editDistance(a, b) {
16
+ const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
17
+ const cur = new Array(b.length + 1);
18
+ for (let i = 1; i <= a.length; i++) {
19
+ cur[0] = i;
20
+ for (let j = 1; j <= b.length; j++) {
21
+ cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
22
+ }
23
+ prev.splice(0, prev.length, ...cur);
24
+ }
25
+ return prev[b.length];
26
+ }
27
+ function nearest(candidates, wanted) {
28
+ const w = wanted.toLowerCase().trim();
29
+ if (!w)
30
+ return undefined;
31
+ const lower = candidates.map((c) => c.toLowerCase());
32
+ const exact = lower.indexOf(w);
33
+ if (exact >= 0)
34
+ return candidates[exact];
35
+ for (let i = 0; i < lower.length; i++) {
36
+ if (lower[i].startsWith(w) || w.startsWith(lower[i]))
37
+ return candidates[i];
38
+ }
39
+ for (let i = 0; i < lower.length; i++) {
40
+ if (lower[i].includes(w) || w.includes(lower[i]))
41
+ return candidates[i];
42
+ }
43
+ let prefixBest;
44
+ let prefixLen = 0;
45
+ for (let i = 0; i < lower.length; i++) {
46
+ let n = 0;
47
+ while (n < w.length && n < lower[i].length && w[n] === lower[i][n])
48
+ n++;
49
+ if (n > prefixLen) {
50
+ prefixLen = n;
51
+ prefixBest = candidates[i];
52
+ }
53
+ }
54
+ if (prefixBest && prefixLen >= Math.max(4, Math.ceil(w.length / 2))) {
55
+ return prefixBest;
56
+ }
57
+ let best;
58
+ let bestScore = Infinity;
59
+ const tolerance = Math.max(2, Math.floor(w.length / 3));
60
+ for (let i = 0; i < lower.length; i++) {
61
+ const d = editDistance(w, lower[i]);
62
+ if (d < bestScore) {
63
+ bestScore = d;
64
+ best = candidates[i];
65
+ }
66
+ }
67
+ return bestScore <= tolerance ? best : undefined;
68
+ }
69
+ exports.nearest = nearest;
70
70
  //# sourceMappingURL=suggest.js.map
package/dist/types.d.ts CHANGED
@@ -1,111 +1,111 @@
1
- import { FieldDataType, SemanticQueryEntityType } from '@spotto/contract';
2
- /**
3
- * What an organisation's catalogue looks like to this package.
4
- *
5
- * These are NOT wire shapes — the wire contract lives in `@spotto/contract`.
6
- * This is the vocabulary a query is resolved AGAINST: which custom fields
7
- * exist, what type each one is, and (for the evaluator) the type documents
8
- * whose values an asset inherits.
9
- */
10
- export interface SemanticFieldDef {
11
- /** The field's id — custom-field matching is by `_id`, not name. */
12
- id: string;
13
- name: string;
14
- dataType: FieldDataType;
15
- /** Dropdown options — an eq value must match one exactly or the query silently returns nothing. */
16
- options?: string[];
17
- }
18
- /** A resolved type-level field value, as materialised in `typeFieldValuesAll`. */
19
- export interface SemanticTypeFieldValue {
20
- _id?: string;
21
- name?: string;
22
- valueString?: string;
23
- valueInteger?: number;
24
- valueDecimal?: number;
25
- valueBoolean?: boolean;
26
- valueDate?: number;
27
- }
28
- export interface SemanticTypeDef {
29
- id: string;
30
- /** Pipe-delimited, pipe-terminated. Root type is "". */
31
- path: string;
32
- /** Inheritance already resolved by the platform. */
33
- typeFieldValuesAll: SemanticTypeFieldValue[];
34
- }
35
- /**
36
- * A NAMED record a condition can point at by name instead of by id.
37
- *
38
- * This is how the event vocabulary escapes the producer gap without repeating
39
- * its mistake. An id cannot be asked of a model — it would be invented, and an
40
- * invented id runs and matches nothing. A NAME can be asked for, but only if
41
- * it is resolved against real records and an unresolvable or ambiguous one
42
- * FAILS: the moment resolution silently picks a candidate, or falls back to a
43
- * regex, it becomes the same silent-wrong-rows problem wearing a friendlier
44
- * face.
45
- *
46
- * Safe here and not for assets purely because of cardinality. Users, readers
47
- * and actions are small named catalogues that fit in a prompt and resolve
48
- * unambiguously; assets number in the thousands and share name stems
49
- * ("BC-A1" is a prefix of "BC-A10").
50
- */
51
- export interface SemanticNamedRef {
52
- id: string;
53
- name: string;
54
- /** Shown to a user in a suggestion when the name does not resolve. */
55
- label?: string;
56
- }
57
- /**
58
- * What VALIDATION needs: field definitions, plus the named catalogues the
59
- * event vocabulary resolves against. Empty catalogues are legitimate — a
60
- * caller that never validates event conditions supplies none, and one that
61
- * does gets an honest "no one called that" rather than a match on nothing.
62
- */
63
- export interface SemanticFieldCatalogue {
64
- fields: SemanticFieldDef[];
65
- /** Organisation users — resolves `{type:'user', name}`. */
66
- users?: SemanticNamedRef[];
67
- /** Readers — resolves `{type:'reader', name}`. */
68
- readers?: SemanticNamedRef[];
69
- /** Form actions — resolves `{type:'action', name}`. */
70
- actions?: SemanticNamedRef[];
71
- }
72
- /**
73
- * What EVALUATION needs: the catalogue plus types, because matching a
74
- * type-level field value in memory means walking the asset's type document.
75
- * (The Mongo compiler gets the same values through a `$lookup` instead.)
76
- */
77
- export interface SemanticAccountSchema extends SemanticFieldCatalogue {
78
- types: SemanticTypeDef[];
79
- }
80
- export interface SemanticValidationIssue {
81
- path: string;
82
- code: string;
83
- message: string;
84
- suggestion?: string;
85
- }
86
- export declare class SemanticQueryValidationError extends Error {
87
- issues: SemanticValidationIssue[];
88
- constructor(issues: SemanticValidationIssue[]);
89
- }
90
- /**
91
- * Throw one validation issue — fail-fast, this package's contract (the issues
92
- * array shape exists for the wire; internally the FIRST problem is the
93
- * answer). One helper beside the error class it throws, so issue construction
94
- * cannot drift between layers.
95
- */
96
- export declare function failSemanticValidation(path: string, code: string, message: string, suggestion?: string): never;
97
- export interface SemanticCompileOptions {
98
- /**
99
- * Explicit — never sampled deeper than the entry point, so a run is
100
- * reproducible: the same query, catalogue, `now` and timezone always give
101
- * the same answer, whoever is asking.
102
- */
103
- now?: Date;
104
- /** IANA zone for resolving relative dates. */
105
- timeZone?: string;
106
- /**
107
- * Which entity's vocabulary applies. Defaults to `asset` — the only entity
108
- * that executes today, and what every existing caller means.
109
- */
110
- entityType?: SemanticQueryEntityType;
111
- }
1
+ import { FieldDataType, SemanticQueryEntityType } from '@spotto/contract';
2
+ /**
3
+ * What an organisation's catalogue looks like to this package.
4
+ *
5
+ * These are NOT wire shapes — the wire contract lives in `@spotto/contract`.
6
+ * This is the vocabulary a query is resolved AGAINST: which custom fields
7
+ * exist, what type each one is, and (for the evaluator) the type documents
8
+ * whose values an asset inherits.
9
+ */
10
+ export interface SemanticFieldDef {
11
+ /** The field's id — custom-field matching is by `_id`, not name. */
12
+ id: string;
13
+ name: string;
14
+ dataType: FieldDataType;
15
+ /** Dropdown options — an eq value must match one exactly or the query silently returns nothing. */
16
+ options?: string[];
17
+ }
18
+ /** A resolved type-level field value, as materialised in `typeFieldValuesAll`. */
19
+ export interface SemanticTypeFieldValue {
20
+ _id?: string;
21
+ name?: string;
22
+ valueString?: string;
23
+ valueInteger?: number;
24
+ valueDecimal?: number;
25
+ valueBoolean?: boolean;
26
+ valueDate?: number;
27
+ }
28
+ export interface SemanticTypeDef {
29
+ id: string;
30
+ /** Pipe-delimited, pipe-terminated. Root type is "". */
31
+ path: string;
32
+ /** Inheritance already resolved by the platform. */
33
+ typeFieldValuesAll: SemanticTypeFieldValue[];
34
+ }
35
+ /**
36
+ * A NAMED record a condition can point at by name instead of by id.
37
+ *
38
+ * This is how the event vocabulary escapes the producer gap without repeating
39
+ * its mistake. An id cannot be asked of a model — it would be invented, and an
40
+ * invented id runs and matches nothing. A NAME can be asked for, but only if
41
+ * it is resolved against real records and an unresolvable or ambiguous one
42
+ * FAILS: the moment resolution silently picks a candidate, or falls back to a
43
+ * regex, it becomes the same silent-wrong-rows problem wearing a friendlier
44
+ * face.
45
+ *
46
+ * Safe here and not for assets purely because of cardinality. Users, readers
47
+ * and actions are small named catalogues that fit in a prompt and resolve
48
+ * unambiguously; assets number in the thousands and share name stems
49
+ * ("BC-A1" is a prefix of "BC-A10").
50
+ */
51
+ export interface SemanticNamedRef {
52
+ id: string;
53
+ name: string;
54
+ /** Shown to a user in a suggestion when the name does not resolve. */
55
+ label?: string;
56
+ }
57
+ /**
58
+ * What VALIDATION needs: field definitions, plus the named catalogues the
59
+ * event vocabulary resolves against. Empty catalogues are legitimate — a
60
+ * caller that never validates event conditions supplies none, and one that
61
+ * does gets an honest "no one called that" rather than a match on nothing.
62
+ */
63
+ export interface SemanticFieldCatalogue {
64
+ fields: SemanticFieldDef[];
65
+ /** Organisation users — resolves `{type:'user', name}`. */
66
+ users?: SemanticNamedRef[];
67
+ /** Readers — resolves `{type:'reader', name}`. */
68
+ readers?: SemanticNamedRef[];
69
+ /** Form actions — resolves `{type:'action', name}`. */
70
+ actions?: SemanticNamedRef[];
71
+ }
72
+ /**
73
+ * What EVALUATION needs: the catalogue plus types, because matching a
74
+ * type-level field value in memory means walking the asset's type document.
75
+ * (The Mongo compiler gets the same values through a `$lookup` instead.)
76
+ */
77
+ export interface SemanticAccountSchema extends SemanticFieldCatalogue {
78
+ types: SemanticTypeDef[];
79
+ }
80
+ export interface SemanticValidationIssue {
81
+ path: string;
82
+ code: string;
83
+ message: string;
84
+ suggestion?: string;
85
+ }
86
+ export declare class SemanticQueryValidationError extends Error {
87
+ issues: SemanticValidationIssue[];
88
+ constructor(issues: SemanticValidationIssue[]);
89
+ }
90
+ /**
91
+ * Throw one validation issue — fail-fast, this package's contract (the issues
92
+ * array shape exists for the wire; internally the FIRST problem is the
93
+ * answer). One helper beside the error class it throws, so issue construction
94
+ * cannot drift between layers.
95
+ */
96
+ export declare function failSemanticValidation(path: string, code: string, message: string, suggestion?: string): never;
97
+ export interface SemanticCompileOptions {
98
+ /**
99
+ * Explicit — never sampled deeper than the entry point, so a run is
100
+ * reproducible: the same query, catalogue, `now` and timezone always give
101
+ * the same answer, whoever is asking.
102
+ */
103
+ now?: Date;
104
+ /** IANA zone for resolving relative dates. */
105
+ timeZone?: string;
106
+ /**
107
+ * Which entity's vocabulary applies. Defaults to `asset` — the only entity
108
+ * that executes today, and what every existing caller means.
109
+ */
110
+ entityType?: SemanticQueryEntityType;
111
+ }
package/dist/types.js CHANGED
@@ -1,24 +1,24 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.failSemanticValidation = exports.SemanticQueryValidationError = void 0;
4
- class SemanticQueryValidationError extends Error {
5
- constructor(issues) {
6
- super(issues.map((i) => i.message).join('; '));
7
- this.issues = issues;
8
- this.name = 'SemanticQueryValidationError';
9
- }
10
- }
11
- exports.SemanticQueryValidationError = SemanticQueryValidationError;
12
- /**
13
- * Throw one validation issue — fail-fast, this package's contract (the issues
14
- * array shape exists for the wire; internally the FIRST problem is the
15
- * answer). One helper beside the error class it throws, so issue construction
16
- * cannot drift between layers.
17
- */
18
- function failSemanticValidation(path, code, message, suggestion) {
19
- throw new SemanticQueryValidationError([
20
- suggestion ? { path, code, message, suggestion } : { path, code, message },
21
- ]);
22
- }
23
- exports.failSemanticValidation = failSemanticValidation;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.failSemanticValidation = exports.SemanticQueryValidationError = void 0;
4
+ class SemanticQueryValidationError extends Error {
5
+ constructor(issues) {
6
+ super(issues.map((i) => i.message).join('; '));
7
+ this.issues = issues;
8
+ this.name = 'SemanticQueryValidationError';
9
+ }
10
+ }
11
+ exports.SemanticQueryValidationError = SemanticQueryValidationError;
12
+ /**
13
+ * Throw one validation issue — fail-fast, this package's contract (the issues
14
+ * array shape exists for the wire; internally the FIRST problem is the
15
+ * answer). One helper beside the error class it throws, so issue construction
16
+ * cannot drift between layers.
17
+ */
18
+ function failSemanticValidation(path, code, message, suggestion) {
19
+ throw new SemanticQueryValidationError([
20
+ suggestion ? { path, code, message, suggestion } : { path, code, message },
21
+ ]);
22
+ }
23
+ exports.failSemanticValidation = failSemanticValidation;
24
24
  //# sourceMappingURL=types.js.map