diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md
index 380cfcc1f..30a3bb705 100644
--- a/CONTRIBUTE.md
+++ b/CONTRIBUTE.md
@@ -12,11 +12,13 @@ StirlingPDF aims to support as many types of operations as possible, including s
 ### Adding a shared (server + client) operation
 1. Add the code for the operation to a new file in the [functions folder](/shared-operations/functions/). 
 
-> **NOTE:** all functions in these files use **dependency injection** (see existing functions for examples).
+> **NOTE:** many of the functions in these files use **dependency injection** (see impose for an example).
 > 
-> **Explanation:** Because the server and client import libraries in different ways, we import the library as needed in the wrapper module, then pass into the a operation function as a parameter.
+> **Explanation:** Because some libraries need to be imported in different ways. We import the library as needed in the ```pdf-operations.js``` files, then pass the required library objects into the operation function as a parameter.
 
-2. Now that we have the function code, we need to tell the other modules that it exists. Edit the [server operations](/server-node/public/pdf-operations.js) and the [client operations](/client-ionic/src/utils/pdf-operations.js) files to add your new operation! (Try to follow existing patterns where possible, keep the added operations in alphabetical order in the files).
+2. Now that we have the function code, we need to tell the other modules that it exists. Edit the [server operations](/server-node/src/pdf-operations.js) and the [client operations](/client-ionic/src/utils/pdf-operations.ts) files to add your new operation! (Try to follow existing patterns where possible, keep the added operations in alphabetical order in the files).
+   
+3. If you added a wrapper function to the [client operations](/client-ionic/src/utils/pdf-operations.ts) file, you will also need to add the TypeScript declarations to the [declaration](/client-ionic/declarations/shared-operations.d.ts) file. See the other module declarations for examples.
 
 ### Adding a server only operation
 > WIP
\ No newline at end of file
diff --git a/server-node/routes/api/operations.js b/server-node/routes/api/operations.js
index d8392c784..8de4bcc52 100644
--- a/server-node/routes/api/operations.js
+++ b/server-node/routes/api/operations.js
@@ -1,5 +1,6 @@
 
-import { rotatePages } from '../../src/pdf-operations.js'
+import { rotatePages } from '../../src/pdf-operations.js';
+import { respondWithBinaryPdf } from '../../src/utils/endpoint-utils.js';
 
 import express from 'express';
 const router = express.Router();
@@ -8,18 +9,9 @@ const upload = multer();
 
 router.post('/rotate-pdf', upload.single("pdfFile"), async function(req, res, next) {
     console.debug("rotating pdf:", req.file)
-
     const rotated = await rotatePages(req.file.buffer, 90)
-
-    // add '_rotated' just before the file extension
-    const newFilename = req.file.originalname.replace(/(\.[^.]+)$/, '_rotated$1');
-
-    res.writeHead(200, {
-        'Content-Type': "application/pdf",
-        'Content-disposition': 'attachment;filename=' + newFilename,
-        'Content-Length': rotated.length
-    });
-    res.end(Buffer.from(rotated, 'binary'))
+    const newFilename = req.file.originalname.replace(/(\.[^.]+)$/, '_rotated$1'); // add '_rotated' just before the file extension
+    respondWithBinaryPdf(res, rotated, newFilename);
 });
 
 export default router;
\ No newline at end of file
diff --git a/server-node/src/utils/endpoint-utils.js b/server-node/src/utils/endpoint-utils.js
new file mode 100644
index 000000000..42932388f
--- /dev/null
+++ b/server-node/src/utils/endpoint-utils.js
@@ -0,0 +1,9 @@
+
+export function respondWithBinaryPdf(res, buffer, filename) {
+    res.writeHead(200, {
+        'Content-Type': "application/pdf",
+        'Content-disposition': 'attachment;filename=' + filename,
+        'Content-Length': buffer.length
+    });
+    res.end(Buffer.from(buffer, 'binary'))
+}