@git-stunts/git-warp 11.5.0 → 12.0.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.
Files changed (51) hide show
  1. package/README.md +145 -1
  2. package/bin/cli/commands/registry.js +4 -0
  3. package/bin/cli/commands/reindex.js +41 -0
  4. package/bin/cli/commands/verify-index.js +59 -0
  5. package/bin/cli/infrastructure.js +7 -2
  6. package/bin/cli/schemas.js +19 -0
  7. package/bin/cli/types.js +2 -0
  8. package/index.d.ts +49 -12
  9. package/package.json +2 -2
  10. package/src/domain/WarpGraph.js +62 -2
  11. package/src/domain/errors/ShardIdOverflowError.js +28 -0
  12. package/src/domain/errors/index.js +1 -0
  13. package/src/domain/services/AdjacencyNeighborProvider.js +140 -0
  14. package/src/domain/services/BitmapIndexReader.js +32 -10
  15. package/src/domain/services/BitmapNeighborProvider.js +178 -0
  16. package/src/domain/services/CheckpointMessageCodec.js +3 -3
  17. package/src/domain/services/CheckpointService.js +77 -12
  18. package/src/domain/services/GraphTraversal.js +1239 -0
  19. package/src/domain/services/IncrementalIndexUpdater.js +765 -0
  20. package/src/domain/services/JoinReducer.js +310 -46
  21. package/src/domain/services/LogicalBitmapIndexBuilder.js +323 -0
  22. package/src/domain/services/LogicalIndexBuildService.js +108 -0
  23. package/src/domain/services/LogicalIndexReader.js +315 -0
  24. package/src/domain/services/LogicalTraversal.js +321 -202
  25. package/src/domain/services/MaterializedViewService.js +379 -0
  26. package/src/domain/services/ObserverView.js +138 -47
  27. package/src/domain/services/PatchBuilderV2.js +3 -3
  28. package/src/domain/services/PropertyIndexBuilder.js +64 -0
  29. package/src/domain/services/PropertyIndexReader.js +111 -0
  30. package/src/domain/services/SyncController.js +576 -0
  31. package/src/domain/services/TemporalQuery.js +128 -14
  32. package/src/domain/types/PatchDiff.js +90 -0
  33. package/src/domain/types/WarpTypesV2.js +4 -4
  34. package/src/domain/utils/MinHeap.js +45 -17
  35. package/src/domain/utils/canonicalCbor.js +36 -0
  36. package/src/domain/utils/fnv1a.js +20 -0
  37. package/src/domain/utils/roaring.js +14 -3
  38. package/src/domain/utils/shardKey.js +40 -0
  39. package/src/domain/utils/toBytes.js +17 -0
  40. package/src/domain/utils/validateShardOid.js +13 -0
  41. package/src/domain/warp/_internal.js +0 -9
  42. package/src/domain/warp/_wiredMethods.d.ts +8 -2
  43. package/src/domain/warp/checkpoint.methods.js +21 -5
  44. package/src/domain/warp/materialize.methods.js +17 -5
  45. package/src/domain/warp/materializeAdvanced.methods.js +142 -3
  46. package/src/domain/warp/query.methods.js +78 -12
  47. package/src/infrastructure/adapters/CasSeekCacheAdapter.js +26 -5
  48. package/src/ports/BlobPort.js +1 -1
  49. package/src/ports/NeighborProviderPort.js +59 -0
  50. package/src/ports/SeekCachePort.js +4 -3
  51. package/src/domain/warp/sync.methods.js +0 -554
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Builds property index shards from node properties.
3
+ *
4
+ * Produces `props_XX.cbor` shards keyed by shard key, where each
5
+ * shard maps nodeId → { key: value, ... }.
6
+ *
7
+ * @module domain/services/PropertyIndexBuilder
8
+ */
9
+
10
+ import defaultCodec from '../utils/defaultCodec.js';
11
+ import computeShardKey from '../utils/shardKey.js';
12
+
13
+ export default class PropertyIndexBuilder {
14
+ /**
15
+ * @param {Object} [options]
16
+ * @param {import('../../ports/CodecPort.js').default} [options.codec]
17
+ */
18
+ constructor({ codec } = {}) {
19
+ this._codec = codec || defaultCodec;
20
+ /** @type {Map<string, Map<string, Record<string, unknown>>>} shardKey → (nodeId → props) */
21
+ this._shards = new Map();
22
+ }
23
+
24
+ /**
25
+ * Adds a property for a node.
26
+ *
27
+ * @param {string} nodeId
28
+ * @param {string} key
29
+ * @param {unknown} value
30
+ */
31
+ addProperty(nodeId, key, value) {
32
+ const shardKey = computeShardKey(nodeId);
33
+ let shard = this._shards.get(shardKey);
34
+ if (!shard) {
35
+ shard = new Map();
36
+ this._shards.set(shardKey, shard);
37
+ }
38
+ let nodeProps = shard.get(nodeId);
39
+ if (!nodeProps) {
40
+ nodeProps = /** @type {Record<string, unknown>} */ (Object.create(null));
41
+ shard.set(nodeId, nodeProps);
42
+ }
43
+ /** @type {Record<string, unknown>} */ (nodeProps)[key] = value;
44
+ }
45
+
46
+ /**
47
+ * Serializes all property shards.
48
+ *
49
+ * @returns {Record<string, Uint8Array>}
50
+ */
51
+ serialize() {
52
+ /** @type {Record<string, Uint8Array>} */
53
+ const tree = {};
54
+ for (const [shardKey, shard] of this._shards) {
55
+ // Encode as array of [nodeId, props] pairs to avoid __proto__ key issues
56
+ // when CBOR decodes into plain objects. Sorted by nodeId for determinism.
57
+ const entries = [...shard.entries()]
58
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
59
+ .map(([nodeId, props]) => [nodeId, props]);
60
+ tree[`props_${shardKey}.cbor`] = this._codec.encode(entries).slice();
61
+ }
62
+ return tree;
63
+ }
64
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Reads property index shards lazily with LRU caching.
3
+ *
4
+ * Loads `props_XX.cbor` shards on demand via IndexStoragePort.readBlob.
5
+ *
6
+ * @module domain/services/PropertyIndexReader
7
+ */
8
+
9
+ import defaultCodec from '../utils/defaultCodec.js';
10
+ import computeShardKey from '../utils/shardKey.js';
11
+ import LRUCache from '../utils/LRUCache.js';
12
+
13
+ export default class PropertyIndexReader {
14
+ /**
15
+ * @param {Object} [options]
16
+ * @param {import('../../ports/IndexStoragePort.js').default} [options.storage]
17
+ * @param {import('../../ports/CodecPort.js').default} [options.codec]
18
+ * @param {number} [options.maxCachedShards=64]
19
+ */
20
+ constructor({ storage, codec, maxCachedShards = 64 } = /** @type {{ storage?: import('../../ports/IndexStoragePort.js').default, codec?: import('../../ports/CodecPort.js').default, maxCachedShards?: number }} */ ({})) {
21
+ this._storage = storage;
22
+ this._codec = codec || defaultCodec;
23
+ /** @type {Map<string, string>} path → oid */
24
+ this._shardOids = new Map();
25
+ /** @type {LRUCache<string, Record<string, Record<string, unknown>>>} */
26
+ this._cache = new LRUCache(maxCachedShards);
27
+ }
28
+
29
+ /**
30
+ * Configures OID mappings for lazy loading.
31
+ *
32
+ * @param {Record<string, string>} shardOids - path → blob OID
33
+ */
34
+ setup(shardOids) {
35
+ this._shardOids = new Map(Object.entries(shardOids));
36
+ this._cache.clear();
37
+ }
38
+
39
+ /**
40
+ * Returns all properties for a node, or null if not found.
41
+ *
42
+ * @param {string} nodeId
43
+ * @returns {Promise<Record<string, unknown>|null>}
44
+ */
45
+ async getNodeProps(nodeId) {
46
+ const shard = await this._loadShard(nodeId);
47
+ if (!shard) {
48
+ return null;
49
+ }
50
+ return shard[nodeId] ?? null;
51
+ }
52
+
53
+ /**
54
+ * Returns a single property value, or undefined.
55
+ *
56
+ * @param {string} nodeId
57
+ * @param {string} key
58
+ * @returns {Promise<unknown|undefined>}
59
+ */
60
+ async getProperty(nodeId, key) {
61
+ const props = await this.getNodeProps(nodeId);
62
+ if (!props) {
63
+ return undefined;
64
+ }
65
+ return props[key];
66
+ }
67
+
68
+ /**
69
+ * @param {string} nodeId
70
+ * @returns {Promise<Record<string, Record<string, unknown>>|null>}
71
+ * @private
72
+ */
73
+ async _loadShard(nodeId) {
74
+ const shardKey = computeShardKey(nodeId);
75
+ const path = `props_${shardKey}.cbor`;
76
+
77
+ const cached = this._cache.get(path);
78
+ if (cached !== undefined) {
79
+ return cached;
80
+ }
81
+
82
+ const oid = this._shardOids.get(path);
83
+ if (!oid) {
84
+ return null;
85
+ }
86
+
87
+ if (!this._storage) {
88
+ return null;
89
+ }
90
+
91
+ const buffer = await /** @type {{ readBlob(oid: string): Promise<Buffer|Uint8Array|undefined|null> }} */ (this._storage).readBlob(oid);
92
+ if (buffer === null || buffer === undefined) {
93
+ throw new Error(`PropertyIndexReader: missing blob for OID '${oid}' (${path})`);
94
+ }
95
+ const decoded = this._codec.decode(buffer);
96
+
97
+ // Shards are stored as array of [nodeId, props] pairs (proto-safe)
98
+ if (!Array.isArray(decoded)) {
99
+ const shape = decoded === null ? 'null' : typeof decoded;
100
+ throw new Error(`PropertyIndexReader: invalid shard format for '${path}' (expected array, got ${shape})`);
101
+ }
102
+
103
+ /** @type {Record<string, Record<string, unknown>>} */
104
+ const data = Object.create(null);
105
+ for (const [nid, props] of /** @type {Array<[string, Record<string, unknown>]>} */ (decoded)) {
106
+ data[nid] = props;
107
+ }
108
+ this._cache.set(path, data);
109
+ return data;
110
+ }
111
+ }