pushwork 1.0.0 → 1.0.3

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 (58) hide show
  1. package/README.md +23 -21
  2. package/dist/cli/commands.d.ts +6 -0
  3. package/dist/cli/commands.d.ts.map +1 -1
  4. package/dist/cli/commands.js +114 -4
  5. package/dist/cli/commands.js.map +1 -1
  6. package/dist/cli.js +27 -0
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/change-detection.d.ts.map +1 -1
  9. package/dist/core/change-detection.js +27 -9
  10. package/dist/core/change-detection.js.map +1 -1
  11. package/dist/core/move-detection.d.ts.map +1 -1
  12. package/dist/core/move-detection.js +8 -2
  13. package/dist/core/move-detection.js.map +1 -1
  14. package/dist/core/sync-engine.d.ts +4 -0
  15. package/dist/core/sync-engine.d.ts.map +1 -1
  16. package/dist/core/sync-engine.js +263 -7
  17. package/dist/core/sync-engine.js.map +1 -1
  18. package/dist/types/documents.d.ts +2 -0
  19. package/dist/types/documents.d.ts.map +1 -1
  20. package/dist/types/documents.js.map +1 -1
  21. package/dist/utils/fs.d.ts.map +1 -1
  22. package/dist/utils/fs.js +7 -1
  23. package/dist/utils/fs.js.map +1 -1
  24. package/dist/utils/network-sync.d.ts.map +1 -1
  25. package/dist/utils/network-sync.js +16 -3
  26. package/dist/utils/network-sync.js.map +1 -1
  27. package/package.json +30 -30
  28. package/src/cli/commands.ts +162 -8
  29. package/src/cli.ts +40 -0
  30. package/src/core/change-detection.ts +25 -12
  31. package/src/core/move-detection.ts +8 -2
  32. package/src/core/sync-engine.ts +270 -7
  33. package/src/types/documents.ts +2 -0
  34. package/src/utils/fs.ts +7 -3
  35. package/src/utils/network-sync.ts +19 -3
  36. package/test/integration/clone-test.sh +0 -0
  37. package/test/integration/conflict-resolution-test.sh +0 -0
  38. package/test/integration/debug-both-nested.sh +74 -0
  39. package/test/integration/debug-concurrent-nested.sh +87 -0
  40. package/test/integration/debug-nested.sh +73 -0
  41. package/test/integration/deletion-behavior-test.sh +0 -0
  42. package/test/integration/deletion-sync-test-simple.sh +0 -0
  43. package/test/integration/deletion-sync-test.sh +0 -0
  44. package/test/integration/full-integration-test.sh +0 -0
  45. package/test/integration/fuzzer.test.ts +865 -0
  46. package/test/integration/manual-sync-test.sh +84 -0
  47. package/test/run-tests.sh +0 -0
  48. package/test/unit/sync-convergence.test.ts +493 -0
  49. package/tools/browser-sync/README.md +0 -116
  50. package/tools/browser-sync/package.json +0 -44
  51. package/tools/browser-sync/patchwork.json +0 -1
  52. package/tools/browser-sync/pnpm-lock.yaml +0 -4202
  53. package/tools/browser-sync/src/components/BrowserSyncTool.tsx +0 -599
  54. package/tools/browser-sync/src/index.ts +0 -20
  55. package/tools/browser-sync/src/polyfills.ts +0 -31
  56. package/tools/browser-sync/src/styles.css +0 -290
  57. package/tools/browser-sync/src/types.ts +0 -27
  58. package/tools/browser-sync/vite.config.ts +0 -25
