{"id":13462581,"url":"https://github.com/zendesk/cross-storage","last_synced_at":"2025-05-14T03:08:41.286Z","repository":{"id":19932154,"uuid":"23198683","full_name":"zendesk/cross-storage","owner":"zendesk","description":"Cross domain local storage, with permissions","archived":false,"fork":false,"pushed_at":"2023-04-09T16:12:08.000Z","size":236,"stargazers_count":2223,"open_issues_count":14,"forks_count":181,"subscribers_count":459,"default_branch":"master","last_synced_at":"2025-04-03T09:05:35.744Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zendesk.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}},"created_at":"2014-08-21T18:39:42.000Z","updated_at":"2025-03-17T06:37:39.000Z","dependencies_parsed_at":"2024-01-19T11:08:22.016Z","dependency_job_id":"1844a8a3-f02c-4656-a04a-4755769a0056","html_url":"https://github.com/zendesk/cross-storage","commit_stats":{"total_commits":137,"total_committers":7,"mean_commits":"19.571428571428573","dds":"0.058394160583941646","last_synced_commit":"9db1cef7f8903baad72236f392701c4b71a24eba"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fcross-storage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fcross-storage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fcross-storage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fcross-storage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zendesk","download_url":"https://codeload.github.com/zendesk/cross-storage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248261932,"owners_count":21074225,"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-07-31T12:00:52.652Z","updated_at":"2025-04-10T17:19:11.369Z","avatar_url":"https://github.com/zendesk.png","language":"JavaScript","funding_links":[],"categories":["Uncategorized","JavaScript","Storage","Storage [🔝](#readme)","17. 本地存储 ##","存储","17. 本地存储"],"sub_categories":["Uncategorized","Runner","13.20 视差滚动(Parallax Scrolling) ###","运行器","13.20 视差滚动(Parallax Scrolling)","运行器e2e测试"],"readme":"![cross-storage](https://github.com/zendesk/cross-storage/raw/master/media/logo.png)\n\nCross domain local storage, with permissions. Enables multiple browser\nwindows/tabs, across a variety of domains, to share a single localStorage.\nFeatures an API using ES6 promises.\n\n[![Build Status](https://travis-ci.org/zendesk/cross-storage.svg?branch=master)](https://travis-ci.org/zendesk/cross-storage)\n\n* [Overview](#overview)\n* [Installation](#installation)\n* [API](#api)\n  * [CrossStorageHub.init(permissions)](#crossstoragehubinitpermissions)\n  * [new CrossStorageClient(url, \\[opts\\])](#new-crossstorageclienturl-opts)\n  * [CrossStorageClient.prototype.onConnect()](#crossstorageclientprototypeonconnect)\n  * [CrossStorageClient.prototype.set(key, value)](#crossstorageclientprototypesetkey-value)\n  * [CrossStorageClient.prototype.get(key1, \\[key2\\], \\[...\\])](#crossstorageclientprototypegetkey1-key2-)\n  * [CrossStorageClient.prototype.del(key1, \\[key2\\], \\[...\\])](#crossstorageclientprototypedelkey1-key2-)\n  * [CrossStorageClient.prototype.getKeys()](#crossstorageclientprototypegetkeys)\n  * [CrossStorageClient.prototype.clear()](#crossstorageclientprototypeclear)\n  * [CrossStorageClient.prototype.close()](#crossstorageclientprototypeclose)\n* [Compatibility](#compatibility)\n* [Compression](#compression)\n* [Building](#building)\n* [Tests](#tests)\n* [Copyright and license](#copyright-and-license)\n\n## Overview\n\nThe library is a convenient alternative to sharing a root domain cookie.\nUnlike cookies, your client-side data isn't limited to a few kilobytes - you\nget up to 2.49M chars. For a client-heavy application, you can potentially\nshave a few KB off your request headers by avoiding cookies. This is all thanks\nto LocalStorage, which is available in IE 8+, FF 3.5+, Chrome 4+, as well as a\nmajority of mobile browsers. For a list of compatible browsers, refer to\n[caniuse](http://caniuse.com/#feat=namevalue-storage).\n\nHow does it work? The library is divided into two types of components: hubs\nand clients. The hubs reside on a host of choice and interact directly with\nthe LocalStorage API. The clients then load said hub over an embedded iframe\nand post messages, requesting data to be stored, retrieved, and deleted. This\nallows multiple clients to access and share the data located in a single store.\n\nCare should be made to limit the origins of the bidirectional communication.\nAs such, when initializing the hub, an array of permissions objects is passed.\nAny messages from clients whose origin does not match the pattern are ignored,\nas well as those not within the allowed set of methods. The set of permissions\nare enforced thanks to the same-origin policy. However, keep in mind that any\nuser has full control of their local storage data - it's still client data.\nThis only restricts access on a per-domain or web app level.\n\n**Hub**\n\n``` javascript\n// Config s.t. subdomains can get, but only the root domain can set and del\nCrossStorageHub.init([\n  {origin: /\\.example.com$/,            allow: ['get']},\n  {origin: /:\\/\\/(www\\.)?example.com$/, allow: ['get', 'set', 'del']}\n]);\n```\n\nNote the $ for matching the end of the string. The RegExps in the above example\nwill match origins such as valid.example.com, but not\ninvalid.example.com.malicious.com.\n\n**Client**\n\n``` javascript\nvar storage = new CrossStorageClient('https://store.example.com/hub.html');\n\nstorage.onConnect().then(function() {\n  return storage.set('newKey', 'foobar');\n}).then(function() {\n  return storage.get('existingKey', 'newKey');\n}).then(function(res) {\n  console.log(res.length); // 2\n}).catch(function(err) {\n  // Handle error\n});\n```\n\n## Installation\n\nThe library can be installed via bower:\n\n``` bash\nbower install cross-storage\n```\n\nOr using npm:\n\n``` bash\nnpm install cross-storage\n```\n\nalong with browserify:\n\n``` javascript\nvar CrossStorageClient = require('cross-storage').CrossStorageClient;\nvar CrossStorageHub    = require('cross-storage').CrossStorageHub;\n```\n\nWhen serving the hub, you may want to set the CORS and CSP headers for your\nserver depending on client/hub location. For example:\n\n``` javascript\n{\n  'Access-Control-Allow-Origin':  '*',\n  'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',\n  'Access-Control-Allow-Headers': 'X-Requested-With',\n  'Content-Security-Policy':      \"default-src 'unsafe-inline' *\",\n  'X-Content-Security-Policy':    \"default-src 'unsafe-inline' *\",\n  'X-WebKit-CSP':                 \"default-src 'unsafe-inline' *\",\n}\n```\n\nIf using inline JS to create the hub, you'll need to specify `unsafe-inline`\nfor the CSP headers. Otherwise, it can be left out if simply including the\ninit code via another resource.\n\n## API\n\n#### CrossStorageHub.init(permissions)\n\nAccepts an array of objects with two keys: origin and allow. The value\nof origin is expected to be a RegExp, and allow, an array of strings.\nThe cross storage hub is then initialized to accept requests from any of\nthe matching origins, allowing access to the associated lists of methods.\nMethods may include any of: get, set, del, getKeys and clear. A 'ready'\nmessage is sent to the parent window once complete.\n\n``` javascript\nCrossStorageHub.init([\n  {origin: /localhost:3000$/, allow: ['get', 'set', 'del', 'getKeys', 'clear']}\n]);\n```\n\n#### new CrossStorageClient(url, [opts])\n\nConstructs a new cross storage client given the url to a hub. By default,\nan iframe is created within the document body that points to the url. It\nalso accepts an options object, which may include a timeout, frameId, and\npromise. The timeout, in milliseconds, is applied to each request and\ndefaults to 5000ms. The options object may also include a frameId,\nidentifying an existing frame on which to install its listeners. If the\npromise key is supplied the constructor for a Promise, that Promise library\nwill be used instead of the default window.Promise.\n\n``` javascript\nvar storage = new CrossStorageClient('http://localhost:3000/hub.html');\n\nvar storage = new CrossStorageClient('http://localhost:3000/hub.html', {\n  timeout: 5000,\n  frameId: 'storageFrame'\n});\n```\n\n#### CrossStorageClient.prototype.onConnect()\n\nReturns a promise that is fulfilled when a connection has been established\nwith the cross storage hub. Its use is required to avoid sending any\nrequests prior to initialization being complete.\n\n``` javascript\nstorage.onConnect().then(function() {\n  // ready!\n});\n```\n\n#### CrossStorageClient.prototype.set(key, value)\n\nSets a key to the specified value. Returns a promise that is fulfilled on\nsuccess, or rejected if any errors setting the key occurred, or the request\ntimed out.\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.set('key', JSON.stringify({foo: 'bar'}));\n});\n```\n\n#### CrossStorageClient.prototype.get(key1, [key2], [...])\n\nAccepts one or more keys for which to retrieve their values. Returns a\npromise that is settled on hub response or timeout. On success, it is\nfulfilled with the value of the key if only passed a single argument.\nOtherwise it's resolved with an array of values. On failure, it is rejected\nwith the corresponding error message.\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.get('key1');\n}).then(function(res) {\n  return storage.get('key1', 'key2', 'key3');\n}).then(function(res) {\n  // ...\n});\n```\n\n#### CrossStorageClient.prototype.del(key1, [key2], [...])\n\nAccepts one or more keys for deletion. Returns a promise that is settled on\nhub response or timeout.\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.del('key1', 'key2');\n});\n```\n\n#### CrossStorageClient.prototype.getKeys()\n\nReturns a promise that, when resolved, passes an array of keys currently\nin storage.\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.getKeys();\n}).then(function(keys) {\n  // ['key1', 'key2', ...]\n});\n```\n\n#### CrossStorageClient.prototype.clear()\n\nReturns a promise that, when resolved, indicates that all localStorage\ndata has been cleared.\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.clear();\n});\n```\n\n#### CrossStorageClient.prototype.close()\n\nDeletes the iframe and sets the connected state to false. The client can\nno longer be used after being invoked.\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.set('key1', 'key2');\n}).catch(function(err) {\n  // Handle error\n}).then(function() {\n  storage.close();\n});\n```\n\n## Compatibility\n\nFor compatibility with older browsers, simply load a Promise polyfill such as\n[es6-promise](https://github.com/jakearchibald/es6-promise).\n\nYou can also use RSVP or any other ES6 compliant promise library. Supports IE8\nand up using the above polyfill. A JSON polyfill is also required\nfor IE8 in Compatibility View. Also note that `catch` is a reserved word in IE8,\nand so error handling with promises can be done as:\n\n``` javascript\nstorage.onConnect().then(function() {\n  return storage.get('key1');\n}).then(function(res) {\n  // ... on success\n})['catch'](function(err) {\n  // ... on error\n});\n```\n\n**Breaking Changes**\n\nAPI breaking changes were introduced in both 0.6 and 1.0. Refer to\n[releases](https://github.com/zendesk/cross-storage/releases) for details.\n\n**Notes on Safari 7+ (OSX, iOS)**\n\nAll cross-domain local storage access is disabled by default with Safari 7+.\nThis is a result of the \"Block cookies and other website data\" privacy setting\nbeing set to \"From third parties and advertisers\". Any cross-storage client\ncode will not crash, however, it will only have access to a sandboxed, isolated\nlocal storage instance. As such, none of the data previously set by other\norigins will be accessible. If an option, one could fall back to using root\ncookies for those user agents, or requesting the data from a server-side store.\n\n## Compression\n\nMost localStorage-compatible browsers offer at least ~5Mb of storage. But keys\nand values are defined as DOMStrings, which are UTF-8 encoded using single\n16-bit sequences. That means a string of ~2.5 million ASCII characters will use\nup ~5Mb, since they're 2 bytes per char.\n\nIf you need to maximize your storage space, consider using\n[lz-string](https://github.com/pieroxy/lz-string/). For smaller strings, it's\nnot uncommon to see a 50% reduction in size when compressed, which will bring\nyou a lot closer to 5 million characters. At that point, you're only limited by\nthe average compression rate of your strings.\n\n## Building\n\nThe minified, production JavaScript can be generated with gulp by running\n`gulp dist`. If not already on your system, gulp can be installed using\n`npm install -g gulp`\n\n## Tests\n\nTests can be ran locally using `npm test`. Tests are ran using Zuul, and\nthe Travis CI build uses Sauce Labs for multi-browser testing as well.\n\n## Copyright and license\n\nCopyright 2016 Zendesk\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthis file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzendesk%2Fcross-storage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzendesk%2Fcross-storage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzendesk%2Fcross-storage/lists"}