[
  {
    "path": ".gitignore",
    "content": "node_modules/\n.idea/\n*-private.html"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "## Code of Conduct\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). \nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact \nopensource-codeofconduct@amazon.com with any additional questions or comments.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nThank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional \ndocumentation, we greatly value feedback and contributions from our community.\n\nPlease read through this document before submitting any issues or pull requests to ensure we have all the necessary \ninformation to effectively respond to your bug report or contribution.\n\n\n## Reporting Bugs/Feature Requests\n\nWe welcome you to use the GitHub issue tracker to report bugs or suggest features.\n\nWhen filing an issue, please check [existing open](https://github.com/aws/amazon-cognito-js/issues), or [recently closed](https://github.com/aws/amazon-cognito-js/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already \nreported the issue. Please try to include as much information as you can. Details like these are incredibly useful:\n\n* A reproducible test case or series of steps\n* The version of our code being used\n* Any modifications you've made relevant to the bug\n* Anything unusual about your environment or deployment\n\n\n## Contributing via Pull Requests\nContributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:\n\n1. You are working against the latest source on the *master* branch.\n2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.\n3. You open an issue to discuss any significant work - we would hate for your time to be wasted.\n\nTo send us a pull request, please:\n\n1. Fork the repository.\n2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.\n3. Ensure local tests pass.\n4. Commit to your fork using clear commit messages.\n5. Send us a pull request, answering any default questions in the pull request interface.\n6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.\n\nGitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and \n[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).\n\n\n## Finding contributions to work on\nLooking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/amazon-cognito-js/labels/help%20wanted) issues is a great place to start. \n\n\n## Code of Conduct\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). \nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact \nopensource-codeofconduct@amazon.com with any additional questions or comments.\n\n\n## Security issue notifications\nIf you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.\n\n\n## Licensing\n\nSee the [LICENSE](https://github.com/aws/amazon-cognito-js/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.\n\nWe may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.\n"
  },
  {
    "path": "Gruntfile.js",
    "content": "module.exports = function(grunt) {\n\n    grunt.initConfig({\n\n        pkg: grunt.file.readJSON('package.json'),\n\n        banner: '/**\\n' +\n        ' * Copyright 2014 Amazon.com,\\n' +\n        ' * Inc. or its affiliates. All Rights Reserved.\\n' +\n        ' * \\n' +\n        ' * Licensed under the Amazon Software License (the \"License\").\\n' +\n        ' * You may not use this file except in compliance with the\\n' +\n        ' * License. A copy of the License is located at\\n' +\n        ' * \\n' +\n        ' *     http://aws.amazon.com/asl/\\n' +\n        ' * \\n' +\n        ' * or in the \"license\" file accompanying this file. This file is\\n' +\n        ' * distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\\n' +\n        ' * CONDITIONS OF ANY KIND, express or implied. See the License\\n' +\n        ' * for the specific language governing permissions and\\n' +\n        ' * limitations under the License. \\n' +\n        ' */\\n\\n',\n\n        qunit: {\n            all: ['tst/**/*.html']\n        },\n\n        jshint: {\n\n            options: {\n                reporterOutput: '',\n                browser: true,\n                eqeqeq: true,\n                globals: {\n                    AWS: true\n                },\n                undef: true\n            },\n\n            src: ['src/*.js']\n\n        },\n\n        jsdoc: {\n            dist: {\n                src: ['src/*.js'],\n                options: {\n                    destination: 'docs'\n                }\n            }\n        },\n\n        uglify: {\n            options: {\n                sourceMap: true,\n                drop_console: true,\n                banner: '<%= banner %>'\n            },\n            dist: {\n                files: {\n                    \"dist/amazon-cognito.min.js\": [\n                        'src/CognitoSyncManager.js',\n                        'src/CognitoSyncConflict.js',\n                        'src/CognitoSyncDataset.js',\n                        'src/CognitoSyncDatasetMetadata.js',\n                        'src/CognitoSyncDatasetUpdates.js',\n                        'src/CognitoSyncLocalStorage.js',\n                        'src/CognitoSyncRecord.js',\n                        'src/CognitoSyncRemoteStorage.js',\n                        'src/CognitoSyncStoreInMemory.js',\n                        'src/CognitoSyncStoreLocalStorage.js'\n                    ]\n                }\n            }\n        },\n\n        umd: {\n            all: {\n                options: {\n                    src: 'dist/amazon-cognito.min.js',\n                    deps: {\n                        default: [{'aws-sdk/global': 'AWS'}],\n                        global: [{'AWS': 'AWS'}]\n                    }\n                }\n            }\n        },\n\n        watch: {\n            scripts: {\n                files: ['src/*.js'],\n                tasks: ['uglify:dist']\n            }\n        }\n\n    });\n\n    grunt.loadNpmTasks('grunt-contrib-jshint');\n    grunt.loadNpmTasks('grunt-contrib-uglify');\n    grunt.loadNpmTasks('grunt-contrib-qunit');\n    grunt.loadNpmTasks('grunt-contrib-watch');\n    grunt.loadNpmTasks('grunt-jsdoc');\n    grunt.loadNpmTasks('grunt-umd');\n\n    grunt.registerTask('default', ['qunit']);\n\n};"
  },
  {
    "path": "LICENSE.txt",
    "content": "﻿\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n"
  },
  {
    "path": "NOTICE.txt",
    "content": "Cognito Sync Manager for JavaScript\nCopyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved."
  },
  {
    "path": "README.md",
    "content": "﻿# Amazon Cognito Sync Manager for JavaScript\n\n**Developer Preview:** We welcome developer feedback on this project. You can reach us by creating an issue on the GitHub repository or post to the Amazon Cognito forums:\n\n* https://github.com/aws/amazon-cognito-js/issues\n* https://forums.aws.amazon.com/forum.jspa?forumID=173\n\nIntroduction\n============\n\nThe Cognito Sync Manager for JavaScript allows your web application to store data in the cloud for your users and\nsynchronize across other devices. The library uses the browser's local storage API to create a local cache for the\ndata, similar to our [mobile SDK](http://aws.amazon.com/mobile/sdk/). This allows your web application to access stored data even when there is no\nconnectivity.\n\n**Note:** This library is designed to run in the browser. It has not been tested for use in other environments.\n\n## Setup\n\n1. Download and include the AWS JavaScript SDK:\n  * http://aws.amazon.com/sdk-for-browser/\n\n2. Download and include the Cognito Sync Manager for JavaScript:\n  * `<script src=\"/path/to/amazon-cognito.min.js\"></script>`\n  * Or... `import 'amazon-cognito-js';`\n  * Or... `require('amazon-cognito-js');`\n\nFor NPM usage refer to the following issue: [NPM usage](https://github.com/aws/amazon-cognito-js/issues/40).\n\n## Usage\n\n**Step 1.** Log into Amazon Cognito management console and create a new identity pool. Be sure to enable the \"unauthenticated\nidentities\" option. On the last step of the wizard, make a note of your Account ID, Identity Pool ID, and\nUnauthenticated Role ARN.\n\n* https://console.aws.amazon.com/cognito/home/?region=us-east-1\n\n**Step 2.** Instantiate the AWS JavaScript SDK using the AWS.CognitoIdentityCredentials class, using the information you\ngathered from the previous step.\n\n```javascript\nAWS.config.region = 'us-east-1';\n\nAWS.config.credentials = new AWS.CognitoIdentityCredentials({\n    IdentityPoolId: 'YOUR IDENTITY POOL ID',\n});\n```\n\n**Step 3.** Make the call to obtain the credentials you configured, and in the callback, instantiate the CognitoSyncManager\nclass. It will assume the credentials from the AWS SDK.\n\n```javascript\nAWS.config.credentials.get(function() {\n\n    client = new AWS.CognitoSyncManager();\n\n    // YOUR CODE HERE\n\n});\n```\n\n**Step 4.** Now you need to open or create a new dataset to start saving data to. Call .openOrCreateDataset() and pass in the\ndesired dataset name.\n\n```javascript\nclient.openOrCreateDataset('myDatasetName', function(err, dataset) {\n\n   // Do something with the dataset here.\n\n});\n```\n\n**Step 5.** Once you have the dataset object, you can write, read, and delete records to that dataset. It is also possible to [get all the records](https://github.com/raptortech-js/amazon-cognito-js/blob/master/src/CognitoSyncDataset.js#L93) from a given dataset, [get the amount of data used](https://github.com/raptortech-js/amazon-cognito-js/blob/master/src/CognitoSyncDataset.js#L102) by a dataset, and [more](https://github.com/raptortech-js/amazon-cognito-js/blob/master/src/CognitoSyncDataset.js).\n\n```javascript\n<!-- Read Records -->\ndataset.get('myRecord', function(err, value) {\n  console.log('myRecord: ' + value);\n});\n\n<!-- Write Records -->\ndataset.put('newRecord', 'newValue', function(err, record) {\n  console.log(record);\n});\n\n<!-- Delete Records -->\ndataset.remove('oldKey', function(err, record) {\n  if (!err) { console.log('success'); }\n});\n```\n\n**Step 6.** Finally, synchronize the data to Cognito. You pass the synchronize function an object with callbacks to handle the\nvarious outcomes: onSuccess, onFailure, onConflict, onDatasetsMerged, onDatasetDeleted.\n\n```javascript\n<!-- Synchronize -->\ndataset.synchronize({\n\n  onSuccess: function(dataset, newRecords) {\n     //...\n  },\n\n  onFailure: function(err) {\n     //...\n  },\n\n  onConflict: function(dataset, conflicts, callback) {\n\n     var resolved = [];\n\n     for (var i=0; i<conflicts.length; i++) {\n\n        // Take remote version.\n        resolved.push(conflicts[i].resolveWithRemoteRecord());\n\n        // Or... take local version.\n        // resolved.push(conflicts[i].resolveWithLocalRecord());\n\n        // Or... use custom logic.\n        // var newValue = conflicts[i].getRemoteRecord().getValue() + conflicts[i].getLocalRecord().getValue();\n        // resolved.push(conflicts[i].resolveWithValue(newValue);\n\n     }\n\n     dataset.resolve(resolved, function() {\n        return callback(true);\n     });\n\n     // Or... callback false to stop the synchronization process.\n     // return callback(false);\n\n  },\n\n  onDatasetDeleted: function(dataset, datasetName, callback) {\n\n     // Return true to delete the local copy of the dataset.\n     // Return false to handle deleted datasets outsid ethe synchronization callback.\n\n     return callback(true);\n\n  },\n\n  onDatasetsMerged: function(dataset, datasetNames, callback) {\n\n     // Return true to continue the synchronization process.\n     // Return false to handle dataset merges outside the synchroniziation callback.\n\n     return callback(false);\n\n  }\n\n});\n```\n\n## Change Log\n\n**v1.0.0:**\n* Initial release. Developer preview.\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"amazon-cognito-js\",\n  \"description\": \"Cognito Sync Manager for AWS JavaScript SDK\",\n  \"main\": \"./dist/amazon-cognito.min.js\",\n  \"version\": \"1.1.0\",\n  \"author\": {\n    \"name\": \"Amazon Web Services\",\n    \"email\": \"aws@amazon.com\",\n    \"url\": \"http://aws.amazon.com\"\n  },\n  \"homepage\": \"http://aws.amazon.com/cognito\",\n  \"contributors\": [\n    \"Mike Murry <mmurry@amazon.com>\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/aws/amazon-cognito-js.git\"\n  },\n  \"license\": \"Apache-2.0\",\n  \"keywords\": [\"amazon\",\"aws\",\"cognito\",\"identity\",\"sync\"],\n  \"scripts\": {\n    \"build\": \"grunt uglify umd\"\n  },\n  \"devDependencies\": {\n    \"grunt\": \"^0.4.5\",\n    \"grunt-contrib-jshint\": \"^0.10.0\",\n    \"grunt-contrib-qunit\": \"^0.5.2\",\n    \"grunt-contrib-uglify\": \"^0.6.0\",\n    \"grunt-contrib-watch\": \"^0.6.1\",\n    \"grunt-jsdoc\": \"^0.5.7\",\n    \"grunt-umd\": \"^2.3.6\",\n    \"qunitjs\": \"^1.15.0\"\n  }\n}\n"
  },
  {
    "path": "src/CognitoSyncConflict.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.Conflict = (function() {\n\n    /**\n     * When the local and remote copies of a dataset are in conflict, this object is returned to the synchronize callback.\n     * @param remoteRecord the record from remote storage\n     * @param localRecord the record from local storage\n     * @prop {string} key\n     * @prop {CognitoSyncRecord} remoteRecord\n     * @prop {CognitoSyncRecord} localRecord\n     * @constructor\n     */\n\n    var CognitoSyncConflict = function(remoteRecord, localRecord) {\n\n        if (!remoteRecord || !localRecord) { throw new Error('Remote and local records cannot be null.'); }\n        if (!remoteRecord.getKey || !localRecord.getKey) { throw new Error('Records are not record objects.'); }\n        if (remoteRecord.getKey() !== localRecord.getKey()) { throw new Error('Remote and local keys do not match.'); }\n\n        this.key = remoteRecord.getKey();\n        this.remoteRecord = remoteRecord;\n        this.localRecord = localRecord;\n\n    };\n\n    /**\n     * Get the key of the records in conflict.\n     * @returns {string} the record's key\n     */\n\n    CognitoSyncConflict.prototype.getKey = function() {\n        return this.key;\n    };\n\n    /**\n     * Get the remote record that is in conflict.\n     * @returns {CognitoSyncRecord} the record\n     */\n\n    CognitoSyncConflict.prototype.getRemoteRecord = function() {\n        return this.remoteRecord;\n    };\n\n    /**\n     * Get the local record that is in conflict.\n     * @returns {CognitoSyncRecord} the record\n     */\n\n    CognitoSyncConflict.prototype.getLocalRecord = function() {\n        return this.localRecord;\n    };\n\n    /**\n     * Resolves conflict with remote record.\n     * @returns {CognitoSyncRecord} the resulting record\n     */\n\n    CognitoSyncConflict.prototype.resolveWithRemoteRecord = function() {\n        this.remoteRecord.setModified(false);\n        return this.remoteRecord;\n    };\n\n    /**\n     * Resolves conflict with local record.\n     * @returns {CognitoSyncRecord} resolved record\n     */\n\n    CognitoSyncConflict.prototype.resolveWithLocalRecord = function() {\n        this.localRecord.setSyncCount(this.remoteRecord.getSyncCount());\n        this.localRecord.setModified(true);\n        return this.localRecord;\n    };\n\n    /**\n     * Resolves conflict with a new value.\n     * @param newValue new value of the record\n     * @returns {CognitoSyncRecord} resolved record\n     */\n\n    CognitoSyncConflict.prototype.resolveWithValue = function(newValue) {\n        return new AWS.CognitoSyncManager.Record({\n            Key: this.remoteRecord.getKey(),\n            Value: newValue,\n            SyncCount: this.remoteRecord.getSyncCount(),\n            LastModifiedDate: new Date(),\n            LastModifiedBy: this.localRecord.getLastModifiedBy(),\n            DeviceLastModifiedDate: new Date(),\n            Modified: true\n        });\n    };\n\n    return CognitoSyncConflict;\n\n})();"
  },
  {
    "path": "src/CognitoSyncDataset.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.Dataset = (function() {\n\n    /**\n     * Constructs a new dataset class.\n     * @param {string} datasetName\n     * @param provider\n     * @param {AWS.CognitoSyncLocalStorage} local\n     * @param {AWS.CognitoSyncRemoteStorage} remote\n     * @param {function} logger\n     * @constructor\n     */\n\n    var CognitoSyncDataset = function(datasetName, provider, local, remote, logger) {\n\n        this.MAX_RETRY = 3;\n\n        this.datasetName = datasetName;\n        this.provider = provider;\n        this.local = local;\n        this.remote = remote;\n        this.logger = logger || function(){};\n\n    };\n\n    /**\n     * Validates the record key to ensure it is not empty and shorter than 128 characters.\n     * @param {String} key The key to validate.\n     * @returns {boolean}\n     */\n\n    CognitoSyncDataset.prototype.validateKey = function(key) {\n        var namePattern = new RegExp('^[a-zA-Z0-9_.:-]{1,128}$');\n        return namePattern.test(key);\n    };\n\n    /**\n     * Writes a record to local storage.\n     * @param {string} key\n     * @param {string} value\n     * @param {function} callback Callback(Error, Record)\n     */\n\n    CognitoSyncDataset.prototype.put = function(key, value, callback) {\n        var valueType = typeof value;\n        if (!this.validateKey(key)) { return callback(new Error('Invalid key.')); }\n        if (valueType !== 'string') {\n            return callback(new Error('The value type must be a string but was ' + valueType + '.'));\n        }\n        this.local.putValue(this.getIdentityId(), this.datasetName, key, value, callback);\n    };\n\n    /**\n     * Writes a record as null, to be cleaned up on the next synchronization.\n     * @param {string} key The key to remove.\n     * @param {function} callback Callback(Error, Record)\n     */\n\n    CognitoSyncDataset.prototype.remove = function(key, callback) {\n        if (!this.validateKey(key)) { return callback(new Error('Invalid key.')); }\n        this.local.putValue(this.getIdentityId(), this.datasetName, key, null, callback);\n    };\n\n    /**\n     * Gets a record's value from local storage.\n     * @param {string} key\n     * @param {function} callback Callback(Error, Value)\n     */\n\n    CognitoSyncDataset.prototype.get = function(key, callback) {\n        if (!this.validateKey(key)) { return callback(new Error('Invalid key.')); }\n        this.local.getValue(this.getIdentityId(), this.datasetName, key, callback);\n    };\n\n    /**\n     * Gets all records in a dataset from local storage.\n     * @param {function} callback Callback(Error, Records)\n     */\n\n    CognitoSyncDataset.prototype.getAllRecords = function(callback) {\n        this.local.getRecords(this.getIdentityId(), this.datasetName, callback);\n    };\n\n    /**\n     * Returns the amount of data stored on the server.\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.getDataStorage = function(callback) {\n\n        this.getDatasetMetadata(function(err, meta) {\n            if (err) { return callback(err); }\n            if (!meta) { return callback(null, 0); }\n            return callback(null, meta.getDataStorage());\n        });\n\n    };\n\n    /**\n     * Returns if a specific record has changed.\n     * @param key\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.isChanged = function(key, callback) {\n        if (!this.validateKey(key)) { return callback(new Error('Invalid key.')); }\n        this.local.getRecord(this.getIdentityId(), this.datasetName, key, function(err, record) {\n            callback(null, (record && record.isModified()));\n        });\n    };\n\n    /**\n     * Returns the dataset metadata.\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.getDatasetMetadata = function(callback) {\n        this.local.getDatasetMetadata(this.getIdentityId(), this.datasetName, callback);\n    };\n\n    /**\n     * Resolves conflicts using the records provided.\n     * @param resolvedRecords\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.resolve = function(resolvedRecords, callback) {\n        this.local.putRecords(this.getIdentityId(), this.datasetName, resolvedRecords, callback);\n    };\n\n    /**\n     * Puts all values into the dataset.\n     * @param values\n     * @param callback\n     * @returns {*}\n     */\n\n    CognitoSyncDataset.prototype.putAll = function(values, callback) {\n\n        var isValid = true;\n\n        for (var key in values) {\n            if (values.hasOwnProperty(key)) {\n                if (!this.validateKey(key)) { isValid = false; }\n            }\n        }\n\n        if (!isValid) { return callback(new Error('Object contains invalid keys.')); }\n\n        this.local.putAllValues(this.getIdentityId(), this.datasetName, values, callback);\n\n    };\n\n    /**\n     * Returns all records from a dataset.\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.getAll = function(callback) {\n\n        var map = {};\n        var record;\n\n        this.local.getRecords(this.getIdentityId(), this.datasetName, function(err, records) {\n\n            if (err) { return callback(err); }\n\n            for (var r in records) {\n                if (records.hasOwnProperty(r)) {\n                    record = records[r];\n                    if (!record.isDeleted()) { map[record.getKey()] = record.getValue(); }\n                }\n            }\n\n            callback(null, map);\n\n        });\n\n    };\n\n    /**\n     * Returns the current user's identity id.\n     * @returns {string};\n     */\n\n    CognitoSyncDataset.prototype.getIdentityId = function() {\n        return this.provider.identityId;\n    };\n\n    /**\n     * Returns the records that have been modified.\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.getModifiedRecords = function(callback) {\n        this.local.getModifiedRecords(this.getIdentityId(), this.datasetName, callback);\n    };\n\n    /**\n     * Returns a list of datasets that have been merged.\n     * @param callback\n     */\n\n    CognitoSyncDataset.prototype.getLocalMergedDatasets = function(callback) {\n\n        var mergedDatasets = [];\n        var prefix = this.datasetName + '.';\n        var dataset;\n\n        this.local.getDatasets(this.getIdentityId(), function(err, datasets) {\n\n            for (var d in datasets) {\n                if (datasets.hasOwnProperty(d)) {\n\n                    dataset = datasets[d];\n\n                    if (dataset.getDatasetName().indexOf(prefix) === 0) {\n                        mergedDatasets.push(dataset.getDatasetName());\n                    }\n\n                }\n            }\n\n            callback(null, mergedDatasets);\n\n        });\n\n    };\n\n    /**\n     * Starts the synchronization process.\n     * @param callback\n     * @param retry\n     */\n\n    CognitoSyncDataset.prototype.synchronize = function(callback, retry) {\n\n        var root = this;\n\n        // Validate callback object.\n        callback = callback || {};\n        callback.onSuccess = callback.onSuccess || function(dataset, updates) {};\n        callback.onFailure = callback.onFailure || function(err) {};\n        callback.onConflict = callback.onConflict || function(dataset, conflicts, callback) { return callback(false); };\n        callback.onDatasetDeleted = callback.onDatasetDeleted || function(dataset, deletedDataset, callback) { return callback(false); };\n        callback.onDatasetsMerged = callback.onDatasetsMerged || function(dataset, merges, callback) { return callback(false); };\n\n        // Validate/initialize retry count.\n        if (retry === undefined) { retry = this.MAX_RETRY; }\n\n        root.logger('Starting synchronization... (retries: ' + retry + ')');\n\n        if (retry < 0) {\n            return callback.onFailure(new Error('Synchronize failed: exceeded maximum retry count.'));\n        }\n\n        // First check if any datasets have been merged locally.\n\n        this.getLocalMergedDatasets(function(err, mergedDatasets) {\n\n            if (err) { callback.onFailure(err); }\n\n            root.logger('Checking for locally merged datasets... found ' + mergedDatasets.length + '.');\n\n            // Detect if merged datasets.\n            if (mergedDatasets.length > 0) {\n\n                root.logger('Deferring to .onDatasetsMerged.');\n\n                return callback.onDatasetsMerged(root, mergedDatasets, function(isContinue) {\n\n                    if (!isContinue) {\n\n                        // Merges were not handled by callback. Cancel sync.\n                        return callback.onFailure(new Error('Synchronization cancelled by onDatasetsMerged() callback returning false.'));\n\n                    } else {\n\n                        // Merges are handled within callback. Restart sync.\n                        return root.synchronize(callback, --retry);\n\n                    }\n\n                });\n\n            } else {\n\n                // Get the last sync count so we can tell the server what to diff.\n\n                root.local.getLastSyncCount(root.getIdentityId(), root.datasetName, function(err, syncCount) {\n\n                    if (err) { return callback.onFailure(err); }\n\n                    root.logger('Detecting last sync count... ' + syncCount);\n\n                    if (parseInt(syncCount) === -1) {\n\n                        // Dataset has been deleted locally\n                        root.remote.deleteDataset(root.datasetName, function(err, data) {\n                            if (err) { return callback.onFailure(err); }\n                            root.local.purgeDataset(root.getIdentityId(), root.datasetName, function(err) {\n                               if (err) { return callback.onFailure(err); }\n                               return callback.onSuccess(root);\n                            });\n                        });\n\n                    } else {\n\n                        // Get all the remote records that have changed since the latest sync count.\n\n                        root.remote.listUpdates(root.datasetName, syncCount, function(err, remoteRecords) {\n\n                            if (err) { return callback.onFailure(err); }\n\n                            root.logger('Fetching remote updates... found ' + remoteRecords.records.length + '.');\n\n                            var mergedNameList = remoteRecords.getMergedDatasetNameList();\n\n                            root.logger('Checking for remote merged datasets... found ' + mergedNameList.length + '.');\n\n                            if (mergedNameList.length > 0) {\n\n                                root.logger('Deferring to .onDatasetsMerged.');\n\n                                // Merged datasets exist. Use callback to determine action.\n                                return callback.onDatasetsMerged(root, mergedNameList, function(doContinue) {\n                                    if (!doContinue) { callback.onFailure(new Error('Cancelled due to .onDatasetsMerged result.')); }\n                                    else { root._synchronizeInternal(callback, --retry); }\n                                });\n                            }\n\n                            // Check if dataset doesn't exist or is deleted.\n\n                            if (syncCount !== 0 && !remoteRecords || remoteRecords.isDeleted()) {\n\n                                return callback.onDatasetDeleted(root, remoteRecords.getDatasetName(), function(doContinue) {\n\n                                    root.logger('Dataset should be deleted. Deferring to .onDatasetDeleted.');\n\n                                    if (doContinue) {\n                                        root.logger('.onDatasetDeleted returned true, purging dataset locally.');\n                                        return root.local.purgeDataset(root.getIdentityId(), root.datasetName, function(err) {\n                                            if (err) { return callback.onFailure(err); }\n                                            return root._synchronizeInternal(callback, --retry);\n                                        });\n                                    } else {\n                                        root.logger('.onDatasetDeleted returned false, cancelling sync.');\n                                        return callback.onFailure(new Error('Cancelled due to .onDatasetDeleted result.'));\n                                    }\n\n                                });\n\n                            }\n\n                            var updatedRemoteRecords = remoteRecords.getRecords();\n                            var lastSyncCount = remoteRecords.getSyncCount();\n                            var sessionToken = remoteRecords.getSyncSessionToken();\n\n                            // Check if there have been any updates since the last sync count.\n\n                            root.logger('Checking for remote updates since last sync count... found ' + updatedRemoteRecords.length + '.');\n\n                            if (updatedRemoteRecords.length > 0) {\n\n                                root._synchronizeResolveLocal(updatedRemoteRecords, function(err, conflicts) {\n\n                                    if (err) { return callback.onFailure(err); }\n\n                                    root.logger('Checking for conflicts... found ' + conflicts.length + '.');\n\n                                    if (conflicts.length > 0) {\n\n                                        root.logger('Conflicts detected. Deferring to .onConflict.');\n\n                                        callback.onConflict(root, conflicts, function(isContinue) {\n\n                                            if (!isContinue) {\n\n                                                root.logger('.onConflict returned false. Cancelling sync.');\n                                                return callback.onFailure(new Error('Sync cancelled. Conflict callback returned false.'));\n\n                                            } else {\n\n                                                // Update remote records or we will just hit another sync conflict next go around.\n\n                                                root._synchronizePushRemote(sessionToken, syncCount, function(){\n                                                    return root.synchronize(callback, --retry);\n                                                });\n\n                                            }\n\n                                        });\n\n                                    } else {\n\n                                        // No conflicts, update local records.\n                                        root.logger('No conflicts. Updating local records.');\n\n                                        root.local.putRecords(root.getIdentityId(), root.datasetName, updatedRemoteRecords, function(err) {\n\n                                            if (err) { return callback.onFailure(err); }\n\n                                            // Update the local sync count to match.\n\n                                            root.local.updateLastSyncCount(root.getIdentityId(), root.datasetName, lastSyncCount, function(err) {\n\n                                                if (err) { return callback.onFailure(err); }\n\n                                                root.logger('Finished resolving records. Restarting sync.');\n\n                                                // Callback returned true, starting sync.\n                                                return root.synchronize(callback, --retry);\n\n                                            });\n                                        });\n\n                                    }\n\n                                });\n\n\n                            } else {\n\n                                // Nothing updated remotely. Push local changes to remote.\n                                root.logger('Nothing updated remotely. Pushing local changes to remote.');\n\n                                root._synchronizePushRemote(sessionToken, lastSyncCount, function(err) {\n\n                                    if (err) {\n                                        root.logger('Remote push failed. Likely concurrent sync conflict. Retrying...');\n                                        return root.synchronize(callback, --retry);\n                                    }\n\n                                    root.logger('Sync successful.');\n                                    return callback.onSuccess(root, updatedRemoteRecords);\n\n                                });\n\n                            }\n                        });\n\n                    }\n\n                });\n\n            }\n\n        });\n    };\n\n    /**\n     * An internal function for helping the synchronization call to resolve local conflicts.\n     * @param remoteRecords\n     * @param callback\n     * @private\n     */\n\n    CognitoSyncDataset.prototype._synchronizeResolveLocal = function(remoteRecords, callback) {\n\n        // Step two of the synchronization flow.\n        // The dataset exists remotely so we need to determine if there are any deletions or conflicts.\n        // Once everything is resolved, we update the local records.\n\n        var root = this;\n        var conflicts = [];\n\n        // Make sure there are remote records that need resolving.\n\n        if (remoteRecords && remoteRecords.length > 0) {\n\n            // Get the local records so we can compare them to the remote records.\n\n            root.local.getRecords(root.getIdentityId(), root.datasetName, function(err, localRecords) {\n\n                var localMap = {};\n                var i, key, local;\n\n                // Build a map of the local records array for easier key lookup.\n\n                for (i=0; i<localRecords.length; i++) {\n                    localMap[localRecords[i].getKey()] = localRecords[i];\n                }\n\n                // Compare local and remote records.\n\n                for (i=0; i<remoteRecords.length; i++) {\n\n                    key = remoteRecords[i].getKey();\n                    local = localMap[key];\n\n                    if (local && local.isModified() && local.getValue() !== remoteRecords[i].getValue()) {\n                        conflicts.push(new AWS.CognitoSyncManager.Conflict(remoteRecords[i], local));\n                    }\n\n                }\n\n                return callback(null, conflicts);\n\n            });\n\n        } else {\n\n            // There are no remote records. Nothing to resolve.\n            return callback(null, conflicts);\n\n        }\n\n    };\n\n    /**\n     * An internal function for helping the synchronization call to push changes to the server.\n     * @param sessionToken\n     * @param syncCount\n     * @param callback\n     * @private\n     */\n\n    CognitoSyncDataset.prototype._synchronizePushRemote = function(sessionToken, syncCount, callback) {\n\n        // Step three of the synchronization flow.\n        // The local dataset has modifications so we need to push the local changes to remote.\n        // Then we need to update the local metadata and update/verify the sync count.\n\n        var root = this;\n\n        // Push changes to remote.\n\n        this.getModifiedRecords(function(err, localChanges) {\n\n            if (localChanges.length > 0) {\n\n                root.remote.putRecords(root.datasetName, localChanges, sessionToken, function(err, records) {\n\n                    if (err) { callback(err); }\n\n                    // Update local metadata.\n                    root.local.putRecords(root.getIdentityId(), root.datasetName, records, function(err) {\n\n                        if (err) { return callback(err); }\n\n                        var newSyncCount = 0;\n\n                        // Calculate new sync count.\n\n                        for (var r in records) {\n                            if (records.hasOwnProperty(r)) {\n                                newSyncCount = newSyncCount < records[r].getSyncCount() ? records[r].getSyncCount() : newSyncCount;\n                            }\n                        }\n\n                        root.local.updateLastSyncCount(root.getIdentityId(), root.datasetName, newSyncCount, function(err) {\n                            if (err) { return callback(err); }\n                            return callback(null, true);\n                        });\n\n                    });\n\n                });\n\n            } else {\n\n                // Nothing to change.\n                return callback(null, true);\n\n            }\n\n        });\n\n    };\n\n    return CognitoSyncDataset;\n\n})();\n"
  },
  {
    "path": "src/CognitoSyncDatasetMetadata.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Constructs a new CognitoSyncDatasetMetadata object.\n * @param metadata the serialized metadata\n * @constructor\n */\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.DatasetMetadata = (function(){\n\n    var CognitoSyncDatasetMetadata = function(metadata) {\n\n        metadata = metadata || {};\n\n        // Assign object.\n        this.datasetName = metadata.DatasetName || '';\n        this.creationDate = new Date(metadata.CreationDate) || new Date();\n        this.lastModifiedDate = new Date(metadata.LastModifiedDate) || new Date();\n        this.lastModifiedBy = metadata.LastModifiedBy || '';\n        this.dataStorage = metadata.DataStorage || 0;\n        this.recordCount = metadata.NumRecords || 0;\n\n        // Meta metadata.\n        this.lastSyncCount = metadata.LastSyncCount || 0;\n        this.lastSyncDate = metadata.LastSyncDate ? new Date(metadata.LastSyncDate) : new Date();\n\n        // Validate object.\n        if (this.dataStorage < 0) { throw new RangeError('Storage size cannot be negative.'); }\n        if (this.recordCount < 0) { throw new RangeError('Record count cannot be negative.'); }\n\n    };\n\n    /**\n     * Get the dataset name.\n     * @returns {string} the dataset's name.\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getDatasetName = function() {\n        return this.datasetName;\n    };\n\n    /**\n     * Sets the dataset name.\n     * @param {string} datasetName the name of the dataset\n     * @returns {CognitoSyncDatasetMetadata} the dataset object\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setDatasetName = function(datasetName) {\n        this.datasetName = datasetName;\n        return this;\n    };\n\n    /**\n     * Get the dataset's creation date.\n     * @returns {Date} the creation date\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getCreationDate = function() {\n        return this.creationDate;\n    };\n\n    /**\n     * Sets the dataset creation date.\n     * @param {Date} creationDate\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setCreationDate = function(creationDate) {\n        this.creationDate = new Date(creationDate);\n        return this;\n    };\n\n    /**\n     * Gets the dataset last modified date.\n     * @returns {Date}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getLastModifiedDate = function() {\n        return this.lastModifiedDate;\n    };\n\n    /**\n     * Sets the dataset last modified date.\n     * @param modifiedDate\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setLastModifiedDate = function(modifiedDate) {\n        this.lastModifiedDate = new Date(modifiedDate);\n        return this;\n    };\n\n    /**\n     * Returns the user/device who last modified the dataset.\n     * @returns {String}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getLastModifiedBy = function() {\n        return this.lastModifiedBy;\n    };\n\n    /**\n     * Sets the user/device who last modified the dataset.\n     * @param {String} modifiedBy\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setLastModifiedBy = function(modifiedBy) {\n        this.lastModifiedBy = modifiedBy;\n        return this;\n    };\n\n    /**\n     * Gets the data storage size.\n     * @returns {number}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getDataStorage = function() {\n        return this.dataStorage;\n    };\n\n    /**\n     * Sets the data storage size.\n     * @param {Number} storageSize\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setDataStorage = function(storageSize) {\n        this.dataStorage = storageSize;\n        return this;\n    };\n\n    /**\n     * Gets the record count.\n     * @returns {number}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getRecordCount = function() {\n        return this.recordCount;\n    };\n\n    /**\n     * Sets the record count.\n     * @param {Number} recordCount\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setRecordCount = function(recordCount) {\n        this.recordCount = recordCount;\n        return this;\n    };\n\n    /**\n     * Gets the last sync count.\n     * @returns {number}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getLastSyncCount = function() {\n        return this.lastSyncCount;\n    };\n\n    /**\n     * Sets the last sync count.\n     * @param {Number} syncCount\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setLastSyncCount = function(syncCount) {\n        this.lastSyncCount = syncCount;\n        return this;\n    };\n\n    /**\n     * Gets the last sync date.\n     * @returns {Date}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.getLastSyncDate = function() {\n        return this.lastSyncDate;\n    };\n\n    /**\n     * Sets the last sync date.\n     * @param {Date} syncDate\n     * @returns {CognitoSyncDatasetMetadata}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.setLastSyncDate = function(syncDate) {\n        this.lastSyncDate = syncDate;\n        return this;\n    };\n\n    /**\n     * Returns a JSON string of the metadata object.\n     * @returns {String}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.toString = function() {\n        return JSON.stringify(this.toJSON());\n    };\n\n    /**\n     * Returns a flat object representing the metadata.\n     * @returns {Object}\n     */\n\n    CognitoSyncDatasetMetadata.prototype.toJSON = function() {\n        return {\n            DatasetName: this.datasetName,\n            CreationDate: this.creationDate,\n            LastModifiedDate: this.lastModifiedDate,\n            LastModifiedBy: this.lastModifiedBy,\n            DataStorage: this.dataStorage,\n            NumRecords: this.recordCount,\n            LastSyncCount: this.lastSyncCount,\n            LastSyncDate: this.lastSyncDate\n        };\n    };\n\n    return CognitoSyncDatasetMetadata;\n\n})();\n"
  },
  {
    "path": "src/CognitoSyncDatasetUpdates.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.DatasetUpdates = (function() {\n\n    /**\n     * Constructs a new dataset update class.\n     * @param datasetName\n     * @constructor\n     */\n\n    var CognitoSyncDatasetUpdates = function (datasetName) {\n\n        this.datasetName = datasetName;\n        this.records = [];\n        this.syncCount = 0;\n        this.syncSessionToken = '';\n        this.exists = true;\n        this.deleted = false;\n        this.mergedDatasetNameList = [];\n\n    };\n\n    CognitoSyncDatasetUpdates.prototype.getDatasetName = function () {\n        return this.datasetName;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.setDatasetName = function (datasetName) {\n        this.datasetName = datasetName;\n        return this;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.getRecords = function () {\n        return this.records;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.addRecord = function (record) {\n        this.records.push(record);\n        return this;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.getSyncCount = function () {\n        return this.syncCount;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.setSyncCount = function (syncCount) {\n        this.syncCount = syncCount;\n        return this;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.getSyncSessionToken = function () {\n        return this.syncSessionToken;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.setSyncSessionToken = function (syncToken) {\n        this.syncSessionToken = syncToken;\n        return this;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.isExists = function () {\n        return this.exists;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.setExists = function (exists) {\n        this.exists = exists;\n        return this;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.isDeleted = function () {\n        return this.deleted;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.setDeleted = function (deleted) {\n        this.deleted = deleted;\n        return this;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.getMergedDatasetNameList = function () {\n        return this.mergedDatasetNameList;\n    };\n\n    CognitoSyncDatasetUpdates.prototype.setMergedDatasetNameList = function (mergedList) {\n        this.mergedDatasetNameList = mergedList;\n        return this;\n    };\n\n    return CognitoSyncDatasetUpdates;\n\n})();\n"
  },
  {
    "path": "src/CognitoSyncLocalStorage.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.LocalStorage = (function() {\n\n    /**\n     * Constructs a new local storage class.\n     * @param options\n     * @constructor\n     */\n\n    var CognitoSyncLocalStorage = function (options) {\n\n        options = options || {};\n\n        this.store = null;\n        this.meta = null;\n\n        // Choose a data store\n        if (options.DataStore) { this.store = new options.DataStore(); }\n        else { this.store = new AWS.CognitoSyncManager.StoreInMemory(); }\n\n    };\n\n    /**\n     * Returns the string used to store dataset metadata.\n     * @param identityId\n     * @param datasetName\n     * @returns {string}\n     */\n\n    CognitoSyncLocalStorage.prototype.getMetadataKey = function (identityId, datasetName) {\n        return identityId + '.' + datasetName;\n    };\n\n    /**\n     * Load the metadata cache from the local store.\n     * @param identityId\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.loadMetadataCache = function (identityId, callback) {\n\n        var root = this;\n\n        this.store.get('_internal', '_metadata', identityId, function (err, data) {\n\n            if (err) {\n                return callback(err, null);\n            }\n            if (!data) {\n                data = {};\n            }\n\n            root.meta = data;\n            callback(null, data);\n\n        });\n\n    };\n\n    /**\n     * Save the metadata cache to the local store.\n     * @param identityId\n     * @param metadata\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.saveMetadataCache = function (identityId, metadata, callback) {\n        this.store.set('_internal', '_metadata', identityId, metadata, function (err) {\n            if (err) {\n                return callback(err);\n            }\n            return callback(null, metadata);\n        });\n    };\n\n    /**\n     * Creates a new dataset.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     * @returns {CognitoSyncLocalStorage}\n     */\n\n    CognitoSyncLocalStorage.prototype.createDataset = function (identityId, datasetName, callback) {\n\n        var root = this;\n\n        this.getDatasetMetadata(identityId, datasetName, function (err, metadata) {\n\n            var stamp = new Date().getTime();\n\n            if (!metadata) {\n\n                metadata = new AWS.CognitoSyncManager.DatasetMetadata({\n                    DatasetName: datasetName,\n                    CreationDate: stamp,\n                    LastModifiedDate: stamp\n                });\n\n                root.setDatasetMetadata(identityId, datasetName, metadata, function (err, data) {\n                    // No-op. Silent update.\n                });\n\n                callback(null, datasetName);\n\n            } else {\n                callback(null, datasetName);\n            }\n\n        });\n\n        return this;\n\n    };\n\n    /**\n     * Returns the dataset metadata.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     * @returns {CognitoSyncLocalStorage}\n     */\n\n    CognitoSyncLocalStorage.prototype.getDatasetMetadata = function (identityId, datasetName, callback) {\n\n        var key = this.getMetadataKey(identityId, datasetName);\n\n        if (this.meta !== null) {\n\n            // Meta data is already loaded. Look it up and return.\n            if (this.meta[key]) {\n                callback(null, new AWS.CognitoSyncManager.DatasetMetadata(this.meta[key]));\n            }\n            else {\n                callback(null, undefined);\n            }\n\n        } else {\n\n            // Load metadata from cache.\n            this.loadMetadataCache(identityId, function (err, cache) {\n                if (cache[key]) {\n                    callback(null, new AWS.CognitoSyncManager.DatasetMetadata(cache[key]));\n                }\n                else {\n                    callback(null, undefined);\n                }\n            });\n\n        }\n\n        return this;\n\n    };\n\n    /**\n     * Sets a dataset's metadata.\n     * @param identityId\n     * @param datasetName\n     * @param metadata\n     * @param callback\n     * @returns {CognitoSyncLocalStorage}\n     */\n\n    CognitoSyncLocalStorage.prototype.setDatasetMetadata = function (identityId, datasetName, metadata, callback) {\n\n        // Write metadata.\n        this.meta[this.getMetadataKey(identityId, datasetName)] = metadata.toJSON();\n\n        // Save metadata.\n        this.saveMetadataCache(identityId, this.meta, callback);\n\n        return this;\n\n    };\n\n\n    /**\n     * Returns a record's value from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getValue = function (identityId, datasetName, key, callback) {\n\n        this.getRecord(identityId, datasetName, key, function (err, record) {\n\n            if (!record) {\n                return callback(null, undefined);\n            }\n\n            return callback(null, record.getValue());\n\n        });\n\n    };\n\n    /**\n     * Sets a record's value from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param value\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.putValue = function (identityId, datasetName, key, value, callback) {\n\n        var root = this;\n\n        this.getRecord(identityId, datasetName, key, function (err, record) {\n\n\n            if (record && record.getValue() === value) {\n                // Record hasn't changed. All done.\n                return callback(null, record);\n            }\n\n            // If record doesn't exist, create a new instance.\n            if (!record) {\n                record = new AWS.CognitoSyncManager.Record();\n            }\n\n            // Update the record with the new properties.\n            record.setKey(key)\n                .setValue(value)\n                .setModified(true)\n                .setSyncCount(record ? record.getSyncCount() : 0)\n                .setDeviceLastModifiedDate(new Date());\n\n            root.store.set(identityId, datasetName, key, record.toJSON(), function (err) {\n\n                if (err) {\n                    return callback(err);\n                }\n\n                root.updateLastModifiedTimestamp(identityId, datasetName, function (err) {\n                    return callback(err, record);\n                });\n\n            });\n\n        });\n\n    };\n\n    /**\n     * Returns a map of values for a dataset from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getValueMap = function (identityId, datasetName, callback) {\n\n        var values = {};\n        var record;\n\n        this.getRecords(identityId, datasetName, function (err, records) {\n\n            for (var r in records) {\n                if (records.hasOwnProperty(r)) {\n                    record = records[r];\n                    if (!record.isDeleted()) {\n                        values[record.getKey()] = record.getValue();\n                    }\n                }\n            }\n\n            callback(null, values);\n\n        });\n\n    };\n\n    /**\n     * Sets multiple records in a dataset in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param values\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.putAllValues = function (identityId, datasetName, values, callback) {\n\n        var root = this;\n\n        var remain = [];\n\n        // Build a list of each value to put.\n\n        for (var v in values) {\n            if (values.hasOwnProperty(v)) {\n                remain.push(v);\n            }\n        }\n\n        var request = function (err) {\n\n            var item;\n\n            if (err) {\n                return callback(err);\n            }\n\n            if (remain.length > 0) {\n\n                // Put each item in the request.\n                item = remain.shift();\n                root.putValue(identityId, datasetName, item, values[item], request);\n\n            } else {\n\n                // Nothing else to update. Break the loop.\n                callback(null, true);\n\n            }\n\n        };\n\n        request(null, null);\n\n    };\n\n    /**\n     * Returns a list of datasets in the local store.\n     * @param identityId\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getDatasets = function (identityId, callback) {\n\n        var datasets = [];\n\n        if (this.meta !== null) {\n\n            for (var m in this.meta) {\n                if (this.meta.hasOwnProperty(m)) {\n                    datasets.push(new AWS.CognitoSyncManager.DatasetMetadata(this.meta[m]));\n                }\n            }\n\n            return callback(null, datasets);\n\n        } else {\n\n            // Meta data is not loaded. Load it.\n            this.loadMetadataCache(identityId, function (err, metadata) {\n\n                for (var m in metadata) {\n                    if (metadata.hasOwnProperty(m)) {\n                        datasets.push(new AWS.CognitoSyncManager.DatasetMetadata(metadata[m]));\n                    }\n                }\n\n                return callback(null, datasets);\n\n            });\n\n        }\n\n    };\n\n    /**\n     * Updates dataset metadata and saves to the cache.\n     * @param identityId\n     * @param metadata\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.updateDatasetMetadata = function (identityId, metadata, callback) {\n\n        var root = this;\n\n        this.getDatasetMetadata(identityId, metadata.getDatasetName(), function (err, local) {\n\n            if (err) { callback(err); }\n\n            if (!local) { local = new AWS.CognitoSyncManager.DatasetMetadata(); }\n\n            local.setDatasetName(metadata.getDatasetName())\n                .setCreationDate(metadata.getCreationDate())\n                .setLastModifiedDate(metadata.getLastModifiedDate())\n                .setLastModifiedBy(metadata.getLastModifiedBy())\n                .setLastSyncCount(metadata.getLastSyncCount())\n                .setRecordCount(metadata.getRecordCount())\n                .setDataStorage(metadata.getDataStorage());\n\n            // Save the updated metadata to the in-memory store.\n\n            root.meta[root.getMetadataKey(identityId, metadata.getDatasetName())] = local.toJSON();\n\n            // Save the updated metadata to the on-disk store.\n\n            root.saveMetadataCache(identityId, root.meta, function (err) {\n                if (err) { return callback(err); }\n                return callback(null, local);\n            });\n\n        });\n\n    };\n\n    /**\n     * Returns a record from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getRecord = function (identityId, datasetName, key, callback) {\n        this.store.get(identityId, datasetName, key, function (err, record) {\n            if (record) { return callback(null, new AWS.CognitoSyncManager.Record(record)); }\n            return callback(new Error('Key doesn\\'t exist.'), null);\n        });\n    };\n\n    /**\n     * Returns all records from a dataset in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getRecords = function (identityId, datasetName, callback) {\n\n        var records = [];\n\n        this.store.getAll(identityId, datasetName, function (err, local) {\n\n            for (var l in local) {\n                if (local.hasOwnProperty(l)) {\n                    records.push(new AWS.CognitoSyncManager.Record(local[l]));\n                }\n            }\n\n            callback(null, records);\n\n        });\n\n    };\n\n    /**\n     * Puts multiple records into a dataset in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param records\n     * @param callback\n     * @returns {CognitoSyncLocalStorage}\n     */\n\n    CognitoSyncLocalStorage.prototype.putRecords = function (identityId, datasetName, records, callback) {\n\n        var root = this;\n        records = records || [];\n        records = records.slice();\n\n        var request = function () {\n\n            if (records.length > 0) {\n\n                root.updateAndClearRecord(identityId, datasetName, records.shift(), function (err) {\n\n                    if (err) { return callback(err); }\n                    if (records.length === 0) { return callback(null, true); }\n\n                    request();\n\n                });\n\n            }\n\n        };\n\n        request();\n\n    };\n\n    /**\n     * Deletes a dataset from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.deleteDataset = function (identityId, datasetName, callback) {\n\n        var root = this;\n\n        // Delete the records.\n\n        this.store.removeAll(identityId, datasetName, function (err) {\n\n            if (err) { return callback(err); }\n\n            // Update dataset metadata.\n\n            root.getDatasetMetadata(identityId, datasetName, function (err, metadata) {\n\n                if (err) { return callback(err); }\n\n                metadata.setLastModifiedDate(new Date());\n                metadata.setLastSyncCount(-1);\n\n                root.updateDatasetMetadata(identityId, metadata, function (err) {\n                    if (err) { return callback(err); }\n                    return callback(null, true);\n                });\n\n            });\n\n        });\n\n    };\n\n    /**\n     * Removes dataset from local storage. Does not remove dataset from remote storage.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.purgeDataset = function (identityId, datasetName, callback) {\n\n        var root = this;\n\n        // Delete records.\n        this.deleteDataset(identityId, datasetName, function (err) {\n\n            if (err) { callback(err); }\n\n            // Delete metadata.\n            delete(root.meta[root.getMetadataKey(identityId, datasetName)]);\n\n            // Save metadata.\n            root.saveMetadataCache(identityId, root.meta, callback);\n\n        });\n\n    };\n\n    /**\n     * Returns the last sync count for a dataset in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getLastSyncCount = function (identityId, datasetName, callback) {\n\n        this.getDatasetMetadata(identityId, datasetName, function (err, metadata) {\n\n            if (metadata) { return callback(null, metadata.getLastSyncCount()); }\n\n            callback(new Error('Dataset doesn\\'t exist.'), null);\n\n        });\n\n    };\n\n    /**\n     * Returns the modified records in a dataset from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.getModifiedRecords = function (identityId, datasetName, callback) {\n\n        var modified = [];\n\n        this.getRecords(identityId, datasetName, function (err, records) {\n\n            for (var i = 0; i < records.length; i++) {\n\n                if (records[i].isModified()) {\n                    modified.push(records[i]);\n                }\n\n            }\n\n            callback(null, modified);\n\n        });\n\n    };\n\n    /**\n     * Updates the last sync count for a dataset in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param lastSyncCount\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.updateLastSyncCount = function (identityId, datasetName, lastSyncCount, callback) {\n\n        var root = this;\n\n        this.getDatasetMetadata(identityId, datasetName, function (err, meta) {\n\n            if (err) {\n                callback(err);\n            }\n\n            meta.setLastSyncCount(lastSyncCount).setLastSyncDate(new Date());\n\n            root.updateDatasetMetadata(identityId, meta, function (err) {\n                if (err) {\n                    callback(err);\n                }\n                callback(null, true);\n            });\n\n        });\n\n    };\n\n    /**\n     * Removes all data from the local store.\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.wipeData = function (callback) {\n        this.store.wipe(callback);\n    };\n\n    /**\n     * Modifies the date a dataset was last modified in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.updateLastModifiedTimestamp = function (identityId, datasetName, callback) {\n\n        var root = this;\n\n        this.getDatasetMetadata(identityId, datasetName, function (err, meta) {\n\n            if (err) {\n                return callback(err);\n            }\n\n            meta.setLastModifiedDate(new Date());\n\n            root.updateDatasetMetadata(identityId, meta, function (err) {\n                if (err) {\n                    return callback(err);\n                }\n                return callback(null, true);\n            });\n\n        });\n\n    };\n\n    /**\n     * Removes a record from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param record\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.removeRecord = function (identityId, datasetName, record, callback) {\n        this.store.remove(identityId, datasetName, record, function (err) {\n            if (err) { return callback(err); }\n            return callback(null, true);\n        });\n    };\n\n    /**\n     * Saves a record to the local store.\n     * @param identityId\n     * @param datasetName\n     * @param record\n     * @param callback\n     */\n\n    CognitoSyncLocalStorage.prototype.updateAndClearRecord = function (identityId, datasetName, record, callback) {\n        this.store.set(identityId, datasetName, record.getKey(), record.toJSON(), function (err) {\n            if (err) { return callback(err); }\n            return callback(null, true);\n        });\n    };\n\n    return CognitoSyncLocalStorage;\n\n})();\n"
  },
  {
    "path": "src/CognitoSyncManager.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nif (AWS === undefined) {\n    throw new Error(\"AWS SDK must be loaded before loading the Sync Manager.\");\n} else {\n\n    /**\n     * Constructs a new Cognito Sync Manager class.\n     * @constructor\n     */\n\n\n    AWS.CognitoSyncManager = function (options) {\n\n        options = options || {};\n\n        var USER_AGENT = 'CognitoJavaScriptSDK/1';\n\n        this.provider = AWS.config.credentials;\n        this.identityPoolId = this.provider.params.IdentityPoolId;\n        this.region = AWS.config.region;\n\n        // Setup logger.\n        this.logger = options.log;\n        if (typeof this.logger !== 'function') {\n            this.logger = function () {\n            };\n        }\n\n        // Initialize local store.\n        this.local = new AWS.CognitoSyncManager.LocalStorage({DataStore: options.DataStore ? options.DataStore : AWS.CognitoSyncManager.StoreLocalStorage});\n\n        // Initialize remote store.\n        this.remote = new AWS.CognitoSyncManager.RemoteStorage(this.identityPoolId, this.provider);\n        this.remote.setUserAgent(USER_AGENT);\n\n    };\n\n    /**\n     * Returns a dataset object, creating it if it doesn't already exist.\n     * @param {string} datasetName\n     * @param {function} callback\n     */\n\n    AWS.CognitoSyncManager.prototype.openOrCreateDataset = function (datasetName, callback) {\n\n        var root = this;\n        var namePattern = new RegExp('^[a-zA-Z0-9_.:-]{1,128}$');\n\n        // Validate the proposed dataset name.\n\n        if (namePattern.test(datasetName)) {\n\n            this.local.createDataset(this.getIdentityId(), datasetName, function (err, data) {\n                if (err) {\n                    return callback(err, null);\n                }\n                callback(null, new AWS.CognitoSyncManager.Dataset(data, root.provider, root.local, root.remote, root.logger));\n            });\n\n        } else {\n\n            callback(new Error('Dataset name must match the pattern ' + namePattern.toString()));\n\n        }\n\n    };\n\n    /**\n     * Returns a list of datasets.\n     * @param {function} callback\n     */\n\n    AWS.CognitoSyncManager.prototype.listDatasets = function (callback) {\n        this.local.getDatasets(this.getIdentityId(), callback);\n    };\n\n    /**\n     * Replaces the local dataset metadata with the latest remote metadata.\n     * @param callback\n     */\n\n    AWS.CognitoSyncManager.prototype.refreshDatasetMetadata = function (callback) {\n\n        var root = this;\n\n        this.remote.getDatasets(function (err, datasets) {\n\n            var metadata = [];\n\n            var request = function (ds) {\n                root.local.updateDatasetMetadata(root.getIdentityId(), ds, response);\n            };\n\n            var response = function (err, md) {\n                metadata.push(md);\n                if (datasets.length > 0) {\n                    request(datasets.shift());\n                }\n                else {\n                    callback(null, metadata);\n                }\n            };\n\n            if (datasets.length > 0) {\n                request(datasets.shift(), callback);\n            } else {\n                callback(null, []);\n            }\n\n        });\n    };\n\n    /**\n     * Removes the local storage and invalidates the cached identity id.\n     */\n\n    AWS.CognitoSyncManager.prototype.wipeData = function () {\n        this.provider.clearCachedId();\n        this.local.wipeData();\n    };\n\n    /**\n     * Returns the cached identity id.\n     * @returns {string}\n     */\n\n    AWS.CognitoSyncManager.prototype.getIdentityId = function () {\n        return this.provider.identityId;\n    };\n\n}\n"
  },
  {
    "path": "src/CognitoSyncRecord.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.Record = (function() {\n\n    /**\n     * Constructs a new remote storage class.\n     * @param {Object} data\n     * @param {string} data.Key - The record's key\n     * @param {string} data.Value - The record's key\n     * @param {number} data.SyncCount\n     * @param {Date} data.LastModifiedDate\n     * @param {string} data.LastModifiedBy\n     * @param {Date} data.DeviceLastModifiedDate\n     * @param {boolean} data.Modified\n     * @constructor\n     */\n\n    var CognitoSyncRecord = function (data) {\n\n        data = data || {};\n\n        // Assign object\n        this.key = data.Key || '';\n        this.value = data.Value || '';\n        this.syncCount = data.SyncCount || 0;\n        this.lastModifiedDate = data.LastModifiedDate ? new Date(data.LastModifiedDate) : new Date();\n        this.lastModifiedBy = data.LastModifiedBy || '';\n        this.deviceLastModifiedDate = data.DeviceLastModifiedDate ? new Date(data.DeviceLastModifiedDate) : new Date();\n        this.modified = data.Modified || false;\n\n    };\n\n    /**\n     * Returns the record's key.\n     * @returns {string}\n     */\n\n    CognitoSyncRecord.prototype.getKey = function () {\n        return this.key;\n    };\n\n    /**\n     * Sets the record's key.\n     * @param key\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setKey = function (key) {\n        this.key = key;\n        return this;\n    };\n\n    /**\n     * Returns the record's value.\n     * @returns {string}\n     */\n\n    CognitoSyncRecord.prototype.getValue = function () {\n        return this.value;\n    };\n\n    /**\n     * Sets the record's value.\n     * @param value\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setValue = function (value) {\n        this.value = value;\n        return this;\n    };\n\n    /**\n     * Returns the current sync count.\n     * @returns {number}\n     */\n\n    CognitoSyncRecord.prototype.getSyncCount = function () {\n        return this.syncCount;\n    };\n\n    /**\n     * Sets the current sync count.\n     * @param syncCount\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setSyncCount = function (syncCount) {\n        this.syncCount = syncCount;\n        return this;\n    };\n\n    /**\n     * Returns the date the record was last modified.\n     * @returns {Date}\n     */\n\n    CognitoSyncRecord.prototype.getLastModifiedDate = function () {\n        return new Date(this.lastModifiedDate);\n    };\n\n    /**\n     * Sets the date the record was last modified.\n     * @param modifiedDate\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setLastModifiedDate = function (modifiedDate) {\n        this.lastModifiedDate = new Date(modifiedDate);\n        return this;\n    };\n\n    /**\n     * Returns the user/device who last modified the record.\n     * @returns {string}\n     */\n\n    CognitoSyncRecord.prototype.getLastModifiedBy = function () {\n        return this.lastModifiedBy;\n    };\n\n    /**\n     * Sets the user/device who last modified the record.\n     * @param modifiedBy\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setLastModifiedBy = function (modifiedBy) {\n        this.lastModifiedBy = modifiedBy;\n        return this;\n    };\n\n    /**\n     * Returns the date when the record was last modified on the local device.\n     * @returns {Date}\n     */\n\n    CognitoSyncRecord.prototype.getDeviceLastModifiedDate = function () {\n        return new Date(this.deviceLastModifiedDate);\n    };\n\n    /**\n     * Sets the date when the record was last modified on the local device.\n     * @param modifiedDate\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setDeviceLastModifiedDate = function (modifiedDate) {\n        this.deviceLastModifiedDate = new Date(modifiedDate);\n        return this;\n    };\n\n    /**\n     * Returns if the record has been modified.\n     * @returns {boolean}\n     */\n\n    CognitoSyncRecord.prototype.isModified = function () {\n        return this.modified;\n    };\n\n    /**\n     * Sets if the record has been modified.\n     * @param modified\n     * @returns {CognitoSyncRecord}\n     */\n\n    CognitoSyncRecord.prototype.setModified = function (modified) {\n        this.modified = modified;\n        return this;\n    };\n\n    /**\n     * Returns if the record has been deleted locally.\n     * @returns {boolean}\n     */\n\n    CognitoSyncRecord.prototype.isDeleted = function () {\n        return this.value === null;\n    };\n\n    /**\n     * Returns a string representation of the record.\n     * @returns {string}\n     */\n\n    CognitoSyncRecord.prototype.toString = function () {\n        return JSON.stringify(this);\n    };\n\n    /**\n     * Returns a flat object representing the record.\n     * @returns {object}\n     */\n\n    CognitoSyncRecord.prototype.toJSON = function () {\n        return {\n            Key: this.key,\n            Value: this.value,\n            SyncCount: this.syncCount,\n            LastModifiedDate: this.lastModifiedDate,\n            LastModifiedBy: this.lastModifiedBy,\n            DeviceLastModifiedDate: this.deviceLastModifiedDate,\n            Modified: this.modified\n        };\n    };\n\n    return CognitoSyncRecord;\n\n})();\n"
  },
  {
    "path": "src/CognitoSyncRemoteStorage.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.RemoteStorage = (function() {\n\n    /**\n     * Constructs a new remote storage class.\n     * @param {string} identityPoolId\n     * @param provider\n     * @constructor\n     */\n\n    var CognitoSyncRemoteStorage = function (identityPoolId, provider) {\n\n        this.identityPoolId = identityPoolId;\n        this.provider = provider;\n        this.client = new AWS.CognitoSync();\n\n    };\n\n    CognitoSyncRemoteStorage.prototype.userAgent = '';\n\n    /**\n     * Gets the current identity ID from the AWS credentials provider.\n     * @returns {string}\n     */\n\n    CognitoSyncRemoteStorage.prototype.getIdentityId = function () {\n        return this.provider.identityId;\n    };\n\n    /**\n     * Returns a list of datasets.\n     * @param {function} callback Callback(Error, Datasets)\n     */\n\n    CognitoSyncRemoteStorage.prototype.getDatasets = function (callback) {\n\n        var root = this;\n        var datasets = [];\n        var nextToken = null;\n\n        // Define the request function. Will be called once per page of results.\n\n        var fetch = function (token, cb) {\n            root.client.listDatasets({\n                IdentityId: root.getIdentityId(),\n                IdentityPoolId: root.identityPoolId,\n                MaxResults: 64,\n                NextToken: token\n            }, cb);\n        };\n\n        // Define the response function. Will be called after each request returns.\n\n        var process = function (err, data) {\n\n            var results = data.Datasets || [];\n\n            // Add the new page of results to the list of datasets.\n\n            for (var i = 0; i < results.length; i++) {\n                datasets.push(new AWS.CognitoSyncManager.DatasetMetadata(results[i]));\n            }\n\n            // Get the NextToken. If it exists, fetch the next page of results, otherwise callback.\n\n            nextToken = data.NextToken;\n\n            if (nextToken) {\n                fetch(nextToken, process);\n            }\n            else {\n                callback(null, datasets);\n            }\n\n        };\n\n        // Start the first fetch.\n\n        fetch(nextToken, process);\n\n    };\n\n    /**\n     * Lists all updates on the remote store since the given sync count.\n     * @param {string} datasetName\n     * @param {number} lastSyncCount\n     * @param {function} callback Callback(Error, Updates)\n     */\n\n    CognitoSyncRemoteStorage.prototype.listUpdates = function (datasetName, lastSyncCount, callback) {\n\n        var root = this;\n        var nextToken = null;\n        var updatedRecords = new AWS.CognitoSyncManager.DatasetUpdates(datasetName);\n\n        var request = function (token, cb) {\n            root.client.listRecords({\n                DatasetName: datasetName,\n                IdentityId: root.getIdentityId(),\n                IdentityPoolId: root.identityPoolId,\n                LastSyncCount: lastSyncCount,\n                MaxResults: 1024,\n                NextToken: token\n            }, cb);\n        };\n\n        var response = function (err, data) {\n\n            if (err) { return callback(err); }\n\n            data = data || {};\n\n            var results = data.Records || [], r;\n\n            for (var i = 0; i < results.length; i++) {\n                r = new AWS.CognitoSyncManager.Record(results[i]);\n                r.setModified(false);\n                updatedRecords.addRecord(r);\n            }\n\n            updatedRecords.setSyncSessionToken(data.SyncSessionToken)\n                .setSyncCount(data.DatasetSyncCount)\n                .setExists(data.DatasetExists)\n                .setDeleted(data.DatasetDeletedAfterRequestedSyncCount);\n\n            if (data.MergedDatasetNames) {\n                updatedRecords.setMergedDatasetNameList(data.MergedDatasetNames);\n            }\n\n            nextToken = data.NextToken;\n\n            if (nextToken) {\n                request(nextToken, response);\n            } else {\n                callback(null, updatedRecords);\n            }\n\n        };\n\n\n        request(null, response);\n\n    };\n\n    /**\n     * Write records to the remote data store.\n     * @param {string} datasetName\n     * @param {array} records\n     * @param {string} syncSessionToken\n     * @param {function} callback\n     */\n\n    CognitoSyncRemoteStorage.prototype.putRecords = function (datasetName, records, syncSessionToken, callback) {\n\n        var root = this;\n\n        var patches = [];\n        var record;\n\n        for (var r in records) {\n            if (records.hasOwnProperty(r)) {\n\n                record = records[r];\n\n                patches.push({\n                    Key: record.getKey(),\n                    Op: record.getValue() ? 'replace' : 'remove',\n                    SyncCount: record.getSyncCount(),\n                    DeviceLastModifiedDate: record.getDeviceLastModifiedDate(),\n                    Value: record.getValue()\n                });\n\n            }\n        }\n\n        this.client.updateRecords({\n            DatasetName: datasetName,\n            IdentityId: root.getIdentityId(),\n            IdentityPoolId: root.identityPoolId,\n            SyncSessionToken: syncSessionToken,\n            RecordPatches: patches\n        }, function (err, data) {\n\n            var dsName = typeof datasetName === 'string' ? datasetName : '(invalid dataset name)';\n\n            if (err) {\n                return callback(new Error('Failed to update records in dataset: ' + dsName + ' (' + err.message + ')'), null);\n            }\n\n            var records = [], r;\n\n            for (var i = 0; i < data.Records.length; i++) {\n                r = new AWS.CognitoSyncManager.Record(data.Records[i]);\n                r.setModified(false);\n                records.push(r);\n            }\n\n            return callback(null, records);\n\n        });\n\n    };\n\n    /**\n     * Delete the dataset from the remote data store.\n     * @param {string} datasetName\n     * @param {function} callback Callback(Error, IsSuccessful)\n     */\n\n    CognitoSyncRemoteStorage.prototype.deleteDataset = function (datasetName, callback) {\n\n        this.client.deleteDataset({\n            DatasetName: datasetName,\n            IdentityId: this.getIdentityId(),\n            IdentityPoolId: this.identityPoolId\n        }, function (err, data) {\n\n            if (err) {\n                return callback(new Error('Failed to delete dataset.'), null);\n            }\n\n            return callback(null, data);\n\n        });\n\n    };\n\n    /**\n     * Gets the dataset metdata from the remote data store.\n     * @param {string} datasetName\n     * @param {function} callback Callback(Error, Metadata)\n     */\n\n    CognitoSyncRemoteStorage.prototype.getDatasetMetadata = function (datasetName, callback) {\n\n        this.client.describeDataset({\n            DatasetName: datasetName,\n            IdentityId: this.getIdentityId(),\n            IdentityPoolId: this.identityPoolId\n        }, function (err, data) {\n\n            if (err) {\n                return callback(new Error('Failed to get dataset metadata.'), null);\n            }\n\n            return callback(null, new AWS.CognitoSyncManager.DatasetMetadata(data.Dataset));\n\n        });\n\n    };\n\n    CognitoSyncRemoteStorage.prototype.setUserAgent = function (userAgent) {\n        this.userAgent = userAgent;\n    };\n\n    return CognitoSyncRemoteStorage;\n\n})();"
  },
  {
    "path": "src/CognitoSyncStoreInMemory.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.StoreInMemory = (function() {\n\n    /**\n     * Storage adapter for using the browser's memory as the Cognito Sync data cache.\n     * @prop {object} store A reference to an object in memory.\n     * @constructor\n     */\n\n    var CognitoSyncStoreInMemory = function () {\n        this.store = {};\n    };\n\n    /**\n     * Constructs the key by combining the identity ID and the dataset name.\n     * @param identityId\n     * @param datasetName\n     * @returns {string}\n     */\n\n    CognitoSyncStoreInMemory.prototype.makeKey = function (identityId, datasetName) {\n        return identityId + '.' + datasetName;\n    };\n\n    /**\n     * Gets an item from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.get = function (identityId, datasetName, key, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        if (!identityId || !datasetName) {\n            return callback(new Error('You must provide an identity id and dataset name.'), null);\n        }\n\n        if (this.store[k] && this.store[k][key]) {\n            return callback(null, this.store[k][key]);\n        }\n\n        return callback(null, undefined);\n\n    };\n\n    /**\n     * Gets a dataset from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.getAll = function (identityId, datasetName, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        if (!identityId || !datasetName) {\n            return callback(new Error('You must provide an identity id and dataset name.'), null);\n        }\n\n        return callback(null, this.store[k]);\n\n    };\n\n    /**\n     * Sets a record in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param value\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.set = function (identityId, datasetName, key, value, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        var entry = this.store[k] || {};\n        entry[key] = value;\n\n        this.store[k] = entry;\n\n        return callback(null, entry);\n\n    };\n\n    /**\n     * Sets an entire dataset in the local store.\n     * @param identityId\n     * @param datasetName\n     * @param obj\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.setAll = function (identityId, datasetName, obj, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n        this.store[k] = obj;\n\n        return callback(null, obj);\n\n    };\n\n    /**\n     * Removes a record from the local store.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.remove = function (identityId, datasetName, key, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        var records = JSON.parse(this.store[k]);\n        if (!records) {\n            records = {};\n        }\n\n        delete(records[key]);\n\n        this.store[k] = JSON.stringify(records);\n\n        return callback(null, true);\n\n    };\n\n    /**\n     * Removes dataset from local store.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.removeAll = function (identityId, datasetName, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n        delete(this.store[k]);\n\n        return callback(null, true);\n\n    };\n\n    /**\n     * Clears the local store, including cached values.\n     * @param callback\n     */\n\n    CognitoSyncStoreInMemory.prototype.wipe = function (callback) {\n        this.store = {};\n        return callback(null, true);\n    };\n\n    return CognitoSyncStoreInMemory;\n\n})();"
  },
  {
    "path": "src/CognitoSyncStoreLocalStorage.js",
    "content": "// Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nAWS = AWS || {};\nAWS.CognitoSyncManager = AWS.CognitoSyncManager || {};\n\nAWS.CognitoSyncManager.StoreLocalStorage = (function() {\n\n    /**\n     * Storage adapter for using the browser's local storage as the Cognito Sync data cache.\n     * @prop {window.localStorage} store A reference to the browser's local storage API.\n     * @constructor\n     */\n\n    var CognitoSyncStoreLocalStorage = function () {\n        this.store = window.localStorage;\n    };\n\n    /**\n     * Constructs the key by combining the identity ID and the dataset name.\n     * @param {string} identityId\n     * @param {string} datasetName\n     * @returns {string}\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.makeKey = function (identityId, datasetName) {\n        return identityId + '.' + datasetName;\n    };\n\n    /**\n     * Returns a value from local storage.\n     * @param {string} identityId The identity that owns the dataset.\n     * @param {string} datasetName The name of the dataset.\n     * @param {string} key The key of the record to return.\n     * @param {function} callback\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.get = function (identityId, datasetName, key, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        if (!identityId || !datasetName) {\n            return callback(new Error('You must provide an identity id and dataset name.'), null);\n        }\n\n        var records = JSON.parse(this.store.getItem(k));\n\n        if (records && records[key]) {\n            return callback(null, records[key]);\n        }\n\n        return callback(null, undefined);\n\n    };\n\n    /**\n     * Gets all records from local storage.\n     * @param identityId\n     * @param datasetName\n     * @param callback Callback(Error, Items)\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.getAll = function (identityId, datasetName, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        if (!identityId || !datasetName) {\n            return callback(new Error('You must provide an identity id and dataset name.'), null);\n        }\n\n        return callback(null, JSON.parse(this.store.getItem(k)));\n\n    };\n\n    /**\n     * Sets a value in local storage.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param value\n     * @param callback Callback(Error, Records)\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.set = function (identityId, datasetName, key, value, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        var records = JSON.parse(this.store.getItem(k));\n        if (!records) {\n            records = {};\n        }\n\n        records[key] = value;\n\n        this.store.setItem(k, JSON.stringify(records));\n\n        callback(null, records);\n\n        return this;\n\n    };\n\n    /**\n     * Sets all values of a dataset.\n     * @param identityId\n     * @param datasetName\n     * @param obj\n     * @param callback Callback(Error, Object)\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.setAll = function (identityId, datasetName, obj, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        this.store.setItem(k, JSON.stringify(obj));\n\n        return callback(null, obj);\n\n    };\n\n    /**\n     * Removes an item from local storage.\n     * @param identityId\n     * @param datasetName\n     * @param key\n     * @param callback\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.remove = function (identityId, datasetName, key, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n\n        var records = JSON.parse(this.store.getItem(k));\n        if (!records) {\n            records = {};\n        }\n\n        delete(records[key]);\n\n        this.store.setItem(k, JSON.stringify(records));\n\n        return callback(null, true);\n\n    };\n\n    /**\n     * Removes dataset from local storage.\n     * @param identityId\n     * @param datasetName\n     * @param callback\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.removeAll = function (identityId, datasetName, callback) {\n\n        var k = this.makeKey(identityId, datasetName);\n        this.store.removeItem(k);\n\n        return callback(null, true);\n\n    };\n\n    /**\n     * Clears local storage, including cached values.\n     * @param callback\n     */\n\n    CognitoSyncStoreLocalStorage.prototype.wipe = function (callback) {\n\n        // We don't want to remove the cached identity id. Remove all other keys.\n\n        for (var prop in this.store) {\n            if (this.store.hasOwnProperty(prop)) {\n                if (prop.indexOf('aws.cognito.identity') === -1) {\n                    this.store.removeItem(prop);\n                }\n            }\n        }\n\n        if (callback) {\n            return callback(null, true);\n        }\n        return this;\n\n    };\n\n    return CognitoSyncStoreLocalStorage;\n\n})();"
  }
]