{"id":15048464,"url":"https://github.com/creationix/js-github","last_synced_at":"2025-04-13T06:34:56.354Z","repository":{"id":57283149,"uuid":"14316123","full_name":"creationix/js-github","owner":"creationix","description":"An implementation of the js-git interface that mounts a live github repo.","archived":false,"fork":false,"pushed_at":"2018-08-02T20:32:33.000Z","size":76,"stargazers_count":164,"open_issues_count":4,"forks_count":33,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-10T22:37:59.400Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/creationix.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}},"created_at":"2013-11-11T23:01:51.000Z","updated_at":"2024-09-20T06:00:39.000Z","dependencies_parsed_at":"2022-09-17T12:50:34.318Z","dependency_job_id":null,"html_url":"https://github.com/creationix/js-github","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fjs-github","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fjs-github/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fjs-github/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fjs-github/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creationix","download_url":"https://codeload.github.com/creationix/js-github/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248674920,"owners_count":21143761,"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-09-24T21:13:18.839Z","updated_at":"2025-04-13T06:34:56.320Z","avatar_url":"https://github.com/creationix.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"js-github\n=========\n\nA [js-git][] mixin that uses github as the data storage backend.\n\nThis allows live mounting of github repos without cloning or pushing.\n\nIt's implemented as a [js-git][] mixin that implements the storage backend\nusing Github's [Git Data][] API using REST calls.\n\nThis will work in the browser or in node.js.  Technically an access token isn't\nrequired to read public repositories, but you will be rate-limited to a very\nsmall amount of requests per hour.  With an auth token, you will be able to do\nmore, and depending on the access of the token you can read private repos or\nwrite to repos.\n\nI highly reccommend using a local cache in IndexedDB or LevelDB or something\navailable on your platform.  This way you never request resources you've asked\nfor before and can do more work without hitting the rate limit.\n\nHere is a sample config for a chrome app that uses IDB for a local cache:\n\n```js\n// Start out the normal way with a plain object.\nvar repo = {};\n\n// This only works for normal repos.  Github doesn't allow access to gists as\n// far as I can tell.\nvar githubName = \"creationix/js-github\";\n\n// Your user can generate these manually at https://github.com/settings/tokens/new\n// Or you can use an oauth flow to get a token for the user.\nvar githubToken = \"8fe7e5ad65814ea315daad99b6b65f2fd0e4c5aa\";\n\n// Mixin the main library using github to provide the following:\n// - repo.loadAs(type, hash) =\u003e value\n// - repo.saveAs(type, value) =\u003e hash\n// - repo.listRefs(filter='') =\u003e [ refs ]\n// - repo.readRef(ref) =\u003e hash\n// - repo.updateRef(ref, hash) =\u003e hash\n// - repo.deleteRef(ref) =\u003e null\n// - repo.createTree(entries) =\u003e hash\n// - repo.hasHash(hash) =\u003e has\nrequire('js-github/mixins/github-db')(repo, githubName, githubToken);\n\n// Github has this built-in, but it's currently very buggy so we replace with\n// the manual implementation in js-git.\nrequire('js-git/mixins/create-tree')(repo);\n\n// Cache github objects locally in indexeddb\nvar db = require('js-git/mixins/indexed-db')\nrequire('js-git/mixins/add-cache')(repo, db);\n\n// Cache everything except blobs over 100 bytes in memory.\n// This makes path-to-hash lookup a sync operation in most cases.\nrequire('js-git/mixins/mem-cache')(repo);\n\n// Combine concurrent read requests for the same hash\nrequire('js-git/mixins/read-combiner')(repo);\n\n// Add in value formatting niceties.  Also adds text and array types.\nrequire('js-git/mixins/formats')(repo);\n\n// Browser only: we need to initialize the indexeddb\ndb.init(function(err) {\n  if (err) throw err;\n});\n```\n\nNote that this backend does not provide `loadRaw` or `saveRaw` and can't be used\nwith the `pack-ops` mixin required for clone, push, and pull.  The good news is\nyou don't need those since all changes are happening on github directly.  If you\nwant to \"push\" a new commit, simply update the ref on the repo and it will be\nlive.\n\nSo, here is an example to load `README.md` from an existing repo, change it to\nall uppercase the save it back as a new commit.\n\n```js\n// I'm using generator syntax, but callback style also works.\n// See js-git main docs for more details.\nvar run = require('gen-run');\nrun(function* () {\n  var headHash = yield repo.readRef(\"refs/heads/master\");\n  var commit = yield repo.loadAs(\"commit\", headHash);\n  var tree = yield repo.loadAs(\"tree\", commit.tree);\n  var entry = tree[\"README.md\"];\n  var readme = yield repo.loadAs(\"text\", entry.hash);\n\n  // Build the updates array\n  var updates = [\n    {\n      path: \"README.md\", // Update the existing entry\n      mode: entry.mode,  // Preserve the mode (it might have been executible)\n      content: readme.toUpperCase() // Write the new content\n    }\n  ];\n  // Based on the existing tree, we only want to update, not replace.\n  updates.base = commit.tree;\n\n  // Create the new file and the updated tree.\n  var treeHash = yield repo.createTree(updates);\n```\n\nAt this point, the new data is live on github, but not visible as it if wasn't\npushed.  If we want to make the change permanent, we need to create a new commit\nand move the master ref to point to it.\n\n```js\n  var commitHash = yield repo.saveAs(\"commit\", {\n    tree: treeHash,\n    author: {\n      name: \"Tim Caswell\",\n      email: \"tim@creationix.com\"\n    },\n    parent: headHash,\n    message: \"Change README.md to be all uppercase using js-github\"\n  });\n\n  // Now we can browse to this commit by hash, but it's still not in master.\n  // We need to update the ref to point to this new commit.\n\n  yield repo.updateRef(\"refs/heads/master\", commitHash);\n});\n```\n\nI tested this on this repo.  Here is the [commit](https://github.com/creationix/js-github/commit/b75c1114cdb5bc85b485b7f6d4cb830595c6cfc1)\n\n[js-git]: https://github.com/creationix/js-git.git\n[Git Data]: https://developer.github.com/v3/git/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fjs-github","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreationix%2Fjs-github","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fjs-github/lists"}