├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── config.js ├── contacts.js ├── package-lock.json ├── package.json ├── public ├── karen.jpg ├── richard.jpg └── tyler.jpg ├── server.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We would love to have you contribute to this project! 4 | 5 | ## How To Contribute 6 | 7 | * check the [existing issues](https://github.com/udacity/reactnd-contacts-server/issues) to see if one matches the change you want to add 8 | * fork this project 9 | * create a descriptive branch name that starts with your name 10 | * make all changes on this branch 11 | * push this branch to your fork 12 | * submit a pull request 13 | 14 | ## Best Practices 15 | 16 | Make sure to follow these conventions: 17 | 18 | * commit messages must start with a capital 19 | * commit message should answer this question: `This commit will...` 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server for Contacts Project 2 | 3 | This is a backend server for the Contacts app in-class project. This project is part of [Udacity's React Nanodegree program](https://www.udacity.com/course/react-nanodegree--nd019). 4 | 5 | You'll build the front end of the Contacts app throughout the course. Because the course is on React and doesn't cover Node or servers, we've built this server and an API to interact with it so can focus on building the front end portion of the project in React. 6 | 7 | ## Getting Set Up 8 | 9 | Getting the server running on your local machine takes only a few steps: 10 | 11 | 1. clone the project - `git clone https://github.com/udacity/reactnd-contacts-server2.git` 12 | 2. `cd reactnd-contacts-server2` 13 | 3. install its dependencies - `npm install` 14 | 4. start the server - `node server.js` 15 | 16 | ## Contributing 17 | 18 | We love receiving pull requests! For specifics on how to contribute to this project, check out the [contributing file](CONTRIBUTING.md). 19 | 20 | ## License 21 | MIT 22 | 23 | # Archival Note 24 | This repository is deprecated; therefore, we are going to archive it. However, learners will be able to fork it to their personal Github account but cannot submit PRs to this repository. If you have any issues or suggestions to make, feel free to: 25 | - Utilize the https://knowledge.udacity.com/ forum to seek help on content-specific issues. 26 | - Submit a support ticket along with the link to your forked repository if (learners are) blocked for other reasons. Here are the links for the [retail consumers](https://udacity.zendesk.com/hc/en-us/requests/new) and [enterprise learners](https://udacityenterprise.zendesk.com/hc/en-us/requests/new?ticket_form_id=360000279131). -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | exports.port = process.env.PORT || 5001 2 | exports.origin = process.env.ORIGIN || `http://localhost:${exports.port}` 3 | -------------------------------------------------------------------------------- /contacts.js: -------------------------------------------------------------------------------- 1 | const clone = require('clone') 2 | const config = require('./config') 3 | 4 | const db = {} 5 | 6 | const defaultData = { 7 | contacts: [ 8 | { 9 | id: 'richard', 10 | name: 'Richard Kalehoff', 11 | handle: '@richardkalehoff', 12 | avatarURL: config.origin + '/richard.jpg' 13 | }, 14 | { 15 | id: 'karen', 16 | name: 'Karen Isgrigg', 17 | handle: '@karen_isgrigg', 18 | avatarURL: config.origin + '/karen.jpg' 19 | }, 20 | { 21 | id: 'tyler', 22 | name: 'Tyler McGinnis', 23 | handle: '@tylermcginnis', 24 | avatarURL: config.origin + '/tyler.jpg' 25 | } 26 | ] 27 | } 28 | 29 | const get = (token) => { 30 | let data = db[token] 31 | 32 | if (data == null) { 33 | data = db[token] = clone(defaultData) 34 | } 35 | 36 | return data 37 | } 38 | 39 | const add = (token, contact) => { 40 | if (!contact.id) { 41 | contact.id = Math.random().toString(36).substr(-8) 42 | } 43 | 44 | get(token).contacts.push(contact) 45 | 46 | return contact 47 | } 48 | 49 | const remove = (token, id) => { 50 | const data = get(token) 51 | const contact = data.contacts.find(c => c.id === id) 52 | 53 | if (contact) { 54 | data.contacts = data.contacts.filter(c => c !== contact) 55 | } 56 | 57 | return { contact } 58 | } 59 | 60 | module.exports = { 61 | get, 62 | add, 63 | remove 64 | } 65 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "accepts": { 6 | "version": "1.3.5", 7 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 8 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 9 | "requires": { 10 | "mime-types": "~2.1.18", 11 | "negotiator": "0.6.1" 12 | } 13 | }, 14 | "array-flatten": { 15 | "version": "1.1.1", 16 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 17 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 18 | }, 19 | "body-parser": { 20 | "version": "1.18.3", 21 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 22 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 23 | "requires": { 24 | "bytes": "3.0.0", 25 | "content-type": "~1.0.4", 26 | "debug": "2.6.9", 27 | "depd": "~1.1.2", 28 | "http-errors": "~1.6.3", 29 | "iconv-lite": "0.4.23", 30 | "on-finished": "~2.3.0", 31 | "qs": "6.5.2", 32 | "raw-body": "2.3.3", 33 | "type-is": "~1.6.16" 34 | } 35 | }, 36 | "bytes": { 37 | "version": "3.0.0", 38 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 39 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 40 | }, 41 | "clone": { 42 | "version": "2.1.2", 43 | "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", 44 | "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" 45 | }, 46 | "content-disposition": { 47 | "version": "0.5.2", 48 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 49 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 50 | }, 51 | "content-type": { 52 | "version": "1.0.4", 53 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 54 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 55 | }, 56 | "cookie": { 57 | "version": "0.3.1", 58 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 59 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 60 | }, 61 | "cookie-signature": { 62 | "version": "1.0.6", 63 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 64 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 65 | }, 66 | "cors": { 67 | "version": "2.8.5", 68 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 69 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 70 | "requires": { 71 | "object-assign": "^4", 72 | "vary": "^1" 73 | } 74 | }, 75 | "debug": { 76 | "version": "2.6.9", 77 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 78 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 79 | "requires": { 80 | "ms": "2.0.0" 81 | } 82 | }, 83 | "depd": { 84 | "version": "1.1.2", 85 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 86 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 87 | }, 88 | "destroy": { 89 | "version": "1.0.4", 90 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 91 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 92 | }, 93 | "ee-first": { 94 | "version": "1.1.1", 95 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 96 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 97 | }, 98 | "encodeurl": { 99 | "version": "1.0.2", 100 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 101 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 102 | }, 103 | "escape-html": { 104 | "version": "1.0.3", 105 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 106 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 107 | }, 108 | "etag": { 109 | "version": "1.8.1", 110 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 111 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 112 | }, 113 | "express": { 114 | "version": "4.16.4", 115 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 116 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 117 | "requires": { 118 | "accepts": "~1.3.5", 119 | "array-flatten": "1.1.1", 120 | "body-parser": "1.18.3", 121 | "content-disposition": "0.5.2", 122 | "content-type": "~1.0.4", 123 | "cookie": "0.3.1", 124 | "cookie-signature": "1.0.6", 125 | "debug": "2.6.9", 126 | "depd": "~1.1.2", 127 | "encodeurl": "~1.0.2", 128 | "escape-html": "~1.0.3", 129 | "etag": "~1.8.1", 130 | "finalhandler": "1.1.1", 131 | "fresh": "0.5.2", 132 | "merge-descriptors": "1.0.1", 133 | "methods": "~1.1.2", 134 | "on-finished": "~2.3.0", 135 | "parseurl": "~1.3.2", 136 | "path-to-regexp": "0.1.7", 137 | "proxy-addr": "~2.0.4", 138 | "qs": "6.5.2", 139 | "range-parser": "~1.2.0", 140 | "safe-buffer": "5.1.2", 141 | "send": "0.16.2", 142 | "serve-static": "1.13.2", 143 | "setprototypeof": "1.1.0", 144 | "statuses": "~1.4.0", 145 | "type-is": "~1.6.16", 146 | "utils-merge": "1.0.1", 147 | "vary": "~1.1.2" 148 | }, 149 | "dependencies": { 150 | "statuses": { 151 | "version": "1.4.0", 152 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 153 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 154 | } 155 | } 156 | }, 157 | "finalhandler": { 158 | "version": "1.1.1", 159 | "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 160 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 161 | "requires": { 162 | "debug": "2.6.9", 163 | "encodeurl": "~1.0.2", 164 | "escape-html": "~1.0.3", 165 | "on-finished": "~2.3.0", 166 | "parseurl": "~1.3.2", 167 | "statuses": "~1.4.0", 168 | "unpipe": "~1.0.0" 169 | }, 170 | "dependencies": { 171 | "statuses": { 172 | "version": "1.4.0", 173 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 174 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 175 | } 176 | } 177 | }, 178 | "forwarded": { 179 | "version": "0.1.2", 180 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 181 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 182 | }, 183 | "fresh": { 184 | "version": "0.5.2", 185 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 186 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 187 | }, 188 | "http-errors": { 189 | "version": "1.6.3", 190 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 191 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 192 | "requires": { 193 | "depd": "~1.1.2", 194 | "inherits": "2.0.3", 195 | "setprototypeof": "1.1.0", 196 | "statuses": ">= 1.4.0 < 2" 197 | } 198 | }, 199 | "iconv-lite": { 200 | "version": "0.4.23", 201 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 202 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 203 | "requires": { 204 | "safer-buffer": ">= 2.1.2 < 3" 205 | } 206 | }, 207 | "inherits": { 208 | "version": "2.0.3", 209 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 210 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 211 | }, 212 | "ipaddr.js": { 213 | "version": "1.8.0", 214 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 215 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 216 | }, 217 | "media-typer": { 218 | "version": "0.3.0", 219 | "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 220 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 221 | }, 222 | "merge-descriptors": { 223 | "version": "1.0.1", 224 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 225 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 226 | }, 227 | "methods": { 228 | "version": "1.1.2", 229 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 230 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 231 | }, 232 | "mime": { 233 | "version": "1.4.1", 234 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 235 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 236 | }, 237 | "mime-db": { 238 | "version": "1.37.0", 239 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 240 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 241 | }, 242 | "mime-types": { 243 | "version": "2.1.21", 244 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 245 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 246 | "requires": { 247 | "mime-db": "~1.37.0" 248 | } 249 | }, 250 | "ms": { 251 | "version": "2.0.0", 252 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 253 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 254 | }, 255 | "negotiator": { 256 | "version": "0.6.1", 257 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 258 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 259 | }, 260 | "object-assign": { 261 | "version": "4.1.1", 262 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 263 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 264 | }, 265 | "on-finished": { 266 | "version": "2.3.0", 267 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 268 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 269 | "requires": { 270 | "ee-first": "1.1.1" 271 | } 272 | }, 273 | "parseurl": { 274 | "version": "1.3.2", 275 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 276 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 277 | }, 278 | "path-to-regexp": { 279 | "version": "0.1.7", 280 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 281 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 282 | }, 283 | "proxy-addr": { 284 | "version": "2.0.4", 285 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 286 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 287 | "requires": { 288 | "forwarded": "~0.1.2", 289 | "ipaddr.js": "1.8.0" 290 | } 291 | }, 292 | "qs": { 293 | "version": "6.5.2", 294 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 295 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 296 | }, 297 | "range-parser": { 298 | "version": "1.2.0", 299 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 300 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 301 | }, 302 | "raw-body": { 303 | "version": "2.3.3", 304 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 305 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 306 | "requires": { 307 | "bytes": "3.0.0", 308 | "http-errors": "1.6.3", 309 | "iconv-lite": "0.4.23", 310 | "unpipe": "1.0.0" 311 | } 312 | }, 313 | "safe-buffer": { 314 | "version": "5.1.2", 315 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 316 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 317 | }, 318 | "safer-buffer": { 319 | "version": "2.1.2", 320 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 321 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 322 | }, 323 | "send": { 324 | "version": "0.16.2", 325 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 326 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 327 | "requires": { 328 | "debug": "2.6.9", 329 | "depd": "~1.1.2", 330 | "destroy": "~1.0.4", 331 | "encodeurl": "~1.0.2", 332 | "escape-html": "~1.0.3", 333 | "etag": "~1.8.1", 334 | "fresh": "0.5.2", 335 | "http-errors": "~1.6.2", 336 | "mime": "1.4.1", 337 | "ms": "2.0.0", 338 | "on-finished": "~2.3.0", 339 | "range-parser": "~1.2.0", 340 | "statuses": "~1.4.0" 341 | }, 342 | "dependencies": { 343 | "statuses": { 344 | "version": "1.4.0", 345 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 346 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 347 | } 348 | } 349 | }, 350 | "serve-static": { 351 | "version": "1.13.2", 352 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 353 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 354 | "requires": { 355 | "encodeurl": "~1.0.2", 356 | "escape-html": "~1.0.3", 357 | "parseurl": "~1.3.2", 358 | "send": "0.16.2" 359 | } 360 | }, 361 | "setprototypeof": { 362 | "version": "1.1.0", 363 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 364 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 365 | }, 366 | "statuses": { 367 | "version": "1.5.0", 368 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 369 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 370 | }, 371 | "type-is": { 372 | "version": "1.6.16", 373 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 374 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 375 | "requires": { 376 | "media-typer": "0.3.0", 377 | "mime-types": "~2.1.18" 378 | } 379 | }, 380 | "unpipe": { 381 | "version": "1.0.0", 382 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 383 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 384 | }, 385 | "utils-merge": { 386 | "version": "1.0.1", 387 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 388 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 389 | }, 390 | "vary": { 391 | "version": "1.1.2", 392 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 393 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 394 | } 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "body-parser": "^1.18.3", 4 | "clone": "^2.1.1", 5 | "cors": "^2.8.3", 6 | "express": "^4.16.4" 7 | }, 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/udacity/reactnd-contacts-server2.git" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /public/karen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/reactnd-contacts-server2/ee87f92726c7a159fa1f6a36059fdc82ce17cd82/public/karen.jpg -------------------------------------------------------------------------------- /public/richard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/reactnd-contacts-server2/ee87f92726c7a159fa1f6a36059fdc82ce17cd82/public/richard.jpg -------------------------------------------------------------------------------- /public/tyler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/reactnd-contacts-server2/ee87f92726c7a159fa1f6a36059fdc82ce17cd82/public/tyler.jpg -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const bodyParser = require('body-parser') 3 | const cors = require('cors') 4 | const config = require('./config') 5 | const contacts = require('./contacts') 6 | 7 | const app = express() 8 | 9 | app.use(express.static('public')) 10 | app.use(cors()) 11 | 12 | app.get('/', (req, res) => { 13 | const help = ` 14 |
15 |     Welcome to the Address Book API!
16 | 
17 |     Use an Authorization header to work with your own data:
18 | 
19 |     fetch(url, { headers: { 'Authorization': 'whatever-you-want' }})
20 | 
21 |     The following endpoints are available:
22 | 
23 |     GET /contacts
24 |     DELETE /contacts/:id
25 |     POST /contacts { name, handle, avatarURL }
26 |   
27 | ` 28 | 29 | res.send(help) 30 | }) 31 | 32 | app.use((req, res, next) => { 33 | const token = req.get('Authorization') 34 | 35 | if (token) { 36 | req.token = token 37 | next() 38 | } else { 39 | res.status(403).send({ 40 | error: 'Please provide an Authorization header to identify yourself (can be whatever you want)' 41 | }) 42 | } 43 | }) 44 | 45 | app.get('/contacts', (req, res) => { 46 | res.send(contacts.get(req.token)) 47 | }) 48 | 49 | app.delete('/contacts/:id', (req, res) => { 50 | res.send(contacts.remove(req.token, req.params.id)) 51 | }) 52 | 53 | app.post('/contacts', bodyParser.json(), (req, res) => { 54 | const { name, handle } = req.body 55 | 56 | if (name && handle) { 57 | res.send(contacts.add(req.token, req.body)) 58 | } else { 59 | res.status(403).send({ 60 | error: 'Please provide both a name and a handle' 61 | }) 62 | } 63 | }) 64 | 65 | app.listen(config.port, () => { 66 | console.log('Server listening on port %s, Ctrl+C to stop', config.port) 67 | }) 68 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.3: 6 | version "1.3.3" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" 8 | dependencies: 9 | mime-types "~2.1.11" 10 | negotiator "0.6.1" 11 | 12 | array-flatten@1.1.1: 13 | version "1.1.1" 14 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 15 | 16 | body-parser@^1.17.1: 17 | version "1.17.1" 18 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" 19 | dependencies: 20 | bytes "2.4.0" 21 | content-type "~1.0.2" 22 | debug "2.6.1" 23 | depd "~1.1.0" 24 | http-errors "~1.6.1" 25 | iconv-lite "0.4.15" 26 | on-finished "~2.3.0" 27 | qs "6.4.0" 28 | raw-body "~2.2.0" 29 | type-is "~1.6.14" 30 | 31 | busboy@^0.2.14: 32 | version "0.2.14" 33 | resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" 34 | dependencies: 35 | dicer "0.2.5" 36 | readable-stream "1.1.x" 37 | 38 | bytes@2.4.0: 39 | version "2.4.0" 40 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" 41 | 42 | clone@^2.1.1: 43 | version "2.1.1" 44 | resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" 45 | 46 | connect-multiparty@^2.0.0: 47 | version "2.0.0" 48 | resolved "https://registry.yarnpkg.com/connect-multiparty/-/connect-multiparty-2.0.0.tgz#57a7b61cc7b31b6eef4a62878d60d771b23699ab" 49 | dependencies: 50 | multiparty "~4.1.2" 51 | on-finished "~2.3.0" 52 | qs "~4.0.0" 53 | type-is "~1.6.4" 54 | 55 | content-disposition@0.5.2: 56 | version "0.5.2" 57 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 58 | 59 | content-type@~1.0.2: 60 | version "1.0.2" 61 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" 62 | 63 | cookie-signature@1.0.6: 64 | version "1.0.6" 65 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 66 | 67 | cookie@0.3.1: 68 | version "0.3.1" 69 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 70 | 71 | core-util-is@~1.0.0: 72 | version "1.0.2" 73 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 74 | 75 | cors@^2.8.3: 76 | version "2.8.3" 77 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.3.tgz#4cf78e1d23329a7496b2fc2225b77ca5bb5eb802" 78 | dependencies: 79 | object-assign "^4" 80 | vary "^1" 81 | 82 | debug@2.6.1: 83 | version "2.6.1" 84 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" 85 | dependencies: 86 | ms "0.7.2" 87 | 88 | debug@2.6.3: 89 | version "2.6.3" 90 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" 91 | dependencies: 92 | ms "0.7.2" 93 | 94 | depd@1.1.0, depd@~1.1.0: 95 | version "1.1.0" 96 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" 97 | 98 | destroy@~1.0.4: 99 | version "1.0.4" 100 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 101 | 102 | dicer@0.2.5: 103 | version "0.2.5" 104 | resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" 105 | dependencies: 106 | readable-stream "1.1.x" 107 | streamsearch "0.1.2" 108 | 109 | ee-first@1.1.1: 110 | version "1.1.1" 111 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 112 | 113 | encodeurl@~1.0.1: 114 | version "1.0.1" 115 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" 116 | 117 | escape-html@~1.0.3: 118 | version "1.0.3" 119 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 120 | 121 | etag@~1.8.0: 122 | version "1.8.0" 123 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" 124 | 125 | express@^4.15.2: 126 | version "4.15.2" 127 | resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" 128 | dependencies: 129 | accepts "~1.3.3" 130 | array-flatten "1.1.1" 131 | content-disposition "0.5.2" 132 | content-type "~1.0.2" 133 | cookie "0.3.1" 134 | cookie-signature "1.0.6" 135 | debug "2.6.1" 136 | depd "~1.1.0" 137 | encodeurl "~1.0.1" 138 | escape-html "~1.0.3" 139 | etag "~1.8.0" 140 | finalhandler "~1.0.0" 141 | fresh "0.5.0" 142 | merge-descriptors "1.0.1" 143 | methods "~1.1.2" 144 | on-finished "~2.3.0" 145 | parseurl "~1.3.1" 146 | path-to-regexp "0.1.7" 147 | proxy-addr "~1.1.3" 148 | qs "6.4.0" 149 | range-parser "~1.2.0" 150 | send "0.15.1" 151 | serve-static "1.12.1" 152 | setprototypeof "1.0.3" 153 | statuses "~1.3.1" 154 | type-is "~1.6.14" 155 | utils-merge "1.0.0" 156 | vary "~1.1.0" 157 | 158 | fd-slicer@~1.0.1: 159 | version "1.0.1" 160 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" 161 | dependencies: 162 | pend "~1.2.0" 163 | 164 | finalhandler@~1.0.0: 165 | version "1.0.1" 166 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" 167 | dependencies: 168 | debug "2.6.3" 169 | encodeurl "~1.0.1" 170 | escape-html "~1.0.3" 171 | on-finished "~2.3.0" 172 | parseurl "~1.3.1" 173 | statuses "~1.3.1" 174 | unpipe "~1.0.0" 175 | 176 | forwarded@~0.1.0: 177 | version "0.1.0" 178 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" 179 | 180 | fresh@0.5.0: 181 | version "0.5.0" 182 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" 183 | 184 | http-errors@~1.6.1: 185 | version "1.6.1" 186 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" 187 | dependencies: 188 | depd "1.1.0" 189 | inherits "2.0.3" 190 | setprototypeof "1.0.3" 191 | statuses ">= 1.3.1 < 2" 192 | 193 | iconv-lite@0.4.15: 194 | version "0.4.15" 195 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" 196 | 197 | inherits@2.0.3, inherits@~2.0.1: 198 | version "2.0.3" 199 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 200 | 201 | ipaddr.js@1.3.0: 202 | version "1.3.0" 203 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" 204 | 205 | isarray@0.0.1: 206 | version "0.0.1" 207 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 208 | 209 | media-typer@0.3.0: 210 | version "0.3.0" 211 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 212 | 213 | merge-descriptors@1.0.1: 214 | version "1.0.1" 215 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 216 | 217 | methods@~1.1.2: 218 | version "1.1.2" 219 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 220 | 221 | mime-db@~1.27.0: 222 | version "1.27.0" 223 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 224 | 225 | mime-types@~2.1.11, mime-types@~2.1.13: 226 | version "2.1.15" 227 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 228 | dependencies: 229 | mime-db "~1.27.0" 230 | 231 | mime@1.3.4: 232 | version "1.3.4" 233 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 234 | 235 | ms@0.7.2: 236 | version "0.7.2" 237 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" 238 | 239 | multiparty@~4.1.2: 240 | version "4.1.3" 241 | resolved "https://registry.yarnpkg.com/multiparty/-/multiparty-4.1.3.tgz#3c43c7fcb1896e17460436a9dd0b6ef1668e4f94" 242 | dependencies: 243 | fd-slicer "~1.0.1" 244 | 245 | negotiator@0.6.1: 246 | version "0.6.1" 247 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 248 | 249 | object-assign@^4: 250 | version "4.1.1" 251 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 252 | 253 | on-finished@~2.3.0: 254 | version "2.3.0" 255 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 256 | dependencies: 257 | ee-first "1.1.1" 258 | 259 | parseurl@~1.3.1: 260 | version "1.3.1" 261 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" 262 | 263 | path-to-regexp@0.1.7: 264 | version "0.1.7" 265 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 266 | 267 | pend@~1.2.0: 268 | version "1.2.0" 269 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" 270 | 271 | proxy-addr@~1.1.3: 272 | version "1.1.4" 273 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" 274 | dependencies: 275 | forwarded "~0.1.0" 276 | ipaddr.js "1.3.0" 277 | 278 | qs@6.4.0: 279 | version "6.4.0" 280 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 281 | 282 | qs@~4.0.0: 283 | version "4.0.0" 284 | resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" 285 | 286 | range-parser@~1.2.0: 287 | version "1.2.0" 288 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 289 | 290 | raw-body@~2.2.0: 291 | version "2.2.0" 292 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" 293 | dependencies: 294 | bytes "2.4.0" 295 | iconv-lite "0.4.15" 296 | unpipe "1.0.0" 297 | 298 | readable-stream@1.1.x: 299 | version "1.1.14" 300 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 301 | dependencies: 302 | core-util-is "~1.0.0" 303 | inherits "~2.0.1" 304 | isarray "0.0.1" 305 | string_decoder "~0.10.x" 306 | 307 | send@0.15.1: 308 | version "0.15.1" 309 | resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" 310 | dependencies: 311 | debug "2.6.1" 312 | depd "~1.1.0" 313 | destroy "~1.0.4" 314 | encodeurl "~1.0.1" 315 | escape-html "~1.0.3" 316 | etag "~1.8.0" 317 | fresh "0.5.0" 318 | http-errors "~1.6.1" 319 | mime "1.3.4" 320 | ms "0.7.2" 321 | on-finished "~2.3.0" 322 | range-parser "~1.2.0" 323 | statuses "~1.3.1" 324 | 325 | serve-static@1.12.1: 326 | version "1.12.1" 327 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" 328 | dependencies: 329 | encodeurl "~1.0.1" 330 | escape-html "~1.0.3" 331 | parseurl "~1.3.1" 332 | send "0.15.1" 333 | 334 | setprototypeof@1.0.3: 335 | version "1.0.3" 336 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 337 | 338 | "statuses@>= 1.3.1 < 2", statuses@~1.3.1: 339 | version "1.3.1" 340 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 341 | 342 | streamsearch@0.1.2: 343 | version "0.1.2" 344 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" 345 | 346 | string_decoder@~0.10.x: 347 | version "0.10.31" 348 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 349 | 350 | type-is@~1.6.14, type-is@~1.6.4: 351 | version "1.6.14" 352 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" 353 | dependencies: 354 | media-typer "0.3.0" 355 | mime-types "~2.1.13" 356 | 357 | unpipe@1.0.0, unpipe@~1.0.0: 358 | version "1.0.0" 359 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 360 | 361 | utils-merge@1.0.0: 362 | version "1.0.0" 363 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" 364 | 365 | vary@^1, vary@~1.1.0: 366 | version "1.1.1" 367 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" 368 | --------------------------------------------------------------------------------