@@ -10,6 +10,8 @@ export async function waitForSync(
10
10
  syncServerStorageId?: StorageId,
11
11
  timeoutMs: number = 60000 // 60 second timeout for debugging
12
12
  ): Promise<void> {
13
+ const startTime = Date.now();
14
+
13
15
  if (!syncServerStorageId) {
14
16
  console.warn(
15
17
  "No sync server storage ID provided. Skipping network sync wait."
@@ -47,7 +49,10 @@ export async function waitForSync(
47
49
  const promises = handlesToWaitOn.map(
48
50
  (handle, index) =>
49
51
  new Promise<void>((resolve, reject) => {
52
+ let pollInterval: NodeJS.Timeout;
53
+
50
54
  const timeout = setTimeout(() => {
55
+ clearInterval(pollInterval);
51
56
  const localHeads = handle.heads();
52
57
  const syncInfo = handle.getSyncInfo(syncServerStorageId);
53
58
  const remoteHeads = syncInfo?.lastHeads;
@@ -79,6 +84,7 @@ export async function waitForSync(
79
84
  console.log(`✅ Document ${index + 1} synced: ${handle.url}`);
80
85
  }
81
86
  clearTimeout(timeout);
87
+ clearInterval(pollInterval);
82
88
  resolve();
83
89
  return true;
84
90
  }
@@ -90,7 +96,14 @@ export async function waitForSync(
90
96
  return;
91
97
  }
92
98
 
93
- // Otherwise, wait for remote-heads event
99
+ // Periodically re-check if heads have converged (polling fallback)
100
+ pollInterval = setInterval(() => {
101
+ if (checkSync()) {
102
+ clearInterval(pollInterval);
103
+ }
104
+ }, 100); // Check every 100ms for faster response
105
+
106
+ // Also wait for remote-heads event (faster when events work)
94
107
  const onRemoteHeads = ({
95
108
  storageId,
96
109
  heads,
@@ -118,6 +131,7 @@ export async function waitForSync(
118
131
  );
119
132
  }
120
133
  clearTimeout(timeout);
134
+ clearInterval(pollInterval);
121
135
  handle.off("remote-heads", onRemoteHeads);
122
136
  resolve();
123
137
  } else if (verbose) {
@@ -134,11 +148,13 @@ export async function waitForSync(
134
148
 
135
149
  try {
136
150
  await Promise.all(promises);
151
+ const elapsed = Date.now() - startTime;
137
152
  if (verbose) {
138
- console.log("✅ All documents synced to network");
153
+ console.log(`✅ All documents synced to network (took ${elapsed}ms)`);
139
154
  }
140
155
  } catch (error) {
141
- console.error(`❌ Sync wait failed: ${error}`);
156
+ const elapsed = Date.now() - startTime;
157
+ console.error(`❌ Sync wait failed after ${elapsed}ms: ${error}`);
142
158
  throw error;
143
159
  }
144
160
  }
File without changes
File without changes
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Get absolute path to pushwork CLI
5
+ PUSHWORK_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
6
+ PUSHWORK_CLI="$PUSHWORK_ROOT/dist/cli.js"
7
+
8
+ echo "=== Creating test repos ==="
9
+ TESTDIR=$(mktemp -d)
10
+ REPO_A="$TESTDIR/repo-a"
11
+ REPO_B="$TESTDIR/repo-b"
12
+ mkdir -p "$REPO_A" "$REPO_B"
13
+
14
+ echo "=== Initializing repo A with a file ==="
15
+ echo "initial" > "$REPO_A/initial.txt"
16
+ cd "$REPO_A"
17
+ node "$PUSHWORK_CLI" init .
18
+
19
+ echo ""
20
+ echo "=== Cloning to repo B ==="
21
+ ROOT_URL=$(node "$PUSHWORK_CLI" url)
22
+ echo "Root URL: $ROOT_URL"
23
+ cd "$TESTDIR"
24
+ node "$PUSHWORK_CLI" clone "$ROOT_URL" "$REPO_B"
25
+
26
+ echo ""
27
+ echo "=== On A: Try to editAndRename non-existent file ==="
28
+ # This should be a no-op since tmjaz/namelye.txt doesn't exist
29
+ echo "(This is a no-op since source doesn't exist)"
30
+
31
+ echo ""
32
+ echo "=== On B: Create file in 2-level nested subdirectory ==="
33
+ mkdir -p "$REPO_B/rlpjug/ewsv"
34
+ echo "" > "$REPO_B/rlpjug/ewsv/sneked.txt"
35
+
36
+ echo ""
37
+ echo "=== Sync round 1: A ==="
38
+ cd "$REPO_A"
39
+ node "$PUSHWORK_CLI" sync
40
+
41
+ echo ""
42
+ echo "=== Sync round 1: B ==="
43
+ cd "$REPO_B"
44
+ node "$PUSHWORK_CLI" sync
45
+
46
+ echo ""
47
+ echo "=== Sync round 2: A ==="
48
+ cd "$REPO_A"
49
+ node "$PUSHWORK_CLI" sync
50
+
51
+ echo ""
52
+ echo "=== Sync round 2: B ==="
53
+ cd "$REPO_B"
54
+ node "$PUSHWORK_CLI" sync
55
+
56
+ echo ""
57
+ echo "=== Verification ==="
58
+ echo "Files in A:"
59
+ find "$REPO_A" -type f \( -name "*.txt" -o -name "*.md" \) | grep -v "\.pushwork" | sed "s|$REPO_A/||" | sort
60
+
61
+ echo ""
62
+ echo "Files in B:"
63
+ find "$REPO_B" -type f \( -name "*.txt" -o -name "*.md" \) | grep -v "\.pushwork" | sed "s|$REPO_B/||" | sort
64
+
65
+ echo ""
66
+ if [ -f "$REPO_A/rlpjug/ewsv/sneked.txt" ]; then
67
+ echo "✅ SUCCESS: B's nested file synced to A"
68
+ else
69
+ echo "❌ FAILURE: B's nested file did NOT sync to A"
70
+ fi
71
+
72
+ echo ""
73
+ echo "Test directory: $TESTDIR"
74
+
@@ -0,0 +1,87 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Get absolute path to pushwork CLI
5
+ PUSHWORK_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
6
+ PUSHWORK_CLI="$PUSHWORK_ROOT/dist/cli.js"
7
+
8
+ echo "=== Creating test repos ==="
9
+ TESTDIR=$(mktemp -d)
10
+ REPO_A="$TESTDIR/repo-a"
11
+ REPO_B="$TESTDIR/repo-b"
12
+ mkdir -p "$REPO_A" "$REPO_B"
13
+
14
+ echo "=== Initializing repo A with a file ==="
15
+ echo "initial" > "$REPO_A/initial.txt"
16
+ cd "$REPO_A"
17
+ node "$PUSHWORK_CLI" init .
18
+
19
+ echo ""
20
+ echo "=== Cloning to repo B ==="
21
+ ROOT_URL=$(node "$PUSHWORK_CLI" url)
22
+ echo "Root URL: $ROOT_URL"
23
+ cd "$TESTDIR"
24
+ node "$PUSHWORK_CLI" clone "$ROOT_URL" "$REPO_B"
25
+
26
+ echo ""
27
+ echo "=== On A: Create file in nested directory dirA/subA ==="
28
+ mkdir -p "$REPO_A/dirA/subA"
29
+ echo "from A" > "$REPO_A/dirA/subA/fileA.txt"
30
+
31
+ echo ""
32
+ echo "=== On B: Create file in different nested directory dirB/subB ==="
33
+ mkdir -p "$REPO_B/dirB/subB"
34
+ echo "from B" > "$REPO_B/dirB/subB/fileB.txt"
35
+
36
+ echo ""
37
+ echo "=== Sync round 1: A (push A's nested file) ==="
38
+ cd "$REPO_A"
39
+ node "$PUSHWORK_CLI" sync
40
+
41
+ echo ""
42
+ echo "=== Sync round 1: B (push B's nested file, pull A's) ==="
43
+ cd "$REPO_B"
44
+ node "$PUSHWORK_CLI" sync
45
+
46
+ echo ""
47
+ echo "=== Sync round 2: A (pull B's nested file) ==="
48
+ cd "$REPO_A"
49
+ node "$PUSHWORK_CLI" sync
50
+
51
+ echo ""
52
+ echo "=== Sync round 2: B (confirm) ==="
53
+ cd "$REPO_B"
54
+ node "$PUSHWORK_CLI" sync
55
+
56
+ echo ""
57
+ echo "=== Verification ==="
58
+ echo "Files in A:"
59
+ find "$REPO_A" -type f \( -name "*.txt" -o -name "*.md" \) | grep -v "\.pushwork" | sed "s|$REPO_A/||" | sort
60
+
61
+ echo ""
62
+ echo "Files in B:"
63
+ find "$REPO_B" -type f \( -name "*.txt" -o -name "*.md" \) | grep -v "\.pushwork" | sed "s|$REPO_B/||" | sort
64
+
65
+ echo ""
66
+ echo "Checking convergence:"
67
+ A_HAS_A=$([ -f "$REPO_A/dirA/subA/fileA.txt" ] && echo YES || echo NO)
68
+ A_HAS_B=$([ -f "$REPO_A/dirB/subB/fileB.txt" ] && echo YES || echo NO)
69
+ B_HAS_A=$([ -f "$REPO_B/dirA/subA/fileA.txt" ] && echo YES || echo NO)
70
+ B_HAS_B=$([ -f "$REPO_B/dirB/subB/fileB.txt" ] && echo YES || echo NO)
71
+
72
+ echo " A has its own file (dirA/subA/fileA.txt): $A_HAS_A"
73
+ echo " A has B's file (dirB/subB/fileB.txt): $A_HAS_B"
74
+ echo " B has A's file (dirA/subA/fileA.txt): $B_HAS_A"
75
+ echo " B has its own file (dirB/subB/fileB.txt): $B_HAS_B"
76
+
77
+ if [ "$A_HAS_A" = "YES" ] && [ "$A_HAS_B" = "YES" ] && [ "$B_HAS_A" = "YES" ] && [ "$B_HAS_B" = "YES" ]; then
78
+ echo ""
79
+ echo "✅ SUCCESS: Both nested files synced correctly!"
80
+ else
81
+ echo ""
82
+ echo "❌ FAILURE: Not all files synced"
83
+ fi
84
+
85
+ echo ""
86
+ echo "Test directory: $TESTDIR"
87
+
@@ -0,0 +1,73 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Get absolute path to pushwork CLI
5
+ PUSHWORK_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
6
+ PUSHWORK_CLI="$PUSHWORK_ROOT/dist/cli.js"
7
+
8
+ echo "=== Creating test repos ==="
9
+ TESTDIR=$(mktemp -d)
10
+ REPO_A="$TESTDIR/repo-a"
11
+ REPO_B="$TESTDIR/repo-b"
12
+ mkdir -p "$REPO_A" "$REPO_B"
13
+
14
+ echo "=== Initializing repo A with a file ==="
15
+ echo "initial" > "$REPO_A/initial.txt"
16
+ cd "$REPO_A"
17
+ node "$PUSHWORK_CLI" init .
18
+
19
+ echo ""
20
+ echo "=== Cloning to repo B ==="
21
+ ROOT_URL=$(node "$PUSHWORK_CLI" url)
22
+ echo "Root URL: $ROOT_URL"
23
+ cd "$TESTDIR"
24
+ node "$PUSHWORK_CLI" clone "$ROOT_URL" "$REPO_B"
25
+
26
+ echo ""
27
+ echo "=== On B: Create file in 2-level nested subdirectory ==="
28
+ mkdir -p "$REPO_B/rlpjug/ewsv"
29
+ echo "" > "$REPO_B/rlpjug/ewsv/sneked.txt"
30
+
31
+ echo ""
32
+ echo "=== Sync round 1: A (no changes) ==="
33
+ cd "$REPO_A"
34
+ node "$PUSHWORK_CLI" sync
35
+
36
+ echo ""
37
+ echo "=== Sync round 1: B (push new nested file) ==="
38
+ cd "$REPO_B"
39
+ node "$PUSHWORK_CLI" sync
40
+
41
+ echo ""
42
+ echo "=== Sync round 2: A (pull B's changes) ==="
43
+ cd "$REPO_A"
44
+ node "$PUSHWORK_CLI" sync
45
+
46
+ echo ""
47
+ echo "=== Sync round 2: B (confirm) ==="
48
+ cd "$REPO_B"
49
+ node "$PUSHWORK_CLI" sync
50
+
51
+ echo ""
52
+ echo "=== Verification ==="
53
+ echo "Files in A:"
54
+ find "$REPO_A" -type f \( -name "*.txt" -o -name "*.md" \) | grep -v "\.pushwork" | sed "s|$REPO_A/||" | sort
55
+
56
+ echo ""
57
+ echo "Files in B:"
58
+ find "$REPO_B" -type f \( -name "*.txt" -o -name "*.md" \) | grep -v "\.pushwork" | sed "s|$REPO_B/||" | sort
59
+
60
+ echo ""
61
+ if [ -f "$REPO_A/rlpjug/ewsv/sneked.txt" ]; then
62
+ echo "✅ SUCCESS: Nested file synced to A"
63
+ else
64
+ echo "❌ FAILURE: Nested file did NOT sync to A"
65
+ echo ""
66
+ echo "Let's check if directories exist:"
67
+ echo "A has rlpjug dir: $([ -d "$REPO_A/rlpjug" ] && echo YES || echo NO)"
68
+ echo "A has rlpjug/ewsv dir: $([ -d "$REPO_A/rlpjug/ewsv" ] && echo YES || echo NO)"
69
+ fi
70
+
71
+ echo ""
72
+ echo "Test directory: $TESTDIR"
73
+
File without changes
File without changes
File without changes
File without changes