@davesheffer/hunch 1.32.8 → 1.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/cli/index.js +2 -0
- package/dist/cli/serve.js +28 -2
- package/dist/cli/state.d.ts +3 -0
- package/dist/cli/state.js +150 -0
- package/dist/client/state.d.ts +82 -14
- package/dist/client/state.js +16 -2
- package/dist/client/stateProof.d.ts +4 -0
- package/dist/client/stateProof.js +17 -0
- package/dist/constitution/behaviorEvaluator.js +1 -1
- package/dist/constitution/schema.d.ts +2 -2
- package/dist/core/automaticReviewMemory.d.ts +5 -0
- package/dist/core/conventionDelivery.d.ts +8 -0
- package/dist/core/conventionDelivery.js +52 -0
- package/dist/core/fieldProvenance.d.ts +8 -0
- package/dist/core/fieldProvenance.js +72 -0
- package/dist/core/recordVisibility.d.ts +9 -0
- package/dist/core/recordVisibility.js +25 -0
- package/dist/core/stateCanonical.d.ts +3 -0
- package/dist/core/stateCanonical.js +34 -0
- package/dist/core/stateContract.d.ts +122 -7
- package/dist/core/stateContract.js +26 -31
- package/dist/core/stateDelivery.d.ts +3 -3
- package/dist/core/stateDelivery.js +10 -1
- package/dist/core/stateHttp.d.ts +280 -0
- package/dist/core/stateHttp.js +17 -0
- package/dist/core/stateProof.d.ts +13 -0
- package/dist/core/stateProof.js +34 -0
- package/dist/core/stateRecords.d.ts +127 -0
- package/dist/core/stateRecords.js +48 -0
- package/dist/core/types.d.ts +146 -4
- package/dist/core/types.js +8 -2
- package/dist/extractors/git.js +3 -10
- package/dist/mcp/server.js +10 -4
- package/dist/serve/app.d.ts +2 -0
- package/dist/serve/app.js +71 -30
- package/dist/serve/config.d.ts +16 -0
- package/dist/serve/config.js +27 -7
- package/dist/serve/operator.d.ts +4 -0
- package/dist/serve/operator.js +223 -0
- package/dist/serve/stateProof.d.ts +15 -0
- package/dist/serve/stateProof.js +105 -0
- package/dist/store/changeLedger.d.ts +6 -0
- package/dist/store/hunchStore.d.ts +4 -2
- package/dist/store/hunchStore.js +18 -19
- package/dist/store/stateAccess.d.ts +13 -0
- package/dist/store/stateAccess.js +85 -0
- package/dist/store/stateBinding.d.ts +13 -18
- package/dist/store/stateBinding.js +161 -52
- package/dist/store/stateCapture.js +10 -2
- package/dist/store/stateError.d.ts +12 -0
- package/dist/store/stateError.js +12 -0
- package/dist/store/statePartition.d.ts +9 -0
- package/dist/store/statePartition.js +30 -0
- package/package.json +5 -1
- package/server.json +2 -2
package/dist/store/hunchStore.js
CHANGED
|
@@ -518,20 +518,20 @@ export class HunchStore {
|
|
|
518
518
|
* relevance ordering (liveness/provenance/recency + topic-chain promotion)
|
|
519
519
|
* go through hybridSearch/searchScoped, where rerankByPriors applies.
|
|
520
520
|
* Falls back to LIKE if the query has no FTS-tokenizable terms. */
|
|
521
|
-
search(query, limit = 12) {
|
|
521
|
+
search(query, limit = 12, allowedIds) {
|
|
522
522
|
const match = toFtsQuery(query);
|
|
523
523
|
// No FTS-tokenizable terms (e.g. a CJK-only query) — degrade to LIKE rather
|
|
524
524
|
// than silently returning nothing (the documented fallback).
|
|
525
525
|
if (!match)
|
|
526
|
-
return this.likeSearch(query, limit);
|
|
526
|
+
return this.likeSearch(query, limit, undefined, allowedIds);
|
|
527
527
|
try {
|
|
528
528
|
const rows = this.db.prepare(`SELECT ref, kind, title, snippet(search, 3, '[', ']', '…', 12) AS snip, bm25(search) AS score
|
|
529
|
-
FROM search WHERE search MATCH ? ORDER BY score LIMIT ?`).all(match, limit);
|
|
529
|
+
FROM search WHERE search MATCH ? ${allowedIds ? 'AND ref IN (SELECT value FROM json_each(?))' : ''} ORDER BY score LIMIT ?`).all(...(allowedIds ? [match, JSON.stringify(allowedIds), limit] : [match, limit]));
|
|
530
530
|
return this.demoteHistoricalState(rows.map((r) => ({ ref: r.ref, kind: r.kind, title: r.title, snippet: r.snip, score: r.score })));
|
|
531
531
|
}
|
|
532
532
|
catch {
|
|
533
533
|
// Malformed FTS expression — degrade to a LIKE scan over titles/bodies.
|
|
534
|
-
return this.likeSearch(query, limit);
|
|
534
|
+
return this.likeSearch(query, limit, undefined, allowedIds);
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
537
|
/** State-of-record ordering for nuryel.state/1 hits (superseded derived, done/cancelled
|
|
@@ -635,7 +635,7 @@ export class HunchStore {
|
|
|
635
635
|
* `hunchrecorddecision` and matched nothing — on precisely the runtimes with no FTS5,
|
|
636
636
|
* where this fallback is the only search there is. Escaping keeps the term literal;
|
|
637
637
|
* leaving `_` unescaped would silently over-match instead. */
|
|
638
|
-
likeSearch(query, limit, kind) {
|
|
638
|
+
likeSearch(query, limit, kind, allowedIds) {
|
|
639
639
|
const terms = (query.toLowerCase().match(/[\p{L}\p{N}_]+/gu)
|
|
640
640
|
?? [query.toLowerCase().trim()].filter(Boolean)).slice(0, 32);
|
|
641
641
|
if (!terms.length)
|
|
@@ -645,8 +645,7 @@ export class HunchStore {
|
|
|
645
645
|
const like = `%${term.replace(/[\\%_]/g, "\\$&")}%`;
|
|
646
646
|
return [like, like];
|
|
647
647
|
});
|
|
648
|
-
const where = kind ? `kind = ? AND (${predicates})` : `(${predicates})
|
|
649
|
-
const params = kind ? [kind, ...likes, limit] : [...likes, limit];
|
|
648
|
+
const where = (kind ? `kind = ? AND (${predicates})` : `(${predicates})`) + (allowedIds ? " AND ref IN (SELECT value FROM json_each(?))" : "");
|
|
650
649
|
// Ordered so a TRUNCATING limit drops the least relevant row rather than an
|
|
651
650
|
// arbitrary one: a title hit outranks a body-only hit, then shortest title
|
|
652
651
|
// (a constraint's one-line statement beats a long decision body that merely
|
|
@@ -657,7 +656,7 @@ export class HunchStore {
|
|
|
657
656
|
const rows = this.db.prepare(`SELECT ref, kind, title, substr(body,1,120) AS snip FROM search
|
|
658
657
|
WHERE ${where}
|
|
659
658
|
ORDER BY CASE WHEN ${titleLikes} THEN 0 ELSE 1 END, length(title), ref
|
|
660
|
-
LIMIT ?`).all(...(kind ? [kind, ...likes, ...
|
|
659
|
+
LIMIT ?`).all(...[...(kind ? [kind] : []), ...likes, ...(allowedIds ? [JSON.stringify(allowedIds)] : []), ...titleParams, limit]);
|
|
661
660
|
return this.demoteHistoricalState(rows.map((r) => ({ ref: r.ref, kind: r.kind, title: r.title, snippet: r.snip, score: 0 })));
|
|
662
661
|
}
|
|
663
662
|
// ---- semantic search (opt-in embeddings) --------------------------------
|
|
@@ -1174,11 +1173,11 @@ export class HunchStore {
|
|
|
1174
1173
|
* history-inclusive view (backward-compatible default). */
|
|
1175
1174
|
why(target, opts = {}) {
|
|
1176
1175
|
target = toPosixTarget(target);
|
|
1177
|
-
const decisions = this.recs("decisions");
|
|
1178
|
-
const bugs = this.recs("bugs");
|
|
1179
|
-
const constraints = this.recs("constraints");
|
|
1180
|
-
const symbols = this.recs("symbols");
|
|
1181
|
-
const components = this.recs("components");
|
|
1176
|
+
const decisions = this.recs("decisions").filter(opts.canRead ?? (() => true));
|
|
1177
|
+
const bugs = this.recs("bugs").filter(opts.canRead ?? (() => true));
|
|
1178
|
+
const constraints = this.recs("constraints").filter(opts.canRead ?? (() => true));
|
|
1179
|
+
const symbols = this.recs("symbols").filter(opts.canRead ?? (() => true));
|
|
1180
|
+
const components = this.recs("components").filter(opts.canRead ?? (() => true));
|
|
1182
1181
|
const asOf = opts.asOf;
|
|
1183
1182
|
// pathsRelated, not bare endsWith: "scenario.ts".endsWith("io.ts") is true,
|
|
1184
1183
|
// so an unanchored suffix pulled unrelated files' records into why()/the
|
|
@@ -1801,13 +1800,13 @@ export class HunchStore {
|
|
|
1801
1800
|
return out;
|
|
1802
1801
|
}
|
|
1803
1802
|
/** Bugs matching a symptom (FTS over bugs) or a symbol, with lineage (hunch_bug_lineage). */
|
|
1804
|
-
bugLineage(symptomOrSymbol) {
|
|
1805
|
-
const bugs = this.recs("bugs");
|
|
1803
|
+
bugLineage(symptomOrSymbol, canRead) {
|
|
1804
|
+
const bugs = this.recs("bugs").filter(canRead ?? (() => true));
|
|
1806
1805
|
const direct = bugs.filter((b) => b.affected_symbols.includes(symptomOrSymbol) || b.affected_files.includes(symptomOrSymbol));
|
|
1807
1806
|
if (direct.length)
|
|
1808
1807
|
return direct;
|
|
1809
1808
|
// fall back to fts over bug titles/symptoms
|
|
1810
|
-
const hits = this.search(symptomOrSymbol).filter((h) => h.kind === "bugs").map((h) => h.ref);
|
|
1809
|
+
const hits = this.search(symptomOrSymbol, 12, canRead ? bugs.map(b => b.id) : undefined).filter((h) => h.kind === "bugs").map((h) => h.ref);
|
|
1811
1810
|
const byHit = bugs.filter((b) => hits.includes(b.id));
|
|
1812
1811
|
if (byHit.length)
|
|
1813
1812
|
return byHit;
|
|
@@ -1905,7 +1904,7 @@ export class HunchStore {
|
|
|
1905
1904
|
blast.set(d.id, d); // keep the MIN depth across start symbols
|
|
1906
1905
|
}
|
|
1907
1906
|
}
|
|
1908
|
-
const bugs = w.bugs.length ? w.bugs : this.bugLineage(target);
|
|
1907
|
+
const bugs = w.bugs.length ? w.bugs : this.bugLineage(target, opts.canRead);
|
|
1909
1908
|
const ctx = {
|
|
1910
1909
|
target,
|
|
1911
1910
|
constraints: w.constraints.sort((a, b) => sev(b.severity) - sev(a.severity)),
|
|
@@ -1913,13 +1912,13 @@ export class HunchStore {
|
|
|
1913
1912
|
bugs,
|
|
1914
1913
|
blast_radius: [...blast.values()].sort((a, b) => a.depth - b.depth).slice(0, 12),
|
|
1915
1914
|
components: w.components,
|
|
1916
|
-
findings: this.liveFindingsFor(target).slice(0, 8),
|
|
1915
|
+
findings: this.liveFindingsFor(target).filter(opts.canRead ?? (() => true)).slice(0, 8),
|
|
1917
1916
|
// Landscape records do not yet carry a valid-time window. A historical
|
|
1918
1917
|
// query therefore withholds them instead of mixing current graph state
|
|
1919
1918
|
// into an as-of memory envelope.
|
|
1920
1919
|
landscape: opts.asOf
|
|
1921
1920
|
? undefined
|
|
1922
|
-
: selectReviewedLandscape(this.recs("resources"), this.recs("edges"), target),
|
|
1921
|
+
: selectReviewedLandscape(this.recs("resources").filter(opts.canRead ?? (() => true)), this.recs("edges").filter(opts.canRead ?? (() => true)), target),
|
|
1923
1922
|
budget_tokens: budget,
|
|
1924
1923
|
};
|
|
1925
1924
|
return ctx;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** A request-local access view. Never installs mutable filters on shared stores. */
|
|
2
|
+
import type { HunchStore } from './hunchStore.js';
|
|
3
|
+
import { type Principal } from '../core/stateContract.js';
|
|
4
|
+
export interface StateAccessOptions {
|
|
5
|
+
additionalStores?: readonly HunchStore[];
|
|
6
|
+
requireVisibility?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function createStateAccess(store: HunchStore, principal: Principal, opts?: StateAccessOptions): {
|
|
9
|
+
restricted: boolean;
|
|
10
|
+
canRead: (record: unknown) => boolean;
|
|
11
|
+
referencesVisible: (root: unknown) => boolean;
|
|
12
|
+
canWrite: (record: unknown) => boolean;
|
|
13
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { STATE_FACETS, scopePath } from '../core/stateContract.js';
|
|
2
|
+
import { visibilityAllows } from '../core/recordVisibility.js';
|
|
3
|
+
import { recordScope, partitionOf, partitionDeclarationOf } from './statePartition.js';
|
|
4
|
+
export function createStateAccess(store, principal, opts = {}) {
|
|
5
|
+
const repo = partitionOf(store), grants = new Set(principal.grants.map(scopePath));
|
|
6
|
+
const sources = [...new Set([store, ...(opts.additionalStores ?? [])])].map(source => ({ source, scope: partitionDeclarationOf(source) }));
|
|
7
|
+
// Protected writers persist this gate before the first restricted record and never remove it.
|
|
8
|
+
const restricted = !!opts.requireVisibility || sources.some(source => !!source.scope.required_capabilities?.length);
|
|
9
|
+
const recordScopes = new WeakMap();
|
|
10
|
+
const scoped = (record) => recordScopes.get(record) ?? recordScope(record, repo);
|
|
11
|
+
const baseAllows = (record, mode = 'read') => grants.has(scopePath(scoped(record))) && visibilityAllows(record, principal.id, mode);
|
|
12
|
+
const lookup = new Map();
|
|
13
|
+
function find(id) {
|
|
14
|
+
const cached = lookup.get(id);
|
|
15
|
+
if (cached)
|
|
16
|
+
return cached;
|
|
17
|
+
const found = [];
|
|
18
|
+
for (const { source, scope } of sources)
|
|
19
|
+
for (const facet of STATE_FACETS) {
|
|
20
|
+
let record;
|
|
21
|
+
// Exact capture/replay must not enumerate a high-cardinality collection. Its
|
|
22
|
+
// schemas require these prefixes; other strings cannot identify these records.
|
|
23
|
+
if (facet === 'derived' || facet === 'receipts' || facet === 'commitments') {
|
|
24
|
+
const prefix = { derived: 'nds', receipts: 'nrc', commitments: 'ncm' }[facet];
|
|
25
|
+
if (!new RegExp(`^${prefix}_[a-f0-9]{24}$`).test(id))
|
|
26
|
+
continue;
|
|
27
|
+
record = source.getStateDirect(facet, id, 'private') ?? source.getStateDirect(facet, id, 'public');
|
|
28
|
+
}
|
|
29
|
+
else
|
|
30
|
+
record = source.getRec(facet, id);
|
|
31
|
+
if (record) {
|
|
32
|
+
const value = record;
|
|
33
|
+
recordScopes.set(value, recordScope(value, scope));
|
|
34
|
+
found.push(value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
lookup.set(id, found);
|
|
38
|
+
return found;
|
|
39
|
+
}
|
|
40
|
+
// Walk only the reachable dependency graph, iteratively so cycles and deep chains
|
|
41
|
+
// cannot overflow the stack. Complete records are withheld, never hash-preserving redactions.
|
|
42
|
+
function referencesVisible(root) {
|
|
43
|
+
const queue = [root], visited = new Set();
|
|
44
|
+
for (let i = 0; i < queue.length; i++) {
|
|
45
|
+
const record = queue[i];
|
|
46
|
+
if (!record || typeof record !== 'object' || visited.has(record))
|
|
47
|
+
continue;
|
|
48
|
+
visited.add(record);
|
|
49
|
+
if (i > 0 && (!visibilityAllows(record, principal.id) || (restricted && !baseAllows(record))))
|
|
50
|
+
return false;
|
|
51
|
+
const own = scoped(record);
|
|
52
|
+
const values = [{ value: record }];
|
|
53
|
+
while (values.length) {
|
|
54
|
+
const { value, field } = values.pop();
|
|
55
|
+
if (field === 'visibility' || field === 'id')
|
|
56
|
+
continue;
|
|
57
|
+
if (typeof value === 'string') {
|
|
58
|
+
queue.push(...find(value));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (Array.isArray(value)) {
|
|
62
|
+
for (const child of value)
|
|
63
|
+
values.push({ value: child });
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (!value || typeof value !== 'object')
|
|
67
|
+
continue;
|
|
68
|
+
const ref = value;
|
|
69
|
+
if (ref.kind === 'record' && typeof ref.id === 'string') {
|
|
70
|
+
const scope = recordScope(ref, own), matches = find(ref.id).filter(candidate => scopePath(scoped(candidate)) === scopePath(scope));
|
|
71
|
+
if (restricted && (!grants.has(scopePath(scope)) || !matches.length))
|
|
72
|
+
return false;
|
|
73
|
+
queue.push(...matches);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
for (const [name, child] of Object.entries(ref))
|
|
77
|
+
values.push({ value: child, field: name });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
const canRead = (record) => !!record && baseAllows(record) && referencesVisible(record);
|
|
83
|
+
return { restricted, canRead, referencesVisible, canWrite: (record) => canRead(record) && baseAllows(record, 'write') };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=stateAccess.js.map
|
|
@@ -1,27 +1,16 @@
|
|
|
1
|
+
import { type StateAccessOptions } from "./stateAccess.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
import type { HunchStore } from "./hunchStore.js";
|
|
3
4
|
import { readLedger } from "./changeLedger.js";
|
|
4
5
|
import { type DeliveryEnvelope } from "../core/delivery.js";
|
|
5
6
|
import { STATE_CONTRACT_VERSION, type Scope, type ReadResponse, type WriteResult, type RecordsResponse } from "../core/stateContract.js";
|
|
6
7
|
/** A typed refusal. `code` is stable for bindings; `conflict` names the incumbent when one exists. */
|
|
7
|
-
export
|
|
8
|
-
readonly code: "outside-grants" | "unsupported" | "malformed" | "identity" | "conflict" | "no-partition-home" | "idempotency";
|
|
9
|
-
readonly conflict: {
|
|
10
|
-
incumbent_id: string;
|
|
11
|
-
reason: string;
|
|
12
|
-
} | null;
|
|
13
|
-
constructor(code: "outside-grants" | "unsupported" | "malformed" | "identity" | "conflict" | "no-partition-home" | "idempotency", message: string, conflict?: {
|
|
14
|
-
incumbent_id: string;
|
|
15
|
-
reason: string;
|
|
16
|
-
} | null);
|
|
17
|
-
}
|
|
8
|
+
export { StateRefusal } from "./stateError.js";
|
|
18
9
|
/** The partition this store IS. A served partition declares itself in `.hunch/partition.json`
|
|
19
10
|
* (`{ kind, id }`, committed with the store); a plain checkout is the repository partition
|
|
20
11
|
* named after its directory, sanitized to the contract's token grammar — stable per clone,
|
|
21
12
|
* discoverable through `capabilities`, and the scope every legacy record defaults to. */
|
|
22
|
-
export
|
|
23
|
-
/** @deprecated name kept for callers written before served partitions; same value as partitionOf. */
|
|
24
|
-
export declare const repositoryScope: typeof partitionOf;
|
|
13
|
+
export { partitionOf, repositoryScope } from "./statePartition.js";
|
|
25
14
|
export declare const SubscribeResponseSchema: z.ZodObject<{
|
|
26
15
|
schema: z.ZodLiteral<"nuryel.state.subscribe/1">;
|
|
27
16
|
scope: z.ZodObject<{
|
|
@@ -35,6 +24,11 @@ export declare const SubscribeResponseSchema: z.ZodObject<{
|
|
|
35
24
|
}, z.core.$strict>;
|
|
36
25
|
head_seq: z.ZodNumber;
|
|
37
26
|
events: z.ZodArray<z.ZodObject<{
|
|
27
|
+
visibility: z.ZodOptional<z.ZodObject<{
|
|
28
|
+
owner: z.ZodString;
|
|
29
|
+
readers: z.ZodArray<z.ZodString>;
|
|
30
|
+
writers: z.ZodArray<z.ZodString>;
|
|
31
|
+
}, z.core.$strict>>;
|
|
38
32
|
schema: z.ZodLiteral<"nuryel.state.subscribe/1">;
|
|
39
33
|
seq: z.ZodNumber;
|
|
40
34
|
at: z.ZodString;
|
|
@@ -57,6 +51,7 @@ export declare const SubscribeResponseSchema: z.ZodObject<{
|
|
|
57
51
|
derived: "derived";
|
|
58
52
|
entities: "entities";
|
|
59
53
|
relationships: "relationships";
|
|
54
|
+
conventions: "conventions";
|
|
60
55
|
}>;
|
|
61
56
|
record_id: z.ZodString;
|
|
62
57
|
record_hash: z.ZodString;
|
|
@@ -109,7 +104,7 @@ export declare function stateHomeFor(store: HunchStore, scope: Scope): {
|
|
|
109
104
|
/** read — the system-of-record answer for a subject, under the delivery envelope's receipt.
|
|
110
105
|
* Grants are the first predicate on every candidate; a matching record in a scope the
|
|
111
106
|
* principal lacks is NAMED in denied_scopes and never described. */
|
|
112
|
-
export declare function readState(store: HunchStore, input: unknown): {
|
|
107
|
+
export declare function readState(store: HunchStore, input: unknown, options?: StateAccessOptions): {
|
|
113
108
|
response: ReadResponse;
|
|
114
109
|
envelope: DeliveryEnvelope;
|
|
115
110
|
};
|
|
@@ -123,7 +118,7 @@ export declare function readState(store: HunchStore, input: unknown): {
|
|
|
123
118
|
* carries one delivery receipt per partition. Reusable by any host (HTTP today; MCP or CLI
|
|
124
119
|
* fronting several roots later). */
|
|
125
120
|
export declare function mergeReadResponses(primary: ReadResponse, others: readonly ReadResponse[], extraDenied?: readonly Scope[]): ReadResponse;
|
|
126
|
-
export interface WriteOptions {
|
|
121
|
+
export interface WriteOptions extends StateAccessOptions {
|
|
127
122
|
/** Internal batch owner rebuilds once in finally while holding the write lock. */
|
|
128
123
|
deferReindex?: boolean;
|
|
129
124
|
/** Internal cache scoped to one uninterrupted partition write lock. Never retained. */
|
|
@@ -139,7 +134,7 @@ export interface WriteOptions {
|
|
|
139
134
|
export declare function writeState(store: HunchStore, input: unknown, opts?: WriteOptions): WriteResult;
|
|
140
135
|
/** subscribe — the scope's ordered change stream after a cursor. Unfiltered, the events are
|
|
141
136
|
* contiguous and assertChangeSequence holds; filtered, `head_seq` is still the cursor. */
|
|
142
|
-
export declare function subscribeState(store: HunchStore, input: unknown): SubscribeResponse;
|
|
137
|
+
export declare function subscribeState(store: HunchStore, input: unknown, options?: StateAccessOptions): SubscribeResponse;
|
|
143
138
|
/** records — fetch by id, grants first. Every id is accounted for: found, denied (its scope is
|
|
144
139
|
* outside the grants — named, never described) or missing. */
|
|
145
|
-
export declare function recordsState(store: HunchStore, input: unknown): RecordsResponse;
|
|
140
|
+
export declare function recordsState(store: HunchStore, input: unknown, options?: StateAccessOptions): RecordsResponse;
|