{"id":25932486,"url":"https://github.com/guest271314/native-messaging-file-writer","last_synced_at":"2025-03-04T00:37:55.297Z","repository":{"id":280378196,"uuid":"941792324","full_name":"guest271314/native-messaging-file-writer","owner":"guest271314","description":"Write files directly to local file system from arbitrary Web pages","archived":false,"fork":false,"pushed_at":"2025-03-03T04:26:50.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-03T04:30:00.579Z","etag":null,"topics":["file-writer","filesystem","javascript","native-messaging","native-messaging-host"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guest271314.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-03T03:58:33.000Z","updated_at":"2025-03-03T04:26:53.000Z","dependencies_parsed_at":"2025-03-03T04:40:12.174Z","dependency_job_id":null,"html_url":"https://github.com/guest271314/native-messaging-file-writer","commit_stats":null,"previous_names":["guest271314/native-messaging-file-writer"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guest271314%2Fnative-messaging-file-writer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guest271314%2Fnative-messaging-file-writer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guest271314%2Fnative-messaging-file-writer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guest271314%2Fnative-messaging-file-writer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guest271314","download_url":"https://codeload.github.com/guest271314/native-messaging-file-writer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241763766,"owners_count":20016161,"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":["file-writer","filesystem","javascript","native-messaging","native-messaging-host"],"created_at":"2025-03-04T00:37:54.630Z","updated_at":"2025-03-04T00:37:55.255Z","avatar_url":"https://github.com/guest271314.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"## native-messaging-file-writer\n\n\n### Synposis\nWrite files directly to local file system from arbitrary Web pages. Use `externally_connectable` to connect to the MV3 `ServiceWorker` from arbitrary Web pages. In the MV3 `ServiceWorker` use `sendNativeMessage()` to start local Node.js built-in `node:http2` HTTP/2 server. Make `fetch()` request from Web page to local server, with `duplex` set to `\"half\"` for the capability to set a `ReadableStream` as `body` for `POST`, and/or `query` request. Write file to file system. Return `Promise` fulfilled to an [`\u003cfs.Stats\u003e`](https://nodejs.org/api/fs.html#class-fsstats) object, or message from `DOMException` `ABORT_ERR`.\n\n#### Motivation\n\n- [Emphasising the importance of in-place writes #260](https://github.com/WICG/file-system-access/issues/260)\n- [Native FS writer makes write changes to a temp file instead of the actual file](https://issues.chromium.org/issues/40743502)\n\n### Installation\n\n#### Create self-signed certificate for HTTP/2 server\n\nCreate self-signed certificates for use with HTTP/2 server, as described [here](https://github.com/GoogleChrome/samples/blob/gh-pages/webtransport/webtransport_server.py#L49C1-L75C45)\n\n```\n# As an alternative, Chromium can be instructed to trust a self-signed\n# certificate using command-line flags.  Here are step-by-step instructions on\n# how to do that:\n#\n#   1. Generate a certificate and a private key:\n#         openssl req -newkey rsa:2048 -nodes -keyout certificate.key \\\n#                   -x509 -out certificate.pem -subj '/CN=Test Certificate' \\\n#                   -addext \"subjectAltName = DNS:localhost\"\n#\n#   2. Compute the fingerprint of the certificate:\n#         openssl x509 -pubkey -noout -in certificate.pem |\n#                   openssl rsa -pubin -outform der |\n#                   openssl dgst -sha256 -binary | base64\n#      The result should be a base64-encoded blob that looks like this:\n#          \"Gi/HIwdiMcPZo2KBjnstF5kQdLI5bPrYJ8i3Vi6Ybck=\"\n#\n#   3. Pass a flag to Chromium indicating what host and port should be allowed\n#      to use the self-signed certificate.  For instance, if the host is\n#      localhost, and the port is 4433, the flag would be:\n#         --origin-to-force-quic-on=localhost:4433\n#\n#   4. Pass a flag to Chromium indicating which certificate needs to be trusted.\n#      For the example above, that flag would be:\n#         --ignore-certificate-errors-spki-list=Gi/HIwdiMcPZo2KBjnstF5kQdLI5bPrYJ8i3Vi6Ybck=\n#\n# See https://www.chromium.org/developers/how-tos/run-chromium-with-flags for\n# details on how to run Chromium with flags.\n```\n\n#### Programmatic installation\nClone repository\n```\ngit clone https://github.com/guest271314/native-messaging-file-writer\n```\n\nInstall Native Messaging host manifest (see [Native manifests](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests)) to Chromium or Chrome user data directory. `install-host.js` currently points to `~/.config/chromium`. Modify to use path to the version of `chrome` being used, e.g., `~/.config/google-chrome`\n```\nnode install-host.js\n```\n#### Manual installation\n\n1. Navigate to `chrome://extensions`.\n2. Toggle `Developer mode`.\n3. Click `Load unpacked`.\n4. Select `native-messaging-file-writer` folder.\n5. Note the generated extension ID.\n6. Open `nm_file_writer.json` in a text editor, set `\"path\"` to absolute path of `nm_file_writer.js` and `chrome-extension://\u003cID\u003e/` using ID from 5 in `\"allowed_origins\"` array. \n7. Copy the `nm_file_writer.json` file to Chrome or Chromium configuration folder, e.g., Chromium on Linux `~/.config/chromium/NativeMessagingHosts`; Chrome dev channel on Linux `~/.config/google-chrome-unstable/NativeMessagingHosts` [User Data Directory - Default Location](https://chromium.googlesource.com/chromium/src.git/+/HEAD/docs/user_data_dir.md#Default-Location).\n8. Set `nm_file_writer.js` permission to executable, e.g., `chmod u+x nm_file_writer.js`.\n9. Reload the extension.\n\n### Usage\n\n`file-writer.js` is a content script that defines `FileWriter` class on all HTTP/HTTPS Web pages at `document_start`.\n\nUse `FileWriter` class in DevTools, Snippets, or other user scripts. The constructor expects an options plain JavaScript object containing `fileName`, `mode` ([Sets the file mode (permission and sticky bits) if the file is created. Default: `0o666` (readable and writable)](https://nodejs.org/api/fs.html#fspromisesopenpath-flags-mode) that are passed to a Node.js [`filehandle.createWriteStream()`](https://nodejs.org/api/fs.html#filehandlecreatewritestream).\n\n```\nvar readable = ... // WHATWG ReadableStream\nvar fs = new FileWriter({\n  fileName: \"/home/user/Downloads/node\", // File path to write to\n  mode: 0o764 // Mode \n}, \"/home/user/native-messaging-file-writer\"); // Path to unpacked extension directory\nfs.write(readable).then(console.log).catch(console.warn);\n// Abort writing to the file\nfs.abort(\"reason\");\n```\n\nUsing a `TransformStream` to write data to the file using a `WritableStreamDefaultWriter`\n\n```\nvar rs = ...; \nvar {\n  readable,\n  writable\n} = new TransformStream({\n  transform(value, c) {\n    c.enqueue(value);\n  },\n  flush() {\n    console.log(\"flush\");\n  }\n});\nvar writer = writable.getWriter();\nwriter.closed.then(console.log).catch(console.warn);\nvar fs = new FileWriter({\n  fileName: \"/home/user/Downloads/node\",\n  mode: 0o764\n}, \"/home/user/native-messaging-file-writer\");\nfs.write(readable).then(console.log).catch(console.warn);\nconsole.log(writer.desiredSize);\n// Abort writing to the file\n// await writer.abort(\"Abort!\").then(console.log).catch(console.warn);\nconsole.log(writer.desiredSize);\nfor await (const data of rs) {\n  try {\n    await writer.ready;\n    await writer.write(data).catch(console.warn);\n  } catch (e) {\n    console.log(e);\n    break;\n  }\n}\nconsole.log(writer.desiredSize);\nif (writer.desiredSize !== null) {\n  await writer.close().catch(console.warn);\n}\n```\n\nWhen the file is written without errors or for the WHATWG `fetch()` request being aborted, ultimately fulfills to a `stat()` object with `fileName` included, e.g., writing `node` nightly to file system\n\n```\n{\n  \"fileName\": \"/home/user/Downloads/node\",\n  \"dev\": 27,\n  \"mode\": 33252,\n  \"nlink\": 1,\n  \"uid\": 1000,\n  \"gid\": 1000,\n  \"rdev\": 0,\n  \"blksize\": 4096,\n  \"ino\": 173609,\n  \"size\": 125675720,\n  \"blocks\": 245464,\n  \"atimeMs\": 1740956750631.332,\n  \"mtimeMs\": 1740979068259.272,\n  \"ctimeMs\": 1740979068259.272,\n  \"birthtimeMs\": 1740956750631.332\n}\n```\n\nWhen the streaming request is aborted\n\n```\nfs.abort(\"Abort file stream\");\n// Or when using a WritableStreamDefaultWriter\nawait writer.abort(\"Abort file stream\").then(console.log).catch(console.warn);\n// Abort file stream\n// The operation was aborted\n```\n\n### License\nDo What the Fuck You Want to Public License [WTFPLv2](http://www.wtfpl.net/about/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguest271314%2Fnative-messaging-file-writer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguest271314%2Fnative-messaging-file-writer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguest271314%2Fnative-messaging-file-writer/lists"}