@git-stunts/git-warp 10.1.1
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/LICENSE +201 -0
- package/NOTICE +16 -0
- package/README.md +480 -0
- package/SECURITY.md +30 -0
- package/bin/git-warp +24 -0
- package/bin/warp-graph.js +1574 -0
- package/index.d.ts +2366 -0
- package/index.js +180 -0
- package/package.json +129 -0
- package/scripts/install-git-warp.sh +258 -0
- package/scripts/uninstall-git-warp.sh +139 -0
- package/src/domain/WarpGraph.js +3157 -0
- package/src/domain/crdt/Dot.js +160 -0
- package/src/domain/crdt/LWW.js +154 -0
- package/src/domain/crdt/ORSet.js +371 -0
- package/src/domain/crdt/VersionVector.js +222 -0
- package/src/domain/entities/GraphNode.js +60 -0
- package/src/domain/errors/EmptyMessageError.js +47 -0
- package/src/domain/errors/ForkError.js +30 -0
- package/src/domain/errors/IndexError.js +23 -0
- package/src/domain/errors/OperationAbortedError.js +22 -0
- package/src/domain/errors/QueryError.js +39 -0
- package/src/domain/errors/SchemaUnsupportedError.js +17 -0
- package/src/domain/errors/ShardCorruptionError.js +56 -0
- package/src/domain/errors/ShardLoadError.js +57 -0
- package/src/domain/errors/ShardValidationError.js +61 -0
- package/src/domain/errors/StorageError.js +57 -0
- package/src/domain/errors/SyncError.js +30 -0
- package/src/domain/errors/TraversalError.js +23 -0
- package/src/domain/errors/WarpError.js +31 -0
- package/src/domain/errors/WormholeError.js +28 -0
- package/src/domain/errors/WriterError.js +39 -0
- package/src/domain/errors/index.js +21 -0
- package/src/domain/services/AnchorMessageCodec.js +99 -0
- package/src/domain/services/BitmapIndexBuilder.js +225 -0
- package/src/domain/services/BitmapIndexReader.js +435 -0
- package/src/domain/services/BoundaryTransitionRecord.js +463 -0
- package/src/domain/services/CheckpointMessageCodec.js +147 -0
- package/src/domain/services/CheckpointSerializerV5.js +281 -0
- package/src/domain/services/CheckpointService.js +384 -0
- package/src/domain/services/CommitDagTraversalService.js +156 -0
- package/src/domain/services/DagPathFinding.js +712 -0
- package/src/domain/services/DagTopology.js +239 -0
- package/src/domain/services/DagTraversal.js +245 -0
- package/src/domain/services/Frontier.js +108 -0
- package/src/domain/services/GCMetrics.js +101 -0
- package/src/domain/services/GCPolicy.js +122 -0
- package/src/domain/services/GitLogParser.js +205 -0
- package/src/domain/services/HealthCheckService.js +246 -0
- package/src/domain/services/HookInstaller.js +326 -0
- package/src/domain/services/HttpSyncServer.js +262 -0
- package/src/domain/services/IndexRebuildService.js +426 -0
- package/src/domain/services/IndexStalenessChecker.js +103 -0
- package/src/domain/services/JoinReducer.js +582 -0
- package/src/domain/services/KeyCodec.js +113 -0
- package/src/domain/services/LegacyAnchorDetector.js +67 -0
- package/src/domain/services/LogicalTraversal.js +351 -0
- package/src/domain/services/MessageCodecInternal.js +132 -0
- package/src/domain/services/MessageSchemaDetector.js +145 -0
- package/src/domain/services/MigrationService.js +55 -0
- package/src/domain/services/ObserverView.js +265 -0
- package/src/domain/services/PatchBuilderV2.js +669 -0
- package/src/domain/services/PatchMessageCodec.js +140 -0
- package/src/domain/services/ProvenanceIndex.js +337 -0
- package/src/domain/services/ProvenancePayload.js +242 -0
- package/src/domain/services/QueryBuilder.js +835 -0
- package/src/domain/services/StateDiff.js +300 -0
- package/src/domain/services/StateSerializerV5.js +156 -0
- package/src/domain/services/StreamingBitmapIndexBuilder.js +709 -0
- package/src/domain/services/SyncProtocol.js +593 -0
- package/src/domain/services/TemporalQuery.js +201 -0
- package/src/domain/services/TranslationCost.js +221 -0
- package/src/domain/services/TraversalService.js +8 -0
- package/src/domain/services/WarpMessageCodec.js +29 -0
- package/src/domain/services/WarpStateIndexBuilder.js +127 -0
- package/src/domain/services/WormholeService.js +353 -0
- package/src/domain/types/TickReceipt.js +285 -0
- package/src/domain/types/WarpTypes.js +209 -0
- package/src/domain/types/WarpTypesV2.js +200 -0
- package/src/domain/utils/CachedValue.js +140 -0
- package/src/domain/utils/EventId.js +89 -0
- package/src/domain/utils/LRUCache.js +112 -0
- package/src/domain/utils/MinHeap.js +114 -0
- package/src/domain/utils/RefLayout.js +280 -0
- package/src/domain/utils/WriterId.js +205 -0
- package/src/domain/utils/cancellation.js +33 -0
- package/src/domain/utils/canonicalStringify.js +42 -0
- package/src/domain/utils/defaultClock.js +20 -0
- package/src/domain/utils/defaultCodec.js +51 -0
- package/src/domain/utils/nullLogger.js +21 -0
- package/src/domain/utils/roaring.js +181 -0
- package/src/domain/utils/shardVersion.js +9 -0
- package/src/domain/warp/PatchSession.js +217 -0
- package/src/domain/warp/Writer.js +181 -0
- package/src/hooks/post-merge.sh +60 -0
- package/src/infrastructure/adapters/BunHttpAdapter.js +225 -0
- package/src/infrastructure/adapters/ClockAdapter.js +57 -0
- package/src/infrastructure/adapters/ConsoleLogger.js +150 -0
- package/src/infrastructure/adapters/DenoHttpAdapter.js +230 -0
- package/src/infrastructure/adapters/GitGraphAdapter.js +787 -0
- package/src/infrastructure/adapters/GlobalClockAdapter.js +5 -0
- package/src/infrastructure/adapters/NoOpLogger.js +62 -0
- package/src/infrastructure/adapters/NodeCryptoAdapter.js +32 -0
- package/src/infrastructure/adapters/NodeHttpAdapter.js +98 -0
- package/src/infrastructure/adapters/PerformanceClockAdapter.js +5 -0
- package/src/infrastructure/adapters/WebCryptoAdapter.js +121 -0
- package/src/infrastructure/codecs/CborCodec.js +384 -0
- package/src/ports/BlobPort.js +30 -0
- package/src/ports/ClockPort.js +25 -0
- package/src/ports/CodecPort.js +25 -0
- package/src/ports/CommitPort.js +114 -0
- package/src/ports/ConfigPort.js +31 -0
- package/src/ports/CryptoPort.js +38 -0
- package/src/ports/GraphPersistencePort.js +57 -0
- package/src/ports/HttpServerPort.js +25 -0
- package/src/ports/IndexStoragePort.js +39 -0
- package/src/ports/LoggerPort.js +68 -0
- package/src/ports/RefPort.js +51 -0
- package/src/ports/TreePort.js +51 -0
- package/src/visualization/index.js +26 -0
- package/src/visualization/layouts/converters.js +75 -0
- package/src/visualization/layouts/elkAdapter.js +86 -0
- package/src/visualization/layouts/elkLayout.js +95 -0
- package/src/visualization/layouts/index.js +29 -0
- package/src/visualization/renderers/ascii/box.js +16 -0
- package/src/visualization/renderers/ascii/check.js +271 -0
- package/src/visualization/renderers/ascii/colors.js +13 -0
- package/src/visualization/renderers/ascii/formatters.js +73 -0
- package/src/visualization/renderers/ascii/graph.js +344 -0
- package/src/visualization/renderers/ascii/history.js +335 -0
- package/src/visualization/renderers/ascii/index.js +14 -0
- package/src/visualization/renderers/ascii/info.js +245 -0
- package/src/visualization/renderers/ascii/materialize.js +255 -0
- package/src/visualization/renderers/ascii/path.js +240 -0
- package/src/visualization/renderers/ascii/progress.js +32 -0
- package/src/visualization/renderers/ascii/symbols.js +33 -0
- package/src/visualization/renderers/ascii/table.js +19 -0
- package/src/visualization/renderers/browser/index.js +1 -0
- package/src/visualization/renderers/svg/index.js +159 -0
- package/src/visualization/utils/ansi.js +14 -0
- package/src/visualization/utils/time.js +40 -0
- package/src/visualization/utils/truncate.js +40 -0
- package/src/visualization/utils/unicode.js +52 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a v5 checkpoint from v4 visible projection.
|
|
3
|
+
* This is the migration boundary.
|
|
4
|
+
*/
|
|
5
|
+
import { createEmptyStateV5 } from './JoinReducer.js';
|
|
6
|
+
import { orsetAdd } from '../crdt/ORSet.js';
|
|
7
|
+
import { createVersionVector, vvIncrement } from '../crdt/VersionVector.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Migrates a V4 visible-projection state to a V5 state with ORSet internals.
|
|
11
|
+
*
|
|
12
|
+
* Creates synthetic dots for each visible node and edge under the migration
|
|
13
|
+
* writer, rebuilds the ORSet structures, and copies only properties belonging
|
|
14
|
+
* to visible nodes (dropping dangling props from deleted nodes).
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} v4State - The V4 materialized state (visible projection)
|
|
17
|
+
* @param {Map<string, {value: boolean}>} v4State.nodeAlive - V4 node alive map
|
|
18
|
+
* @param {Map<string, {value: boolean}>} v4State.edgeAlive - V4 edge alive map
|
|
19
|
+
* @param {Map<string, *>} v4State.prop - V4 property map
|
|
20
|
+
* @param {string} migrationWriterId - Writer ID to use for synthetic dots
|
|
21
|
+
* @returns {import('./JoinReducer.js').WarpStateV5} The migrated V5 state
|
|
22
|
+
*/
|
|
23
|
+
export function migrateV4toV5(v4State, migrationWriterId) {
|
|
24
|
+
const v5State = createEmptyStateV5();
|
|
25
|
+
const vv = createVersionVector();
|
|
26
|
+
|
|
27
|
+
// For each visible node in v4, add to v5 OR-Set with synthetic dot
|
|
28
|
+
for (const [nodeId, reg] of v4State.nodeAlive) {
|
|
29
|
+
if (reg.value) {
|
|
30
|
+
const dot = vvIncrement(vv, migrationWriterId);
|
|
31
|
+
orsetAdd(v5State.nodeAlive, nodeId, dot);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Same for edges
|
|
36
|
+
for (const [edgeKey, reg] of v4State.edgeAlive) {
|
|
37
|
+
if (reg.value) {
|
|
38
|
+
const dot = vvIncrement(vv, migrationWriterId);
|
|
39
|
+
orsetAdd(v5State.edgeAlive, edgeKey, dot);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Only copy props for VISIBLE nodes (don't carry dangling props)
|
|
44
|
+
for (const [propKey, reg] of v4State.prop) {
|
|
45
|
+
const idx = propKey.indexOf('\0');
|
|
46
|
+
const nodeId = propKey.slice(0, idx);
|
|
47
|
+
const nodeReg = v4State.nodeAlive.get(nodeId);
|
|
48
|
+
if (nodeReg?.value) {
|
|
49
|
+
v5State.prop.set(propKey, reg);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
v5State.observedFrontier = vv;
|
|
54
|
+
return v5State;
|
|
55
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObserverView - Read-only filtered view of a materialized WarpGraph.
|
|
3
|
+
*
|
|
4
|
+
* Provides an observer that sees only nodes matching a glob pattern,
|
|
5
|
+
* with property visibility controlled by expose/redact lists.
|
|
6
|
+
* Edges are only visible when both endpoints pass the match filter.
|
|
7
|
+
*
|
|
8
|
+
* @module domain/services/ObserverView
|
|
9
|
+
* @see Paper IV, Section 3 -- Observers as resource-bounded functors
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import QueryBuilder from './QueryBuilder.js';
|
|
13
|
+
import LogicalTraversal from './LogicalTraversal.js';
|
|
14
|
+
import { orsetContains, orsetElements } from '../crdt/ORSet.js';
|
|
15
|
+
import { decodeEdgeKey } from './KeyCodec.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Tests whether a string matches a glob-style pattern.
|
|
19
|
+
*
|
|
20
|
+
* Supports `*` as a wildcard matching zero or more characters.
|
|
21
|
+
* A lone `*` matches everything.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} pattern - Glob pattern (e.g. 'user:*', '*:admin', '*')
|
|
24
|
+
* @param {string} str - The string to test
|
|
25
|
+
* @returns {boolean} True if the string matches the pattern
|
|
26
|
+
*/
|
|
27
|
+
function matchGlob(pattern, str) {
|
|
28
|
+
if (pattern === '*') {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (!pattern.includes('*')) {
|
|
32
|
+
return pattern === str;
|
|
33
|
+
}
|
|
34
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
35
|
+
const regex = new RegExp(`^${escaped.replace(/\*/g, '.*')}$`);
|
|
36
|
+
return regex.test(str);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Filters a properties Map based on expose and redact lists.
|
|
41
|
+
*
|
|
42
|
+
* - If `redact` contains a key, it is excluded (highest priority).
|
|
43
|
+
* - If `expose` is provided and non-empty, only keys in `expose` are included.
|
|
44
|
+
* - If `expose` is absent/empty, all non-redacted keys are included.
|
|
45
|
+
*
|
|
46
|
+
* @param {Map<string, *>} propsMap - The full properties Map
|
|
47
|
+
* @param {string[]|undefined} expose - Whitelist of property keys to include
|
|
48
|
+
* @param {string[]|undefined} redact - Blacklist of property keys to exclude
|
|
49
|
+
* @returns {Map<string, *>} Filtered properties Map
|
|
50
|
+
*/
|
|
51
|
+
function filterProps(propsMap, expose, redact) {
|
|
52
|
+
const redactSet = redact && redact.length > 0 ? new Set(redact) : null;
|
|
53
|
+
const exposeSet = expose && expose.length > 0 ? new Set(expose) : null;
|
|
54
|
+
|
|
55
|
+
const filtered = new Map();
|
|
56
|
+
for (const [key, value] of propsMap) {
|
|
57
|
+
// Redact takes precedence
|
|
58
|
+
if (redactSet && redactSet.has(key)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// If expose is specified, only include listed keys
|
|
62
|
+
if (exposeSet && !exposeSet.has(key)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
filtered.set(key, value);
|
|
66
|
+
}
|
|
67
|
+
return filtered;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Read-only observer view of a materialized WarpGraph state.
|
|
72
|
+
*
|
|
73
|
+
* Provides the same query/traverse API as WarpGraph, but filtered
|
|
74
|
+
* by observer configuration (match pattern, expose, redact).
|
|
75
|
+
*/
|
|
76
|
+
export default class ObserverView {
|
|
77
|
+
/**
|
|
78
|
+
* Creates a new ObserverView.
|
|
79
|
+
*
|
|
80
|
+
* @param {Object} options
|
|
81
|
+
* @param {string} options.name - Observer name
|
|
82
|
+
* @param {Object} options.config - Observer configuration
|
|
83
|
+
* @param {string} options.config.match - Glob pattern for visible nodes
|
|
84
|
+
* @param {string[]} [options.config.expose] - Property keys to include
|
|
85
|
+
* @param {string[]} [options.config.redact] - Property keys to exclude (takes precedence over expose)
|
|
86
|
+
* @param {import('../WarpGraph.js').default} options.graph - The source WarpGraph instance
|
|
87
|
+
*/
|
|
88
|
+
constructor({ name, config, graph }) {
|
|
89
|
+
/** @type {string} */
|
|
90
|
+
this._name = name;
|
|
91
|
+
|
|
92
|
+
/** @type {string} */
|
|
93
|
+
this._matchPattern = config.match;
|
|
94
|
+
|
|
95
|
+
/** @type {string[]|undefined} */
|
|
96
|
+
this._expose = config.expose;
|
|
97
|
+
|
|
98
|
+
/** @type {string[]|undefined} */
|
|
99
|
+
this._redact = config.redact;
|
|
100
|
+
|
|
101
|
+
/** @type {import('../WarpGraph.js').default} */
|
|
102
|
+
this._graph = graph;
|
|
103
|
+
|
|
104
|
+
/** @type {LogicalTraversal} */
|
|
105
|
+
this.traverse = new LogicalTraversal(this);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets the observer name.
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
get name() {
|
|
113
|
+
return this._name;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ===========================================================================
|
|
117
|
+
// Internal: State access (used by QueryBuilder and LogicalTraversal)
|
|
118
|
+
// ===========================================================================
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Materializes and returns the graph details, used internally by
|
|
122
|
+
* QueryBuilder and LogicalTraversal.
|
|
123
|
+
*
|
|
124
|
+
* Builds a filtered adjacency structure that only includes edges
|
|
125
|
+
* where both endpoints pass the match filter.
|
|
126
|
+
*
|
|
127
|
+
* @returns {Promise<{state: *, stateHash: string, adjacency: {outgoing: Map, incoming: Map}}>}
|
|
128
|
+
* @private
|
|
129
|
+
*/
|
|
130
|
+
async _materializeGraph() {
|
|
131
|
+
const materialized = await this._graph._materializeGraph();
|
|
132
|
+
const { state, stateHash } = materialized;
|
|
133
|
+
|
|
134
|
+
// Build filtered adjacency: only edges where both endpoints match
|
|
135
|
+
const outgoing = new Map();
|
|
136
|
+
const incoming = new Map();
|
|
137
|
+
|
|
138
|
+
for (const edgeKey of orsetElements(state.edgeAlive)) {
|
|
139
|
+
const { from, to, label } = decodeEdgeKey(edgeKey);
|
|
140
|
+
|
|
141
|
+
// Both endpoints must be alive
|
|
142
|
+
if (!orsetContains(state.nodeAlive, from) || !orsetContains(state.nodeAlive, to)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Both endpoints must match the observer pattern
|
|
147
|
+
if (!matchGlob(this._matchPattern, from) || !matchGlob(this._matchPattern, to)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!outgoing.has(from)) {
|
|
152
|
+
outgoing.set(from, []);
|
|
153
|
+
}
|
|
154
|
+
if (!incoming.has(to)) {
|
|
155
|
+
incoming.set(to, []);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
outgoing.get(from).push({ neighborId: to, label });
|
|
159
|
+
incoming.get(to).push({ neighborId: from, label });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const sortNeighbors = (list) => {
|
|
163
|
+
list.sort((a, b) => {
|
|
164
|
+
if (a.neighborId !== b.neighborId) {
|
|
165
|
+
return a.neighborId < b.neighborId ? -1 : 1;
|
|
166
|
+
}
|
|
167
|
+
return a.label < b.label ? -1 : a.label > b.label ? 1 : 0;
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
for (const list of outgoing.values()) {
|
|
172
|
+
sortNeighbors(list);
|
|
173
|
+
}
|
|
174
|
+
for (const list of incoming.values()) {
|
|
175
|
+
sortNeighbors(list);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { state, stateHash, adjacency: { outgoing, incoming } };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ===========================================================================
|
|
182
|
+
// Node API
|
|
183
|
+
// ===========================================================================
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Checks if a node exists and is visible to this observer.
|
|
187
|
+
*
|
|
188
|
+
* @param {string} nodeId - The node ID to check
|
|
189
|
+
* @returns {Promise<boolean>} True if the node exists and matches the observer pattern
|
|
190
|
+
*/
|
|
191
|
+
async hasNode(nodeId) {
|
|
192
|
+
if (!matchGlob(this._matchPattern, nodeId)) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return await this._graph.hasNode(nodeId);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Gets all visible nodes that match the observer pattern.
|
|
200
|
+
*
|
|
201
|
+
* @returns {Promise<string[]>} Array of visible node IDs
|
|
202
|
+
*/
|
|
203
|
+
async getNodes() {
|
|
204
|
+
const allNodes = await this._graph.getNodes();
|
|
205
|
+
return allNodes.filter((id) => matchGlob(this._matchPattern, id));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Gets filtered properties for a node.
|
|
210
|
+
*
|
|
211
|
+
* Returns null if the node does not exist or does not match
|
|
212
|
+
* the observer pattern.
|
|
213
|
+
*
|
|
214
|
+
* @param {string} nodeId - The node ID to get properties for
|
|
215
|
+
* @returns {Promise<Map<string, *>|null>} Filtered properties Map, or null
|
|
216
|
+
*/
|
|
217
|
+
async getNodeProps(nodeId) {
|
|
218
|
+
if (!matchGlob(this._matchPattern, nodeId)) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
const propsMap = await this._graph.getNodeProps(nodeId);
|
|
222
|
+
if (!propsMap) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return filterProps(propsMap, this._expose, this._redact);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ===========================================================================
|
|
229
|
+
// Edge API
|
|
230
|
+
// ===========================================================================
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Gets all visible edges.
|
|
234
|
+
*
|
|
235
|
+
* An edge is visible only when both endpoints match the observer pattern.
|
|
236
|
+
*
|
|
237
|
+
* @returns {Promise<Array<{from: string, to: string, label: string, props: Record<string, *>}>>}
|
|
238
|
+
*/
|
|
239
|
+
async getEdges() {
|
|
240
|
+
const allEdges = await this._graph.getEdges();
|
|
241
|
+
return allEdges
|
|
242
|
+
.filter(
|
|
243
|
+
(e) => matchGlob(this._matchPattern, e.from) && matchGlob(this._matchPattern, e.to)
|
|
244
|
+
)
|
|
245
|
+
.map((e) => {
|
|
246
|
+
const propsMap = new Map(Object.entries(e.props));
|
|
247
|
+
const filtered = filterProps(propsMap, this._expose, this._redact);
|
|
248
|
+
const filteredObj = Object.fromEntries(filtered);
|
|
249
|
+
return { ...e, props: filteredObj };
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ===========================================================================
|
|
254
|
+
// Query API
|
|
255
|
+
// ===========================================================================
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Creates a fluent query builder operating on the filtered view.
|
|
259
|
+
*
|
|
260
|
+
* @returns {QueryBuilder} A query builder scoped to this observer
|
|
261
|
+
*/
|
|
262
|
+
query() {
|
|
263
|
+
return new QueryBuilder(this);
|
|
264
|
+
}
|
|
265
|
+
}
|