{"id":18320859,"url":"https://github.com/bazaarvoice/swat-proxy","last_synced_at":"2025-04-05T22:32:04.767Z","repository":{"id":39262143,"uuid":"57311633","full_name":"bazaarvoice/swat-proxy","owner":"bazaarvoice","description":"A node.js proxy server that makes injecting applications or prototype applications onto potential client websites easy.","archived":false,"fork":false,"pushed_at":"2016-09-29T22:41:19.000Z","size":52,"stargazers_count":51,"open_issues_count":4,"forks_count":9,"subscribers_count":23,"default_branch":"master","last_synced_at":"2024-08-19T02:42:37.233Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bazaarvoice.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-28T15:16:43.000Z","updated_at":"2024-01-28T21:45:35.000Z","dependencies_parsed_at":"2022-09-02T18:21:17.989Z","dependency_job_id":null,"html_url":"https://github.com/bazaarvoice/swat-proxy","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bazaarvoice%2Fswat-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bazaarvoice%2Fswat-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bazaarvoice%2Fswat-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bazaarvoice%2Fswat-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bazaarvoice","download_url":"https://codeload.github.com/bazaarvoice/swat-proxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223221181,"owners_count":17108525,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T18:17:40.818Z","updated_at":"2024-11-05T18:17:41.367Z","avatar_url":"https://github.com/bazaarvoice.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/bazaarvoice/swat-proxy.svg?branch=master)](https://travis-ci.org/bazaarvoice/swat-proxy)\n\n# swat-proxy\n\nswat-proxy is a tool to easily inject content, such as Javascript web applications,\nonto third party web pages. This is useful in the development of applications\nintended for third party use. It can also be useful in establishing a general\nproxy server for use in applications that might need to regularly transform\nrequested content.\n\nswat-proxy acts as a man-in-the-middle between browser and server, altering the\nserver response for specified pages. The browser renders the modified response\nas if it came directly from the server itself. This allows viewing and\ninteracting with content on the target page.\n\nThe name swat-proxy derives from the name of the Small Web-Apps Technology team\nwhose members built the first iteration of this tool.\n\n## Installation\n\n```bash\nnpm install swat-proxy\n```\n\n## Quick Start\n\n### Write a script that runs the Proxy\n\n```js\n/* Filename: do-proxy.js */\n\n// Import swat-proxy.\nvar swat_proxy = require('swat-proxy');\n\n// Add some JS to the end of the Google homepage.\nswat_proxy.proxy('http://www.google.com/', {\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cscript\u003e alert (\"Hello from swat-proxy!\"); \u003c/script\u003e'\n});\n\n// Start the proxy server.\nswat_proxy.start();\n```\n\n### Run your Script\n\n```bash\nnode do-proxy.js\n```\n\nBy default swat-proxy runs on port `8063` so set your browser to use the proxy\nat `127.0.0.1:8063` and navigate to `http://www.google.com/`.\n\nYou should be immediately presented with the greeting alert, and you can\n`View Page Source` to see that the Javascript was inserted before the closing\nbody tag (`\u003c/body\u003e`).\n\n## Usage\n\nLet us dig a little deeper.\n\n### Proxy Blocks\n\nA call to `.proxy` is referred to as a *proxy block*:\n\n```js\nswat_proxy.proxy('http://www.google.com/', {\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cscript\u003e alert (\"Hello from swat-proxy!\"); \u003c/script\u003e'\n});\n```\n\nThe way to read this proxy block is:\n\n\u003e *APPEND* `content` to the *body* of `http://www.google.com`.\n\n#### Removing Proxy Blocks\n\nIn order to prevent memory leaks over the lifetime of potentially long-running\nproxy scripts, when new proxy URLs may be registered in an ad hoc fashion, a\n`.removeProxy` function is also provided. An example usage might look like this:\n\n```js\nvar options = {\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cscript\u003e alert (\"Hello from swat-proxy!\"); \u003c/script\u003e'\n};\n\nswat_proxy.proxy('http://www.google.com/', options);\nswat_proxy.removeProxy('http://www.google.com/', options);\n// OR\nswat_proxy.removeProxy('http://www.google.com/');\n```\n\nNote that any options objects passed to `.removeProxy` are compared by reference,\nnot by value. If you want to remove an options object from your proxy at a future\ntime, you need to store a reference for it in a variable, to be passed later. If\nyou simply want to clear all proxies associated with a given URL, you can ignore\nthe second option and just pass the target URL.\n\n#### Details\n\nLet us break down the parameters of proxy blocks. The most up-to-date\ndocumentation can always be found in the [source code][1], but for convenience\nit is detailed here as well. Refer to the following signature:\n\n```js\nswat_proxy.proxy(url, {\n  selector,\n  manipulation,\n  content,\n  [matchType]\n});\n```\n\n##### URL\n\nThe target URL to inject content into. Example `http://www.google.com/`.\n\nNote that this must match **exactly** to the browser URL - `google.com` will\n**not** match `www.google.com`. In other words, if you point your proxy block at\n`google.com` but navigate to `www.google.com`, your content will not be injected.\n\nThe easiest way to grab your target URL is to navigate to your target page and\ncopy/paste the URL directly into your proxy block code. For example, typing\n`google.com` into Firefox and copy/pasting results in `http://google.com/`. This\nis the value you want to use.\n\n##### selector\n\nA CSS selector to target DOM elements. Examples `body`, `div`, `#id`, `.class`.\n\n##### manipulation\n\n`swat-proxy` provides an enumeration of supported DOM manipulations to be used\nas values for `manipulation`. They are:\n\n  * `APPEND`: Insert `content` as the last child of each of the selected elements.\n  * `PREPEND`: Insert `content` as the first child of each of the selected elements.\n  * `REPLACE`: Replace selected elements with `content`.\n  * `WRAP`: Wrap selected elements with `content`.\n\n`swat-proxy` uses the `cheerio` package under the hood. For more information on\nthese manipulations, see the [cheerio documentation][2].\n\n##### content\n\nA string containing the content to inject, or a function that returns a string of\ncontent to be injected. If passing a function, it will receive the original element's\nmarkup for transformation, and is expected to return the transformed markup. Since\ncontent is injected into an HTML page, it is important to wrap the content with the\nappropriate HTML tags.\n\n##### matchType\n\n`swat-proxy` also provides an enumeration of matchType algorithms for some flexibility\nin the way it matches URLs. For backwards compatibility, this field is optional, and\ndefaults to `EXACT`. The values in the matchType enumeration are:\n\n  * `DOMAIN`: Match against just the domain portion of the url. This includes subdomain.\n  * `EXACT`: Match the url exactly as it's been entered, including query parameters.\n  * `PREFIX`: Match the target URL against the beginning of the requested URL (i.e. URL starts with)\n\nThe `matchType` option is provided as part of the options object(s) passed to the `.proxy`\nfunction, meaning you can provide a different `matchType` parameter for each rule in the\noverall set of options, if you desire different behavior based on the URL stub.\n\n```js\n// HTML Markup.\ncontent: '\u003cdiv id=\"MyWidget\"\u003eThis is my widget!\u003c/div\u003e'\n\n// Some Javascript.\ncontent: '\u003cscript\u003e alert (\"Hello from my widget!\"); \u003c/script\u003e'\n\n// A block of CSS.\ncontent: '\u003cstyle\u003e #MyWidget { font-variant: small-caps; } \u003c/style\u003e'\n```\n\n###### Using React\n\n[React][3] is currently very popular for building front-end user interfaces.\nHere is an example of using React to generate markup to assign to `content`:\n\n```js\n/* Filename: MyWidget.js */\n\nmodule.exports = React.createClass({\n  render: function () {\n    return (\n      \u003cdiv id=\"MyWidget\"\u003eThis is my widget!\u003c/div\u003e\n    );\n  }\n});\n```\n\n```js\n/* Filename: main.js */\n\nvar MyWidget = require('./MyWidget.js');\nconst WidgetFactory = React.createFactory(MyWidget);\nconst widgetContent = ReactDOMServer.renderToStaticMarkup(WidgetFactory());\n\nswat_proxy.proxy(example_url, {\n  selector: example_selector,\n  manipulation: example_manipulation,\n  content: widgetContent\n});\n\n```\n\n### Third Party JS Common Use Case\n\nA common use case for third party Javascript applications is for clients or\ncustomers to place on their page (a) a container `\u003cdiv\u003e` where content should\nappear, and (b) a `\u003cscript\u003e` tag to load the application that will place content\ninto the container element.\n\nThis can be simulated by injecting more than one piece of content into a page\nusing `swat-proxy`.\n\n#### Using an Array\n\nPass an array of manipulation instructions into a single proxy block, like so:\n\n```js\n// Import swat-proxy.\nvar swat_proxy = require('swat-proxy');\n\n// Add a container div and Javascript that populates it to the end of the Google\n// homepage.\nswat_proxy.proxy('http://www.google.com/', [{\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cdiv id=\"MyWidgetContainer\"\u003e\u003c/div\u003e'\n}, {\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cscript\u003edocument.getElementById(\"MyWidgetContainer\").innerHTML = \"Hello from swat-proxy!\";\u003c/script\u003e'\n}]);\n\n// Start the proxy server.\nswat_proxy.start();\n```\n\n#### Multiple Proxy Blocks\n\nThe same result can be achieved using multiple proxy blocks with the same target\nURL:\n\n```js\n// Import swat-proxy.\nvar swat_proxy = require('swat-proxy');\n\n// Add a container div to the end of the Google homepage.\nswat_proxy.proxy('http://www.google.com/', {\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cdiv id=\"MyWidgetContainer\"\u003e\u003c/div\u003e'\n});\n\n// Add Javascript that populates the container div to the end of the Google\n// homepage.\nswat_proxy.proxy('http://www.google.com/', {\n  selector: 'body',\n  manipulation: swat_proxy.Manipulations.APPEND,\n  content: '\u003cscript\u003edocument.getElementById(\"MyWidgetContainer\").innerHTML = \"Hello from swat-proxy!\";\u003c/script\u003e'\n});\n\n// Start the proxy server.\nswat_proxy.start();\n```\n\n## FAQ\n\n**Q:** Why is my content not injected?\n**A:** The `.start` function supports a `debugMode` property that can hopefully\nhelp:\n\n```js\n// Start the proxy server in debug mode.\nswat_proxy.start({ debugMode: true });\n```\n\nThis will log each request URL from to the console and notify when that URL\nmatches the URL of any proxy block. If there are no matches, revisit the proxy\nblock's [url configuration](#url).\n\n---\n\n**Q:** I keep getting `Error: listen EADDRINUSE :::8063`?\n**A:** The target port (`8063`) is currently in use, most likely because another\ninstance of the proxy server is running. Shut down that process and try again.\nIf another service is using that port, it is possible to instruct `swat-proxy`\nto use a different port:\n\n```js\n// Start the proxy server on port 8064.\nswat_proxy.start({ port: 8064 });\n```\n\n---\n\n**Q:** My injection worked yesterday and today it doesn't - I haven't changed\nanything!\n**A:** Many third parties change their web pages on a frequent basis. Ensure\nthat the selectors used in code and configuration still exist.\n\n## Contributing\n\nPlease refer to the [Contributing Guidelines][4].\n\n[1]: https://github.com/bazaarvoice/swat-proxy/blob/master/src/proxy.js\n[2]: https://github.com/cheeriojs/cheerio\n[3]: https://facebook.github.io/react/\n[4]: .github/CONTRIBUTING.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbazaarvoice%2Fswat-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbazaarvoice%2Fswat-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbazaarvoice%2Fswat-proxy/lists"}