@git-stunts/git-warp 10.8.0 → 11.2.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.
Files changed (70) hide show
  1. package/README.md +53 -32
  2. package/SECURITY.md +64 -0
  3. package/bin/cli/commands/check.js +168 -0
  4. package/bin/cli/commands/doctor/checks.js +422 -0
  5. package/bin/cli/commands/doctor/codes.js +46 -0
  6. package/bin/cli/commands/doctor/index.js +239 -0
  7. package/bin/cli/commands/doctor/types.js +89 -0
  8. package/bin/cli/commands/history.js +73 -0
  9. package/bin/cli/commands/info.js +139 -0
  10. package/bin/cli/commands/install-hooks.js +128 -0
  11. package/bin/cli/commands/materialize.js +99 -0
  12. package/bin/cli/commands/path.js +88 -0
  13. package/bin/cli/commands/query.js +194 -0
  14. package/bin/cli/commands/registry.js +28 -0
  15. package/bin/cli/commands/seek.js +592 -0
  16. package/bin/cli/commands/trust.js +154 -0
  17. package/bin/cli/commands/verify-audit.js +113 -0
  18. package/bin/cli/commands/view.js +45 -0
  19. package/bin/cli/infrastructure.js +336 -0
  20. package/bin/cli/schemas.js +177 -0
  21. package/bin/cli/shared.js +244 -0
  22. package/bin/cli/types.js +85 -0
  23. package/bin/presenters/index.js +6 -0
  24. package/bin/presenters/text.js +136 -0
  25. package/bin/warp-graph.js +5 -2346
  26. package/index.d.ts +32 -2
  27. package/index.js +2 -0
  28. package/package.json +8 -7
  29. package/src/domain/WarpGraph.js +106 -3252
  30. package/src/domain/errors/QueryError.js +2 -2
  31. package/src/domain/errors/TrustError.js +29 -0
  32. package/src/domain/errors/index.js +1 -0
  33. package/src/domain/services/AuditMessageCodec.js +137 -0
  34. package/src/domain/services/AuditReceiptService.js +471 -0
  35. package/src/domain/services/AuditVerifierService.js +693 -0
  36. package/src/domain/services/HttpSyncServer.js +36 -22
  37. package/src/domain/services/MessageCodecInternal.js +3 -0
  38. package/src/domain/services/MessageSchemaDetector.js +2 -2
  39. package/src/domain/services/SyncAuthService.js +69 -3
  40. package/src/domain/services/WarpMessageCodec.js +4 -1
  41. package/src/domain/trust/TrustCanonical.js +42 -0
  42. package/src/domain/trust/TrustCrypto.js +111 -0
  43. package/src/domain/trust/TrustEvaluator.js +180 -0
  44. package/src/domain/trust/TrustRecordService.js +274 -0
  45. package/src/domain/trust/TrustStateBuilder.js +209 -0
  46. package/src/domain/trust/canonical.js +68 -0
  47. package/src/domain/trust/reasonCodes.js +64 -0
  48. package/src/domain/trust/schemas.js +160 -0
  49. package/src/domain/trust/verdict.js +42 -0
  50. package/src/domain/types/git-cas.d.ts +20 -0
  51. package/src/domain/utils/RefLayout.js +59 -0
  52. package/src/domain/warp/PatchSession.js +18 -0
  53. package/src/domain/warp/Writer.js +18 -3
  54. package/src/domain/warp/_internal.js +26 -0
  55. package/src/domain/warp/_wire.js +58 -0
  56. package/src/domain/warp/_wiredMethods.d.ts +100 -0
  57. package/src/domain/warp/checkpoint.methods.js +397 -0
  58. package/src/domain/warp/fork.methods.js +323 -0
  59. package/src/domain/warp/materialize.methods.js +188 -0
  60. package/src/domain/warp/materializeAdvanced.methods.js +339 -0
  61. package/src/domain/warp/patch.methods.js +529 -0
  62. package/src/domain/warp/provenance.methods.js +284 -0
  63. package/src/domain/warp/query.methods.js +279 -0
  64. package/src/domain/warp/subscribe.methods.js +272 -0
  65. package/src/domain/warp/sync.methods.js +549 -0
  66. package/src/infrastructure/adapters/GitGraphAdapter.js +67 -1
  67. package/src/infrastructure/adapters/InMemoryGraphAdapter.js +36 -0
  68. package/src/ports/CommitPort.js +10 -0
  69. package/src/ports/RefPort.js +17 -0
  70. package/src/hooks/post-merge.sh +0 -60
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Trust V1 Zod schemas.
3
+ *
4
+ * Schemas for trust record envelope, per-type subjects, policy config,
5
+ * and assessment output contract. These are the canonical validation
6
+ * boundary — all trust data passes through these schemas.
7
+ *
8
+ * @module domain/trust/schemas
9
+ * @see docs/specs/TRUST_V1_CRYPTO.md Sections 8–10, 14
10
+ */
11
+
12
+ import { z } from 'zod';
13
+
14
+ // ── Primitives ──────────────────────────────────────────────────────────
15
+
16
+ export const KeyIdSchema = z.string().regex(
17
+ /^ed25519:[a-f0-9]{64}$/,
18
+ 'keyId must be "ed25519:" followed by 64 hex chars',
19
+ );
20
+
21
+ export const RecordIdSchema = z.string().regex(
22
+ /^[a-f0-9]{64}$/,
23
+ 'recordId must be 64 lowercase hex chars',
24
+ );
25
+
26
+ export const RecordTypeSchema = z.enum([
27
+ 'KEY_ADD',
28
+ 'KEY_REVOKE',
29
+ 'WRITER_BIND_ADD',
30
+ 'WRITER_BIND_REVOKE',
31
+ ]);
32
+
33
+ // ── Signature ───────────────────────────────────────────────────────────
34
+
35
+ export const TrustSignatureSchema = z.object({
36
+ alg: z.literal('ed25519'),
37
+ sig: z.string().min(1, 'signature must not be empty'),
38
+ });
39
+
40
+ // ── Per-type subject schemas ────────────────────────────────────────────
41
+
42
+ export const KeyAddSubjectSchema = z.object({
43
+ keyId: KeyIdSchema,
44
+ publicKey: z.string().min(1, 'publicKey must not be empty'),
45
+ });
46
+
47
+ export const KeyRevokeSubjectSchema = z.object({
48
+ keyId: KeyIdSchema,
49
+ reasonCode: z.enum(['KEY_COMPROMISE', 'KEY_ROLLOVER', 'OPERATOR_REQUEST']),
50
+ });
51
+
52
+ export const WriterBindAddSubjectSchema = z.object({
53
+ writerId: z.string().trim().min(1),
54
+ keyId: KeyIdSchema,
55
+ });
56
+
57
+ export const WriterBindRevokeSubjectSchema = z.object({
58
+ writerId: z.string().trim().min(1),
59
+ keyId: KeyIdSchema,
60
+ reasonCode: z.enum(['ACCESS_REMOVED', 'ROTATION', 'KEY_REVOKED']),
61
+ });
62
+
63
+ // ── Trust record envelope ───────────────────────────────────────────────
64
+
65
+ export const TrustRecordSchema = z.object({
66
+ schemaVersion: z.literal(1),
67
+ recordType: RecordTypeSchema,
68
+ recordId: RecordIdSchema,
69
+ issuerKeyId: KeyIdSchema,
70
+ issuedAt: z.string().datetime({ offset: false }),
71
+ prev: RecordIdSchema.nullable(),
72
+ subject: z.record(z.unknown()),
73
+ meta: z.record(z.unknown()).optional().default({}),
74
+ signature: TrustSignatureSchema,
75
+ }).superRefine((record, ctx) => {
76
+ /** @param {string} message */
77
+ const addIssue = (message) =>
78
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message });
79
+
80
+ switch (record.recordType) {
81
+ case 'KEY_ADD': {
82
+ const r = KeyAddSubjectSchema.safeParse(record.subject);
83
+ if (!r.success) {
84
+ addIssue(`Invalid KEY_ADD subject: ${r.error.message}`);
85
+ } else {
86
+ record.subject = r.data;
87
+ }
88
+ break;
89
+ }
90
+ case 'KEY_REVOKE': {
91
+ const r = KeyRevokeSubjectSchema.safeParse(record.subject);
92
+ if (!r.success) {
93
+ addIssue(`Invalid KEY_REVOKE subject: ${r.error.message}`);
94
+ } else {
95
+ record.subject = r.data;
96
+ }
97
+ break;
98
+ }
99
+ case 'WRITER_BIND_ADD': {
100
+ const r = WriterBindAddSubjectSchema.safeParse(record.subject);
101
+ if (!r.success) {
102
+ addIssue(`Invalid WRITER_BIND_ADD subject: ${r.error.message}`);
103
+ } else {
104
+ record.subject = r.data;
105
+ }
106
+ break;
107
+ }
108
+ case 'WRITER_BIND_REVOKE': {
109
+ const r = WriterBindRevokeSubjectSchema.safeParse(record.subject);
110
+ if (!r.success) {
111
+ addIssue(`Invalid WRITER_BIND_REVOKE subject: ${r.error.message}`);
112
+ } else {
113
+ record.subject = r.data;
114
+ }
115
+ break;
116
+ }
117
+ default:
118
+ addIssue(`Unsupported recordType: ${/** @type {string} */ (record.recordType)}`);
119
+ }
120
+ });
121
+
122
+ // ── Policy config ───────────────────────────────────────────────────────
123
+
124
+ export const TrustPolicySchema = z.object({
125
+ schemaVersion: z.literal(1),
126
+ mode: z.enum(['warn', 'enforce']),
127
+ writerPolicy: z.literal('all_writers_must_be_trusted'),
128
+ });
129
+
130
+ // ── Assessment output contract ──────────────────────────────────────────
131
+
132
+ export const TrustExplanationSchema = z.object({
133
+ writerId: z.string().min(1),
134
+ trusted: z.boolean(),
135
+ reasonCode: z.string().min(1),
136
+ reason: z.string().min(1),
137
+ });
138
+
139
+ export const EvidenceSummarySchema = z.object({
140
+ recordsScanned: z.number().int().nonnegative(),
141
+ activeKeys: z.number().int().nonnegative(),
142
+ revokedKeys: z.number().int().nonnegative(),
143
+ activeBindings: z.number().int().nonnegative(),
144
+ revokedBindings: z.number().int().nonnegative(),
145
+ });
146
+
147
+ export const TrustAssessmentSchema = z.object({
148
+ trustSchemaVersion: z.literal(1),
149
+ mode: z.literal('signed_evidence_v1'),
150
+ trustVerdict: z.enum(['pass', 'fail', 'not_configured']),
151
+ trust: z.object({
152
+ status: z.enum(['configured', 'pinned', 'error', 'not_configured']),
153
+ source: z.enum(['ref', 'cli_pin', 'env_pin', 'none']),
154
+ sourceDetail: z.string().nullable(),
155
+ evaluatedWriters: z.array(z.string()),
156
+ untrustedWriters: z.array(z.string()),
157
+ explanations: z.array(TrustExplanationSchema),
158
+ evidenceSummary: EvidenceSummarySchema,
159
+ }),
160
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Trust V1 verdict derivation.
3
+ *
4
+ * Deterministic mapping from TrustAssessment to verdict string.
5
+ * This is the single source of truth for verdict logic.
6
+ *
7
+ * @module domain/trust/verdict
8
+ * @see docs/specs/TRUST_V1_CRYPTO.md Section 13
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} TrustAssessmentV1
13
+ * @property {'not_configured'|'configured'|'pinned'|'error'} status
14
+ * @property {string[]} untrustedWriters
15
+ */
16
+
17
+ /**
18
+ * Derives the trust verdict from a V1 trust assessment.
19
+ *
20
+ * Mapping (evaluated in order):
21
+ * - status 'not_configured' → 'not_configured'
22
+ * - status 'error' → 'fail'
23
+ * - untrustedWriters.length > 0 → 'fail'
24
+ * - otherwise → 'pass'
25
+ *
26
+ * V1 has no 'degraded' verdict — untrusted writers are a hard failure.
27
+ *
28
+ * @param {TrustAssessmentV1} trust
29
+ * @returns {'pass'|'fail'|'not_configured'}
30
+ */
31
+ export function deriveTrustVerdict(trust) {
32
+ if (trust.status === 'not_configured') {
33
+ return 'not_configured';
34
+ }
35
+ if (trust.status === 'error') {
36
+ return 'fail';
37
+ }
38
+ if (Array.isArray(trust.untrustedWriters) && trust.untrustedWriters.length > 0) {
39
+ return 'fail';
40
+ }
41
+ return 'pass';
42
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Type stub for @git-stunts/git-cas.
3
+ *
4
+ * Provides just enough shape for CasSeekCacheAdapter to typecheck.
5
+ */
6
+ declare module '@git-stunts/git-cas' {
7
+ interface CasStore {
8
+ put(key: string, value: Uint8Array): Promise<string>;
9
+ get(key: string): Promise<Uint8Array | null>;
10
+ has(key: string): Promise<boolean>;
11
+ delete(key: string): Promise<boolean>;
12
+ }
13
+
14
+ interface ContentAddressableStore {
15
+ createCbor(opts: { plumbing: unknown }): CasStore;
16
+ }
17
+
18
+ const ContentAddressableStore: ContentAddressableStore;
19
+ export default ContentAddressableStore;
20
+ }
@@ -10,6 +10,8 @@
10
10
  * - refs/warp/<graph>/coverage/head
11
11
  * - refs/warp/<graph>/cursor/active
12
12
  * - refs/warp/<graph>/cursor/saved/<name>
13
+ * - refs/warp/<graph>/audit/<writer_id>
14
+ * - refs/warp/<graph>/trust/records
13
15
  *
14
16
  * @module domain/utils/RefLayout
15
17
  */
@@ -291,6 +293,43 @@ export function buildCursorSavedPrefix(graphName) {
291
293
  return `${REF_PREFIX}/${graphName}/cursor/saved/`;
292
294
  }
293
295
 
296
+ /**
297
+ * Builds the audit ref path for the given graph and writer ID.
298
+ *
299
+ * Audit refs track the latest audit commit for each writer, forming
300
+ * an independent chain of tamper-evident receipts per writer.
301
+ *
302
+ * @param {string} graphName - The name of the graph
303
+ * @param {string} writerId - The writer's unique identifier
304
+ * @returns {string} The full ref path, e.g. `refs/warp/<graphName>/audit/<writerId>`
305
+ * @throws {Error} If graphName or writerId is invalid
306
+ *
307
+ * @example
308
+ * buildAuditRef('events', 'alice');
309
+ * // => 'refs/warp/events/audit/alice'
310
+ */
311
+ export function buildAuditRef(graphName, writerId) {
312
+ validateGraphName(graphName);
313
+ validateWriterId(writerId);
314
+ return `${REF_PREFIX}/${graphName}/audit/${writerId}`;
315
+ }
316
+
317
+ /**
318
+ * Builds the audit ref prefix for listing all audit writers of a graph.
319
+ *
320
+ * @param {string} graphName - The name of the graph
321
+ * @returns {string} The ref prefix, e.g. `refs/warp/<graphName>/audit/`
322
+ * @throws {Error} If graphName is invalid
323
+ *
324
+ * @example
325
+ * buildAuditPrefix('events');
326
+ * // => 'refs/warp/events/audit/'
327
+ */
328
+ export function buildAuditPrefix(graphName) {
329
+ validateGraphName(graphName);
330
+ return `${REF_PREFIX}/${graphName}/audit/`;
331
+ }
332
+
294
333
  /**
295
334
  * Builds the seek cache ref path for the given graph.
296
335
  *
@@ -310,6 +349,26 @@ export function buildSeekCacheRef(graphName) {
310
349
  return `${REF_PREFIX}/${graphName}/seek-cache`;
311
350
  }
312
351
 
352
+ /**
353
+ * Builds the trust record chain ref path for the given graph.
354
+ *
355
+ * The trust record ref points to the tip commit of the trust record
356
+ * chain — an append-only sequence of signed trust records (key adds,
357
+ * key revokes, writer bindings).
358
+ *
359
+ * @param {string} graphName - The name of the graph
360
+ * @returns {string} The full ref path, e.g. `refs/warp/<graphName>/trust/records`
361
+ * @throws {Error} If graphName is invalid
362
+ *
363
+ * @example
364
+ * buildTrustRecordRef('events');
365
+ * // => 'refs/warp/events/trust/records'
366
+ */
367
+ export function buildTrustRecordRef(graphName) {
368
+ validateGraphName(graphName);
369
+ return `${REF_PREFIX}/${graphName}/trust/records`;
370
+ }
371
+
313
372
  // -----------------------------------------------------------------------------
314
373
  // Parsers
315
374
  // -----------------------------------------------------------------------------
@@ -130,6 +130,24 @@ export class PatchSession {
130
130
  return this;
131
131
  }
132
132
 
133
+ /**
134
+ * Sets a property on an edge.
135
+ *
136
+ * @param {string} from - Source node ID
137
+ * @param {string} to - Target node ID
138
+ * @param {string} label - Edge label/type
139
+ * @param {string} key - Property key
140
+ * @param {*} value - Property value (must be JSON-serializable)
141
+ * @returns {this} This session for chaining
142
+ * @throws {Error} If this session has already been committed
143
+ */
144
+ // eslint-disable-next-line max-params -- direct delegate matching PatchBuilderV2 signature
145
+ setEdgeProperty(from, to, label, key, value) {
146
+ this._ensureNotCommitted();
147
+ this._builder.setEdgeProperty(from, to, label, key, value);
148
+ return this;
149
+ }
150
+
133
151
  /**
134
152
  * Builds the PatchV2 object without committing.
135
153
  *
@@ -71,6 +71,9 @@ export class Writer {
71
71
 
72
72
  /** @type {import('../../ports/CodecPort.js').default|undefined} */
73
73
  this._codec = codec || defaultCodec;
74
+
75
+ /** @type {boolean} */
76
+ this._commitInProgress = false;
74
77
  }
75
78
 
76
79
  /**
@@ -163,6 +166,7 @@ export class Writer {
163
166
  *
164
167
  * @param {(p: PatchSession) => void | Promise<void>} build - Function to build the patch
165
168
  * @returns {Promise<string>} The commit SHA of the new patch
169
+ * @throws {WriterError} COMMIT_IN_PROGRESS if called while another commitPatch() is in progress (not reentrant)
166
170
  * @throws {WriterError} EMPTY_PATCH if no operations were added
167
171
  * @throws {WriterError} WRITER_REF_ADVANCED if CAS fails (ref moved since beginPatch)
168
172
  * @throws {WriterError} PERSIST_WRITE_FAILED if git operations fail
@@ -174,8 +178,19 @@ export class Writer {
174
178
  * });
175
179
  */
176
180
  async commitPatch(build) {
177
- const patch = await this.beginPatch();
178
- await build(patch);
179
- return await patch.commit();
181
+ if (this._commitInProgress) {
182
+ throw new WriterError(
183
+ 'COMMIT_IN_PROGRESS',
184
+ 'commitPatch() is not reentrant. Use beginPatch() for nested or concurrent patches.',
185
+ );
186
+ }
187
+ this._commitInProgress = true;
188
+ try {
189
+ const patch = await this.beginPatch();
190
+ await build(patch);
191
+ return await patch.commit();
192
+ } finally {
193
+ this._commitInProgress = false;
194
+ }
180
195
  }
181
196
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared constants and re-exports for WarpGraph method files.
3
+ *
4
+ * Method files (`*.methods.js`) import from here to avoid
5
+ * brittle relative paths back into the domain root.
6
+ *
7
+ * @module domain/warp/_internal
8
+ */
9
+
10
+ // ── Error constructors ──────────────────────────────────────────────────────
11
+ export { default as QueryError } from '../errors/QueryError.js';
12
+ export { default as ForkError } from '../errors/ForkError.js';
13
+ export { default as SyncError } from '../errors/SyncError.js';
14
+ export { default as OperationAbortedError } from '../errors/OperationAbortedError.js';
15
+
16
+ // ── Shared constants ────────────────────────────────────────────────────────
17
+ export const DEFAULT_ADJACENCY_CACHE_SIZE = 3;
18
+ export const E_NO_STATE_MSG = 'No materialized state. Call materialize() before querying, or use autoMaterialize: true (the default). See https://github.com/git-stunts/git-warp#materialization';
19
+ export const E_STALE_STATE_MSG = 'State is stale (patches written since last materialize). Call materialize() to refresh. See https://github.com/git-stunts/git-warp#materialization';
20
+
21
+ // ── Sync constants ──────────────────────────────────────────────────────────
22
+ export const DEFAULT_SYNC_SERVER_MAX_BYTES = 4 * 1024 * 1024;
23
+ export const DEFAULT_SYNC_WITH_RETRIES = 3;
24
+ export const DEFAULT_SYNC_WITH_BASE_DELAY_MS = 250;
25
+ export const DEFAULT_SYNC_WITH_MAX_DELAY_MS = 2000;
26
+ export const DEFAULT_SYNC_WITH_TIMEOUT_MS = 10_000;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Prototype wiring helper for WarpGraph method extraction.
3
+ *
4
+ * Assigns exported functions from `*.methods.js` modules onto a class
5
+ * prototype, with duplicate-name detection at import time.
6
+ *
7
+ * @module domain/warp/_wire
8
+ */
9
+
10
+ /**
11
+ * Wires exported functions from method modules onto a class prototype.
12
+ *
13
+ * Each module is expected to export named functions. The function names
14
+ * become method names on the prototype. Duplicates across modules are
15
+ * detected eagerly and throw at import time (not at call time).
16
+ *
17
+ * @param {Function} Class - The class constructor whose prototype to extend
18
+ * @param {Array<Record<string, Function>>} methodModules - Array of method module namespace objects
19
+ * @throws {Error} If a method name appears in more than one module
20
+ */
21
+ export function wireWarpMethods(Class, methodModules) {
22
+ /** @type {Map<string, string>} name → source module index (for error messages) */
23
+ const seen = new Map();
24
+ const existing = new Set(Object.getOwnPropertyNames(Class.prototype));
25
+
26
+ for (let i = 0; i < methodModules.length; i++) {
27
+ const mod = methodModules[i];
28
+ for (const [name, fn] of Object.entries(mod)) {
29
+ if (typeof fn !== 'function') {
30
+ continue;
31
+ }
32
+
33
+ if (existing.has(name)) {
34
+ throw new Error(
35
+ `wireWarpMethods: method "${name}" already exists on ${Class.name}.prototype — ` +
36
+ `attempted to overwrite from module index ${i}`
37
+ );
38
+ }
39
+
40
+ if (seen.has(name)) {
41
+ throw new Error(
42
+ `wireWarpMethods: duplicate method "${name}" — ` +
43
+ `already defined in module index ${seen.get(name)}, ` +
44
+ `attempted again in module index ${i}`
45
+ );
46
+ }
47
+
48
+ seen.set(name, String(i));
49
+
50
+ Object.defineProperty(Class.prototype, name, {
51
+ value: fn,
52
+ writable: true,
53
+ configurable: true,
54
+ enumerable: false,
55
+ });
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * TypeScript augmentation for WarpGraph wired methods.
3
+ *
4
+ * Methods in *.methods.js are wired onto WarpGraph.prototype at runtime
5
+ * via wireWarpMethods(). This declaration file makes them visible to tsc.
6
+ */
7
+
8
+ /* eslint-disable @typescript-eslint/no-explicit-any */
9
+
10
+ import type { PatchBuilderV2 } from '../services/PatchBuilderV2.js';
11
+ import type { Writer } from './Writer.js';
12
+
13
+ export {};
14
+
15
+ declare module '../WarpGraph.js' {
16
+ export default interface WarpGraph {
17
+ // ── query.methods.js ──────────────────────────────────────────────────
18
+ hasNode(nodeId: string): Promise<boolean>;
19
+ getNodeProps(nodeId: string): Promise<Map<string, any> | null>;
20
+ getEdgeProps(from: string, to: string, label: string): Promise<Record<string, any> | null>;
21
+ neighbors(nodeId: string, direction?: 'outgoing' | 'incoming' | 'both', edgeLabel?: string): Promise<Array<{ nodeId: string; label: string; direction: 'outgoing' | 'incoming' }>>;
22
+ getStateSnapshot(): Promise<any>;
23
+ getNodes(): Promise<string[]>;
24
+ getEdges(): Promise<Array<{ from: string; to: string; label: string; props: Record<string, any> }>>;
25
+ getPropertyCount(): Promise<number>;
26
+ query(): any;
27
+ observer(name: string, config: any): Promise<any>;
28
+ translationCost(configA: any, configB: any): Promise<{ cost: number; breakdown: { nodeLoss: number; edgeLoss: number; propLoss: number } }>;
29
+
30
+ // ── subscribe.methods.js ──────────────────────────────────────────────
31
+ subscribe(options: { onChange: Function; onError?: Function; replay?: boolean }): { unsubscribe: () => void };
32
+ watch(pattern: string, options: { onChange: Function; onError?: Function; poll?: number }): { unsubscribe: () => void };
33
+ _notifySubscribers(diff: any, currentState: any): void;
34
+
35
+ // ── provenance.methods.js ─────────────────────────────────────────────
36
+ patchesFor(entityId: string): Promise<string[]>;
37
+ materializeSlice(nodeId: string, options?: any): Promise<any>;
38
+ _computeBackwardCone(nodeId: string): Promise<Map<string, any>>;
39
+ loadPatchBySha(sha: string): Promise<any>;
40
+ _loadPatchBySha(sha: string): Promise<any>;
41
+ _loadPatchesBySha(shas: string[]): Promise<Array<{ patch: any; sha: string }>>;
42
+ _sortPatchesCausally(patches: any[]): any[];
43
+
44
+ // ── fork.methods.js ───────────────────────────────────────────────────
45
+ fork(options: { from: string; at: string; forkName?: string; forkWriterId?: string }): Promise<WarpGraph>;
46
+ createWormhole(fromSha: string, toSha: string): Promise<{ fromSha: string; toSha: string; writerId: string; payload: any; patchCount: number }>;
47
+ _isAncestor(ancestorSha: string, descendantSha: string): Promise<boolean>;
48
+ _relationToCheckpointHead(ckHead: string, incomingSha: string): Promise<string>;
49
+ _validatePatchAgainstCheckpoint(writerId: string, incomingSha: string, checkpoint: any): Promise<void>;
50
+
51
+ // ── sync.methods.js ───────────────────────────────────────────────────
52
+ getFrontier(): Promise<Map<string, string>>;
53
+ hasFrontierChanged(): Promise<boolean>;
54
+ status(): Promise<any>;
55
+ createSyncRequest(): Promise<any>;
56
+ processSyncRequest(request: any): Promise<any>;
57
+ applySyncResponse(response: any): any;
58
+ syncNeeded(remoteFrontier: any): Promise<boolean>;
59
+ syncWith(remote: any, options?: any): Promise<any>;
60
+ serve(options?: any): Promise<any>;
61
+
62
+ // ── checkpoint.methods.js ─────────────────────────────────────────────
63
+ createCheckpoint(): Promise<string>;
64
+ syncCoverage(): Promise<void>;
65
+ _loadLatestCheckpoint(): Promise<any>;
66
+ _loadPatchesSince(checkpoint: any): Promise<any[]>;
67
+ _validateMigrationBoundary(): Promise<void>;
68
+ _hasSchema1Patches(): Promise<boolean>;
69
+ _maybeRunGC(state: any): any;
70
+ maybeRunGC(): any;
71
+ runGC(): any;
72
+ getGCMetrics(): any;
73
+
74
+ // ── patch.methods.js ──────────────────────────────────────────────────
75
+ createPatch(): Promise<PatchBuilderV2>;
76
+ patch(build: (p: PatchBuilderV2) => void | Promise<void>): Promise<string>;
77
+ _nextLamport(): Promise<{ lamport: number; parentSha: string | null }>;
78
+ _loadWriterPatches(writerId: string, stopAtSha?: string | null): Promise<Array<{ patch: import('../types/WarpTypesV2.js').PatchV2; sha: string }>>;
79
+ getWriterPatches(writerId: string, stopAtSha?: string | null): Promise<Array<{ patch: import('../types/WarpTypesV2.js').PatchV2; sha: string }>>;
80
+ _onPatchCommitted(writerId: string, opts?: { patch?: any; sha?: string }): Promise<void>;
81
+ writer(writerId?: string): Promise<Writer>;
82
+ createWriter(opts?: any): Promise<Writer>;
83
+ _ensureFreshState(): Promise<void>;
84
+ discoverWriters(): Promise<string[]>;
85
+ discoverTicks(): Promise<{ ticks: number[]; maxTick: number; perWriter: Map<string, { ticks: number[]; tipSha: string | null; tickShas: Record<number, string> }> }>;
86
+ join(otherState: any): any;
87
+ _frontierEquals(a: any, b: any): boolean;
88
+
89
+ // ── materialize.methods.js ────────────────────────────────────────────
90
+ materialize(options?: any): Promise<any>;
91
+ _materializeGraph(): Promise<any>;
92
+
93
+ // ── materializeAdvanced.methods.js ────────────────────────────────────
94
+ _resolveCeiling(options: any): any;
95
+ _buildAdjacency(state: any): any;
96
+ _setMaterializedState(state: any): Promise<{ state: any; stateHash: string; adjacency: any }>;
97
+ _materializeWithCeiling(ceiling: any, collectReceipts: boolean, t0: number): Promise<any>;
98
+ materializeAt(checkpointSha: string): Promise<any>;
99
+ }
100
+ }