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.
- package/README.md +23 -21
- package/dist/cli/commands.d.ts +6 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +114 -4
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/change-detection.d.ts.map +1 -1
- package/dist/core/change-detection.js +27 -9
- package/dist/core/change-detection.js.map +1 -1
- package/dist/core/move-detection.d.ts.map +1 -1
- package/dist/core/move-detection.js +8 -2
- package/dist/core/move-detection.js.map +1 -1
- package/dist/core/sync-engine.d.ts +4 -0
- package/dist/core/sync-engine.d.ts.map +1 -1
- package/dist/core/sync-engine.js +263 -7
- package/dist/core/sync-engine.js.map +1 -1
- package/dist/types/documents.d.ts +2 -0
- package/dist/types/documents.d.ts.map +1 -1
- package/dist/types/documents.js.map +1 -1
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +7 -1
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/network-sync.d.ts.map +1 -1
- package/dist/utils/network-sync.js +16 -3
- package/dist/utils/network-sync.js.map +1 -1
- package/package.json +30 -30
- package/src/cli/commands.ts +162 -8
- package/src/cli.ts +40 -0
- package/src/core/change-detection.ts +25 -12
- package/src/core/move-detection.ts +8 -2
- package/src/core/sync-engine.ts +270 -7
- package/src/types/documents.ts +2 -0
- package/src/utils/fs.ts +7 -3
- package/src/utils/network-sync.ts +19 -3
- package/test/integration/clone-test.sh +0 -0
- package/test/integration/conflict-resolution-test.sh +0 -0
- package/test/integration/debug-both-nested.sh +74 -0
- package/test/integration/debug-concurrent-nested.sh +87 -0
- package/test/integration/debug-nested.sh +73 -0
- package/test/integration/deletion-behavior-test.sh +0 -0
- package/test/integration/deletion-sync-test-simple.sh +0 -0
- package/test/integration/deletion-sync-test.sh +0 -0
- package/test/integration/full-integration-test.sh +0 -0
- package/test/integration/fuzzer.test.ts +865 -0
- package/test/integration/manual-sync-test.sh +84 -0
- package/test/run-tests.sh +0 -0
- package/test/unit/sync-convergence.test.ts +493 -0
- package/tools/browser-sync/README.md +0 -116
- package/tools/browser-sync/package.json +0 -44
- package/tools/browser-sync/patchwork.json +0 -1
- package/tools/browser-sync/pnpm-lock.yaml +0 -4202
- package/tools/browser-sync/src/components/BrowserSyncTool.tsx +0 -599
- package/tools/browser-sync/src/index.ts +0 -20
- package/tools/browser-sync/src/polyfills.ts +0 -31
- package/tools/browser-sync/src/styles.css +0 -290
- package/tools/browser-sync/src/types.ts +0 -27
- 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
|
-
//
|
|
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(
|
|
153
|
+
console.log(`✅ All documents synced to network (took ${elapsed}ms)`);
|
|
139
154
|
}
|
|
140
155
|
} catch (error) {
|
|
141
|
-
|
|
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
|